像素数据格式的转换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;//别忘了清理空间
}