Android平台GB28181设备接入模块动态文字图片水印技术探究

​技术背景

前几年,我们发布的了Android平台GB28181设备接入模块,实现了不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181---2016或GB/T28181---2022服务。

Android终端除支持常规的音视频数据接入外,还可以支持移动设备位置(MobilePosition)订阅和通知、图像抓拍、语音广播和语音对讲、历史视音频下载和回放,支持对接数据类型如下:

  1. 编码前数据(目前支持的有YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型),其中,Android平台前后摄像头数据,或者屏幕数据,或者Unity拿到的数据,均属编码前数据;
  2. 编码后数据(如无人机等264/HEVC数据,或者本地解析的MP4音视频数据);
  3. 拉取RTSP或RTMP流并接入至GB28181平台(比如其他IPC的RTSP流,可通过Android平台GB28181接入到国标平台)。

实现的主要功能如下:

  • [视频格式]H.264/H.265(Android H.265硬编码);
  • [音频格式]G.711 A律、AAC;
  • [音量调节]Android平台采集端支持实时音量调节;
  • [H.264硬编码]支持H.264特定机型硬编码;
  • [H.265硬编码]支持H.265特定机型硬编码;
  • [软硬编码参数配置]支持gop间隔、帧率、bit-rate设置;
  • [软编码参数配置]支持软编码profile、软编码速度、可变码率设置;
  • 支持横屏、竖屏推流;
  • Android平台支持后台service推送屏幕(推送屏幕需要5.0+版本);
  • 支持纯视频、音视频PS打包传输;
  • 支持RTP OVER UDP和RTP OVER TCP被动模式(TCP媒体流传输客户端);
  • 支持信令通道网络传输协议TCP/UDP设置;
  • 支持注册、注销,支持注册刷新及注册有效期设置;
  • 支持设备目录查询应答;
  • 支持心跳机制,支持心跳间隔、心跳检测次数设置;
  • 支持移动设备位置(MobilePosition)订阅和通知;
  • 适用国家标准:GB/T 28181---2016、GB/T28181---2022;
  • 支持语音广播;
  • 支持语音对讲;
  • 支持图像抓拍;
  • 支持历史视音频文件检索;
  • 支持历史视音频文件下载;
  • 支持历史视音频文件回放;
  • 支持云台控制和预置位查询;
  • [实时水印]支持动态文字水印、png水印;
  • [镜像]Android平台支持前置摄像头实时镜像功能;
  • [实时静音]支持实时静音/取消静音;
  • [实时快照]支持实时快照;
  • [降噪]支持环境音、手机干扰等引起的噪音降噪处理、自动增益、VAD检测;
  • [外部编码前视频数据对接]支持YUV数据对接;
  • [外部编码前音频数据对接]支持PCM对接;
  • [外部编码后视频数据对接]支持外部H.264数据对接;
  • [外部编码后音频数据对接]外部AAC数据对接;
  • [扩展录像功能]支持和录像SDK组合使用,录像相关功能。

Android平台的GB28181设备接入端模块,对水印要求比较高,除了传统的文字外,还需要图片、时间戳等,更重要的是,有动态水印的技术诉求。下面我们从水印创建、叠加、更新等维度介绍下动态水印的实现。

创建水印内容

  • 实时时间水印:获取当前系统时间,并将其格式化为字符串,以便添加到视频帧中作为水印。例如,使用 SimpleDateFormat 类来格式化时间:

    private String makeTimestampString() { if (null == date_format_) date_format_ = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    javascript 复制代码
    return date_format_.format(new Date());

    }

  • 文本水印:定义你想要添加到视频中的特定文本信息,比如设备编号、用户信息等。这些文本信息可以在代码中预先定义好,也可以根据实际情况从外部获取,比如从设备的配置文件中读取或者通过网络请求获取。

  • 图片水印:准备好要作为水印的图片文件,可以将其放置在项目的资源文件夹中,然后通过 BitmapFactory 类来加载图片:

    private Bitmap getAssetsBitmap() { if (null == context_) return null;

    ini 复制代码
    Context context = context_.get();
    if (null == context)
    	return null;
    
    Bitmap bitmap = null;
    try {
    	InputStream s = context.getAssets().open("tca.png");
    	bitmap = BitmapFactory.decodeStream(s);
    	s.close();
    } catch (Exception e) {
    	e.printStackTrace();
    }
    return bitmap;

    }

