提高对不规范国标TCP推流的兼容性 (#2966)

问题: 建立tcp链接后,并不是从rtp包头开始发数据,所以无法解析出正确的包。
解决方案:在tcp数据报文中搜索0x000001bb(关键帧的system header),找到后偏移固定字节恢复rtp包头。
This commit is contained in:
xbpeng121 2023-11-10 21:53:43 +08:00 committed by GitHub
parent 055fe2cb92
commit 884f1d760b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 2 deletions

View File

@ -164,8 +164,23 @@ static const char *findSSRC(const char *data, ssize_t len, uint32_t ssrc) {
return nullptr;
}
static const char *findPsHeaderFlag(const char *data, ssize_t len) {
for (ssize_t i = 2; i <= len - 4; ++i) {
auto ptr = (const uint8_t *) data + i;
//PsHeader 0x000001ba、PsSystemHeader0x000001bb关键帧标识
if (ptr[0] == (0x00) && ptr[1] == (0x00) && ptr[2] == (0x01) && ptr[3] == (0xbb)) {
return (const char *) ptr;
}
}
return nullptr;
}
//rtp长度到ssrc间的长度固定为10
static size_t constexpr kSSRCOffset = 2 + 4 + 4;
// rtp长度到ps header间的长度固定为14 暂时不采用找ps header,采用找system header代替
// rtp长度到ps system header间的长度固定为20 (关键帧标识)
static size_t constexpr kPSHeaderOffset = 2 + 4 + 4 + 4 + 20;
const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
if (!_search_rtp) {
@ -173,12 +188,26 @@ const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
return RtpSplitter::onSearchPacketTail(data, len);
}
if (!_process) {
throw SockException(Err_shutdown, "ssrc未获取到无法通过ssrc恢复tcp上下文");
InfoL << "ssrc未获取到无法通过ssrc恢复tcp上下文尝试搜索PsSystemHeader恢复tcp上下文。";
auto rtp_ptr1 = searchByPsHeaderFlag(data,len);
return rtp_ptr1;
}
auto rtp_ptr0 = searchBySSRC(data,len);
if(rtp_ptr0) {
return rtp_ptr0;
}
// ssrc搜索失败继续尝试搜索ps header flag
auto rtp_ptr2 = searchByPsHeaderFlag(data,len);
return rtp_ptr2;
}
const char *RtpSession::searchBySSRC(const char *data, size_t len) {
InfoL << "尝试rtp搜索ssrc..._ssrc=" << _ssrc;
//搜索第一个rtp的ssrc
auto ssrc_ptr0 = findSSRC(data, len, _ssrc);
if (!ssrc_ptr0) {
//未搜索到任意rtp返回数据不够
InfoL << "rtp搜索ssrc失败第一个数据不够丢弃rtp数据为" << len;
return nullptr;
}
//这两个字节是第一个rtp的长度字段
@ -189,13 +218,14 @@ const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
auto ssrc_ptr1 = findSSRC(ssrc_ptr0 + rtp_len, data + (ssize_t) len - ssrc_ptr0 - rtp_len, _ssrc);
if (!ssrc_ptr1) {
//未搜索到第二个rtp返回数据不够
InfoL << "rtp搜索ssrc失败(第二个数据不够)丢弃rtp数据为" << len;
return nullptr;
}
//两个ssrc的间隔正好等于rtp的长度(外加rtp长度字段)那么说明找到rtp
auto ssrc_offset = ssrc_ptr1 - ssrc_ptr0;
if (ssrc_offset == rtp_len + 2 || ssrc_offset == rtp_len + 4) {
InfoL << "rtp搜索成功tcp上下文恢复成功丢弃的rtp残余数据为" << rtp_len_ptr - data;
InfoL << "rtp搜索ssrc成功tcp上下文恢复成功丢弃的rtp残余数据为" << rtp_len_ptr - data;
_search_rtp_finished = true;
if (rtp_len_ptr == data) {
//停止搜索rtp否则会进入死循环
@ -208,5 +238,32 @@ const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
return ssrc_ptr1 - kSSRCOffset;
}
const char *RtpSession::searchByPsHeaderFlag(const char *data, size_t len) {
InfoL << "尝试rtp搜索PsSystemHeaderFlag..._ssrc=" << _ssrc;
// 搜索rtp中的第一个PsHeaderFlag
auto ps_header_flag_ptr = findPsHeaderFlag(data,len);
if (!ps_header_flag_ptr) {
InfoL << "rtp搜索flag失败丢弃rtp数据为" << len;
return nullptr;
}
auto rtp_ptr = ps_header_flag_ptr - kPSHeaderOffset;
_search_rtp_finished = true;
if (rtp_ptr == data) {
//停止搜索rtp否则会进入死循环
_search_rtp = false;
}
InfoL << "rtp搜索flag成功tcp上下文恢复成功丢弃的rtp残余数据为" << rtp_ptr - data;
// TODO or Not ? 更新设置ssrc
uint32_t rtp_ssrc = 0;
RtpSelector::getSSRC(rtp_ptr+2, len, rtp_ssrc);
_ssrc = rtp_ssrc;
InfoL << "设置_ssrc为" << _ssrc;
// RtpServer::updateSSRC(uint32_t ssrc)
return rtp_ptr;
}
}//namespace mediakit
#endif//defined(ENABLE_RTPPROXY)

View File

@ -41,6 +41,10 @@ protected:
void onRtpPacket(const char *data, size_t len) override;
// RtpSplitter override
const char *onSearchPacketTail(const char *data, size_t len) override;
// 搜寻SSRC
const char *searchBySSRC(const char *data, size_t len);
// 搜寻PS包里的关键帧标头
const char *searchByPsHeaderFlag(const char *data, size_t len);
private:
bool _delay_close = false;