C++
FFMPEG实现YUV与RGBA互转
  • By刘立博
  • 2021-01-10 23:07:41
  • 2749人已阅读

程序流程设计

 

函数简介

 

获取转换上下文 sws_getCachedContext()

 

struct SwsContext *context :如果传入的上下文为NULL,则会创建上下文。如果不为NULL则会查找缓存中的上下文,若存在则返回指针,若不存在则会创建一个新的上下文。

int srcW : 输入视频宽度

int srcH : 输入视频高度

enum AVPixelFormat srcFormat : 输入视频像素格式

int dstW : 输出视频宽度

int dstH : 输出视频高度

enum AVPixelFormat dstFormat : 输出视频像素格式

int flags : 转换算法

SwsFilter *srcFilter : 输入视频过滤器

SwsFilter *dstFilter : 输出视频过滤器

const double *param : 配置项

 

 

转换图像像素和尺寸 int sws_scale()

转换输入图像,并将结果存储在输出图像数据指针

 

struct SwsContext *c : 转换上下文

const uint8_t *const srcSlice[] : 输入图像数据指针

const int srcStride[] : 输入图像每行字节数

int srcSliceY : 输入图像处理起点

int srcSliceH : 输入图像处理行数

uint8_t *const dst[] :输出图像数据指针

const int dstStride[] : 输出图像每行字节数

 

 

YUV与RGBA互转

读取YUV文件test.yuv将其转换为1280X720的RGBA文件testOut.rgba

再读取testOut.rgba将其转换为1280X720的YUV文件testOut.yuv

 

#include <iostream>
#include <fstream>
using namespace std;

extern "C" {
#include <libswscale/swscale.h>
}

#pragma comment(lib,"swscale.lib")

int main(int argc, char* argv[])
{
	int srcWidth = 1280;
	int srcHeight = 720;

	int desWidth = 1280;
	int desHeight = 720;
	
	unsigned char* yuvData[3] = { 0 };

	int yuvLineSize[3] = { srcWidth,srcWidth / 2,srcWidth / 2 };
	yuvData[0] = new unsigned char[srcWidth * srcHeight];
	yuvData[1] = new unsigned char[srcWidth * srcHeight/4];
	yuvData[2] = new unsigned char[srcWidth * srcHeight/4];

	unsigned char* rgbaData = new unsigned char[desWidth * desHeight * 4];
	int rgbaLineSize = desWidth * 4;

	ifstream ifs;
	ifs.open("test.yuv", ios::binary);

	ofstream ofs;
	ofs.open("testOut.rgba",ios::binary);

	SwsContext* yuv2Rgba = nullptr;
	for (;;)
	{
		//读取YUV
		ifs.read((char*)yuvData[0], srcWidth * srcHeight);
		ifs.read((char*)yuvData[1], srcWidth * srcHeight/4);
		ifs.read((char*)yuvData[2], srcWidth * srcHeight/4);

		if (ifs.gcount() == 0) break;

		//获取上下文
		yuv2Rgba = sws_getCachedContext(
			yuv2Rgba,
			srcWidth,srcHeight,AV_PIX_FMT_YUV420P,
			desWidth,desHeight,AV_PIX_FMT_RGBA,
			SWS_BILINEAR,
			0,0,0
		);

		unsigned char* desData[1];
		desData[0] = rgbaData;
		int desLineSize[1] = { rgbaLineSize };

		//YUV转RGBA
		int r = sws_scale(
			yuv2Rgba,
			yuvData,
			yuvLineSize,
			0,
			desHeight,
			desData,
			desLineSize
		);

		//写入文件
		ofs.write((char*)rgbaData, desWidth * desHeight * 4);
		cout << r << endl;
	}

	cout << "rgba 2 yuv" << endl;

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

	ifs.open("testOut.rgba", ios::binary);
	ofs.open("testOut.yuv", ios::binary);

	SwsContext* rgba2yuv = nullptr;

	for (;;)
	{
		//读取RGBA文件
		ifs.read((char*)rgbaData, desWidth * desHeight * 4);
		if (ifs.gcount() == 0) break;

		//获取上下文
		rgba2yuv = sws_getCachedContext(
			rgba2yuv,
			desWidth,desHeight,
			AV_PIX_FMT_RGBA,
			srcWidth,srcHeight,
			AV_PIX_FMT_YUV420P,
			SWS_BILINEAR,
			0,0,0
		);

		unsigned char* data[1];
		data[0] = rgbaData;
		int srcLineSize[1] = { rgbaLineSize };

		//RGBA转YUV
		int r = sws_scale(
			rgba2yuv,
			data,
			srcLineSize,
			0,
			desHeight,
			yuvData,
			yuvLineSize
		);

		//写入YUV文件
		ofs.write((char*)rgbaData, desWidth * desHeight * 2);
		cout << r << endl;
	}


	delete yuvData[0];
	delete yuvData[1];
	delete yuvData[2];
	delete rgbaData;

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

	return 0;
}