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

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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() << "/"

View File

@@ -18,6 +18,10 @@ namespace mediakit{
/**
* G711音频通道
* G711 audio channel
* [AUTO-TRANSLATED:57f8bc08]
*/
class G711Track : public AudioTrackImp{
public:

View File

@@ -16,7 +16,8 @@ void G711RtpEncoder::setOpt(int opt, const toolkit::Any &param) {
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;
}
}

View File

@@ -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;

View File

@@ -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-2324 (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-2324 (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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -22,6 +22,11 @@ namespace mediakit {
* h265 rtp解码类
* 将 h265 over rtsp-rtp 解复用出 h265-Frame
* 《草案H265-over-RTPdraft-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

View File

@@ -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; }

View File

@@ -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();

View File

@@ -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;

View File

@@ -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";

View File

@@ -18,6 +18,10 @@ namespace mediakit {
/**
* L16音频通道
* L16 audio channel
* [AUTO-TRANSLATED:7a4b086f]
*/
class L16Track : public AudioTrackImp{
public:

View File

@@ -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";

View File

@@ -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 ;
};

View File

@@ -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");
}

View File

@@ -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{