FFmpeg 像素格式和尺寸转换函数
双线性过滤(Bilinear_filtering)
代码
test_sws_scale.cpp
#include <iostream>
#include <fstream>
extern "C"
{
#include "libswscale/swscale.h"
}
#pragma comment(lib, "swscale.lib")
#define YUVFILE "400_300_25.yuv"
#define RGBAFILE "800_600_25.rgba"
using namespace std;
int main()
{
ifstream ifs;
ofstream ofs;
const int yuv_width = 400;
const int yuv_height = 300;
const int rgba_width = 800;
const int rgba_height = 600;
unsigned char* yuv[3] = { 0 };
SwsContext* yuv2rgba = nullptr;
SwsContext* rgba2yuv = nullptr;
int yuv_linesize[3] = { yuv_width , yuv_width / 2, yuv_width / 2 };
unsigned char* rgba = nullptr;
int rgba_linesize = rgba_width * 4;
int slice_height = 0;
yuv[0] = new unsigned char[yuv_width * yuv_height]; // Y
yuv[1] = new unsigned char[yuv_width * yuv_height / 4]; // U
yuv[2] = new unsigned char[yuv_width * yuv_height / 4]; // V
rgba = new unsigned char[rgba_width * rgba_height * 4];
ifs.open(YUVFILE, ios::in | ios::binary);
if (!ifs)
{
cerr << "open " << YUVFILE << " failed" << endl;
return -1;
}
ofs.open(RGBAFILE, ios::out | ios::binary);
if (!ofs)
{
cerr << "open " << RGBAFILE << " failed" << endl;
return -1;
}
/* YUV420P 转 RGBA */
for (int i = 0; i < 10; i++) // 读取10帧数据
{
/* 读取一帧的 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);
/* 文件已经读完 */
if (ifs.gcount() == 0)
{
break;
}
/* YUV转RGBA 上下文件创建和获取 */
yuv2rgba = sws_getCachedContext(
yuv2rgba, // 转换上下文,NULL新创建,非NULL判断与现有参数是否一致,
// 一致直接返回,不一致先清理当前然后再创建
yuv_width, yuv_height, // 输入宽高
AV_PIX_FMT_YUV420P, // 输入像素格式
rgba_width, rgba_height, // 输出的宽高
AV_PIX_FMT_RGBA, // 输出的像素格式
SWS_BILINEAR, // 选择支持变化的算法,双线性插值
nullptr, nullptr, nullptr // 过滤器参数
);
if (!yuv2rgba)
{
cerr << "sws_getCachedContext failed!" << endl;
return -1;
}
slice_height = sws_scale(
yuv2rgba,
yuv, // 输入数据
yuv_linesize, // 输入数据行字节数
0,
yuv_height, // 输入高度
&rgba, // 输出数据
&rgba_linesize
);
ofs.write((char*)rgba, rgba_width * rgba_height * 4); // 将转换后的 RGBA 数据写入到 rgba 文件中
cout << slice_height << " " << flush;
}
ifs.close();
ofs.close();
ifs.open(RGBAFILE, ios::in | ios::binary);
if (!ifs)
{
cerr << "open " << YUVFILE << " failed" << endl;
return -1;
}
/* 将 RGBA 转成 YUV420P */
for (;;)
{
/* 读取一帧的 RGBA 数据 */
ifs.read((char*)rgba, rgba_width * rgba_height * 4);
/* 文件已经读完 */
if (ifs.gcount() == 0)
{
break;
}
/* RGBA 转 YUV 上下文件创建和获取 */
rgba2yuv = sws_getCachedContext(
rgba2yuv, // 转换上下文,NULL新创建,非NULL判断与现有参数是否一致,
// 一致直接返回,不一致先清理当前然后再创建
rgba_width, rgba_height, // 输入宽高
AV_PIX_FMT_RGBA, // 输入像素格式
yuv_width, yuv_height, // 输出的宽高
AV_PIX_FMT_YUV420P, // 输出的像素格式
SWS_BILINEAR, // 选择支持变化的算法,双线性插值
nullptr, nullptr, nullptr // 过滤器参数
);
if (!rgba2yuv)
{
cerr << "sws_getCachedContext failed!" << endl;
return -1;
}
slice_height = sws_scale(
rgba2yuv,
&rgba, // 输入数据
&rgba_linesize, // 输入数据行字节数
0,
rgba_height, // 输入高度
yuv, // 输出数据
yuv_linesize
);
cout << "(" << slice_height << ")" << " " << flush;
}
ifs.close();
delete[] yuv[0];
delete[] yuv[1];
delete[] yuv[2];
delete[] rgba;
return 0;
}
实现了 YUV420P 和 RGBA 图像不同尺寸不同像素格式之间的转换。
测试结果