mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-27 04:20:13 +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;
|
||||
}
|
||||
|
||||
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)
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user