Android平台RTMP推送|轻量级RTSP服务|GB28181接入之文字、png图片水印的精进之路

技术背景

Android平台推流模块,添加文字或png水印,不是一件稀奇的事儿,常规的做法也非常多,本文,我们主要是以大牛直播SDK水印迭代,谈谈音视频行业的精进和工匠精神。

第一代:不可动态改变的文字、png水印

2015年,我们在做Android平台RTMP推送模块和轻量级RTSP服务模块的时候,有这样的场景诉求,应急指挥、智慧巡检或安防类,都有文字或png水印的技术诉求,针对这种情况,我们当时做了如下的接口设计:

   /** SmartPublisherJniV2.java* WebSite: https://daniusdk.com* * Created by DaniuLive on 2015/09/20.*/ /*** Set Text water-mark(设置文字水印)* * @param fontSize: it should be "MEDIUM", "SMALL", "BIG"* * @param waterPostion: it should be "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT".* * @param xPading, yPading: the distance of the original picture.* * <pre> The interface is only used for setting font water-mark when publishing stream. </pre>  * * @return {0} if successful*//** 已废弃, 请使用层模式加水印*public native int SmartPublisherSetTextWatermark(long handle, String waterText, int isAppendTime, int fontSize, int waterPostion, int xPading, int yPading);*//*** Set Text water-mark font file name(设置文字水印字体路径)** @param fontFileName:  font full file name, e.g: /system/fonts/DroidSansFallback.ttf** @return {0} if successful*//* 已废弃, 请使用层模式加水印* public native int SmartPublisherSetTextWatermarkFontFileName(long handle, String fontFileName);*//*** Set picture water-mark(设置png图片水印)* 											* @param picPath: the picture working path, e.g: /sdcard/logo.png* * @param waterPostion: it should be "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT".* * @param picWidth, picHeight: picture width & height* * @param xPading, yPading: the distance of the original picture.* * <pre> The interface is only used for setting picture(logo) water-mark when publishing stream, with "*.png" format </pre>  * * @return {0} if successful*//** 已废弃, 请使用层模式加水印*public native int SmartPublisherSetPictureWatermark(long handle, String picPath, int waterPostion, int picWidth, int picHeight, int xPading, int yPading);*/

第二代:实时动态文字、png水印

尽管上面的水印,已经可以满足大多技术场景的需求,但在我们内部,却被一直诟病,因为违背我们SDK设计和使用的smart策略。

随着Android平台GB28181设备接入模块的发布,基于GB28181设备接入模块,对水印提出来更高的要求,好多公司或开发者,需要实时更新水印内容(比如MobilePosition位置信息、实时时间、作业内容等),为此,我们想到的是,这一版,我们需要实现动态水印能力。

以文字水印为例,我们的实现和设计如下,通过bitmap获取到文字水印数据,然后通过PostLayerImageRGBA8888ByteBuffer()接口投递到jni,这种设计,几乎已经满足了100%的技术诉求:

    private int postText1Layer(List<LibPublisherWrapper> publisher_list, int index, int left, int top, int video_w, int video_h) {Bitmap text_bitmap = makeTextBitmap("文本水印一", getFontSize(video_w) + 8,Color.argb(255, 200, 250, 0),false, 0, false);if (null == text_bitmap)return 0;ByteBuffer buffer = ByteBuffer.allocateDirect(text_bitmap.getByteCount());text_bitmap.copyPixelsToBuffer(buffer);for (LibPublisherWrapper i : publisher_list)i.PostLayerImageRGBA8888ByteBuffer(index, left, top, buffer, 0,text_bitmap.getRowBytes(), text_bitmap.getWidth(), text_bitmap.getHeight(),0, 0, 0, 0, 0, 0); int ret = text_bitmap.getHeight();text_bitmap.recycle();return ret;}

 第三代:Bitmap接口设计

尽管第二代水印设计,已经满足了技术层面的场景诉求,但从效率角度,我们认为还有进步的空间,为此,我们直接把生成的bitmap数据投递到jni层,减少了一次拷贝,特别是在频繁水印处理时,提高了数据处理效率。

    private int postText1Layer(List<LibPublisherWrapper> publisher_list, int index, int left, int top, int video_w, int video_h) {Bitmap text_bitmap = makeTextBitmap("文本水印一", getFontSize(video_w) + 8,Color.argb(255, 200, 250, 0),false, 0, false);if (null == text_bitmap)return 0;for (LibPublisherWrapper i : publisher_list)i.PostLayerBitmap(index, left, top, text_bitmap, 0, 0, 0, 0,0, 0, 0, 0, 0, 0);int ret = text_bitmap.getHeight();text_bitmap.recycle();return ret;}

