技能背景

早在2015年,咱们发布了RTMP直播推送模块,那时分音视频直播这块场景需求,还不像现在这么普遍,咱们做这块的初衷,首要是为了完成移动单兵应急指挥系统的低推迟音视频数据传输。很多开发者可能会疑惑,走RTMP怎么可能低推迟?网上看到的RTMP推拉流推迟,总归要2-3秒起,假如是自己完成结构,RTMP推拉流逻辑自己完成的话,推迟确实能够操控在毫秒级,这个已无需赘述。

跟着无纸化会议、才智教室、智能化硬件产品的普及,RTMP的技能计划开展一度非常好,有些无人机或智能机器人,都能够自带推送RTMP流数据,合作大牛直播SDK的RTMP低推迟播放器模块,能够完成毫秒级的技能体验。

那为什么后边要做GB28181设备接入模块呢?咱们推出的Android渠道GB28181接入模块的意图,可完成不具备国标音视频才能的 Android终端,经过渠道注册接入到现有的GB/T28181—2016服务,可用于如法律记录仪、智能安全帽、智能监控、才智零售、才智教育、长途工作、明厨亮灶、才智交通、才智工地、雪亮工程、安全乡村、出产运输、车载终端等场景。

GB28181规范,信令和媒体数据分离,能够订阅实时方位信息、云台操控、对焦等,数据传输走TCP或UDP,完成按需查看和语音播送、语音对讲,更成体系化,也更适合有交互的场景。

Android平台音视频推送选RTMP还是GB28181?

咱们完成demo的时分,RTMP推送和GB28181都放到一起了,也便是说,能够一起运用RTMP推送和GB28181设备接入,也能够单独运用。

技能比照

RTMP推送

Android平台音视频推送选RTMP还是GB28181?

RTMP选用的是TCP传输,选用全自研结构,易于扩展,自适应算法让推迟更低、收集编码传输功率更高。推迟合作咱们的播放器,轻松完成毫秒级推迟。

功用规划如下:

  • 音频编码:AAC/SPEEX;
  • 视频编码:H.264、H.265(RTMP扩展H.265);
  • 推流协议:RTMP;
  • [音视频]支撑纯音频/纯视频/音视频推送;
  • [摄像头]支撑收集过程中,前后摄像头实时切换;
  • 支撑帧率、关键帧距离(GOP)、码率(bit-rate)设置;
  • 支撑RTMP推送 live|record形式设置;
  • 支撑前置摄像头镜像设置;
  • 支撑软编码、特定机型硬编码;
  • 支撑横屏、竖屏推送;
  • 支撑Android屏幕收集推送;
  • 支撑自建规范RTMP服务器或CDN;
  • 支撑断网主动重连、网络状况回调;
  • 支撑动态水印(文字、图片);
  • 支撑降噪处理、主动增益操控;
  • 支撑实时快照;
  • 支撑实时静音和实时音量调理;
  • 支撑录像功用扩展(录制MP4文件);
  • 支撑Android 5.1及以上版别。

接口调用如下:

    class ButtonStartPushListener implements View.OnClickListener {
        public void onClick(View v) {
            if (isPushingRtmp) {
                stopPush();
                btnRTMPPusher.setText("推送RTMP");
                return;
            }
            Log.i(TAG, "onClick start push rtmp..");
            if (libPublisher == null)
                return;
            if (!isRTSPPublisherRunning && !isGB28181StreamRunning && !isRecording) {
                InitAndSetConfig();
            }
            if (libPublisher.SmartPublisherSetURL(publisherHandle, rtmp_pusher_url) != 0) {
                Log.e(TAG, "Failed to set publish stream URL..");
            }
            int startRet = libPublisher.SmartPublisherStartPublisher(publisherHandle);
            if (startRet != 0) {
                Log.e(TAG, "Failed to start push stream..");
                return;
            }
            if (!isRTSPPublisherRunning && !isGB28181StreamRunning && !isRecording) {
                CheckInitAudioRecorder();
            }
            startLayerPostThread();
            btnRTMPPusher.setText("中止推送 ");
            isPushingRtmp = true;
        }
    }

