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的预期就是专注、极致、智慧、比快更快,做音视频行业的基石,帮助更多的行业,更少的精力实现音视频接入能力,任何行业,持续进步,才会有更大的收获。从另一个角度来说,看似每一次的精进,对我们技术从业者来说,都是持续的乐趣。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《云原生安全攻防》-- 容器环境下的攻击行为

在本节课程中&#xff0c;我们将以攻击者的视角来深入探讨容器环境下的攻击行为&#xff0c;并揭示攻击者在容器环境中的各种攻击细节。 在这个课程中&#xff0c;我们将学习以下内容&#xff1a; 攻击容器环境&#xff1a;模拟容器内应用入侵的场景。 容器环境下的攻击行为&a…

[Elasticsearch] ES更新问题踩坑记录

drop table if exists tmp.test_create_table; create table if not exists tmp.test_create_table( id int, name string ) stored as parquet; 问题排查 查看ES数据 发现ES创建表的状态没有正常更新 yn 还是0 查看日志 查看日志, 截取部分关键信息: ReceiverControl…

载波相移CPS-SPWM调制方法的simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 载波相移CPS-SPWM调制方法的simulink建模与仿真&#xff0c;载波相移PWM方法&#xff1a; 2.系统仿真结果 单极倍频 釆用 调制波 反相 法 &#xff0c; 基本调制原理为 &…

Django模板的使用(详细版)

1、配置 在工程中创建模板目录templates&#xff08;这个名字可以变&#xff01;&#xff01;&#xff09; 在settings.py配置文件中修改TEMPLATES配置项的DIRS值 2、定义模板 在templates目录中新建一个模板文件&#xff0c;如index.html 3、模板渲染 Django提供了一个函数…

Golang的GC

目录 介绍GC 概要 什么是根对象 三色标记法 什么情况下三色标记法会失效 屏障机制 “强-弱” 三色不变式 插入屏障 (强三色) 删除屏障(弱三色) Go 的混合写屏障机制 混合写屏障规则 介绍GC 概要 作用范围&#xff1a;只回收堆内存&#xff0c;不回收栈内存&#xf…

亚马逊冗余库存处理

在亚马逊放置90天以上的产品&#xff0c;又不在正常的动销&#xff0c;就要采取一定的措施了。清库存方式&#xff1a; 最直接的方式——降价促销&#xff08;至少要降价百分之三十以上&#xff0c;库龄越久&#xff0c;降价越狠&#xff09;参加官方的活动促销的话是需要符合…

Python学习笔记速成版

数据容器 列表的方法-总览 具体操作 元组 定义 相关操作 注意事项 特点 字符串 总览 常用操作 特点 序列 定义 切片操作 Set集合 总览 定义 常用操作 注意事项 字典 总览 定义 常用操作 获取 嵌套 其他操作 summary 通用操作 字符串大小比较 函数进阶 多个返回值 多种传…

2024年江苏三支一扶公告已出,招440人!

本次江苏省将招募440名高校毕业生&#xff0c;安排到乡镇&#xff08;街道&#xff09;从事支教、支农、支医、帮扶乡村振兴、水利、就业和社会保障服务工作&#xff08;以下简称“三支一扶”计划&#xff09;&#xff0c;服务期限为2年。 招募程序 招募工作按照个人报名、资格…

Ansible离线部署 之 Zabbix

Ansible介绍 Ansible 是一个自动化平台&#xff0c;用于 IT 自动化&#xff0c;如配置管理、应用部署、任务自动化等。Ansible 使用 SSH 来连接到远程机器&#xff0c;并执行预定义的任务。Ansible 的主要特点是其简单性、易用性和强大的功能集。 以下是 Ansible 的一些关键特…

Mysql学习(八)——多表查询

文章目录 五、多表查询5.1 多表关系5.2 多表查询概述5.3 内连接5.4 外连接5.5 自连接5.6 联合查询5.7子查询5.8 总结 五、多表查询 5.1 多表关系 概述&#xff1a;项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;…