对应封装设计:

    public boolean PostLayerBitmap(int index, int left, int top,android.graphics.Bitmap bitmap, int clip_left, int clip_top, int clip_width, int clip_height,int is_vertical_flip, int is_horizontal_flip,int scale_width, int scale_height, int scale_filter_mode,int rotation_degree) {if (!check_native_handle())return false;if (!read_lock_.tryLock())return false;try {if (!check_native_handle())return false;return OK == lib_publisher_.PostLayerBitmap(get(), index, left, top,bitmap, clip_left, clip_top, clip_width, clip_height, is_vertical_flip, is_horizontal_flip,scale_width, scale_height, scale_filter_mode, rotation_degree);} catch (Exception e) {Log.e(TAG, "PostLayerBitmap Exception:", e);return false;} finally {read_lock_.unlock();}}

总结

有人说,音视频行业最苦最没有意思、高投入低回报的就是做SDK。在我们看来,少一次拷贝、一次功能的迭代是进步,但大多数情况下,对于不了解细节的开发者看来,不深耕不细测很难看出端倪。大牛直播SDK的预期就是专注、极致、智慧、比快更快,做音视频行业的基石,帮助更多的行业,更少的精力实现音视频接入能力,任何行业,持续进步,才会有更大的收获。从另一个角度来说,看似每一次的精进,对我们技术从业者来说,都是持续的乐趣。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/25561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络9——无线网络和移动网络2无线个人区域网 WPAN

文章目录 一、蓝牙系统二、低速 WPAN三、高速 WPAN 无线个人区域网WPAN(Wireless Personal Area Network)就是在个人工作的地方把属于个人使用的电子设备(如便携式电脑、平板电脑、便携式打印机以及蜂窝电话等)用无线技术连接起来自组网络&#xff0c;不需要使用接入点AP&#…

【设计模式】创建型设计模式之 建造者模式

文章目录 一、介绍定义UML 类图 二、用法1 简化复杂对象具体构建过程省略抽象的 Builder 类省略 Director 类 三、用法2 控制对象构造方法、限制参数关系Guava 中使用建造者模式构建 cache 来进行参数校验 一、介绍 定义 建造者模式&#xff0c;将一个复杂的对象的构建过程与…

实用软件分享---简单菜谱 0.3版本 几千种美食(安卓)

专栏介绍:本专栏主要分享一些实用的软件(Po Jie版); 声明1:软件不保证时效性;只能保证在写本文时,该软件是可用的;不保证后续时间该软件能一直正常运行;不保证没有bug;如果软件不可用了,我知道后会第一时间在题目上注明(已失效)。介意者请勿订阅。 声明2:本专栏的…

Hive日志介绍

日志描述 日志路径&#xff1a;Hive相关日志的默认存储路径为“/var/log/Bigdata/hive/角色名”&#xff0c;Hive1相关日志的默认存储路径为“/var/log/Bigdata/hive1/角色名”&#xff0c;以此类推。 HiveServer&#xff1a;“/var/log/Bigdata/hive/hiveserver”&#xff0…

住宿管理系统 java+jsp+web三件套

文章目录 1、简要介绍2、数据库设计3、中间遇到的困难一、数据问题二、文件问题 4、项目 写了将近3周&#xff0c;人都写麻了 记录下&#xff0c;第一个 ss 代码 仅仅使用了layui作为前端UI框架&#xff0c;因为另一个项目用的也是他&#xff0c;感觉一些组件比较好用 后端是j…

reverse入门刷题(6.9)

总结&#xff1a; 拿到附件&#xff0c;先运行看看有没有信息&#xff0c;再查壳&#xff0c;再IDA运行 1.Easy_vb 收获&#xff1a; 使用搜索&#xff1a;在String的时候用的是ctrlf 在IDA_view的时候使用搜索是Aitt 打开IDA&#xff0c;Aitt搜索MCTF&#xff08;关键字即…

文献阅读:Solving olympiad geometry without human demonstrations

文献阅读&#xff1a;Solving olympiad geometry without human demonstrations 1. 文章简介2. 方法介绍 1. Overview2. Symbolic deduce3. Language Model4. 联合使用 3. 实验考察 & 结论 1. 基础实验考察2. 结果分析3. 样例展示 4. 总结 & 思考 文献链接&#xff1a…

看似不同的事情,却是相同的坑

目录 一、背景二、过程1.遭遇战-微盘股的下杀2.不失为一件好事3.一切向后看吧&#xff0c;最近的学习感受4.该有的心境 三、总结 一、背景 也在一点点改变&#xff0c;期间势必要经历流血的过程&#xff1b;所谓无疯狂不成长&#xff0c;积极的心态去应对&#xff0c;去总结总…

引入Springcloud--Sleuth-链路追踪中MDC是如何获取到traceid和何时放入traceid的

在分布式项目中需要引入 spring-cloud-starter-sleuth框架来记录跟踪请求在不同服务之前流转的路径。在整个流转路径通过traceid将所有的路径给串联起来。 项目中需要保存traceid来实现日志快速搜索和定位&#xff0c;可以通过MDC.get("traceId")获取到traceId。 …

