0

I create a NV12 texture with cpu access, and use shaderResource to map Luma and Chroma, then copy decoded frame with NV12 format to it, since 1080p is 1920x1088 in buffer actually, so i dropped the bottom 8px data.

  // Create NV12Texture
  bool Texture::CreateNV12Texture(uint32_t width, uint32_t height)
  {
      HRESULT hr;
      xres = width;
      yres = height;
      real_yres = yres;
      if (yres == 1088)
      {
          real_yres = 1080;
      }
      D3D11_TEXTURE2D_DESC const texDesc = CD3D11_TEXTURE2D_DESC(
          DXGI_FORMAT_NV12,           // HoloLens PV camera format, common for video sources
          xres,                 // Width of the video frames
          real_yres,                    // Height of the video frames
          1,                          // Number of textures in the array
          1,                          // Number of miplevels in each texture
          D3D11_BIND_SHADER_RESOURCE, // We read from this texture in the shader
          D3D11_USAGE_DYNAMIC,        // Because we'll be copying from CPU memory
          D3D11_CPU_ACCESS_WRITE      // We only need to write into the texture
      );
      hr = device->CreateTexture2D(&texDesc, nullptr, &nv12_texture);
      if (FAILED(hr))
          return false;

      D3D11_SHADER_RESOURCE_VIEW_DESC const luminancePlaneDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
          nv12_texture,
          D3D11_SRV_DIMENSION_TEXTURE2D,
          DXGI_FORMAT_R8_UNORM
      );
      hr = device->CreateShaderResourceView(
          nv12_texture,
          &luminancePlaneDesc,
          &luminanceView
      );
      if (FAILED(hr))
          return false;

      D3D11_SHADER_RESOURCE_VIEW_DESC const chrominancePlaneDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
          nv12_texture,
          D3D11_SRV_DIMENSION_TEXTURE2D,
          DXGI_FORMAT_R8G8_UNORM
      );

      hr = device->CreateShaderResourceView(
          nv12_texture,
          &chrominancePlaneDesc,
          &chrominanceView
      );
      if (FAILED(hr))
          return false;

      D3D11_TEXTURE2D_DESC desc = { 0 };
      nv12_texture->GetDesc(&desc);
      desc.BindFlags = D3D11_BIND_RENDER_TARGET;
      desc.CPUAccessFlags = 0;
      desc.Usage = D3D11_USAGE_DEFAULT;
      hr = device->CreateTexture2D(&desc, 0, &d3d_texture);
      if (FAILED(hr))
          return false;

      return true;
  }

  // copy frame to texture
  bool Texture::updateNV12(const uint8_t* data, size_t data_size)
  {
      assert(data);
      assert(data_size == xres * yres * 6 / 4);
      HRESULT hr = S_OK;

      // NV12 Copy
      int stride_y = xres;
      uint8_t* src_y = (uint8_t*)data;
      uint8_t* src_uv = src_y + stride_y * yres;

      // COPY
      D3D11_MAPPED_SUBRESOURCE ms;
      hr = ctx->Map(nv12_texture, 0, D3D11_MAP_WRITE_DISCARD, 0, &ms);
      if (FAILED(hr))
          return false;

      uint8_t* dst = (uint8_t*)ms.pData;
      ms.RowPitch = xres;
      uint8_t* dst_y = dst;
      uint8_t* dst_uv = dst_y + stride_y * real_yres;
      
      for (int i = 0; i < real_yres; i++)
      {
          //memcpy(dst + stride_y * i, dst_y + stride_y * i, stride_y);
          memcpy(dst_y, src_y, stride_y);
          dst_y += stride_y;
          src_y += stride_y;
      }

      for (int i = 0; i < real_yres / 2; i++)
      {
          //memcpy(dst + (real_yres + i) * stride_y, dst_uv + stride_y * i, stride_y);
          memcpy(dst_uv, src_uv, stride_y);
          dst_uv += stride_y;
          src_uv += stride_y;
      }

      ctx->Unmap(nv12_texture, 0);

      ctx->CopyResource(d3d_texture, nv12_texture);

      hr = ProcessNV12ToBmpFile("data/nv12.bmp", dst, xres, xres, real_yres);
      if (FAILED(hr))
          return false;

      return true;
  }

Treat d3d_texture as input_view, dxgi_backbuffer(BGRA format) as output_view of VideoProcessor, then call VideoProcessorBlt() and Present() method.

I tested 720p and 4k videos, decode and render normal, but not work for 1080p videos, the rendered image like this 1080p frame render result, i convert this NV12 buffer to bmp file, the bmp file seems normal, so the NV12 buffer of texture maybe no problem NV12 to bmp file saved.

Update

I upload my test solution to Github, including one 1080p video example, you can test it, here is dx11_video_player

Update Again

I tesetd Microsoft DX11VideoRenderer sample, which use hard decoded texture2D for render, and i also copy the texture2D data from GPU to CPU then converted to bmp file. Under this condition, the render result is normal, but converted bmp file seems like green screen, similiar with 1080p frame render result.

Update Last

By accident, i solved this problem. If i use AMD Radeon 520 grahpic card to render 1080p nv12 format video, problem occured; but if i change to Intel UHD 630 graphic card with latest driver, problem disappered. IF you met same problem, i recommend you to change you graphic card or update driver, good luck for you

Grey
  • 5
  • 3

0 Answers0