接口请求的六种常见方式详解(get、post、head等)

一&#xff0e;接口请求的六种常见方式&#xff1a; 1、Get 向特定资源发出请求&#xff08;请求指定页面信息&#xff0c;并返回实体主体&#xff09; 2、Post 向指定资源提交数据进行处理请求&#xff08;提交表单、上传文件&#xff09;&#xff0c;又可能导致新的资源的建…

基于大模型的360度全景图像生成技术:L-MAGIC

在数字技术的浪潮中,我们迎来了一项革命性的创新——L-MAGIC,一个能够基于一张普通照片和简单文字描述,快速生成360度全方位全景画面的系统。L-MAGIC不仅提供了沉浸式的视觉体验,还融合了多种素材和技术手段,让全景图像的生成变得更加丰富和真实。 技术亮点 1. 多角度视…

SpringMVC01-初始SpringMVC

SpringMVC 回顾MVC 什么是MVC MVC是模型(Model)、视图(View)、控制器(Controller)的简写&#xff0c;是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向偶合。MVC不是一种设计模式&#xff0c;MVC是一种架构模…

[FreeRTOS 基础知识] 保存现场与恢复现场

文章目录 什么是现场&#xff1f;保存现场的数据存放在哪里&#xff1f;保护现场的场景 什么是现场&#xff1f; 在[FreeRTOS 基础知识] 栈 与 汇编语言文章中解析了fun_c汇编函数&#xff0c;假设在执行fun_c函数的过程中产生高优先级的中断。如下图所示。 此时刚从RAM的SP栈…

[大模型]GLM4-9B-chat Lora 微调

本节我们简要介绍如何基于 transformers、peft 等框架&#xff0c;对 LLaMA3-8B-Instruct 模型进行 Lora 微调。Lora 是一种高效微调方法&#xff0c;深入了解其原理可参见博客&#xff1a;知乎|深入浅出 Lora。 这个教程会在同目录下给大家提供一个 nodebook 文件&#xff0c…

【docker】 pull access denied for alpine-java, repository does not exist

问题&#xff1a; com.spotify.docker.client.exceptions.DockerException: pull access denied for alpine-java, repository does not exist or may require docker login: denied: requested access to the resource is denied org.apache.maven.plugin.MojoExecutionExce…

[Algorithm][动态规划][完全背包问题][零钱兑换][零钱兑换Ⅱ][完全平方数]详细讲解

目录 1.零钱兑换1.题目链接2.算法原理详解3.代码实现 2.零钱兑换 II1.题目链接2.算法原理详解3.代码实现 3.完全平方数1.题目链接2.算法原理详解3.代码实现 1.零钱兑换 1.题目链接 零钱兑换 2.算法原理详解 思路&#xff1a; 确定状态表示 -> dp[i][j]的含义 dp[i][j]&am…

Gitlab安装配置

gitlab git是一个分布式的代码版本管理软件。用于敏捷高效地处理任何或小或大的项目。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。 1.版本控制 是指对软件开发过程中各种程序代码&#xff0c;配置文件及说明文档等文件变更的管…

如何用R语言ggplot2画高水平期刊散点图

文章目录 前言一、数据集二、ggplot2画图1、全部代码2、细节拆分1&#xff09;导包2&#xff09;创建图形对象3&#xff09;主题设置4&#xff09;轴设置5&#xff09;图例设置6&#xff09;散点颜色7&#xff09;保存图片 前言 一、数据集 数据下载链接见文章顶部 处理前的数据…

LabVIEW图像采集处理项目中相机选择与应用

在LabVIEW图像采集处理项目中&#xff0c;选择合适的相机是确保项目成功的关键。本文将详细探讨相机选择时需要关注的参数、黑白相机与彩色相机的区别及其适用场合&#xff0c;帮助工程师和开发者做出明智的选择。 相机选择时需要关注的参数 1. 分辨率 定义&#xff1a;分辨率…