ffmpeg处理YUV422和YUV420P相互转换

YUV422空间大小计算
YUV422封包width*height+width/2*height*2
YUYV Y分量width*height
YUYV U分量width/2*height
YUYV V分量width/2*height

 YUV420空间大小计算

YUV420封包width*height+width/2*height/2*2
Y分量width*height
U分量width/2*height/2
V分量width/2*height/2

 

extern "C" {
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "avutil.lib")
 };

YUV422分量实现(YUYV)

static void YUYV422Planes(uint8_t *yuv422, uint8_t *y_ptr, uint8_t *u_ptr, uint8_t *v_ptr, int width, int height)
{
	//计算出空间大小
	int numBytes = width*height+width/2*height*2;
	unsigned int yIndex = 0;
	unsigned int uIndex = 0;
	unsigned int vIndex = 0;
	//分量
	for (unsigned int i = 0; i < numBytes; i += 4) {
		memcpy((unsigned char *)y_ptr + yIndex, yuv422+i, 1);
		yIndex++;
		memcpy((unsigned char *)u_ptr + uIndex, yuv422+i+1, 1);
		uIndex++;
		memcpy((unsigned char *)y_ptr + yIndex, yuv422+i+2, 1);
		yIndex++;
		memcpy((unsigned char *)v_ptr + vIndex, yuv422+i+3, 1);
		vIndex++;
	}
}

YUV422封包实现(YUYV)

static void YUYV422Packages(uint8_t *yuv422, uint8_t *y_ptr, uint8_t *u_ptr, uint8_t *v_ptr, int width, int height)
{
	//计算出空间大小
	int numBytes = width * height + width / 2 * height * 2;
	unsigned int yIndex = 0;
	unsigned int uIndex = 0;
	unsigned int vIndex = 0;
	//封包
	for (unsigned int i = 0; i < numBytes; i+=4) {
		//y
		memcpy((unsigned char *)yuv422+i,y_ptr+yIndex,1);
		yIndex++;
		//u
		memcpy((unsigned char *)yuv422+i+1, u_ptr+uIndex, 1);
		uIndex++;
		//y
		memcpy((unsigned char *)yuv422+i+2, y_ptr+yIndex, 1);
		yIndex++;
		//v
		memcpy((unsigned char *)yuv422+i+3, v_ptr+vIndex, 1);
		vIndex++;
	}
}

YUV420封包实现

static void YUV420PPackages(uint8_t *yuv420, uint8_t *y_ptr, uint8_t *u_ptr,
			    uint8_t *v_ptr, int width, int height)
{
	//Y分量的长度
	int yLen = width * height;
	//U和V分量的长度
	int uvLen = width / 2 * height / 2;
	memcpy((unsigned char *)yuv420, y_ptr, yLen);
	memcpy((unsigned char *)yuv420 + yLen, u_ptr, uvLen);
	memcpy((unsigned char *)yuv420+yLen+uvLen, v_ptr, uvLen);
}

YUV420分量实现

static void YUV420PPlanes(uint8_t *yuv420, uint8_t *y_ptr, uint8_t *u_ptr,
			  uint8_t *v_ptr, int width, int height)
{
	//Y分量的长度
	int yLen = width * height;
	//U和V分量的长度
	int uvLen = width / 2 * height / 2;
	memcpy((unsigned char *)y_ptr, yuv420, yLen);
	memcpy((unsigned char *)u_ptr, yuv420 + yLen, uvLen);
	memcpy((unsigned char *)v_ptr, yuv420 + yLen + uvLen, uvLen);
}

YUV420P转YUYV422

static void YUV420P_TO_YUYV422(uint8_t *yuv420p, void *y_ptr, void *u_ptr, void *v_ptr, int width, int height)
{
	AVFrame *Input_pFrame = nullptr;
	AVFrame *Output_pFrame = nullptr;
	struct SwsContext *img_convert_ctx = nullptr; //用于解码后的格式转换
	/*1. 申请空间*/
	Input_pFrame = av_frame_alloc();
	Output_pFrame = av_frame_alloc();
	/*2.设置转码参数*/
	img_convert_ctx =
		sws_getContext(width, height, AV_PIX_FMT_YUV420P, //输入
			       width, height, AV_PIX_FMT_YUYV422, //输出
			       SWS_BICUBIC, nullptr, nullptr, nullptr);
	int numBytes = avpicture_get_size(AV_PIX_FMT_YUYV422, width, height);
	//申请空间
	uint8_t *yuv422 = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
	/*3. 申请转码需要空间*/
	/*4. 设置转码的源数据地址*/
	avpicture_fill((AVPicture *)Input_pFrame, yuv420p, AV_PIX_FMT_YUV420P,
		       width, height);
	avpicture_fill((AVPicture *)Output_pFrame, yuv422, AV_PIX_FMT_YUYV422,
		       width, height);

	//转格式
	sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data,
		  Input_pFrame->linesize, 0, height, Output_pFrame->data,
		  Output_pFrame->linesize);

	//yuv422分量
	YUYV422Planes(yuv422, (uint8_t *)y_ptr, (uint8_t *)u_ptr,
		      (uint8_t *)v_ptr, width, height);

	//释放空间
	if (Input_pFrame)
		av_free(Input_pFrame);
	if (Output_pFrame)
		av_free(Output_pFrame);
	if (yuv422)
		av_free(yuv422);
	if (img_convert_ctx)
		sws_freeContext(img_convert_ctx);
}

YUYV转YUV420P格式

static void YUYV422_TO_YUV420P(uint8_t *yuyv422, uint8_t *yuv420p, int video_width, int video_height)
{
	AVFrame *Input_pFrame = nullptr;
	AVFrame *Output_pFrame = nullptr;
	struct SwsContext *img_convert_ctx = nullptr; //用于解码后的格式转换
	/*1. 申请空间*/
	Input_pFrame = av_frame_alloc();
	Output_pFrame = av_frame_alloc();
	/*2.设置转码参数*/
	img_convert_ctx = sws_getContext(
		video_width, video_height, AV_PIX_FMT_YUYV422, //输入
		video_width, video_height, AV_PIX_FMT_YUV420P, //输出
		SWS_BICUBIC, nullptr, nullptr, nullptr);
	/*3. 申请转码需要空间*/
	/*4. 设置转码的源数据地址*/
	avpicture_fill((AVPicture *)Input_pFrame, yuyv422, AV_PIX_FMT_YUYV422,
		       video_width, video_height);
	avpicture_fill((AVPicture *)Output_pFrame, yuv420p, AV_PIX_FMT_YUV420P,
		       video_width, video_height);

	//转格式
	sws_scale(img_convert_ctx, (uint8_t const **)Input_pFrame->data,
		  Input_pFrame->linesize, 0, video_height, Output_pFrame->data,
		  Output_pFrame->linesize);
	//释放空间
	if (Input_pFrame)
		av_free(Input_pFrame);
	if (Output_pFrame)
		av_free(Output_pFrame);
	if (img_convert_ctx)
		sws_freeContext(img_convert_ctx);
}


版权声明:本文为wu110112原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。