You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ProRes 422视频转Metal着色器:YpCbCr转RGB画面发紫问题

解决ProRes 422视频在Metal着色器里YpCbCr转RGB偏紫的问题

1. 先修正纹理格式,这是偏紫的核心原因

你当前创建Metal纹理用的是.bgrg422(RGB类格式),但从AVPlayer获取的像素缓冲区是kCVPixelFormatType_422YpCbCr8(YUV格式),格式完全不匹配导致数据解析错误,这是画面偏紫的主要原因。

把纹理创建的格式改成与像素缓冲区对应的YUV格式:

CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, pixelBuffer, nil, .ycbcr422, width, height, 0, &cvTexture)

2. 编写正确的Metal片段着色器转换逻辑

格式匹配后,需要在着色器里正确解析YUV数据并转换为RGB。ProRes通常采用BT.709转换标准,同时要注意YUV范围的归一化处理:

#include <metal_stdlib>
using namespace metal;

fragment float4 ycbcr_to_rgb(texture2d<half, access::sample> ycbcrTex [[texture(0)]],
                             float2 texCoord [[texture_coord(0)]]) {
    // 采样YUV纹理:packed 422格式每个纹理像素存储两个Y分量、一个Cb、一个Cr
    half4 ycbcrData = ycbcrTex.sample(sampler(coord::normalized, address::clamp_to_edge, filter::linear), texCoord);
    
    // 根据纹理坐标的奇偶性选取对应的Y分量
    half y = fract(texCoord.x * ycbcrTex.get_width()) < 0.5 ? ycbcrData.x : ycbcrData.z;
    half cb = ycbcrData.y;
    half cr = ycbcrData.w;
    
    // 将YUV从视频标准范围(Y:16-235,CbCr:16-240)转换为0-1的浮点范围
    y = (y - 16.0/255.0) / (219.0/255.0);
    cb = (cb - 128.0/255.0) / (224.0/255.0);
    cr = (cr - 128.0/255.0) / (224.0/255.0);
    
    // 采用BT.709标准转换为RGB
    half r = y + 1.5748 * cr;
    half g = y - 0.1873 * cb - 0.4681 * cr;
    half b = y + 1.8556 * cb;
    
    // 限制RGB值在0-1区间,避免颜色溢出
    r = clamp(r, 0.0, 1.0);
    g = clamp(g, 0.0, 1.0);
    b = clamp(b, 0.0, 1.0);
    
    return float4(r, g, b, 1.0);
}

3. 额外检查项

  • 打印CVPixelBufferGetPixelFormatType(pixelBuffer)确认像素格式确实是kCVPixelFormatType_422YpCbCr8,避免格式混淆。
  • 确保纹理宽高与像素缓冲区宽高完全一致,防止拉伸导致颜色错位。
  • 采样器坐标模式设置为normalized,避免使用像素坐标导致采样位置错误。

内容的提问来源于stack exchange,提问作者JoeBayLD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:43:13