C实现RGBA转NV12

static inline uint8_t clip(int v)
{
    return v < 0 ? 0 : v > 255 ? 255 : v;
}

// 计算alpha混合后的rgb
static inline void get_rgba_blend(const uint8_t* rgba, int idx, uint8_t bg_r, uint8_t bg_g, uint8_t bg_b, int src_w,
                                  int src_h, int i, int j, uint8_t* r, uint8_t* g, uint8_t* b)
{
    if (i < src_w && j < src_h) {
        uint8_t R = rgba[idx];
        uint8_t G = rgba[idx + 1];
        uint8_t B = rgba[idx + 2];
        uint8_t A = rgba[idx + 3];
        if (A == 0) {
            *r = bg_r;
            *g = bg_g;
            *b = bg_b;
        } else if (A == 255) {
            *r = R;
            *g = G;
            *b = B;
        } else {
            *r = (R * A + bg_r * (255 - A)) / 255;
            *g = (G * A + bg_g * (255 - A)) / 255;
            *b = (B * A + bg_b * (255 - A)) / 255;
        }
    } else {
        *r = bg_r;
        *g = bg_g;
        *b = bg_b;
    }
}

/**
 * @brief 将RGBA格式图像数据转换为NV12格式。
 *
 * 自动对齐到偶数宽高,对齐部分填充为背景色
 * 支持Alpha通道混合:若像素完全不透明则直接采样,若完全透明则用背景色,半透明时则与背景色按Alpha值混合。
 *
 * @param rgba    源RGBA像素数据,按行优先,每像素4字节(R,G,B,A)。
 * @param src_w   源图像宽度
 * @param src_h   源图像高度
 * @param nv12  输出缓冲区,需至少分配 w*h*3/2 字节,w h为对齐后的尺寸
 * @param bgcolor 背景色,RGB
 */
static void rgba_to_nv12(const uint8_t* rgba, int src_w, int src_h, uint8_t* nv12, uint32_t bgcolor)
{
    // 计算对齐后的尺寸
    int w      = (src_w + 1) & ~1;
    int h      = (src_h + 1) & ~1;
    int y_size = w * h;

    uint8_t* y_plane  = nv12;
    uint8_t* uv_plane = nv12 + y_size;

    uint8_t bg_r = (bgcolor >> 16) & 0xFF;
    uint8_t bg_g = (bgcolor >> 8) & 0xFF;
    uint8_t bg_b = bgcolor & 0xFF;

    // 填充Y分量
    for (int j = 0; j < h; ++j) {
        for (int i = 0; i < w; ++i) {
            uint8_t r, g, b;
            int idx = (j * src_w + i) * 4;
            get_rgba_blend(rgba, idx, bg_r, bg_g, bg_b, src_w, src_h, i, j, &r, &g, &b);
            int y              = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
            y_plane[j * w + i] = clip(y);
        }
    }

    // 填充UV分量
    for (int j = 0; j < h; j += 2) {
        for (int i = 0; i < w; i += 2) {
            int r_sum = 0, g_sum = 0, b_sum = 0;
            for (int jj = 0; jj < 2; ++jj) {
                for (int ii = 0; ii < 2; ++ii) {
                    int x = i + ii, y = j + jj;
                    int idx = (y * src_w + x) * 4;
                    uint8_t r, g, b;
                    get_rgba_blend(rgba, idx, bg_r, bg_g, bg_b, src_w, src_h, x, y, &r, &g, &b);
                    r_sum += r;
                    g_sum += g;
                    b_sum += b;
                }
            }
            int r                = r_sum / 4;
            int g                = g_sum / 4;
            int b                = b_sum / 4;
            int u                = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
            int v                = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
            int uv_idx           = (j / 2) * w + i;
            uv_plane[uv_idx]     = clip(u);
            uv_plane[uv_idx + 1] = clip(v);
        }
    }
}

你可能感兴趣的:(c语言,算法,rgba,nv12,yuv)