mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2026-06-12 19:24:22 +08:00
AI automatically translates all comments in the code into English (#3917)
This commit is contained in:
@@ -37,14 +37,18 @@ public:
|
||||
unsigned int channel_configuration; // 3 uimsbf 表示声道数
|
||||
unsigned int original; // 1 bslbf
|
||||
unsigned int home; // 1 bslbf
|
||||
// 下面的为改变的参数即每一帧都不同
|
||||
// 下面的为改变的参数即每一帧都不同 [AUTO-TRANSLATED:481aa349]
|
||||
// The following are the parameters that change in each frame
|
||||
unsigned int copyright_identification_bit; // 1 bslbf
|
||||
unsigned int copyright_identification_start; // 1 bslbf
|
||||
unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
|
||||
unsigned int adts_buffer_fullness; // 11 bslbf 0x7FF 说明是码率可变的码流
|
||||
// no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧.
|
||||
// 所以说number_of_raw_data_blocks_in_frame == 0
|
||||
// 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
|
||||
// no_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧. [AUTO-TRANSLATED:3e975531]
|
||||
// no_raw_data_blocks_in_frame indicates that there are number_of_raw_data_blocks_in_frame + 1 AAC raw frames in the ADTS frame.
|
||||
// 所以说number_of_raw_data_blocks_in_frame == 0 [AUTO-TRANSLATED:1b8e9697]
|
||||
// So number_of_raw_data_blocks_in_frame == 0
|
||||
// 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据) [AUTO-TRANSLATED:4a09d783]
|
||||
// means that there is one AAC data block in the ADTS frame, not that there is none. (An AAC raw frame contains 1024 samples and related data over a period of time)
|
||||
unsigned int no_raw_data_blocks_in_frame; // 2 uimsfb
|
||||
};
|
||||
|
||||
@@ -203,6 +207,9 @@ bool parseAacConfig(const string &config, int &samplerate, int &channels) {
|
||||
|
||||
/**
|
||||
* aac类型SDP
|
||||
* aac type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:c06f00b1]
|
||||
*/
|
||||
class AACSdp : public Sdp {
|
||||
public:
|
||||
@@ -213,6 +220,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* Constructor
|
||||
* @param aac_cfg aac two-byte configuration description
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:6fe1f3b2]
|
||||
*/
|
||||
AACSdp(const string &aac_cfg, int payload_type, int sample_rate, int channels, int bitrate)
|
||||
: Sdp(sample_rate, payload_type) {
|
||||
@@ -271,7 +286,8 @@ int AACTrack::getAudioChannel() const {
|
||||
static Frame::Ptr addADTSHeader(const Frame::Ptr &frame_in, const std::string &aac_config) {
|
||||
auto frame = FrameImp::create();
|
||||
frame->_codec_id = CodecAAC;
|
||||
// 生成adts头
|
||||
// 生成adts头 [AUTO-TRANSLATED:c285b9b0]
|
||||
// Generate adts header
|
||||
char adts_header[32] = { 0 };
|
||||
auto size = dumpAacConfig(aac_config, frame_in->size(), (uint8_t *)adts_header, sizeof(adts_header));
|
||||
CHECK(size > 0, "Invalid adts config");
|
||||
@@ -290,7 +306,8 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
//有adts头,尝试分帧
|
||||
// 有adts头,尝试分帧 [AUTO-TRANSLATED:f691c4ce]
|
||||
// There is an adts header, try to frame
|
||||
int64_t dts = frame->dts();
|
||||
int64_t pts = frame->pts();
|
||||
|
||||
@@ -322,13 +339,15 @@ bool AACTrack::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
bool AACTrack::inputFrame_l(const Frame::Ptr &frame) {
|
||||
if (_cfg.empty() && frame->prefixSize()) {
|
||||
// 未获取到aac_cfg信息,根据7个字节的adts头生成aac config
|
||||
// 未获取到aac_cfg信息,根据7个字节的adts头生成aac config [AUTO-TRANSLATED:1b80f562]
|
||||
// Unable to get aac_cfg information, generate aac config based on the 7-byte adts header
|
||||
_cfg = makeAacConfig((uint8_t *)(frame->data()), frame->prefixSize());
|
||||
update();
|
||||
}
|
||||
|
||||
if (frame->size() > frame->prefixSize()) {
|
||||
// 除adts头外,有实际负载
|
||||
// 除adts头外,有实际负载 [AUTO-TRANSLATED:5b7c088e]
|
||||
// There is an actual payload besides the adts header
|
||||
return AudioTrack::inputFrame(frame);
|
||||
}
|
||||
return false;
|
||||
@@ -377,7 +396,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
aac_cfg_str = findSubString(track->_fmtp.data(), "config=", nullptr);
|
||||
}
|
||||
if (aac_cfg_str.empty()) {
|
||||
// 如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track
|
||||
// 如果sdp中获取不到aac config信息,那么在rtp也无法获取,那么忽略该Track [AUTO-TRANSLATED:995bc20d]
|
||||
// If aac config information cannot be obtained from sdp, then it cannot be obtained from rtp either, so ignore this Track
|
||||
return nullptr;
|
||||
}
|
||||
string aac_cfg;
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* aac音频通道
|
||||
* AAC audio channel
|
||||
|
||||
* [AUTO-TRANSLATED:0d58b638]
|
||||
*/
|
||||
class AACTrack : public AudioTrack {
|
||||
public:
|
||||
@@ -28,6 +31,10 @@ public:
|
||||
|
||||
/**
|
||||
* 通过aac extra data 构造对象
|
||||
* Construct object through AAC extra data
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:1fa035c8]
|
||||
*/
|
||||
AACTrack(const std::string &aac_cfg);
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
namespace mediakit {
|
||||
/**
|
||||
* aac Rtmp转adts类
|
||||
* aac Rtmp to adts class
|
||||
|
||||
* [AUTO-TRANSLATED:8b262ddb]
|
||||
*/
|
||||
class AACRtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -28,12 +31,19 @@ public:
|
||||
/**
|
||||
* 输入Rtmp并解码
|
||||
* @param rtmp Rtmp数据包
|
||||
* Input Rtmp and decode
|
||||
* @param rtmp Rtmp data packet
|
||||
|
||||
* [AUTO-TRANSLATED:43b1eae8]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* aac adts转Rtmp类
|
||||
* aac adts to Rtmp class
|
||||
|
||||
* [AUTO-TRANSLATED:2d9c53dd]
|
||||
*/
|
||||
class AACRtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -44,17 +54,31 @@ public:
|
||||
* 如果track不为空且包含adts头相关信息,
|
||||
* 那么inputFrame时可以不输入adts头
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case the adts header is input when inputFrame is called
|
||||
* If track is not empty and contains adts header related information,
|
||||
* then the adts header can be omitted when inputFrame is called
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:fcf8f765]
|
||||
*/
|
||||
AACRtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入aac 数据,可以不带adts头
|
||||
* @param frame aac数据
|
||||
* Input aac data, can be without adts header
|
||||
* @param frame aac data
|
||||
|
||||
* [AUTO-TRANSLATED:d9f4131a]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config package
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ AACRtpDecoder::AACRtpDecoder() {
|
||||
}
|
||||
|
||||
void AACRtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
// 从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 [AUTO-TRANSLATED:f85fe201]
|
||||
// Re-apply the object from the cache pool to prevent overwriting the object that has been written to the ring buffer
|
||||
_frame = FrameImp::create();
|
||||
_frame->_codec_id = CodecAAC;
|
||||
}
|
||||
@@ -55,45 +56,56 @@ void AACRtpDecoder::obtainFrame() {
|
||||
bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
// 无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:2267e6ac]
|
||||
// No actual load
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stamp = rtp->getStampMS();
|
||||
// rtp数据开始部分
|
||||
// rtp数据开始部分 [AUTO-TRANSLATED:f22ebdb9]
|
||||
// Start of rtp data
|
||||
auto ptr = rtp->getPayload();
|
||||
// rtp数据末尾
|
||||
// rtp数据末尾 [AUTO-TRANSLATED:ee108f2b]
|
||||
// End of rtp data
|
||||
auto end = ptr + payload_size;
|
||||
// 首2字节表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数
|
||||
// 首2字节表示Au-Header的个数,单位bit,所以除以16得到Au-Header个数 [AUTO-TRANSLATED:c7175051]
|
||||
// The first 2 bytes represent the number of Au-Headers, in bits, so divide by 16 to get the number of Au-Headers
|
||||
auto au_header_count = ((ptr[0] << 8) | ptr[1]) >> 4;
|
||||
if (!au_header_count) {
|
||||
// 问题issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869
|
||||
// 问题issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869 [AUTO-TRANSLATED:14be1ff8]
|
||||
// Issue: https://github.com/ZLMediaKit/ZLMediaKit/issues/1869
|
||||
WarnL << "invalid aac rtp au_header_count";
|
||||
return false;
|
||||
}
|
||||
// 记录au_header起始指针
|
||||
// 记录au_header起始指针 [AUTO-TRANSLATED:b9083b72]
|
||||
// Record the starting pointer of au_header
|
||||
auto au_header_ptr = ptr + 2;
|
||||
ptr = au_header_ptr + au_header_count * 2;
|
||||
|
||||
if (end < ptr) {
|
||||
// 数据不够
|
||||
// 数据不够 [AUTO-TRANSLATED:830a2785]
|
||||
// Not enough data
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_last_dts) {
|
||||
// 记录第一个时间戳
|
||||
// 记录第一个时间戳 [AUTO-TRANSLATED:2e85b398]
|
||||
// Record the first timestamp
|
||||
_last_dts = stamp;
|
||||
}
|
||||
|
||||
// 每个audio unit时间戳增量
|
||||
// 每个audio unit时间戳增量 [AUTO-TRANSLATED:0345240c]
|
||||
// Timestamp increment for each audio unit
|
||||
auto dts_inc = static_cast<int64_t>(stamp - _last_dts) / au_header_count;
|
||||
if (dts_inc < 0 || dts_inc > 100) {
|
||||
// 时间戳增量异常,忽略
|
||||
// 时间戳增量异常,忽略 [AUTO-TRANSLATED:d2750ef8]
|
||||
// Timestamp increment anomaly, ignore
|
||||
dts_inc = 0;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < (size_t)au_header_count; ++i) {
|
||||
// 之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用
|
||||
// 之后的2字节是AU_HEADER,其中高13位表示一帧AAC负载的字节长度,低3位无用 [AUTO-TRANSLATED:404eb444]
|
||||
// The following 2 bytes are AU_HEADER, where the high 13 bits represent the byte length of one frame of AAC payload, and the low 3 bits are useless
|
||||
auto size = ((au_header_ptr[0] << 8) | au_header_ptr[1]) >> 3;
|
||||
auto len = std::min<int>(size, end - ptr);
|
||||
if (len <= 0) {
|
||||
@@ -104,12 +116,14 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
au_header_ptr += 2;
|
||||
|
||||
if (_frame->size() >= (size_t)size) {
|
||||
// 设置当前audio unit时间戳
|
||||
// 设置当前audio unit时间戳 [AUTO-TRANSLATED:eee18d6e]
|
||||
// Set the current audio unit timestamp
|
||||
_frame->_dts = _last_dts + i * dts_inc;
|
||||
flushData();
|
||||
}
|
||||
}
|
||||
// 记录上次时间戳
|
||||
// 记录上次时间戳 [AUTO-TRANSLATED:a830d69f]
|
||||
// Record the last timestamp
|
||||
_last_dts = stamp;
|
||||
return false;
|
||||
}
|
||||
@@ -117,7 +131,8 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
void AACRtpDecoder::flushData() {
|
||||
auto ptr = reinterpret_cast<const uint8_t *>(_frame->data());
|
||||
if ((ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0) && _frame->size() > ADTS_HEADER_LEN) {
|
||||
// adts头打入了rtp包,不符合规范,兼容EasyPusher的bug
|
||||
// adts头打入了rtp包,不符合规范,兼容EasyPusher的bug [AUTO-TRANSLATED:203a5ee9]
|
||||
// The adts header is inserted into the rtp packet, which is not compliant with the specification, compatible with the bug of EasyPusher
|
||||
_frame->_prefix_size = ADTS_HEADER_LEN;
|
||||
}
|
||||
RtpCodec::inputFrame(_frame);
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
namespace mediakit {
|
||||
/**
|
||||
* aac rtp转adts类
|
||||
* aac rtp to adts class
|
||||
|
||||
* [AUTO-TRANSLATED:8ff7580f]
|
||||
*/
|
||||
class AACRtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@@ -28,6 +31,11 @@ public:
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
* input rtp and decode
|
||||
* @param rtp rtp data packet
|
||||
* @param key_pos this parameter is internally forced to false, please ignore it
|
||||
|
||||
* [AUTO-TRANSLATED:2993fcbe]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
@@ -43,6 +51,9 @@ private:
|
||||
|
||||
/**
|
||||
* aac adts转rtp类
|
||||
* aac adts to rtp class
|
||||
|
||||
* [AUTO-TRANSLATED:1ed889e2]
|
||||
*/
|
||||
class AACRtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@@ -51,6 +62,11 @@ public:
|
||||
/**
|
||||
* 输入aac 数据,必须带dats头
|
||||
* @param frame 带dats头的aac数据
|
||||
* input aac data, must have dats header
|
||||
* @param frame aac data with dats header
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:459bba30]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* G711类型SDP
|
||||
* G711 type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:ea72d60a]
|
||||
*/
|
||||
class G711Sdp : public Sdp {
|
||||
public:
|
||||
@@ -31,6 +34,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* G711 sampling rate is fixed at 8000
|
||||
* @param codecId G711A G711U
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:5ea4b771]
|
||||
*/
|
||||
G711Sdp(CodecId codecId, int payload_type, int sample_rate, int channels, int bitrate)
|
||||
: Sdp(sample_rate, payload_type) {
|
||||
@@ -136,7 +147,8 @@ RtpCodec::Ptr getRtpDecoderByCodecIdU() {
|
||||
RtmpCodec::Ptr getRtmpEncoderByTrack(const Track::Ptr &track) {
|
||||
auto audio_track = dynamic_pointer_cast<AudioTrack>(track);
|
||||
if (audio_track->getAudioSampleRate() != 8000 || audio_track->getAudioChannel() != 1 || audio_track->getAudioSampleBit() != 16) {
|
||||
//rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711
|
||||
// rtmp对g711只支持8000/1/16规格,但是ZLMediaKit可以解析其他规格的G711 [AUTO-TRANSLATED:0ddeaafe]
|
||||
// rtmp only supports 8000/1/16 specifications for g711, but ZLMediaKit can parse other specifications of G711
|
||||
WarnL << "RTMP only support G711 with 8000/1/16, now is"
|
||||
<< audio_track->getAudioSampleRate() << "/"
|
||||
<< audio_track->getAudioChannel() << "/"
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace mediakit{
|
||||
|
||||
/**
|
||||
* G711音频通道
|
||||
* G711 audio channel
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:57f8bc08]
|
||||
*/
|
||||
class G711Track : public AudioTrackImp{
|
||||
public:
|
||||
|
||||
@@ -16,7 +16,8 @@ void G711RtpEncoder::setOpt(int opt, const toolkit::Any ¶m) {
|
||||
WarnL << "set g711 rtp encoder duration ms failed for " << dur;
|
||||
return;
|
||||
}
|
||||
// 向上 20ms 取整
|
||||
// 向上 20ms 取整 [AUTO-TRANSLATED:b8a9e39e]
|
||||
// Round up to the nearest 20ms
|
||||
_pkt_dur_ms = (dur + 19) / 20 * 20;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* G711 rtp编码类
|
||||
* G711 rtp encoding class
|
||||
|
||||
* [AUTO-TRANSLATED:92aa6cf3]
|
||||
*/
|
||||
class G711RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@@ -28,11 +31,20 @@ public:
|
||||
* 构造函数
|
||||
* @param codec 编码类型
|
||||
* @param channels 通道数
|
||||
* Constructor
|
||||
* @param codec Encoding type
|
||||
* @param channels Number of channels
|
||||
|
||||
* [AUTO-TRANSLATED:dbbd593e]
|
||||
*/
|
||||
G711RtpEncoder(CodecId codec, uint32_t channels);
|
||||
|
||||
/**
|
||||
* 输入帧数据并编码成rtp
|
||||
* Input frame data and encode it into rtp
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:02bc9009]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
|
||||
@@ -67,24 +67,31 @@ void splitH264(
|
||||
while (true) {
|
||||
auto next_start = memfind(start, end - start, "\x00\x00\x01", 3);
|
||||
if (next_start) {
|
||||
//找到下一帧
|
||||
// 找到下一帧 [AUTO-TRANSLATED:7161f54a]
|
||||
// Find the next frame
|
||||
if (*(next_start - 1) == 0x00) {
|
||||
//这个是00 00 00 01开头
|
||||
// 这个是00 00 00 01开头 [AUTO-TRANSLATED:b0d79e9e]
|
||||
// This starts with 00 00 00 01
|
||||
next_start -= 1;
|
||||
next_prefix = 4;
|
||||
} else {
|
||||
//这个是00 00 01开头
|
||||
// 这个是00 00 01开头 [AUTO-TRANSLATED:18ae81d8]
|
||||
// This starts with 00 00 01
|
||||
next_prefix = 3;
|
||||
}
|
||||
//记得加上本帧prefix长度
|
||||
// 记得加上本帧prefix长度 [AUTO-TRANSLATED:8bde5d52]
|
||||
// Remember to add the prefix length of this frame
|
||||
cb(start - prefix, next_start - start + prefix, prefix);
|
||||
//搜索下一帧末尾的起始位置
|
||||
// 搜索下一帧末尾的起始位置 [AUTO-TRANSLATED:8976b719]
|
||||
// Search for the starting position of the end of the next frame
|
||||
start = next_start + next_prefix;
|
||||
//记录下一帧的prefix长度
|
||||
// 记录下一帧的prefix长度 [AUTO-TRANSLATED:756aee4e]
|
||||
// Record the prefix length of the next frame
|
||||
prefix = next_prefix;
|
||||
continue;
|
||||
}
|
||||
//未找到下一帧,这是最后一帧
|
||||
// 未找到下一帧,这是最后一帧 [AUTO-TRANSLATED:58365453]
|
||||
// The next frame was not found, this is the last frame
|
||||
cb(start - prefix, end - start + prefix, prefix);
|
||||
break;
|
||||
}
|
||||
@@ -96,17 +103,20 @@ size_t prefixSize(const char *ptr, size_t len) {
|
||||
}
|
||||
|
||||
if (ptr[0] != 0x00 || ptr[1] != 0x00) {
|
||||
//不是0x00 00开头
|
||||
// 不是0x00 00开头 [AUTO-TRANSLATED:c406f0da]
|
||||
// Not 0x00 00 at the beginning
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ptr[2] == 0x00 && ptr[3] == 0x01) {
|
||||
//是0x00 00 00 01
|
||||
// 是0x00 00 00 01 [AUTO-TRANSLATED:70caae72]
|
||||
// It is 0x00 00 00 01
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (ptr[2] == 0x01) {
|
||||
//是0x00 00 01
|
||||
// 是0x00 00 01 [AUTO-TRANSLATED:78b4a3c9]
|
||||
// It is 0x00 00 01
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
@@ -148,7 +158,8 @@ bool H264Track::inputFrame(const Frame::Ptr &frame) {
|
||||
return inputFrame_l(frame);
|
||||
}
|
||||
|
||||
//非I/B/P帧情况下,split一下,防止多个帧粘合在一起
|
||||
// 非I/B/P帧情况下,split一下,防止多个帧粘合在一起 [AUTO-TRANSLATED:b69c6e75]
|
||||
// In the case of non-I/B/P frames, split it to prevent multiple frames from sticking together
|
||||
bool ret = false;
|
||||
splitH264(frame->data(), frame->size(), frame->prefixSize(), [&](const char *ptr, size_t len, size_t prefix) {
|
||||
H264FrameInternal::Ptr sub_frame = std::make_shared<H264FrameInternal>(frame, (char *)ptr, len, prefix);
|
||||
@@ -267,13 +278,15 @@ bool H264Track::inputFrame_l(const Frame::Ptr &frame) {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// 避免识别不出关键帧
|
||||
// 避免识别不出关键帧 [AUTO-TRANSLATED:8eb84679]
|
||||
// Avoid not being able to recognize keyframes
|
||||
if (_latest_is_config_frame && !frame->dropAble()) {
|
||||
if (!frame->keyFrame()) {
|
||||
const_cast<Frame::Ptr &>(frame) = std::make_shared<FrameCacheAble>(frame, true);
|
||||
}
|
||||
}
|
||||
// 判断是否是I帧, 并且如果是,那判断前面是否插入过config帧, 如果插入过就不插入了
|
||||
// 判断是否是I帧, 并且如果是,那判断前面是否插入过config帧, 如果插入过就不插入了 [AUTO-TRANSLATED:40733cd8]
|
||||
// Determine if it is an I frame, and if it is, determine if a config frame has been inserted before, and if it has been inserted, do not insert it
|
||||
if (frame->keyFrame() && !_latest_is_config_frame) {
|
||||
insertConfigFrame(frame);
|
||||
}
|
||||
@@ -313,6 +326,11 @@ public:
|
||||
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
|
||||
Non Interleaved Mode = 1,// Non-interleaved Mode: 1-23,24 (STAP-A),28 (FU-A) are allowed
|
||||
Interleaved Mode = 2, // 25 (STAP-B),26 (MTAP16),27 (MTAP24),28 (EU-A),and 29 (EU-B) are allowed.
|
||||
Single NAI Unit Mode = 0. // Single NAI mode (Only nals from 1-23 are allowed)
|
||||
Non Interleaved Mode = 1,// Non-interleaved Mode: 1-23,24 (STAP-A),28 (FU-A) are allowed
|
||||
Interleaved Mode = 2, // 25 (STAP-B),26 (MTAP16),27 (MTAP24),28 (EU-A),and 29 (EU-B) are allowed.
|
||||
*
|
||||
* [AUTO-TRANSLATED:6166738f]
|
||||
**/
|
||||
GET_CONFIG(bool, h264_stap_a, Rtp::kH264StapA);
|
||||
_printer << "a=fmtp:" << payload_type << " packetization-mode=" << h264_stap_a << "; profile-level-id=";
|
||||
@@ -365,7 +383,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
auto sps = decodeBase64(base64_SPS);
|
||||
auto pps = decodeBase64(base64_PPS);
|
||||
if (sps.empty() || pps.empty()) {
|
||||
//如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps [AUTO-TRANSLATED:60f03d45]
|
||||
// If there is no sps/pps in the sdp, then it may be possible to recover the sps/pps in the subsequent rtp
|
||||
return std::make_shared<H264Track>();
|
||||
}
|
||||
return std::make_shared<H264Track>(sps, pps, 0, 0);
|
||||
|
||||
@@ -68,24 +68,35 @@ public:
|
||||
bool decodeAble() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H264_TYPE(*nal_ptr);
|
||||
//多slice情况下, first_mb_in_slice 表示其为一帧的开始
|
||||
// 多slice情况下, first_mb_in_slice 表示其为一帧的开始 [AUTO-TRANSLATED:80e88e88]
|
||||
// // In the case of multiple slices, first_mb_in_slice indicates the start of a frame
|
||||
return type >= NAL_B_P && type <= NAL_IDR && (nal_ptr[1] & 0x80);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 264帧类
|
||||
* 264 frame class
|
||||
|
||||
* [AUTO-TRANSLATED:342ccb1e]
|
||||
*/
|
||||
using H264Frame = H264FrameHelper<FrameImp>;
|
||||
|
||||
/**
|
||||
* 防止内存拷贝的H264类
|
||||
* 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类
|
||||
* H264 class that prevents memory copying
|
||||
* Users can quickly wrap a pointer into a Frame class without copying using this type
|
||||
|
||||
* [AUTO-TRANSLATED:ff9be1c8]
|
||||
*/
|
||||
using H264FrameNoCacheAble = H264FrameHelper<FrameFromPtr>;
|
||||
|
||||
/**
|
||||
* 264视频通道
|
||||
* 264 video channel
|
||||
|
||||
* [AUTO-TRANSLATED:6936e76d]
|
||||
*/
|
||||
class H264Track : public VideoTrack {
|
||||
public:
|
||||
@@ -94,6 +105,10 @@ public:
|
||||
/**
|
||||
* 不指定sps pps构造h264类型的媒体
|
||||
* 在随后的inputFrame中获取sps pps
|
||||
* Construct a media of h264 type without specifying sps pps
|
||||
* Get sps pps in the subsequent inputFrame
|
||||
|
||||
* [AUTO-TRANSLATED:84d01c7f]
|
||||
*/
|
||||
H264Track() = default;
|
||||
|
||||
@@ -103,6 +118,14 @@ public:
|
||||
* @param pps pps帧数据
|
||||
* @param sps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param pps_prefix_len 264头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* Construct a media of h264 type
|
||||
* @param sps sps frame data
|
||||
* @param pps pps frame data
|
||||
* @param sps_prefix_len 264 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param pps_prefix_len 264 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:702c1433]
|
||||
*/
|
||||
H264Track(const std::string &sps, const std::string &pps, int sps_prefix_len = 4, int pps_prefix_len = 4);
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ void H264RtmpEncoder::flush() {
|
||||
bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
if (!_rtmp_packet) {
|
||||
_rtmp_packet = RtmpPacket::create();
|
||||
//flags/not config/cts预占位
|
||||
// flags/not config/cts预占位 [AUTO-TRANSLATED:7effb692]
|
||||
// flags/not config/cts placeholder
|
||||
_rtmp_packet->buffer.resize(5);
|
||||
}
|
||||
|
||||
@@ -78,7 +79,8 @@ bool H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
_rtmp_packet->chunk_id = CHUNK_VIDEO;
|
||||
_rtmp_packet->stream_index = STREAM_MEDIA;
|
||||
_rtmp_packet->type_id = MSG_VIDEO;
|
||||
// 输出rtmp packet
|
||||
// 输出rtmp packet [AUTO-TRANSLATED:d72e89a7]
|
||||
// Output rtmp packet
|
||||
RtmpCodec::inputRtmp(_rtmp_packet);
|
||||
_rtmp_packet = nullptr;
|
||||
}, &_rtmp_packet->buffer);
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace mediakit {
|
||||
/**
|
||||
* h264 Rtmp解码类
|
||||
* 将 h264 over rtmp 解复用出 h264-Frame
|
||||
* h264 Rtmp decoder class
|
||||
* Demultiplex h264-Frame from h264 over rtmp
|
||||
|
||||
* [AUTO-TRANSLATED:4908a1f3]
|
||||
*/
|
||||
class H264RtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -29,6 +33,10 @@ public:
|
||||
/**
|
||||
* 输入264 Rtmp包
|
||||
* @param rtmp Rtmp包
|
||||
* Input 264 Rtmp package
|
||||
* @param rtmp Rtmp package
|
||||
|
||||
* [AUTO-TRANSLATED:06f3e94c]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
|
||||
@@ -39,6 +47,9 @@ private:
|
||||
|
||||
/**
|
||||
* 264 Rtmp打包类
|
||||
* 264 Rtmp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:e5bc7c66]
|
||||
*/
|
||||
class H264RtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -49,22 +60,39 @@ public:
|
||||
* 如果track不为空且包含sps pps信息,
|
||||
* 那么inputFrame时可以不输入sps pps
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case sps pps is input when inputFrame
|
||||
* If track is not empty and contains sps pps information,
|
||||
* then sps pps can be omitted when inputFrame
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:e61fdfed]
|
||||
*/
|
||||
H264RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入264帧,可以不带sps pps
|
||||
* @param frame 帧数据
|
||||
* Input 264 frame, sps pps can be omitted
|
||||
* @param frame Frame data
|
||||
|
||||
* [AUTO-TRANSLATED:caefd055]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache output
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config package
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
||||
@@ -51,7 +51,9 @@ bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||
WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||
}
|
||||
_last_seq = seq;
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始 [AUTO-TRANSLATED:115ae07c]
|
||||
// cpp
|
||||
// Ensure that when there is sps rtp, the gop starts from sps; otherwise, it starts from the key frame
|
||||
return _is_gop && !last_is_gop;
|
||||
}
|
||||
|
||||
@@ -70,6 +72,23 @@ Table 1. Summary of NAL unit types and their payload structures
|
||||
28 FU-A Fragmentation unit 5.8
|
||||
29 FU-B Fragmentation unit 5.8
|
||||
30-31 undefined -
|
||||
/*
|
||||
RTF3984 Section 5.2 Common Structure of the RTP Payload Format
|
||||
Table 1. Summary of NAL unit types and their payload structures
|
||||
|
||||
Type Packet Type name Section
|
||||
---------------------------------------------------------
|
||||
0 undefined -
|
||||
1-23 NAL unit Single NAL unit packet per H.264 5.6
|
||||
24 STAP-A Single-time aggregation packet 5.7.1
|
||||
25 STAP-B Single-time aggregation packet 5.7.1
|
||||
26 MTAP16 Multi-time aggregation packet 5.7.2
|
||||
27 MTAP24 Multi-time aggregation packet 5.7.2
|
||||
28 FU-A Fragmentation unit 5.8
|
||||
29 FU-B Fragmentation unit 5.8
|
||||
30-31 undefined -
|
||||
|
||||
* [AUTO-TRANSLATED:57545317]
|
||||
*/
|
||||
|
||||
bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp){
|
||||
@@ -82,7 +101,8 @@ bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
|
||||
}
|
||||
|
||||
bool H264RtpDecoder::unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp) {
|
||||
//STAP-A 单一时间的组合包
|
||||
// STAP-A 单一时间的组合包 [AUTO-TRANSLATED:cfa62307]
|
||||
// STAP-A single-time aggregation packet
|
||||
auto have_key_frame = false;
|
||||
auto end = ptr + size;
|
||||
while (ptr + 2 < end) {
|
||||
@@ -105,7 +125,8 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
auto nal_suffix = *ptr & (~0x1F);
|
||||
FuFlags *fu = (FuFlags *) (ptr + 1);
|
||||
if (fu->start_bit) {
|
||||
//该帧的第一个rtp包
|
||||
// 该帧的第一个rtp包 [AUTO-TRANSLATED:a9581a23]
|
||||
// The first rtp packet of this frame
|
||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||
_frame->_buffer.push_back(nal_suffix | fu->nal_type);
|
||||
_frame->_pts = stamp;
|
||||
@@ -113,28 +134,34 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
}
|
||||
|
||||
if (_fu_dropped) {
|
||||
//该帧不完整
|
||||
// 该帧不完整 [AUTO-TRANSLATED:6bd7eca7]
|
||||
// This frame is incomplete
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fu->start_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||
// 中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃 [AUTO-TRANSLATED:6953b332]
|
||||
// The middle or end rtp packet, its seq must be continuous, otherwise it indicates that the rtp packet is lost, then the frame is incomplete and must be discarded
|
||||
_fu_dropped = true;
|
||||
_frame->_buffer.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
//后面追加数据
|
||||
// 后面追加数据 [AUTO-TRANSLATED:248516e9]
|
||||
// Append data
|
||||
_frame->_buffer.append((char *) ptr + 2, size - 2);
|
||||
|
||||
if (!fu->end_bit) {
|
||||
//非末尾包
|
||||
// 非末尾包 [AUTO-TRANSLATED:2e43ac3c]
|
||||
// Not the end packet
|
||||
return fu->start_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
|
||||
}
|
||||
|
||||
//确保下一次fu必须收到第一个包
|
||||
// 确保下一次fu必须收到第一个包 [AUTO-TRANSLATED:491d81ec]
|
||||
// Ensure that the next fu must receive the first packet
|
||||
_fu_dropped = true;
|
||||
//该帧最后一个rtp包,输出frame
|
||||
// 该帧最后一个rtp包,输出frame [AUTO-TRANSLATED:a648aaa5]
|
||||
// The last rtp packet of this frame, output frame
|
||||
outputFrame(rtp, _frame);
|
||||
return false;
|
||||
}
|
||||
@@ -142,7 +169,8 @@ bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual payload
|
||||
return false;
|
||||
}
|
||||
auto frame = rtp->getPayload();
|
||||
@@ -173,10 +201,12 @@ bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
|
||||
void H264RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame) {
|
||||
if (frame->dropAble()) {
|
||||
//不参与dts生成
|
||||
// 不参与dts生成 [AUTO-TRANSLATED:dff3b747]
|
||||
// Not involved in dts generation
|
||||
frame->_dts = frame->_pts;
|
||||
} else {
|
||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||
// rtsp没有dts,那么根据pts排序算法生成dts [AUTO-TRANSLATED:f37c17f3]
|
||||
// Rtsp does not have dts, so dts is generated according to the pts sorting algorithm
|
||||
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||
}
|
||||
|
||||
@@ -196,17 +226,20 @@ void H264RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
if (!_sps || !_pps) {
|
||||
return;
|
||||
}
|
||||
//gop缓存从sps开始,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false
|
||||
// gop缓存从sps开始,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false [AUTO-TRANSLATED:e8dcff77]
|
||||
// The gop cache starts from sps, sps, pps and then there are key frames with the same timestamp, so the mark bit is false
|
||||
packRtp(_sps->data() + _sps->prefixSize(), _sps->size() - _sps->prefixSize(), pts, false, true);
|
||||
packRtp(_pps->data() + _pps->prefixSize(), _pps->size() - _pps->prefixSize(), pts, false, false);
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
if (len + 3 <= getRtpInfo().getMaxSize()) {
|
||||
// 采用STAP-A/Single NAL unit packet per H.264 模式
|
||||
// 采用STAP-A/Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:1a719984]
|
||||
// Use STAP-A/Single NAL unit packet per H.264 mode
|
||||
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
|
||||
} else {
|
||||
//STAP-A模式打包会大于MTU,所以采用FU-A模式
|
||||
// STAP-A模式打包会大于MTU,所以采用FU-A模式 [AUTO-TRANSLATED:f3923abc]
|
||||
// STAP-A mode packaging will be larger than MTU, so FU-A mode is used
|
||||
packRtpFu(ptr, len, pts, is_mark, gop_pos);
|
||||
}
|
||||
}
|
||||
@@ -214,12 +247,14 @@ void H264RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
|
||||
void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
auto packet_size = getRtpInfo().getMaxSize() - 2;
|
||||
if (len <= packet_size + 1) {
|
||||
// 小于FU-A打包最小字节长度要求,采用STAP-A/Single NAL unit packet per H.264 模式
|
||||
// 小于FU-A打包最小字节长度要求,采用STAP-A/Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:b83bb4d1]
|
||||
// Less than the minimum byte length requirement for FU-A packaging, use STAP-A/Single NAL unit packet per H.264 mode
|
||||
packRtpSmallFrame(ptr, len, pts, is_mark, gop_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
//末尾5bit为nalu type,固定为28(FU-A)
|
||||
// 末尾5bit为nalu type,固定为28(FU-A) [AUTO-TRANSLATED:6293f1a9]
|
||||
// The last 5 bits are the nalu type, fixed to 28 (FU-A)
|
||||
auto fu_char_0 = (ptr[0] & (~0x1F)) | 28;
|
||||
auto fu_char_1 = H264_TYPE(ptr[0]);
|
||||
FuFlags *fu_flags = (FuFlags *) (&fu_char_1);
|
||||
@@ -233,17 +268,23 @@ void H264RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
|
||||
fu_flags->end_bit = 1;
|
||||
}
|
||||
|
||||
//传入nullptr先不做payload的内存拷贝
|
||||
// 传入nullptr先不做payload的内存拷贝 [AUTO-TRANSLATED:1858cf77]
|
||||
// Pass in nullptr first, do not copy the payload memory
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, packet_size + 2, fu_flags->end_bit && is_mark, pts);
|
||||
//rtp payload 负载部分
|
||||
// rtp payload 负载部分 [AUTO-TRANSLATED:aecf73cc]
|
||||
// rtp payload load part
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
//FU-A 第1个字节
|
||||
// FU-A 第1个字节 [AUTO-TRANSLATED:b5558495]
|
||||
// FU-A first byte
|
||||
payload[0] = fu_char_0;
|
||||
//FU-A 第2个字节
|
||||
// FU-A 第2个字节 [AUTO-TRANSLATED:6b4540bb]
|
||||
// FU-A second byte
|
||||
payload[1] = fu_char_1;
|
||||
//H264 数据
|
||||
// H264 数据 [AUTO-TRANSLATED:79204239]
|
||||
// H264 data
|
||||
memcpy(payload + 2, (uint8_t *) ptr + offset, packet_size);
|
||||
//输入到rtp环形缓存
|
||||
// 输入到rtp环形缓存 [AUTO-TRANSLATED:5208ef90]
|
||||
// Input to the rtp ring buffer
|
||||
RtpCodec::inputRtp(rtp, gop_pos);
|
||||
|
||||
offset += packet_size;
|
||||
@@ -261,7 +302,8 @@ void H264RtpEncoder::packRtpSmallFrame(const char *data, size_t len, uint64_t pt
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||
// 如果帧长度不超过mtu,为了兼容性 webrtc,采用STAP-A模式打包
|
||||
// 如果帧长度不超过mtu,为了兼容性 webrtc,采用STAP-A模式打包 [AUTO-TRANSLATED:a091199c]
|
||||
// If the frame length does not exceed mtu, for compatibility with webrtc, use STAP-A mode packaging
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, len + 3, is_mark, pts);
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
//STAP-A
|
||||
@@ -274,7 +316,8 @@ void H264RtpEncoder::packRtpStapA(const char *ptr, size_t len, uint64_t pts, boo
|
||||
}
|
||||
|
||||
void H264RtpEncoder::packRtpSingleNalu(const char *data, size_t len, uint64_t pts, bool is_mark, bool gop_pos) {
|
||||
// Single NAL unit packet per H.264 模式
|
||||
// Single NAL unit packet per H.264 模式 [AUTO-TRANSLATED:9332a8e4]
|
||||
// Single NAL unit packet per H.264 mode
|
||||
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, data, len, is_mark, pts), gop_pos);
|
||||
}
|
||||
|
||||
@@ -300,7 +343,8 @@ bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
inputFrame_l(frame, true);
|
||||
} else {
|
||||
if (_last_frame) {
|
||||
//如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:19b68429]
|
||||
// If the timestamp changes, then the markbit is set to true
|
||||
inputFrame_l(_last_frame, _last_frame->pts() != frame->pts());
|
||||
}
|
||||
_last_frame = Frame::getCacheAbleFrame(frame);
|
||||
@@ -310,7 +354,8 @@ bool H264RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
void H264RtpEncoder::flush() {
|
||||
if (_last_frame) {
|
||||
// 如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:6b1d0fe0]
|
||||
// If the timestamp changes, then the markbit is set to true
|
||||
inputFrame_l(_last_frame, true);
|
||||
_last_frame = nullptr;
|
||||
}
|
||||
@@ -318,7 +363,8 @@ void H264RtpEncoder::flush() {
|
||||
|
||||
bool H264RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
|
||||
if (frame->keyFrame()) {
|
||||
//保证每一个关键帧前都有SPS与PPS
|
||||
// 保证每一个关键帧前都有SPS与PPS [AUTO-TRANSLATED:9d1a9d5e]
|
||||
// Ensure that there are SPS and PPS before each key frame
|
||||
insertConfigFrame(frame->pts());
|
||||
}
|
||||
packRtp(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), frame->pts(), is_mark, false);
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace mediakit {
|
||||
* h264 rtp解码类
|
||||
* 将 h264 over rtsp-rtp 解复用出 h264-Frame
|
||||
* rfc3984
|
||||
* h264 rtp decoder class
|
||||
* Demultiplex h264-Frame from h264 over rtsp-rtp
|
||||
* rfc3984
|
||||
|
||||
* [AUTO-TRANSLATED:84b4831b]
|
||||
*/
|
||||
class H264RtpDecoder : public RtpCodec{
|
||||
public:
|
||||
@@ -33,6 +38,11 @@ public:
|
||||
* 输入264 rtp包
|
||||
* @param rtp rtp包
|
||||
* @param key_pos 此参数忽略之
|
||||
* Input 264 rtp packet
|
||||
* @param rtp rtp packet
|
||||
* @param key_pos This parameter is ignored
|
||||
|
||||
* [AUTO-TRANSLATED:a9ed29db]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
|
||||
|
||||
@@ -56,6 +66,9 @@ private:
|
||||
|
||||
/**
|
||||
* 264 rtp打包类
|
||||
* 264 rtp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:baed5b50]
|
||||
*/
|
||||
class H264RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@@ -64,11 +77,19 @@ public:
|
||||
/**
|
||||
* 输入264帧
|
||||
* @param frame 帧数据,必须
|
||||
* Input 264 frame
|
||||
* @param frame Frame data, required
|
||||
|
||||
* [AUTO-TRANSLATED:1190bc60]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame buffers in the output
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
@@ -87,6 +108,6 @@ private:
|
||||
Frame::Ptr _last_frame;
|
||||
};
|
||||
|
||||
}//namespace mediakit{
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_H264RTPCODEC_H
|
||||
|
||||
@@ -219,6 +219,9 @@ void H265Track::insertConfigFrame(const Frame::Ptr &frame) {
|
||||
|
||||
/**
|
||||
* h265类型sdp
|
||||
* h265 type sdp
|
||||
|
||||
* [AUTO-TRANSLATED:4418a7df]
|
||||
*/
|
||||
class H265Sdp : public Sdp {
|
||||
public:
|
||||
@@ -228,9 +231,17 @@ public:
|
||||
* @param pps 265 pps,不带0x00000001头
|
||||
* @param payload_type rtp payload type 默认96
|
||||
* @param bitrate 比特率
|
||||
* Constructor
|
||||
* @param sps 265 sps, without 0x00000001 header
|
||||
* @param pps 265 pps, without 0x00000001 header
|
||||
* @param payload_type rtp payload type, default 96
|
||||
* @param bitrate Bitrate
|
||||
|
||||
* [AUTO-TRANSLATED:93f4ec48]
|
||||
*/
|
||||
H265Sdp(const string &strVPS, const string &strSPS, const string &strPPS, int payload_type, int bitrate) : Sdp(90000, payload_type) {
|
||||
//视频通道
|
||||
// 视频通道 [AUTO-TRANSLATED:642ca881]
|
||||
// Video channel
|
||||
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
||||
if (bitrate) {
|
||||
_printer << "b=AS:" << bitrate << "\r\n";
|
||||
@@ -276,7 +287,8 @@ Track::Ptr getTrackBySdp(const SdpTrack::Ptr &track) {
|
||||
auto sps = decodeBase64(map["sprop-sps"]);
|
||||
auto pps = decodeBase64(map["sprop-pps"]);
|
||||
if (sps.empty() || pps.empty()) {
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps
|
||||
// 如果sdp里面没有sps/pps,那么可能在后续的rtp里面恢复出sps/pps [AUTO-TRANSLATED:9300510b]
|
||||
// If there is no sps/pps in the sdp, then it may be possible to recover sps/pps from the subsequent rtp
|
||||
return std::make_shared<H265Track>();
|
||||
}
|
||||
return std::make_shared<H265Track>(vps, sps, pps, 0, 0, 0);
|
||||
|
||||
@@ -65,7 +65,8 @@ public:
|
||||
bool keyFrame() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H265_TYPE(*nal_ptr);
|
||||
// 参考自FFmpeg: IRAP VCL NAL unit types span the range
|
||||
// 参考自FFmpeg: IRAP VCL NAL unit types span the range [AUTO-TRANSLATED:45413c06]
|
||||
// Referenced from FFmpeg: IRAP VCL NAL unit types span the range
|
||||
// [BLA_W_LP (16), RSV_IRAP_VCL23 (23)].
|
||||
return (type >= NAL_BLA_W_LP && type <= NAL_RSV_IRAP_VCL23) && decodeAble() ;
|
||||
}
|
||||
@@ -93,24 +94,35 @@ public:
|
||||
bool decodeAble() const override {
|
||||
auto nal_ptr = (uint8_t *) this->data() + this->prefixSize();
|
||||
auto type = H265_TYPE(*nal_ptr);
|
||||
//多slice情况下, first_slice_segment_in_pic_flag 表示其为一帧的开始
|
||||
// 多slice情况下, first_slice_segment_in_pic_flag 表示其为一帧的开始 [AUTO-TRANSLATED:0427551b]
|
||||
// In the case of multiple slices, first_slice_segment_in_pic_flag indicates the beginning of a frame
|
||||
return type >= NAL_TRAIL_N && type <= NAL_RSV_IRAP_VCL23 && (nal_ptr[2] & 0x80);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 265帧类
|
||||
* 265 frame class
|
||||
|
||||
* [AUTO-TRANSLATED:9141a4be]
|
||||
*/
|
||||
using H265Frame = H265FrameHelper<FrameImp>;
|
||||
|
||||
/**
|
||||
* 防止内存拷贝的H265类
|
||||
* 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类
|
||||
* H265 class to prevent memory copying
|
||||
* Users can quickly wrap a pointer into a Frame class without copying through this type
|
||||
|
||||
* [AUTO-TRANSLATED:44bde991]
|
||||
*/
|
||||
using H265FrameNoCacheAble = H265FrameHelper<FrameFromPtr>;
|
||||
|
||||
/**
|
||||
* 265视频通道
|
||||
* 265 video channel
|
||||
|
||||
* [AUTO-TRANSLATED:27c65a36]
|
||||
*/
|
||||
class H265Track : public VideoTrack {
|
||||
public:
|
||||
@@ -119,6 +131,10 @@ public:
|
||||
/**
|
||||
* 不指定sps pps构造h265类型的媒体
|
||||
* 在随后的inputFrame中获取sps pps
|
||||
* Construct a h265 media without specifying sps pps
|
||||
* Get sps pps in the subsequent inputFrame
|
||||
|
||||
* [AUTO-TRANSLATED:bf86e048]
|
||||
*/
|
||||
H265Track() = default;
|
||||
|
||||
@@ -130,6 +146,16 @@ public:
|
||||
* @param vps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param sps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* @param pps_prefix_len 265头长度,可以为3个或4个字节,一般为0x00 00 00 01
|
||||
* Construct a h265 media
|
||||
* @param vps vps frame data
|
||||
* @param sps sps frame data
|
||||
* @param pps pps frame data
|
||||
* @param vps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param sps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
* @param pps_prefix_len 265 header length, can be 3 or 4 bytes, generally 0x00 00 00 01
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:a8c42d9f]
|
||||
*/
|
||||
H265Track(const std::string &vps,const std::string &sps, const std::string &pps,int vps_prefix_len = 4, int sps_prefix_len = 4, int pps_prefix_len = 4);
|
||||
|
||||
|
||||
@@ -22,12 +22,14 @@ namespace mediakit {
|
||||
|
||||
void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
if (_info.codec == CodecInvalid) {
|
||||
// 先判断是否为增强型rtmp
|
||||
// 先判断是否为增强型rtmp [AUTO-TRANSLATED:86c4f86a]
|
||||
// First, determine if it is an enhanced rtmp
|
||||
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
|
||||
}
|
||||
|
||||
if (_info.is_enhanced) {
|
||||
// 增强型rtmp
|
||||
// 增强型rtmp [AUTO-TRANSLATED:d7d72114]
|
||||
// Enhanced rtmp
|
||||
parseVideoRtmpPacket((uint8_t *)pkt->data(), pkt->size(), &_info);
|
||||
if (!_info.is_enhanced || _info.codec != CodecH265) {
|
||||
throw std::invalid_argument("Invalid enhanced-rtmp hevc packet!");
|
||||
@@ -61,7 +63,8 @@ void H265RtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 国内扩展(12) H265 rtmp
|
||||
// 国内扩展(12) H265 rtmp [AUTO-TRANSLATED:ba272139]
|
||||
// Domestic extension (12) H265 rtmp
|
||||
if (pkt->isConfigFrame()) {
|
||||
CHECK_RET(pkt->size() > 5);
|
||||
getTrack()->setExtraData((uint8_t *)pkt->data() + 5, pkt->size() - 5);
|
||||
@@ -133,7 +136,8 @@ bool H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
_rtmp_packet->chunk_id = CHUNK_VIDEO;
|
||||
_rtmp_packet->stream_index = STREAM_MEDIA;
|
||||
_rtmp_packet->type_id = MSG_VIDEO;
|
||||
// 输出rtmp packet
|
||||
// 输出rtmp packet [AUTO-TRANSLATED:d72e89a7]
|
||||
// Output rtmp packet
|
||||
RtmpCodec::inputRtmp(_rtmp_packet);
|
||||
_rtmp_packet = nullptr;
|
||||
}, &_rtmp_packet->buffer);
|
||||
|
||||
@@ -19,6 +19,10 @@ namespace mediakit {
|
||||
/**
|
||||
* h265 Rtmp解码类
|
||||
* 将 h265 over rtmp 解复用出 h265-Frame
|
||||
* h265 Rtmp decoder class
|
||||
* Demultiplex h265-Frame from h265 over rtmp
|
||||
|
||||
* [AUTO-TRANSLATED:2768e4bd]
|
||||
*/
|
||||
class H265RtmpDecoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -29,6 +33,10 @@ public:
|
||||
/**
|
||||
* 输入265 Rtmp包
|
||||
* @param rtmp Rtmp包
|
||||
* Input 265 Rtmp packet
|
||||
* @param rtmp Rtmp packet
|
||||
|
||||
* [AUTO-TRANSLATED:63dbe33f]
|
||||
*/
|
||||
void inputRtmp(const RtmpPacket::Ptr &rtmp) override;
|
||||
|
||||
@@ -42,6 +50,9 @@ protected:
|
||||
|
||||
/**
|
||||
* 265 Rtmp打包类
|
||||
* 265 Rtmp packaging class
|
||||
|
||||
* [AUTO-TRANSLATED:5891c800]
|
||||
*/
|
||||
class H265RtmpEncoder : public RtmpCodec {
|
||||
public:
|
||||
@@ -52,22 +63,39 @@ public:
|
||||
* 如果track不为空且包含sps pps信息,
|
||||
* 那么inputFrame时可以不输入sps pps
|
||||
* @param track
|
||||
* Constructor, track can be empty, in which case sps pps is input when inputFrame
|
||||
* If track is not empty and contains sps pps information,
|
||||
* Then sps pps can be omitted when inputFrame
|
||||
* @param track
|
||||
|
||||
* [AUTO-TRANSLATED:e61fdfed]
|
||||
*/
|
||||
H265RtmpEncoder(const Track::Ptr &track) : RtmpCodec(track) {}
|
||||
|
||||
/**
|
||||
* 输入265帧,可以不带sps pps
|
||||
* @param frame 帧数据
|
||||
* Input 265 frame, sps pps can be omitted
|
||||
* @param frame Frame data
|
||||
|
||||
* [AUTO-TRANSLATED:7d1be1e7]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache output
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* 生成config包
|
||||
* Generate config packet
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:8f851364]
|
||||
*/
|
||||
void makeConfigPacket() override;
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
namespace mediakit{
|
||||
|
||||
//https://datatracker.ietf.org/doc/rfc7798/
|
||||
//H265 nalu 头两个字节的定义
|
||||
// H265 nalu 头两个字节的定义 [AUTO-TRANSLATED:d896dd59]
|
||||
// H265 nalu header definition of the first two bytes
|
||||
/*
|
||||
0 1
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
@@ -71,7 +72,8 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
||||
*/
|
||||
bool H265RtpDecoder::unpackAp(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint64_t stamp){
|
||||
bool have_key_frame = false;
|
||||
//忽略PayloadHdr
|
||||
// 忽略PayloadHdr [AUTO-TRANSLATED:9868ddb5]
|
||||
// Ignore PayloadHdr
|
||||
CHECK_SIZE(size, 2, have_key_frame);
|
||||
ptr += 2;
|
||||
size -= 2;
|
||||
@@ -125,7 +127,8 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
auto e_bit = (ptr[2] >> 6) & 0x01;
|
||||
auto type = ptr[2] & 0x3f;
|
||||
if (s_bit) {
|
||||
//该帧的第一个rtp包
|
||||
// 该帧的第一个rtp包 [AUTO-TRANSLATED:a9581a23]
|
||||
// The first rtp packet of this frame
|
||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||
_frame->_buffer.push_back((type << 1) | (ptr[0] & 0x81));
|
||||
_frame->_buffer.push_back(ptr[1]);
|
||||
@@ -134,22 +137,26 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
}
|
||||
|
||||
if (_fu_dropped) {
|
||||
//该帧不完整
|
||||
// 该帧不完整 [AUTO-TRANSLATED:6bd7eca7]
|
||||
// This frame is incomplete
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!s_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||
// 中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃 [AUTO-TRANSLATED:6953b332]
|
||||
// The middle or end rtp packet, its seq must be continuous, otherwise it means rtp packet loss, then this frame is incomplete and must be discarded
|
||||
_fu_dropped = true;
|
||||
_frame->_buffer.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
//跳过PayloadHdr + FU header
|
||||
// 跳过PayloadHdr + FU header [AUTO-TRANSLATED:51ec6760]
|
||||
// Skip PayloadHdr + FU header
|
||||
ptr += 3;
|
||||
size -= 3;
|
||||
if (_using_donl_field) {
|
||||
//DONL确保不少于2个字节
|
||||
// DONL确保不少于2个字节 [AUTO-TRANSLATED:7e72ecc1]
|
||||
// DONL must be no less than 2 bytes
|
||||
CHECK_SIZE(size, 2, false);
|
||||
uint16_t donl = AV_RB16(ptr);
|
||||
size -= 2;
|
||||
@@ -158,17 +165,21 @@ bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssiz
|
||||
|
||||
CHECK_SIZE(size, 1, false);
|
||||
|
||||
//后面追加数据
|
||||
// 后面追加数据 [AUTO-TRANSLATED:248516e9]
|
||||
// Append data later
|
||||
_frame->_buffer.append((char *) ptr, size);
|
||||
|
||||
if (!e_bit) {
|
||||
//非末尾包
|
||||
// 非末尾包 [AUTO-TRANSLATED:2e43ac3c]
|
||||
// Non-end packet
|
||||
return s_bit ? (_frame->keyFrame() || _frame->configFrame()) : false;
|
||||
}
|
||||
|
||||
//确保下一次fu必须收到第一个包
|
||||
// 确保下一次fu必须收到第一个包 [AUTO-TRANSLATED:491d81ec]
|
||||
// Ensure that the next fu must receive the first packet
|
||||
_fu_dropped = true;
|
||||
//该帧最后一个rtp包
|
||||
// 该帧最后一个rtp包 [AUTO-TRANSLATED:ea395f0e]
|
||||
// The last rtp packet of this frame
|
||||
outputFrame(rtp, _frame);
|
||||
return false;
|
||||
}
|
||||
@@ -182,14 +193,16 @@ bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||
}
|
||||
_last_seq = seq;
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始
|
||||
// 确保有sps rtp的时候,gop从sps开始;否则从关键帧开始 [AUTO-TRANSLATED:115ae07c]
|
||||
// Ensure that when there is sps rtp, gop starts from sps; otherwise, it starts from the key frame
|
||||
return _is_gop && !last_is_gop;
|
||||
}
|
||||
|
||||
bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||
auto payload_size = rtp->getPayloadSize();
|
||||
if (payload_size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual payload
|
||||
return false;
|
||||
}
|
||||
auto frame = rtp->getPayload();
|
||||
@@ -229,10 +242,12 @@ bool H265RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr,
|
||||
|
||||
void H265RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame) {
|
||||
if (frame->dropAble()) {
|
||||
//不参与dts生成
|
||||
// 不参与dts生成 [AUTO-TRANSLATED:dff3b747]
|
||||
// Not involved in dts generation
|
||||
frame->_dts = frame->_pts;
|
||||
} else {
|
||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||
// rtsp没有dts,那么根据pts排序算法生成dts [AUTO-TRANSLATED:f37c17f3]
|
||||
// rtsp does not have dts, so dts is generated according to the pts sorting algorithm
|
||||
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||
}
|
||||
|
||||
@@ -270,19 +285,26 @@ void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool i
|
||||
}
|
||||
|
||||
{
|
||||
// 传入nullptr先不做payload的内存拷贝
|
||||
// 传入nullptr先不做payload的内存拷贝 [AUTO-TRANSLATED:7ed49f0a]
|
||||
// Pass in nullptr first, do not copy the payload memory
|
||||
auto rtp = getRtpInfo().makeRtp(TrackVideo, nullptr, max_size + 3, mark_bit, pts);
|
||||
// rtp payload 负载部分
|
||||
// rtp payload 负载部分 [AUTO-TRANSLATED:03a5ef9b]
|
||||
// rtp payload load part
|
||||
uint8_t *payload = rtp->getPayload();
|
||||
// FU 第1个字节,表明为FU
|
||||
// FU 第1个字节,表明为FU [AUTO-TRANSLATED:9cf07fda]
|
||||
// FU first byte, indicating FU
|
||||
payload[0] = 49 << 1;
|
||||
// FU 第2个字节貌似固定为1
|
||||
// FU 第2个字节貌似固定为1 [AUTO-TRANSLATED:77983091]
|
||||
// FU second byte seems to be fixed to 1
|
||||
payload[1] = ptr[1]; // 1;
|
||||
// FU 第3个字节
|
||||
// FU 第3个字节 [AUTO-TRANSLATED:c627abd0]
|
||||
// FU third byte
|
||||
payload[2] = s_e_flags;
|
||||
// H265 数据
|
||||
// H265 数据 [AUTO-TRANSLATED:a2c3135f]
|
||||
// H265 data
|
||||
memcpy(payload + 3, ptr + offset, max_size);
|
||||
// 输入到rtp环形缓存
|
||||
// 输入到rtp环形缓存 [AUTO-TRANSLATED:6bafd42b]
|
||||
// Input to rtp ring buffer
|
||||
RtpCodec::inputRtp(rtp, fu_start && gop_pos);
|
||||
}
|
||||
|
||||
@@ -296,7 +318,8 @@ void H265RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_
|
||||
//signal-nalu
|
||||
RtpCodec::inputRtp(getRtpInfo().makeRtp(TrackVideo, ptr, len, is_mark, pts), gop_pos);
|
||||
} else {
|
||||
//FU-A模式
|
||||
// FU-A模式 [AUTO-TRANSLATED:a273a49c]
|
||||
// FU-A mode
|
||||
packRtpFu(ptr, len, pts, is_mark, gop_pos);
|
||||
}
|
||||
}
|
||||
@@ -305,7 +328,8 @@ void H265RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
WarnL<<" not ok";
|
||||
return;
|
||||
}
|
||||
//gop缓存从vps 开始,vps ,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false
|
||||
// gop缓存从vps 开始,vps ,sps、pps后面还有时间戳相同的关键帧,所以mark bit为false [AUTO-TRANSLATED:2534b06f]
|
||||
// gop cache starts from vps, vps, sps, pps followed by key frames with the same timestamp, so mark bit is false
|
||||
packRtp(_vps->data() + _vps->prefixSize(), _vps->size() - _vps->prefixSize(), pts, false, true);
|
||||
packRtp(_sps->data() + _sps->prefixSize(), _sps->size() - _sps->prefixSize(), pts, false, false);
|
||||
packRtp(_pps->data() + _pps->prefixSize(), _pps->size() - _pps->prefixSize(), pts, false, false);
|
||||
@@ -313,7 +337,8 @@ void H265RtpEncoder::insertConfigFrame(uint64_t pts){
|
||||
}
|
||||
bool H265RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
|
||||
if (frame->keyFrame()) {
|
||||
//保证每一个关键帧前都有SPS PPS VPS
|
||||
// 保证每一个关键帧前都有SPS PPS VPS [AUTO-TRANSLATED:9189f8d7]
|
||||
// Ensure that there are SPS PPS VPS before each key frame
|
||||
insertConfigFrame(frame->pts());
|
||||
}
|
||||
packRtp(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), frame->pts(), is_mark, false);
|
||||
@@ -347,7 +372,8 @@ bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
inputFrame_l(frame, true);
|
||||
} else {
|
||||
if (_last_frame) {
|
||||
//如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:19b68429]
|
||||
// If the timestamp changes, then markbit is set to true
|
||||
inputFrame_l(_last_frame, _last_frame->pts() != frame->pts());
|
||||
}
|
||||
_last_frame = Frame::getCacheAbleFrame(frame);
|
||||
@@ -357,7 +383,8 @@ bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
|
||||
void H265RtpEncoder::flush() {
|
||||
if (_last_frame) {
|
||||
// 如果时间戳发生了变化,那么markbit才置true
|
||||
// 如果时间戳发生了变化,那么markbit才置true [AUTO-TRANSLATED:6b1d0fe0]
|
||||
// If the timestamp changes, then markbit is set to true
|
||||
inputFrame_l(_last_frame, true);
|
||||
_last_frame = nullptr;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace mediakit {
|
||||
* h265 rtp解码类
|
||||
* 将 h265 over rtsp-rtp 解复用出 h265-Frame
|
||||
* 《草案(H265-over-RTP)draft-ietf-payload-rtp-h265-07.pdf》
|
||||
* h265 rtp decoder class
|
||||
* Demultiplex h265-Frame from h265 over rtsp-rtp
|
||||
* 《Draft (H265-over-RTP) draft-ietf-payload-rtp-h265-07.pdf》
|
||||
|
||||
* [AUTO-TRANSLATED:24e7e278]
|
||||
*/
|
||||
class H265RtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@@ -33,6 +38,11 @@ public:
|
||||
* 输入265 rtp包
|
||||
* @param rtp rtp包
|
||||
* @param key_pos 此参数忽略之
|
||||
* Input 265 rtp packet
|
||||
* @param rtp rtp packet
|
||||
* @param key_pos This parameter is ignored
|
||||
|
||||
* [AUTO-TRANSLATED:35e8fa1d]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = true) override;
|
||||
|
||||
@@ -57,6 +67,9 @@ private:
|
||||
|
||||
/**
|
||||
* 265 rtp打包类
|
||||
* 265 rtp packer class
|
||||
|
||||
* [AUTO-TRANSLATED:4b3f96fe]
|
||||
*/
|
||||
class H265RtpEncoder : public RtpCodec {
|
||||
public:
|
||||
@@ -65,11 +78,19 @@ public:
|
||||
/**
|
||||
* 输入265帧
|
||||
* @param frame 帧数据,必须
|
||||
* Input 265 frame
|
||||
* @param frame Frame data, required
|
||||
|
||||
* [AUTO-TRANSLATED:48454707]
|
||||
*/
|
||||
bool inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
/**
|
||||
* 刷新输出所有frame缓存
|
||||
* Flush all frame cache in output
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:adaea568]
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
@@ -85,6 +106,6 @@ private:
|
||||
Frame::Ptr _last_frame;
|
||||
};
|
||||
|
||||
}//namespace mediakit{
|
||||
}//namespace mediakit
|
||||
|
||||
#endif //ZLMEDIAKIT_H265RTPCODEC_H
|
||||
|
||||
@@ -42,11 +42,16 @@ public:
|
||||
/**
|
||||
* JPEG/MJPEG帧
|
||||
* @param pix_type pixel format type; AV_PIX_FMT_YUVJ422P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV422P) : 1; AV_PIX_FMT_YUVJ420P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV420P) : 0
|
||||
* JPEG/MJPEG frame
|
||||
* @param pix_type pixel format type; AV_PIX_FMT_YUVJ422P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV422P) : 1; AV_PIX_FMT_YUVJ420P || (AVCOL_RANGE_JPEG && AV_PIX_FMT_YUV420P) : 0
|
||||
|
||||
* [AUTO-TRANSLATED:d746e541]
|
||||
*/
|
||||
template <typename... ARGS>
|
||||
JPEGFrame(uint8_t pix_type, ARGS &&...args) : Parent(std::forward<ARGS>(args)...) {
|
||||
_pix_type = pix_type;
|
||||
// JFIF头固定20个字节长度
|
||||
// JFIF头固定20个字节长度 [AUTO-TRANSLATED:bd63b447]
|
||||
// JFIF header is fixed at 20 bytes in length
|
||||
CHECK(this->size() > kJFIFSize);
|
||||
}
|
||||
size_t prefixSize() const override { return 0; }
|
||||
|
||||
@@ -632,7 +632,8 @@ void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uin
|
||||
for (j = 0; j < tables; j++)
|
||||
qtables[nb_qtables + j] = buf + i + 5 + j * 65;
|
||||
nb_qtables += tables;
|
||||
// 大致忽略DQT/qtable所占字节数,提高搜寻速度
|
||||
// 大致忽略DQT/qtable所占字节数,提高搜寻速度 [AUTO-TRANSLATED:63423997]
|
||||
// Roughly ignore the number of bytes occupied by DQT/qtable to improve search speed
|
||||
i += tables << 6;
|
||||
} else if (buf[i + 1] == SOF0) {
|
||||
if (buf[i + 14] != 17 || buf[i + 17] != 17) {
|
||||
@@ -642,7 +643,8 @@ void JPEGRtpEncoder::rtpSendJpeg(const uint8_t *buf, int size, uint64_t pts, uin
|
||||
}
|
||||
h = (buf[i + 5] * 256 + buf[i + 6]) / 8;
|
||||
w = (buf[i + 7] * 256 + buf[i + 8]) / 8;
|
||||
// 大致忽略SOF0所占字节数,提高搜寻速度
|
||||
// 大致忽略SOF0所占字节数,提高搜寻速度 [AUTO-TRANSLATED:438cbf70]
|
||||
// Roughly ignore the number of bytes occupied by SOF0 to improve search speed
|
||||
i += 16;
|
||||
} else if (buf[i + 1] == DHT) {
|
||||
int dht_size = AV_RB16(&buf[i + 2]);
|
||||
@@ -811,7 +813,8 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
auto seq = rtp->getSeq();
|
||||
auto marker = rtp->getHeader()->mark;
|
||||
if (size <= 0) {
|
||||
//无实际负载
|
||||
// 无实际负载 [AUTO-TRANSLATED:305af48f]
|
||||
// No actual load
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -829,7 +832,8 @@ bool JPEGRtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool JPEGRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
// JFIF头固定20个字节长度
|
||||
// JFIF头固定20个字节长度 [AUTO-TRANSLATED:bd63b447]
|
||||
// JFIF header is fixed at 20 bytes in length
|
||||
auto ptr = (uint8_t *)frame->data() + frame->prefixSize() + JPEGFrameImp::kJFIFSize;
|
||||
auto len = frame->size() - frame->prefixSize() - JPEGFrameImp::kJFIFSize;
|
||||
auto pts = frame->pts();
|
||||
|
||||
@@ -19,6 +19,9 @@ struct PayloadContext {
|
||||
|
||||
/**
|
||||
* 通用 rtp解码类
|
||||
* General rtp decoding class
|
||||
|
||||
* [AUTO-TRANSLATED:41b57089]
|
||||
*/
|
||||
class JPEGRtpDecoder : public RtpCodec {
|
||||
public:
|
||||
@@ -30,6 +33,12 @@ public:
|
||||
* 输入rtp并解码
|
||||
* @param rtp rtp数据包
|
||||
* @param key_pos 此参数内部强制转换为false,请忽略之
|
||||
* Input rtp and decode
|
||||
* @param rtp rtp data packet
|
||||
* @param key_pos This parameter is internally forced to false, please ignore it
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:2993fcbe]
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* L16类型SDP
|
||||
* L16 type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:11b1196d]
|
||||
*/
|
||||
class L16Sdp : public Sdp {
|
||||
public:
|
||||
@@ -29,6 +32,14 @@ public:
|
||||
* @param channels 通道数
|
||||
* @param sample_rate 音频采样率
|
||||
* @param bitrate 比特率
|
||||
* L16 sampling bit width is fixed to 16 bits
|
||||
* @param payload_type rtp payload type
|
||||
* @param channels number of channels
|
||||
* @param sample_rate audio sampling rate
|
||||
* @param bitrate bitrate
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7a08a400]
|
||||
*/
|
||||
L16Sdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
|
||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* L16音频通道
|
||||
* L16 audio channel
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:7a4b086f]
|
||||
*/
|
||||
class L16Track : public AudioTrackImp{
|
||||
public:
|
||||
|
||||
@@ -20,6 +20,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* Opus类型SDP
|
||||
* Opus type SDP
|
||||
|
||||
* [AUTO-TRANSLATED:6c0a72ed]
|
||||
*/
|
||||
class OpusSdp : public Sdp {
|
||||
public:
|
||||
@@ -29,6 +32,14 @@ public:
|
||||
* @param sample_rate 音频采样率
|
||||
* @param channels 通道数
|
||||
* @param bitrate 比特率
|
||||
* Construct opus sdp
|
||||
* @param payload_type rtp payload type
|
||||
* @param sample_rate audio sample rate
|
||||
* @param channels number of channels
|
||||
* @param bitrate bitrate
|
||||
|
||||
|
||||
* [AUTO-TRANSLATED:40713e9d]
|
||||
*/
|
||||
OpusSdp(int payload_type, int sample_rate, int channels, int bitrate) : Sdp(sample_rate, payload_type) {
|
||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace mediakit {
|
||||
|
||||
/**
|
||||
* Opus帧音频通道
|
||||
* Opus frame audio channel
|
||||
|
||||
* [AUTO-TRANSLATED:522e95da]
|
||||
*/
|
||||
class OpusTrack : public AudioTrackImp{
|
||||
public:
|
||||
@@ -25,11 +28,13 @@ public:
|
||||
OpusTrack() : AudioTrackImp(CodecOpus,48000,2,16){}
|
||||
|
||||
private:
|
||||
//克隆该Track
|
||||
// 克隆该Track [AUTO-TRANSLATED:9a15682a]
|
||||
// Clone this Track
|
||||
Track::Ptr clone() const override {
|
||||
return std::make_shared<OpusTrack>(*this);
|
||||
}
|
||||
//生成sdp
|
||||
// 生成sdp [AUTO-TRANSLATED:663a9367]
|
||||
// Generate sdp
|
||||
Sdp::Ptr getSdp(uint8_t payload_type) const override ;
|
||||
};
|
||||
|
||||
|
||||
@@ -2155,7 +2155,8 @@ exit:
|
||||
|
||||
void h264GetWidthHeight(T_SPS *ptSps, int *piWidth, int *piHeight)
|
||||
{
|
||||
// ¿í¸ß¼ÆË㹫ʽ
|
||||
// ¿í¸ß¼ÆË㹫ʽ [AUTO-TRANSLATED:e2d61727]
|
||||
// What is the frame rate
|
||||
int iCodeWidth = 0;
|
||||
int iCodedHeight = 0;
|
||||
iCodeWidth = 16 * ptSps->iMbWidth;
|
||||
@@ -2278,7 +2279,8 @@ void h265GeFramerate(T_HEVCVPS *ptVps, T_HEVCSPS *ptSps,float *pfFramerate)
|
||||
*pfFramerate = (float)(ptSps->tVui.u32VuiTimeScale) / (float)(ptSps->tVui.u32VuiNumUnitsInTick);
|
||||
}
|
||||
else{
|
||||
//vps sps可能不包含帧率
|
||||
// vps sps可能不包含帧率 [AUTO-TRANSLATED:15424320]
|
||||
// vps sps may not contain frame rate
|
||||
*pfFramerate = 0.0F;
|
||||
RPT(RPT_WRN, "frame rate:0");
|
||||
}
|
||||
|
||||
@@ -144,6 +144,11 @@ typedef struct T_AVRational{
|
||||
/***
|
||||
* Sequence parameter set
|
||||
* ¿É²Î¿¼H264±ê×¼µÚ7½ÚºÍ¸½Â¼D E
|
||||
/***
|
||||
* Sequence parameter set
|
||||
* H.264 sequence parameter set, version 7 and above, D E
|
||||
|
||||
* [AUTO-TRANSLATED:bd590cb8]
|
||||
*/
|
||||
#define Extended_SAR 255
|
||||
|
||||
@@ -490,7 +495,8 @@ typedef struct {
|
||||
int log2_sao_offset_scale_luma;
|
||||
int log2_sao_offset_scale_chroma;
|
||||
|
||||
// 可以根据需要添加更多字段
|
||||
// 可以根据需要添加更多字段 [AUTO-TRANSLATED:57b9a7c1]
|
||||
// You can add more fields as needed
|
||||
} T_HEVC_PPS;
|
||||
|
||||
typedef struct T_GetBitContext{
|
||||
|
||||
Reference in New Issue
Block a user