Commit 67d88374 by xiongguangjie

rtp h265 packet like h264

parent 599208dd
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
*/ */
#include "H265Rtp.h" #include "H265Rtp.h"
#include "Common/config.h"
namespace mediakit{ namespace mediakit{
//https://datatracker.ietf.org/doc/rfc7798/ //https://datatracker.ietf.org/doc/rfc7798/
...@@ -258,58 +258,119 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc, ...@@ -258,58 +258,119 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
ui8Interleaved) { ui8Interleaved) {
} }
bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) { void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
auto ptr = (uint8_t *) frame->data() + frame->prefixSize();
auto len = frame->size() - frame->prefixSize();
auto pts = frame->pts();
auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
auto max_size = getMaxSize() - 3; auto max_size = getMaxSize() - 3;
auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
//超过MTU,按照FU方式打包
if (len > max_size + 2) {
//获取帧头数据,1byte
unsigned char s_e_flags; unsigned char s_e_flags;
bool fu_start = true; bool fu_start = true;
bool mark_bit = false; bool mark_bit = false;
size_t offset = 2; size_t offset = 2;
while (!mark_bit) { while (!mark_bit) {
if (len <= offset + max_size) { if (len <= offset + max_size) {
//FU end // FU end
mark_bit = true; mark_bit = true;
max_size = len - offset; max_size = len - offset;
s_e_flags = (1 << 6) | nal_type; s_e_flags = (1 << 6) | nal_type;
} else if (fu_start) { } else if (fu_start) {
//FU start // FU start
s_e_flags = (1 << 7) | nal_type; s_e_flags = (1 << 7) | nal_type;
} else { } else {
//FU mid // FU mid
s_e_flags = nal_type; s_e_flags = nal_type;
} }
{ {
//传入nullptr先不做payload的内存拷贝 // 传入nullptr先不做payload的内存拷贝
auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts); auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
//rtp payload 负载部分 // rtp payload 负载部分
uint8_t *payload = rtp->getPayload(); uint8_t *payload = rtp->getPayload();
//FU 第1个字节,表明为FU // FU 第1个字节,表明为FU
payload[0] = 49 << 1; payload[0] = 49 << 1;
//FU 第2个字节貌似固定为1 // FU 第2个字节貌似固定为1
payload[1] = ptr[1];// 1; payload[1] = ptr[1]; // 1;
//FU 第3个字节 // FU 第3个字节
payload[2] = s_e_flags; payload[2] = s_e_flags;
//H265 数据 // H265 数据
memcpy(payload + 3, ptr + offset, max_size); memcpy(payload + 3, ptr + offset, max_size);
//输入到rtp环形缓存 // 输入到rtp环形缓存
RtpCodec::inputRtp(rtp, fu_start && frame->keyFrame()); RtpCodec::inputRtp(rtp, fu_start && gop_pos);
} }
offset += max_size; offset += max_size;
fu_start = false; fu_start = false;
} }
}
void H265RtpEncoder::packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
if (len + 3 <= getMaxSize()) {
//signal-nalu
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, is_mark, pts), gop_pos);
} else {
//FU-A模式
packRtpFu(ptr, len, pts, is_mark, gop_pos);
}
}
void H265RtpEncoder::insertConfigFrame(uint64_t pts){
if (!_sps || !_pps || !_vps) {
WarnL<<" not ok";
return;
}
//gop缓存从vps 开始,vps ,sps、pps后面还有时间戳相同的关键帧,所以mark bit为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);
}
bool H265RtpEncoder::inputFrame_l(const Frame::Ptr &frame, bool is_mark){
if (frame->keyFrame()) {
//保证每一个关键帧前都有SPS PPS VPS
insertConfigFrame(frame->pts());
}
packRtp(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize(), frame->pts(), is_mark, false);
return true;
}
bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
auto ptr = (uint8_t *) frame->data() + frame->prefixSize();
auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
switch (nal_type) {
case H265Frame::NAL_SPS: {
_sps = Frame::getCacheAbleFrame(frame);
return true;
}
case H265Frame::NAL_PPS: {
_pps = Frame::getCacheAbleFrame(frame);
return true;
}
case H265Frame::NAL_VPS:{
_vps = Frame::getCacheAbleFrame(frame);
return true;
}
default: break;
}
GET_CONFIG(int,lowLatency,Rtp::kLowLatency);
if (lowLatency) { // 低延迟模式
if (_last_frame) {
flush();
}
inputFrame_l(frame, true);
} else { } else {
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, false, pts), frame->keyFrame()); if (_last_frame) {
//如果时间戳发生了变化,那么markbit才置true
inputFrame_l(_last_frame, _last_frame->pts() != frame->pts());
}
_last_frame = Frame::getCacheAbleFrame(frame);
}
return true;
}
void H265RtpEncoder::flush() {
if (_last_frame) {
// 如果时间戳发生了变化,那么markbit才置true
inputFrame_l(_last_frame, true);
_last_frame = nullptr;
} }
return len > 0;
} }
}//namespace mediakit }//namespace mediakit
...@@ -85,6 +85,22 @@ public: ...@@ -85,6 +85,22 @@ public:
* @param frame 帧数据,必须 * @param frame 帧数据,必须
*/ */
bool inputFrame(const Frame::Ptr &frame) override; bool inputFrame(const Frame::Ptr &frame) override;
/**
* 刷新输出所有frame缓存
*/
void flush() override;
private:
void packRtp(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos);
void packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos);
void insertConfigFrame(uint64_t pts);
bool inputFrame_l(const Frame::Ptr &frame, bool is_mark);
private:
Frame::Ptr _sps;
Frame::Ptr _pps;
Frame::Ptr _vps;
Frame::Ptr _last_frame;
}; };
}//namespace mediakit{ }//namespace mediakit{
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论