FFmpeg RGB轉MP4


下面是一個讀取本地 RGB 文件,轉換並輸出 MP4 視頻文件的一個例子,具體步驟如下:

1、創建編碼器

2、創建輸出視頻上下文

3、添加視頻流

4、rgb轉yuv

5、寫視頻文件頭

6、寫視頻文件,循環內部進行H264編碼

完整代碼如下:

#include <iostream>

extern "C"
{
	#include <libavformat/avformat.h>
	#include <libswscale/swscale.h>
}

#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"swscale.lib")

using namespace std;

int main()
{
	char infile[] = "out.rgb";
	char outfile[] = "rgb.mp4";

	// 注冊所有和編解碼器有關的組件
	av_register_all();

	// 打開RGB文件
	FILE *fp = fopen(infile, "rb");
	if (!fp)
	{
		cout << infile << " open failed!" << endl;
		getchar();
		return -1;
	}

	// 源圖像參數
	int width = 848;
	int height = 480;
	int fps = 25;

	///1 創建編碼器
	// 查找編碼器
	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!codec)
	{
		cout << " avcodec_find_encoder AV_CODEC_ID_H264 failed!" << endl;
		getchar();
		return -1;
	}

	// 給編碼器分配內存,返回對應編碼器上下文
	AVCodecContext *c = avcodec_alloc_context3(codec);
	if (!c)
	{
		cout << " avcodec_alloc_context3  failed!" << endl;
		getchar();
		return -1;
	}
	// 配置編碼器上下文的成員
	c->bit_rate = 400000000; // 比特率(碼率),越高視頻質量越好
	c->width = width; // 設置編碼視頻寬度 
	c->height = height; // 設置編碼視頻高度
	c->time_base.num = 1;
	c->time_base.den = 25; // 設置幀率,num為分子,den為分母,如果是1/25則表示25幀/s

	c->gop_size = 50; // 畫面組大小,關鍵幀
	c->max_b_frames = 0; // 設置B幀最大數,該值表示在兩個非B幀之間,所允許插入的B幀的最大幀數

	c->pix_fmt = AV_PIX_FMT_YUV420P; // 設置輸出像素格式
	c->codec_id = AV_CODEC_ID_H264; // 設置編碼格式
	c->thread_count = 8; // 線程數量
	c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; // 全局的編碼信息

	// 打開編碼器
	int ret = avcodec_open2(c, codec, NULL);
	if (ret < 0)
	{
		cout << " avcodec_open2  failed!" << endl;
		getchar();
		return -1;
	}
	cout << "avcodec_open2 success!" << endl;

	///2 創建輸出視頻上下文
	AVFormatContext *oc = NULL;
	avformat_alloc_output_context2(&oc, 0, 0, outfile);

	///3 添加視頻流
	AVStream *st = avformat_new_stream(oc, NULL);
	st->id = 0;
	st->codecpar->codec_tag = 0;
	// 將AVCodecContext信息拷貝到AVCodecParameterst結構體中
	avcodec_parameters_from_context(st->codecpar, c);

	cout << "===============================================" << endl;
	// 打印AVFormatContext的內容
	av_dump_format(oc, 0, outfile, 1);
	cout << "===============================================" << endl;

	///4 rgb轉yuv
	SwsContext *ctx = NULL;
	ctx = sws_getCachedContext(ctx,
		width, height, AV_PIX_FMT_BGRA,
		width, height, AV_PIX_FMT_YUV420P,
		SWS_BICUBIC,
		NULL, NULL, NULL
		);
	// 分配輸入空間
	unsigned char *rgb = new unsigned char[width*height * 4];

	// 分配輸出空間
	AVFrame *yuv = av_frame_alloc();
	yuv->format = AV_PIX_FMT_YUV420P;
	yuv->width = width;
	yuv->height = height;
	ret = av_frame_get_buffer(yuv, 32);
	if (ret < 0)
	{
		cout << " av_frame_get_buffer  failed!" << endl;
		getchar();
		return -1;
	}

	///5 寫視頻文件頭
	// 創建並初始化AVIOContext以訪問outfile指示的資源
	ret = avio_open(&oc->pb, outfile, AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		cout << " avio_open  failed!" << endl;
		getchar();
		return -1;
	}
	// 寫視頻文件頭
	ret = avformat_write_header(oc, NULL);
	if (ret < 0)
	{
		cout << " avformat_write_header  failed!" << endl;
		getchar();
		return -1;
	}

	// 循環寫視頻文件
	int pts = 0;
	for (;;)
	{
		// 讀取RGB文件的像素數據長度
		int len = fread(rgb, 1, width*height * 4, fp);
		if (len <= 0)
		{
			break;
		}

		// 像素格式轉換:RGB轉YUV
		uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
		indata[0] = rgb;
		int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };
		inlinesize[0] = width * 4;
		int h = sws_scale(ctx, indata, inlinesize, 0, height,
			yuv->data, yuv->linesize
			);
		if (h <= 0)
			break;

		///6 H264編碼
		// 將未壓縮的AVFrame數據(yuv)給編碼器
		yuv->pts = pts;
		//yuv->pict_type = AV_PICTURE_TYPE_I;
		pts = pts + 3600;
		ret = avcodec_send_frame(c, yuv);
		if (ret != 0)
		{
			continue;
		}
		// 將編碼數據保存在AVPacket
		AVPacket pkt;
		av_init_packet(&pkt);
		ret = avcodec_receive_packet(c, &pkt);
		if (ret != 0)
			continue;

		// 將AVPacket寫入輸出媒體文件
		//av_write_frame(oc, &pkt);
		//av_packet_unref(&pkt);
		av_interleaved_write_frame(oc, &pkt);

		cout << "<"<<pkt.size<<">";
	}
	
	//寫入視頻索引
	av_write_trailer(oc);

	//關閉視頻輸出io
	avio_close(oc->pb);

	//清理封裝輸出上下文
	avformat_free_context(oc);

	//關閉編碼器
	avcodec_close(c);

	//清理編碼器上下文
	avcodec_free_context(&c);

	//清理視頻重采樣上下文
	sws_freeContext(ctx);

	cout << "======================end=========================" << endl;

	delete rgb;
	getchar();
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM