rtp h265 packet like h264

This commit is contained in:
xiongguangjie 2023-04-06 19:54:59 +08:00
parent 599208dd6a
commit 67d8837442
2 changed files with 124 additions and 47 deletions

View File

@ -9,7 +9,7 @@
*/
#include "H265Rtp.h"
#include "Common/config.h"
namespace mediakit{
//https://datatracker.ietf.org/doc/rfc7798/
@ -258,58 +258,119 @@ H265RtpEncoder::H265RtpEncoder(uint32_t ui32Ssrc,
ui8Interleaved) {
}
bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
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 帧类型
void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
auto max_size = getMaxSize() - 3;
//超过MTU,按照FU方式打包
if (len > max_size + 2) {
//获取帧头数据1byte
auto nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
unsigned char s_e_flags;
bool fu_start = true;
bool mark_bit = false;
size_t offset = 2;
while (!mark_bit) {
if (len <= offset + max_size) {
//FU end
// FU end
mark_bit = true;
max_size = len - offset;
s_e_flags = (1 << 6) | nal_type;
} else if (fu_start) {
//FU start
// FU start
s_e_flags = (1 << 7) | nal_type;
} else {
//FU mid
// FU mid
s_e_flags = nal_type;
}
{
//传入nullptr先不做payload的内存拷贝
// 传入nullptr先不做payload的内存拷贝
auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
//rtp payload 负载部分
// rtp payload 负载部分
uint8_t *payload = rtp->getPayload();
//FU 第1个字节表明为FU
// FU 第1个字节表明为FU
payload[0] = 49 << 1;
//FU 第2个字节貌似固定为1
payload[1] = ptr[1];// 1;
//FU 第3个字节
// FU 第2个字节貌似固定为1
payload[1] = ptr[1]; // 1;
// FU 第3个字节
payload[2] = s_e_flags;
//H265 数据
// H265 数据
memcpy(payload + 3, ptr + offset, max_size);
//输入到rtp环形缓存
RtpCodec::inputRtp(rtp, fu_start && frame->keyFrame());
// 输入到rtp环形缓存
RtpCodec::inputRtp(rtp, fu_start && gop_pos);
}
offset += max_size;
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 {
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, false, pts), frame->keyFrame());
//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 {
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

View File

@ -85,6 +85,22 @@ public:
* @param frame
*/
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{