From 35d9321b93e0dac5ba367db0d052f95ee66a85cc Mon Sep 17 00:00:00 2001 From: ziyue <1213642868@qq.com> Date: Fri, 9 Jul 2021 13:38:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86H264/H265=20Frame=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E5=8F=8A=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Extension/Frame.cpp | 145 +++++++++++++------------------------ src/Extension/Frame.h | 33 +++++++-- src/Extension/H264.cpp | 42 ----------- src/Extension/H264.h | 66 ++++++++++++----- src/Extension/H264Rtmp.cpp | 31 +++----- src/Extension/H264Rtmp.h | 4 +- src/Extension/H265.cpp | 57 +-------------- src/Extension/H265.h | 72 +++++++++++++----- src/Extension/H265Rtmp.cpp | 37 +++------- src/Extension/H265Rtmp.h | 2 +- src/Extension/H265Rtp.cpp | 8 +- src/Extension/H265Rtp.h | 2 - 12 files changed, 201 insertions(+), 298 deletions(-) diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index ec45e87d..f619c3cd 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -58,12 +58,12 @@ public: typedef std::shared_ptr Ptr; FrameCacheAble(const Frame::Ptr &frame){ - if(frame->cacheAble()){ + if (frame->cacheAble()) { _frame = frame; _ptr = frame->data(); - }else{ + } else { _buffer = FrameImp::create(); - _buffer->_buffer.assign(frame->data(),frame->size()); + _buffer->_buffer.assign(frame->data(), frame->size()); _ptr = _buffer->data(); } _size = frame->size(); @@ -73,6 +73,8 @@ public: _codec_id = frame->getCodecId(); _key = frame->keyFrame(); _config = frame->configFrame(); + _drop_able = frame->dropAble(); + _decode_able = frame->decodeAble(); } ~FrameCacheAble() override = default; @@ -92,9 +94,19 @@ public: return _config; } + bool dropAble() const override { + return _drop_able; + } + + bool decodeAble() const override { + return _decode_able; + } + private: bool _key; bool _config; + bool _drop_able; + bool _decode_able; Frame::Ptr _frame; FrameImp::Ptr _buffer; }; @@ -153,18 +165,18 @@ const char* getTrackString(TrackType type){ } } -const char *CodecInfo::getCodecName() { +const char *CodecInfo::getCodecName() const { return mediakit::getCodecName(getCodecId()); } -TrackType CodecInfo::getTrackType() { +TrackType CodecInfo::getTrackType() const { return mediakit::getTrackType(getCodecId()); } static size_t constexpr kMaxFrameCacheSize = 100; bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ - if (_frameCached.empty()) { + if (_frame_cache.empty()) { //缓存为空 return false; } @@ -182,36 +194,20 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ default: break; } //遇到新帧、或时间戳变化或缓存太多,防止内存溢出,则flush输出 - return new_frame || _frameCached.back()->dts() != frame->dts() || _frameCached.size() > kMaxFrameCacheSize; + return new_frame || _frame_cache.back()->dts() != frame->dts() || _frame_cache.size() > kMaxFrameCacheSize; } case mp4_nal_size: case h264_prefix: { - if (!frameCacheHasVCL()) { + if (!_have_decode_able_frame) { //缓存中没有有效的能解码的帧,所以这次不flush - return false; + return _frame_cache.size() > kMaxFrameCacheSize; } - if (_frameCached.back()->dts() != frame->dts()) { - //时间戳变化了,立即flush + if (_frame_cache.back()->dts() != frame->dts() || frame->decodeAble()) { + //时间戳变化了,或新的一帧,立即flush return true; } - switch (frame->getCodecId()) { - case CodecH264 : { - auto type = H264_TYPE(frame->data()[frame->prefixSize()]); - // sei aud pps sps 不判断;264 新一帧的开始,刷新输出 - return (frame->data()[frame->prefixSize() + 1] & 0x80) != 0 && type >= H264Frame::NAL_B_P && - type <= H264Frame::NAL_IDR; - } - case CodecH265 : { - auto type = H265_TYPE(frame->data()[frame->prefixSize()]); - //first_slice_segment_in_pic_flag is frame start - return (type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) && - ((frame->data()[frame->prefixSize() + 2] >> 7 & 0x01) != 0); - } - default : - //缓存太多,防止内存溢出 - return _frameCached.size() > kMaxFrameCacheSize; - } + return _frame_cache.size() > kMaxFrameCacheSize; } default: /*不可达*/ assert(0); return true; } @@ -245,86 +241,39 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con } } -bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{ - switch (frame->getCodecId()) { - case CodecH264: { - switch (H264_TYPE(frame->data()[frame->prefixSize()])) { - // 防止把AUD或者SEI当成一帧 - case H264Frame::NAL_SEI: - case H264Frame::NAL_AUD: return true; - default: return false; - } - } - - case CodecH265: { - switch (H265_TYPE(frame->data()[frame->prefixSize()])) { - // 防止把AUD或者SEI当成一帧 - case H265Frame::NAL_AUD: - case H265Frame::NAL_SEI_SUFFIX: - case H265Frame::NAL_SEI_PREFIX: return true; - default: return false; - } - } - - default: return false; - } -} - -bool FrameMerger::frameCacheHasVCL() const { - bool has_vcl = false; - bool is_h264_or_h265 = false; - _frameCached.for_each([&](const Frame::Ptr &frame) { - switch (frame->getCodecId()) { - case CodecH264: { - auto type = H264_TYPE(frame->data()[frame->prefixSize()]); - //有编码数据 - has_vcl = type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR; - is_h264_or_h265 = true; - break; - } - case CodecH265: { - auto type = H265_TYPE(frame->data()[frame->prefixSize()]); - //有编码数据 - has_vcl = type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23; - is_h264_or_h265 = true; - break; - } - default: break; - } - }); - if (is_h264_or_h265) { - return has_vcl; - } - return true; -} - -void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { +void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb, BufferLikeString *buffer) { if (willFlush(frame)) { - Frame::Ptr back = _frameCached.back(); + Frame::Ptr back = _frame_cache.back(); Buffer::Ptr merged_frame = back; - bool have_idr = back->keyFrame(); + bool have_key_frame = back->keyFrame(); - if (_frameCached.size() != 1 || _type == mp4_nal_size) { + if (_frame_cache.size() != 1 || _type == mp4_nal_size || buffer) { //在MP4模式下,一帧数据也需要在前添加nalu_size - BufferLikeString merged; - merged.reserve(back->size() + 1024); - _frameCached.for_each([&](const Frame::Ptr &frame) { + BufferLikeString tmp; + BufferLikeString &merged = buffer ? *buffer : tmp; + + if (!buffer) { + tmp.reserve(back->size() + 1024); + } + + _frame_cache.for_each([&](const Frame::Ptr &frame) { doMerge(merged, frame); if (frame->keyFrame()) { - have_idr = true; + have_key_frame = true; } }); - merged_frame = std::make_shared >(std::move(merged)); + merged_frame = std::make_shared >(buffer ? merged : std::move(merged)); } - cb(back->dts(), back->pts(), merged_frame, have_idr); - _frameCached.clear(); + cb(back->dts(), back->pts(), merged_frame, have_key_frame); + _frame_cache.clear(); + _have_decode_able_frame = false; } switch (_type) { case h264_prefix: case mp4_nal_size: { - //h264头和mp4头模式过滤无效的帧 - if (shouldDrop(frame)) { + if (frame->dropAble()) { + //h264头和mp4头模式过滤无效的帧 return; } break; @@ -332,7 +281,10 @@ void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { default: break; } - _frameCached.emplace_back(Frame::getCacheAbleFrame(frame)); + if (frame->decodeAble()) { + _have_decode_able_frame = true; + } + _frame_cache.emplace_back(Frame::getCacheAbleFrame(frame)); } FrameMerger::FrameMerger(int type) { @@ -340,7 +292,8 @@ FrameMerger::FrameMerger(int type) { } void FrameMerger::clear() { - _frameCached.clear(); + _frame_cache.clear(); + _have_decode_able_frame = false; } }//namespace mediakit diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 4cc9d529..a256ecdb 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -95,12 +95,12 @@ public: /** * 获取编码器名称 */ - const char *getCodecName(); + const char *getCodecName() const; /** * 获取音视频类型 */ - TrackType getTrackType(); + TrackType getTrackType() const; }; /** @@ -144,6 +144,26 @@ public: */ virtual bool cacheAble() const { return true; } + /** + * 该帧是否可以丢弃 + * SEI/AUD帧可以丢弃 + * 默认都不能丢帧 + */ + virtual bool dropAble() const { return false; } + + /** + * 是否为可解码帧 + * sps pps等帧不能解码 + */ + virtual bool decodeAble() const { + if (getTrackType() != TrackVideo) { + //非视频帧都可以解码 + return true; + } + //默认非sps pps帧都可以解码 + return !configFrame(); + } + /** * 返回可缓存的frame */ @@ -459,7 +479,7 @@ private: */ class FrameMerger { public: - using onOutput = function; + using onOutput = function; using Ptr = std::shared_ptr; enum { none = 0, @@ -471,17 +491,16 @@ public: ~FrameMerger() = default; void clear(); - void inputFrame(const Frame::Ptr &frame, const onOutput &cb); + void inputFrame(const Frame::Ptr &frame, const onOutput &cb, BufferLikeString *buffer = nullptr); private: bool willFlush(const Frame::Ptr &frame) const; void doMerge(BufferLikeString &buffer, const Frame::Ptr &frame) const; - bool shouldDrop(const Frame::Ptr &frame) const; - bool frameCacheHasVCL() const; private: int _type; - List _frameCached; + bool _have_decode_able_frame = false; + List _frame_cache; }; }//namespace mediakit diff --git a/src/Extension/H264.cpp b/src/Extension/H264.cpp index 1db1f676..60f8ac2a 100644 --- a/src/Extension/H264.cpp +++ b/src/Extension/H264.cpp @@ -276,48 +276,6 @@ Sdp::Ptr H264Track::getSdp() { return std::make_shared(getSps(), getPps(), getBitRate() / 1024); } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -bool H264Frame::keyFrame() const { - //多slice 一帧的情况下检查 first_mb_in_slice 是否为0 表示其为一帧的开始 - return H264_TYPE(_buffer[_prefix_size]) == H264Frame::NAL_IDR && (_buffer[_prefix_size + 1] & 0x80); -} - -bool H264Frame::configFrame() const { - switch (H264_TYPE(_buffer[_prefix_size])) { - case H264Frame::NAL_SPS: - case H264Frame::NAL_PPS: return true; - default: return false; - } -} - -H264Frame::H264Frame() { - _codec_id = CodecH264; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -H264FrameNoCacheAble::H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size){ - _ptr = ptr; - _size = size; - _dts = dts; - _pts = pts; - _prefix_size = prefix_size; - _codec_id = CodecH264; -} - -bool H264FrameNoCacheAble::keyFrame() const { - return H264_TYPE(_ptr[_prefix_size]) == H264Frame::NAL_IDR; -} - -bool H264FrameNoCacheAble::configFrame() const { - switch (H264_TYPE(_ptr[_prefix_size])) { - case H264Frame::NAL_SPS: - case H264Frame::NAL_PPS: return true; - default: return false; - } -} - }//namespace mediakit diff --git a/src/Extension/H264.h b/src/Extension/H264.h index 395b0ea8..2ff63d1d 100644 --- a/src/Extension/H264.h +++ b/src/Extension/H264.h @@ -23,12 +23,12 @@ bool getAVCInfo(const string &strSps,int &iVideoWidth, int &iVideoHeight, float void splitH264(const char *ptr, size_t len, size_t prefix, const std::function &cb); size_t prefixSize(const char *ptr, size_t len); -/** - * 264帧类 - */ -class H264Frame : public FrameImp { +template +class H264FrameHelper : public Parent{ public: - using Ptr = std::shared_ptr; + friend class FrameImp; + friend class ResourcePool_l; + using Ptr = std::shared_ptr; enum { NAL_IDR = 5, @@ -39,28 +39,54 @@ public: NAL_B_P = 1, }; - bool keyFrame() const override; - bool configFrame() const override; + template + H264FrameHelper(ARGS &&...args): Parent(std::forward(args)...) { + this->_codec_id = CodecH264; + } -protected: - friend class FrameImp; - friend class ResourcePool_l; - H264Frame(); + ~H264FrameHelper() override = default; + + bool keyFrame() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + return H264_TYPE(*nal_ptr) == NAL_IDR && decodeAble(); + } + + bool configFrame() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + switch (H264_TYPE(*nal_ptr)) { + case NAL_SPS: + case NAL_PPS: return true; + default: return false; + } + } + + bool dropAble() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + switch (H264_TYPE(*nal_ptr)) { + case NAL_SEI: + case NAL_AUD: return true; + default: return false; + } + } + + bool decodeAble() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + auto type = H264_TYPE(*nal_ptr); + //多slice情况下, first_mb_in_slice 表示其为一帧的开始 + return type >= NAL_B_P && type <= NAL_IDR && (nal_ptr[1] & 0x80); + } }; +/** + * 264帧类 + */ +using H264Frame = H264FrameHelper; + /** * 防止内存拷贝的H264类 * 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类 - * 该类型在DevChannel中有使用 */ -class H264FrameNoCacheAble : public FrameFromPtr { -public: - using Ptr = std::shared_ptr; - - H264FrameNoCacheAble(char *ptr,size_t size,uint32_t dts , uint32_t pts ,size_t prefix_size = 4); - bool keyFrame() const override; - bool configFrame() const override; -}; +using H264FrameNoCacheAble = H264FrameHelper; /** * 264视频通道 diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index b0f2e58d..6f4e1e06 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -157,10 +157,8 @@ void H264RtmpEncoder::makeConfigPacket(){ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { auto data = frame->data() + frame->prefixSize(); auto len = frame->size() - frame->prefixSize(); - auto type = H264_TYPE(((uint8_t*)data)[0]); + auto type = H264_TYPE(data[0]); switch (type) { - case H264Frame::NAL_SEI: - case H264Frame::NAL_AUD: return; case H264Frame::NAL_SPS: { if (!_got_config_frame) { _sps = string(data, len); @@ -178,21 +176,6 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { default : break; } - if (frame->configFrame() && _rtmp_packet && _has_vcl) { - //sps pps flush frame - RtmpCodec::inputRtmp(_rtmp_packet); - _has_vcl = false; - _rtmp_packet = nullptr; - } - - if (_rtmp_packet && (_rtmp_packet->time_stamp != frame->dts() || ((data[1] & 0x80) != 0 && type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR && _has_vcl))) { - RtmpCodec::inputRtmp(_rtmp_packet); - _has_vcl = false; - _rtmp_packet = nullptr; - } - if (type >= H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR) { - _has_vcl = true; - } if (!_rtmp_packet) { //I or P or B frame int8_t flags = FLV_CODEC_H264; @@ -200,6 +183,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); _rtmp_packet = RtmpPacket::create(); + _rtmp_packet->buffer.clear(); _rtmp_packet->buffer.push_back(flags); _rtmp_packet->buffer.push_back(!is_config); int32_t cts = frame->pts() - frame->dts(); @@ -213,10 +197,13 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { _rtmp_packet->time_stamp = frame->dts(); _rtmp_packet->type_id = MSG_VIDEO; } - uint32_t size = htonl((uint32_t) len); - _rtmp_packet->buffer.append((char *) &size, 4); - _rtmp_packet->buffer.append(data, len); - _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + + _merger.inputFrame(frame, [&](uint32_t, uint32_t, const Buffer::Ptr &, bool) { + //输出rtmp packet + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + RtmpCodec::inputRtmp(_rtmp_packet); + _rtmp_packet = nullptr; + }, &_rtmp_packet->buffer); } void H264RtmpEncoder::makeVideoConfigPkt() { diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index ee59a2fe..f60daf99 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -75,13 +75,15 @@ public: * 生成config包 */ void makeConfigPacket() override; + private: void makeVideoConfigPkt(); + private: - bool _has_vcl = false; bool _got_config_frame = false; H264Track::Ptr _track; RtmpPacket::Ptr _rtmp_packet; + FrameMerger _merger{FrameMerger::mp4_nal_size}; }; }//namespace mediakit diff --git a/src/Extension/H265.cpp b/src/Extension/H265.cpp index 883a4839..53cf7a8f 100644 --- a/src/Extension/H265.cpp +++ b/src/Extension/H265.cpp @@ -50,56 +50,6 @@ bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, i ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool H265Frame::keyFrame() const { - return isKeyFrame(H265_TYPE(_buffer[_prefix_size]), _buffer.data() + _prefix_size); -} - -bool H265Frame::configFrame() const { - switch (H265_TYPE(_buffer[_prefix_size])) { - case H265Frame::NAL_VPS: - case H265Frame::NAL_SPS: - case H265Frame::NAL_PPS : return true; - default : return false; - } -} - -bool H265Frame::isKeyFrame(int type, const char *ptr) { - if (ptr) { - return (((*((uint8_t *) ptr + 2)) >> 7) & 0x01) == 1 && (type == NAL_IDR_N_LP || type == NAL_IDR_W_RADL); - } - return false; -} - -H265Frame::H265Frame(){ - _codec_id = CodecH265; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -H265FrameNoCacheAble::H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts, uint32_t pts, size_t prefix_size) { - _ptr = ptr; - _size = size; - _dts = dts; - _pts = pts; - _prefix_size = prefix_size; - _codec_id = CodecH265; -} - -bool H265FrameNoCacheAble::keyFrame() const { - return H265Frame::isKeyFrame(H265_TYPE(((uint8_t *) _ptr)[_prefix_size]), _ptr + _prefix_size); -} - -bool H265FrameNoCacheAble::configFrame() const { - switch (H265_TYPE(((uint8_t *) _ptr)[_prefix_size])) { - case H265Frame::NAL_VPS: - case H265Frame::NAL_SPS: - case H265Frame::NAL_PPS: return true; - default: return false; - } -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - H265Track::H265Track(const string &vps,const string &sps, const string &pps,int vps_prefix_len, int sps_prefix_len, int pps_prefix_len) { _vps = vps.substr(vps_prefix_len); _sps = sps.substr(sps_prefix_len); @@ -154,17 +104,16 @@ void H265Track::inputFrame(const Frame::Ptr &frame) { } void H265Track::inputFrame_l(const Frame::Ptr &frame) { - int type = H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0]); - if (H265Frame::isKeyFrame(type, frame->data() + frame->prefixSize())) { + if (frame->keyFrame()) { insertConfigFrame(frame); VideoTrack::inputFrame(frame); _is_idr = true; return; } - _is_idr = false; + _is_idr = false; //非idr帧 - switch (type) { + switch (H265_TYPE(((uint8_t *) frame->data() + frame->prefixSize())[0])) { case H265Frame::NAL_VPS: { _vps = string(frame->data() + frame->prefixSize(), frame->size() - frame->prefixSize()); break; diff --git a/src/Extension/H265.h b/src/Extension/H265.h index fe24df3f..8659e552 100644 --- a/src/Extension/H265.h +++ b/src/Extension/H265.h @@ -22,12 +22,13 @@ namespace mediakit { bool getHEVCInfo(const string &strVps, const string &strSps, int &iVideoWidth, int &iVideoHeight, float &iVideoFps); -/** - * 265帧类 - */ -class H265Frame : public FrameImp { +template +class H265FrameHelper : public Parent{ public: - using Ptr = std::shared_ptr; + friend class FrameImp; + friend class ResourcePool_l; + using Ptr = std::shared_ptr; + enum { NAL_TRAIL_N = 0, NAL_TRAIL_R = 1, @@ -59,24 +60,57 @@ public: NAL_SEI_SUFFIX = 40, }; - bool keyFrame() const override; - bool configFrame() const override; - static bool isKeyFrame(int type, const char* ptr); + template + H265FrameHelper(ARGS &&...args): Parent(std::forward(args)...) { + this->_codec_id = CodecH265; + } -protected: - friend class FrameImp; - friend class ResourcePool_l; - H265Frame(); + ~H265FrameHelper() override = default; + + bool keyFrame() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + auto type = H265_TYPE(*nal_ptr); + return (type == NAL_IDR_N_LP || type == NAL_IDR_W_RADL) && decodeAble(); + } + + bool configFrame() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + switch (H265_TYPE(*nal_ptr)) { + case NAL_VPS: + case NAL_SPS: + case NAL_PPS : return true; + default : return false; + } + } + + bool dropAble() const override { + auto nal_ptr = (uint8_t *) this->data() + this->prefixSize(); + switch (H264_TYPE(*nal_ptr)) { + case NAL_AUD: + case NAL_SEI_SUFFIX: + case NAL_SEI_PREFIX: return true; + default: return false; + } + } + + 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 表示其为一帧的开始 + return type >= NAL_TRAIL_R && type <= NAL_RSV_IRAP_VCL23 && (nal_ptr[2] & 0x80); + } }; -class H265FrameNoCacheAble : public FrameFromPtr { -public: - using Ptr = std::shared_ptr; +/** + * 265帧类 + */ +using H265Frame = H265FrameHelper; - H265FrameNoCacheAble(char *ptr, size_t size, uint32_t dts,uint32_t pts, size_t prefix_size = 4); - bool keyFrame() const override; - bool configFrame() const override; -}; +/** + * 防止内存拷贝的H265类 + * 用户可以通过该类型快速把一个指针无拷贝的包装成Frame类 + */ +using H265FrameNoCacheAble = H265FrameHelper; /** * 265视频通道 diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp index 1dedd0ae..5a91a13e 100644 --- a/src/Extension/H265Rtmp.cpp +++ b/src/Extension/H265Rtmp.cpp @@ -136,8 +136,7 @@ void H265RtmpEncoder::makeConfigPacket(){ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { auto data = frame->data() + frame->prefixSize(); auto len = frame->size() - frame->prefixSize(); - auto type = H265_TYPE(((uint8_t*)data)[0]); - + auto type = H265_TYPE(data[0]); switch (type) { case H265Frame::NAL_SPS: { if (!_got_config_frame) { @@ -160,37 +159,16 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { } break; } - case H265Frame::NAL_AUD: - case H265Frame::NAL_SEI_PREFIX: - case H265Frame::NAL_SEI_SUFFIX: return; default: break; } - if(frame->configFrame() && _rtmp_packet && _has_vcl){ - // sps pps flush frame - RtmpCodec::inputRtmp(_rtmp_packet); - _rtmp_packet = nullptr; - _has_vcl = false; - } - - if (_rtmp_packet && (_rtmp_packet->time_stamp != frame->dts() || (_has_vcl && type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23 && (data[2] >> 7 & 0x01) != 0))) { - RtmpCodec::inputRtmp(_rtmp_packet); - _has_vcl = false; - _rtmp_packet = nullptr; - } - - if (type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) { - _has_vcl = true; - } - if (!_rtmp_packet) { //I or P or B frame int8_t flags = FLV_CODEC_H265; bool is_config = false; flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - // todo 必须是IDR帧才能是关键帧,否则有可能开始帧会花屏 SPS PPS VPS 打头的是一般I帧,但不一定是IDR帧 - // RtmpCodec::inputRtmp 时需要判断 是否是IDR帧,做出相应的修改 _rtmp_packet = RtmpPacket::create(); + _rtmp_packet->buffer.clear(); _rtmp_packet->buffer.push_back(flags); _rtmp_packet->buffer.push_back(!is_config); int32_t cts = frame->pts() - frame->dts(); @@ -204,10 +182,13 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { _rtmp_packet->time_stamp = frame->dts(); _rtmp_packet->type_id = MSG_VIDEO; } - uint32_t size = htonl((uint32_t) len); - _rtmp_packet->buffer.append((char *) &size, 4); - _rtmp_packet->buffer.append(data, len); - _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + + _merger.inputFrame(frame, [&](uint32_t, uint32_t, const Buffer::Ptr &, bool) { + //输出rtmp packet + _rtmp_packet->body_size = _rtmp_packet->buffer.size(); + RtmpCodec::inputRtmp(_rtmp_packet); + _rtmp_packet = nullptr; + }, &_rtmp_packet->buffer); } void H265RtmpEncoder::makeVideoConfigPkt() { diff --git a/src/Extension/H265Rtmp.h b/src/Extension/H265Rtmp.h index c9ef7420..14e38546 100644 --- a/src/Extension/H265Rtmp.h +++ b/src/Extension/H265Rtmp.h @@ -78,13 +78,13 @@ private: void makeVideoConfigPkt(); private: - bool _has_vcl = false; bool _got_config_frame = false; string _vps; string _sps; string _pps; H265Track::Ptr _track; RtmpPacket::Ptr _rtmp_packet; + FrameMerger _merger{FrameMerger::mp4_nal_size}; }; }//namespace mediakit diff --git a/src/Extension/H265Rtp.cpp b/src/Extension/H265Rtp.cpp index c3079313..9e780522 100644 --- a/src/Extension/H265Rtp.cpp +++ b/src/Extension/H265Rtp.cpp @@ -269,19 +269,15 @@ void H265RtpEncoder::inputFrame(const Frame::Ptr &frame) { //H265 数据 memcpy(payload + 3, ptr + offset, max_size); //输入到rtp环形缓存 - RtpCodec::inputRtp(rtp, fu_start && H265Frame::isKeyFrame(nal_type, frame->data() + frame->prefixSize())); + RtpCodec::inputRtp(rtp, fu_start && frame->keyFrame()); } offset += max_size; fu_start = false; } } else { - makeH265Rtp(nal_type, ptr, len, false, true, pts); + RtpCodec::inputRtp(makeRtp(getTrackType(), ptr, len, false, pts), frame->keyFrame()); } } -void H265RtpEncoder::makeH265Rtp(int nal_type,const void* data, size_t len, bool mark, bool first_packet, uint32_t uiStamp) { - RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp),first_packet && H265Frame::isKeyFrame(nal_type, (const char*)data + prefixSize((const char*)data, len))); -} - }//namespace mediakit diff --git a/src/Extension/H265Rtp.h b/src/Extension/H265Rtp.h index 4bbacea0..1af07623 100644 --- a/src/Extension/H265Rtp.h +++ b/src/Extension/H265Rtp.h @@ -84,8 +84,6 @@ public: * @param frame 帧数据,必须 */ void inputFrame(const Frame::Ptr &frame) override; -private: - void makeH265Rtp(int nal_type,const void *pData, size_t uiLen, bool bMark, bool first_packet,uint32_t uiStamp); }; }//namespace mediakit{