AI automatically translates all comments in the code into English (#3917)

This commit is contained in:
alex
2024-09-19 14:53:50 +08:00
committed by GitHub
parent 046de691cb
commit 4152dcd409
279 changed files with 10602 additions and 3038 deletions

View File

@@ -21,14 +21,16 @@ RtpPacket::Ptr RtpInfo::makeRtp(TrackType type, const void* data, size_t len, bo
rtp->type = type;
rtp->track_index = _track_index;
//rtsp over tcp 头
// rtsp over tcp 头 [AUTO-TRANSLATED:4225b9ec]
// rtsp over tcp header
auto ptr = (uint8_t *) rtp->data();
ptr[0] = '$';
ptr[1] = _interleaved;
ptr[2] = payload_len >> 8;
ptr[3] = payload_len & 0xFF;
//rtp头
// rtp头 [AUTO-TRANSLATED:64aef747]
// rtp header
auto header = rtp->getHeader();
header->version = RtpPacket::kRtpVersion;
header->padding = 0;
@@ -41,7 +43,8 @@ RtpPacket::Ptr RtpInfo::makeRtp(TrackType type, const void* data, size_t len, bo
header->stamp = htonl(uint64_t(stamp) * _sample_rate / 1000);
header->ssrc = htonl(_ssrc);
rtp->ntp_stamp = stamp;
//有效负载
// 有效负载 [AUTO-TRANSLATED:8530a274]
// payload
if (data) {
memcpy(&ptr[RtpPacket::kRtpHeaderSize + RtpPacket::kRtpTcpHeaderSize], data, len);
}

View File

@@ -28,6 +28,10 @@ public:
/**
* 设置rtp环形缓存
* @param ring
* Set the RTP ring buffer
* @param ring
* [AUTO-TRANSLATED:283d737a]
*/
void setRtpRing(RingType::Ptr ring) {
_ring = std::move(ring);
@@ -38,6 +42,12 @@ public:
* @param rtp rtp包
* @param key_pos 是否为关键帧第一个rtp包
* @return 是否为关键帧第一个rtp包
* Input RTP packet
* @param rtp RTP packet
* @param key_pos Whether it is the first RTP packet of the key frame
* @return Whether it is the first RTP packet of the key frame
* [AUTO-TRANSLATED:05ccdd17]
*/
virtual bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
if (_ring) {
@@ -66,7 +76,8 @@ public:
_track_index = track_index;
}
//返回rtp负载最大长度
// 返回rtp负载最大长度 [AUTO-TRANSLATED:0a8ee7d9]
// Return the maximum length of the RTP payload
size_t getMaxSize() const {
return _mtu_size - RtpPacket::kRtpHeaderSize;
}
@@ -101,6 +112,13 @@ public:
*
* @param opt 设置的选项
* @param param 设置的参数
* @brief Set the parameters of the RTP packer and unpacker, mainly used for g711 RTP packer, the usage is similar to setsockopt
*
* @param opt Set options
* @param param Set parameters
* [AUTO-TRANSLATED:95859425]
*/
virtual void setOpt(int opt, const toolkit::Any &param) {};

View File

@@ -58,11 +58,13 @@ std::shared_ptr<uint32_t> MultiCastAddressMaker::obtain(uint32_t max_try) {
}
auto iGotAddr = _addr++;
if (_used_addr.find(iGotAddr) != _used_addr.end()) {
//已经分配过了
// 已经分配过了 [AUTO-TRANSLATED:b231af33]
// Already allocated
if (max_try) {
return obtain(--max_try);
}
//分配完了,应该不可能到这里
// 分配完了,应该不可能到这里 [AUTO-TRANSLATED:c7f06cb9]
// Allocation is complete, it should not be possible to reach here
ErrorL;
return nullptr;
}
@@ -111,7 +113,8 @@ RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, con
}
for (auto i = 0; i < 2; ++i) {
//创建udp socket, 数组下标为TrackType
// 创建udp socket, 数组下标为TrackType [AUTO-TRANSLATED:17d153d5]
// Create UDP socket, array index is TrackType
_udp_sock[i] = helper.createSocket();
if (!_udp_sock[i]->bindUdpSock((i == TrackVideo) ? video_port : audio_port, local_ip.data())) {
auto err = StrPrinter << "绑定UDP端口失败:" << local_ip << endl;
@@ -125,9 +128,11 @@ RtpMultiCaster::RtpMultiCaster(SocketHelper &helper, const string &local_ip, con
struct sockaddr_in peer;
peer.sin_family = AF_INET;
//组播目标端口为本地发送端口
// 组播目标端口为本地发送端口 [AUTO-TRANSLATED:9eae5d47]
// Multicast target port is the local sending port
peer.sin_port = htons(_udp_sock[i]->get_local_port());
//组播目标地址
// 组播目标地址 [AUTO-TRANSLATED:3291a33b]
// Multicast target address
peer.sin_addr.s_addr = htonl(*_multicast_ip);
bzero(&(peer.sin_zero), sizeof peer.sin_zero);
_udp_sock[i]->bindPeerAddr((struct sockaddr *) &peer);

View File

@@ -39,7 +39,8 @@ RtpPacket::Ptr RtpTrack::inputRtp(TrackType type, int sample_rate, uint8_t *ptr,
return nullptr;
}
if (!sample_rate) {
//无法把时间戳转换成毫秒
// 无法把时间戳转换成毫秒 [AUTO-TRANSLATED:ec2d97b6]
// Unable to convert timestamp to milliseconds
return nullptr;
}
RtpHeader *header = (RtpHeader *) ptr;
@@ -47,11 +48,13 @@ RtpPacket::Ptr RtpTrack::inputRtp(TrackType type, int sample_rate, uint8_t *ptr,
throw BadRtpException("invalid rtp version");
}
if (header->getPayloadSize(len) < 0) {
//rtp有效负载小于0非法
// rtp有效负载小于0非法 [AUTO-TRANSLATED:07eb3ec3]
// RTP payload is less than 0, illegal
throw BadRtpException("invalid rtp payload size");
}
//比对缓存ssrc
// 比对缓存ssrc [AUTO-TRANSLATED:206cb66f]
// Compare cache ssrc
auto ssrc = ntohl(header->ssrc);
if (_pt == 0xFF) {
@@ -62,16 +65,20 @@ RtpPacket::Ptr RtpTrack::inputRtp(TrackType type, int sample_rate, uint8_t *ptr,
}
if (!_ssrc) {
//记录并锁定ssrc
// 记录并锁定ssrc [AUTO-TRANSLATED:29452029]
// Record and lock ssrc
_ssrc = ssrc;
_ssrc_alive.resetTime();
} else if (_ssrc == ssrc) {
//ssrc匹配正确,刷新计时器
// ssrc匹配正确,刷新计时器 [AUTO-TRANSLATED:266518e6]
// SSRC matches correctly, refresh timer
_ssrc_alive.resetTime();
} else {
//ssrc错误
// ssrc错误 [AUTO-TRANSLATED:b967d497]
// SSRC error
if (_ssrc_alive.elapsedTime() < 3 * 1000) {
//接收正确ssrc的rtp在10秒内那么我们认为存在多路rtp,忽略掉ssrc不匹配的rtp
// 接收正确ssrc的rtp在10秒内那么我们认为存在多路rtp,忽略掉ssrc不匹配的rtp [AUTO-TRANSLATED:2f98c2b5]
// If the RTP with the correct SSRC is received within 10 seconds, we consider it to be multi-path RTP, and ignore the RTP with mismatched SSRC
WarnL << "ssrc mismatch, rtp dropped:" << ssrc << " != " << _ssrc;
return nullptr;
}
@@ -81,25 +88,30 @@ RtpPacket::Ptr RtpTrack::inputRtp(TrackType type, int sample_rate, uint8_t *ptr,
}
auto rtp = RtpPacket::create();
//需要添加4个字节的rtp over tcp头
// 需要添加4个字节的rtp over tcp头 [AUTO-TRANSLATED:a37d639b]
// Need to add 4 bytes of RTP over TCP header
rtp->setCapacity(RtpPacket::kRtpTcpHeaderSize + len);
rtp->setSize(RtpPacket::kRtpTcpHeaderSize + len);
rtp->sample_rate = sample_rate;
rtp->type = type;
//赋值4个字节的rtp over tcp头
// 赋值4个字节的rtp over tcp头 [AUTO-TRANSLATED:eeb990a9]
// Assign 4 bytes of RTP over TCP header
uint8_t *data = (uint8_t *) rtp->data();
data[0] = '$';
data[1] = 2 * type;
data[2] = (len >> 8) & 0xFF;
data[3] = len & 0xFF;
//拷贝rtp
// 拷贝rtp [AUTO-TRANSLATED:3a2466c2]
// Copy RTP
memcpy(&data[4], ptr, len);
if (_disable_ntp) {
//不支持ntp时间戳例如国标推流那么直接使用rtp时间戳
// 不支持ntp时间戳例如国标推流那么直接使用rtp时间戳 [AUTO-TRANSLATED:20085979]
// Does not support NTP timestamp, such as national standard streaming, so directly use RTP timestamp
rtp->ntp_stamp = rtp->getStamp() * uint64_t(1000) / sample_rate;
} else {
//设置ntp时间戳
// 设置ntp时间戳 [AUTO-TRANSLATED:5e60d5cf]
// Set NTP timestamp
rtp->ntp_stamp = _ntp_stamp.getNtpStamp(rtp->getStamp(), sample_rate);
}
onBeforeRtpSorted(rtp);

View File

@@ -34,6 +34,9 @@ public:
/**
* 清空状态
* Clear the state
* [AUTO-TRANSLATED:6aadbd77]
*/
void clear() {
_started = false;
@@ -43,6 +46,9 @@ public:
/**
* 获取排序缓存长度
* Get the length of the sorting cache
* [AUTO-TRANSLATED:8e05a703]
*/
size_t getJitterSize() const { return _pkt_sort_cache_map.size(); }
@@ -50,31 +56,42 @@ public:
* 输入并排序
* @param seq 序列号
* @param packet 包负载
* Input and sort
* @param seq Sequence number
* @param packet Packet payload
* [AUTO-TRANSLATED:0fbf096e]
*/
void sortPacket(SEQ seq, T packet) {
_latest_seq = seq;
if (!_started) {
// 记录第一个seq
// 记录第一个seq [AUTO-TRANSLATED:410c831f]
// Record the first seq
_started = true;
_last_seq_out = seq - 1;
}
auto next_seq = static_cast<SEQ>(_last_seq_out + 1);
if (seq == next_seq) {
// 收到下一个seq
// 收到下一个seq [AUTO-TRANSLATED:44960fea]
// Receive the next seq
output(seq, std::move(packet));
// 清空连续包列表
// 清空连续包列表 [AUTO-TRANSLATED:fdaafd3b]
// Clear the continuous packet list
flushPacket();
_pkt_drop_cache_map.clear();
return;
}
if (seq < next_seq && !mayLooped(next_seq, seq)) {
// 无回环风险, 缓存seq回退包
// 无回环风险, 缓存seq回退包 [AUTO-TRANSLATED:4200dd1b]
// No loop risk, cache seq rollback packets
_pkt_drop_cache_map.emplace(seq, std::move(packet));
if (_pkt_drop_cache_map.size() > _max_distance || _ticker.elapsedTime() > _max_buffer_ms) {
// seq回退包太多可能源端重置seq计数器这部分数据需要输出
// seq回退包太多可能源端重置seq计数器这部分数据需要输出 [AUTO-TRANSLATED:d31aead7]
// Too many seq rollback packets, the source may reset the seq counter, this part of data needs to be output
forceFlush(next_seq);
// 旧的seq计数器的数据清空后把新seq计数器的数据赋值给排序列队
// 旧的seq计数器的数据清空后把新seq计数器的数据赋值给排序列队 [AUTO-TRANSLATED:f69f864c]
// After clearing the data of the old seq counter, assign the data of the new seq counter to the sorting queue
_pkt_sort_cache_map = std::move(_pkt_drop_cache_map);
popIterator(_pkt_sort_cache_map.begin());
}
@@ -123,17 +140,22 @@ private:
if (_pkt_sort_cache_map.empty()) {
return;
}
// 寻找距离比next_seq大的最近的seq
// 寻找距离比next_seq大的最近的seq [AUTO-TRANSLATED:d2de6f5b]
// Find the nearest seq that is greater than next_seq
auto it = _pkt_sort_cache_map.lower_bound(next_seq);
if (it == _pkt_sort_cache_map.end()) {
// 没有比next_seq更大的seq应该是回环时丢包导致
// 没有比next_seq更大的seq应该是回环时丢包导致 [AUTO-TRANSLATED:d0d6970b]
// There is no seq greater than next_seq, it should be caused by packet loss during loopback
it = _pkt_sort_cache_map.begin();
}
// 丢包无法恢复把这个包当做next_seq
// 丢包无法恢复把这个包当做next_seq [AUTO-TRANSLATED:2d8c0b9e]
// Packet loss cannot be recovered, treat this packet as next_seq
popIterator(it);
// 清空连续包列表
// 清空连续包列表 [AUTO-TRANSLATED:fdaafd3b]
// Clear the continuous packet list
flushPacket();
// 删除距离next_seq太大的包
// 删除距离next_seq太大的包 [AUTO-TRANSLATED:9e774c5e]
// Delete packets that are too far away from next_seq
for (auto it = _pkt_sort_cache_map.begin(); it != _pkt_sort_cache_map.end();) {
if (distance(it->first) > _max_distance) {
it = _pkt_sort_cache_map.erase(it);
@@ -152,12 +174,14 @@ private:
auto next_seq = static_cast<SEQ>(_last_seq_out + 1);
auto it = _pkt_sort_cache_map.lower_bound(next_seq);
if (!mayLooped(next_seq, next_seq)) {
// 无回环风险, 清空 < next_seq的值
// 无回环风险, 清空 < next_seq的值 [AUTO-TRANSLATED:10c77bf9]
// No loop risk, clear values less than next_seq
it = _pkt_sort_cache_map.erase(_pkt_sort_cache_map.begin(), it);
}
while (it != _pkt_sort_cache_map.end()) {
// 找到下一个包
// 找到下一个包 [AUTO-TRANSLATED:8e20ab9f]
// Find the next packet
if (it->first == static_cast<SEQ>(_last_seq_out + 1)) {
it = popIterator(it);
continue;
@@ -186,23 +210,32 @@ private:
private:
bool _started = false;
// 排序缓存最大保存数据长度,单位毫秒
// 排序缓存最大保存数据长度,单位毫秒 [AUTO-TRANSLATED:ed217b1c]
// Maximum data length of sorting cache, unit: milliseconds
size_t _max_buffer_ms = 1000;
// 排序缓存最大保存数据个数
// 排序缓存最大保存数据个数 [AUTO-TRANSLATED:9cfa91b4]
// Maximum number of data in sorting cache
size_t _max_buffer_size = 1024;
// seq最大跳跃距离
// seq最大跳跃距离 [AUTO-TRANSLATED:bb663e41]
// Maximum seq jump distance
size_t _max_distance = 256;
// 记录上次output至今的时间
// 记录上次output至今的时间 [AUTO-TRANSLATED:83e53e42]
// Record the time since the last output
toolkit::Ticker _ticker;
// 最近输入的seq
// 最近输入的seq [AUTO-TRANSLATED:24ca96ee]
// The most recently input seq
SEQ _latest_seq = 0;
// 下次应该输出的SEQ
// 下次应该输出的SEQ [AUTO-TRANSLATED:e757a4fa]
// The next SEQ to be output
SEQ _last_seq_out = 0;
// pkt排序缓存根据seq排序
// pkt排序缓存根据seq排序 [AUTO-TRANSLATED:3787f9a6]
// pkt sorting cache, sorted by seq
std::map<SEQ, T> _pkt_sort_cache_map;
// 预丢弃包列表
// 预丢弃包列表 [AUTO-TRANSLATED:67e57ebc]
// Pre-discard packet list
std::map<SEQ, T> _pkt_drop_cache_map;
// 回调
// 回调 [AUTO-TRANSLATED:03bad27d]
// Callback
std::function<void(SEQ seq, T packet)> _cb;
};
@@ -277,6 +310,15 @@ public:
* @param ptr rtp数据指针
* @param len rtp数据指针长度
* @return 解析成功返回true
* Generate and sort rtp packets from input data pointer
* @param index Track index
* @param type Track type
* @param samplerate RTP timestamp base clock, 90000 for video, sample rate for audio
* @param ptr RTP data pointer
* @param len RTP data pointer length
* @return Return true if parsing is successful
* [AUTO-TRANSLATED:4ec12e4a]
*/
bool handleOneRtp(int index, TrackType type, int sample_rate, uint8_t *ptr, size_t len) {
assert(index < kCount && index >= 0);
@@ -289,6 +331,13 @@ public:
* @param index track下标索引
* @param rtp_stamp rtp时间戳
* @param ntp_stamp_ms ntp时间戳
* Set ntp timestamp, set when receiving rtcp sender report
* If rtp_stamp/sample_rate/ntp_stamp_ms are all 0, then use rtp timestamp as ntp timestamp
* @param index Track index
* @param rtp_stamp RTP timestamp
* @param ntp_stamp_ms NTP timestamp
* [AUTO-TRANSLATED:1e50904e]
*/
void setNtpStamp(int index, uint32_t rtp_stamp, uint64_t ntp_stamp_ms) {
assert(index < kCount && index >= 0);
@@ -321,6 +370,11 @@ protected:
* rtp数据包排序后输出
* @param rtp rtp数据包
* @param track_index track索引
* Output rtp data packets after sorting
* @param rtp RTP data packet
* @param track_index Track index
* [AUTO-TRANSLATED:55022da9]
*/
virtual void onRtpSorted(RtpPacket::Ptr rtp, int index) {}
@@ -328,6 +382,11 @@ protected:
* 解析出rtp但还未排序
* @param rtp rtp数据包
* @param track_index track索引
* RTP data packet parsed but not yet sorted
* @param rtp RTP data packet
* @param track_index Track index
* [AUTO-TRANSLATED:c1636911]
*/
virtual void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int index) {}

View File

@@ -102,7 +102,8 @@ string SdpTrack::getName() const {
string SdpTrack::getControlUrl(const string &base_url) const {
if (_control.find("://") != string::npos) {
// 以rtsp://开头
// 以rtsp://开头 [AUTO-TRANSLATED:293b3f8c]
// Starts with rtsp://
return _control;
}
return base_url + "/" + _control;
@@ -224,7 +225,8 @@ void SdpParser::load(const string &sdp) {
sscanf(rtpmap.data(), "%d", &pt);
if (track._pt != pt && track._pt != 0xff) {
// pt不匹配
// pt不匹配 [AUTO-TRANSLATED:ce7abb0a]
// pt mismatch
it = track._attr.erase(it);
continue;
}
@@ -245,7 +247,8 @@ void SdpParser::load(const string &sdp) {
int pt;
sscanf(fmtp.data(), "%d", &pt);
if (track._pt != pt && track._pt != 0xff) {
// pt不匹配
// pt不匹配 [AUTO-TRANSLATED:ce7abb0a]
// pt mismatch
it = track._attr.erase(it);
continue;
}
@@ -259,7 +262,8 @@ void SdpParser::load(const string &sdp) {
}
if (!track._samplerate && track._type == TrackVideo) {
// 未设置视频采样率时赋值为90000
// 未设置视频采样率时赋值为90000 [AUTO-TRANSLATED:416c4f0f]
// If video sampling rate is not set, assign it to 90000
track._samplerate = 90000;
} else if (!track._samplerate && track._type == TrackAudio) {
// some rtsp sdp no sample rate but has fmt config to parser get sample rate
@@ -333,7 +337,8 @@ string SdpParser::toString() const {
std::string SdpParser::getControlUrl(const std::string &url) const {
auto title_track = getTrack(TrackTitle);
if (title_track && title_track->_control.find("://") != string::npos) {
// 以rtsp://开头
// 以rtsp://开头 [AUTO-TRANSLATED:293b3f8c]
// Starts with rtsp://
return title_track->_control;
}
return url;
@@ -366,7 +371,8 @@ public:
}
makeSockPair_l(sock_pair, pair, local_ip, re_use_port, is_udp);
// 确保udp和tcp模式都能打开
// 确保udp和tcp模式都能打开 [AUTO-TRANSLATED:dcb46232]
// Ensure both udp and tcp modes are open
auto new_pair = std::make_pair(Socket::createSocket(), Socket::createSocket());
makeSockPair_l(sock_pair, new_pair, local_ip, re_use_port, !is_udp);
}
@@ -376,32 +382,38 @@ public:
auto &sock1 = pair.second;
if (is_udp) {
if (!sock0->bindUdpSock(2 * *sock_pair, local_ip.data(), re_use_port)) {
// 分配端口失败
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
throw runtime_error("open udp socket[0] failed");
}
if (!sock1->bindUdpSock(2 * *sock_pair + 1, local_ip.data(), re_use_port)) {
// 分配端口失败
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
throw runtime_error("open udp socket[1] failed");
}
auto on_cycle = [sock_pair](Socket::Ptr &, std::shared_ptr<void> &) {};
// udp socket没onAccept事件设置该回调目的是为了在销毁socket时回收对象
// udp socket没onAccept事件设置该回调目的是为了在销毁socket时回收对象 [AUTO-TRANSLATED:ee91256f]
// UDP socket has no onAccept event, set this callback to recycle the object when destroying the socket
sock0->setOnAccept(on_cycle);
sock1->setOnAccept(on_cycle);
} else {
if (!sock0->listen(2 * *sock_pair, local_ip.data())) {
// 分配端口失败
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
throw runtime_error("listen tcp socket[0] failed");
}
if (!sock1->listen(2 * *sock_pair + 1, local_ip.data())) {
// 分配端口失败
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
throw runtime_error("listen tcp socket[1] failed");
}
auto on_cycle = [sock_pair](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {};
// udp socket没onAccept事件设置该回调目的是为了在销毁socket时回收对象
// udp socket没onAccept事件设置该回调目的是为了在销毁socket时回收对象 [AUTO-TRANSLATED:ee91256f]
// UDP socket has no onAccept event, set this callback to recycle the object when destroying the socket
sock0->setOnRead(on_cycle);
sock1->setOnRead(on_cycle);
}
@@ -413,7 +425,8 @@ private:
lock_guard<recursive_mutex> lck(_pool_mtx);
auto it = _port_pair_pool.begin();
while (start_pos < end_pos) {
// 随机端口排序,防止重启后导致分配的端口重复
// 随机端口排序,防止重启后导致分配的端口重复 [AUTO-TRANSLATED:b622db1c]
// Randomly sort ports to prevent duplicate port allocation after restart
_port_pair_pool.insert(it, start_pos++);
it = _port_pair_pool.begin() + (rng() % (1 + _port_pair_pool.size()));
}
@@ -436,7 +449,8 @@ private:
return;
}
InfoL << "return port to pool:" << 2 * pos << "-" << 2 * pos + 1;
// 回收端口号
// 回收端口号 [AUTO-TRANSLATED:646a5284]
// Recycle port number
lock_guard<recursive_mutex> lck(strong_self->_pool_mtx);
strong_self->_port_pair_pool.emplace_back(pos);
});
@@ -452,7 +466,8 @@ void makeSockPair(std::pair<Socket::Ptr, Socket::Ptr> &pair, const string &local
int try_count = 0;
while (true) {
try {
// udp和tcp端口池使用相同算法和范围分配但是互不相干
// udp和tcp端口池使用相同算法和范围分配但是互不相干 [AUTO-TRANSLATED:86200c72]
// UDP and TCP port pools use the same algorithm and range for allocation, but are independent of each other
if (is_udp) {
PortManager<0>::Instance().makeSockPair(pair, local_ip, re_use_port, is_udp);
} else {
@@ -518,7 +533,8 @@ Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved) {
#define AV_RB16(x) ((((const uint8_t *)(x))[0] << 8) | ((const uint8_t *)(x))[1])
size_t RtpHeader::getCsrcSize() const {
// 每个csrc占用4字节
// 每个csrc占用4字节 [AUTO-TRANSLATED:6237ca37]
// Each csrc occupies 4 bytes
return csrc << 2;
}
@@ -530,18 +546,21 @@ uint8_t *RtpHeader::getCsrcData() {
}
size_t RtpHeader::getExtSize() const {
// rtp有ext
// rtp有ext [AUTO-TRANSLATED:d5d9af4f]
// RTP has ext
if (!ext) {
return 0;
}
auto ext_ptr = &payload + getCsrcSize();
// uint16_t reserved = AV_RB16(ext_ptr);
// 每个ext占用4字节
// 每个ext占用4字节 [AUTO-TRANSLATED:93e9b453]
// Each ext occupies 4 bytes
return AV_RB16(ext_ptr + 2) << 2;
}
uint16_t RtpHeader::getExtReserved() const {
// rtp有ext
// rtp有ext [AUTO-TRANSLATED:d5d9af4f]
// RTP has ext
if (!ext) {
return 0;
}
@@ -554,12 +573,14 @@ uint8_t *RtpHeader::getExtData() {
return nullptr;
}
auto ext_ptr = &payload + getCsrcSize();
// 多出的4个字节分别为reserved、ext_len
// 多出的4个字节分别为reserved、ext_len [AUTO-TRANSLATED:070138f4]
// The extra 4 bytes are reserved, ext_len
return ext_ptr + 4;
}
size_t RtpHeader::getPayloadOffset() const {
// 有ext时还需要忽略reserved、ext_len 4个字节
// 有ext时还需要忽略reserved、ext_len 4个字节 [AUTO-TRANSLATED:3e222997]
// When there is ext, you also need to ignore the reserved, ext_len 4 bytes
return getCsrcSize() + (ext ? (4 + getExtSize()) : 0);
}
@@ -600,7 +621,8 @@ string RtpHeader::dumpString(size_t rtp_size) const {
///////////////////////////////////////////////////////////////////////
RtpHeader *RtpPacket::getHeader() {
// 需除去rtcp over tcp 4个字节长度
// 需除去rtcp over tcp 4个字节长度 [AUTO-TRANSLATED:936f6f5b]
// Need to remove the rtcp over tcp 4 byte length
return (RtpHeader *)(data() + RtpPacket::kRtpTcpHeaderSize);
}
@@ -633,7 +655,8 @@ uint8_t *RtpPacket::getPayload() {
}
size_t RtpPacket::getPayloadSize() const {
// 需除去rtcp over tcp 4个字节长度
// 需除去rtcp over tcp 4个字节长度 [AUTO-TRANSLATED:936f6f5b]
// Need to remove the rtcp over tcp 4 byte length
return getHeader()->getPayloadSize(size() - kRtpTcpHeaderSize);
}
@@ -656,6 +679,12 @@ RtpPacket::Ptr RtpPacket::create() {
* @param dur_sec rtsp点播时长0代表直播单位秒
* @param header 自定义sdp描述
* @param version sdp版本
* Construct title type sdp
* @param dur_sec rtsp on-demand duration, 0 represents live broadcast, unit is seconds
* @param header Custom sdp description
* @param version sdp version
* [AUTO-TRANSLATED:a548fc69]
*/
TitleSdp::TitleSdp(float dur_sec, const std::map<std::string, std::string> &header, int version)
@@ -674,10 +703,12 @@ TitleSdp::TitleSdp(float dur_sec, const std::map<std::string, std::string> &head
}
if (dur_sec <= 0) {
// 直播
// 直播 [AUTO-TRANSLATED:079c0cbc]
// Live broadcast
_printer << "a=range:npt=now-\r\n";
} else {
// 点播
// 点播 [AUTO-TRANSLATED:f0b0f74a]
// On-demand
_dur_sec = dur_sec;
_printer << "a=range:npt=0-" << dur_sec << "\r\n";
}

View File

@@ -70,100 +70,130 @@ typedef enum {
class RtpHeader {
public:
#if __BYTE_ORDER == __BIG_ENDIAN
// 版本号固定为2
// 版本号固定为2 [AUTO-TRANSLATED:08ed82fa]
// Version number, fixed to 2
uint32_t version : 2;
// padding
uint32_t padding : 1;
// 扩展
// 扩展 [AUTO-TRANSLATED:6189584a]
// Extension
uint32_t ext : 1;
// csrc
uint32_t csrc : 4;
// mark
uint32_t mark : 1;
// 负载类型
// 负载类型 [AUTO-TRANSLATED:09b49a77]
// Payload type
uint32_t pt : 7;
#else
// csrc
uint32_t csrc : 4;
// 扩展
// 扩展 [AUTO-TRANSLATED:6189584a]
// Extension
uint32_t ext : 1;
// padding
uint32_t padding : 1;
// 版本号固定为2
// 版本号固定为2 [AUTO-TRANSLATED:08ed82fa]
// Version number, fixed to 2
uint32_t version : 2;
// 负载类型
// 负载类型 [AUTO-TRANSLATED:09b49a77]
// Payload type
uint32_t pt : 7;
// mark
uint32_t mark : 1;
#endif
// 序列号
// 序列号 [AUTO-TRANSLATED:fe421425]
// Sequence number
uint32_t seq : 16;
// 时间戳
// 时间戳 [AUTO-TRANSLATED:516f43a9]
// Timestamp
uint32_t stamp;
// ssrc
uint32_t ssrc;
// 负载如果有csrc和ext前面为 4 * csrc + (4 + 4 * ext_len)
// 负载如果有csrc和ext前面为 4 * csrc + (4 + 4 * ext_len) [AUTO-TRANSLATED:fcd87b19]
// Payload, if csrc and ext exist, the front is 4 * csrc + (4 + 4 * ext_len)
uint8_t payload;
public:
// 返回csrc字段字节长度
// 返回csrc字段字节长度 [AUTO-TRANSLATED:2203e1db]
// Return the byte length of the csrc field
size_t getCsrcSize() const;
// 返回csrc字段首地址不存在时返回nullptr
// 返回csrc字段首地址不存在时返回nullptr [AUTO-TRANSLATED:2c89718a]
// Return the starting address of the csrc field, return nullptr if it does not exist
uint8_t *getCsrcData();
// 返回ext字段字节长度
// 返回ext字段字节长度 [AUTO-TRANSLATED:487dcc4e]
// Return the byte length of the ext field
size_t getExtSize() const;
// 返回ext reserved值
// 返回ext reserved值 [AUTO-TRANSLATED:131355c0]
// Return the ext reserved value
uint16_t getExtReserved() const;
// 返回ext段首地址不存在时返回nullptr
// 返回ext段首地址不存在时返回nullptr [AUTO-TRANSLATED:6662b24f]
// Return the starting address of the ext segment, return nullptr if it does not exist
uint8_t *getExtData();
// 返回有效负载指针,跳过csrc、ext
// 返回有效负载指针,跳过csrc、ext [AUTO-TRANSLATED:139a5683]
// Return the valid payload pointer, skip csrc, ext
uint8_t *getPayloadData();
// 返回有效负载总长度,不包括csrc、ext、padding
// 返回有效负载总长度,不包括csrc、ext、padding [AUTO-TRANSLATED:b4ec90d4]
// Return the total length of the valid payload, excluding csrc, ext, padding
ssize_t getPayloadSize(size_t rtp_size) const;
// 打印调试信息
// 打印调试信息 [AUTO-TRANSLATED:f36e06da]
// Print debug information
std::string dumpString(size_t rtp_size) const;
private:
// 返回有效负载偏移量
// 返回有效负载偏移量 [AUTO-TRANSLATED:47496d37]
// Return the valid payload offset
size_t getPayloadOffset() const;
// 返回padding长度
// 返回padding长度 [AUTO-TRANSLATED:6dabd44d]
// Return the padding length
size_t getPaddingSize(size_t rtp_size) const;
};
#pragma pack(pop)
// 此rtp为rtp over tcp形式需要忽略前4个字节
// 此rtp为rtp over tcp形式需要忽略前4个字节 [AUTO-TRANSLATED:ceb00f83]
// This rtp is in the form of rtp over tcp, the first 4 bytes need to be ignored
class RtpPacket : public toolkit::BufferRaw {
public:
using Ptr = std::shared_ptr<RtpPacket>;
enum { kRtpVersion = 2, kRtpHeaderSize = 12, kRtpTcpHeaderSize = 4 };
// 获取rtp头
// 获取rtp头 [AUTO-TRANSLATED:41d58919]
// Get the rtp header
RtpHeader *getHeader();
const RtpHeader *getHeader() const;
// 打印调试信息
// 打印调试信息 [AUTO-TRANSLATED:f36e06da]
// Print debug information
std::string dumpString() const;
// 主机字节序的seq
// 主机字节序的seq [AUTO-TRANSLATED:67c278dd]
// Host byte order seq
uint16_t getSeq() const;
uint32_t getStamp() const;
// 主机字节序的时间戳,已经转换为毫秒
// 主机字节序的时间戳,已经转换为毫秒 [AUTO-TRANSLATED:14cdf080]
// Host byte order timestamp, converted to milliseconds
uint64_t getStampMS(bool ntp = true) const;
// 主机字节序的ssrc
// 主机字节序的ssrc [AUTO-TRANSLATED:37d06f6c]
// Host byte order ssrc
uint32_t getSSRC() const;
// 有效负载跳过csrc、ext
// 有效负载跳过csrc、ext [AUTO-TRANSLATED:e4e97453]
// Valid payload, skip csrc, ext
uint8_t *getPayload();
// 有效负载长度不包括csrc、ext、padding
// 有效负载长度不包括csrc、ext、padding [AUTO-TRANSLATED:a93e4b08]
// Valid payload length, excluding csrc, ext, padding
size_t getPayloadSize() const;
// 音视频类型
// 音视频类型 [AUTO-TRANSLATED:dc0fa851]
// Audio and video type
TrackType type;
// 音频为采样率视频一般为90000
// 音频为采样率视频一般为90000 [AUTO-TRANSLATED:8bd1854b]
// Audio is the sampling rate, video is generally 90000
uint32_t sample_rate;
// ntp时间戳
// ntp时间戳 [AUTO-TRANSLATED:912cacf2]
// ntp timestamp
uint64_t ntp_stamp;
int track_index;
@@ -175,7 +205,8 @@ private:
RtpPacket() = default;
private:
// 对象个数统计
// 对象个数统计 [AUTO-TRANSLATED:f4a012d0]
// Object Count Statistics
toolkit::ObjectStatistic<RtpPacket> _statistic;
};
@@ -224,7 +255,8 @@ public:
uint8_t _interleaved = 0;
uint16_t _seq = 0;
uint32_t _ssrc = 0;
// 时间戳,单位毫秒
// 时间戳,单位毫秒 [AUTO-TRANSLATED:9513087f]
// Timestamp, unit: milliseconds
uint32_t _time_stamp = 0;
};
@@ -248,6 +280,9 @@ private:
/**
* rtsp sdp基类
* rtsp sdp base class
* [AUTO-TRANSLATED:05395f48]
*/
class Sdp {
public:
@@ -257,6 +292,11 @@ public:
* 构造sdp
* @param sample_rate 采样率
* @param payload_type pt类型
* Construct sdp
* @param sample_rate Sampling rate
* @param payload_type pt type
* [AUTO-TRANSLATED:49f61fff]
*/
Sdp(uint32_t sample_rate, uint8_t payload_type) {
_sample_rate = sample_rate;
@@ -268,18 +308,30 @@ public:
/**
* 获取sdp字符串
* @return
* Get sdp string
* @return
* [AUTO-TRANSLATED:ca0e2ad7]
*/
virtual std::string getSdp() const = 0;
/**
* 获取pt
* @return
* Get pt
* @return
* [AUTO-TRANSLATED:872f1b6a]
*/
uint8_t getPayloadType() const { return _payload_type; }
/**
* 获取采样率
* @return
* Get sampling rate
* @return
* [AUTO-TRANSLATED:463a0075]
*/
uint32_t getSampleRate() const { return _sample_rate; }
@@ -290,6 +342,9 @@ private:
/**
* sdp中除音视频外的其他描述部分
* Other description part in sdp except audio and video
* [AUTO-TRANSLATED:3a1dad65]
*/
class TitleSdp : public Sdp {
public:
@@ -299,6 +354,12 @@ public:
* @param dur_sec rtsp点播时长0代表直播单位秒
* @param header 自定义sdp描述
* @param version sdp版本
* Construct title type sdp
* @param dur_sec rtsp on-demand duration, 0 represents live broadcast, unit: seconds
* @param header Custom sdp description
* @param version sdp version
* [AUTO-TRANSLATED:bcd1dd5a]
*/
TitleSdp(float dur_sec = 0, const std::map<std::string, std::string> &header = std::map<std::string, std::string>(), int version = 0);
@@ -311,11 +372,14 @@ private:
toolkit::_StrPrinter _printer;
};
// 创建rtp over tcp4个字节的头
// 创建rtp over tcp4个字节的头 [AUTO-TRANSLATED:25031f0d]
// Create 4-byte header for rtp over tcp
toolkit::Buffer::Ptr makeRtpOverTcpPrefix(uint16_t size, uint8_t interleaved);
// 创建rtp-rtcp端口对
// 创建rtp-rtcp端口对 [AUTO-TRANSLATED:f8abe61b]
// Create rtp-rtcp port pair
void makeSockPair(std::pair<toolkit::Socket::Ptr, toolkit::Socket::Ptr> &pair, const std::string &local_ip, bool re_use_port = false, bool is_udp = true);
// 十六进制方式打印ssrc
// 十六进制方式打印ssrc [AUTO-TRANSLATED:c58cd95f]
// Print ssrc in hexadecimal format
std::string printSSRC(uint32_t ui32Ssrc);
bool getSSRC(const char *data, size_t data_len, uint32_t &ssrc);

View File

@@ -39,7 +39,8 @@ void RtspDemuxer::loadSdp(const SdpParser &attr) {
break;
}
}
//rtsp能通过sdp立即知道有多少个track
// rtsp能通过sdp立即知道有多少个track [AUTO-TRANSLATED:66a4c8d3]
// rtsp can immediately know how many tracks there are through sdp
addTrackCompleted();
auto titleTrack = attr.getTrack(TrackTitle);
@@ -85,20 +86,24 @@ void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) {
if (_audio_rtp_decoder) {
return;
}
//生成Track对象
// 生成Track对象 [AUTO-TRANSLATED:c2f2ac3b]
// Generate Track object
_audio_track = dynamic_pointer_cast<AudioTrack>(Factory::getTrackBySdp(audio));
if (!_audio_track) {
return;
}
setBitRate(audio, _audio_track);
//生成RtpCodec对象以便解码rtp
// 生成RtpCodec对象以便解码rtp [AUTO-TRANSLATED:889376fd]
// Generate RtpCodec object to decode rtp
_audio_rtp_decoder = Factory::getRtpDecoderByCodecId(_audio_track->getCodecId());
if (!_audio_rtp_decoder) {
//找不到相应的rtp解码器该track无效
// 找不到相应的rtp解码器该track无效 [AUTO-TRANSLATED:1c8c5eab]
// Cannot find the corresponding rtp decoder, the track is invalid
_audio_track.reset();
return;
}
//设置rtp解码器代理生成的frame写入该Track
// 设置rtp解码器代理生成的frame写入该Track [AUTO-TRANSLATED:b2a2362e]
// Set the rtp decoder proxy, the generated frame is written to this Track
_audio_rtp_decoder->addDelegate(_audio_track);
addTrack(_audio_track);
}
@@ -107,20 +112,24 @@ void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) {
if (_video_rtp_decoder) {
return;
}
//生成Track对象
// 生成Track对象 [AUTO-TRANSLATED:c2f2ac3b]
// Generate Track object
_video_track = dynamic_pointer_cast<VideoTrack>(Factory::getTrackBySdp(video));
if (!_video_track) {
return;
}
setBitRate(video, _video_track);
//生成RtpCodec对象以便解码rtp
// 生成RtpCodec对象以便解码rtp [AUTO-TRANSLATED:889376fd]
// Generate RtpCodec object to decode rtp
_video_rtp_decoder = Factory::getRtpDecoderByCodecId(_video_track->getCodecId());
if (!_video_rtp_decoder) {
//找不到相应的rtp解码器该track无效
// 找不到相应的rtp解码器该track无效 [AUTO-TRANSLATED:1c8c5eab]
// Cannot find the corresponding rtp decoder, the track is invalid
_video_track.reset();
return;
}
//设置rtp解码器代理生成的frame写入该Track
// 设置rtp解码器代理生成的frame写入该Track [AUTO-TRANSLATED:b2a2362e]
// Set the rtp decoder proxy, the generated frame is written to this Track
_video_rtp_decoder->addDelegate(_video_track);
addTrack(_video_track);
}

View File

@@ -23,6 +23,9 @@ public:
/**
* 加载sdp
* Load sdp
* [AUTO-TRANSLATED:235be34f]
*/
void loadSdp(const std::string &sdp);
@@ -30,12 +33,22 @@ public:
* 开始解复用
* @param rtp rtp包
* @return true 代表是i帧第一个rtp包
* Start demultiplexing
* @param rtp rtp packet
* @return true represents the first rtp packet of the i-frame
* [AUTO-TRANSLATED:116d3186]
*/
bool inputRtp(const RtpPacket::Ptr &rtp);
/**
* 获取节目总时长
* @return 节目总时长,单位秒
* Get the total duration of the program
* @return Total duration of the program, in seconds
* [AUTO-TRANSLATED:6b2ec56c]
*/
float getDuration() const;

View File

@@ -28,6 +28,12 @@ namespace mediakit {
* rtsp有关键的两要素分别是sdp、rtp包
* 只要生成了这两要素那么要实现rtsp推流、rtsp服务器就很简单了
* rtsp推拉流协议中先传递sdp然后再协商传输方式(tcp/udp/组播)最后一直传递rtp
* Data abstraction of rtsp media source
* Rtsp has two key elements, sdp and rtp packets
* As long as these two elements are generated, it is very simple to implement rtsp push stream and rtsp server
* In the rtsp push and pull stream protocol, sdp is transmitted first, then the transmission method (tcp/udp/multicast) is negotiated, and finally rtp is continuously transmitted
* [AUTO-TRANSLATED:e04eee56]
*/
class RtspMediaSource : public MediaSource, public toolkit::RingDelegate<RtpPacket::Ptr>, private PacketCache<RtpPacket> {
public:
@@ -41,6 +47,13 @@ public:
* @param app 应用名
* @param stream_id 流id
* @param ring_size 可以设置固定的环形缓冲大小0则自适应
* Constructor
* @param vhost Virtual host name
* @param app Application name
* @param stream_id Stream id
* @param ring_size You can set a fixed ring buffer size, 0 is adaptive
* [AUTO-TRANSLATED:5dd23423]
*/
RtspMediaSource(const MediaTuple& tuple, int ring_size = RTP_GOP_SIZE): MediaSource(RTSP_SCHEMA, tuple), _ring_size(ring_size) {}
@@ -54,6 +67,9 @@ public:
/**
* 获取媒体源的环形缓冲
* Get the ring buffer of the media source
* [AUTO-TRANSLATED:91a762bc]
*/
const RingType::Ptr &getRing() const {
return _ring;
@@ -73,6 +89,9 @@ public:
/**
* 获取播放器个数
* Get the number of players
* [AUTO-TRANSLATED:a451c846]
*/
int readerCount() override {
return _ring ? _ring->readerCount() : 0;
@@ -80,6 +99,9 @@ public:
/**
* 获取该源的sdp
* Get the sdp of this source
* [AUTO-TRANSLATED:ebc43430]
*/
const std::string &getSdp() const {
return _sdp;
@@ -91,6 +113,9 @@ public:
/**
* 获取相应轨道的ssrc
* Get the ssrc of the corresponding track
* [AUTO-TRANSLATED:d26d7f76]
*/
virtual uint32_t getSsrc(TrackType trackType) {
assert(trackType >= 0 && trackType < TrackMax);
@@ -103,6 +128,9 @@ public:
/**
* 获取相应轨道的seqence
* Get the sequence of the corresponding track
* [AUTO-TRANSLATED:24b0ee74]
*/
virtual uint16_t getSeqence(TrackType trackType) {
assert(trackType >= 0 && trackType < TrackMax);
@@ -115,16 +143,25 @@ public:
/**
* 获取相应轨道的时间戳,单位毫秒
* Get the timestamp of the corresponding track, in milliseconds
* [AUTO-TRANSLATED:564a0794]
*/
uint32_t getTimeStamp(TrackType trackType) override;
/**
* 更新时间戳
* Update timestamp
* [AUTO-TRANSLATED:8defe253]
*/
void setTimeStamp(uint32_t stamp) override;
/**
* 设置sdp
* Set sdp
* [AUTO-TRANSLATED:76a533c4]
*/
virtual void setSdp(const std::string &sdp);
@@ -132,6 +169,11 @@ public:
* 输入rtp
* @param rtp rtp包
* @param keyPos 该包是否为关键帧的第一个包
* Input rtp
* @param rtp rtp packet
* @param keyPos Whether this packet is the first packet of a key frame
* [AUTO-TRANSLATED:fe55afe8]
*/
void onWrite(RtpPacket::Ptr rtp, bool keyPos) override;
@@ -145,9 +187,15 @@ private:
* 批量flush rtp包时触发该函数
* @param rtp_list rtp包列表
* @param key_pos 是否包含关键帧
* Trigger this function when flushing rtp packets in batches
* @param rtp_list rtp packet list
* @param key_pos Whether it contains a key frame
* [AUTO-TRANSLATED:612c574b]
*/
void onFlush(std::shared_ptr<toolkit::List<RtpPacket::Ptr> > rtp_list, bool key_pos) override {
//如果不存在视频那么就没有存在GOP缓存的意义所以is_key一直为true确保一直清空GOP缓存
// 如果不存在视频那么就没有存在GOP缓存的意义所以is_key一直为true确保一直清空GOP缓存 [AUTO-TRANSLATED:5818a8d8]
// If there is no video, then there is no point in having a GOP cache, so is_key is always true to ensure that the GOP cache is always cleared
_ring->write(std::move(rtp_list), _have_video ? key_pos : true);
}

View File

@@ -16,14 +16,16 @@ void RtspMediaSource::setSdp(const std::string &sdp) {
uint32_t RtspMediaSource::getTimeStamp(TrackType trackType) {
assert(trackType >= TrackInvalid && trackType < TrackMax);
if (trackType != TrackInvalid) {
//获取某track的时间戳
// 获取某track的时间戳 [AUTO-TRANSLATED:e3fecb81]
// Get the timestamp of a track
auto &track = _tracks[trackType];
if (track) {
return track->_time_stamp;
}
}
//获取所有track的最小时间戳
// 获取所有track的最小时间戳 [AUTO-TRANSLATED:8cf9218b]
// Get the minimum timestamp of all tracks
uint32_t ret = UINT32_MAX;
for (auto &track : _tracks) {
if (track && track->_time_stamp < ret) {
@@ -35,6 +37,9 @@ uint32_t RtspMediaSource::getTimeStamp(TrackType trackType) {
/**
* 更新时间戳
* Update timestamp
* [AUTO-TRANSLATED:fa02a89e]
*/
void RtspMediaSource::setTimeStamp(uint32_t stamp) {
for (auto &track : _tracks) {
@@ -63,8 +68,10 @@ void RtspMediaSource::onWrite(RtpPacket::Ptr rtp, bool keyPos) {
}
strongSelf->onReaderChanged(size);
};
//GOP默认缓冲512组RTP包每组RTP包时间戳相同(如果开启合并写了那么每组为合并写时间内的RTP包),
//每次遇到关键帧第一个RTP包则会清空GOP缓存(因为有新的关键帧了,同样可以实现秒开)
// GOP默认缓冲512组RTP包每组RTP包时间戳相同(如果开启合并写了那么每组为合并写时间内的RTP包), [AUTO-TRANSLATED:dc09b92e]
// GOP defaults to buffering 512 groups of RTP packets, each group of RTP packets has the same timestamp (if merge writing is enabled, then each group is the RTP packet within the merge writing time),
// 每次遇到关键帧第一个RTP包则会清空GOP缓存(因为有新的关键帧了,同样可以实现秒开) [AUTO-TRANSLATED:db44dc72]
// Every time a key frame's first RTP packet is encountered, the GOP cache will be cleared (because there is a new key frame, which can also achieve instant playback)
_ring = std::make_shared<RingType>(_ring_size, std::move(lam));
if (!_sdp.empty()) {
regist();
@@ -92,16 +99,20 @@ void RtspMediaSourceImp::setSdp(const std::string &strSdp)
void RtspMediaSourceImp::onWrite(RtpPacket::Ptr rtp, bool key_pos)
{
if (_all_track_ready && !_muxer->isEnabled()) {
//获取到所有Track后并且未开启转协议那么不需要解复用rtp
//在关闭rtp解复用后无法知道是否为关键帧这样会导致无法秒开或者开播花屏
// 获取到所有Track后并且未开启转协议那么不需要解复用rtp [AUTO-TRANSLATED:31cbc558]
// After getting all Tracks and not enabling protocol conversion, there is no need to demultiplex rtp
// 在关闭rtp解复用后无法知道是否为关键帧这样会导致无法秒开或者开播花屏 [AUTO-TRANSLATED:279f1332]
// After closing rtp demultiplexing, it is impossible to know whether it is a key frame, which will lead to the inability to achieve instant playback or the screen will be garbled when playing
key_pos = rtp->type == TrackVideo;
} else {
//需要解复用rtp
// 需要解复用rtp [AUTO-TRANSLATED:0deaf9f1]
// Need to demultiplex rtp
key_pos = _demuxer->inputRtp(rtp);
}
GET_CONFIG(bool, directProxy, Rtsp::kDirectProxy);
if (directProxy) {
//直接代理模式才直接使用原始rtp
// 直接代理模式才直接使用原始rtp [AUTO-TRANSLATED:afd4ae3b]
// Only the direct proxy mode directly uses the original rtp
RtspMediaSource::onWrite(std::move(rtp), key_pos);
}
}
@@ -109,14 +120,17 @@ void RtspMediaSourceImp::onWrite(RtpPacket::Ptr rtp, bool key_pos)
void RtspMediaSourceImp::setProtocolOption(const ProtocolOption &option)
{
GET_CONFIG(bool, direct_proxy, Rtsp::kDirectProxy);
//开启直接代理模式时rtsp直接代理不重复产生但是有些rtsp推流端由于sdp中已有sps ppsrtp中就不再包括sps pps,
//导致rtc无法播放所以在rtsp推流rtc播放时建议关闭直接代理模式
// 开启直接代理模式时rtsp直接代理不重复产生但是有些rtsp推流端由于sdp中已有sps ppsrtp中就不再包括sps pps, [AUTO-TRANSLATED:1bbc0e31]
// When direct proxy mode is enabled, rtsp is directly proxied and not duplicated; however, some rtsp push stream ends, because there are already sps pps in the sdp, rtp no longer includes sps pps,
// 导致rtc无法播放所以在rtsp推流rtc播放时建议关闭直接代理模式 [AUTO-TRANSLATED:2c705dec]
// This leads to the inability of rtc to play, so it is recommended to turn off direct proxy mode when rtsp pushes the stream and rtc plays
_option = option;
_option.enable_rtsp = !direct_proxy;
_muxer = std::make_shared<MultiMediaSourceMuxer>(_tuple, _demuxer->getDuration(), _option);
_muxer->setMediaListener(getListener());
_muxer->setTrackListener(std::static_pointer_cast<RtspMediaSourceImp>(shared_from_this()));
//让_muxer对象拦截一部分事件(比如说录像相关事件)
// 让_muxer对象拦截一部分事件(比如说录像相关事件) [AUTO-TRANSLATED:32320477]
// Let the _muxer object intercept some events (such as recording related events)
MediaSource::setListener(_muxer);
for (auto &track : _demuxer->getTracks(false)) {

View File

@@ -27,21 +27,37 @@ public:
* @param app 应用名
* @param id 流id
* @param ringSize 环形缓存大小
* Constructor
* @param vhost Virtual host
* @param app Application name
* @param id Stream id
* @param ringSize Ring buffer size
* [AUTO-TRANSLATED:7679d212]
*/
RtspMediaSourceImp(const MediaTuple& tuple, int ringSize = RTP_GOP_SIZE);
/**
* 设置sdp
* Set sdp
* [AUTO-TRANSLATED:76a533c4]
*/
void setSdp(const std::string &strSdp) override;
/**
* 输入rtp并解析
* Input rtp and parse
* [AUTO-TRANSLATED:778f743f]
*/
void onWrite(RtpPacket::Ptr rtp, bool key_pos) override;
/**
* 获取观看总人数,包括(hls/rtsp/rtmp)
* Get total number of viewers, including (hls/rtsp/rtmp)
* [AUTO-TRANSLATED:19a26d5a]
*/
int totalReaderCount() override {
return readerCount() + (_muxer ? _muxer->totalReaderCount() : 0);
@@ -49,6 +65,9 @@ public:
/**
* 设置协议转换选项
* Set protocol conversion options
* [AUTO-TRANSLATED:a6a9b24a]
*/
void setProtocolOption(const ProtocolOption &option);
@@ -58,6 +77,9 @@ public:
/**
* _demuxer触发的添加Track事件
* _demuxer triggered add Track event
* [AUTO-TRANSLATED:80dbcf16]
*/
bool addTrack(const Track::Ptr &track) override {
if (_muxer) {
@@ -71,6 +93,9 @@ public:
/**
* _demuxer触发的Track添加完毕事件
* _demuxer triggered Track add complete event
* [AUTO-TRANSLATED:939cb312]
*/
void addTrackCompleted() override {
if (_muxer) {
@@ -86,6 +111,9 @@ public:
/**
* _muxer触发的所有Track就绪的事件
* _muxer triggered all Track ready event
* [AUTO-TRANSLATED:1d34b7e0]
*/
void onAllTrackReady() override{
_all_track_ready = true;
@@ -94,13 +122,19 @@ public:
/**
* 设置事件监听器
* @param listener 监听器
* Set event listener
* @param listener Listener
* [AUTO-TRANSLATED:d829419b]
*/
void setListener(const std::weak_ptr<MediaSourceEvent> &listener) override{
if (_muxer) {
//_muxer对象不能处理的事件再给listener处理
// _muxer对象不能处理的事件再给listener处理 [AUTO-TRANSLATED:47858305]
// _muxer object cannot handle the event, then give it to the listener
_muxer->setMediaListener(listener);
} else {
//未创建_muxer对象事件全部给listener处理
// 未创建_muxer对象事件全部给listener处理 [AUTO-TRANSLATED:eec04bc3]
// The _muxer object is not created, all events are given to the listener
MediaSource::setListener(listener);
}
}

View File

@@ -75,7 +75,8 @@ public:
}
bool isEnabled() {
//缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存
// 缓存尚未清空时还允许触发inputFrame函数以便及时清空缓存 [AUTO-TRANSLATED:7cfd4d49]
// The inputFrame function is still allowed to be triggered when the cache has not been cleared, so that the cache can be cleared in time.
return _option.rtsp_demand ? (_clear_cache ? true : _enabled) : true;
}

View File

@@ -21,19 +21,23 @@ void RtspMuxer::onRtp(RtpPacket::Ptr in, bool is_key) {
if (_live) {
auto &ref = _tracks[in->track_index];
if (ref.rtp_stamp != in->getHeader()->stamp) {
// rtp时间戳变化才计算ntp节省cpu资源
// rtp时间戳变化才计算ntp节省cpu资源 [AUTO-TRANSLATED:729d54f2]
// Only calculate NTP when the RTP timestamp changes, saving CPU resources
int64_t stamp_ms = in->getStamp() * uint64_t(1000) / in->sample_rate;
int64_t stamp_ms_inc;
// 求rtp时间戳增量
// 求rtp时间戳增量 [AUTO-TRANSLATED:f6ba022f]
// Get the RTP timestamp increment
ref.stamp.revise(stamp_ms, stamp_ms, stamp_ms_inc, stamp_ms_inc);
ref.rtp_stamp = in->getHeader()->stamp;
ref.ntp_stamp = stamp_ms_inc + _ntp_stamp_start;
}
// rtp拦截入口此处统一赋值ntp
// rtp拦截入口此处统一赋值ntp [AUTO-TRANSLATED:1412435a]
// RTP interception entry, set NTP here uniformly
in->ntp_stamp = ref.ntp_stamp;
} else {
// 点播情况下设置ntp时间戳为rtp时间戳加基准ntp时间戳
// 点播情况下设置ntp时间戳为rtp时间戳加基准ntp时间戳 [AUTO-TRANSLATED:b9f77de4]
// In on-demand scenarios, set the NTP timestamp to the RTP timestamp plus the base NTP timestamp
in->ntp_stamp = _ntp_stamp_start + (in->getStamp() * uint64_t(1000) / in->sample_rate);
}
_rtpRing->write(std::move(in), is_key);
@@ -57,7 +61,8 @@ RtspMuxer::RtspMuxer(const TitleSdp::Ptr &title) {
bool RtspMuxer::addTrack(const Track::Ptr &track) {
if (_track_existed[track->getTrackType()]) {
// rtsp不支持多个同类型track
// rtsp不支持多个同类型track [AUTO-TRANSLATED:87262d86]
// RTSP does not support multiple tracks of the same type
WarnL << "Already add a track kind of: " << track->getTrackTypeStr() << ", ignore track: " << track->getCodecName();
return false;
}
@@ -66,7 +71,8 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) {
auto &encoder = ref.encoder;
CHECK(!encoder);
// payload type 96以后则为动态pt
// payload type 96以后则为动态pt [AUTO-TRANSLATED:812ac0a2]
// Payload type 96 and above is dynamic PT
Sdp::Ptr sdp = track->getSdp(96 + _index);
if (!sdp) {
WarnL << "Unsupported codec: " << track->getCodecName();
@@ -78,21 +84,25 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) {
return false;
}
// 标记已经存在该类型track
// 标记已经存在该类型track [AUTO-TRANSLATED:ed79ebb5]
// Mark that a track of this type already exists
_track_existed[track->getTrackType()] = true;
{
static atomic<uint32_t> s_ssrc(0);
uint32_t ssrc = s_ssrc++;
if (!ssrc) {
// ssrc不能为0
// ssrc不能为0 [AUTO-TRANSLATED:312a1b47]
// SSRC cannot be 0
ssrc = s_ssrc++;
}
if (track->getTrackType() == TrackVideo) {
// 视频的ssrc是偶数方便调试
// 视频的ssrc是偶数方便调试 [AUTO-TRANSLATED:c22cd03f]
// The video SSRC is even for debugging convenience
ssrc = 2 * ssrc;
} else {
// 音频ssrc是奇数
// 音频ssrc是奇数 [AUTO-TRANSLATED:50688636]
// The audio SSRC is odd
ssrc = 2 * ssrc + 1;
}
GET_CONFIG(uint32_t, audio_mtu, Rtp::kAudioMtuSize);
@@ -101,7 +111,8 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) {
encoder->setRtpInfo(ssrc, mtu, sdp->getSampleRate(), sdp->getPayloadType(), 2 * track->getTrackType(), track->getIndex());
}
// 设置rtp输出环形缓存
// 设置rtp输出环形缓存 [AUTO-TRANSLATED:5ac7e24a]
// Set the RTP output circular buffer
encoder->setRtpRing(_rtpInterceptor);
auto str = sdp->getSdp();
@@ -109,11 +120,13 @@ bool RtspMuxer::addTrack(const Track::Ptr &track) {
str += std::to_string(_index);
str += "\r\n";
// 添加其sdp
// 添加其sdp [AUTO-TRANSLATED:80958925]
// Add its SDP
_sdp.append(str);
trySyncTrack();
// rtp的时间戳是pts允许回退
// rtp的时间戳是pts允许回退 [AUTO-TRANSLATED:f4a977fc]
// The RTP timestamp is PTS, allowing rollback
if (track->getTrackType() == TrackVideo) {
ref.stamp.enableRollback(true);
}

View File

@@ -36,6 +36,9 @@ private:
/**
* rtsp生成器
* RTSP generator
* [AUTO-TRANSLATED:2a72d801]
*/
class RtspMuxer : public MediaSinkInterface {
public:
@@ -43,39 +46,64 @@ public:
/**
* 构造函数
* Constructor
* [AUTO-TRANSLATED:41469869]
*/
RtspMuxer(const TitleSdp::Ptr &title = nullptr);
/**
* 获取完整的SDP字符串
* @return SDP字符串
* Get the complete SDP string
* @return SDP string
* [AUTO-TRANSLATED:f5d1b0a6]
*/
std::string getSdp() ;
/**
* 获取rtp环形缓存
* @return
* Get the RTP ring buffer
* @return
* [AUTO-TRANSLATED:644e8634]
*/
RtpRing::RingType::Ptr getRtpRing() const;
/**
* 添加ready状态的track
* Add a ready state track
* [AUTO-TRANSLATED:2d8138b3]
*/
bool addTrack(const Track::Ptr & track) override;
/**
* 写入帧数据
* @param frame 帧
* Write frame data
* @param frame Frame
* [AUTO-TRANSLATED:b7c92013]
*/
bool inputFrame(const Frame::Ptr &frame) override;
/**
* 刷新输出所有frame缓存
* Flush all frame buffers
* [AUTO-TRANSLATED:adaea568]
*/
void flush() override;
/**
* 重置所有track
* Reset all tracks
* [AUTO-TRANSLATED:f203fa3e]
*/
void resetTracks() override ;

View File

@@ -121,7 +121,8 @@ void RtspPlayer::onConnect(const SockException &err) {
void RtspPlayer::onRecv(const Buffer::Ptr &buf) {
if (_benchmark_mode && !_play_check_timer) {
// 在性能测试模式下如果rtsp握手完毕后不再解析rtp包
// 在性能测试模式下如果rtsp握手完毕后不再解析rtp包 [AUTO-TRANSLATED:747b5399]
// In performance test mode, if the RTSP handshake is complete, no RTP packets will be parsed
_rtp_recv_ticker.resetTime();
return;
}
@@ -134,14 +135,16 @@ void RtspPlayer::onRecv(const Buffer::Ptr &buf) {
}
void RtspPlayer::onError(const SockException &ex) {
// 定时器_pPlayTimer为空后表明握手结束了
// 定时器_pPlayTimer为空后表明握手结束了 [AUTO-TRANSLATED:06a369c2]
// After the timer _pPlayTimer is empty, it indicates that the handshake is complete
onPlayResult_l(ex, !_play_check_timer);
}
// from live555
bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
if (!_realm.empty()) {
// 已经认证过了
// 已经认证过了 [AUTO-TRANSLATED:f2db5f9c]
// It has been authenticated
return false;
}
@@ -173,7 +176,8 @@ bool RtspPlayer::handleAuthenticationFailure(const string &paramsStr) {
bool RtspPlayer::handleResponse(const string &cmd, const Parser &parser) {
string authInfo = parser["WWW-Authenticate"];
// 发送DESCRIBE命令后的回复
// 发送DESCRIBE命令后的回复 [AUTO-TRANSLATED:39629cf0]
// The response after sending the DESCRIBE command
if ((parser.status() == "401") && handleAuthenticationFailure(authInfo)) {
sendOptions();
return false;
@@ -204,7 +208,8 @@ void RtspPlayer::handleResDESCRIBE(const Parser &parser) {
_content_base.pop_back();
}
// 解析sdp
// 解析sdp [AUTO-TRANSLATED:ed3f07fe]
// Parse SDP
SdpParser sdpParser(parser.content());
_control_url = sdpParser.getControlUrl(_content_base);
@@ -237,7 +242,8 @@ void RtspPlayer::handleResDESCRIBE(const Parser &parser) {
sendSetup(0);
}
// 有必要的情况下创建udp端口
// 有必要的情况下创建udp端口 [AUTO-TRANSLATED:651202fc]
// Create UDP port if necessary
void RtspPlayer::createUdpSockIfNecessary(int track_idx) {
auto &rtpSockRef = _rtp_sock[track_idx];
auto &rtcpSockRef = _rtcp_sock[track_idx];
@@ -249,7 +255,8 @@ void RtspPlayer::createUdpSockIfNecessary(int track_idx) {
}
}
// 发送SETUP命令
// 发送SETUP命令 [AUTO-TRANSLATED:68a7ca33]
// Send SETUP command
void RtspPlayer::sendSetup(unsigned int track_idx) {
_on_response = std::bind(&RtspPlayer::handleResSETUP, this, placeholders::_1, track_idx);
auto &track = _sdp_track[track_idx];
@@ -314,10 +321,12 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
auto &pRtcpSockRef = _rtcp_sock[track_idx];
if (_rtp_type == Rtsp::RTP_MULTICAST) {
// udp组播
// udp组播 [AUTO-TRANSLATED:ccc90d1f]
// UDP multicast
auto multiAddr = transport_map["destination"];
pRtpSockRef = createSocket();
// 目前组播仅支持ipv4
// 目前组播仅支持ipv4 [AUTO-TRANSLATED:8215bfd2]
// Currently, multicast only supports IPv4
if (!pRtpSockRef->bindUdpSock(rtp_port, "0.0.0.0")) {
pRtpSockRef.reset();
throw std::runtime_error("open udp sock err");
@@ -327,33 +336,41 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
SockUtil::joinMultiAddr(fd, multiAddr.data(), get_local_ip().data());
}
// 设置rtcp发送端口
// 设置rtcp发送端口 [AUTO-TRANSLATED:f39b07bd]
// Set RTCP send port
pRtcpSockRef = createSocket();
// 目前组播仅支持ipv4
// 目前组播仅支持ipv4 [AUTO-TRANSLATED:8215bfd2]
// Currently, multicast only supports IPv4
if (!pRtcpSockRef->bindUdpSock(0, "0.0.0.0")) {
// 分配端口失败
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
throw runtime_error("open udp socket failed");
}
// 设置发送地址和发送端口
// 设置发送地址和发送端口 [AUTO-TRANSLATED:67e1cb6e]
// Set send address and send port
auto dst = SockUtil::make_sockaddr(get_peer_ip().data(), rtcp_port);
pRtcpSockRef->bindPeerAddr((struct sockaddr *)&(dst));
} else {
createUdpSockIfNecessary(track_idx);
// udp单播
// udp单播 [AUTO-TRANSLATED:7d16a875]
// UDP unicast
auto dst = SockUtil::make_sockaddr(get_peer_ip().data(), rtp_port);
pRtpSockRef->bindPeerAddr((struct sockaddr *)&(dst));
// 发送rtp打洞包
// 发送rtp打洞包 [AUTO-TRANSLATED:9a79d94f]
// Send RTP hole punching packet
pRtpSockRef->send("\xce\xfa\xed\xfe", 4);
dst = SockUtil::make_sockaddr(get_peer_ip().data(), rtcp_port);
// 设置rtcp发送目标为后续发送rtcp做准备
// 设置rtcp发送目标为后续发送rtcp做准备 [AUTO-TRANSLATED:70929b8e]
// Set RTCP send target, prepare for subsequent RTCP sending
pRtcpSockRef->bindPeerAddr((struct sockaddr *)&(dst));
}
auto peer_ip = get_peer_ip();
weak_ptr<RtspPlayer> weakSelf = static_pointer_cast<RtspPlayer>(shared_from_this());
// 设置rtp over udp接收回调处理函数
// 设置rtp over udp接收回调处理函数 [AUTO-TRANSLATED:6e74b593]
// Set RTP over UDP receive callback handler
pRtpSockRef->setOnRead([peer_ip, track_idx, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
@@ -368,7 +385,8 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
});
if (pRtcpSockRef) {
// 设置rtcp over udp接收回调处理函数
// 设置rtcp over udp接收回调处理函数 [AUTO-TRANSLATED:eed55b8e]
// Set RTCP over UDP receive callback handler
pRtcpSockRef->setOnRead([peer_ip, track_idx, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr, int addr_len) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
@@ -384,12 +402,15 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
}
if (track_idx < _sdp_track.size() - 1) {
// 需要继续发送SETUP命令
// 需要继续发送SETUP命令 [AUTO-TRANSLATED:d7ea1a7a]
// Need to continue sending SETUP command
sendSetup(track_idx + 1);
return;
}
// 所有setup命令发送完毕
// 发送play命令
// 所有setup命令发送完毕 [AUTO-TRANSLATED:be499080]
// All SETUP commands have been sent
// 发送play命令 [AUTO-TRANSLATED:47a826d1]
// Send PLAY command
if (_speed==0.0f) {
sendPause(type_play, 0);
} else {
@@ -399,7 +420,8 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int track_idx) {
}
void RtspPlayer::sendDescribe() {
// 发送DESCRIBE命令后处理函数:handleResDESCRIBE
// 发送DESCRIBE命令后处理函数:handleResDESCRIBE [AUTO-TRANSLATED:3c2b0ffe]
// Handle the response to the DESCRIBE command: handleResDESCRIBE
_on_response = std::bind(&RtspPlayer::handleResDESCRIBE, this, placeholders::_1);
sendRtspRequest("DESCRIBE", _play_url, { "Accept", "application/sdp" });
}
@@ -409,14 +431,16 @@ void RtspPlayer::sendOptions() {
if (!handleResponse("OPTIONS", parser)) {
return;
}
// 获取服务器支持的命令
// 获取服务器支持的命令 [AUTO-TRANSLATED:8a6a12f1]
// Get the commands supported by the server
_supported_cmd.clear();
auto public_val = split(parser["Public"], ",");
for (auto &cmd : public_val) {
trim(cmd);
_supported_cmd.emplace(cmd);
}
// 发送Describe请求获取sdp
// 发送Describe请求获取sdp [AUTO-TRANSLATED:f2e291d1]
// Send Describe request to get SDP
sendDescribe();
};
sendRtspRequest("OPTIONS", _play_url);
@@ -425,17 +449,20 @@ void RtspPlayer::sendOptions() {
void RtspPlayer::sendKeepAlive() {
_on_response = [](const Parser &parser) {};
if (_supported_cmd.find("GET_PARAMETER") != _supported_cmd.end()) {
// 支持GET_PARAMETER用此命令保活
// 支持GET_PARAMETER用此命令保活 [AUTO-TRANSLATED:b45cd737]
// Support GET_PARAMETER, use this command to keep alive
sendRtspRequest("GET_PARAMETER", _control_url);
} else {
// 不支持GET_PARAMETER用OPTIONS命令保活
// 不支持GET_PARAMETER用OPTIONS命令保活 [AUTO-TRANSLATED:3391350c]
// Do not support GET_PARAMETER, use OPTIONS command to keep alive
sendRtspRequest("OPTIONS", _play_url);
}
}
void RtspPlayer::sendPause(int type, uint32_t seekMS) {
_on_response = std::bind(&RtspPlayer::handleResPAUSE, this, placeholders::_1, type);
// 开启或暂停rtsp
// 开启或暂停rtsp [AUTO-TRANSLATED:8ba5b594]
// Start or pause RTSP
switch (type) {
case type_pause: sendRtspRequest("PAUSE", _control_url, {}); break;
case type_play:
@@ -476,14 +503,17 @@ void RtspPlayer::handleResPAUSE(const Parser &parser, int type) {
}
if (type == type_pause) {
// 暂停成功!
// 暂停成功! [AUTO-TRANSLATED:782cea77]
// Pause successfully!
_rtp_check_timer.reset();
return;
}
// play或seek成功
// play或seek成功 [AUTO-TRANSLATED:ba7b0da3]
// Play or seek successfully
uint32_t iSeekTo = 0;
// 修正时间轴
// 修正时间轴 [AUTO-TRANSLATED:5ab341f9]
// Correct the timeline
auto strRange = parser["Range"];
if (strRange.size()) {
auto strStart = findSubString(strRange.data(), "npt=", "-");
@@ -499,7 +529,8 @@ void RtspPlayer::handleResPAUSE(const Parser &parser, int type) {
void RtspPlayer::onWholeRtspPacket(Parser &parser) {
if (!start_with(parser.method(), "RTSP")) {
// 不是rtsp回复忽略
// 不是rtsp回复忽略 [AUTO-TRANSLATED:1dca8f64]
// Not an RTSP response, ignore
WarnL << "Not rtsp response: " << parser.method();
return;
}
@@ -511,7 +542,8 @@ void RtspPlayer::onWholeRtspPacket(Parser &parser) {
}
parser.clear();
} catch (std::exception &err) {
// 定时器_pPlayTimer为空后表明握手结束了
// 定时器_pPlayTimer为空后表明握手结束了 [AUTO-TRANSLATED:06a369c2]
// _pPlayTimer is empty after handshake ends
onPlayResult_l(SockException(Err_other, err.what()), !_play_check_timer);
}
}
@@ -536,14 +568,16 @@ void RtspPlayer::onRtpPacket(const char *data, size_t len) {
}
}
// 此处预留rtcp处理函数
// 此处预留rtcp处理函数 [AUTO-TRANSLATED:30c3afa8]
// Reserved for RTCP processing function
void RtspPlayer::onRtcpPacket(int track_idx, SdpTrack::Ptr &track, uint8_t *data, size_t len) {
auto rtcp_arr = RtcpHeader::loadFromBytes((char *)data, len);
for (auto &rtcp : rtcp_arr) {
_rtcp_context[track_idx]->onRtcp(rtcp);
if ((RtcpType)rtcp->pt == RtcpType::RTCP_SR) {
auto sr = (RtcpSR *)(rtcp);
// 设置rtp时间戳与ntp时间戳的对应关系
// 设置rtp时间戳与ntp时间戳的对应关系 [AUTO-TRANSLATED:e92f4749]
// Set the correspondence between RTP timestamp and NTP timestamp
setNtpStamp(track_idx, sr->rtpts, sr->getNtpUnixStampMS());
}
}
@@ -611,7 +645,8 @@ void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const Str
if (!_realm.empty() && !(*this)[Client::kRtspUser].empty()) {
if (!_md5_nonce.empty()) {
// MD5认证
// MD5认证 [AUTO-TRANSLATED:0640fa6a]
// MD5 authentication
/*
response计算方法如下
RTSP客户端应该使用username + password并计算response如下:
@@ -619,6 +654,15 @@ void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const Str
response = md5( password:nonce:md5(public_method:url) );
(2)当password为ANSI字符串,则
response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
/*
The response calculation method is as follows:
The RTSP client should use username + password and calculate the response as follows:
(1) When password is MD5 encoded, then
response = md5( password:nonce:md5(public_method:url) );
(2) When password is ANSI string, then
response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
* [AUTO-TRANSLATED:7858b67d]
*/
string encrypted_pwd = (*this)[Client::kRtspPwd];
if (!(*this)[Client::kRtspPwdIsMD5].as<bool>()) {
@@ -634,7 +678,8 @@ void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const Str
printer << "response=\"" << response << "\"";
header.emplace("Authorization", printer);
} else if (!(*this)[Client::kRtspPwdIsMD5].as<bool>()) {
// base64认证
// base64认证 [AUTO-TRANSLATED:06d26447]
// Base64 authentication
auto authStrBase64 = encodeBase64((*this)[Client::kRtspUser] + ":" + (*this)[Client::kRtspPwd]);
header.emplace("Authorization", StrPrinter << "Basic " << authStrBase64);
}
@@ -657,11 +702,13 @@ void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) {
auto &ticker = _rtcp_send_ticker[track_idx];
if (ticker.elapsedTime() < _beat_interval_ms) {
// 心跳时间未到
// 心跳时间未到 [AUTO-TRANSLATED:265d4e62]
// Heartbeat time not reached
return;
}
// 有些rtsp服务器需要rtcp保活有些需要发送信令保活; rtcp与rtsp信令轮流心跳该特性用于兼容issue:#642
// 有些rtsp服务器需要rtcp保活有些需要发送信令保活; rtcp与rtsp信令轮流心跳该特性用于兼容issue:#642 [AUTO-TRANSLATED:a36070c5]
// Some RTSP servers require RTCP keep-alive, some require sending signaling keep-alive; RTCP and RTSP signaling alternate heartbeat, this feature is used to be compatible with issue:#642
auto &rtcp_flag = _send_rtcp[track_idx];
ticker.resetTime();
@@ -672,16 +719,19 @@ void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) {
default: rtcp_flag = !rtcp_flag; break;
}
// 发送信令保活
// 发送信令保活 [AUTO-TRANSLATED:0ef0747e]
// Send signaling keep-alive
if (!rtcp_flag) {
if (track_idx == 0) {
// 两个track无需同时触发发送信令保活
// 两个track无需同时触发发送信令保活 [AUTO-TRANSLATED:7dde4aec]
// Two tracks do not need to trigger sending signaling keep-alive at the same time
sendKeepAlive();
}
return;
}
// 发送rtcp
// 发送rtcp [AUTO-TRANSLATED:5c7aad87]
// Send RTCP
static auto send_rtcp = [](RtspPlayer *thiz, int index, Buffer::Ptr ptr) {
if (thiz->_rtp_type == Rtsp::RTP_TCP) {
auto &track = thiz->_sdp_track[index];
@@ -703,27 +753,33 @@ void RtspPlayer::onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) {
void RtspPlayer::onPlayResult_l(const SockException &ex, bool handshake_done) {
if (ex.getErrCode() == Err_shutdown) {
// 主动shutdown的不触发回调
// 主动shutdown的不触发回调 [AUTO-TRANSLATED:21f9c396]
// Active shutdown, do not trigger callback
return;
}
WarnL << ex.getErrCode() << " " << ex.what();
if (!handshake_done) {
// 开始播放阶段
// 开始播放阶段 [AUTO-TRANSLATED:7ef385fc]
// Start playback stage
_play_check_timer.reset();
onPlayResult(ex);
// 是否为性能测试模式
// 是否为性能测试模式 [AUTO-TRANSLATED:871a0e65]
// Whether it is performance test mode
_benchmark_mode = (*this)[Client::kBenchmarkMode].as<int>();
} else if (ex) {
// 播放成功后异常断开回调
// 播放成功后异常断开回调 [AUTO-TRANSLATED:3fe28e4f]
// Callback for abnormal disconnection after successful playback
onShutdown(ex);
} else {
// 恢复播放
// 恢复播放 [AUTO-TRANSLATED:7a99afd6]
// Resume playback
onResume();
}
if (!ex) {
// 播放成功恢复rtp接收超时定时器
// 播放成功恢复rtp接收超时定时器 [AUTO-TRANSLATED:0ebefcb5]
// Playback successful, restore RTP receive timeout timer
_rtp_recv_ticker.resetTime();
auto timeoutMS = (*this)[Client::kMediaTimeoutMS].as<uint64_t>();
weak_ptr<RtspPlayer> weakSelf = static_pointer_cast<RtspPlayer>(shared_from_this());
@@ -733,13 +789,15 @@ void RtspPlayer::onPlayResult_l(const SockException &ex, bool handshake_done) {
return false;
}
if (strongSelf->_rtp_recv_ticker.elapsedTime() > timeoutMS) {
// 接收rtp媒体数据包超时
// 接收rtp媒体数据包超时 [AUTO-TRANSLATED:601b8c0c]
// Receive RTP media data packet timeout
strongSelf->onPlayResult_l(SockException(Err_timeout, "receive rtp timeout"), true);
return false;
}
return true;
};
// 创建rtp数据接收超时检测定时器
// 创建rtp数据接收超时检测定时器 [AUTO-TRANSLATED:edbffc19]
// Create RTP data receive timeout detection timer
_rtp_check_timer = std::make_shared<Timer>(timeoutMS / 2000.0f, lam, getPoller());
} else {
sendTeardown();
@@ -806,7 +864,8 @@ bool RtspPlayerImp::onCheckSDP(const std::string &sdp) {
}
void RtspPlayerImp::onRecvRTP(RtpPacket::Ptr rtp, const SdpTrack::Ptr &track) {
// rtp解复用时可以判断是否为关键帧起始位置
// rtp解复用时可以判断是否为关键帧起始位置 [AUTO-TRANSLATED:fb7d9b6e]
// When demultiplexing RTP, it can be determined whether it is the starting position of the key frame
auto key_pos = _demuxer->inputRtp(rtp);
if (_rtsp_media_src) {
_rtsp_media_src->onWrite(std::move(rtp), key_pos);

View File

@@ -24,7 +24,8 @@
namespace mediakit {
//实现了rtsp播放器协议部分的功能及数据接收功能
// 实现了rtsp播放器协议部分的功能及数据接收功能 [AUTO-TRANSLATED:c1ed5c0f]
// Implemented the rtsp player protocol part functionality, and data receiving functionality
class RtspPlayer : public PlayerBase, public toolkit::TcpClient, public RtspSplitter, public RtpReceiver {
public:
using Ptr = std::shared_ptr<RtspPlayer>;
@@ -39,7 +40,8 @@ public:
float getPacketLossRate(TrackType type) const override;
protected:
//派生类回调函数
// 派生类回调函数 [AUTO-TRANSLATED:61e20903]
// Derived class callback function
virtual bool onCheckSDP(const std::string &sdp) = 0;
virtual void onRecvRTP(RtpPacket::Ptr rtp, const SdpTrack::Ptr &track) = 0;
uint32_t getProgressMilliSecond() const;
@@ -48,6 +50,10 @@ protected:
/**
* 收到完整的rtsp包回调包括sdp等content数据
* @param parser rtsp包
* Callback for receiving a complete rtsp packet, including sdp and other content data
* @param parser rtsp packet
* [AUTO-TRANSLATED:4d3c2056]
*/
void onWholeRtspPacket(Parser &parser) override ;
@@ -55,6 +61,11 @@ protected:
* 收到rtp包回调
* @param data
* @param len
* Callback for receiving rtp packet
* @param data
* @param len
* [AUTO-TRANSLATED:c8f7c9bb]
*/
void onRtpPacket(const char *data,size_t len) override ;
@@ -62,6 +73,11 @@ protected:
* rtp数据包排序后输出
* @param rtp rtp数据包
* @param track_idx track索引
* Output rtp data packets after sorting
* @param rtp rtp data packet
* @param track_idx track index
* [AUTO-TRANSLATED:8f9ca364]
*/
void onRtpSorted(RtpPacket::Ptr rtp, int track_idx) override;
@@ -69,6 +85,11 @@ protected:
* 解析出rtp但还未排序
* @param rtp rtp数据包
* @param track_index track索引
* Parse out rtp but not yet sorted
* @param rtp rtp data packet
* @param track_index track index
* [AUTO-TRANSLATED:c1636911]
*/
void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index) override;
@@ -78,6 +99,13 @@ protected:
* @param track sdp相关信息
* @param data rtcp内容
* @param len rtcp内容长度
* Callback for receiving RTCP packet
* @param track_idx track index
* @param track sdp related information
* @param data rtcp content
* @param len rtcp content length
* [AUTO-TRANSLATED:1a2cfa4f]
*/
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, uint8_t *data, size_t len);
@@ -109,27 +137,35 @@ private:
void createUdpSockIfNecessary(int track_idx);
private:
//是否为性能测试模式
// 是否为性能测试模式 [AUTO-TRANSLATED:1fde8234]
// Whether it is performance test mode
bool _benchmark_mode = false;
//轮流发送rtcp与GET_PARAMETER保活
// 轮流发送rtcp与GET_PARAMETER保活 [AUTO-TRANSLATED:5b6f9c37]
// Send rtcp and GET_PARAMETER keep-alive in turn
bool _send_rtcp[2] = {true, true};
// 心跳类型
// 心跳类型 [AUTO-TRANSLATED:c22abb05]
// Heartbeat type
uint32_t _beat_type = 0;
// 心跳保护间隔
// 心跳保护间隔 [AUTO-TRANSLATED:de16d9c9]
// Heartbeat protection interval
uint32_t _beat_interval_ms = 0;
std::string _play_url;
// rtsp开始倍速
// rtsp开始倍速 [AUTO-TRANSLATED:9ab84508]
// Rtsp start speed
float _speed= 0.0f;
std::vector<SdpTrack::Ptr> _sdp_track;
std::function<void(const Parser&)> _on_response;
//RTP端口,trackid idx 为数组下标
// RTP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:77c186bb]
// RTP port, trackid idx is the array subscript
toolkit::Socket::Ptr _rtp_sock[2];
//RTCP端口,trackid idx 为数组下标
// RTCP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:446a7861]
// RTCP port, trackid idx is the array subscript
toolkit::Socket::Ptr _rtcp_sock[2];
//rtsp鉴权相关
// rtsp鉴权相关 [AUTO-TRANSLATED:947dc6a3]
// Rtsp authentication related
std::string _md5_nonce;
std::string _realm;
//rtsp info
@@ -139,19 +175,24 @@ private:
std::string _control_url;
Rtsp::eRtpType _rtp_type = Rtsp::RTP_TCP;
//当前rtp时间戳
// 当前rtp时间戳 [AUTO-TRANSLATED:410f2691]
// Current rtp timestamp
uint32_t _stamp[2] = {0, 0};
//超时功能实现
// 超时功能实现 [AUTO-TRANSLATED:1d603b3a]
// Timeout function implementation
toolkit::Ticker _rtp_recv_ticker;
std::shared_ptr<toolkit::Timer> _play_check_timer;
std::shared_ptr<toolkit::Timer> _rtp_check_timer;
//服务器支持的命令
// 服务器支持的命令 [AUTO-TRANSLATED:f7f589bf]
// Server supported commands
std::set<std::string> _supported_cmd;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
// rtcp发送时间,trackid idx 为数组下标 [AUTO-TRANSLATED:bf3248b1]
// Rtcp send time, trackid idx is the array subscript
toolkit::Ticker _rtcp_send_ticker[2];
//统计rtp并发送rtcp
// 统计rtp并发送rtcp [AUTO-TRANSLATED:0ac2b665]
// Statistics rtp and send rtcp
std::vector<RtcpContext::Ptr> _rtcp_context;
};

View File

@@ -60,7 +60,8 @@ public:
std::vector<Track::Ptr> getTracks(bool ready = true) const override;
private:
//派生类回调函数
// 派生类回调函数 [AUTO-TRANSLATED:61e20903]
// Derived class callback function
bool onCheckSDP(const std::string &sdp) override;
void onRecvRTP(RtpPacket::Ptr rtp, const SdpTrack::Ptr &track) override;

View File

@@ -101,15 +101,18 @@ void RtspPusher::publish(const string &url_str) {
void RtspPusher::onPublishResult_l(const SockException &ex, bool handshake_done) {
DebugL << ex.what();
if (ex.getErrCode() == Err_shutdown) {
//主动shutdown的不触发回调
// 主动shutdown的不触发回调 [AUTO-TRANSLATED:bd97b1c1]
// Actively shutdown, do not trigger callback
return;
}
if (!handshake_done) {
//播放结果回调
// 播放结果回调 [AUTO-TRANSLATED:a5714269]
// Playback result callback
_publish_timer.reset();
onPublishResult(ex);
} else {
//播放成功后异常断开回调
// 播放成功后异常断开回调 [AUTO-TRANSLATED:b5c5fa80]
// Callback for abnormal disconnection after playback success
onShutdown(ex);
}
@@ -119,7 +122,8 @@ void RtspPusher::onPublishResult_l(const SockException &ex, bool handshake_done)
}
void RtspPusher::onError(const SockException &ex) {
//定时器_pPublishTimer为空后表明握手结束了
// 定时器_pPublishTimer为空后表明握手结束了 [AUTO-TRANSLATED:630ec31e]
// The timer _pPublishTimer is empty, indicating that the handshake is over
onPublishResult_l(ex, !_publish_timer);
}
@@ -136,7 +140,8 @@ void RtspPusher::onRecv(const Buffer::Ptr &buf){
input(buf->data(), buf->size());
} catch (exception &e) {
SockException ex(Err_other, e.what());
//定时器_pPublishTimer为空后表明握手结束了
// 定时器_pPublishTimer为空后表明握手结束了 [AUTO-TRANSLATED:630ec31e]
// The timer _pPublishTimer is empty, indicating that the handshake is over
onPublishResult_l(ex, !_publish_timer);
}
}
@@ -171,7 +176,8 @@ void RtspPusher::sendAnnounce() {
if (!src) {
throw std::runtime_error("the media source was released");
}
//解析sdp
// 解析sdp [AUTO-TRANSLATED:a2d549e2]
// Parse sdp
_sdp_parser.load(src->getSdp());
_track_vec = _sdp_parser.getAvailableTrack();
if (_track_vec.empty()) {
@@ -187,7 +193,8 @@ void RtspPusher::sendAnnounce() {
void RtspPusher::handleResAnnounce(const Parser &parser) {
string authInfo = parser["WWW-Authenticate"];
//发送DESCRIBE命令后的回复
// 发送DESCRIBE命令后的回复 [AUTO-TRANSLATED:924afd2e]
// Reply after sending DESCRIBE command
if ((parser.status() == "401") && handleAuthenticationFailure(authInfo)) {
sendAnnounce();
return;
@@ -219,7 +226,8 @@ void RtspPusher::handleResAnnounce(const Parser &parser) {
bool RtspPusher::handleAuthenticationFailure(const string &params_str) {
if (!_realm.empty()) {
//已经认证过了
// 已经认证过了 [AUTO-TRANSLATED:3c8ce1d6]
// Already authenticated
return false;
}
@@ -249,7 +257,8 @@ bool RtspPusher::handleAuthenticationFailure(const string &params_str) {
return false;
}
//有必要的情况下创建udp端口
// 有必要的情况下创建udp端口 [AUTO-TRANSLATED:b59b7389]
// Create UDP port if necessary
void RtspPusher::createUdpSockIfNecessary(int track_idx){
auto &rtpSockRef = _rtp_sock[track_idx];
auto &rtcpSockRef = _rtcp_sock[track_idx];
@@ -312,17 +321,20 @@ void RtspPusher::handleResSetup(const Parser &parser, unsigned int track_idx) {
auto &rtcp_sock = _rtcp_sock[track_idx];
auto rtpto = SockUtil::make_sockaddr(get_peer_ip().data(), rtp_port);
//设置rtp发送目标为后续发送rtp做准备
// 设置rtp发送目标为后续发送rtp做准备 [AUTO-TRANSLATED:5ae9bd72]
// Set RTP sending target, prepare for subsequent RTP sending
rtp_sock->bindPeerAddr((struct sockaddr *) &(rtpto));
//设置rtcp发送目标为后续发送rtcp做准备
// 设置rtcp发送目标为后续发送rtcp做准备 [AUTO-TRANSLATED:a487732d]
// Set RTCP sending target, prepare for subsequent RTCP sending
auto rtcpto = SockUtil::make_sockaddr(get_peer_ip().data(), rtcp_port);
rtcp_sock->bindPeerAddr((struct sockaddr *)&(rtcpto));
auto peer_ip = get_peer_ip();
weak_ptr<RtspPusher> weakSelf = static_pointer_cast<RtspPusher>(shared_from_this());
if(rtcp_sock) {
//设置rtcp over udp接收回调处理函数
// 设置rtcp over udp接收回调处理函数 [AUTO-TRANSLATED:59963785]
// Set RTCP over UDP receive callback handler
rtcp_sock->setOnRead([peer_ip, track_idx, weakSelf](const Buffer::Ptr &buf, struct sockaddr *addr , int addr_len) {
auto strongSelf = weakSelf.lock();
if (!strongSelf) {
@@ -340,7 +352,8 @@ void RtspPusher::handleResSetup(const Parser &parser, unsigned int track_idx) {
RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP);
if (track_idx < _track_vec.size() - 1) {
//需要继续发送SETUP命令
// 需要继续发送SETUP命令 [AUTO-TRANSLATED:fddda4c6]
// Need to continue sending SETUP command
sendSetup(track_idx + 1);
return;
}
@@ -359,7 +372,8 @@ void RtspPusher::updateRtcpContext(const RtpPacket::Ptr &rtp){
auto &rtcp_ctx = _rtcp_context[track_index];
rtcp_ctx->onRtp(rtp->getSeq(), rtp->getStamp(), rtp->ntp_stamp, rtp->sample_rate, rtp->size() - RtpPacket::kRtpTcpHeaderSize);
if (!rtp->ntp_stamp && !rtp->getStamp()) {
// 忽略时间戳都为0的rtp
// 忽略时间戳都为0的rtp [AUTO-TRANSLATED:6b793565]
// Ignore RTP with all timestamps being 0
return;
}
//send rtcp every 5 second
@@ -469,7 +483,8 @@ void RtspPusher::sendRecord() {
}
});
if (_rtp_type != Rtsp::RTP_TCP) {
/////////////////////////心跳/////////////////////////////////
// ///////////////////////心跳///////////////////////////////// [AUTO-TRANSLATED:4e72777b]
// ///////////////////////Heartbeat/////////////////////////////////
_beat_timer.reset(new Timer((*this)[Client::kBeatIntervalMS].as<int>() / 1000.0f, [weak_self]() {
auto strong_self = weak_self.lock();
if (!strong_self) {
@@ -480,7 +495,8 @@ void RtspPusher::sendRecord() {
}, getPoller()));
}
onPublishResult_l(SockException(Err_success, "success"), false);
//提升发送性能
// 提升发送性能 [AUTO-TRANSLATED:90630751]
// Improve sending performance
setSocketFlags();
};
sendRtspRequest("RECORD", _content_base, {"Range", "npt=0.000-"});
@@ -489,7 +505,8 @@ void RtspPusher::sendRecord() {
void RtspPusher::setSocketFlags(){
GET_CONFIG(int, merge_write_ms, General::kMergeWriteMS);
if (merge_write_ms > 0) {
//提高发送性能
// 提高发送性能 [AUTO-TRANSLATED:de96ec30]
// Improve sending performance
setSendFlags(SOCKET_DEFAULE_FLAGS | FLAG_MORE);
SockUtil::setNoDelay(getSock()->rawFD(), false);
}
@@ -519,7 +536,8 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrC
if (!_realm.empty() && !(*this)[Client::kRtspUser].empty()) {
if (!_nonce.empty()) {
//MD5认证
// MD5认证 [AUTO-TRANSLATED:57936f0b]
// MD5 authentication
/*
response计算方法如下
RTSP客户端应该使用username + password并计算response如下:
@@ -527,6 +545,15 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrC
response = md5( password:nonce:md5(public_method:url) );
(2)当password为ANSI字符串,则
response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
/*
The response calculation method is as follows:
The RTSP client should use username + password and calculate the response as follows:
(1) When password is MD5 encoded, then
response = md5( password:nonce:md5(public_method:url) );
(2) When password is ANSI string, then
response= md5( md5(username:realm:password):nonce:md5(public_method:url) );
* [AUTO-TRANSLATED:7858b67d]
*/
string encrypted_pwd = (*this)[Client::kRtspPwd];
if (!(*this)[Client::kRtspPwdIsMD5].as<bool>()) {
@@ -542,7 +569,8 @@ void RtspPusher::sendRtspRequest(const string &cmd, const string &url,const StrC
printer << "response=\"" << response << "\"";
header.emplace("Authorization", printer);
} else if (!(*this)[Client::kRtspPwdIsMD5].as<bool>()) {
// base64认证
// base64认证 [AUTO-TRANSLATED:06d26447]
// base64 authentication
auto authStrBase64 = encodeBase64((*this)[Client::kRtspUser] + ":" + (*this)[Client::kRtspPwd]);
header.emplace("Authorization", StrPrinter << "Basic " << authStrBase64);
}

View File

@@ -71,7 +71,8 @@ private:
unsigned int _cseq = 1;
Rtsp::eRtpType _rtp_type = Rtsp::RTP_TCP;
//rtsp鉴权相关
// rtsp鉴权相关 [AUTO-TRANSLATED:947dc6a3]
// RTSP authentication related
std::string _nonce;
std::string _realm;
std::string _url;
@@ -79,21 +80,27 @@ private:
std::string _content_base;
SdpParser _sdp_parser;
std::vector<SdpTrack::Ptr> _track_vec;
//RTP端口,trackid idx 为数组下标
// RTP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:77c186bb]
// RTP port, trackid idx is the array index
toolkit::Socket::Ptr _rtp_sock[2];
//RTCP端口,trackid idx 为数组下标
// RTCP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:446a7861]
// RTCP port, trackid idx is the array index
toolkit::Socket::Ptr _rtcp_sock[2];
//超时功能实现
// 超时功能实现 [AUTO-TRANSLATED:1d603b3a]
// Timeout function implementation
toolkit::Timer::Ptr _publish_timer;
//心跳定时器
// 心跳定时器 [AUTO-TRANSLATED:536ec800]
// Heartbeat timer
toolkit::Timer::Ptr _beat_timer;
std::weak_ptr<RtspMediaSource> _push_src;
RtspMediaSource::RingType::RingReader::Ptr _rtsp_reader;
std::function<void(const Parser&)> _on_res_func;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
// rtcp发送时间,trackid idx 为数组下标 [AUTO-TRANSLATED:bf3248b1]
// RTCP send time, trackid idx is the array index
toolkit::Ticker _rtcp_send_ticker[2];
//统计rtp并发送rtcp
// 统计rtp并发送rtcp [AUTO-TRANSLATED:0ac2b665]
// Statistics RTP and send RTCP
std::vector<RtcpContext::Ptr> _rtcp_context;
};

View File

@@ -29,8 +29,10 @@ class RtspSession : public toolkit::Session, public RtspSplitter, public RtpRece
public:
using Ptr = std::shared_ptr<RtspSession>;
using onGetRealm = std::function<void(const std::string &realm)>;
//encrypted为true是则表明是md5加密的密码否则是明文密码
//在请求明文密码时如果提供md5密码者则会导致认证失败
// encrypted为true是则表明是md5加密的密码否则是明文密码 [AUTO-TRANSLATED:cad96e51]
// `encrypted` being `true` indicates an MD5 encrypted password, otherwise it is a plain text password
// 在请求明文密码时如果提供md5密码者则会导致认证失败 [AUTO-TRANSLATED:8a38bff8]
// When requesting a plain text password, providing an MD5 password will result in authentication failure
using onAuth = std::function<void(bool encrypted, const std::string &pwd_or_md5)>;
RtspSession(const toolkit::Socket::Ptr &sock);
@@ -41,11 +43,14 @@ public:
protected:
/////RtspSplitter override/////
//收到完整的rtsp包回调包括sdp等content数据
// 收到完整的rtsp包回调包括sdp等content数据 [AUTO-TRANSLATED:efbe20df]
// Callback for receiving a complete RTSP packet, including SDP and other content data
void onWholeRtspPacket(Parser &parser) override;
//收到rtp包回调
// 收到rtp包回调 [AUTO-TRANSLATED:119f1cca]
// Callback for receiving an RTP packet
void onRtpPacket(const char *data, size_t len) override;
//从rtsp头中获取Content长度
// 从rtsp头中获取Content长度 [AUTO-TRANSLATED:0e6f033e]
// Get the Content length from the RTSP header
ssize_t getContentLength(Parser &parser) override;
////RtpReceiver override////
@@ -53,36 +58,47 @@ protected:
void onBeforeRtpSorted(const RtpPacket::Ptr &rtp, int track_index) override;
///////MediaSourceEvent override///////
// 关闭
// 关闭 [AUTO-TRANSLATED:92392f02]
// Close
bool close(MediaSource &sender) override;
// 播放总人数
// 播放总人数 [AUTO-TRANSLATED:c42a3161]
// Total number of players
int totalReaderCount(MediaSource &sender) override;
// 获取媒体源类型
// 获取媒体源类型 [AUTO-TRANSLATED:34290a69]
// Get the media source type
MediaOriginType getOriginType(MediaSource &sender) const override;
// 获取媒体源url或者文件路径
// 获取媒体源url或者文件路径 [AUTO-TRANSLATED:fa34d795]
// Get the media source URL or file path
std::string getOriginUrl(MediaSource &sender) const override;
// 获取媒体源客户端相关信息
// 获取媒体源客户端相关信息 [AUTO-TRANSLATED:037ef910]
// Get the media source client related information
std::shared_ptr<SockInfo> getOriginSock(MediaSource &sender) const override;
// 由于支持断连续推存在OwnerPoller变更的可能
// 由于支持断连续推存在OwnerPoller变更的可能 [AUTO-TRANSLATED:1c863b40]
// Due to support for continuous pushing, there is a possibility of OwnerPoller changes
toolkit::EventPoller::Ptr getOwnerPoller(MediaSource &sender) override;
/////Session override////
ssize_t send(toolkit::Buffer::Ptr pkt) override;
//收到RTCP包回调
// 收到RTCP包回调 [AUTO-TRANSLATED:249f4807]
// Callback for receiving an RTCP packet
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, const char *data, size_t len);
//回复客户端
// 回复客户端 [AUTO-TRANSLATED:8108ebea]
// Reply to the client
virtual bool sendRtspResponse(const std::string &res_code, const StrCaseMap &header = StrCaseMap(), const std::string &sdp = "", const char *protocol = "RTSP/1.0");
protected:
//url解析后保存的相关信息
// url解析后保存的相关信息 [AUTO-TRANSLATED:1c26e4e3]
// Information related to the URL after parsing
MediaInfo _media_info;
////////RTP over udp_multicast////////
//共享的rtp组播对象
// 共享的rtp组播对象 [AUTO-TRANSLATED:d4a5cfdd]
// Shared RTP multicast object
RtpMultiCaster::Ptr _multicaster;
//Session号
// Session号 [AUTO-TRANSLATED:4552ec74]
// Session number
std::string _sessionid;
uint32_t _multicast_ip = 0;
@@ -90,122 +106,176 @@ protected:
uint16_t _multicast_audio_port = 0;
private:
//处理options方法,获取服务器能力
// 处理options方法,获取服务器能力 [AUTO-TRANSLATED:a51f6d7c]
// Handle the OPTIONS method, get server capabilities
void handleReq_Options(const Parser &parser);
//处理describe方法请求服务器rtsp sdp信息
// 处理describe方法请求服务器rtsp sdp信息 [AUTO-TRANSLATED:ed2c8fcb]
// Handle the DESCRIBE method, request server RTSP SDP information
void handleReq_Describe(const Parser &parser);
//处理ANNOUNCE方法请求推流附带sdp
// 处理ANNOUNCE方法请求推流附带sdp [AUTO-TRANSLATED:aa4b4517]
// Handle the ANNOUNCE method, request streaming, with SDP attached
void handleReq_ANNOUNCE(const Parser &parser);
//处理record方法开始推流
// 处理record方法开始推流 [AUTO-TRANSLATED:885cf8a9]
// Handle the RECORD method, start streaming
void handleReq_RECORD(const Parser &parser);
//处理setup方法播放和推流协商rtp传输方式用
// 处理setup方法播放和推流协商rtp传输方式用 [AUTO-TRANSLATED:cbe5dcfc]
// Handle the SETUP method, used for negotiating RTP transport methods for playback and streaming
void handleReq_Setup(const Parser &parser);
//处理play方法开始或恢复播放
// 处理play方法开始或恢复播放 [AUTO-TRANSLATED:f15d151d]
// Handle the PLAY method, start or resume playback
void handleReq_Play(const Parser &parser);
//处理pause方法暂停播放
// 处理pause方法暂停播放 [AUTO-TRANSLATED:0c3b8f79]
// Handle the PAUSE method, pause playback
void handleReq_Pause(const Parser &parser);
//处理teardown方法结束播放
// 处理teardown方法结束播放 [AUTO-TRANSLATED:64d82572]
// Handle the TEARDOWN method, end playback
void handleReq_Teardown(const Parser &parser);
//处理Get方法,rtp over http才用到
// 处理Get方法,rtp over http才用到 [AUTO-TRANSLATED:c7c51eb6]
// Handle the GET method, only used for RTP over HTTP
void handleReq_Get(const Parser &parser);
//处理Post方法rtp over http才用到
// 处理Post方法rtp over http才用到 [AUTO-TRANSLATED:228bdbbe]
// Handle the POST method, only used for RTP over HTTP
void handleReq_Post(const Parser &parser);
//处理SET_PARAMETER、GET_PARAMETER方法一般用于心跳
// 处理SET_PARAMETER、GET_PARAMETER方法一般用于心跳 [AUTO-TRANSLATED:b9e333e1]
// Handle the SET_PARAMETER, GET_PARAMETER methods, generally used for heartbeats
void handleReq_SET_PARAMETER(const Parser &parser);
//rtsp资源未找到
// rtsp资源未找到 [AUTO-TRANSLATED:9b779890]
// RTSP resource not found
void send_StreamNotFound();
//不支持的传输模式
// 不支持的传输模式 [AUTO-TRANSLATED:ef90414c]
// Unsupported transport mode
void send_UnsupportedTransport();
//会话id错误
// 会话id错误 [AUTO-TRANSLATED:7cf632d3]
// Session ID error
void send_SessionNotFound();
//一般rtsp服务器打开端口失败时触发
// 一般rtsp服务器打开端口失败时触发 [AUTO-TRANSLATED:82ecb043]
// Triggered when the general RTSP server fails to open the port
void send_NotAcceptable();
//获取track下标
// 获取track下标 [AUTO-TRANSLATED:36d0b2c2]
// Get the track index
int getTrackIndexByTrackType(TrackType type);
int getTrackIndexByControlUrl(const std::string &control_url);
int getTrackIndexByInterleaved(int interleaved);
//一般用于接收udp打洞包也用于rtsp推流
// 一般用于接收udp打洞包也用于rtsp推流 [AUTO-TRANSLATED:0b55c12f]
// Generally used to receive UDP hole punching packets, also used for RTSP pushing
void onRcvPeerUdpData(int interleaved, const toolkit::Buffer::Ptr &buf, const struct sockaddr_storage &addr);
//配合onRcvPeerUdpData使用
// 配合onRcvPeerUdpData使用 [AUTO-TRANSLATED:811d2d1a]
// Used in conjunction with onRcvPeerUdpData
void startListenPeerUdpData(int track_idx);
////rtsp专有认证相关////
//认证成功
// //rtsp专有认证相关//// [AUTO-TRANSLATED:0f021bb5]
// // RTSP specific authentication related ////
// 认证成功 [AUTO-TRANSLATED:e1bafff3]
// Authentication successful
void onAuthSuccess();
//认证失败
// 认证失败 [AUTO-TRANSLATED:a188326a]
// Authentication failed
void onAuthFailed(const std::string &realm, const std::string &why, bool close = true);
//开始走rtsp专有认证流程
// 开始走rtsp专有认证流程 [AUTO-TRANSLATED:2d773497]
// Start the RTSP specific authentication process
void onAuthUser(const std::string &realm, const std::string &authorization);
//校验base64方式的认证加密
// 校验base64方式的认证加密 [AUTO-TRANSLATED:bde8662f]
// Verify base64 authentication encryption
void onAuthBasic(const std::string &realm, const std::string &auth_base64);
//校验md5方式的认证加密
// 校验md5方式的认证加密 [AUTO-TRANSLATED:0cc37fa7]
// Verify MD5 authentication encryption
void onAuthDigest(const std::string &realm, const std::string &auth_md5);
//触发url鉴权事件
// 触发url鉴权事件 [AUTO-TRANSLATED:776dc4b5]
// Trigger URL authentication event
void emitOnPlay();
//发送rtp给客户端
// 发送rtp给客户端 [AUTO-TRANSLATED:18602be0]
// Send RTP to the client
void sendRtpPacket(const RtspMediaSource::RingDataType &pkt);
//触发rtcp发送
// 触发rtcp发送 [AUTO-TRANSLATED:4fbe7706]
// Trigger RTCP sending
void updateRtcpContext(const RtpPacket::Ptr &rtp);
//回复客户端
// 回复客户端 [AUTO-TRANSLATED:8108ebea]
// Reply to the client
bool sendRtspResponse(const std::string &res_code, const std::initializer_list<std::string> &header, const std::string &sdp = "", const char *protocol = "RTSP/1.0");
//设置socket标志
// 设置socket标志 [AUTO-TRANSLATED:4086e686]
// Set socket flag
void setSocketFlags();
private:
//是否已经触发on_play事件
// 是否已经触发on_play事件 [AUTO-TRANSLATED:49c937ce]
// Whether the on_play event has been triggered
bool _emit_on_play = false;
bool _send_sr_rtcp[2] = {true, true};
//断连续推延时
// 断连续推延时 [AUTO-TRANSLATED:13ad578a]
// Delay in continuous pushing
uint32_t _continue_push_ms = 0;
//推流或拉流客户端采用的rtp传输方式
// 推流或拉流客户端采用的rtp传输方式 [AUTO-TRANSLATED:27411079]
// RTP transport method used by the pushing or pulling client
Rtsp::eRtpType _rtp_type = Rtsp::RTP_Invalid;
//收到的seq回复时一致
// 收到的seq回复时一致 [AUTO-TRANSLATED:64544fb4]
// Received seq, consistent when replying
int _cseq = 0;
//消耗的总流量
// 消耗的总流量 [AUTO-TRANSLATED:45ad2785]
// Total traffic consumed
uint64_t _bytes_usage = 0;
//ContentBase
std::string _content_base;
//记录是否需要rtsp专属鉴权防止重复触发事件
// 记录是否需要rtsp专属鉴权防止重复触发事件 [AUTO-TRANSLATED:9cff90b9]
// Record whether RTSP specific authentication is required to prevent duplicate event triggering
std::string _rtsp_realm;
//登录认证
// 登录认证 [AUTO-TRANSLATED:43fdb875]
// Login authentication
std::string _auth_nonce;
//用于判断客户端是否超时
// 用于判断客户端是否超时 [AUTO-TRANSLATED:86cb328a]
// Used to determine if the client has timed out
toolkit::Ticker _alive_ticker;
//rtsp推流相关绑定的源
// rtsp推流相关绑定的源 [AUTO-TRANSLATED:a25078d9]
// Source bound to RTSP pushing
RtspMediaSourceImp::Ptr _push_src;
//推流器所有权
// 推流器所有权 [AUTO-TRANSLATED:e47b4bcb]
// Pusher ownership
std::shared_ptr<void> _push_src_ownership;
//rtsp播放器绑定的直播源
// rtsp播放器绑定的直播源 [AUTO-TRANSLATED:a7e130b5]
// Live source bound to the RTSP player
std::weak_ptr<RtspMediaSource> _play_src;
//直播源读取器
// 直播源读取器 [AUTO-TRANSLATED:e1edc193]
// Live source reader
RtspMediaSource::RingType::RingReader::Ptr _play_reader;
//sdp里面有效的track,包含音频或视频
// sdp里面有效的track,包含音频或视频 [AUTO-TRANSLATED:64e2fcdf]
// Valid track in SDP, including audio or video
std::vector<SdpTrack::Ptr> _sdp_track;
//播放器setup指定的播放track,默认为TrackInvalid表示不指定即音视频都推
// 播放器setup指定的播放track,默认为TrackInvalid表示不指定即音视频都推 [AUTO-TRANSLATED:c7a0df5e]
// Track specified by the player setup, default is TrackInvalid, which means no specification, both audio and video are pushed
TrackType _target_play_track = TrackInvalid;
////////RTP over udp////////
//RTP端口,trackid idx 为数组下标
// RTP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:77c186bb]
// RTP port, trackid idx is the array index
toolkit::Socket::Ptr _rtp_socks[2];
//RTCP端口,trackid idx 为数组下标
// RTCP端口,trackid idx 为数组下标 [AUTO-TRANSLATED:446a7861]
// RTCP port, trackid idx is the array index
toolkit::Socket::Ptr _rtcp_socks[2];
//标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号
// 标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 [AUTO-TRANSLATED:ad039c25]
// Flag whether the UDP hole punching packet for playback has been received. The external UDP port number can only be known after receiving the UDP hole punching packet for playback.
std::unordered_set<int> _udp_connected_flags;
////////RTSP over HTTP ////////
//quicktime 请求rtsp会产生两次tcp连接
//一次发送 get 一次发送post需要通过x-sessioncookie关联起来
// quicktime 请求rtsp会产生两次tcp连接 [AUTO-TRANSLATED:3f72e181]
// QuickTime requests for RTSP will generate two TCP connections,
// 一次发送 get 一次发送post需要通过x-sessioncookie关联起来 [AUTO-TRANSLATED:f29a653f]
// one for sending GET and one for sending POST. They need to be associated through x-sessioncookie.
std::string _http_x_sessioncookie;
std::function<void(const toolkit::Buffer::Ptr &)> _on_recv;
////////// rtcp ////////////////
//rtcp发送时间,trackid idx 为数组下标
// rtcp发送时间,trackid idx 为数组下标 [AUTO-TRANSLATED:bf3248b1]
// RTCP send time, trackid idx is the array index
toolkit::Ticker _rtcp_send_tickers[2];
//统计rtp并发送rtcp
// 统计rtp并发送rtcp [AUTO-TRANSLATED:0ac2b665]
// Count RTP and send RTCP
std::vector<RtcpContext::Ptr> _rtcp_context;
};
/**
* 支持ssl加密的rtsp服务器可用于诸如亚马逊echo show这样的设备访问
* RTSP server supporting SSL encryption, which can be used for devices such as Amazon Echo Show to access.
* [AUTO-TRANSLATED:7d1eed83]
*/
using RtspSessionWithSSL = toolkit::SessionWithSSL<RtspSession>;

View File

@@ -27,7 +27,8 @@ const char *RtspSplitter::onSearchPacketTail(const char *data, size_t len) {
}
if (len > 256 * 1024) {
//rtp大于256KB
// rtp大于256KB [AUTO-TRANSLATED:d8d8a481]
// rtp is greater than 256KB
ret = (char *) memchr(data, '$', len);
if (!ret) {
WarnL << "rtp缓存溢出:" << hexdump(data, 1024);
@@ -39,21 +40,26 @@ const char *RtspSplitter::onSearchPacketTail(const char *data, size_t len) {
const char *RtspSplitter::onSearchPacketTail_l(const char *data, size_t len) {
if(!_enableRecvRtp || data[0] != '$'){
//这是rtsp包
// 这是rtsp包 [AUTO-TRANSLATED:cdc2211d]
// This is an rtsp packet
_isRtpPacket = false;
return HttpRequestSplitter::onSearchPacketTail(data, len);
}
//这是rtp包
// 这是rtp包 [AUTO-TRANSLATED:627d4881]
// This is an rtp packet
if(len < 4){
//数据不够
// 数据不够 [AUTO-TRANSLATED:72802244]
// Not enough data
return nullptr;
}
uint16_t length = (((uint8_t *)data)[2] << 8) | ((uint8_t *)data)[3];
if(len < (size_t)(length + 4)){
//数据不够
// 数据不够 [AUTO-TRANSLATED:72802244]
// Not enough data
return nullptr;
}
//返回rtp包末尾
// 返回rtp包末尾 [AUTO-TRANSLATED:2546d5ce]
// Return the end of the rtp packet
_isRtpPacket = true;
return data + 4 + length;
}
@@ -74,11 +80,14 @@ ssize_t RtspSplitter::onRecvHeader(const char *data, size_t len) {
_parser.parse(data, len);
} catch (toolkit::AssertFailedException &ex){
if (!_enableRecvRtp) {
// 还在握手中,直接中断握手
// 还在握手中,直接中断握手 [AUTO-TRANSLATED:19dfdf7a]
// Still in handshake, interrupt handshake directly
throw;
}
// 握手已经结束如果rtsp server存在发送缓存溢出的bug那么rtsp信令可能跟rtp混在一起
// 这种情况下rtsp信令解析异常不中断链接只丢弃这个包
// 握手已经结束如果rtsp server存在发送缓存溢出的bug那么rtsp信令可能跟rtp混在一起 [AUTO-TRANSLATED:56c28270]
// Handshake has ended, if rtsp server has a send buffer overflow bug, then rtsp signaling may be mixed with rtp
// 这种情况下rtsp信令解析异常不中断链接只丢弃这个包 [AUTO-TRANSLATED:93cd60b4]
// In this case, rtsp signaling parsing exception does not interrupt the connection, just discard this packet
WarnL << ex.what();
return 0;
}

View File

@@ -21,12 +21,20 @@ public:
/**
* 是否允许接收rtp包
* @param enable
* Whether to allow receiving rtp packets
* @param enable
* [AUTO-TRANSLATED:8de8e1ee]
*/
void enableRecvRtp(bool enable);
protected:
/**
* 收到完整的rtsp包回调包括sdp等content数据
* @param parser rtsp包
* Callback for receiving a complete rtsp packet, including sdp and other content data
* @param parser rtsp packet
* [AUTO-TRANSLATED:4d3c2056]
*/
virtual void onWholeRtspPacket(Parser &parser) = 0;
@@ -34,6 +42,11 @@ protected:
* 收到rtp包回调
* @param data
* @param len
* Callback for receiving rtp packets
* @param data
* @param len
* [AUTO-TRANSLATED:c8f7c9bb]
*/
virtual void onRtpPacket(const char *data,size_t len) = 0;
@@ -41,6 +54,12 @@ protected:
* 从rtsp头中获取Content长度
* @param parser
* @return
* Get the Content length from the rtsp header
* @param parser
* @return
* [AUTO-TRANSLATED:f0bc1fb8]
*/
virtual ssize_t getContentLength(Parser &parser);

View File

@@ -33,7 +33,8 @@ Socket::Ptr UDPServer::getSock(SocketHelper &helper, const char* local_ip, int i
if (it == _udp_sock_map.end()) {
Socket::Ptr sock = helper.createSocket();
if (!sock->bindUdpSock(local_port, local_ip)) {
//分配失败
// 分配失败 [AUTO-TRANSLATED:a6c6a6e6]
// Allocation failed
return nullptr;
}