RGB24转YUV420P实现

RGB24转YUV420P实现

/* rgb24 转 yuv420p */
/* 参考:https://blog.youkuaiyun.com/leixiaohua1020/article/details/50534150 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

static unsigned char clip_value(unsigned char val, unsigned char min_val, unsigned char max_val)
{
	if (val > max_val)
    {
		return max_val;
	}
    else if (val < min_val)
    {
		return min_val;
	}
    else
    {
		return val;
	}
}

static int __rgb24_to_yuv420p(unsigned char *rgb24_buf, int w, int h, unsigned char *yuv420p_buf)
{
    unsigned char *yuv420p_y = NULL;
    unsigned char *yuv420p_u = NULL;
    unsigned char *yuv420p_v = NULL;
    unsigned char *rgb24 = NULL;
    unsigned char y, u, v, r, g, b;
    int i, j;

    memset(yuv420p_buf, 0, (w * h * 3)/2);
    yuv420p_y = yuv420p_buf;
    yuv420p_u = yuv420p_buf + w * h;
    yuv420p_v = yuv420p_buf + w * h + (w * h)/4;


    // j可以理解图片中的各行
    for (j = 0; j < h; j++)
    {
        // rgb24指向图片中每一行的开始
        rgb24 = rgb24_buf + j * w * 3; // j * w * 3每一行所有像素点占用内存空间

        // i可以理解图片中一行中的每一个像素点
        for (i = 0; i < w; i++)
        {
            // 获取第i行中每一个像素点的r,g,b值
            r = *(rgb24++);
            g = *(rgb24++);
            b = *(rgb24++);
		
			// rgb转yuv计算公式
            // Y =  0.299*R + 0.587*G + 0.114*B
            // U = -0.147*R - 0.289*G + 0.463*B
            // V =  0.615*R - 0.515*G - 0.100*B
            // 按转换公式转换成y,u,v,转换成整数运算,避免浮点运算
            y = (unsigned char)(( 66 * r + 129 * g + 25  * b + 128) >> 8) + 16;
            u = (unsigned char)((-38 * r - 74  * g + 112 * b + 128) >> 8) + 128;
            v = (unsigned char)((112 * r - 94  * g - 18  * b + 128) >> 8) + 128;

            // 取全部的Y
            *(yuv420p_y++) = clip_value(y, 0, 255);

            if (j % 2 == 0)
            {
                // u取的是偶数行的偶数列,相当于宽、高都除2, 也就是w * h/4;
                if (i % 2 == 0)
                {
                    *(yuv420p_u++) = clip_value(u, 0, 255);
                }
            }
            else
            {
                // v取的是奇数行的偶数列,相当于宽、高都除2, 也就是w * h/4;
                if (i % 2 == 0)
                {
                    *(yuv420p_v++) = clip_value(v, 0, 255);
                }
            }
        }
    }

    return 0;
}

// 将rgb24图片转换成yuv420p格式图片
int rgb24_to_yuv420p(const char *file_rgb24, int w, int h, const char *file_yuv420p)
{
    FILE *fp_rgb24 = fopen(file_rgb24, "rb+");
    FILE *fp_yuv420p = fopen(file_yuv420p, "wb+");
    unsigned int rgb24_size = w * h * 3;
    unsigned int yuv420p_size = w * h * 3/2;

    unsigned char *rgb24_buf = (unsigned char *)malloc(rgb24_size);
    if (rgb24_buf == NULL)
    {
        printf("malloc error: rgb24_buf error\n");
        fclose(fp_rgb24);
        fclose(fp_yuv420p);
        return -1;
    }

    unsigned char *yuv420p_buf = (unsigned char *)malloc(yuv420p_size);
    if (rgb24_buf == NULL)
    {
        printf("malloc error: yuv420p_buf error\n");
        free(rgb24_buf);
        fclose(fp_rgb24);
        fclose(fp_yuv420p);
        return -1;
    }

    fread(rgb24_buf, 1, rgb24_size, fp_rgb24);
    __rgb24_to_yuv420p(rgb24_buf, w, h, yuv420p_buf);
    fwrite(yuv420p_buf, 1, yuv420p_size, fp_yuv420p);

    free(rgb24_buf);
    free(yuv420p_buf);
    fclose(fp_rgb24);
    fclose(fp_yuv420p);

    return 0;
}


int main(void)
{
    const char *file_rgb24 = "lena_256x256_rgb24.rgb";
    const char *file_yuv420p = "output_lena_256x256_yuv420p.yuv";

    rgb24_to_yuv420p(file_rgb24, 256, 256, file_yuv420p);

    return 0;
}

参考

视音频数据处理入门:RGB、YUV像素数据处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值