Commit fae86a9b by 夏楚 Committed by Gitee

!11 合帧逻辑 加强判断,防止 SPS PPS VPS 作为一帧,rtmp h264/h265 打包 保证帧内必须有VCL

Merge pull request !11 from xiongguangjie/dev
parents 3f36a10b c0f362af
...@@ -267,11 +267,44 @@ bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{ ...@@ -267,11 +267,44 @@ bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{
} }
return false; return false;
} }
bool FrameMerger::frameCacheHasVCL(List<Frame::Ptr> &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) { void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) {
if(shouldDrop(frame)){ if(shouldDrop(frame)){
return; return;
} }
if (willFlush(frame)) { if (willFlush(frame) && frameCacheHasVCL(_frameCached)) {
Frame::Ptr back = _frameCached.back(); Frame::Ptr back = _frameCached.back();
Buffer::Ptr merged_frame = back; Buffer::Ptr merged_frame = back;
bool have_idr = back->keyFrame(); bool have_idr = back->keyFrame();
......
...@@ -476,6 +476,7 @@ private: ...@@ -476,6 +476,7 @@ private:
bool willFlush(const Frame::Ptr &frame) const; bool willFlush(const Frame::Ptr &frame) const;
void doMerge(BufferLikeString &buffer, const Frame::Ptr &frame) const; void doMerge(BufferLikeString &buffer, const Frame::Ptr &frame) const;
bool shouldDrop(const Frame::Ptr &frame) const; bool shouldDrop(const Frame::Ptr &frame) const;
bool frameCacheHasVCL(List<Frame::Ptr> &frameCached) const;
private: private:
int _type; int _type;
......
...@@ -159,7 +159,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { ...@@ -159,7 +159,7 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
auto pcData = frame->data() + frame->prefixSize(); auto pcData = frame->data() + frame->prefixSize();
auto iLen = frame->size() - frame->prefixSize(); auto iLen = frame->size() - frame->prefixSize();
auto type = H264_TYPE(((uint8_t*)pcData)[0]); auto type = H264_TYPE(((uint8_t*)pcData)[0]);
if(type == H264Frame::NAL_SEI){ if(type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD){
return; return;
} }
...@@ -182,10 +182,20 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) { ...@@ -182,10 +182,20 @@ void H264RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
break; break;
} }
} }
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))) { if(_lastPacket && (_lastPacket->time_stamp != frame->dts() || ((pcData[1]&0x80) != 0 && type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR && _lastPacketHasVCL))) {
RtmpCodec::inputRtmp(_lastPacket); RtmpCodec::inputRtmp(_lastPacket);
_lastPacket = nullptr; _lastPacket = nullptr;
_lastPacketHasVCL = false;
}
if(type>=H264Frame::NAL_B_P && type<=H264Frame::NAL_IDR){
_lastPacketHasVCL = true;
} }
if(!_lastPacket) { if(!_lastPacket) {
......
...@@ -80,6 +80,7 @@ private: ...@@ -80,6 +80,7 @@ private:
private: private:
H264Track::Ptr _track; H264Track::Ptr _track;
bool _gotSpsPps = false; bool _gotSpsPps = false;
bool _lastPacketHasVCL = false;
RtmpPacket::Ptr _lastPacket; RtmpPacket::Ptr _lastPacket;
}; };
......
...@@ -169,9 +169,21 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { ...@@ -169,9 +169,21 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
return;// 防止sei aud 作为一帧 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); RtmpCodec::inputRtmp(_lastPacket);
_lastPacket = nullptr; _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) { if(!_lastPacket) {
...@@ -179,7 +191,9 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) { ...@@ -179,7 +191,9 @@ void H265RtmpEncoder::inputFrame(const Frame::Ptr &frame) {
int8_t flags = FLV_CODEC_H265; int8_t flags = FLV_CODEC_H265;
bool is_config = false; bool is_config = false;
flags |= (((frame->configFrame() || frame->keyFrame()) ? FLV_KEY_FRAME : FLV_INTER_FRAME) << 4); 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 = RtmpPacket::create();
_lastPacket->buffer.push_back(flags); _lastPacket->buffer.push_back(flags);
_lastPacket->buffer.push_back(!is_config); _lastPacket->buffer.push_back(!is_config);
......
...@@ -84,6 +84,7 @@ private: ...@@ -84,6 +84,7 @@ private:
string _pps; string _pps;
H265Track::Ptr _track; H265Track::Ptr _track;
RtmpPacket::Ptr _lastPacket; RtmpPacket::Ptr _lastPacket;
bool _lastPacketHasVCL = false;
}; };
}//namespace mediakit }//namespace mediakit
......
...@@ -68,7 +68,13 @@ foreach(TEST_SRC ${TEST_SRC_LIST}) ...@@ -68,7 +68,13 @@ foreach(TEST_SRC ${TEST_SRC_LIST})
if(WIN32) if(WIN32)
set_target_properties(${TEST_EXE_NAME} PROPERTIES COMPILE_FLAGS ${VS_FALGS} ) set_target_properties(${TEST_EXE_NAME} PROPERTIES COMPILE_FLAGS ${VS_FALGS} )
endif(WIN32) 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() endforeach()
if(MSVC AND SDL2_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND) if(MSVC AND SDL2_FOUND AND AVCODEC_FOUND AND AVUTIL_FOUND)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论