Android平台GB28181设备接入侧如何实现GB28181-2022实时快照

​规范解读

GB/T28181-2022相对2016版,除了对H.265、AAC有了明确的说明外,快照也有了具体的要求。源设备向目标设备发送图像抓拍配置命令,携带传输路径、会话ID等信息。目标设备完成图像传输后,发送图像抓拍传输完成通知命令,采用IETF RFC 3428中的MESSAGE方法实现,图像格式宜使用JPEG,图像分辨率宜采用与主码流相同的分辨率。

具体流程如下图:

需要注意的是,MESSAGE消息头Content-type头域要求Content-type:Application/MANSCDP+xml。图像传输方式宜采用http,图像抓拍传输完成通知命令采用MANSCDP协议格式定义。

技术实现

本文以大牛直播SDK实现的Android平台GB28181设备接入模块为例,介绍下快照实现逻辑,需要注意的是,哪怕设备侧不回传,也需要具备快照能力,并保存为jpeg格式,然后按照gb28181规范要求,把采集到的图片,上传到国标平台侧。

先说外部驱动快照:

scss 复制代码
    /*
     * MainActivity.java
     * Author: daniusdk.com
     */
    class ButtonCaptureImageListener implements View.OnClickListener {
        public void onClick(View v) {
            if (null == snap_shot_impl_) {
                snap_shot_impl_ = new SnapShotImpl(image_path_, context_, handler_, libPublisher, snap_shot_publisher_);
                snap_shot_impl_.start();
            }

            startLayerPostThread();
            snap_shot_impl_.set_layer_post_thread(layer_post_thread_);

            snap_shot_impl_.capture();
        }
    }

SnapShotImpl实现如下:

ini 复制代码
    public SnapShotImpl(String dir, Context context, android.os.Handler handler,
                        SmartPublisherJniV2 lib_sdk, LibPublisherWrapper publisher) {
        this.dir_ = dir;

        if (context != null)
            this.context_ = new WeakReference<>(context);

        if (handler != null)
            this.os_handler_ = new WeakReference<>(handler);

        this.lib_sdk_ = lib_sdk;
        this.publisher_ = publisher;
    }

调用capture()的时候,处理逻辑如下:

typescript 复制代码
    protected boolean capture(String file_name, boolean is_update_layers, String user_data) {
        if (is_null_or_empty(file_name)) {
            Log.e(TAG, "capture file name is null");
            return false;
        }

        if (publisher_.empty()) {
            if (!init_sdk_instance()) {
                Log.e(TAG, "init_sdk_instance failed");
                return false;
            }
        }

        if (is_update_layers && layer_post_thread_ != null)
            layer_post_thread_.update_layers();

        boolean ret = publisher_.CaptureImage(0, 100, file_name, user_data);
        if (ret)
            update_sdk_instance_release_time();

        return ret;
    }

其中init_sdk_instance()实现如下:

ini 复制代码
    protected boolean init_sdk_instance() {
        if (!publisher_.empty())
            return true;

        Context context = application_context();
        if (null == context)
            return false;

        if (null == lib_sdk_)
            return false;

        long handle = lib_sdk_.SmartPublisherOpen(context, 0, 3, 1920, 1080);
        if (0 == handle) {
            Log.e(TAG, "init_sdk_instance sdk open failed!");
            return false;
        }

        lib_sdk_.SetSmartPublisherEventCallbackV2(handle, new SDKEventHandler(this));
        lib_sdk_.SmartPublisherSetFPS(handle, 4);
        publisher_.set(lib_sdk_, handle);
        update_sdk_instance_release_time();

        Log.i(TAG, "init_sdk_instance ok handle:" + handle);
        return true;
    }

对接gb28181平台部分,快照状态定义:

arduino 复制代码
        public final static int INITIALIZATION_STATUS = 0; // 初始状态
        public final static int CAPTURING_STATUS = 1; // 抓拍中
        public final static int CAPTURE_COMPLETION_STATUS = 2; // 抓拍完成状态
        public final static int UPLOADING_STATUS = 3; // 图像上传中状态
        public final static int UPLOAD_COMPLETION_STATUS = 4; // 图像上传完成状态
        public final static int ERROR_STATUS = 5; // 错误状态

快照完成后,告知国标平台:

ini 复制代码
        public void notify_server(List<String> notified_files) {
            ArrayList<String> snap_shot_list = new ArrayList(items_.size());
            for (SnapItem i : items_) {
                if (SnapItem.UPLOAD_COMPLETION_STATUS == i.status())
                    snap_shot_list.add(i.gb_snap_shot_file_id());

                if (notified_files != null)
                    notified_files.add(i.file_name());
            }

            if (null == agent_)
                return;

            GBSIPAgent agent = agent_.get();
            if (null == agent)
                return;

            agent.notifyUploadSnapShotFinished(from_user_name_, from_user_name_at_domain_, device_id_, this.session_id(), snap_shot_list);
        }

技术总结

GB28181-2022快照实现,最好是单独开个实例,帧率根据实际快照间隔或者要求,不需要全帧率投递,在不录像不实时回传的时候,也能实现快照逻辑,然后按照规范要求和国标平台侧的客制化诉求,把快照后的文件上传到国标平台。

​

相关推荐
Industio_触觉智能1 天前
瑞芯微RK平台视频硬解排障指南-上|编解码、GStreamer与零拷贝全解析
视频编码·视频编解码·零拷贝·gstreamer·视频解码·rk3576
Hello_Pyhx3 天前
Bilirec 配置入门:录制哔哩哔哩直播间
直播·视频录制·哔哩哔哩·直播工具
屏什么录4 天前
电脑如何录屏幕视频和声音?从工具到代码,7 种方案帮你彻底搞定
前端·音视频开发
VimorphTech4 天前
转写结果怎么生成双语字幕?TypeScript 实现 SRT、WebVTT 与索引匹配
javascript·音视频开发
znnnk5 天前
【网络优化】减少B站直播卡顿的上行占用:AdGuard nowebrtc规则 / WebRTC Control 实测
服务器·网络·webrtc·直播·bilibili·adguard
the3clipse8 天前
VVC码率控制算法:从数学模型到工程落地实战指南
视频编码·vvc·码率控制·r-λ模型·比特分配·x266调优·低延迟直播
音视频牛哥9 天前
人形机器人的未来发展趋势是什么?从VLA、实时视觉到规模化运营
机器学习·机器人·音视频开发
霍营_托尼10 天前
纯前端播 40GB 本地视频?我把浏览器改造成了「磁盘流式」播放器
前端·javascript·音视频开发
the3clipse13 天前
VVenc开源编码器实战指南:H.266/VVC编码工具编译、参数调优与性能测试
视频编码·vvc·h.266·编译安装·vvdec·开源编码器
the3clipse14 天前
H.265全系列总结与H.266/VVC展望:从HEVC核心架构到下一代视频编码标准
视频编码·h.265·hevc·vvc·h.266·视频压缩·ctu