FFmpeg使用fps滤镜时内存暴涨崩溃但scale滤镜正常如何排查
问题原因与修复方案
scale滤镜为逐帧处理的同步滤镜,输入1帧立刻输出1帧,内部不会留存多余帧;但fps滤镜属于帧率转换滤镜,需要缓存多帧完成插帧或帧丢弃逻辑,尤其是当设置的目标帧率高于源视频帧率时,滤镜会持续缓存帧用于生成中间插帧,你现有代码的帧拉取逻辑存在缺陷,导致滤镜内部缓存的帧无法被及时取出,内存占用持续升高最终崩溃。
具体代码缺陷
- 帧拉取逻辑不合理:
applyFilter函数每次仅拉取1帧就返回,若fps滤镜输入1帧生成多帧,剩余输出帧会滞留在滤镜缓冲区中;当返回EAGAIN(暂无输出帧)时,你直接跳过编码逻辑,滞留在缓冲区的帧永远不会被取出,积累量越来越大。 - 帧引用处理逻辑有问题:无论
applyFilter返回值是否有效,你都直接替换frame指针,若返回EAGAIN时filterFrame为空,会导致后续编码逻辑拿到空指针,同时原输入帧的引用管理也存在冗余问题。 - 注意你贴出的代码存在低级语法错误:
char filterDesc = "fps=fps=30000/1000"应为char *filterDesc,字符变量无法存储字符串指针。
修复方案
调整滤镜的调用逻辑,送帧后循环拉取所有可输出的滤镜帧,全部完成编码后再处理下一输入帧,同时添加末尾冲刷逻辑取出滤镜残留的所有帧。
修正后代码示例
char *filterDesc = "fps=fps=30000/1000"; filter = initFilter(filterDesc, params); for (EVER) { getFrame(decoder, frame, packet); if (decoder->container->streams[packet->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { if (filter != NULL) { // 输入帧送入滤镜 int ret = av_buffersrc_add_frame_flags(filter->buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); if (ret < 0) { printf("Error while sending frame to filter\n"); return -1; } // 循环拉取所有可用输出帧 while (1) { ret = av_buffersink_get_frame(filter->buffersink_ctx, filterFrame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } if (ret < 0) { printf("Error while getting filtered frame\n"); return -1; } // 拿到有效帧直接编码 encode(decoder, encoder, filterFrame, packet->stream_index); av_frame_unref(filterFrame); } av_frame_unref(frame); // 跳过后续通用编码逻辑,避免重复编码 continue; } } // 非视频流或未启用滤镜的场景直接编码 encode(decoder, encoder, frame, packet->stream_index); av_frame_unref(frame); } // 所有输入帧处理完成后,冲刷滤镜缓冲区取出剩余帧 if (filter != NULL) { av_buffersrc_add_frame_flags(filter->buffersrc_ctx, NULL, 0); while (av_buffersink_get_frame(filter->buffersink_ctx, filterFrame) >= 0) { encode(decoder, encoder, filterFrame, packet->stream_index); av_frame_unref(filterFrame); } }
内容的提问来源于stack exchange,提问作者Gabriel Ayala
相关产品推荐
相关产品推荐

