sws_scale像素格式转换RGBA转YUV420P

FFmpeg 像素格式和尺寸转换函数

sws_scale像素格式转换RGBA转YUV420P_第1张图片

sws_scale像素格式转换RGBA转YUV420P_第2张图片 

双线性过滤(Bilinear_filtering)

sws_scale像素格式转换RGBA转YUV420P_第3张图片

代码

test_sws_scale.cpp

#include 
#include 

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 图像不同尺寸不同像素格式之间的转换。

测试结果

 

你可能感兴趣的:(音视频,音视频)