当前位置: 首页 > news >正文

接入海康设备mark全是false解决方案

原因

问题:tpline/宇视接入正常,海康设备没有画面和音频。

排查方向:

1.抓包发现海康设备mark全是false,rtp完整帧判断没有做时间戳判断单独处理

2.扩展rtp时间戳判断完整帧机制后,dump解析后的文件只有I帧,音频存在问题。因此解析ps逻辑后的流有问题。

从wreshark抓包看mark最后一帧下一个包的起始数据,然后看dump抓包文件16进制。判断地址区间是否只有一种数据,如果存在音视频都有,需要特别处理。

根据00 00 01 e0/c0判断 0000A870之前的地址是否同时存在音视频数据。那就说明rtp的一帧判断机制是包含音视频数据,需要做特别处理。 

1.锁定rtp完整一帧的本地文件区间,判断区间内是否同时存在e0/c0

tpline/宇视属于rtp完整一帧只有音频or视频

回归海康设备 

查看时间戳分界的最后一个包,查看二进制数据与dump完整对比。

第0个rtp完整帧(rtp时间戳相同)最后一帧  没看到同时存在音视频起始码,因为I帧过大原因

0210   ed 5a 1b 96 f3 41 04 c1 b3 23 ff 97 4c 67 f1 e9   .Z...A...#..Lg..
0220   90 63 ed 76 bf 84 54 33 b9 7f 6f a6 92 0d 30 e4   .c.v..T3..o...0.
0230   40 6c c1 f6 26 f9 02 e2 84 3f cc 59 2c d0 72 47   @l..&....?.Y,.rG
0240   8c 44 e3 5d 08 c7 88 1c ff d3 f9 5e 3b ff ff 0c   .D.].......^;...
0250   b5 f4 00 00 01 bd 00 6a 8c 80 07 2f d4 e5 06 31   .......j.../...1
0260   ff f8 00 02 00 17 00 01 80 00 23 ff a2 a0 e0 f1   ..........#.....
0270   f0 50 e0 67 2e cb e6 58 60 a4 47 17 5b 46 1f d5   .P.g...X`.G.[F..
0280   cb 77 6d 25 82 e7 39 49 13 e7 c0 90 9d 9a 40 46   .wm%..9I......@F
0290   f7 de ed c8 22 2e 3c fb db be 43 94 59 d2 b5 c6   ....".<...C.Y...
02a0   cc ad ed c8 22 2e 3c fb db be 43 94 59 d2 b5 c6   ....".<...C.Y...
02b0   cc ad ff 6c b3 c1 9e 78 eb ff ea 65 d9 21 a9 09   ...l...x...e.!..
02c0   cf 87                

第1个rtp完整帧(rtp时间戳相同)

第一个包
0000   00 0c 29 01 52 cc 04 bd 70 26 71 27 08 00 45 00   ..).R...p&q'..E.
0010   01 78 4f fb 40 00 3f 11 73 f8 ac 19 08 52 c0 a8   .xO.@.?.s....R..
0020   01 6e 3a d4 33 91 01 64 ca e3 80 60 00 47 00 00   .n:.3..d...`.G..
0030   0e 10 0b eb df 7c 00 00 01 c0
第二个包
0020   01 6e 3a d4 33 91 05 8c 07 d1 80 60 00 48 00 00   .n:.3......`.H..
0030   0e 10 0b eb df 7c 00 00 01 ba 7f 53 94 89 44 01   .....|.....S..D.
0040   01 36 6b fe ff ff 00 23 a2 a1 00 00 01 e0 0d 02   .6k....#........
0050   8c 80 08 2f d4 e5 22 51 ff ff f8 00 00 00 01 41   .../.."Q.......A

第2个rtp完整帧(rtp时间戳相同)

第一个包

0010   01 78 50 01 40 00 3f 11 73 f2 ac 19 08 52 c0 a8   .xP.@.?.s....R..
0020   01 6e 3a d4 33 91 01 64 7c 9b 80 60 00 4b 00 00   .n:.3..d|..`.K..
0030   1c 20 0b eb df 7c 00 00 01 c0 01 4a 8c 80 07 2f   . ...|.....J.../

