diff --git a/src/Extension/Frame.cpp b/src/Extension/Frame.cpp index 62753f59..62965553 100644 --- a/src/Extension/Frame.cpp +++ b/src/Extension/Frame.cpp @@ -267,11 +267,44 @@ bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{ } return false; } +bool FrameMerger::frameCacheHasVCL(List &frameCached) const{ + bool hasVCL = false; + bool isH264OrH265 = false; + frameCached.for_each([&hasVCL,&isH264OrH265](const Frame::Ptr &frame){ + switch (frame->getCodecId()) { + case CodecH264:{ + auto type = H264_TYPE(frame->data()[frame->prefixSize()]); + if(type >=H264Frame::NAL_B_P && type <= H264Frame::NAL_IDR){ + //有编码数据 + hasVCL=true; + } + isH264OrH265 = true; + break; + } + case CodecH265: { + //如果是新的一帧,前面的缓存需要输出 + auto type = H265_TYPE(frame->data()[frame->prefixSize()]); + if(type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23){ + //有编码数据 + hasVCL=true; + } + isH264OrH265 = true; + break; + } + default: break; + } + }); + if(isH264OrH265){ + return hasVCL; + } + return true; + +} void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { if(shouldDrop(frame)){ return; } - if (willFlush(frame)) { + if (willFlush(frame) && frameCacheHasVCL(_frameCached)) { Frame::Ptr back = _frameCached.back(); Buffer::Ptr merged_frame = back; bool have_idr = back->keyFrame(); diff --git a/src/Extension/Frame.h b/src/Extension/Frame.h index 95a5ec6d..973b6359 100644 --- a/src/Extension/Frame.h +++ b/src/Extension/Frame.h @@ -476,6 +476,7 @@ 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(List &frameCached) const; private: int _type; diff --git a/src/Extension/H264Rtmp.cpp b/src/Extension/H264Rtmp.cpp index b3426fe8..f3c7734c 100644 --- a/src/Extension/H264Rtmp.cpp +++ b/src/Extension/H264Rtmp.cpp @@ -159,7 +159,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { auto pcData = frame->data() + frame->prefixSize(); auto iLen = frame->size() - frame->prefixSize(); auto type = H264_TYPE(((uint8_t*)pcData)[0]); - if(type == H264Frame::NAL_SEI){ + if(type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD){ return; } @@ -182,10 +182,20 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { break; } } - - if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || ((pcData[1]&0x80) != 0 && type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR))) { + if(frame->configFrame() && _lastPacket &&_lastPacketHasVCL){ + //sps pps flush frame RtmpCodec::inputRtmp(_lastPacket); _lastPacket = nullptr; + _lastPacketHasVCL = false; + } + + if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || ((pcData[1]&0x80) != 0 && type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR && _lastPacketHasVCL))) { + RtmpCodec::inputRtmp(_lastPacket); + _lastPacket = nullptr; + _lastPacketHasVCL = false; + } + if(type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR){ + _lastPacketHasVCL = true; } if(!_lastPacket) { diff --git a/src/Extension/H264Rtmp.h b/src/Extension/H264Rtmp.h index a7c243ca..c45da3a6 100644 --- a/src/Extension/H264Rtmp.h +++ b/src/Extension/H264Rtmp.h @@ -80,6 +80,7 @@ private: private: H264Track::Ptr _track; bool _gotSpsPps = false; + bool _lastPacketHasVCL = false; RtmpPacket::Ptr _lastPacket; }; diff --git a/src/Extension/H265Rtmp.cpp b/src/Extension/H265Rtmp.cpp index 84dddad6..e5f2a8ec 100644 --- a/src/Extension/H265Rtmp.cpp +++ b/src/Extension/H265Rtmp.cpp @@ -169,9 +169,21 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { return;// 防止sei aud 作为一帧 } - if (_lastPacket && (_lastPacket->time_stamp != frame->dts() || (type >=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR && (pcData[2]>>7 &0x01) !=0))) { + if(frame->configFrame() && _lastPacket &&_lastPacketHasVCL){ + // sps pps flush frame RtmpCodec::inputRtmp(_lastPacket); _lastPacket = nullptr; + _lastPacketHasVCL = false; + } + + if (_lastPacket && (_lastPacket->time_stamp != frame->dts() || (_lastPacketHasVCL &&type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23 && (pcData[2]>>7 &0x01) !=0))) { + RtmpCodec::inputRtmp(_lastPacket); + _lastPacket = nullptr; + _lastPacketHasVCL = false; + } + + if(type>=H265Frame::NAL_TRAIL_R &&type<= H265Frame::NAL_RSV_IRAP_VCL23){ + _lastPacketHasVCL = true; } if(!_lastPacket) { @@ -179,7 +191,9 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { int8_t flags = FLV_CODEC_H265; bool is_config = false; flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); - + // to do + // 必须是IDR帧才能是关键帧,否则有可能开始帧会花屏 SPS PPS VPS 打头的是一般I帧,但不一定是IDR帧 + // RtmpCodec::inputRtmp 时需要判断 是否是IDR帧,做出相应的修改 _lastPacket = RtmpPacket::create(); _lastPacket->buffer.push_back(flags); _lastPacket->buffer.push_back(!is_config); diff --git a/src/Extension/H265Rtmp.h b/src/Extension/H265Rtmp.h index e4f97a08..6ba0f8a1 100644 --- a/src/Extension/H265Rtmp.h +++ b/src/Extension/H265Rtmp.h @@ -84,6 +84,7 @@ private: string _pps; H265Track::Ptr _track; RtmpPacket::Ptr _lastPacket; + bool _lastPacketHasVCL = false; }; }//namespace mediakit diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8219b816..c01fd5d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -68,7 +68,13 @@ foreach(TEST_SRC ${TEST_SRC_LIST}) if(WIN32) set_target_properties(${TEST_EXE_NAME} PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) endif(WIN32) - target_link_libraries(${TEST_EXE_NAME} ${LINK_LIB_LIST}) + if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_link_libraries(${TEST_EXE_NAME} -Wl,--start-group ${LINK_LIB_LIST} -Wl,--end-group) + else () + target_link_libraries(${TEST_EXE_NAME} ${LINK_LIB_LIST}) + endif () + + #target_link_libraries(${TEST_EXE_NAME} ${LINK_LIB_LIST}) endforeach() if(MSVC AND SDL2_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND)