【C++】ffmpeg將png圖片序列轉成mp4

#include <stdio.h>

extern "C"//包含C文件頭
{
#include "libavformat/avformat.h"
};
#define DATASIZE 2048*2048

AVStream *add_vidio_stream(AVFormatContext *oc, enum AVCodecID codec_id)//用以初始化一個用於輸出的AVFormatContext結構體
{
	AVStream *st;
	AVCodec *codec;

	st = avformat_new_stream(oc, NULL);
	if (!st)
	{
		printf("Could not alloc stream\n");
		exit(1);
	}
	codec = avcodec_find_encoder(codec_id);//查找mjpeg解碼器
	if (!codec)
	{
		printf("codec not found\n");
		exit(1);
	}
	avcodec_get_context_defaults3(st->codec, codec);//申請AVStream->codec(AVCodecContext對象)空間並設置默認值(由avcodec_get_context_defaults3()設置

	st->codec->bit_rate = 400000;//設置採樣參數,即比特率  
	st->codec->width = 1332;//設置視頻寬高,這裏跟圖片的寬高保存一致即可
	st->codec->height = 620;
	st->codec->time_base.den = 25;//設置幀率
	st->codec->time_base.num = 1;

	st->codec->pix_fmt = AV_PIX_FMT_YUV420P;//設置像素格式  
	st->codec->codec_tag = 0;
	if (oc->oformat->flags & AVFMT_GLOBALHEADER)//一些格式需要視頻流數據頭分開
		st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
	return st;
}

void main()
{
	AVFormatContext *ofmt_ctx = NULL;//其包含碼流參數較多,是一個貫穿始終的數據結構,很多函數都要用到它作爲參數
	const char *out_filename = "d:\\out.mp4";//輸出文件路徑,在這裏也可以將mkv改成別的ffmpeg支持的格式,如mp4,flv,avi之類的
	int ret;//返回標誌

	av_register_all();//初始化解碼器和複用器
	avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);//初始化一個用於輸出的AVFormatContext結構體,視頻幀率和寬高在此函數裏面設置
	if (!ofmt_ctx)
	{
		printf("Could not create output context\n");
		return;
	}

	//AVStream *out_stream = add_vidio_stream(ofmt_ctx, AV_CODEC_ID_MJPEG);//創造輸出視頻流
	AVStream *out_stream = add_vidio_stream(ofmt_ctx, AV_CODEC_ID_PNG);//創造輸出視頻流(第三個參數指向圖片的格式)
	av_dump_format(ofmt_ctx, 0, out_filename, 1);//該函數會打印出視頻流的信息,如果看着不開心可以不要

	if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE))//打開輸出視頻文件
	{
		ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
		if (ret < 0) {
			printf("Could not open output file '%s'", out_filename);
			return;
		}
	}

	if (avformat_write_header(ofmt_ctx, NULL) < 0)//寫文件頭(Write file header)
	{
		printf("Error occurred when opening output file\n");
		return;
	}

	int frame_index = 0;//放入視頻的圖像計數
	unsigned char *mydata = new unsigned char[DATASIZE];
	AVPacket pkt;
	av_init_packet(&pkt);
	pkt.flags |= AV_PKT_FLAG_KEY;
	pkt.stream_index = out_stream->index;//獲取視頻信息,爲壓入幀圖像做準備

	char buf[250] = { 0 };
	while (frame_index < 626)//將圖像壓入視頻中
	{
		_snprintf(buf, 255, "1_00%03d.png", frame_index);//1_00000

		std::string dir = "F:\\幀轉視頻\\data5\\";
		std::string filePath = dir + buf;
		FILE *file;//打開一張jpeg圖像並讀取其數據,在這裏圖像最大爲1M,如果超過1M,則需要修改1024*1024這裏
		fopen_s(&file, filePath.c_str(), "rb");
		pkt.size = fread(mydata, 1, DATASIZE, file);
		pkt.data = mydata;

		fclose(file);
		if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) //寫入圖像到視頻
		{
			printf("Error muxing packet\n");
			break;
		}
		printf("Write %8d frames to output file\n", frame_index);//打印出當前壓入的幀數
		frame_index++;
	}


	av_free_packet(&pkt);//釋放掉幀數據包對象
	av_write_trailer(ofmt_ctx);//寫文件尾(Write file trailer)
	delete[]mydata;//釋放數據對象
	if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE))
		avio_close(ofmt_ctx->pb);//關閉視頻文件
	avformat_free_context(ofmt_ctx);//釋放輸出視頻相關數據結構
	return;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章