评书下载到u盘,下载到内存卡,下载到手机或电脑的方法

评书下载的方法有很多种&#xff0c;无论是通过什么方法&#xff0c;我们都可以快速的获取喜爱的评书。下面将详细介绍常见的评书下载方法&#xff0c;帮助您快速上手。 1、搜索“十方评书网”。 2、要下载那个评书家的选择那个评书家就可以。 3、点击进去后可以一键下载单部评…

Elasticsearch中各种query的适用场景

Elasticsearch 提供了丰富的 Query 类型&#xff0c;以满足各种搜索需求。以下列举一些常见的 Query 类型&#xff0c;并分析其区别和应用场景&#xff1a; 一、 几个常用的基本Query 1. Term Query 应用场景: 查找包含特定词语的文档&#xff0c;适合精确匹配单个词语的场景…

【SpringBoot + Vue 尚庭公寓实战】标签和配套管理接口实现接口实现(六)

【SpringBoot Vue 尚庭公寓实战】标签和配套管理接口实现接口实现&#xff08;六&#xff09; 文章目录 【SpringBoot Vue 尚庭公寓实战】标签和配套管理接口实现接口实现&#xff08;六&#xff09;1、保存或更新标签信息2、根据id删除标签信息3、根据类型查询配套列表4、新…

Aptos Builder Jam 亚洲首站|见证 Aptos 公链 2024 年新突破

4 月下旬的「TinTin DESTINATION MOON」杭州站活动让我们构建下一个 Web3 巅峰的项目生态行动与未来战略。时隔三个月&#xff0c;「TinTin DESTINATION MOON」Aptos 线下活动将再次来到杭州&#xff0c;为 Aptos Builder Jam 亚洲首站火热造势&#xff0c;7 月 6 日诚邀 Web3 …

vue2中如何动态渲染组件

vue2中如何动态渲染组件 动态渲染组件代码解读通过函数调用渲染组件 封装一个函数调用的二次确认弹窗如何让外部知道用户点击了取消还是确定呢&#xff1f; 思考小结 vue2 的项目中&#xff0c;main.js 文件中有一个挂载 App.vue 组件的方法&#xff1a; new Vue({name: Root,…

工程师 - 什么是EMI测试

一、EMC EMI EMS定义&#xff1a; EMC&#xff08;ElectromagneticCompatibility&#xff09; 电磁兼容&#xff0c;是指设备或系统在电磁环境中性能不降级的状态。电磁兼容&#xff0c;一方面要求系统内没有严重的干扰源&#xff0c;一方面要求设备或系统自身有较好的抗电磁…

5G发牌五周年丨移远通信:全面发力,加快推进5G技术服务社会发展

2024年6月6日&#xff0c;正值中国5G商用牌照发牌五周年。根据移动通信“十年一代”的规律&#xff0c;5G已走过一半征程。在过去的五年时间里&#xff0c;5G技术从萌芽到成熟&#xff0c;深刻改变了工业、农业、医疗及消费端等各个领域的发展脉络。无论是无人机配送、自动驾驶…

【LeetCode】两数相加(基于单向链表)难度:中等

目录 理清题目 解题思路 题目代码 运行结果 我们来看一下题目描述&#xff1a; 理清题目 首先题目要求链表中的节点的值必须在[0,9]之间也就是说我们要处理的数字必为正整数&#xff0c;因此就不会涉及到太复杂的计算&#xff0c;题目其实就是要求对两个链表中的节点的值分…

详解 Flink 的状态管理

一、Flink 状态介绍 1. 流处理的无状态和有状态 无状态的流处理&#xff1a;根据每一次当前输入的数据直接转换输出结果的过程&#xff0c;在处理中只需要观察每个输入的独立事件。例如&#xff0c; 将一个字符串类型的数据拆分开作为元组输出或将每个输入的数值加 1 后输出。…

台积电代工!Intel新AI PC芯片Lunar Lake发布:AI算力120TOPS!

根据英特尔披露的数据显示&#xff0c;Lunar Lake的GPU性能提升50%、NPU内核的AI算力增加了四倍、SoC耗电量减少40%、GPU AI算力增加3.5倍&#xff0c;整个SoC的算力超过了120TOPS。 6月4日&#xff0c;英特尔CEO帕特基辛格在COMPUTEX 2024上发表主题演讲&#xff0c;正式公布…

如何确保redis缓存中的数据与数据库一致

一、双写模式&#xff1a; 在写入数据库时&#xff0c;也写入缓存。 二&#xff1a;失效模式&#xff1a; 在写入新数据后&#xff0c;删除缓存中数据&#xff0c;下次请求时查询数据库&#xff0c;并把查到的最新数据写入缓存。 不管是双写模式还是失效模式&#xff0c;缓…