mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 20:27:34 +08:00
rtp h265 packet like h264
This commit is contained in:
parent
599208dd6a
commit
67d8837442
@ -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,
|
|||||||
ui8Interleaved) {
|
ui8Interleaved) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void H265RtpEncoder::packRtpFu(const char *ptr, size_t len, uint64_t pts, bool is_mark, bool gop_pos){
|
||||||
|
auto max_size = getMaxSize() - 3;
|
||||||
|
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
|
||||||
|
mark_bit = true;
|
||||||
|
max_size = len - offset;
|
||||||
|
s_e_flags = (1 << 6) | nal_type;
|
||||||
|
} else if (fu_start) {
|
||||||
|
// FU start
|
||||||
|
s_e_flags = (1 << 7) | nal_type;
|
||||||
|
} else {
|
||||||
|
// FU mid
|
||||||
|
s_e_flags = nal_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// 传入nullptr先不做payload的内存拷贝
|
||||||
|
auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
|
||||||
|
// rtp payload 负载部分
|
||||||
|
uint8_t *payload = rtp->getPayload();
|
||||||
|
// FU 第1个字节,表明为FU
|
||||||
|
payload[0] = 49 << 1;
|
||||||
|
// FU 第2个字节貌似固定为1
|
||||||
|
payload[1] = ptr[1]; // 1;
|
||||||
|
// FU 第3个字节
|
||||||
|
payload[2] = s_e_flags;
|
||||||
|
// H265 数据
|
||||||
|
memcpy(payload + 3, ptr + offset, max_size);
|
||||||
|
// 输入到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 {
|
||||||
|
//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) {
|
bool H265RtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||||
auto ptr = (uint8_t *) frame->data() + frame->prefixSize();
|
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 nal_type = H265_TYPE(ptr[0]); //获取NALU的5bit 帧类型
|
||||||
auto max_size = getMaxSize() - 3;
|
|
||||||
|
|
||||||
//超过MTU,按照FU方式打包
|
switch (nal_type) {
|
||||||
if (len > max_size + 2) {
|
case H265Frame::NAL_SPS: {
|
||||||
//获取帧头数据,1byte
|
_sps = Frame::getCacheAbleFrame(frame);
|
||||||
unsigned char s_e_flags;
|
return true;
|
||||||
bool fu_start = true;
|
|
||||||
bool mark_bit = false;
|
|
||||||
size_t offset = 2;
|
|
||||||
while (!mark_bit) {
|
|
||||||
if (len <= offset + max_size) {
|
|
||||||
//FU end
|
|
||||||
mark_bit = true;
|
|
||||||
max_size = len - offset;
|
|
||||||
s_e_flags = (1 << 6) | nal_type;
|
|
||||||
} else if (fu_start) {
|
|
||||||
//FU start
|
|
||||||
s_e_flags = (1 << 7) | nal_type;
|
|
||||||
} else {
|
|
||||||
//FU mid
|
|
||||||
s_e_flags = nal_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
//传入nullptr先不做payload的内存拷贝
|
|
||||||
auto rtp = makeRtp(getTrackType(), nullptr, max_size + 3, mark_bit, pts);
|
|
||||||
//rtp payload 负载部分
|
|
||||||
uint8_t *payload = rtp->getPayload();
|
|
||||||
//FU 第1个字节,表明为FU
|
|
||||||
payload[0] = 49 << 1;
|
|
||||||
//FU 第2个字节貌似固定为1
|
|
||||||
payload[1] = ptr[1];// 1;
|
|
||||||
//FU 第3个字节
|
|
||||||
payload[2] = s_e_flags;
|
|
||||||
//H265 数据
|
|
||||||
memcpy(payload + 3, ptr + offset, max_size);
|
|
||||||
//输入到rtp环形缓存
|
|
||||||
RtpCodec::inputRtp(rtp, fu_start && frame->keyFrame());
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += max_size;
|
|
||||||
fu_start = false;
|
|
||||||
}
|
}
|
||||||
} else {
|
case H265Frame::NAL_PPS: {
|
||||||
RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, false, pts), frame->keyFrame());
|
_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
|
}//namespace mediakit
|
||||||
|
@ -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{
|
||||||
|
Loading…
Reference in New Issue
Block a user