C++-FFmpeg-(4)-1-基于FFmpeg改变像素格式和图像尺寸

本文主要完成两个功能YUV->RGB  文件格式转换 ,RGB->YUV文件格式的转换
原理上就一个难点,双线性过滤,如下图所示:

1.用到3个函数
2.实现的步骤
3.示例代码:
  3.1YUV->RGB
  3.2RGB->YUV

 


1、YUV->RGB  文件格式转换 ,RGB->YUV文件格式的转换用到3个主要的函数:
  1.1.初始化:

  1.2缩放:

  1.3文件操作   #include <fstream>

       fstream ifs;fstream ofs;
    1.3.1 ifs.open("file.yuv",ios::binary)                        打开或者新建
    1.3.2 ifs.read(char* c, datasize)        读
    1.3.3 ifs.gcount()==0                                               读到结尾处
    1.3.4 ofs.write(char* c,datasize)                             写
    1.3.5 ifs.close(),ofs.close()                                                      关闭/
2 步骤:
   2.1 打开文件
   2.2 读取文件
   2.3 初始化
   2.4 转换
   2.5 关闭文件
   在实现之前要有文件名定义和数据空间的分配工作:

YUV是平面存储  YYYY UU VV
RGB是交叉存储  rgba

   #define YUV_FILE "400_300_25.yuv"
   #define RGBA_FILE "800_600_25.rgba"

    //设定文件宽、高
	int width = 400;
	int height = 300;
	int rgb_width = 800;
	int rgb_height = 600;

	//分配数据空间 new  delete
	// YUV420P 平面存储 yyyy uu vv
	unsigned char* yuv[3] = { 0 };
	int yuv_linesize[3] = { width,width / 2,width / 2 }; //YUV 每行的linesize 
	yuv[0] = new unsigned char[width * height];     //Y
	yuv[1] = new unsigned char[width * height / 4]; //U
	yuv[2] = new unsigned char[width * height / 4]; //V
	
	//RGBA 交叉存储 rgba rgba
	unsigned char* rgba = new unsigned char[rgb_width * rgb_height * 4];
	int rgba_linesize = rgb_width * 4;

3.示例代码
3.1.YUV->RGB
 

//1.打开文件 ifs.open ofs.open
	ifstream ifs;
	ifs.open(YUV_FILE, ios::binary);

	ofstream ofs;
	ofs.open(RGBA_FILE, ios::binary);

	SwsContext* yuv2rgb = nullptr;
	for (int i = 0; i < 10; i++)
	{
		//1.2.读取YUV帧  ifs.gcount()读到结尾
		ifs.read((char*)yuv[0], width * height);
		ifs.read((char*)yuv[1], width * height / 4);
		ifs.read((char*)yuv[2], width * height / 4);
		if (ifs.gcount() == 0)break;

		//1.3.初始化上下文
		
		yuv2rgb = sws_getCachedContext(
			yuv2rgb,                 //转换上下文,NULL新创建,非NULL判断与现有参数是否一致,
									  //一致直接返回,不一致先清理当前然后再创建
			width, height,           //输入宽高
			AV_PIX_FMT_YUV420P,     //输入像素格式
			rgb_width, rgb_height,   //输出的宽高
			AV_PIX_FMT_RGBA,        //输出的像素格式
			SWS_BILINEAR,           //选择支持变化的算法,双线性插值
			0, 0, 0                 //过滤器参数

		);
		//1.4转换函数  re 输出的高度
		unsigned char* data[1];
		data[0] = rgba;
		int lines[1] = { rgba_linesize };
		int re = sws_scale(yuv2rgb,
			yuv,                //输入数据
			yuv_linesize,       //输入数据行字节数
			0,
			height,             //输入高度
			data,               //输出数据
			lines
		);
		cout << re << " " << flush;
		ofs.write((char*)rgba, rgb_width * rgb_height * 4);
	}

	ifs.close();
	ofs.close();


3.2.RGB->YUV
 

