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

本文涉及的产品
视觉智能开放平台,视频资源包5000点
视觉智能开放平台,分割抠图1万点
视觉智能开放平台,图像资源包5000点
简介: 本文探讨了Android平台上推流模块中添加文字与PNG水印的技术演进。自2015年起,为了满足应急指挥及安防领域的需求,逐步发展出三代水印技术:第一代为静态文字与图像水印;第二代实现了动态更新水印内容的能力,例如实时位置与时间信息;至第三代,则优化了数据传输效率,直接使用Bitmap对象传递水印数据至JNI层,减少了内存拷贝次数。这些迭代不仅提升了用户体验和技术效率,也体现了开发者追求极致与不断创新的精神。

技术背景

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

image.gif

第一代:不可动态改变的文字、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);
     */

image.gif

第二代:实时动态文字、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;
    }

image.gif

第三代: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;
    }

image.gif

对应封装设计:

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();
        }
    }

image.gif

总结

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

相关文章
|
2月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
32 1
|
3月前
|
JavaScript 前端开发 Android开发
让Vite+Vue3项目在Android端离线打开(不需要起服务)
让Vite+Vue3项目在Android端离线打开(不需要起服务)
118 10
|
3月前
|
安全 API 开发工具
Android平台RTMP推送|轻量级RTSP服务如何实现麦克风|扬声器声音采集切换
Android平台扬声器播放声音的采集,在无纸化同屏等场景下,意义很大,早期低版本的Android设备,是没法直接采集扬声器audio的(从Android 10开始支持),所以,如果需要采集扬声器audio,需要先做系统版本判断,添加相应的权限。
|
3月前
|
编解码 开发工具 Android开发
Android平台实现屏幕录制(屏幕投影)|音频播放采集|麦克风采集并推送RTMP或轻量级RTSP服务
Android平台屏幕采集、音频播放声音采集、麦克风采集编码打包推送到RTMP和轻量级RTSP服务的相关技术实现,做成高稳定低延迟的同屏系统,还需要有配套好的RTMP、RTSP直播播放器
|
7月前
|
XML Java Android开发
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
995 0
|
6月前
|
调度 Android开发
43. 【Android教程】服务:Service
43. 【Android教程】服务:Service
62 2
|
Android开发 开发者
|
Android开发
Android四大组件之一服务(Service)
Service作为Android必不可少的组件,大家有兴趣可以来看看
269 0

热门文章

最新文章

下一篇
DataWorks