FFmpeg学习:04.利用FFmpeg将rgb转为h264

1,478 阅读1分钟

利用指令将yuv转为h264格式。

ffmpeg -s 1920x1080 -i Screen.yuv -vcodec libx264 Screenh264.264

播放h264

ffplay Screenh264.264

转换的代码附上,其中主要的思路是讲 rgb 转为 yuv 存储在 AVFrame 在将 yuv 转为 h264 存储在 AVPacket 中。

void SaveRgb2H264Complete()
{
	int width = 1920;
	int height = 1080;

	FILE* fpinRGB = fopen("ScreenRGBComplete.rgb", "rb");
	if (!fpinRGB) return;

	FILE* fpoutH264 = fopen("ScreenH264Complete.264", "wb");
	if (!fpoutH264) return;
	
	av_register_all();

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

	//创建YUV视频帧并配置
	AVFrame *yuvFrame = av_frame_alloc();
	yuvFrame->format = AV_PIX_FMT_YUV420P;
	yuvFrame->width = width;
	yuvFrame->height = height;
	int ret = av_frame_get_buffer(yuvFrame, 4*8);
	if (ret < 0) return;

	// 查找编码器
	AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
	if (!codec) return;

	// 给编码器分配内存,返回对应编码器上下文
	AVCodecContext *codecCtx = avcodec_alloc_context3(codec);
	if (!codecCtx) return;

	// 配置编码器上下文的成员
	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; // 设置输出像素格式

	// 打开编码器
	ret = avcodec_open2(codecCtx, codec, NULL);
	if (ret < 0) return;

	unsigned char *rgbBuf = new unsigned char[width * height * 4];
	int count = 0;

	while (true) 
	{
		//每次读取一帧RGB数据到rgbBuf,读取完毕则退出
		int len = fread(rgbBuf, 1, width * height * 4, fpinRGB);
		if (len <= 0) break;

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

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

		// 将未压缩的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;

		// 写入H264文件
		fwrite(pkt.data, 1, pkt.size, fpoutH264);
	}

	av_frame_free(&yuvFrame);

	fclose(fpinRGB);
	fclose(fpoutH264);
	delete rgbBuf;
	avcodec_close(codecCtx);//关闭编码器
	avcodec_free_context(&codecCtx);//清理编码器上下文
	sws_freeContext(swsCtx);
}

参考链接:www.cnblogs.com/linuxAndMcu…