中止RTMP推送

    //中止rtmp推送
    private void stopPush() {
        if(!isPushingRtmp)
            return;
        isPushingRtmp = false;
        if (!isRTSPPublisherRunning && !isGB28181StreamRunning && !isRecording)
            stopLayerPostThread();
        if (!isRTSPPublisherRunning && !isGB28181StreamRunning && !isRecording) {
            if (audioRecord_ != null) {
                Log.i(TAG, "stopPush, call audioRecord_.StopRecording..");
                audioRecord_.Stop();
                if (audioRecordCallback_ != null) {
                    audioRecord_.RemoveCallback(audioRecordCallback_);
                    audioRecordCallback_ = null;
                }
                audioRecord_ = null;
            }
        }
        if (null == libPublisher || 0 == publisherHandle)
            return;
        libPublisher.SmartPublisherStopPublisher(publisherHandle);
        if (!isRTSPPublisherRunning && !isGB28181StreamRunning && !isRecording) {
            releasePublisherHandle();
        }
    }

GB/T28181

国标GB/T28181协议全称《安全防范视频监控联网系统信息传输、交流、操控技能要求》,是一个界说视频联网传输和设备操控规范的白皮书,由公安部科技信息化局提出,该规范规则了城市监控报警联网系统中信息传输、交流、操控的互联结构、通信协议结构,传输、交流、操控的基本要求和安全性要求,以及操控、传输流程和协议接口等技能要求。处理了视频间互联互通,数据同享,以及设备操控的问题,这个问题从顶层处理了视频信息各自为战的问题,打通了视频联网的信息孤岛。

支撑对接数据类型:

  1. 编码前数据(现在支撑的有YV12/NV21/NV12/I420/RGB24/RGBA32/RGB565等数据类型);
  2. 编码后数据(如无人机等264/HEVC数据,或许本地解析的MP4音视频数据);
  3. 拉取RTSP或RTMP流并接入至GB28181渠道(比如其他IPC的RTSP流,可经过Android渠道GB28181接入到国标渠道)。

Android平台音视频推送选RTMP还是GB28181?

功用规划如下:

  • 音频编码:G.711 A律、AAC;
  • 视频编码:H.264、H.265;
  • 支撑纯视频、音视频PS打包传输;
  • [摄像头]支撑收集过程中,前后摄像头实时切换;
  • 支撑帧率、关键帧距离(GOP)、码率(bit-rate)设置;
  • 支撑前置摄像头镜像设置;
  • 支撑软编码、特定机型硬编码;
  • 支撑横屏、竖屏推送;
  • 支撑RTP OVER UDP和RTP OVER TCP被动形式(TCP媒体流传输客户端);
  • 支撑信令通道网络传输协议TCP/UDP设置;
  • 支撑注册、刊出,支撑注册刷新及注册有用期设置;
  • 支撑设备目录查询应对;
  • 支撑心跳机制,支撑心跳距离、心跳检测次数设置;
  • 支撑移动设备方位(MobilePosition)订阅和告诉;
  • 支撑云台操控和预置位查询;
  • 支撑设备目录查询应对;
  • 支撑TeleBoot长途发动回调;
  • 支撑语音播送;
  • 支撑语音对讲;
  • 支撑动态水印(文字、图片);
  • 支撑降噪处理、主动增益操控;
  • 支撑实时快照;
  • 支撑实时静音和实时音量调理;
  • 支撑录像功用扩展(录制MP4文件);
  • 适用国家规范:GB/T 28181—2016;
  • 支撑Android 5.1以上版别。

信令处理

GBSIPAgentListener首要系GB28181注册、心跳、DevicePosition等,如注册成功、注册超时、注册网络传输层错误、心跳反常、设备方位恳求处理:

public interface GBSIPAgentListener
{
    /*注册成功
    * @param dateString: 服务器日期,用来校准设备端时刻,用户自行决定是否校准设备时刻
    */
    void ntsRegisterOK(String dateString);
    /*
    *注册超时
    */
    void ntsRegisterTimeout();
    /*
    *注册网络传输层反常
    */
    void ntsRegisterTransportError(String errorInfo);
    /*
    *心跳达到反常次数
    */
    void ntsOnHeartBeatException(int exceptionCount, String lastExceptionInfo);
    /*
     * 设备方位恳求, 这个首要用在移动设备方位订阅上
     * @param interval 恳求距离, 单位是毫秒
     */
    void ntsOnDevicePositionRequest(String deviceId, int interval);
}

GBSIPAgentPlayListener首要系GB28181的Invite、Ack、Bye等处理:

