自建国标设备接入的常见问题

当用户自建的国标设备出现接入异常情况时,在确认设备接入和功能实现符合GB/T 28181-2016协议规范定义的前提下,可以参考本文从信令和流媒体的角度排查问题。

信令接入常见问题

IPC设备、NVR主设备上线失败

  1. 检查自建国标设备配置的服务器IP和端口号是否正确。

  2. 抓包检查设备是否与服务器完成两阶段注册交互:

    • 设备向服务器发送首次REGISTER报文。

    • 服务器向设备回复401 Unauthorized报文,并携带用于鉴权的WWW-Authenticate字段。

    • 设备向服务器发送二次REGISTER报文,相比首次REGISTER报文,携带用于鉴权的Authorization字段。

    • 服务器向设备回复200 OK报文:

      • 如果发现接收不到来自服务器的报文,检查网络联通性。

      • 如果发现服务器始终回复401 Unauthorized报文,检查密码填写是否正确。二次REGISTER报文是否包含用于鉴权的Authorization字段。

      • 如果发现服务器始终回复400 Bad Request报文,检查服务器或设备国标ID填写是否正确。

NVR视频通道(子设备)上线失败

  1. 检查自建国标设备的视频通道(子设备)配置是否正确。

  2. 抓包检查设备是否与服务器完成查询子设备目录的交互:

    • 服务器向设备发送MESSAGE报文,报文体包含<Query>,Catalog,查询子设备目录。

    • 设备向服务器回复200 OK报文。

    • 设备向服务器发送MESSAGE报文,报文体包含<Response>,Catalog,回复子设备目录(可能多条)。

    • 服务器向设备回复200 OK报文(如果多条,则一一对应):

      1. 如果发现接收不到来自服务器的报文,请检查网络联通性。

      2. 如果交互均正常,检查设备发送MESSAGE报文速度是否过慢。

        • 设备发送首条MESSAGE报文,距离服务发送MESSAGE报文时间间隔应当低于1000毫秒。

        • 设备发送一条MESSAGE报文,距离设备发送上一条MESSAGE报文时间间隔应当低于1000毫秒。

        • 设备发送所有MESSAGE报文总时间应当低于3000毫秒。

获取设备录像文件失败

  1. 检查自建国标设备在查询时段内是否存在录像文件。

  2. 抓包检查设备是否与服务器完成查询录像文件的交互:

    • 服务器向设备发送MESSAGE报文,报文体包含<Query>,RecordInfo,查询录像文件。

    • 设备向服务器回复200 OK报文。

    • 设备向服务器发送 MESSAGE 报文,报文体包含<Response>,RecordInfo,回复录像文件(可能多条)。

    • 服务器向设备回复200 OK报文(如果多条,则一一对应):

      1. 如果发现接收不到来自服务器的报文,检查网络联通性。

      2. 如果交互均正常,检查设备发送MESSAGE报文速度是否过慢。

        • 设备发送首条MESSAGE报文,距离服务端发送MESSAGE报文的时间间隔应当低于500毫秒。

        • 设备发送一条MESSAGE报文,距离设备发送上一条MESSAGE报文的时间间隔应当低于500毫秒。

        • 设备发送所有MESSAGE报文的总时间应当低于2000毫秒。

设备直播、点播失败

抓包检查设备是否与服务器完成直播、点播的信令交互:

  • 服务器向设备发送INVITE报文,报文体包含SDP消息内容。

  • 设备向服务器回复100 Trying报文(中间报文,可能无)。

  • 设备向服务器回复101 Dialog Establishment报文(中间报文,可能无)。

  • 设备向服务器回复200 OK报文,报文体包含SDP消息内容。

  • 服务器向设备回复ACK报文:

    1. 如果发现接收不到来自服务器的报文,检查网络联通性。

    2. 如果发现设备回复503 Service Unavailable,检查设备是否处于可用状态,或重启设备。

    3. 如果发现设备回复486 Busy Here,检查设备是否被邀请同时推主码流和子码流。

    4. 部分国标设备不支持同时推多路直播流,且国标设备不区分主、子码流,邀请同时推主码流和子码流会导致异常。

    5. 如果发现服务不回复ACK,检查设备回复200 OK是否速度过慢,设备回复200 OK,距离服务发送INVITE报文时间间隔应当低于2000毫秒。

流媒体接入常见问题

