使用ffmpeg将视频解析为YUV420

本文介绍了如何使用ffmpeg版本开发库实现avi和mp4视频文件的解析为YUV420格式,并提供了改进后的代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 使用ffmpeg解析视频文件为YUV420,下载最新的 ffmpeg-20151221-git-c0f67e1-win32-dev 版本的开发库,然后用里面的sample做熟悉测试,发现由不少问题,还以为在Win7+VS2010中无法编译呢。但是经过一天多的查找终于解决了,实现了avi和mp4视频的解析(只做了这两种格式的测试)为YUV420.下面的代码是在filtering_video.c例子上做了改进得到的。

#ifdef __cplusplus
extern "C" {
#endif
#include<stdio.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>

#ifdef __cplusplus
}
#endif

static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
static int video_stream_index = -1;

static int open_input_file(const char *filename)
{
    int ret;
    AVCodec *dec;

    if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) 
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n");
        return ret;
    }

    if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) 
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n");
        return ret;
    }

    /* select the video stream */
    ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
    if (ret < 0) 
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
        return ret;
    }
    video_stream_index = ret;
    dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
    av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0);

    /* init the video decoder */
    if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) 
	{
        av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
        return ret;
    }

    return 0;
}

int main(int argc, char **argv)
{
	
    int ret;
	int got_frame;
    AVPacket packet;
    AVFrame *frame = av_frame_alloc();

    if (!frame) {
        perror("Could not allocate frame");
        exit(1);
    }

    av_register_all();	
    if ((ret = open_input_file(argv[1])) < 0)
	{
		printf("open_input_file wrong\n");
        exit(1);        
	}

	clock_t start = 0;
	FILE *fp = fopen("video.yuv", "wb");

    /* read all packets */
    while (1)
	{
        if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
        {
			break;
		}

        if (packet.stream_index == video_stream_index) 
		{
            got_frame = 0;

			start = clock();
            ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, &packet);
            if (ret < 0) 
			{
                av_log(NULL, AV_LOG_ERROR, "Error decoding video\n");
                break;
            }
			printf("Time:  %d\n",(clock()-start));

            if (got_frame)
			{
				//use to ouput 1920*1080 yuv420 video with faster speed, need data line alignment
				//fwrite(frame->data[0], sizeof(frame->data[0][0]), frame->width*frame->height, fp);
				//fwrite(frame->data[1], sizeof(frame->data[1][0]), frame->width*frame->height/4, fp);
				//fwrite(frame->data[2], sizeof(frame->data[2][0]), frame->width*frame->height/4, fp);

				//can be used to ouput any size yuv420 video with fast speed
				//int width = dec_ctx->width, height = dec_ctx->height;
				//int height_half = height / 2, width_half = width / 2;
				//int y_wrap = frame->linesize[0];
				//int u_wrap = frame->linesize[1];
				//int v_wrap = frame->linesize[2];

				//unsigned char *y_buf = frame->data[0];
				//unsigned char *u_buf = frame->data[1];
				//unsigned char *v_buf = frame->data[2];

				////save y
				//for (int i = 0; i < height; i++)
				//	fwrite(y_buf + i * y_wrap, 1, width, fp);
				////save u
				//for (int i = 0; i < height_half; i++)
				//	fwrite(u_buf + i * u_wrap, 1, width_half, fp);
				////save v
				//for (int i = 0; i < height_half; i++)
				//	fwrite(v_buf + i * v_wrap, 1, width_half, fp);
				//fflush(fp);

                av_frame_unref(frame);
            }
        }
        av_packet_unref(&packet);
    }

	fclose(fp);
    avcodec_close(dec_ctx);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&frame);

	system("pause");
    return 0;
}

参考链接:

http://www.cnblogs.com/lidabo/p/3326502.html

http://m.blog.youkuaiyun.com/blog/sun6623518/8602372


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值