//2.1 打开文件
	ifs.open(YUV_FILE, ios::binary);
	ifs.open(RGBA_FILE, ios::binary);
	SwsContext* rgb2yuv = nullptr;
	
	for (;;)
	{
		//2.2 读取RGB
		ifs.read((char*)rgba, rgb_width * rgb_height * 4);
		if (ifs.gcount() == 0)break;

		//2.3 初始化
		rgb2yuv = sws_getCachedContext(
			rgb2yuv,                 //转换上下文,NULL新创建,非NULL判断与现有参数是否一致,
									//一致直接返回,不一致先清理当前然后再创建
			rgb_width, rgb_height,         //输入宽高
			AV_PIX_FMT_RGBA,               //输入像素格式
			width, height,                 //输出的宽高
			AV_PIX_FMT_YUV420P,            //输出的像素格式
			SWS_BILINEAR,                  //选择支持变化的算法,双线性插值
			0, 0, 0                        //过滤器参数
		);

	   //2.4 转换 sws_scale
		unsigned char* data[1];
		data[0] = rgba;
		int lines[1] = { rgba_linesize };
		int re = sws_scale(rgb2yuv,
			data,                //输入数据
			lines,               //输入数据行字节数
			0,
			rgb_height,         //输入高度
			yuv,                //输出数据
			yuv_linesize        //输出数据
		);
	}
	
	

	//1.2.2 释放空间
	delete yuv[0];
	delete yuv[1];
	delete yuv[2];
	delete rgba;




 



 

FFmpeg是一个广泛使用的开源库,用于处理多媒体文件,包括音频、视频流的编码、解码、转换等。在C++中使用FFmpeg进行图像转为视频,通常涉及以下几个步骤: 1. **安装FFmpeg**:首先需要从FFmpeg官网下载源代码并编译安装,或者直接在项目中引用预编译的静态库。 2. **包含头文件**:在C++代码中,你需要包含`libavcodec/avcodec.h` 和 `libavformat/avformat.h` 等头文件,这些包含了FFmpeg的主要函数声明。 3. **初始化上下文**:创建AVFormatContext和AVCodecContext结构体实例,分别用于表示媒体格式和编码器。 4. **加载输入图像**:使用`avformat_open_input()`打开图片文件,并读取像素数据。 5. **选择编码器**:找到适合的视频编码器,比如H.264或WebM,通过`avcodec_find_encoder_by_name()`函数获取对应的编码器。 6. **分配帧缓冲区**:为编码器分配内存,用于存储每一帧数据。 7. **编码过程**:创建一个AVPacket来封装图像数据,然后调用编码器的`encode_frame()`函数进行编码。循环这个过程直到所有图像都被编码。 8. **创建输出文件**:使用`avformat_alloc_output_context2()`创建一个新的AVFormatContext,指定输出文件名和所需的容器格式。 9. **写入编码后的帧**:将编码好的AVPackets写入到输出文件,调用`av_interleaved_write_frame()`完成帧的写入。 10. **清理资源**:关闭所有的上下文和文件,释放内存。 ```cpp // 示例代码片段 #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> int main() { // 初始化FFmpeg av_register_all(); // ... (继续上述步骤) // 创建输出文件 AVOutputFormat* format = av_guess_format("output.mp4", NULL, NULL); if (!format) { std::cerr << "Failed to guess output format" << std::endl; return -1; } AVWriter* writer = avformat_new_writer(output_file, format->oformat); if (!writer) { std::cerr << "Failed to create output file" << std::endl; return -1; } // 写入帧 for (int i = 0; i < num_images; ++i) { // 编码图像... AVPacket packet; int result = encode_image_to_packet(&packet); if (result < 0) { std::cerr << "Failed to encode frame" << std::endl; break; } int written = av_interleaved_write_frame(writer, &packet); if (written < 0) { std::cerr << "Failed to write frame" << std::endl; break; } } // 清理 avio_close(writer->pb); avformat_free_context(writer); avformat_close_input(&input); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值