利用FFmpeg将mkv视频转换为H.264

本文介绍一个简单的基于FFmpeg的转码器,其将MKV文件转换为mp4g格式,采用H.264编码,主要是为了学习并记录相应的流程。

现贴上代码:

const char* SRC_FILE = "Titanic.mkv";
const char* OUT_FILE = "Titanic.h264";
const char* OUT_FMT_FILE = "Titanic.mp4";
int _tmain(int argc, _TCHAR* argv[])
{
	av_register_all();
	AVFormatContext* pFormat = NULL;
	if (avformat_open_input(&pFormat, SRC_FILE, NULL, NULL) < 0)
	{
		return 0;
	}
	AVCodecContext* video_dec_ctx = NULL;
	AVCodec* video_dec = NULL;
	if (avformat_find_stream_info(pFormat, NULL) < 0)
	{
		return 0;
	}
	av_dump_format(pFormat, 0, SRC_FILE, 0);
	video_dec_ctx = pFormat->streams[0]->codec;
	video_dec = avcodec_find_decoder(video_dec_ctx->codec_id);
	if (avcodec_open2(video_dec_ctx, video_dec, NULL) < 0)
	{
		return 0;
	}

	AVFormatContext* pOFormat = NULL;
	AVOutputFormat* ofmt = NULL;
	if (avformat_alloc_output_context2(&pOFormat, NULL, NULL, OUT_FILE) < 0)
	{
		return 0;
	}
	ofmt = pOFormat->oformat;
	if (avio_open(&(pOFormat->pb), OUT_FILE, AVIO_FLAG_READ_WRITE) < 0)
	{
		return 0;
	}
	AVCodecContext *video_enc_ctx = NULL;
	AVCodec *video_enc = NULL;
	video_enc = avcodec_find_encoder(AV_CODEC_ID_H264);
	AVStream *video_st = avformat_new_stream(pOFormat, video_enc);
	if (!video_st)
		return 0;
	video_enc_ctx = video_st->codec;
	video_enc_ctx->width = video_dec_ctx->width;
	video_enc_ctx->height = video_dec_ctx->height;
	video_enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
	video_enc_ctx->time_base.num = 1;
	video_enc_ctx->time_base.den = 25;
	video_enc_ctx->bit_rate = video_dec_ctx->bit_rate;
	video_enc_ctx->gop_size = 250;
	video_enc_ctx->max_b_frames = 10;

	video_enc_ctx->qmin = 10;
	video_enc_ctx->qmax = 51;
	if (avcodec_open2(video_enc_ctx, video_enc, NULL) < 0)
	{
		printf("编码器打开失败!\n");
		return 0;
	}
	printf("Output264video Information====================\n");
	av_dump_format(pOFormat, 0, OUT_FILE, 1);
	printf("Output264video Information====================\n");

	//mp4 file
	AVFormatContext* pMp4Format = NULL;
	AVOutputFormat* pMp4OFormat = NULL;
	if (avformat_alloc_output_context2(&pMp4Format, NULL, NULL, OUT_FMT_FILE) < 0)
	{
		return 0;
	}
	pMp4OFormat = pMp4Format->oformat;
	if (avio_open(&(pMp4Format->pb), OUT_FMT_FILE, AVIO_FLAG_READ_WRITE) < 0)
	{
		return 0;
	}
	for (int i = 0; i < pFormat->nb_streams; i++) {
		AVStream *in_stream = pFormat->streams[i];
		AVStream *out_stream = avformat_new_stream(pMp4Format, in_stream->codec->codec);
		if (!out_stream) {
			return 0;
		}
		int ret = 0;
		ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
		if (ret < 0) {
			fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
			return 0;
		}
		out_stream->codec->codec_tag = 0;
		if (pMp4Format->oformat->flags & AVFMT_GLOBALHEADER)
			out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
	}
	av_dump_format(pMp4Format, 0, OUT_FMT_FILE, 1);
	if (avformat_write_header(pMp4Format, NULL) < 0)
	{
		return 0;
	}
	av_opt_set(video_enc_ctx->priv_data, "preset", "superfast", 0);
	av_opt_set(video_enc_ctx->priv_data, "tune", "zerolatency", 0);
	avformat_write_header(pOFormat, NULL);
	AVPacket *pkt = new AVPacket();
	av_init_packet(pkt);
	AVFrame *pFrame = av_frame_alloc();// avcodec_alloc_frame();
	int ts = 0;
	while (1)
	{
		if (av_read_frame(pFormat, pkt) < 0)
		{
			avio_close(pOFormat->pb);
			av_write_trailer(pMp4Format);
			avio_close(pMp4Format->pb);
			delete pkt;
			return 0;
		}
		if (pkt->stream_index == 0)
		{

			int got_picture = 0, ret = 0;
			ret = avcodec_decode_video2(video_dec_ctx, pFrame, &got_picture, pkt);
			if (ret < 0)
			{
				delete pkt;
				return 0;
			}
			pFrame->pts = pFrame->pkt_pts;//ts++;
			if (got_picture)
			{
				AVPacket *tmppkt = new AVPacket;
				av_init_packet(tmppkt);
				int size = video_enc_ctx->width*video_enc_ctx->height * 3 / 2;
				char* buf = new char[size];
				memset(buf, 0, size);
				tmppkt->data = (uint8_t*)buf;
				tmppkt->size = size;
				ret = avcodec_encode_video2(video_enc_ctx, tmppkt, pFrame, &got_picture);
				if (ret < 0)
				{
					avio_close(pOFormat->pb);
					delete buf;
					return 0;
				}
				if (got_picture)
				{
					//ret = av_interleaved_write_frame(pOFormat, tmppkt);
					AVStream *in_stream = pFormat->streams[pkt->stream_index];
					AVStream *out_stream = pMp4Format->streams[pkt->stream_index];

					tmppkt->pts = av_rescale_q_rnd(tmppkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
					tmppkt->dts = av_rescale_q_rnd(tmppkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
					tmppkt->duration = av_rescale_q(tmppkt->duration, in_stream->time_base, out_stream->time_base);
					tmppkt->pos = -1;
					ret = av_interleaved_write_frame(pMp4Format, tmppkt);
					if (ret < 0)
						return 0;
					delete tmppkt;
					delete buf;
				}
			}
			//avcodec_free_frame(&pFrame);
		}
		else if (pkt->stream_index == 1)
		{
			AVStream *in_stream = pFormat->streams[pkt->stream_index];
			AVStream *out_stream = pMp4Format->streams[pkt->stream_index];

			pkt->pts = av_rescale_q_rnd(pkt->pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
			pkt->dts = av_rescale_q_rnd(pkt->dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
			pkt->duration = av_rescale_q(pkt->duration, in_stream->time_base, out_stream->time_base);
			pkt->pos = -1;
			if (av_interleaved_write_frame(pMp4Format, pkt) < 0)
				return 0;
		}
	}
	av_frame_free(&pFrame);
	return 0;
}
工程下载地址(VC2013):http://download.csdn.net/detail/wootengxjj/9559344。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值