mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-26 04:31:37 +08:00
确保rtp丢包时,丢弃gop后续所有帧,防止丢包花屏
This commit is contained in:
parent
55fc598d4c
commit
375d36b4c8
@ -46,7 +46,14 @@ H264Frame::Ptr H264RtpDecoder::obtainFrame() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
bool H264RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool key_pos) {
|
||||||
return decodeRtp(rtp);
|
auto seq = rtp->getSeq();
|
||||||
|
auto ret = decodeRtp(rtp);
|
||||||
|
if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) {
|
||||||
|
_gop_dropped = true;
|
||||||
|
WarnL << "start drop h264 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||||
|
}
|
||||||
|
_last_seq = seq;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -66,118 +73,115 @@ Table 1. Summary of NAL unit types and their payload structures
|
|||||||
30-31 undefined -
|
30-31 undefined -
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool H264RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
||||||
|
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||||
|
_frame->_buffer.append((char *) ptr, size);
|
||||||
|
_frame->_pts = stamp;
|
||||||
|
auto key = _frame->keyFrame();
|
||||||
|
outputFrame(rtp, _frame);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool H264RtpDecoder::unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp) {
|
||||||
|
//STAP-A 单一时间的组合包
|
||||||
|
auto have_key_frame = false;
|
||||||
|
auto end = ptr + size;
|
||||||
|
while (ptr + 2 < end) {
|
||||||
|
uint16_t len = (ptr[0] << 8) | ptr[1];
|
||||||
|
if (!len || ptr + len > end) {
|
||||||
|
WarnL << "invalid rtp data size:" << len << ",rtp:\r\n" << rtp->dumpString();
|
||||||
|
_gop_dropped = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
if (singleFrame(rtp, ptr, len, stamp)) {
|
||||||
|
have_key_frame = true;
|
||||||
|
}
|
||||||
|
ptr += len;
|
||||||
|
}
|
||||||
|
return have_key_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool H264RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp, uint16_t seq){
|
||||||
|
auto nal_suffix = *ptr & (~0x1F);
|
||||||
|
FuFlags *fu = (FuFlags *) (ptr + 1);
|
||||||
|
if (fu->start_bit) {
|
||||||
|
//该帧的第一个rtp包
|
||||||
|
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||||
|
_frame->_buffer.push_back(nal_suffix | fu->nal_type);
|
||||||
|
_frame->_pts = stamp;
|
||||||
|
_fu_dropped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_fu_dropped) {
|
||||||
|
//该帧不完整
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fu->start_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||||
|
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||||
|
_fu_dropped = true;
|
||||||
|
_frame->_buffer.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//后面追加数据
|
||||||
|
_frame->_buffer.append((char *) ptr + 2, size - 2);
|
||||||
|
|
||||||
|
if (!fu->end_bit) {
|
||||||
|
//非末尾包
|
||||||
|
return fu->start_bit ? _frame->keyFrame() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//确保下一次fu必须收到第一个包
|
||||||
|
_fu_dropped = true;
|
||||||
|
//该帧最后一个rtp包,输出frame
|
||||||
|
outputFrame(rtp, _frame);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
bool H264RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||||
auto frame = rtp->getPayload();
|
auto frame = rtp->getPayload();
|
||||||
auto length = rtp->getPayloadSize();
|
auto length = rtp->getPayloadSize();
|
||||||
auto stamp = rtp->getStampMS();
|
auto stamp = rtp->getStampMS();
|
||||||
auto seq = rtp->getSeq();
|
auto seq = rtp->getSeq();
|
||||||
auto nal_type = *frame & 0x1F;
|
int nal = H264_TYPE(frame[0]);
|
||||||
auto nal_suffix = *frame & (~0x1F);
|
|
||||||
|
|
||||||
if (nal_type >= 0 && nal_type < 24) {
|
switch (nal) {
|
||||||
//a full frame
|
case 24:
|
||||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
// 24 STAP-A Single-time aggregation packet 5.7.1
|
||||||
_frame->_buffer.append((char *) frame, length);
|
return unpackStapA(rtp, frame + 1, length - 1, stamp);
|
||||||
_frame->_pts = stamp;
|
|
||||||
auto key = _frame->keyFrame();
|
|
||||||
onGetH264(_frame);
|
|
||||||
return (key); //i frame
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (nal_type) {
|
case 28:
|
||||||
case 24: {
|
// 28 FU-A Fragmentation unit
|
||||||
// 24 STAP-A 单一时间的组合包
|
return mergeFu(rtp, frame, length, stamp, seq);
|
||||||
bool haveIDR = false;
|
|
||||||
auto ptr = frame + 1;
|
|
||||||
while (true) {
|
|
||||||
size_t off = ptr - frame;
|
|
||||||
if (off >= length) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//获取当前nalu的大小
|
|
||||||
uint16_t len = *ptr++;
|
|
||||||
len <<= 8;
|
|
||||||
len |= *ptr++;
|
|
||||||
if (off + len > length) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
//有有效数据
|
|
||||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
|
||||||
_frame->_buffer.append((char *) ptr, len);
|
|
||||||
_frame->_pts = stamp;
|
|
||||||
if ((ptr[0] & 0x1F) == H264Frame::NAL_IDR) {
|
|
||||||
haveIDR = true;
|
|
||||||
}
|
|
||||||
onGetH264(_frame);
|
|
||||||
}
|
|
||||||
ptr += len;
|
|
||||||
}
|
|
||||||
return haveIDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 28: {
|
|
||||||
//FU-A
|
|
||||||
FuFlags *fu = (FuFlags *) (frame + 1);
|
|
||||||
if (fu->start_bit) {
|
|
||||||
//该帧的第一个rtp包 FU-A start
|
|
||||||
//预留空间,防止频繁扩容拷贝
|
|
||||||
_frame->_buffer.reserve(_max_frame_size);
|
|
||||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
|
||||||
_frame->_buffer.push_back(nal_suffix | fu->nal_type);
|
|
||||||
_frame->_buffer.append((char *) frame + 2, length - 2);
|
|
||||||
_frame->_pts = stamp;
|
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
|
||||||
_last_seq = seq;
|
|
||||||
return _frame->keyFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seq != (uint16_t) (_last_seq + 1)) {
|
|
||||||
//中间的或末尾的rtp包,其seq必须连续(如果回环了则判定为连续),否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
|
||||||
_frame->_buffer.clear();
|
|
||||||
WarnL << "rtp丢包: " << seq << " != " << _last_seq << " + 1,该帧被废弃";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fu->end_bit) {
|
|
||||||
//该帧的中间rtp包 FU-A mid
|
|
||||||
_frame->_buffer.append((char *) frame + 2, length - 2);
|
|
||||||
//该函数return时,保存下当前sequence,以便下次对比seq是否连续
|
|
||||||
_last_seq = seq;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//该帧最后一个rtp包 FU-A end
|
|
||||||
_frame->_buffer.append((char *) frame + 2, length - 2);
|
|
||||||
_frame->_pts = stamp;
|
|
||||||
//计算最大的帧
|
|
||||||
auto frame_size = _frame->size();
|
|
||||||
if (frame_size > _max_frame_size) {
|
|
||||||
_max_frame_size = frame_size;
|
|
||||||
}
|
|
||||||
onGetH264(_frame);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// 29 FU-B 单NAL单元B模式
|
if (nal < 24) {
|
||||||
// 25 STAP-B 单一时间的组合包
|
//Single NAL Unit Packets
|
||||||
// 26 MTAP16 多个时间的组合包
|
return singleFrame(rtp, frame, length, stamp);
|
||||||
// 27 MTAP24 多个时间的组合包
|
}
|
||||||
WarnL << "不支持的rtp类型:" << (int) nal_type << " " << seq;
|
_gop_dropped = true;
|
||||||
|
WarnL << "不支持该类型的264 RTP包, nal type:" << nal << ", rtp:\r\n" << rtp->dumpString();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void H264RtpDecoder::onGetH264(const H264Frame::Ptr &frame) {
|
void H264RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame) {
|
||||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||||
_dts_generator.getDts(frame->_pts,frame->_dts);
|
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||||
RtpCodec::inputFrame(frame);
|
|
||||||
|
if (frame->keyFrame() && _gop_dropped) {
|
||||||
|
_gop_dropped = false;
|
||||||
|
InfoL << "new gop received, rtp:\r\n" << rtp->dumpString();
|
||||||
|
}
|
||||||
|
if (!_gop_dropped) {
|
||||||
|
RtpCodec::inputFrame(frame);
|
||||||
|
}
|
||||||
_frame = obtainFrame();
|
_frame = obtainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
H264RtpEncoder::H264RtpEncoder(uint32_t ssrc, uint32_t mtu, uint32_t sample_rate, uint8_t pt, uint8_t interleaved)
|
H264RtpEncoder::H264RtpEncoder(uint32_t ssrc, uint32_t mtu, uint32_t sample_rate, uint8_t pt, uint8_t interleaved)
|
||||||
|
@ -43,13 +43,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
||||||
|
bool unpackStapA(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
||||||
|
bool mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp, uint16_t seq);
|
||||||
|
|
||||||
bool decodeRtp(const RtpPacket::Ptr &rtp);
|
bool decodeRtp(const RtpPacket::Ptr &rtp);
|
||||||
void onGetH264(const H264Frame::Ptr &frame);
|
|
||||||
H264Frame::Ptr obtainFrame();
|
H264Frame::Ptr obtainFrame();
|
||||||
|
void outputFrame(const RtpPacket::Ptr &rtp, const H264Frame::Ptr &frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool _gop_dropped = false;
|
||||||
|
bool _fu_dropped = true;
|
||||||
uint16_t _last_seq = 0;
|
uint16_t _last_seq = 0;
|
||||||
size_t _max_frame_size = 0;
|
|
||||||
H264Frame::Ptr _frame;
|
H264Frame::Ptr _frame;
|
||||||
DtsGenerator _dts_generator;
|
DtsGenerator _dts_generator;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
|
//https://datatracker.ietf.org/doc/rfc7798/
|
||||||
//H265 nalu 头两个字节的定义
|
//H265 nalu 头两个字节的定义
|
||||||
/*
|
/*
|
||||||
0 1
|
0 1
|
||||||
@ -41,7 +42,7 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
|||||||
|
|
||||||
#define CHECK_SIZE(total, size, ret) \
|
#define CHECK_SIZE(total, size, ret) \
|
||||||
if (total < size) { \
|
if (total < size) { \
|
||||||
WarnL << "数据不够:" << total << " " << size; return ret; \
|
WarnL << "invalid rtp data size:" << total << " < " << size << ",rtp:\r\n" << rtp->dumpString(); _gop_dropped = true; return ret; \
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4.4.2. Aggregation Packets (APs) (p25)
|
// 4.4.2. Aggregation Packets (APs) (p25)
|
||||||
@ -68,9 +69,8 @@ H265Frame::Ptr H265RtpDecoder::obtainFrame() {
|
|||||||
| : ...OPTIONAL RTP padding |
|
| : ...OPTIONAL RTP padding |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
bool H265RtpDecoder::unpackAp(const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
bool H265RtpDecoder::unpackAp(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
||||||
bool have_key_frame = false;
|
bool have_key_frame = false;
|
||||||
|
|
||||||
//忽略PayloadHdr
|
//忽略PayloadHdr
|
||||||
CHECK_SIZE(size, 2, have_key_frame);
|
CHECK_SIZE(size, 2, have_key_frame);
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
@ -88,7 +88,7 @@ bool H265RtpDecoder::unpackAp(const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
|||||||
size -= 2;
|
size -= 2;
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
CHECK_SIZE(size, nalu_size, have_key_frame)
|
CHECK_SIZE(size, nalu_size, have_key_frame)
|
||||||
if (singleFrame(ptr, nalu_size, stamp)) {
|
if (singleFrame(rtp, ptr, nalu_size, stamp)) {
|
||||||
have_key_frame = true;
|
have_key_frame = true;
|
||||||
}
|
}
|
||||||
size -= nalu_size;
|
size -= nalu_size;
|
||||||
@ -119,7 +119,7 @@ bool H265RtpDecoder::unpackAp(const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
|||||||
+---------------+
|
+---------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool H265RtpDecoder::mergeFu(const uint8_t *ptr, ssize_t size, uint16_t seq, uint32_t stamp){
|
bool H265RtpDecoder::mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp, uint16_t seq){
|
||||||
CHECK_SIZE(size, 4, false);
|
CHECK_SIZE(size, 4, false);
|
||||||
auto s_bit = ptr[2] >> 7;
|
auto s_bit = ptr[2] >> 7;
|
||||||
auto e_bit = (ptr[2] >> 6) & 0x01;
|
auto e_bit = (ptr[2] >> 6) & 0x01;
|
||||||
@ -127,15 +127,21 @@ bool H265RtpDecoder::mergeFu(const uint8_t *ptr, ssize_t size, uint16_t seq, uin
|
|||||||
if (s_bit) {
|
if (s_bit) {
|
||||||
//该帧的第一个rtp包
|
//该帧的第一个rtp包
|
||||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||||
//恢复nalu头两个字节
|
|
||||||
_frame->_buffer.push_back((type << 1) | (ptr[0] & 0x81));
|
_frame->_buffer.push_back((type << 1) | (ptr[0] & 0x81));
|
||||||
_frame->_buffer.push_back(ptr[1]);
|
_frame->_buffer.push_back(ptr[1]);
|
||||||
|
_frame->_pts = stamp;
|
||||||
|
_fu_dropped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s_bit && seq != (uint16_t) (_last_seq + 1) && seq != 0) {
|
if (_fu_dropped) {
|
||||||
|
//该帧不完整
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_bit && seq != (uint16_t) (_last_seq + 1)) {
|
||||||
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
//中间的或末尾的rtp包,其seq必须连续,否则说明rtp丢包,那么该帧不完整,必须得丢弃
|
||||||
|
_fu_dropped = true;
|
||||||
_frame->_buffer.clear();
|
_frame->_buffer.clear();
|
||||||
WarnL << "rtp丢包: " << seq << " != " << _last_seq << " + 1,该帧被废弃";
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,64 +158,80 @@ bool H265RtpDecoder::mergeFu(const uint8_t *ptr, ssize_t size, uint16_t seq, uin
|
|||||||
|
|
||||||
CHECK_SIZE(size, 1, false);
|
CHECK_SIZE(size, 1, false);
|
||||||
|
|
||||||
|
//后面追加数据
|
||||||
|
_frame->_buffer.append((char *) ptr, size);
|
||||||
|
|
||||||
if (!e_bit) {
|
if (!e_bit) {
|
||||||
//非末尾包
|
//非末尾包
|
||||||
_last_seq = seq;
|
|
||||||
_frame->_buffer.append((char *) ptr, size);
|
|
||||||
return s_bit ? _frame->keyFrame() : false;
|
return s_bit ? _frame->keyFrame() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//确保下一次fu必须收到第一个包
|
||||||
|
_fu_dropped = true;
|
||||||
//该帧最后一个rtp包
|
//该帧最后一个rtp包
|
||||||
_frame->_pts = stamp;
|
outputFrame(rtp, _frame);
|
||||||
_frame->_buffer.append((char *) ptr, size);
|
|
||||||
outputFrame(_frame);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool ) {
|
bool H265RtpDecoder::inputRtp(const RtpPacket::Ptr &rtp, bool) {
|
||||||
|
auto seq = rtp->getSeq();
|
||||||
|
auto ret = decodeRtp(rtp);
|
||||||
|
if (!_gop_dropped && seq != (uint16_t) (_last_seq + 1) && _last_seq) {
|
||||||
|
_gop_dropped = true;
|
||||||
|
WarnL << "start drop h265 gop, last seq:" << _last_seq << ", rtp:\r\n" << rtp->dumpString();
|
||||||
|
}
|
||||||
|
_last_seq = seq;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool H265RtpDecoder::decodeRtp(const RtpPacket::Ptr &rtp) {
|
||||||
auto frame = rtp->getPayload();
|
auto frame = rtp->getPayload();
|
||||||
auto length = rtp->getPayloadSize();
|
auto length = rtp->getPayloadSize();
|
||||||
auto stamp = rtp->getStampMS();
|
auto stamp = rtp->getStampMS();
|
||||||
auto seq = rtp->getSeq();
|
auto seq = rtp->getSeq();
|
||||||
int nal = H265_TYPE(frame[0]);
|
int nal = H265_TYPE(frame[0]);
|
||||||
|
|
||||||
if (nal > 50){
|
|
||||||
// packet discard, Unsupported (HEVC) NAL type
|
|
||||||
WarnL << "不支持该类型的265 RTP包" << nal;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (nal) {
|
switch (nal) {
|
||||||
case 50:
|
|
||||||
//4.4.4. PACI Packets (p32)
|
|
||||||
WarnL << "不支持该类型的265 RTP包" << nal;
|
|
||||||
return false;
|
|
||||||
case 48:
|
case 48:
|
||||||
// aggregated packet (AP) - with two or more NAL units
|
// aggregated packet (AP) - with two or more NAL units
|
||||||
return unpackAp(frame, length, stamp);
|
return unpackAp(rtp, frame, length, stamp);
|
||||||
case 49:
|
|
||||||
|
case 49:
|
||||||
// fragmentation unit (FU)
|
// fragmentation unit (FU)
|
||||||
return mergeFu(frame, length, seq, stamp);
|
return mergeFu(rtp, frame, length, stamp, seq);
|
||||||
default:
|
|
||||||
// 4.4.1. Single NAL Unit Packets (p24)
|
default: {
|
||||||
return singleFrame(frame, length, stamp);
|
if (nal < 48) {
|
||||||
|
// Single NAL Unit Packets (p24)
|
||||||
|
return singleFrame(rtp, frame, length, stamp);
|
||||||
|
}
|
||||||
|
_gop_dropped = true;
|
||||||
|
WarnL << "不支持该类型的265 RTP包, nal type" << nal << ", rtp:\r\n" << rtp->dumpString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool H265RtpDecoder::singleFrame(const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
bool H265RtpDecoder::singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp){
|
||||||
//a full frame
|
|
||||||
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
_frame->_buffer.assign("\x00\x00\x00\x01", 4);
|
||||||
_frame->_buffer.append((char *) ptr, size);
|
_frame->_buffer.append((char *) ptr, size);
|
||||||
_frame->_pts = stamp;
|
_frame->_pts = stamp;
|
||||||
auto key = _frame->keyFrame();
|
auto key = _frame->keyFrame();
|
||||||
outputFrame(_frame);
|
outputFrame(rtp, _frame);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void H265RtpDecoder::outputFrame(const H265Frame::Ptr &frame) {
|
void H265RtpDecoder::outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame) {
|
||||||
//rtsp没有dts,那么根据pts排序算法生成dts
|
//rtsp没有dts,那么根据pts排序算法生成dts
|
||||||
_dts_generator.getDts(frame->_pts,frame->_dts);
|
_dts_generator.getDts(frame->_pts, frame->_dts);
|
||||||
//输出frame
|
|
||||||
RtpCodec::inputFrame(frame);
|
if (frame->keyFrame() && _gop_dropped) {
|
||||||
|
_gop_dropped = false;
|
||||||
|
InfoL << "new gop received, rtp:\r\n" << rtp->dumpString();
|
||||||
|
}
|
||||||
|
if (!_gop_dropped) {
|
||||||
|
RtpCodec::inputFrame(frame);
|
||||||
|
}
|
||||||
_frame = obtainFrame();
|
_frame = obtainFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,15 +44,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool unpackAp(const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
bool unpackAp(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
||||||
bool mergeFu(const uint8_t *ptr, ssize_t size, uint16_t seq, uint32_t stamp);
|
bool mergeFu(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp, uint16_t seq);
|
||||||
bool singleFrame(const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
bool singleFrame(const RtpPacket::Ptr &rtp, const uint8_t *ptr, ssize_t size, uint32_t stamp);
|
||||||
|
|
||||||
|
bool decodeRtp(const RtpPacket::Ptr &rtp);
|
||||||
H265Frame::Ptr obtainFrame();
|
H265Frame::Ptr obtainFrame();
|
||||||
void outputFrame(const H265Frame::Ptr &frame);
|
void outputFrame(const RtpPacket::Ptr &rtp, const H265Frame::Ptr &frame);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _using_donl_field = false;
|
bool _using_donl_field = false;
|
||||||
|
bool _gop_dropped = false;
|
||||||
|
bool _fu_dropped = true;
|
||||||
uint16_t _last_seq = 0;
|
uint16_t _last_seq = 0;
|
||||||
H265Frame::Ptr _frame;
|
H265Frame::Ptr _frame;
|
||||||
DtsGenerator _dts_generator;
|
DtsGenerator _dts_generator;
|
||||||
|
Loading…
Reference in New Issue
Block a user