ffmpeg4.0以上如何在callback中利用fifo读H264视频流并且解码成YUV格式 给个C语言示例
时间: 2024-03-11 09:45:19 浏览: 97
以下是一个简单的C语言示例,它演示了如何使用ffmpeg4.0以上版本中的FIFO和解码器,将H264视频流解码为YUV格式:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
#define INBUF_SIZE 4096
int main(int argc, char *argv[]) {
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
AVFrame *frame_yuv = NULL;
uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
int inbuf_size;
uint8_t *data[4];
int linesize[4];
int ret, i, j;
if (argc <= 1) {
printf("Usage: %s <input file>\n", argv[0]);
return 0;
}
av_register_all();
avformat_network_init();
avcodec_register_all();
if (avformat_open_input(&fmt_ctx, argv[1], NULL, NULL) < 0) {
printf("Cannot open input file.\n");
return -1;
}
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
printf("Cannot find stream information.\n");
return -1;
}
int video_stream_index = -1;
for (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) {
printf("Cannot find video stream.\n");
return -1;
}
dec = avcodec_find_decoder(fmt_ctx->streams[video_stream_index]->codecpar->codec_id);
if (!dec) {
printf("Failed to find decoder.\n");
return -1;
}
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx) {
printf("Failed to allocate codec context.\n");
return -1;
}
if (avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar) < 0) {
printf("Failed to copy codec parameters to context.\n");
return -1;
}
if (avcodec_open2(dec_ctx, dec, NULL) < 0) {
printf("Failed to open codec.\n");
return -1;
}
frame = av_frame_alloc();
if (!frame) {
printf("Failed to allocate frame.\n");
return -1;
}
frame_yuv = av_frame_alloc();
if (!frame_yuv) {
printf("Failed to allocate YUV frame.\n");
return -1;
}
int numBytes = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, dec_ctx->width, dec_ctx->height, 1);
uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, buffer, AV_PIX_FMT_YUV420P, dec_ctx->width, dec_ctx->height, 1);
struct SwsContext *sws_ctx = sws_getContext(dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, dec_ctx->width, dec_ctx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
if (!sws_ctx) {
printf("Failed to create SwsContext.\n");
return -1;
}
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
while (av_read_frame(fmt_ctx, &pkt) >= 0) {
if (pkt.stream_index == video_stream_index) {
ret = avcodec_send_packet(dec_ctx, &pkt);
if (ret < 0) {
printf("Error sending packet to decoder.\n");
break;
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
printf("Error receiving frame from decoder.\n");
goto end;
}
sws_scale(sws_ctx, (const uint8_t *const *)frame->data, frame->linesize, 0, dec_ctx->height, frame_yuv->data, frame_yuv->linesize);
printf("Decoded frame %d (%d bytes).\n", dec_ctx->frame_number, ret);
}
}
av_packet_unref(&pkt);
}
end:
avcodec_free_context(&dec_ctx);
avformat_close_input(&fmt_ctx);
avformat_free_context(fmt_ctx);
av_frame_free(&frame);
av_frame_free(&frame_yuv);
sws_freeContext(sws_ctx);
av_free(buffer);
return 0;
}
```
这个示例程序使用了FIFO和解码器来读取H264视频流并将其解码为YUV格式。它首先打开输入文件并查找视频流,然后为解码器分配上下文并打开它。然后,它创建一个AVFrame结构体来存储解码的帧,并创建一个AVFrame结构体来存储YUV格式的帧。它还分配了一个缓冲区来存储YUV帧的像素数据。
接下来,它创建一个SwsContext结构体,用于执行YUV格式转换。然后,它循环读取视频流中的数据包并将其发送到解码器。每当解码器成功解码一帧时,它将使用SwsContext将帧转换为YUV格式,并将其输出到控制台。
最后,它清理并释放分配的内存,并关闭输入文件。
请注意,此示例程序仅用于演示如何使用ffmpeg4.0以上版本中的FIFO和解码器,实际应用中可能需要添加更多的错误处理和异常情况处理。
阅读全文