FFmpeg录屏首2秒异常帧问题:如何清理AVFormatContext缓存包?
FFmpeg录制视频前2秒异常帧问题解决
我使用FFmpeg编写视频录制类时遇到异常:录制生成的视频前1秒为黑屏帧,第2秒为单帧重复25次,后续播放正常。若录制10秒视频,最终文件时长变为12秒,多出来的2秒就是前面的异常部分。
相关代码
头文件与全局变量
#include <iostream> #include <sstream> #include <string> #include <iomanip> #include <thread> extern "C" { #include <libavformat/avformat.h> }
bool recording; const std::string recordFileName = "video.avi"; std::string camera_address; std::thread recordingThread; AVFormatContext* inputFormatContext; AVOutputFormat* outputFormat; AVFormatContext* outputFormatContext; AVStream* outputVideoStream;
启动录制函数
bool VideoRecorder::start_record() { if (!recording) { AVDictionary* options = nullptr; av_dict_set(&options, "rtsp_transport", "udp", 0); if (avformat_open_input(&inputFormatContext, camera_address.c_str(), nullptr, &options) != 0) { std::cerr << "Error opening input stream." << std::endl; return false; } if (avformat_find_stream_info(inputFormatContext, nullptr) < 0) { std::cerr << "Error finding stream information." << std::endl; avformat_close_input(&inputFormatContext); return false; } // Open output file AVI if (avformat_alloc_output_context2(&outputFormatContext, outputFormat, "avi", recordFileName.c_str()) < 0) { std::cerr << "Error allocating output context." << std::endl; avformat_close_input(&inputFormatContext); return false; } // Add a new video stream to the output file outputVideoStream = avformat_new_stream(outputFormatContext, nullptr); if (!outputVideoStream) { std::cerr << "Error creating output video stream." << std::endl; avformat_close_input(&inputFormatContext); avformat_free_context(outputFormatContext); return false; } if (avcodec_parameters_copy(outputVideoStream->codecpar, inputFormatContext->streams[0]->codecpar) < 0) { std::cerr << "Error copying codec parameters." << std::endl; avformat_close_input(&inputFormatContext); avformat_free_context(outputFormatContext); return false; } // Open the output file for writing if (avio_open(&outputFormatContext->pb, recordFileName.c_str(), AVIO_FLAG_WRITE) < 0) { std::cerr << "Error opening output file for writing." << std::endl; avformat_close_input(&inputFormatContext); avformat_free_context(outputFormatContext); return false; } // Write output file header if (avformat_write_header(outputFormatContext, nullptr) < 0) { std::cerr << "Error writing output file header." << std::endl; avformat_close_input(&inputFormatContext); avformat_free_context(outputFormatContext); return false; } recording = true; recordingThread = std::thread(&VideoRecorder::record_video, this); std::cout << "Recording started." << std::endl; return true; } return false; }
帧录制函数
bool VideoRecorder::record_video() { if (recording) { AVPacket packet; while (recording && av_read_frame(inputFormatContext, &packet) >= 0) { AVStream* in_stream = inputFormatContext->streams[packet.stream_index]; AVStream* out_stream = outputFormatContext->streams[0]; // Adjustment of DTS and PTS to ensure increasing monoticity if (packet.pts != AV_NOPTS_VALUE) { packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); } if (packet.dts != AV_NOPTS_VALUE) { packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); } packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base); packet.stream_index = 0; av_interleaved_write_frame(outputFormatContext, &packet); av_packet_unref(&packet); } return true; } std::cerr << "Error recording video. Recording not started or already stopped." << std::endl; return false; }
异常原因
已确认额外的2秒异常帧来自avformat_open_input(&inputFormatContext, camera_address.c_str(), nullptr, &options)和avformat_find_stream_info(inputFormatContext, nullptr)的执行过程,这两个函数耗时约2-3秒,期间产生的数据包被缓存到了inputFormatContext中,后续录制时被写入了输出文件。
已尝试的解决方案(均无效)
- 调用
avformat_flush(inputFormatContext);清理缓存 - 循环读取并丢弃缓存包:
while (av_read_frame(inputFormatContext, &packet) >= 0) { av_packet_unref(&packet); } - 将前2秒内容写入临时文件,不写入最终输出
- 调用FFmpeg命令裁剪前2秒(终端执行有效,但代码中调用无效),裁剪代码如下:
void VideoRecorder::cut_video() { std::string outputFileName = "cut_" + recordFileName; std::string command = "ffmpeg -ss 2 -i " + recordFileName + " -c copy " + outputFileName; int result = std::system(command.c_str()); if (result == 0) { std::cout << "Video cut successfully." << std::endl; std::remove(recordFileName.c_str()); std::cout << "Original video file deleted." << std::endl; } else { std::cerr << "Error cutting video." << std::endl; } }
- 校验packet的dts和pts值,丢弃异常数据包
需求
需要一种能有效移除视频前2秒异常帧的方案,同时希望了解如何正确清理AVFormatContext中的缓存数据包。
内容的提问来源于stack exchange,提问作者Jorge Augusto Wilchen
相关产品推荐
相关产品推荐

