Commit c393cc7c by xiongziliang

修复GB28181粘帧导致花屏的问题: #964,#954

parent 756b6a4c
...@@ -180,6 +180,7 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ ...@@ -180,6 +180,7 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{
} }
default: break; default: break;
} }
//遇到新帧、或时间戳变化或缓存太多,防止内存溢出,则flush输出
return new_frame || _frameCached.back()->dts() != frame->dts() || _frameCached.size() > kMaxFrameCacheSize; return new_frame || _frameCached.back()->dts() != frame->dts() || _frameCached.size() > kMaxFrameCacheSize;
} }
...@@ -192,31 +193,21 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ ...@@ -192,31 +193,21 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{
switch (frame->getCodecId()) { switch (frame->getCodecId()) {
case CodecH264 : { case CodecH264 : {
auto type = H264_TYPE(frame->data()[frame->prefixSize()]); auto type = H264_TYPE(frame->data()[frame->prefixSize()]);
if ((frame->data()[frame->prefixSize() + 1] & 0x80) != 0 && type >= H264Frame::NAL_B_P && // sei aud pps sps 不判断;264 新一帧的开始,刷新输出
type <= H264Frame::NAL_IDR) {// sei aud pps sps 不判断 return (frame->data()[frame->prefixSize() + 1] & 0x80) != 0 && type >= H264Frame::NAL_B_P &&
//264 新一帧的开始,刷新输出 type <= H264Frame::NAL_IDR;
return true;
} else {
// 不刷新输出
return false;
}
break;
} }
case CodecH265 : { case CodecH265 : {
auto type = H265_TYPE(frame->data()[frame->prefixSize()]); auto type = H265_TYPE(frame->data()[frame->prefixSize()]);
if ((type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) &&
((frame->data()[frame->prefixSize() + 2] >> 7 & 0x01) != 0)) {
//first_slice_segment_in_pic_flag is frame start //first_slice_segment_in_pic_flag is frame start
return true; return (type >= H265Frame::NAL_TRAIL_R && type <= H265Frame::NAL_RSV_IRAP_VCL23) &&
} else { ((frame->data()[frame->prefixSize() + 2] >> 7 & 0x01) != 0);
return false;
}
break;
}
default : break;
} }
default :
//缓存太多,防止内存溢出
return _frameCached.size() > kMaxFrameCacheSize; return _frameCached.size() > kMaxFrameCacheSize;
} }
}
default: /*不可达*/ assert(0); return true; default: /*不可达*/ assert(0); return true;
} }
} }
...@@ -224,10 +215,16 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{ ...@@ -224,10 +215,16 @@ bool FrameMerger::willFlush(const Frame::Ptr &frame) const{
void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) const{ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) const{
switch (_type) { switch (_type) {
case none : { case none : {
//此处是合并ps解析输出的流,解析出的流可能是半帧或多帧,不能简单的根据nal type过滤
//此流程只用于合并ps解析输出为H264/H265,后面流程有split和忽略无效帧操作
merged.append(frame->data(), frame->size()); merged.append(frame->data(), frame->size());
break; break;
} }
case h264_prefix: { case h264_prefix: {
if (shouldDrop(frame)) {
//h264头模式过滤无效的帧
break;
}
if (frame->prefixSize()) { if (frame->prefixSize()) {
merged.append(frame->data(), frame->size()); merged.append(frame->data(), frame->size());
} else { } else {
...@@ -237,6 +234,10 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con ...@@ -237,6 +234,10 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con
break; break;
} }
case mp4_nal_size: { case mp4_nal_size: {
if (shouldDrop(frame)) {
//MP4头模式过滤无效的帧
break;
}
uint32_t nalu_size = (uint32_t) (frame->size() - frame->prefixSize()); uint32_t nalu_size = (uint32_t) (frame->size() - frame->prefixSize());
nalu_size = htonl(nalu_size); nalu_size = htonl(nalu_size);
merged.append((char *) &nalu_size, 4); merged.append((char *) &nalu_size, 4);
...@@ -250,26 +251,26 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con ...@@ -250,26 +251,26 @@ void FrameMerger::doMerge(BufferLikeString &merged, const Frame::Ptr &frame) con
bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{ bool FrameMerger::shouldDrop(const Frame::Ptr &frame) const{
switch (frame->getCodecId()) { switch (frame->getCodecId()) {
case CodecH264: { case CodecH264: {
auto type = H264_TYPE(frame->data()[frame->prefixSize()]); switch (H264_TYPE(frame->data()[frame->prefixSize()])) {
if (type == H264Frame::NAL_SEI || type == H264Frame::NAL_AUD) { // 防止把AUD或者SEI当成一帧
// 防止吧AUD或者SEI当成一帧 case H264Frame::NAL_SEI:
return true; case H264Frame::NAL_AUD: return true;
default: return false;
} }
break;
} }
case CodecH265: { case CodecH265: {
//如果是新的一帧,前面的缓存需要输出 switch (H265_TYPE(frame->data()[frame->prefixSize()])) {
auto type = H265_TYPE(frame->data()[frame->prefixSize()]); // 防止把AUD或者SEI当成一帧
if (type == H265Frame::NAL_AUD || type == H265Frame::NAL_SEI_PREFIX || type == H265Frame::NAL_SEI_SUFFIX) { case H265Frame::NAL_AUD:
// 防止吧AUD或者SEI当成一帧 case H265Frame::NAL_SEI_SUFFIX:
return true; case H265Frame::NAL_SEI_PREFIX: return true;
default: return false;
} }
break;
} }
default:
break; default: return false;
} }
return false;
} }
bool FrameMerger::frameCacheHasVCL(List<Frame::Ptr> &frameCached) const { bool FrameMerger::frameCacheHasVCL(List<Frame::Ptr> &frameCached) const {
...@@ -307,9 +308,6 @@ bool FrameMerger::frameCacheHasVCL(List<Frame::Ptr> &frameCached) const { ...@@ -307,9 +308,6 @@ bool FrameMerger::frameCacheHasVCL(List<Frame::Ptr> &frameCached) const {
} }
void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) {
if (shouldDrop(frame)) {
return;
}
if (willFlush(frame) && frameCacheHasVCL(_frameCached)) { 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;
...@@ -325,6 +323,10 @@ void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) { ...@@ -325,6 +323,10 @@ void FrameMerger::inputFrame(const Frame::Ptr &frame, const onOutput &cb) {
have_idr = true; have_idr = true;
} }
}); });
if (merged.empty()) {
_frameCached.clear();
return;
}
merged_frame = std::make_shared<BufferOffset<BufferLikeString> >(std::move(merged)); merged_frame = std::make_shared<BufferOffset<BufferLikeString> >(std::move(merged));
} }
cb(back->dts(), back->pts(), merged_frame, have_idr); cb(back->dts(), back->pts(), merged_frame, have_idr);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论