public interface GBSIPAgentPlayListener {
    /*
     *收到s=Play的实时视音频点播
     */
    void ntsOnInvitePlay(String deviceId, SessionDescription sessionDescription);
    /*
     *发送play invite response 反常
     */
    void ntsOnPlayInviteResponseException(String deviceId, int statusCode, String errorInfo);
    /*
     * 收到CANCEL play INVITE恳求
     */
    void ntsOnCancelPlay(String deviceId);
    /*
     * 收到Ack
     */
    void ntsOnAckPlay(String deviceId);
    /*
     * 收到Bye
     */
    void ntsOnByePlay(String deviceId);
    /*
     * 不是在收到BYE Message情况下, 停止Play
     */
    void ntsOnTerminatePlay(String deviceId);
    /*
     * Play会话对应的对话停止, 一般不会动身这个回调,现在只要在呼应了200K, 但在64*T1时刻后还没收到ACK,才可能会动身
    收到这个, 请做相关清理处理
    */
    void ntsOnPlayDialogTerminated(String deviceId);
}

GBSIPAgentAudioBroadcastListener首要系GB28181语音播送处理相关,如有语音播送相关需求,可参照demo实例完成:

public interface GBSIPAgentAudioBroadcastListener {
    /*
     *收到语音播送告诉
     */
    void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID);
    /*
     *需求准备接受语音播送的SDP内容
     */
    void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID);
    /*
     *音频播送, 发送Invite恳求反常
     */
    void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo);
    /*
     *音频播送, 等待Invite呼应超时
     */
    void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID);
    /*
     *音频播送, 收到Invite消息终究呼应
     */
    void ntsOnInviteAudioBroadcastResponse(String sourceID, String targetID, int statusCode, SessionDescription sessionDescription);
    /*
     * 音频播送, 收到BYE Message
     */
    void ntsOnByeAudioBroadcast(String sourceID, String targetID);
    /*
     * 不是在收到BYE Message情况下, 停止音频播送
     */
    void ntsOnTerminateAudioBroadcast(String sourceID, String targetID);
}

GBSIPAgentDeviceControlListener首要系GB28181设备操控相关,比如长途发动、云台操控:

public interface GBSIPAgentDeviceControlListener {
    /*
     * 收到长途发动操控指令
     */
    void ntsOnDeviceControlTeleBootCommand(String deviceId, String teleBootValue);
    /*
    * 云台操控
     */
    void ntsOnDeviceControlPTZCmd(String deviceId, String typeValue);
}

GBSIPAgentQueryCommandListener首要系GB28181查询指令,如预置位查询:

public interface GBSIPAgentQueryCommandListener {
    /*
     * 设备预置位查询
     */
    void ntsOnDevicePresetQueryCommand(String fromUserName, String fromUserNameAtDomain, String sn, String deviceId);
}

GBSIPAgentTalkListener首要系GB28181语音对讲相关处理:

public interface GBSIPAgentTalkListener {
    /*
     *收到s=Talk 语音对讲
     */
    void ntsOnInviteTalk(String deviceId, SessionDescription sessionDescription);
    /*
     *发送talk invite response 反常
     */
    void ntsOnTalkInviteResponseException(String deviceId, int statusCode, String errorInfo);
    /*
     * 收到CANCEL Talk INVITE恳求
     */
    void ntsOnCancelTalk(String deviceId);
    /*
     * 收到Ack
     */
    void ntsOnAckTalk(String deviceId);
    /*
     * 收到Bye
     */
    void ntsOnByeTalk(String deviceId);
    /*
     * 不是在收到BYE Message情况下, 停止Talk
     */
    void ntsOnTerminateTalk(String deviceId);
    /*
     * Talk会话对应的对话停止, 一般不会动身这个回调,现在只要在呼应了200K, 但在64*T1时刻后还没收到ACK,才可能会动身
    收到这个, 请做相关清理处理
    */
    void ntsOnTalkDialogTerminated(String deviceId);
}

媒体数据处理

RTP数据发送

RTP Sender(SmartPublisherJniV2.java)相关接口规划:

/*
 * SmartPublisherJniV2.java
 * Author: https://daniusdk.com
 */
/*
 * 创建RTP Sender实例
 *
 * @param reserve:保存参数传0
 *
 * @return RTP Sender 句柄,0表明失利
 */
public native long CreateRTPSender(int reserve);
/**
 *设置 RTP Sender传输协议
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param transport_protocol, 0:UDP, 1:TCP, 默许是UDP
 *
 * @return {0} if successful
 */
public native int SetRTPSenderTransportProtocol(long rtp_sender_handle, int transport_protocol);
/**
 *设置 RTP Sender IP地址类型
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param ip_address_type, 0:IPV4, 1:IPV6, 默许是IPV4, 当前仅支撑IPV4
 *
 * @return {0} if successful
 */
public native int SetRTPSenderIPAddressType(long rtp_sender_handle, int ip_address_type);
/**
 *设置 RTP Sender RTP Socket本地端口
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param port, 有必要是偶数,设置0的话SDK会主动分配, 默许值是0
 *
 * @return {0} if successful
 */
