RGB24 To Yuv420 C语言实现

RGB24 To Yuv420 C语言实现(非SIMD版本)

以下代码来自 libyuv

#include <stdint.h>

//下面三个函数为RGB-->>Yuv420的公式
static __inline int RGBToYJ(uint8_t r, uint8_t g, uint8_t b)
{
	return (38 * r + 75 * g + 15 * b + 64) >> 7;
}
static __inline int RGBToUJ(uint8_t r, uint8_t g, uint8_t b)
{
	return (127 * b - 84 * g - 43 * r + 0x8080) >> 8;
}
static __inline int RGBToVJ(uint8_t r, uint8_t g, uint8_t b)
{
	return (127 * r - 107 * g - 20 * b + 0x8080) >> 8;
}

//取平均值
#define AVGB(a, b) (((a) + (b) + 1) >> 1)

#define R 2					//R的顺序
#define G 1					//G的顺序
#define B 0					//B的顺序
#define BPP 3				//BPP是一个像素占的字节数

void RGB24ToYRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width) {

	int x;
	for (x = 0; x < width; ++x) {
		
		dst_y[0] = RGBToYJ(src_rgb[R], src_rgb[G], src_rgb[B]);
		src_rgb += BPP; /*BPP == 3*/
		dst_y += 1;
	}
}
void RGB24ToUVRow_C(const uint8_t* src_rgb, int src_stride_rgb, uint8_t* dst_u, uint8_t* dst_v, int width)
{
	const uint8_t* src_rgb1 = src_rgb + src_stride_rgb;
	int x;
	for (x = 0; x < width - 1; x += 2)//一次处理两行
	{
		//U,V采样方式:四个像素(边长为2像素的正方形,如下)RGB值的平均值,再计算出U,V
		//      p1  p2    这是第一行的两个像素
		//      p3  p4    这是第二行的两个像素
		uint8_t ab = AVGB(AVGB(src_rgb[B], src_rgb1[B]), AVGB(src_rgb[B + BPP], src_rgb1[B + BPP]));
		uint8_t ag = AVGB(AVGB(src_rgb[G], src_rgb1[G]), AVGB(src_rgb[G + BPP], src_rgb1[G + BPP]));
		uint8_t ar = AVGB(AVGB(src_rgb[R], src_rgb1[R]), AVGB(src_rgb[R + BPP], src_rgb1[R + BPP]));
		dst_u[0] = RGBToUJ(ar, ag, ab);
		dst_v[0] = RGBToVJ(ar, ag, ab);
		src_rgb += BPP * 2;
		src_rgb1 += BPP * 2;
		dst_u += 1;
		dst_v += 1;
	}
	if (width & 1)//奇数行的情况下,最后一行只对两个像素求平均
	{
		uint8_t ab = AVGB(src_rgb[B], src_rgb1[B]);
		uint8_t ag = AVGB(src_rgb[G], src_rgb1[G]);
		uint8_t ar = AVGB(src_rgb[R], src_rgb1[R]);
		dst_u[0] = RGBToUJ(ar, ag, ab);
		dst_v[0] = RGBToVJ(ar, ag, ab);
	}
}

/*
src_rgb24: rgb24数据,注意顺序为BGR
src_stride_rgb24: 一行像素点占用的字节数,循环的时候换行要用到(此处应该是width * 3,然后结果补成4的倍数)

dst_y: 存放y平面的地址 
dst_stride_y: 和src_stride_rgb24类似,只是这里应该是width

..后面的参数参考前面即可

width: 图像宽度(单位:像素)
height: 图像高度 (单位:像素)
*/
int RGB24ToI420(const uint8_t* src_rgb24, int src_stride_rgb24, uint8_t* dst_y, int dst_stride_y, uint8_t* dst_u, int dst_stride_u, uint8_t* dst_v, int dst_stride_v, int width, int height)
{
	int y;
	void(*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
		uint8_t* dst_u, uint8_t* dst_v, int width) =
		RGB24ToUVRow_C;
	void(*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
		RGB24ToYRow_C;

	if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
		return -1;
	}

	if (height < 0) {
		height = -height;
		src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
		src_stride_rgb24 = -src_stride_rgb24;
	}

	for (y = 0; y < height - 1; y += 2)	//一次处理两行
	{

		RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
		RGB24ToYRow(src_rgb24, dst_y, width);
		RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
		src_rgb24 += src_stride_rgb24 * 2;
		dst_y += dst_stride_y * 2;
		dst_u += dst_stride_u;
		dst_v += dst_stride_v;
	}
	if (height & 1)	//高度为奇数的话,再单独处理最后一行
	{
		RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
		RGB24ToYRow(src_rgb24, dst_y, width);
	}
	return 0;
}

性能测试: 转换一张1920x1080图片用时:30ms(SIMD版本用时<1ms)

测试机器: 在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suspend.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值