欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

像素数据格式的转换yuv转rgba

程序员文章站 2022-07-02 10:30:16
...

本文介绍如何使用ffmpeg中的接口转换像素数据格式.

假定现有 yuv.yuv(YUV420P格式)文件需要转为RGBA格式
将rgb.rgb转成yuv格式

#include <iostream>
#include <fstream>
using namespace std;
extern "C"{
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
}
//预处理指令导入库
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swscale.lib")

#define YUV_FILE "yuv.yuv"
#define RGBA_FILE "rgb.rgb"

#define YUV_WIDTH 400
#define YUV_HEIGHT 300

#define RGB_WIDTH 800
#define RGB_HEIGHT 600

int main()
{
//1,申请3个用于存放yuv数据的数组 并设置好linesize
	unsigned char *yuv[3];
	int yuv_linesize[3] = { YUV_WIDTH, YUV_WIDTH / 2, YUV_WIDTH / 2 };
	yuv[0] = new unsigned char[YUV_WIDTH * YUV_HEIGHT ];
	yuv[1] = new unsigned char[YUV_WIDTH * YUV_HEIGHT / 4];
	yuv[2] = new unsigned char[YUV_WIDTH * YUV_HEIGHT  / 4];
//2,申请一个用于存放RGBA数据的数组 并设置好linesize
	unsigned char* rgba = new unsigned char[RGB_WIDTH * RGB_HEIGHT *4];
	int rgba_linesize = RGB_WIDTH * 4;

//3,打开YUV_FILE文件 和 RGBA_FILE
	ifstream ifs;
	ifs.open(YUV_FILE, ios::binary);
	if(!ifs){
		cout << "open file failed" << endl;
		return -1;
	}
	ofstream ofs;
	ofs.open("yuv2rgb.rgb", ios::binary);
	if(!ofs){
		cout << "open file yuv2rgb.rgb file failed" << endl;
		return -2;
	}
//4, 循环转换至文件结束 转换要用到SwsContex对象
	SwsContext* yuv2rgb = nullptr; //yuv -> rgba
	for(;;){
		//读取一帧的yuv数据
		ifs.read((char*)yuv[0], YUV_WIDTH * YUV_HEIGHT);
		ifs.read((char*)yuv[1], YUV_WIDTH * YUV_HEIGHT / 4);
		ifs.read((char*)yuv[2], YUV_WIDTH * YUV_HEIGHT / 4);
		//获取yuv转RGBA的上下文
		yuv2rgb = sws_getCachedContext(
				yuv2rgb,	//转换上下文, 如果是nullptr新建, 不是nullptr判断是否与现有参数一致, 一致直接返回, 不一致先清理原数据, 再新建
				YUV_WIDTH, YUV_HEIGHT, //输入数据的宽高
				 AV_PIX_FMT_YUV420P,  //输入的像素格式
				 RGB_WIDTH, RGB_HEIGHT, //输出数据的宽高
				 AV_PIX_FMT_RGBA,		//输出的像素格式
				 SWS_BILINEAR, 	 		//选择变换算法, 双线性插值算法
				 0,0,0					//过滤器参数
				);
		if(!yuv2rgb){
			cout << "sws_getCacheContext failed" << endl;
			return -4;
		}
		//通过格式转换上下文yuv2rgb开始转换
		int ret = sws_scale(yuv2rgb,
					yuv,		//输入数据
					yuv_linesize, //输入数据行字节数
					0,			//图像层次
					YUV_HEIGHT, //输入高度
					&rgba,		//输出的数据
					&rgba_linesize //输出的行大小
		);
		cout << ret << " " << flush;
		//写入文件
		ofs.write((char*)rgba, RGB_WIDTH  * RGB_HEIGHT  * 4);
		if(ifs.eof()) break;
	}
	ifs.close();
	ofs.close();



//rgb转yuv
	ifs.open(RGBA_FILE, ios::binary);
		if(!ifs){
		cout << "open file failed" << endl;
		return -5;
	}
	ofs.open("rgb2yuv.yuv", ios::binary);
	if(!ifs){
		cout << "open rgb2yuv.yuv failed" << endl;
		return -6;
	}
	SwsContext* rgb2yuv = nullptr; //rgba -> yuv
	for(;;){
		ifs.read((char*)rgba, RGB_WIDTH * RGB_HEIGHT * 4);
				rgb2yuv = sws_getCachedContext(
			rgb2yuv, //转换上下文, NULL新创建, 非NULL判断与现有参数是否一致, 一致直接返回, 不一致先清理原数据,然后再创建
			RGB_WIDTH, RGB_HEIGHT,  // 输入宽高
			AV_PIX_FMT_RGBA,		//输入像素格式
			YUV_WIDTH, YUV_HEIGHT,	//输出宽高
			AV_PIX_FMT_YUV420P,		//输出像素格式
			SWS_BILINEAR,			//选择变换算法, 双线性插值算法
			0, 0, 0					//过滤器参数
		);
		if(!rgb2yuv){
			cout << "sws_getCachedContext failed" << endl;
			return -7;
		}
		int ret = sws_scale(rgb2yuv,
			&rgba,			//输入数据
			&rgba_linesize,	//输入数据行字节数
			0,				//图像层次
			RGB_HEIGHT,			//输入高度
			yuv,			//输出的数据
			yuv_linesize //输出的行大小
		);
		cout << ret << " " << flush;


		ofs.write((char *)yuv[0], YUV_WIDTH * YUV_HEIGHT);
		ofs.write((char*)yuv[1], YUV_WIDTH * YUV_HEIGHT /4);
		ofs.write((char*)yuv[2], YUV_WIDTH* YUV_HEIGHT / 4);

		if (ifs.eof()) break;
	}





	ifs.close();
	ofs.close();
	delete yuv[0]; //别忘了清理空间
	delete yuv[1]; //别忘了清理空间
	delete yuv[2]; //别忘了清理空间
	delete rgba;//别忘了清理空间
	
	
}