一份FFmpeg异步解码的代码
时间: 2023-04-08 13:04:16 浏览: 84
我可以回答这个问题。以下是一份FFmpeg异步解码的代码示例:
```
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
#include <atomic>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
using namespace std;
// 定义一个解码帧的结构体
struct DecodedFrame {
AVFrame* frame;
int streamIndex;
};
// 定义一个解码器的结构体
struct Decoder {
AVCodecContext* codecCtx;
AVPacket* packet;
queue<DecodedFrame*> decodedFrames;
mutex mtx;
condition_variable cv;
atomic<bool> stop;
};
// 解码器线程函数
void decodeThread(Decoder* decoder) {
AVCodecContext* codecCtx = decoder->codecCtx;
AVPacket* packet = decoder->packet;
queue<DecodedFrame*>& decodedFrames = decoder->decodedFrames;
mutex& mtx = decoder->mtx;
condition_variable& cv = decoder->cv;
atomic<bool>& stop = decoder->stop;
AVFrame* frame = av_frame_alloc();
if (!frame) {
cerr << "Failed to allocate frame" << endl;
return;
}
while (!stop) {
int ret = avcodec_send_packet(codecCtx, packet);
if (ret < 0) {
cerr << "Error sending packet to decoder: " << av_err2str(ret) << endl;
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codecCtx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
cerr << "Error receiving frame from decoder: " << av_err2str(ret) << endl;
break;
}
DecodedFrame* decodedFrame = new DecodedFrame{frame, codecCtx->stream_index};
unique_lock<mutex> lock(mtx);
decodedFrames.push(decodedFrame);
lock.unlock();
cv.notify_one();
}
}
av_frame_free(&frame);
}
// 主函数
int main(int argc, char* argv[]) {
if (argc < 2) {
cerr << "Usage: " << argv[0] << " <input file>" << endl;
return 1;
}
av_register_all();
AVFormatContext* formatCtx = nullptr;
int ret = avformat_open_input(&formatCtx, argv[1], nullptr, nullptr);
if (ret < 0) {
cerr << "Error opening input file: " << av_err2str(ret) << endl;
return 1;
}
ret = avformat_find_stream_info(formatCtx, nullptr);
if (ret < 0) {
cerr << "Error finding stream info: " << av_err2str(ret) << endl;
avformat_close_input(&formatCtx);
return 1;
}
AVCodec* codec = nullptr;
int streamIndex = av_find_best_stream(formatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (streamIndex < 0) {
cerr << "Error finding video stream: " << av_err2str(streamIndex) << endl;
avformat_close_input(&formatCtx);
return 1;
}
AVCodecContext* codecCtx = avcodec_alloc_context3(codec);
if (!codecCtx) {
cerr << "Failed to allocate codec context" << endl;
avformat_close_input(&formatCtx);
return 1;
}
ret = avcodec_parameters_to_context(codecCtx, formatCtx->streams[streamIndex]->codecpar);
if (ret < 0) {
cerr << "Error setting codec parameters: " << av_err2str(ret) << endl;
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
ret = avcodec_open2(codecCtx, codec, nullptr);
if (ret < 0) {
cerr << "Error opening codec: " << av_err2str(ret) << endl;
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
AVPacket* packet = av_packet_alloc();
if (!packet) {
cerr << "Failed to allocate packet" << endl;
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
Decoder decoder{codecCtx, packet, queue<DecodedFrame*>(), mutex(), condition_variable(), atomic<bool>(false)};
thread decoderThread(decodeThread, &decoder);
AVFrame* frame = av_frame_alloc();
if (!frame) {
cerr << "Failed to allocate frame" << endl;
av_packet_free(&packet);
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
SwsContext* swsCtx = sws_getContext(codecCtx->width, codecCtx->height, codecCtx->pix_fmt,
codecCtx->width, codecCtx->height, AV_PIX_FMT_RGB24,
SWS_BILINEAR, nullptr, nullptr, nullptr);
if (!swsCtx) {
cerr << "Failed to allocate SwsContext" << endl;
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
AVFrame* rgbFrame = av_frame_alloc();
if (!rgbFrame) {
cerr << "Failed to allocate RGB frame" << endl;
sws_freeContext(swsCtx);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 1;
}
int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height, 1);
uint8_t* buffer = (uint8_t*)av_malloc(numBytes * sizeof(uint8_t));
av_image_fill_arrays(rgbFrame->data, rgbFrame->linesize, buffer, AV_PIX_FMT_RGB24, codecCtx->width, codecCtx->height, 1);
while (av_read_frame(formatCtx, packet) >= 0) {
if (packet->stream_index != streamIndex) {
av_packet_unref(packet);
continue;
}
unique_lock<mutex> lock(decoder.mtx);
while (decoder.decodedFrames.empty()) {
decoder.cv.wait(lock);
}
DecodedFrame* decodedFrame = decoder.decodedFrames.front();
decoder.decodedFrames.pop();
lock.unlock();
if (decodedFrame->streamIndex != streamIndex) {
av_frame_unref(decodedFrame->frame);
delete decodedFrame;
continue;
}
sws_scale(swsCtx, decodedFrame->frame->data, decodedFrame->frame->linesize, 0, codecCtx->height, rgbFrame->data, rgbFrame->linesize);
// 在这里处理解码后的帧
// ...
av_frame_unref(decodedFrame->frame);
delete decodedFrame;
}
decoder.stop = true;
decoder.cv.notify_one();
decoderThread.join();
av_free(buffer);
av_frame_free(&rgbFrame);
sws_freeContext(swsCtx);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codecCtx);
avformat_close_input(&formatCtx);
return 0;
}
```