NV12纹理在DirectX 11.1中不起作用

时间:2017-03-27 15:47:02

标签: c++ ffmpeg directx

我正在尝试使用DirectX 11.1从使用ffmpeg 2.8.11解码的帧渲染NV12纹理,但是当我渲染它们时纹理被破坏并且颜色总是关闭。

结果是:http://imgur.com/a/YIVQk

以下代码是如何通过ffmpeg解码YUV420P格式的帧,然后通过交错U和V平面将(不确定)转换为NV12格式。

static uint8_t *pixelsPtr_ = nullptr;

UINT rowPitch = ((width + 1) >> 1) * 2;
UINT imageSize = (rowPitch * height) + ((rowPitch * height + 1) >> 1);

if (!pixelsPtr_)
{
    pixelsPtr_ = new uint8_t[imageSize];
}

int j, position = 0;

uint32_t pitchY = avFrame.linesize[0];
uint32_t pitchU = avFrame.linesize[1];
uint32_t pitchV = avFrame.linesize[2];

uint8_t *avY = avFrame.data[0];
uint8_t *avU = avFrame.data[1];
uint8_t *avV = avFrame.data[2];

::SecureZeroMemory(pixelsPtr_, imageSize);

for (j = 0; j < height; j++)
{               
    ::CopyMemory(pixelsPtr_ + position, avY, (width));
    position += (width);
    avY += pitchY;
}

for (j = 0; j < height >> 1; j++)
{
    ::CopyMemory(pixelsPtr_ + position, avU, (width >> 1));
    position += (width >> 1);
    avU += pitchU;

    ::CopyMemory(pixelsPtr_ + position, avV, (width >> 1));
    position += (width >> 1);
    avV += pitchV;
}

这就是我用我刚刚获得的数据创建Texture2D的方法。

// Create texture
D3D11_TEXTURE2D_DESC desc;
desc.Width = width;
desc.Height = height;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_NV12;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;

D3D11_SUBRESOURCE_DATA initData;
initData.pSysMem = pixelsPtr_;
initData.SysMemPitch = rowPitch;

ID3D11Texture2D* tex = nullptr;
hr = d3dDevice->CreateTexture2D(&desc, &initData, &tex);
if (SUCCEEDED(hr) && tex != 0)
{
    D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
    memset(&SRVDesc, 0, sizeof(SRVDesc));
    SRVDesc.Format = DXGI_FORMAT_R8_UNORM;
    SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    SRVDesc.Texture2D.MipLevels = 1;

    hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, &textureViewYUV[0]);
    if (FAILED(hr))
    {
        tex->Release();
        return hr;
    }

    SRVDesc.Format = DXGI_FORMAT_R8G8_UNORM;

    hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, &textureViewYUV[1]);
    if (FAILED(hr))
    {
        tex->Release();
        return hr;
    }

    tex->Release();
}

然后我将Shader Resource View传递给Pixel Shader

graphics->Context()->PSSetShaderResources(0, 2, textureViewYUV);

这是像素着色器:

struct PixelShaderInput
{
    float4 pos         : SV_POSITION;
    float4 Color       : COLOR;
    float2 texCoord    : TEXCOORD;
};

static const float3x3 YUVtoRGBCoeffMatrix =
{
    1.164383f,  1.164383f, 1.164383f,
    0.000000f, -0.391762f, 2.017232f,
    1.596027f, -0.812968f, 0.000000f
};

Texture2D<float>  luminanceChannel;
Texture2D<float2> chrominanceChannel;

SamplerState linearfilter
{
    Filter = MIN_MAG_MIP_LINEAR;
};

float3 ConvertYUVtoRGB(float3 yuv)
{
    // Derived from https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx
    // Section: Converting 8-bit YUV to RGB888

    // These values are calculated from (16 / 255) and (128 / 255)
    yuv -= float3(0.062745f, 0.501960f, 0.501960f);
    yuv = mul(yuv, YUVtoRGBCoeffMatrix);

    return saturate(yuv);
}

float4 main(PixelShaderInput input) : SV_TARGET
{
    float y = luminanceChannel.Sample(linearfilter, input.texCoord);
    float2 uv = chrominanceChannel.Sample(linearfilter, input.texCoord);

    float3 YUV = float3(y, uv.x, uv.y);
    float4 YUV4 = float4(YUV.x, YUV.y, YUV.z, 1);

    float3 RGB = ConvertYUVtoRGB(YUV);
    float4 RGB4 = float4(RGB.x, RGB.y, RGB.z, 1);

    return RGB4;
}

有人能帮助我吗?我做错了什么?

编辑#1

int skipLineArea = 0;
int uvCount = (height >> 1) * (width >> 1);

for (j = 0, k = 0; j < uvCount; j++, k++)
{
    if (skipLineArea == (width >> 1))
    {
        k += pitchU - (width >> 1);
        skipLineArea = 0;
    }

    pixelsPtr_[position++] = avU[k];
    pixelsPtr_[position++] = avV[k];
    skipLineArea++;
}

编辑#2

更新纹理而不是创建新纹理

D3D11_MAPPED_SUBRESOURCE mappedResource;
d3dContext->Map(tex, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);

uint8_t* mappedData = reinterpret_cast<uint8_t*>(mappedResource.pData);

for (UINT i = 0; i < height * 1.5; ++i)
{
    memcpy(mappedData, frameData, rowPitch);
    mappedData += mappedResource.RowPitch;
    frameData += rowPitch;
}

d3dContext->Unmap(tex, 0);

1 个答案:

答案 0 :(得分:1)

NV12格式不会将UV值分开。它们是交错的NV12 format。您应该使用IMC4纹理格式。或者,您可以更改复制代码以交错UV值。