Andorid平台GB28181设备接入端如何生成黑帧并推送至国标平台

2023-04-21 17:40:01 浏览数 (1)

​我们在做Android平台GB28181设备接入模块的时候,遇到这样的需求,做移动对讲的时候,是不需要视频数据的,但是国标平台侧,没有视频的话,大多平台又无法播纯音频打包的数据(网页端大多基于http-flv或webrtc实现),基于此,我们做了个简单的处理,通过Bitmap生成个32*32的黑帧,然后,确保上行的音视频数据都有,但是由于视频系黑帧数据,几乎不占用带宽。

废话不多说,上代码:

代码语言:java复制
    class LayerPostThread extends Thread
    {
        private volatile boolean is_exit_ = false;
        private long handle_ = 0;
        ByteBuffer image_buffer_ = null;
        private int width_ = 32;
        private int height_ = 32;

        @Override
        public void run() {
            image_buffer_ = null;

            if (0 == handle_)
                return;

            generateImageBuffer(width_, height_);

            while(!is_exit_) {
                postImageLayer(0, 0, 0, width_, height_);
                waitSleep(40);
            }

            image_buffer_ = null;
        }

        private void generateImageBuffer(int width, int height)
        {
            Bitmap bitmap = android.graphics.Bitmap.createBitmap(width, height, android.graphics.Bitmap.Config.ARGB_8888);
            bitmap.eraseColor(android.graphics.Color.argb(255, 0, 0, 0));

            if (null == bitmap)
                return;

            if ( image_buffer_ != null) {
                image_buffer_.rewind();

                if ( image_buffer_.remaining() < bitmap.getByteCount())
                    image_buffer_ = null;
            }

            if (null == image_buffer_)
                image_buffer_ = ByteBuffer.allocateDirect(bitmap.getByteCount());

            bitmap.copyPixelsToBuffer(image_buffer_);
        }

        private int postImageLayer(int index, int left, int top, int video_w, int video_h) {
            if (video_w < 1 || video_h < 1)
                return  0;

            int scale_w = 0, scale_h = 0, scale_filter_mode = 0;

            libPublisher.PostLayerImageRGBA8888ByteBuffer(handle_, index, left, top, image_buffer_, 0,
                    4*video_w, video_w, video_h,
                    0, 0, scale_w, scale_h, scale_filter_mode,0);

            return 0;
        }

        public void startPost(long handle, int w, int h, boolean is_text, boolean is_pitcure) {
            this.is_exit_ = false;
            this.handle_ = handle;

            try {
                this.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public void stopPost() {
            this.is_exit_ = true;

            try {
                this.join(1000);
            }
            catch (Exception e) {
                e.printStackTrace();
            }

            handle_ = 0;
        }
    }

外部调用逻辑如下:

代码语言:java复制
    private LayerPostThread layer_post_thread_ = null;

    private void startLayerPostThread() {
        if (null == layer_post_thread_) {
            layer_post_thread_ = new LayerPostThread();
            layer_post_thread_.startPost(publisherHandle, video_width_, video_height_, isHasTextWatermark(), isHasPictureWatermark());
        }
    }

    private void stopLayerPostThread() {
        if (layer_post_thread_ != null) {
            layer_post_thread_.stopPost();
            layer_post_thread_ = null;
        }
    }

简单来说,读取到的Bitmap数据,转bytebuffer,然后通过调用PostLayerImageRGBA8888ByteBuffer()接口投递到底层,PostLayerImageRGBA8888ByteBuffer()的接口设计如下:

代码语言:java复制
    /*
     * SmartPublisherJniV2.java
     * Author: daniusdk.com
     */
	/**
	 * 投递层RGBA8888图像,如果不需要Aplpha通道的话, 请使用RGBX8888接口, 效率高
	 *
	 * @param index: 层索引, 必须大于等于0, 注意:如果index是0的话,将忽略Alpha通道
	 *
	 * @param left: 层叠加的左上角坐标, 对于第0层的话传0
	 *
	 * @param top: 层叠加的左上角坐标, 对于第0层的话传0
	 *
	 * @param rgba_plane: rgba 图像数据
	 *
	 * @param offset: 图像偏移, 这个主要目的是用来做clip的, 一般传0
	 *
	 * @param row_stride: stride information
	 *
	 * @param width: width, 必须大于1, 如果是奇数, 将减1
	 *
	 * @param height: height, 必须大于1, 如果是奇数, 将减1
	 *
	 * @param  is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转
	 *
	 * @param  is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转
	 *
	 * @param  scale_width: 缩放宽,必须是偶数, 0或负数不缩放
	 *
	 * @param  scale_height: 缩放高, 必须是偶数, 0或负数不缩放
	 *
	 * @param  scale_filter_mode: 缩放质量, 传0使用默认速度,可选等级范围是:[1,3],值越大缩放质量越好, 但速度越慢
	 *
	 * @param  rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270, 注意:旋转是在缩放, 垂直/水品反转之后再做, 请留意顺序
	 *
	 * @return {0} if successful
	 */
	public native int PostLayerImageRGBA8888ByteBuffer(long handle, int index, int left, int top,
											 ByteBuffer rgba_plane, int offset, int row_stride, int width, int height,
											 int is_vertical_flip,  int is_horizontal_flip,
											 int scale_width,  int scale_height, int scale_filter_mode,
											 int rotation_degree);

这个接口非常强大,可以针对传下去的数据,进行裁剪、反转等各种操作,感兴趣的开发者可以尝试看看。

0 人点赞