mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 10:40:05 +08:00
提高对不规范国标TCP推流的兼容性 (#2966)
问题: 建立tcp链接后,并不是从rtp包头开始发数据,所以无法解析出正确的包。 解决方案:在tcp数据报文中搜索0x000001bb(关键帧的system header),找到后偏移固定字节恢复rtp包头。
This commit is contained in:
parent
055fe2cb92
commit
884f1d760b
@ -164,8 +164,23 @@ static const char *findSSRC(const char *data, ssize_t len, uint32_t ssrc) {
|
|||||||
return nullptr;
|
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
|
//rtp长度到ssrc间的长度固定为10
|
||||||
static size_t constexpr kSSRCOffset = 2 + 4 + 4;
|
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) {
|
const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
|
||||||
if (!_search_rtp) {
|
if (!_search_rtp) {
|
||||||
@ -173,12 +188,26 @@ const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
|
|||||||
return RtpSplitter::onSearchPacketTail(data, len);
|
return RtpSplitter::onSearchPacketTail(data, len);
|
||||||
}
|
}
|
||||||
if (!_process) {
|
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
|
//搜索第一个rtp的ssrc
|
||||||
auto ssrc_ptr0 = findSSRC(data, len, _ssrc);
|
auto ssrc_ptr0 = findSSRC(data, len, _ssrc);
|
||||||
if (!ssrc_ptr0) {
|
if (!ssrc_ptr0) {
|
||||||
//未搜索到任意rtp,返回数据不够
|
//未搜索到任意rtp,返回数据不够
|
||||||
|
InfoL << "rtp搜索ssrc失败(第一个数据不够),丢弃rtp数据为:" << len;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
//这两个字节是第一个rtp的长度字段
|
//这两个字节是第一个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);
|
auto ssrc_ptr1 = findSSRC(ssrc_ptr0 + rtp_len, data + (ssize_t) len - ssrc_ptr0 - rtp_len, _ssrc);
|
||||||
if (!ssrc_ptr1) {
|
if (!ssrc_ptr1) {
|
||||||
//未搜索到第二个rtp,返回数据不够
|
//未搜索到第二个rtp,返回数据不够
|
||||||
|
InfoL << "rtp搜索ssrc失败(第二个数据不够),丢弃rtp数据为:" << len;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//两个ssrc的间隔正好等于rtp的长度(外加rtp长度字段),那么说明找到rtp
|
//两个ssrc的间隔正好等于rtp的长度(外加rtp长度字段),那么说明找到rtp
|
||||||
auto ssrc_offset = ssrc_ptr1 - ssrc_ptr0;
|
auto ssrc_offset = ssrc_ptr1 - ssrc_ptr0;
|
||||||
if (ssrc_offset == rtp_len + 2 || ssrc_offset == rtp_len + 4) {
|
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;
|
_search_rtp_finished = true;
|
||||||
if (rtp_len_ptr == data) {
|
if (rtp_len_ptr == data) {
|
||||||
//停止搜索rtp,否则会进入死循环
|
//停止搜索rtp,否则会进入死循环
|
||||||
@ -208,5 +238,32 @@ const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
|
|||||||
return ssrc_ptr1 - kSSRCOffset;
|
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
|
}//namespace mediakit
|
||||||
#endif//defined(ENABLE_RTPPROXY)
|
#endif//defined(ENABLE_RTPPROXY)
|
@ -41,6 +41,10 @@ protected:
|
|||||||
void onRtpPacket(const char *data, size_t len) override;
|
void onRtpPacket(const char *data, size_t len) override;
|
||||||
// RtpSplitter override
|
// RtpSplitter override
|
||||||
const char *onSearchPacketTail(const char *data, size_t len) 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:
|
private:
|
||||||
bool _delay_close = false;
|
bool _delay_close = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user