public native int SetRTPSenderLocalPort(long rtp_sender_handle, int port);
/**
 *设置 RTP Sender SSRC
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param ssrc, 假如设置的话,这个字符串要能转换成uint32类型, 否则设置失利
 *
 * @return {0} if successful
 */
public native int SetRTPSenderSSRC(long rtp_sender_handle, String ssrc);
/**
 *设置 RTP Sender RTP socket 发送Buffer巨细
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param buffer_size, 有必要大于0, 默许是512*1024, 当前仅对UDP socket有用, 依据视频码率考虑设置适宜的值
 *
 * @return {0} if successful
 */
public native int SetRTPSenderSocketSendBuffer(long rtp_sender_handle, int buffer_size);
/**
 *设置 RTP Sender RTP时刻戳时钟频率
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param clock_rate, 有必要大于0, 关于GB28181 PS规则是90kHz, 也便是90000
 *
 * @return {0} if successful
 */
public native int SetRTPSenderClockRate(long rtp_sender_handle, int clock_rate);
/**
 *设置 RTP Sender 意图IP地址, 注意当前用在GB2818推送上,只设置一个地址,将来扩展假如用在其他地方,可能要设置多个意图地址,到时分接口可能会调整
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param address, IP地址
 * @param port, 端口
 *
 * @return {0} if successful
 */
public native int SetRTPSenderDestination(long rtp_sender_handle, String address, int port);
/**
 * 设置是否敞开 RTP Receiver
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param is_enable, 0表明不收RTP包, 1表明收RTP包, SDK默许值为0.
 * @return
 */
public native int EnableRTPSenderReceive(long rtp_sender_handle, int is_enable);
/**
 *设置RTP Receiver SSRC
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param ssrc, 假如设置的话,这个字符串要能转换成uint32类型, 否则设置失利
 *
 * @return {0} if successful
 */
public native int SetRTPSenderReceiveSSRC(long rtp_sender_handle, String ssrc);
/**
 *设置RTP Receiver Payload 相关信息
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @param payload_type, 请参阅 RFC 3551
 *
 * @param encoding_name, 编码名, 请参阅 RFC 3551, 假如payload_type不是动态的, 可能传null就好
 *
 * @param media_type, 媒体类型, 请参阅 RFC 3551, 1 是视频, 2是音频
 *
 * @param clock_rate, 请参阅 RFC 3551
 *
 * @return {0} if successful
 */
public native int SetRTPSenderReceivePayloadType(long rtp_sender_handle, int payload_type, String encoding_name, int media_type, int clock_rate);
/**
 *设置RTP Receiver PS的pts和dts clock frequency
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @param ps_clock_frequency, 默许是90000, 一些特别场景需求设置
 *
 * @return {0} if successful
 */
public native int SetRTPSenderReceivePSClockFrequency(long rtp_sender_handle, int ps_clock_frequency);
/**
 *设置 RTP Receiver 音频采样率
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param sampling_rate, 音频采样率
 *
 * @return {0} if successful
 */
public native int SetRTPSenderReceiveAudioSamplingRate(long rtp_sender_handle, int sampling_rate);
/**
 *设置 RTP Receiver 音频通道数
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 * @param channels, 音频通道数
 *
 * @return {0} if successful
 */
public native int SetRTPSenderReceiveAudioChannels(long rtp_sender_handle, int channels);
/**
 *初始化RTP Sender, 初始化之前先调用上面的接口配置相关参数
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @return {0} if successful
 */
public native int InitRTPSender(long rtp_sender_handle);
/**
 *获取RTP Sender RTP Socket本地端口
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @return 失利回来0, 成功的话回来呼应的端口, 请在InitRTPSender回来成功之后调用
 */
public native int GetRTPSenderLocalPort(long rtp_sender_handle);
/**
 * UnInit RTP Sender
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @return {0} if successful
 */
public native int UnInitRTPSender(long rtp_sender_handle);
/**
 * 开释RTP Sender, 开释之后rtp_sender_handle就无效了,请不要再运用
 *
 * @param rtp_sender_handle, CreateRTPSender回来值
 *
 * @return {0} if successful
 */
public native int DestoryRTPSender(long rtp_sender_handle);

RTP数据接纳

对应RTP Receiver(SmartPlayerJniV2.java)相关接口规划,如无语音播送或语音对讲相关技能需求,这部分可疏忽:

/*
 * SmartPlayerJniV2.java
 * Author: https://daniusdk.com
 */
/*
 * 创建RTP Receiver
 *
 * @param reserve:保存参数传0
 *
 * @return RTP Receiver 句柄,0表明失利
 */
