YUV4:2:0转RGB后图像偏绿的D3D11渲染问题排查
YUV420转RGB渲染偏绿问题排查
问题背景
解码得到YUV420平面帧(UV分量未打包),使用D3D11渲染时需转换为RGB格式(假设渲染目标视图不支持YUV)。创建3个DXGI_FORMAT_R8_UNORM类型的纹理和ShaderResourceView,将帧的每个平面数据复制到对应视图,依靠采样器处理Y与UV平面的尺寸差异。黑白画面显示正常,但彩色画面严重偏绿。已尝试交换UV平面、调整转换系数,遵循官方图像转换指南,问题仍未解决。
相关代码
像素着色器代码
min16float4 main(PixelShaderInput input) : SV_TARGET { float y = YChannel.Sample(defaultSampler, input.texCoord).r; float u = UChannel.Sample(defaultSampler, input.texCoord).r - 0.5; float v = VChannel.Sample(defaultSampler, input.texCoord).r - 0.5; float r = y + 1.13983 * v; float g = y - 0.39465 * u - 0.58060 * v; float b = y + 2.03211 * u; return min16float4(r, g, b , 1.f); }
创建ShaderResourceView代码
D3D11_TEXTURE2D_DESC texDesc; ZeroMemory(&texDesc, sizeof(texDesc)); texDesc.Width = 1670; texDesc.Height = 626; texDesc.MipLevels = 1; texDesc.ArraySize = 1; texDesc.Format = DXGI_FORMAT_R8_UNORM; texDesc.SampleDesc.Count = 1; texDesc.SampleDesc.Quality = 0; texDesc.Usage = D3D11_USAGE_DYNAMIC; texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; dev->CreateTexture2D(&texDesc, NULL, &pYPictureTexture); dev->CreateTexture2D(&texDesc, NULL, &pUPictureTexture); dev->CreateTexture2D(&texDesc, NULL, &pVPictureTexture); D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc; shaderResourceViewDesc.Format = DXGI_FORMAT_R8_UNORM; shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; shaderResourceViewDesc.Texture2D.MostDetailedMip = 0; shaderResourceViewDesc.Texture2D.MipLevels = 1; dev->CreateShaderResourceView(pYPictureTexture, &shaderResourceViewDesc, &pYPictureTextureResourceView); dev->CreateShaderResourceView(pUPictureTexture, &shaderResourceViewDesc, &pUPictureTextureResourceView); dev->CreateShaderResourceView(pVPictureTexture, &shaderResourceViewDesc, &pVPictureTextureResourceView);
复制FFmpeg解码后AVFrames代码
int height = 626; int width = 1670; D3D11_MAPPED_SUBRESOURCE msY; D3D11_MAPPED_SUBRESOURCE msU; D3D11_MAPPED_SUBRESOURCE msV; devcon->Map(pYPictureTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &msY); memcpy(msY.pData, frame->data[0], height * width); devcon->Unmap(pYPictureTexture, 0); devcon->Map(pUPictureTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &msU); memcpy(msU.pData, frame->data[1], (height*width) / 4); devcon->Unmap(pUPictureTexture, 0); devcon->Map(pVPictureTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &msV); memcpy(msV.pData, frame->data[2], (height*width) / 4); devcon->Unmap(pVPictureTexture, 0);
问题排查方向
- UV纹理尺寸错误:YUV420的UV平面宽高应为Y平面的1/2(即Width=835,Height=313),当前UV纹理和Y平面尺寸一致,采样时会重复读取数据导致色彩偏移。
- 行间距(Pitch)未正确处理:FFmpeg的
AVFrame->linesize可能大于实际宽度,直接用height*width拷贝会导致数据错位,应使用linesize[0]、linesize[1]、linesize[2]计算拷贝字节数,逐行拷贝而非直接memcpy整个区域。 - 色彩空间系数不匹配:当前转换系数对应BT.601标准,若视频为BT.709格式,需调整系数:
float r = y + 1.5748 * v; float g = y - 0.1873 * u - 0.4681 * v; float b = y + 1.8556 * u; - 采样器设置问题:确保采样器使用
D3D11_FILTER_MIN_MAG_MIP_LINEAR,地址模式设置合理,避免UV采样时拉伸错误。
内容的提问来源于stack exchange,提问作者luckybroma
相关产品推荐
相关产品推荐

