ffmpeg C API - 创建帧队列

ffmpeg C API - creating queue of frames

本文关键字:队列 创建 API ffmpeg      更新时间:2023-10-16

我使用 ffmpeg 的 C API 创建了一个 C++ 应用程序,该应用程序从文件中读取帧并将其写入新文件。一切正常,只要我立即将帧写入输出即可。换句话说,程序的以下结构输出正确的结果(我现在只放置伪代码,如果需要,我也可以发布一些真实的片段,但我为处理 ffmpeg 功能而创建的类非常大):

AVFrame* frame = av_frame_alloc();
int got_frame;
// readFrame returns 0 if file is ended, got frame = 1 if
// a complete frame has been extracted
while(readFrame(inputfile,frame, &got_frame)) {
if (got_frame) {
// I actually do some processing here
writeFrame(outputfile,frame);
}
}
av_frame_free(&frame);

下一步是并行化应用程序,因此,帧在读取后不会立即写入(我不想详细介绍并行化)。在这种情况下会出现问题:输出中有一些闪烁,就好像某些帧随机重复一样。但是,输出视频的帧数和持续时间仍然正确。

我现在要做的是在串行实现中将读取与写入完全分开,以便了解正在发生的事情。我正在创建一个指向框架的指针队列:

std::queue<AVFrame*> queue;
int ret = 1, got_frame;
while (ret) {
AVFrame* frame = av_frame_alloc();
ret = readFrame(inputfile,frame,&got_frame);
if (got_frame) 
queue.push(frame);
}

要将帧写入输出文件,我这样做:

while (!queue.empty()) {
frame = queue.front();
queue.pop();
writeFrame(outputFile,frame);
av_frame_free(&frame);
}

在这种情况下,结果是具有正确持续时间和帧数的输出视频,该视频仅重复视频的最后 3 帧(我认为)。

我的猜测是可能会出现问题,因为在第一种情况下,我总是使用相同的内存位置来读取帧,而在第二种情况下,我分配了许多不同的帧。

关于可能是什么问题的任何建议?

啊,所以我假设readFrame()是libavformat的av_read_frame()和libavcodec的avcodec_decode_video2()的包装器,对吗?

从文档中:

AVCodecContext.refcounted_frames设置为 1 时,帧为 引用计数,返回的引用属于调用方。 调用方必须在以下情况下使用av_frame_unref()释放帧 不再需要框架。

和:

什么时候AVCodecContext.refcounted_frames设置为 0,返回的引用 属于解码器,仅在下次调用此 函数或直到关闭或刷新解码器。

显然,由此可以得出您需要将AVCodecContext.refcounted_frames设置为 1。默认值为 0,所以我的直觉是您需要将其设置为 1,这将解决您的问题。使用后不要忘记在图片上使用av_fame_unref()以防止内存泄漏,如果got_frame = 0,也不要忘记在此循环中释放AVFrame- 再次防止内存泄漏:

while (ret) {
AVFrame* frame = av_frame_alloc();
ret = readFrame(inputfile,frame,&got_frame);
if (got_frame) 
queue.push(frame);
else
av_frame_free(frame);
}

(或者,您也可以为frame实现一些缓存,以便仅在前一个对象被推送到队列中时才重新分配它。

你的伪代码没有明显的问题。 问题几乎肯定在于如何在线程之间锁定队列。

你的内存分配对我来说似乎是一样的。在阅读和写入帧之间,您是否可能会做其他事情?

queue读取和写入帧的例程中是否为同一队列?