一份FFmpeg异步解码的代码
时间: 2023-04-08 16:04:16 浏览: 165
ffmpeg视频解码示例代码
我可以回答这个问题。以下是一份FFmpeg异步解码的代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#define MAX_VIDEO_FRAME_NUM 10
typedef struct {
AVFormatContext *fmt_ctx;
AVCodecContext *codec_ctx;
AVCodec *codec;
AVFrame *frame;
AVPacket *pkt;
int video_stream_index;
int frame_count;
int video_frame_num;
int video_frame_index;
pthread_mutex_t mutex;
pthread_cond_t cond;
} VideoState;
void *video_decode_thread(void *arg) {
VideoState *vs = (VideoState *)arg;
AVFormatContext *fmt_ctx = vs->fmt_ctx;
AVCodecContext *codec_ctx = vs->codec_ctx;
AVCodec *codec = vs->codec;
AVFrame *frame = vs->frame;
AVPacket *pkt = vs->pkt;
int video_stream_index = vs->video_stream_index;
int frame_count = vs->frame_count;
int video_frame_num = vs->video_frame_num;
int video_frame_index = vs->video_frame_index;
pthread_mutex_t *mutex = &vs->mutex;
pthread_cond_t *cond = &vs->cond;
while (av_read_frame(fmt_ctx, pkt) >= 0) {
if (pkt->stream_index == video_stream_index) {
int ret = avcodec_send_packet(codec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
break;
}
pthread_mutex_lock(mutex);
while (video_frame_index >= video_frame_num) {
pthread_cond_wait(cond, mutex);
}
AVFrame *dst_frame = av_frame_alloc();
if (!dst_frame) {
fprintf(stderr, "Error allocating destination frame\n");
break;
}
int dst_width = codec_ctx->width;
int dst_height = codec_ctx->height;
enum AVPixelFormat dst_pix_fmt = AV_PIX_FMT_RGB24;
struct SwsContext *sws_ctx = sws_getContext(
codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
dst_width, dst_height, dst_pix_fmt, SWS_BILINEAR, NULL, NULL, NULL);
if (!sws_ctx) {
fprintf(stderr, "Error creating SwsContext\n");
break;
}
av_image_alloc(dst_frame->data, dst_frame->linesize, dst_width, dst_height, dst_pix_fmt, 1);
sws_scale(sws_ctx, frame->data, frame->linesize, 0, codec_ctx->height,
dst_frame->data, dst_frame->linesize);
vs->frame_count++;
vs->video_frame_index++;
pthread_mutex_unlock(mutex);
pthread_cond_signal(cond);
av_frame_free(&dst_frame);
sws_freeContext(sws_ctx);
}
}
av_packet_unref(pkt);
}
av_packet_free(&pkt);
av_frame_free(&frame);
avcodec_free_context(&codec_ctx);
avformat_close_input(&fmt_ctx);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <input file>\n", argv[0]);
return 1;
}
av_register_all();
avcodec_register_all();
AVFormatContext *fmt_ctx = NULL;
if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
fprintf(stderr, "Could not open input file '%s'\n", argv[1]);
return 1;
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "Could not find stream information\n");
return 1;
}
int video_stream_index = -1;
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}
if (video_stream_index == -1) {
fprintf(stderr, "Could not find video stream\n");
return 1;
}
AVCodecContext *codec_ctx = avcodec_alloc_context3(NULL);
if (!codec_ctx) {
fprintf(stderr, "Could not allocate codec context\n");
return 1;
}
if (avcodec_parameters_to_context(codec_ctx, fmt_ctx->streams[video_stream_index]->codecpar) < 0) {
fprintf(stderr, "Could not copy codec parameters to codec context\n");
return 1;
}
AVCodec *codec = avcodec_find_decoder(codec_ctx->codec_id);
if (!codec) {
fprintf(stderr, "Could not find codec\n");
return 1;
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
return 1;
}
AVFrame *frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
return 1;
}
AVPacket *pkt = av_packet_alloc();
if (!pkt) {
fprintf(stderr, "Could not allocate packet\n");
return 1;
}
int video_frame_num = MAX_VIDEO_FRAME_NUM;
int frame_count = 0;
int video_frame_index = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
VideoState vs = {
.fmt_ctx = fmt_ctx,
.codec_ctx = codec_ctx,
.codec = codec,
.frame = frame,
.pkt = pkt,
.video_stream_index = video_stream_index,
.frame_count = frame_count,
.video_frame_num = video_frame_num,
.video_frame_index = video_frame_index,
.mutex = mutex,
.cond = cond,
};
pthread_t tid;
pthread_create(&tid, NULL, video_decode_thread, &vs);
while (1) {
pthread_mutex_lock(&mutex);
while (video_frame_index >= video_frame_num) {
pthread_cond_wait(&cond, &mutex);
}
printf("Frame %d decoded\n", frame_count);
video_frame_index++;
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
pthread_join(tid, NULL);
return 0;
}
```
这是一个简单的异步解码器,它使用FFmpeg库解码视频文件,并将解码后的帧转换为RGB24格式。它使用一个线程来解码视频,并将解码后的帧存储在一个缓冲区中,主线程从缓冲区中读取帧并进行处理。这个代码示例可以作为FFmpeg异步解码的入门参考。
阅读全文