YUV420转RGBA

今天发现,在ffmpeg解码mp4视频的libavformat/mov.c中,有一个YUV420转RGBA的函数,特意单独提取出来,供以后参考,具体如下:

static uint32_t yuv_to_rgba(uint32_t ycbcr)
{
    uint8_t r, g, b;
    int y, cb, cr;

    y  = (ycbcr >> 16) & 0xFF;
    cr = (ycbcr >> 8)  & 0xFF;
    cb =  ycbcr        & 0xFF;

    b = av_clip_uint8((1164 * (y - 16)                     + 2018 * (cb - 128)) / 1000);
    g = av_clip_uint8((1164 * (y - 16) -  813 * (cr - 128) -  391 * (cb - 128)) / 1000);
    r = av_clip_uint8((1164 * (y - 16) + 1596 * (cr - 128)                    ) / 1000);

    return (r << 16) | (g << 8) | b;
}


上面的转换公式对于一般自己写格式转换的时候比较有用,但是ffmpeg其实是用汇编写的这个转换函数,据说速度是非常非常快的。

// ffmpeg-3.2.4/libavformat/movenc.c [2023-09-20]
static uint32_t rgb_to_yuv(uint32_t rgb)
{
    uint8_t r, g, b;
    int y, cb, cr;

    r = (rgb >> 16) & 0xFF;
    g = (rgb >>  8) & 0xFF;
    b = (rgb      ) & 0xFF;

    y  = av_clip_uint8(( 16000 +  257 * r + 504 * g +  98 * b)/1000);
    cb = av_clip_uint8((128000 -  148 * r - 291 * g + 439 * b)/1000);
    cr = av_clip_uint8((128000 +  439 * r - 368 * g -  71 * b)/1000);

    return (y << 16) | (cr << 8) | cb;
}

在Java中将RGBA(红、绿、蓝、透明度)颜色空间换为YUV420P(逐行扫描,主要用于图像压缩)通常涉及到色彩模型的数学变换。由于RGBYUV都是常见的色彩空间,但它们之间的映射不是线性的,所以需要一些公式来完成这个换。 这里提供一个简化的步骤概述: 1. 分离Alpha通道(如果存在):如果RGBA有Alpha通道,首先提取出来并单独处理,因为YUV不包含透明度信息。 ```java float alpha = rgba.getAlpha(); Color colorWithoutAlpha = new Color(rgba.getRed(), rgba.getGreen(), rgba.getBlue()); ``` 2. 将RGB换为亮度Y和色差UV:对于每个像素(R, G, B),分别计算亮度Y和色差分量U/V。常见的公式是: - Y = 0.299 * R + 0.587 * G + 0.114 * B - V = 0.596 * (B - Y) - 0.1687 * (G - Y) - U = 0.439 * (R - Y) - 0.3114 * (B - Y) 3. YUV420P格式的处理:YUV420P采用逐行扫描的方式,其中U和V数据通常是每四个Y样本中的一对。因此,你需要将UV数据进行适当的插值或打包成对应的4x4网格(例如,对于一个宽高比为16:9的图像,宽度上每8个Y样本会有一个UV块)。 4. 结果存储:将换后的Y、U、V数组分别存储到YUV420P的数据结构中,比如`byte[]`数组。 以下是伪代码示例: ```java // 假设rgba为ARGBInt数组,width和height为图像尺寸 int[] yuv = new int[width * height]; int yIndex = 0; for (int i = 0; i < height; i++) { for (int j = 0; j < width / 2; j++) { // 只处理半宽,因为YUV420P是奇数像素 int r = rgba[j * 4]; int g = rgba[j * 4 + 1]; int b = rgba[j * 4 + 2]; float y = calculateY(r, g, b); float u = calculateU(r, g, b); float v = calculateV(r, g, b); yuv[yIndex++] = (int) Math.round(y); // Y if ((i + j) % 2 == 0) { // 每两个Y样本有一个UV块 // 对UV进行插值或其他处理,然后存储到yuv数组对应位置 } } } ``` 请注意,以上代码是一个简化版本,实际的颜色换可能会更复杂,包括考虑浮点精度和色彩空间间的校准系数等。如果你打算在生产环境中使用,建议参考相关的图像处理库,如Apache Commons Imaging或JTransforms。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值