使用FFMPEG将YUV编码为H.264

本文介绍一个如何使用FFmpeg实现YUV420P的像素数据编码为H.264的压缩编码数据。

项目十分简单,没有多少代码在其中。弄清楚了该项目的代码也就基本弄清楚了FFMPEG的编码流程。

本程序使用的FFmpeg版本为2.2.2(版本较新),开发平台为VC2008(VC2010估计很多人都用不了)。

相关配置已经完成,只需下载源码运行即可。

下面直接上代码:

/* 
 *将YUV420P进行H264编码压缩
 *码术 codemanship
 *邮箱: [email protected]
 *http://blog.csdn.net/codemanship
 *微信公众号: codemanship
 *本程序实现了YUV420P的像素数据编码为H.264的压缩编码数据
 *是最简单的FFmpeg视频编码方面的教程。
 *通过学习本例子可以了解FFmpeg的图片压缩过程。
*/
#ifndef INT64_C
#define INT64_C
#define UINT64_C
#endif
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavutil/imgutils.h"
#include "libavutil/parseutils.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
};
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"swscale.lib")
#pragma comment(lib,"avutil.lib")

#define  FrameCount 50
static void fill_yuv_image(uint8_t *data[4], int linesize[4],
                           int width, int height, int frame_index)
{
    int x, y;

    /* Y */
    for (y = 0; y < height; y++)
        for (x = 0; x < width; x++)
            data[0][y * linesize[0] + x] = x + y + frame_index * 3;

    /* Cb and Cr */
    for (y = 0; y < height / 2; y++) {
        for (x = 0; x < width / 2; x++) {
            data[1][y * linesize[1] + x] = 128 + y + frame_index * 2;
            data[2][y * linesize[2] + x] = 64 + x + frame_index * 5;
        }
    }
}



int main(int argc, char **argv)
{
	AVFormatContext* pFormatCtx;
	AVOutputFormat* fmt;
	AVStream* video_st;
	AVCodecContext* pCodecCtx;
	AVCodec* pCodec;
	AVFrame* srcFrame;
	int size;

	int width=640,height=480;
	const char* outfilename = "out_640x480.h264";

	av_register_all();
	pFormatCtx = avformat_alloc_context();
	fmt = av_guess_format(NULL, outfilename, NULL);
	pFormatCtx->oformat = fmt;

	if (avio_open(&pFormatCtx->pb,outfilename, AVIO_FLAG_READ_WRITE) < 0)
	{
		printf("open file failed.");
		exit(1);
	}

	video_st = av_new_stream(pFormatCtx, 0);
	if (video_st==NULL)
	{
		exit(1);
	}
	pCodecCtx = video_st->codec;
	pCodecCtx->codec_id = fmt->video_codec;
	pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
	pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
	pCodecCtx->width = width;  
	pCodecCtx->height = height;
	pCodecCtx->time_base.num = 1;  
	pCodecCtx->time_base.den = 25;  
	pCodecCtx->bit_rate = 40000;  
	pCodecCtx->gop_size=10;
	pCodecCtx->qmin = 10;
	pCodecCtx->qmax = 30;

	//输出格式信息
	av_dump_format(pFormatCtx, 0, outfilename, 1);

	pCodec = avcodec_find_encoder(pCodecCtx->codec_id);
	if (!pCodec)
	{
		fprintf(stderr, "Codec not found\n");
		exit(1);
	}
	//设置X264编码的参数,减小延迟
	AVDictionary *opts = NULL;
	av_dict_set(&opts, "profile", "baseline", 0); 
	av_dict_set(&opts, "preset", "fast", 0);
	av_dict_set(&opts, "tune", "zerolatency", 0);
	if (avcodec_open2(pCodecCtx, pCodec,&opts) < 0)
	{
		fprintf(stderr, "Could not open codec\n");
		exit(1);
	}
	srcFrame = av_frame_alloc();
	size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
	/* allocate source and destination image buffers */
	if ((av_image_alloc(srcFrame->data, srcFrame->linesize,
		width, height, PIX_FMT_YUV420P, 16)) < 0) {
			fprintf(stderr, "Could not allocate source image\n");
			exit(1);
	}
	//写文件头
	avformat_write_header(pFormatCtx,NULL);

	AVPacket pkt;
	int y_size = pCodecCtx->width * pCodecCtx->height;
	av_new_packet(&pkt,y_size*3);

	for (int i=0; idata,srcFrame->linesize,width,height,i);
		/*设置pts*/
		srcFrame->pts=i;
		int got_picture=0;
		/*编码*/
		int ret = avcodec_encode_video2(pCodecCtx, &pkt,srcFrame, &got_picture);
		if(ret < 0)
		{
			fprintf(stderr, "Error encoding frame\n");
			return -1;
		}
		if (got_picture==1)
		{
			printf("Write frame %3d (size=%5d)\n", i, pkt.size);
			pkt.stream_index = video_st->index;
			ret = av_write_frame(pFormatCtx, &pkt);
			av_free_packet(&pkt);
		}
	}

	//写文件尾
	av_write_trailer(pFormatCtx);
	//清理
	if (video_st)
	{
		avcodec_close(video_st->codec);
		av_freep(srcFrame);
	}
	avio_close(pFormatCtx->pb);
	avformat_free_context(pFormatCtx);
	return 0;
}

程序截图

使用FFMPEG将YUV编码为H.264_第1张图片

编码前YUV数据

使用FFMPEG将YUV编码为H.264_第2张图片

编码后H264码流

使用FFMPEG将YUV编码为H.264_第3张图片

你可能感兴趣的:(FFMpeg)