ffmpeg av_read_frame读取的数据放到队列中,另外一个线程从队列中获取数据并且解码
时间: 2024-02-06 11:12:52 浏览: 122
ffmpeg 指定时间解码 av_seek_frame
5星 · 资源好评率100%
你可以使用一个生产者-消费者模型,将FFmpeg读取到的数据放到一个队列中,然后让另一个线程从队列中获取数据并进行解码。下面是一个示例代码:
```c++
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "ffmpeg.h"
using namespace std;
// 队列元素结构体
struct QueueItem {
AVPacket* pkt;
int stream_idx;
};
// 生产者线程
void producer_thread(queue<QueueItem>& q, AVFormatContext* fmt_ctx, mutex& mtx, condition_variable& cv)
{
AVPacket pkt;
av_init_packet(&pkt);
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
// 将数据包放到队列中
QueueItem item = { av_packet_clone(&pkt), pkt.stream_index };
unique_lock<mutex> lock(mtx);
q.push(item);
lock.unlock();
cv.notify_one();
av_packet_unref(&pkt);
}
// 发送结束标志
QueueItem item = { nullptr, -1 };
unique_lock<mutex> lock(mtx);
q.push(item);
lock.unlock();
cv.notify_one();
}
// 消费者线程
void consumer_thread(queue<QueueItem>& q, AVCodecContext** codec_ctxs, AVFrame** frames, mutex& mtx, condition_variable& cv)
{
while (true) {
// 获取队列元素
unique_lock<mutex> lock(mtx);
cv.wait(lock, [&q] { return !q.empty(); });
QueueItem item = q.front();
q.pop();
lock.unlock();
if (!item.pkt) {
// 退出线程
break;
}
// 解码数据包
AVCodecContext* codec_ctx = codec_ctxs[item.stream_idx];
AVFrame* frame = frames[item.stream_idx];
int ret = avcodec_send_packet(codec_ctx, item.pkt);
if (ret < 0) {
cerr << "Error sending packet to decoder: " << av_err2str(ret) << endl;
continue;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
// 没有更多的输出帧
break;
} else if (ret < 0) {
cerr << "Error during decoding: " << av_err2str(ret) << endl;
break;
}
// 在此处添加帧处理操作
av_frame_unref(frame);
}
av_packet_unref(item.pkt);
av_packet_free(&item.pkt);
}
}
int main(int argc, char* argv[])
{
// 初始化FFmpeg
av_register_all();
avcodec_register_all();
// 打开输入文件
AVFormatContext* fmt_ctx = nullptr;
int ret = avformat_open_input(&fmt_ctx, argv[1], nullptr, nullptr);
if (ret < 0) {
cerr << "Error opening input file: " << av_err2str(ret) << endl;
return -1;
}
// 检索流信息
ret = avformat_find_stream_info(fmt_ctx, nullptr);
if (ret < 0) {
cerr << "Error finding stream information: " << av_err2str(ret) << endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 查找视频流
int video_stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
if (video_stream_idx < 0) {
cerr << "Error finding video stream: " << av_err2str(video_stream_idx) << endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 获取视频解码器
AVCodec* codec = avcodec_find_decoder(fmt_ctx->streams[video_stream_idx]->codecpar->codec_id);
if (!codec) {
cerr << "Error finding video codec" << endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 创建解码器上下文
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
cerr << "Error allocating codec context" << endl;
avformat_close_input(&fmt_ctx);
return -1;
}
// 初始化解码器上下文
ret = avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream_idx]->codecpar);
if (ret < 0) {
cerr << "Error initializing codec context: " << av_err2str(ret) << endl;
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
return -1;
}
// 打开解码器
ret = avcodec_open2(codec_ctx, codec, nullptr);
if (ret < 0) {
cerr << "Error opening codec: " << av_err2str(ret) << endl;
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
return -1;
}
// 创建解码器上下文数组
AVCodecContext** codec_ctxs = new AVCodecContext*[fmt_ctx->nb_streams];
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
codec_ctxs[i] = nullptr;
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
codec = avcodec_find_decoder(fmt_ctx->streams[i]->codecpar->codec_id);
if (!codec) {
cerr << "Error finding codec" << endl;
continue;
}
codec_ctxs[i] = avcodec_alloc_context3(codec);
if (!codec_ctxs[i]) {
cerr << "Error allocating codec context" << endl;
continue;
}
ret = avcodec_parameters_to_context(codec_ctxs[i], fmt_ctx->streams[i]->codecpar);
if (ret < 0) {
cerr << "Error initializing codec context: " << av_err2str(ret) << endl;
avcodec_free_context(&codec_ctxs[i]);
continue;
}
ret = avcodec_open2(codec_ctxs[i], codec, nullptr);
if (ret < 0) {
cerr << "Error opening codec: " << av_err2str(ret) << endl;
avcodec_free_context(&codec_ctxs[i]);
continue;
}
}
}
// 创建帧数组
AVFrame** frames =
阅读全文