第二个包

0000   00 0c 29 01 52 cc 04 bd 70 26 71 27 08 00 45 00   ..).R...p&q'..E.
0010   05 a0 50 03 40 00 3f 11 6f c8 ac 19 08 52 c0 a8   ..P.@.?.o....R..
0020   01 6e 3a d4 33 91 05 8c 0f 1b 80 60 00 4c 00 00   .n:.3......`.L..
0030   1c 20 0b eb df 7c 00 00 01 ba 7f 53 94 f9 c4 01   . ...|.....S....
0040   01 36 6b fe ff ff 00 23 a2 a2 00 00 01 e0 0c 22   .6k....#......." 

调试过程中,发现海康ps流携带了bd,记录一下。 

因此解析rtp包后,解析ps流时,需要对完整帧做音频和视频直接处理。

代码

rtp完整帧,时间戳判断

std::vector<std::unique_ptr<PacketBuffer::Packet>> PacketBuffer::FindFrames(uint64_t seq_num)
{last_rtp_seq_num = seq_num;std::vector<std::unique_ptr<PacketBuffer::Packet>> found_frames;for (size_t i = 0; i < buffer_.size(); ++i){size_t cur_index = seq_num % buffer_.size();const auto &cur_entry = buffer_[cur_index];size_t index = (seq_num-1+buffer_.size()) % buffer_.size();const auto &entry = buffer_[index];if (entry == nullptr || cur_entry == nullptr)break;if (entry->marker_bit || cur_entry->timestamp != entry->timestamp){int64_t start_seq_num = seq_num - 1 ;int start_index = index;uint64_t last_packet_receive_time_ms = entry->receive_time_ms;bool continuous = true;while (true){if (first_seq_num_ == start_seq_num)break;if (start_seq_num - 1 == last_sent_seq_num_)break;start_index = start_index > 0 ? start_index - 1 : buffer_.size() - 1;if (buffer_[start_index] == nullptr){uint64_t recv_time = GetPrePacketReceiveTimeMs(start_seq_num);if (last_packet_receive_time_ms - recv_time <= kDefaultPacketTimeoutInterval){continuous = false;RT_FUNC_DEBUG_TRACE_THIS(",start_seq_num = " << start_seq_num<<" last_packet_receive_time_ms=" << last_packet_receive_time_ms<<" recv_time=" << recv_time);break;}}else{// last_packet_receive_time_ms = buffer_[start_index]->receive_time_ms;}--start_seq_num;}if (continuous){const uint64_t end_seq_num = seq_num;uint16_t num_packets = end_seq_num - start_seq_num;found_frames.reserve(found_frames.size() + num_packets);for (uint64_t i = start_seq_num; i != end_seq_num; ++i){std::unique_ptr<Packet> &packet = buffer_[i % buffer_.size()];if (packet == nullptr)continue;found_frames.push_back(std::move(packet));}}else{break;}}++seq_num;}return found_frames;
}

解析ps流代码示例

void GB28181StreamParser::ParserStream(rtc::CopyOnWriteBuffer payload)
{uint8_t *buf = payload.data(); // 获取载荷数据和长度unsigned int len = payload.size();std::unique_ptr<MediaFrame> frame = std::make_unique<MediaFrame>();frame->frameType_ = FRAME_TYPE_P;frame->timestamp_ = -1;// 解析 PS 流uint8_t *pos = buf;uint8_t *posLast = pos;while (pos - buf < len){int curHdrLen = 0;int curDataLen = -1;// 检查 PS 包头if (0x00 == pos[0] && 0x00 == pos[1] && 0x01 == pos[2]){curDataLen = 0;// 根据不同的包类型进行处理if (0xBA == pos[3]) // 处理 PS 包头{ uint8_t stuffingLen = (*(uint8_t *)(pos + 13)); // 跳过 9 个字节,暂时不关心它的内容,看第 10 个字节stuffingLen &= 0x07; // 取低 3 位,长度就是是扩展内容curHdrLen = 14 + stuffingLen;pos += curHdrLen; // 移动指针到下一个包}else if (0xBB == pos[3]) // 处理系统头{ // 处理系统头uint16_t systemHeaderLen = ntohs(*(uint16_t *)(pos + 4));  // 两个字节的系统头长度curHdrLen = systemHeaderLen + 6;pos += curHdrLen; // 移动指针到下一个包}else if (0xBC == pos[3])  // I帧,psm头{   // 处理节目流图,可能包含 stream_typeframe->frameType_ = FRAME_TYPE_I;// frame->width_ = *(uint8_t *)(pos + 26) * 8;// frame->height_ = *(uint8_t *)(pos + 27) * 8;int offset = 8;uint16_t ps_info_len = ntohs(*(uint16_t *)(pos + offset));offset += (2 + ps_info_len);uint16_t es_map_len = ntohs(*(uint16_t *)(pos + offset));offset += 2;for (int i = 0; i <= es_map_len - 4;) {uint8_t stream_type = pos[offset + i];uint8_t stream_id = pos[offset + i + 1];if (0xE0 == stream_id) {video_stream_type_ = stream_type;if(0x1B != stream_type && 0x24 != stream_type){RT_FUNC_WARNING_TRACE_THIS("unknow video stream_type: " << stream_type);}} else if (0xC0 == stream_id ) {audio_stream_type_ = stream_type;// 0x92  G.722.1 (not supported)// 0x93  G.723.1 (not supported)// 0x99 G.729 (not supported)// 0x9B SVAC (not supported)if(0x0F != stream_type&& 0x91 != stream_type && 0x90 != stream_type){RT_FUNC_WARNING_TRACE_THIS("unknow audio stream_type: " << stream_type);}}uint16_t es_info_len =ntohs(*(uint16_t *)(pos + offset + i + 2));i += (4 + es_info_len);}uint16_t mapHeaderLen = ntohs(*(uint16_t *)(pos + 4));curHdrLen = mapHeaderLen + 6;pos += curHdrLen;}else if (0xBD == pos[3]) // 处理私有数据{uint16_t pesPacketLen = ntohs(*(uint16_t *)(pos + 4));curHdrLen = pesPacketLen + 6;pos += curHdrLen;}else if (0xC0 == pos[3]) // 处理音频 PES{OnCompleteFrame_i(std::move(frame));frame = std::make_unique<MediaFrame>();frame->frameType_ = FRAME_TYPE_A; // 设置帧类型为音频帧frame->timestamp_ = m_curFrameNormalTs;if(0x0F == audio_stream_type_){     // AACframe->streamType_ = AAC_TYPE;}else if(0x90 == audio_stream_type_){ //  G.711 Aframe->streamType_ = PCMA_TYPE;}else if(0x91 == audio_stream_type_)  // G.711 U{frame->streamType_ = PCMU_TYPE;}else{frame->streamType_ = OTHER_TYPE;}uint16_t pesPacketLen = ntohs(*(uint16_t *)(pos + 4));uint8_t stuffingLen = (*(uint8_t *)(pos + 8));curHdrLen = 9 + stuffingLen;pos += curHdrLen;curDataLen = pesPacketLen - stuffingLen - 3;}else if (0xE0 == pos[3]) // 处理视频 PES{//海康设备因根据rtp.timestamp判断完整一帧,导致视频帧和音频帧混在一起。//因音频处理时重新设置了音频类型,因此需要重新设置。并且防止音频帧和视频帧混在一起,需直接处理完整一帧音频数据。if(frame->frameType_ == FRAME_TYPE_A){OnCompleteFrame_i(std::move(frame));frame = std::make_unique<MediaFrame>();frame->timestamp_ = m_curFrameNormalTs;frame->frameType_ = FRAME_TYPE_P;}if(0x1B == video_stream_type_){frame->streamType_ = H264_TYPE;}else if(0x24 == video_stream_type_){frame->streamType_ = H265_TYPE;}else{frame->streamType_ = OTHER_TYPE;}uint16_t pesPacketLen = ntohs(*(uint16_t *)(pos + 4));uint8_t stuffingLen = (*(uint8_t *)(pos + 8));curHdrLen = 9 + stuffingLen;pos += curHdrLen;curDataLen = pesPacketLen - stuffingLen - 3;}}// 处理剩余数据,PES Bodyint remainLen = len - (pos - buf);if (remainLen <= 0)break;curDataLen = -1 == curDataLen ? 1 : curDataLen;if (curDataLen > 0){int copyLen = remainLen < curDataLen ? remainLen : curDataLen;frame->append(pos, copyLen);pos += copyLen;}if (posLast == pos){pos += 1;static int time = 0;if (time++ % 1024 == 0){RT_FUNC_WARNING_TRACE_THIS(" not found ps header");}}posLast = pos;}// 处理完整帧OnCompleteFrame_i(std::move(frame));
}

最后成功接入海康设备,音视频画面正常。


总结

  1. 海康设备发出的rtp数据是mark位字段全是false。
  2. 海康设备音频格式布局是0XBD + 0XC0,与前两者不同,有携带私有数据字段。
  3. 使用时间戳机制判断rtp完整帧,完整帧存在同时拥有音频和视频。在解析ps流时需要视频和音频要直接处理。

http://www.dtcms.com/a/294590.html

相关文章:

  • Elasticsearch整合:Repository+RestClient双模式查询优化
  • 【杂谈】-代理协议:重塑AI协作新生态,开启智能互联新时代
  • 开闭原则在C++中的实现
  • InfluxDB HTTP API 接口调用详解(二)
  • [HarmonyOS] 鸿蒙LiteOS-A内核深度解析 —— 面向 IoT 与智能终端的“小而强大”内核
  • 算法第27天|贪心算法:合并区间 、单调递增的数字
  • 面试实战,问题七,Object类中包含哪些常用方法及其作用,怎么回答
  • biji 1
  • 开源 Arkts 鸿蒙应用 开发(十)通讯--Http数据传输
  • RAG深入理解和简易实现
  • Linux基础服务(Crontab和NFS)
  • 解决报错:ModuleNotFoundError: No module named ‘_pafprocess‘
  • 测试左移方法论
  • NX741NX777美光固态闪存NX783NX791
  • 算法思想之队列
  • 精准医学在肿瘤治疗中的应用案例研究
  • 终端VS命令解释器(Linux Windows)
  • 一招拿捏Windows的软件,仅仅1.22M
  • 如何硬解析 .shp 文件中的几何体,拯救 .dbf、.shx 等文件缺失的 ESRI Shapefile 格式文件
  • (Python)类的练习与巩固(图书管理系统扩展)(类与方法的基础教程)(if条件扩展)(动态类型)(Python教程)
  • LLC协议支持哪些类型的帧?它们各自的功能是什么?
  • IAR Embedded Workbench for ARM 8.1 安装教程
  • 深兰科技陈海波:AI企业出海要坚持“区域深耕”与“长期主义”
  • 《设计模式之禅》笔记摘录 - 9.责任链模式
  • 使用Ollama,VLLM,LMDeploy部署大模型
  • 二分查找-162.寻找峰值-力扣(LeetCode)
  • P1040 [NOIP 2003 提高组] 加分二叉树
  • 小米浏览器overflow不能左右滑动
  • spring-cloud概述
  • (Arxiv-2025)OVIS-U1技术报告