public native long CreateRTPReceiver(int reserve);
/**
 *设置 RTP Receiver传输协议
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param transport_protocol, 0:UDP, 1:TCP, 默许是UDP
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverTransportProtocol(long rtp_receiver_handle, int transport_protocol);
/**
 *设置 RTP Receiver IP地址类型
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param ip_address_type, 0:IPV4, 1:IPV6, 默许是IPV4
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverIPAddressType(long rtp_receiver_handle, int ip_address_type);
/**
 *设置 RTP Receiver RTP Socket本地端口
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param port, 有必要是偶数,设置0的话SDK会主动分配, 默许值是0
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverLocalPort(long rtp_receiver_handle, int port);
/**
 *设置 RTP Receiver SSRC
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param ssrc, 假如设置的话,这个字符串要能转换成uint32类型, 否则设置失利
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverSSRC(long rtp_receiver_handle, String ssrc);
/**
 *创建 RTP Receiver 会话
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param reserve, 保存值,现在传0
 *
 * @return {0} if successful
 */
public native int CreateRTPReceiverSession(long rtp_receiver_handle, int reserve);
/**
 *获取 RTP Receiver RTP Socket本地端口
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @return 失利回来0, 成功的话回来呼应的端口, 请在CreateRTPReceiverSession回来成功之后调用
 */
public native int GetRTPReceiverLocalPort(long rtp_receiver_handle);
/**
 *设置 RTP Receiver Payload 相关信息
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @param payload_type, 请参阅 RFC 3551
 *
 * @param encoding_name, 编码名, 请参阅 RFC 3551, 假如payload_type不是动态的, 可能传null就好
 *
 * @param media_type, 媒体类型, 请参阅 RFC 3551, 1 是视频, 2是音频
 *
 * @param clock_rate, 请参阅 RFC 3551
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverPayloadType(long rtp_receiver_handle, int payload_type, String encoding_name, int media_type, int clock_rate);
/**
 *设置 RTP Receiver 音频采样率
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param sampling_rate, 音频采样率
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverAudioSamplingRate(long rtp_receiver_handle, int sampling_rate);
/**
 *设置 RTP Receiver 音频通道数
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param channels, 音频通道数
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverAudioChannels(long rtp_receiver_handle, int channels);
/**
 *设置 RTP Receiver 远端地址
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 * @param address, IP地址
 * @param port, 端口
 *
 * @return {0} if successful
 */
public native int SetRTPReceiverRemoteAddress(long rtp_receiver_handle, String address, int port);
/**
 *初始化 RTP Receiver
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @return {0} if successful
 */
public native int InitRTPReceiver(long rtp_receiver_handle);
/**
 *UnInit RTP Receiver
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @return {0} if successful
 */
public native int UnInitRTPReceiver(long rtp_receiver_handle);
/**
 *Destory RTP Receiver Session
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @return {0} if successful
 */
public native int DestoryRTPReceiverSession(long rtp_receiver_handle);
/**
 *Destory RTP Receiver
 *
 * @param rtp_receiver_handle, CreateRTPReceiver
 *
 * @return {0} if successful
 */
public native int DestoryRTPReceiver(long rtp_receiver_handle);

PostAudioPacket(SmartPlayerJniV2.java),投递音频包给外部Live source,现在仅于语音对讲运用:

/*
 * SmartPlayerJniV2.java
 * Author: https://daniusdk.com
 */
/**
 * 投递音频包给外部Live source, 注意ByteBuffer对象有必要是DirectBuffer
 *
 * @param handle: return value from SmartPlayerOpen()
 *
 * @return {0} if successful
 */
public native int PostAudioPacket(long handle, int codec_id,
                          java.nio.ByteBuffer packet, int offset, int size, long pts, boolean is_pts_discontinuity,
                          java.nio.ByteBuffer extra_data, int extra_data_offset, int extra_data_size, int sample_rate, int channels);

总结

Android渠道音视频数据流转,首要还看技能计划挑选怎样的场景,假如是对接法律记录仪、智能安全帽、智能监控、才智零售、才智教育、长途工作、明厨亮灶、才智交通、才智工地、雪亮工程、安全乡村、出产运输、车载终端等场景等,现在挑选GB28181的更多一些,假如首要是上云或许无纸化同屏、才智教室等,还是RTMP推送多一些。详细能够依据场景挑选适合自己的技能计划。

大家比较担心推迟问题,假如GB28181渠道侧走RTMP或许webrtc的话,推迟也不大,和RTMP计划一样,整体都能够做到毫秒级。