创建水印图像

  • 根据水印内容创建一个图像对象,用于表示水印。如果是文本水印,可以使用 Canvas 和 Paint 在一个空白的 Bitmap 上绘制文本。如果是图片水印,则直
    接使用之前加载的图片 Bitmap 作为水印图像。不过,可能需要根据实际需求对图片进行缩放、旋转等处理,以适应视频帧的大小和方向。

将水印图像叠加到视频帧上

  • 将水印图像的像素数据与视频帧的像素数据进行合并处理,从而实现水印的叠加。这一步通常需要对像素数据进行逐行或逐像素的操作,根据一定的算法将水印图像的像素值与视频帧的像素值进行混合。
  • 可以使用类似于图像处理软件中的图层叠加方式,将水印图像作为一个图层叠加到视频帧上。具体的实现方式可能因使用的视频处理库或框架而有所不同,但一般需要获取视频帧的像素数据缓冲区,然后在缓冲区中进行数据的修改和叠加操作。
  • 在叠加水印时,需要注意水印的位置、透明度和大小等参数,以确保水印不会遮挡视频的重要内容,同时又能够清晰地显示出来。可以根据实际需求在代码中设置这些参数,或者提供用户界面让用户可以自定义水印的参数。

更新动态水印

如果水印内容是动态变化的(如实时时间),需要定期更新水印图像。可以使用定时器或 Handler 来周期性地获取新的水印内容,重新创建水印图像,并将其叠加到视频帧上。例如,使用 Handler 的 postDelayed() 方法来实现定时更新。

SmartGBD动态水印设计

本文以大牛直播SDK的Android平台GB28181设备接入模块(SmartGBD)的动态水印为例,探讨下我们的动态水印设计实现,我们提供了图片水印、文字水印、全部水印、不加水印几个选项。

ini 复制代码
/* SmartGbdActivity.java
 * Created by daniusdk.com
 * WeChat: xinsheng120
 */
watermarkSelctor = (Spinner) findViewById(R.id.watermarkSelctor);

final String[] watermarks = new String[]{"图片水印", "全部水印", "文字水印", "不加水印"};

ArrayAdapter<String> adapterWatermark = new ArrayAdapter<String>(this,
		android.R.layout.simple_spinner_item, watermarks);

adapterWatermark.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

watermarkSelctor.setAdapter(adapterWatermark);

watermarkSelctor.setSelection(3,true);
watemarkType = 3;   //默认不加水印

watermarkSelctor.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {

	@Override
	public void onItemSelected(AdapterView<?> parent, View view,
							   int position, long id) {

		watemarkType = position;

		Log.i(TAG, "[水印类型]Currently choosing: " + watermarks[position] + ", watemarkType: " + watemarkType);

			if (layer_post_thread_ != null) {
				layer_post_thread_.enableText(isHasTextWatermark());
				layer_post_thread_.enablePicture(isHasPictureWatermark());
				layer_post_thread_.update_layers();
			}
	}

	@Override
	public void onNothingSelected(AdapterView<?> parent) {

	}
});

以文字水印设计和数据投递为例:

java 复制代码
    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;
    }

对应封装设计:

csharp 复制代码
    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();
        }
    }

总结

Android平台的GB28181设备接入模块,主要用在如执法记录仪、智能安全帽、智能监控、智慧零售、智慧教育、远程办公、明厨亮灶、智慧交通、智慧工地、雪亮工程、平安乡村、生产运输、车载终端等场景,这些场景,好多对动态水印的诉求都非常大,动态水印的设计和实现,一方面需要足够灵活,另一方面,还需要尽可能的资源占用低,以上是大概的技术实现,感兴趣的开发者,可以跟我单独沟通探讨。

相关推荐
音视频牛哥7 小时前
[2015~2024]SmartMediaKit音视频直播技术演进之路
音视频开发·视频编码·直播
音视频牛哥2 天前
Windows平台Unity3D下RTMP播放器低延迟设计探讨
音视频开发·视频编码·直播
音视频牛哥3 天前
Windows平台Unity3D下如何低延迟低资源占用播放RTMP或RTSP流?
音视频开发·视频编码·直播
陈年3 天前
纯前端视频剪辑
音视频开发
声知视界4 天前
音视频基础能力之 Android 音频篇 (三):高性能音频采集
android·音视频开发
音视频牛哥7 天前
RTSP摄像头8K超高清使用场景探究和播放器要求
音视频开发·视频编码·直播
音视频牛哥7 天前
RTMP如何实现毫秒级延迟体验?
音视频开发·视频编码·直播
CHEtuzki8 天前
现在的电商风口已经很明显了
微信·直播·抖音·电商·录播
哔哩哔哩技术10 天前
WASM 助力 WebCodecs:填补解封装能力的空白
音视频开发