FFmpeg RGB转H264

前言

下面代码是在我的上一篇博客:FFmpeg RGB转YUV 的代码的基础上修改而来的,创建了编码器并进行 H264 编码,进一步将 RGB 格式像素数据转换成 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[] = "dove_BGRA.rgb";
	char outfile[] = "out.264";

	// 源图像参数
	int width = 640;
	int height = 360;
	int fps = 25;

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

	FILE *fpout = fopen(outfile, "wb");
	if (!fpout)
	{
		cout << "open outfile failed!" << endl;
		exit(1);
	}
	// 创建RGB缓冲区同时分配内存
	unsigned char *rgbBuf = new unsigned char[width*height * 4];

	// 注册所有和编解码器有关的组件
	av_register_all();

	/* 2 创建编码器 */
	// 查找编码器
	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 *codecCtx = avcodec_alloc_context3(codec);
	if (!codecCtx)
	{
		cout << "avcodec_alloc_context3  failed!" << endl;
		getchar();
		return -1;
	}
	// 配置编码器上下文的成员
	codecCtx->width = width; // 设置编码视频宽度 
	codecCtx->height = height; // 设置编码视频高度
	codecCtx->time_base.num = 1;
	codecCtx->time_base.den = 25; // 设置帧率,num为分子,den为分母,如果是1/25则表示25帧/s
	codecCtx->pix_fmt = AV_PIX_FMT_YUV420P; // 设置输出像素格式

	// 打开编码器
	int ret = avcodec_open2(codecCtx, codec, NULL);
	if (ret < 0)
	{
		cout << "avcodec_open2  failed!" << endl;
		getchar();
		return -1;
	}
	cout << "avcodec_open2 success!" << endl;

	// 3 创建视频重采样上下文:指定源和目标图像分辨率、格式
	SwsContext *swsCtx = NULL;
	swsCtx = sws_getCachedContext(swsCtx,
		width, height, AV_PIX_FMT_BGRA,
		width, height, AV_PIX_FMT_YUV420P,
		SWS_BICUBIC,
		NULL, NULL, NULL
		);

	//4 创建YUV视频帧并配置
	AVFrame *yuvFrame = av_frame_alloc();
	yuvFrame->format = AV_PIX_FMT_YUV420P;
	yuvFrame->width = width;
	yuvFrame->height = height;
	ret = av_frame_get_buffer(yuvFrame, 32);
	if (ret < 0)
	{
		cout << "av_frame_get_buffer  failed!" << endl;
		getchar();
		return -1;
	}

	// 循环写视频文件
	int pts = 0;
	int count = 0;
	for (;;)
	{
		//5 每次读取一帧RGB数据到rgbBuf,读取完毕则退出
		int len = fread(rgbBuf, 1, width*height * 4, fpin);
		if (len <= 0)
		{
			break;
		}

		//5 创建RGB视频帧并绑定RGB缓冲区(avpicture_fill是给rgbFrame初始化一些字段,并且会自动填充data和linesize)
		AVFrame *rgbFrame = av_frame_alloc();
		avpicture_fill((AVPicture *)rgbFrame, rgbBuf, AV_PIX_FMT_BGRA, width, height);

		//7 像素格式转换,转换后的YUV数据存放在yuvFrame
		int outSliceH = sws_scale(swsCtx, rgbFrame->data, rgbFrame->linesize, 0, height,
			yuvFrame->data, yuvFrame->linesize
			);
		if (outSliceH <= 0)
			break;

		/* 8 H264编码 */
		// 将未压缩的AVFrame数据(yuv)给编码器
		yuvFrame->pts = count++ * (codecCtx->time_base.num * 1000 / codecCtx->time_base.den);
		ret = avcodec_send_frame(codecCtx, yuvFrame);
		if (ret != 0)
		{
			continue;
		}
		// 将编码数据保存在AVPacket
		AVPacket pkt;
		av_init_packet(&pkt);
		ret = avcodec_receive_packet(codecCtx, &pkt);
		if (ret != 0)
			continue;

		//9 写入H264文件
		fwrite(pkt.data, 1, pkt.size, fpout);
		//av_packet_unref(&pkt);

		cout << "<" << pkt.size << ">";
	}

	// 关闭RGB和YUV文件
	fclose(fpin);
	fclose(fpout);

	// 释放RGB缓冲区
	delete rgbBuf;

	//关闭编码器
	avcodec_close(codecCtx);

	//清理编码器上下文
	avcodec_free_context(&codecCtx);

	//清理视频重采样上下文
	sws_freeContext(swsCtx);

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

	getchar();

	return 0;
}

原文链接: https://www.cnblogs.com/linuxAndMcu/p/12131721.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    FFmpeg RGB转H264

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/191361

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午5:42
下一篇 2023年2月12日 下午5:42

相关推荐