mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-29 22:55:52 +08:00
Merge branch 'master' of https://gitee.com/xia-chu/ZLMediaKit into dev
This commit is contained in:
commit
743862d786
@ -12,6 +12,7 @@
|
|||||||
#include "RtpSession.h"
|
#include "RtpSession.h"
|
||||||
#include "RtpSelector.h"
|
#include "RtpSelector.h"
|
||||||
#include "Network/TcpServer.h"
|
#include "Network/TcpServer.h"
|
||||||
|
#include "Rtsp/RtpReceiver.h"
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
const string RtpSession::kStreamID = "stream_id";
|
const string RtpSession::kStreamID = "stream_id";
|
||||||
@ -57,23 +58,40 @@ void RtpSession::onManager() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RtpSession::onRtpPacket(const char *data, size_t len) {
|
void RtpSession::onRtpPacket(const char *data, size_t len) {
|
||||||
|
if (_search_rtp) {
|
||||||
|
//搜索上下文期间,数据丢弃
|
||||||
|
if (_search_rtp_finished) {
|
||||||
|
//下个包开始就是正确的rtp包了
|
||||||
|
_search_rtp_finished = false;
|
||||||
|
_search_rtp = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (len > 1024 * 10) {
|
if (len > 1024 * 10) {
|
||||||
throw SockException(Err_shutdown, StrPrinter << "rtp包长度异常(" << len << "),发送端可能缓存溢出并覆盖");
|
_search_rtp = true;
|
||||||
|
WarnL << "rtp包长度异常(" << len << "),发送端可能缓存溢出并覆盖,开始搜索ssrc以便恢复上下文";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (!_process) {
|
if (!_process) {
|
||||||
uint32_t ssrc;
|
if (!RtpSelector::getSSRC(data, len, _ssrc)) {
|
||||||
if (!RtpSelector::getSSRC(data, len, ssrc)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_stream_id.empty()) {
|
if (_stream_id.empty()) {
|
||||||
//未指定流id就使用ssrc为流id
|
//未指定流id就使用ssrc为流id
|
||||||
_stream_id = printSSRC(ssrc);
|
_stream_id = printSSRC(_ssrc);
|
||||||
}
|
}
|
||||||
//tcp情况下,一个tcp链接只可能是一路流,不需要通过多个ssrc来区分,所以不需要频繁getProcess
|
//tcp情况下,一个tcp链接只可能是一路流,不需要通过多个ssrc来区分,所以不需要频繁getProcess
|
||||||
_process = RtpSelector::Instance().getProcess(_stream_id, true);
|
_process = RtpSelector::Instance().getProcess(_stream_id, true);
|
||||||
_process->setListener(dynamic_pointer_cast<RtpSession>(shared_from_this()));
|
_process->setListener(dynamic_pointer_cast<RtpSession>(shared_from_this()));
|
||||||
}
|
}
|
||||||
_process->inputRtp(false, getSock(), data, len, &addr);
|
try {
|
||||||
|
_process->inputRtp(false, getSock(), data, len, &addr);
|
||||||
|
} catch (RtpReceiver::BadRtpException &ex) {
|
||||||
|
WarnL << ex.what() << ",开始搜索ssrc以便恢复上下文";
|
||||||
|
_search_rtp = true;
|
||||||
|
} catch (...) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
_ticker.resetTime();
|
_ticker.resetTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,5 +110,57 @@ int RtpSession::totalReaderCount(MediaSource &sender) {
|
|||||||
return _process ? _process->getTotalReaderCount() : sender.totalReaderCount();
|
return _process ? _process->getTotalReaderCount() : sender.totalReaderCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *findSSRC(const char *data, ssize_t len, uint32_t ssrc) {
|
||||||
|
//rtp前面必须预留两个字节的长度字段
|
||||||
|
for (ssize_t i = 2; i <= len - 4; ++i) {
|
||||||
|
auto ptr = (const uint8_t *) data + i;
|
||||||
|
if (ptr[0] == (ssrc >> 24) && ptr[1] == ((ssrc >> 16) & 0xFF) &&
|
||||||
|
ptr[2] == ((ssrc >> 8) & 0xFF) && ptr[3] == (ssrc & 0xFF)) {
|
||||||
|
return (const char *) ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//rtp长度到ssrc间的长度固定为10
|
||||||
|
static size_t constexpr kSSRCOffset = 2 + 4 + 4;
|
||||||
|
|
||||||
|
const char *RtpSession::onSearchPacketTail(const char *data, size_t len) {
|
||||||
|
if (!_search_rtp) {
|
||||||
|
//tcp上下文正常,不用搜索ssrc
|
||||||
|
return RtpSplitter::onSearchPacketTail(data, len);
|
||||||
|
}
|
||||||
|
if (!_process) {
|
||||||
|
throw SockException(Err_shutdown, "ssrc未获取到,无法通过ssrc恢复tcp上下文");
|
||||||
|
}
|
||||||
|
//搜索第一个rtp的ssrc
|
||||||
|
auto ssrc_ptr0 = findSSRC(data, len, _ssrc);
|
||||||
|
if (!ssrc_ptr0) {
|
||||||
|
//未搜索到任意rtp,返回数据不够
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
//这两个字节是第一个rtp的长度字段
|
||||||
|
auto rtp_len_ptr = (ssrc_ptr0 - kSSRCOffset);
|
||||||
|
auto rtp_len = ((uint8_t *)rtp_len_ptr)[0] << 8 | ((uint8_t *)rtp_len_ptr)[1];
|
||||||
|
|
||||||
|
//搜索第二个rtp的ssrc
|
||||||
|
auto ssrc_ptr1 = findSSRC(ssrc_ptr0 + rtp_len, data + (ssize_t) len - ssrc_ptr0 - rtp_len, _ssrc);
|
||||||
|
if (!ssrc_ptr1) {
|
||||||
|
//未搜索到第二个rtp,返回数据不够
|
||||||
|
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;
|
||||||
|
_search_rtp_finished = true;
|
||||||
|
//前面的数据都需要丢弃,这个是rtp的起始
|
||||||
|
return rtp_len_ptr;
|
||||||
|
}
|
||||||
|
//第一个rtp长度不匹配,说明第一个找到的ssrc不是rtp,丢弃之,我们从第二个ssrc所在rtp开始搜索
|
||||||
|
return ssrc_ptr1 - kSSRCOffset;
|
||||||
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
#endif//defined(ENABLE_RTPPROXY)
|
#endif//defined(ENABLE_RTPPROXY)
|
@ -38,7 +38,12 @@ protected:
|
|||||||
// 收到rtp回调
|
// 收到rtp回调
|
||||||
void onRtpPacket(const char *data, size_t len) override;
|
void onRtpPacket(const char *data, size_t len) override;
|
||||||
|
|
||||||
|
const char *onSearchPacketTail(const char *data, size_t len) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _search_rtp = false;
|
||||||
|
bool _search_rtp_finished = false;
|
||||||
|
uint32_t _ssrc = 0;
|
||||||
Ticker _ticker;
|
Ticker _ticker;
|
||||||
string _stream_id;
|
string _stream_id;
|
||||||
struct sockaddr addr;
|
struct sockaddr addr;
|
||||||
|
@ -42,7 +42,7 @@ bool RtpReceiver::handleOneRtp(int index, TrackType type, int sample_rate, uint8
|
|||||||
}
|
}
|
||||||
RtpHeader *header = (RtpHeader *) ptr;
|
RtpHeader *header = (RtpHeader *) ptr;
|
||||||
if (header->version != RtpPacket::kRtpVersion) {
|
if (header->version != RtpPacket::kRtpVersion) {
|
||||||
throw std::invalid_argument("非法的rtp,version字段非法");
|
throw BadRtpException("非法的rtp,version字段非法");
|
||||||
}
|
}
|
||||||
if (!header->getPayloadSize(len)) {
|
if (!header->getPayloadSize(len)) {
|
||||||
//无有效负载的rtp包
|
//无有效负载的rtp包
|
||||||
|
@ -165,6 +165,13 @@ public:
|
|||||||
RtpReceiver();
|
RtpReceiver();
|
||||||
virtual ~RtpReceiver();
|
virtual ~RtpReceiver();
|
||||||
|
|
||||||
|
class BadRtpException : public invalid_argument {
|
||||||
|
public:
|
||||||
|
template<typename Type>
|
||||||
|
BadRtpException(Type &&type) : invalid_argument(std::forward<Type>(type)) {}
|
||||||
|
~BadRtpException() = default;
|
||||||
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* 输入数据指针生成并排序rtp包
|
* 输入数据指针生成并排序rtp包
|
||||||
|
Loading…
Reference in New Issue
Block a user