设备直播、点播失败

  1. 根据信令接入常见问题设备直播、点播失败,检查信令交互阶段是否有异常。

  2. 物联网智能视频服务仅支持RTP/PS/H.264(H.265)+AAC的流媒体数据封包格式和TCP流媒体传输模式,即视频编码格式采用H.264H.265,音频编码格式采用AAC,音视频流封装格式采用PS,实时传输协议采用RTP,收流传输层协议采用TCP。需逐一检查设备实现是否符合协议标准。

    1. GB/T 28181-2016定义TCP收流的RTP封装需要符合RFC 4571标准,即RTP over TCP相比RTP over UDP的封包格式,在RTP头部前有2字节的标识信息:length用于标识后续RTP报文的长度。以上信息的缺失或错误会导致RTP解码失败。

      RTP包外格式信息:

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |            length             |         RTP Packet...         
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    2. 检查RTP头部中填充的SSRC字段,是否与信令交互中INVITE报文中SDP报文体的y字段标识的SSRC相等。

      物联网智能视频服务使用SSRC字段进行流鉴权,SSRC字段来源有误,会导致流鉴权失败。

      说明

      如果SSRC填写正确,仍然鉴权失败,请切换大小端写入方式重试。

      RTP头部格式信息:

       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |V=2|P|X|  CC   |M|     PT      |       sequence number         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           timestamp                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |           synchronization source (SSRC) identifier            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      |           contributing source (CSRC) identifiers...           |
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    3. 检查推流的首个关键帧是否为包含spspps等信息的sequence header帧。获取不到sequence header关键帧,会导致后续收流失败。

    4. 检查RTP载荷的视频数据格式是否正确:

      1. 使用抓包工具抓取设备端向服务器发送的流媒体数据包。

      2. 获取RTP裸流数据:可以使用Wireshark打开抓包获得的pcap/pcapng文件,跟踪该RTP流数据的TCP流,用Raw格式展示抓取的RTP裸流数据。

        image

      3. 保存为rtp.raw文件。

        image

      4. 获取PS流数据。使用下面的脚本将rtp.raw解析为demux.ps文件。

        import struct
        
        def parse_rtp_packet(rtp_packet):
            """
            解析RTP报文,并返回序列号、SSRC和有效载荷。
            """
            # 解析固定的RTP头部,长度为12字节
            rtp_header_format = '!BBHII'
            rtp_header_length = struct.calcsize(rtp_header_format)
            rtp_header = rtp_packet[:rtp_header_length]
            _, _, sequence_number, _, ssrc = struct.unpack(rtp_header_format, rtp_header)
            payload = rtp_packet[rtp_header_length:]  # 跳过固定头部,获取载荷
            return sequence_number, ssrc, payload
        
        def parse_rtp_stream(file_path, output_path):
            """
            解析RTP流并将载荷数据保存到文件中。
            """
            with open(file_path, 'rb') as f, open(output_path, 'wb') as out:
                while True:
                    # 读取2字节的长度字段
                    length_data = f.read(2)
                    if not length_data:
                        break  # 文件结束
                    # 解析长度字段,获取RTP报文长度
                    (rtp_packet_length,) = struct.unpack('!H', length_data)
                    # 读取RTP报文
                    rtp_packet = f.read(rtp_packet_length)
                    if len(rtp_packet) != rtp_packet_length:
                        print("Warning: RTP packet length mismatch. Expected: {}, got: {}".format(rtp_packet_length, len(rtp_packet)))
                        break  # 数据长度不符,可能是文件损坏或读取错误
                    # 解析RTP报文
                    sequence_number, ssrc, payload = parse_rtp_packet(rtp_packet)
                    print("Sequence: {}, SSRC: {}".format(sequence_number, ssrc))
                    # 将载荷写入输出文件
                    out.write(payload)
        
        # 文件路径和输出路径
        rtp_file_path = 'rtp.raw'
        output_payload_path = 'demux.ps'
        
        # 解析RTP流并保存载荷
        parse_rtp_stream(rtp_file_path, output_payload_path)
        

        RTP裸流数据包含多个RTP数据包,数据包的SSRC相同。如果发现数据包的SSRC不相同,检查RTP包外格式信息和RTP头部格式信息。

        image

      5. 使用FFplay工具播放demux.ps文件,观察是否符合预期。

        image