Example #1
0
HRESULT CDecDXVA2::CreateDXVA2Decoder(int nSurfaces, IDirect3DSurface9 **ppSurfaces)
{
  DbgLog((LOG_TRACE, 10, L"-> CDecDXVA2::CreateDXVA2Decoder"));
  HRESULT hr = S_OK;
  LPDIRECT3DSURFACE9 pSurfaces[DXVA2_MAX_SURFACES];

  if (!m_pDXVADecoderService)
    return E_FAIL;

  DestroyDecoder(false, true);

  GUID input = GUID_NULL;
  D3DFORMAT output;
  FindVideoServiceConversion(m_pAVCtx->codec_id, &input, &output);

  if (!nSurfaces) {
    m_dwSurfaceWidth = FFALIGN(m_pAVCtx->coded_width, 16);
    m_dwSurfaceHeight = FFALIGN(m_pAVCtx->coded_height, 16);

    m_NumSurfaces = GetBufferCount();
    hr = m_pDXVADecoderService->CreateSurface(m_dwSurfaceWidth, m_dwSurfaceHeight, m_NumSurfaces - 1, output, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, pSurfaces, NULL);
    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> Creation of surfaces failed with hr: %X", hr));
      m_NumSurfaces = 0;
      return E_FAIL;
    }
    ppSurfaces = pSurfaces;
  } else {
    m_NumSurfaces = nSurfaces;
    for (int i = 0; i < m_NumSurfaces; i++) {
      ppSurfaces[i]->AddRef();
    }
  }

  for (int i = 0; i < m_NumSurfaces; i++) {
    m_pSurfaces[i].index = i;
    m_pSurfaces[i].d3d = ppSurfaces[i];
    m_pSurfaces[i].age = 0;
    m_pSurfaces[i].used = false;
  }

  DbgLog((LOG_TRACE, 10, L"-> Successfully created %d surfaces (%dx%d)", m_NumSurfaces, m_dwSurfaceWidth, m_dwSurfaceHeight));

  DXVA2_VideoDesc desc;
  ZeroMemory(&desc, sizeof(desc));
  desc.SampleWidth = m_pAVCtx->coded_width;
  desc.SampleHeight = m_pAVCtx->coded_height;
  desc.Format = output;

  hr = FindDecoderConfiguration(input, &desc, &m_DXVAVideoDecoderConfig);
  if (FAILED(hr)) {
    DbgLog((LOG_TRACE, 10, L"-> FindDecoderConfiguration failed with hr: %X", hr));
    return hr;
  }

  IDirectXVideoDecoder *decoder = NULL;
  hr = m_pDXVADecoderService->CreateVideoDecoder(input, &desc, &m_DXVAVideoDecoderConfig, ppSurfaces, m_NumSurfaces, &decoder);
  if (FAILED(hr)) {
    DbgLog((LOG_TRACE, 10, L"-> CreateVideoDecoder failed with hr: %X", hr));
    return E_FAIL;
  }
  m_pDecoder = decoder;

  /* fill hwaccel_context */
  dxva_context *ctx = (dxva_context *)m_pAVCtx->hwaccel_context;
  ctx->cfg           = &m_DXVAVideoDecoderConfig;
  ctx->decoder       = m_pDecoder;
  ctx->surface       = m_pRawSurface;
  ctx->surface_count = m_NumSurfaces;

  if (m_dwVendorId == VEND_ID_INTEL && input == DXVADDI_Intel_ModeH264_E)
    ctx->workaround = FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;
  else if (m_dwVendorId == VEND_ID_ATI && IsAMDUVD(m_dwDeviceId))
    ctx->workaround = FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG;
  else
    ctx->workaround = 0;

  memset(m_pRawSurface, 0, sizeof(m_pRawSurface));
  for (int i = 0; i < m_NumSurfaces; i++) {
    m_pRawSurface[i] = m_pSurfaces[i].d3d;
  }

  return S_OK;
}
Example #2
0
/**
 * Called from both native and non-native mode
 * Initialize all the common DXVA2 interfaces and device handles
 */
HRESULT CDecDXVA2::SetD3DDeviceManager(IDirect3DDeviceManager9 *pDevManager)
{
  HRESULT hr = S_OK;
  ASSERT(pDevManager);

  m_pD3DDevMngr = pDevManager;

  RetrieveVendorId(pDevManager);

  // This should really be null here, but since we're overwriting it, make sure its actually released
  SafeRelease(&m_pDXVADecoderService);

  hr = CreateDXVAVideoService(m_pD3DDevMngr, &m_pDXVADecoderService);
  if (FAILED(hr)) {
    DbgLog((LOG_TRACE, 10, L"-> Creation of DXVA2 Decoder Service failed with hr: %X", hr));
    goto done;
  }

  // If the decoder was initialized already, check if we can use this device
  if (m_pAVCtx) {
    DbgLog((LOG_TRACE, 10, L"-> Checking hardware for format support..."));

    GUID input = GUID_NULL;
    D3DFORMAT output;
    hr = FindVideoServiceConversion(m_pAVCtx->codec_id, &input, &output);
    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> No decoder device available that can decode codec '%S' to NV12", avcodec_get_name(m_pAVCtx->codec_id)));
      goto done;
    }

    if (FAILED(CheckHWCompatConditions(input))) {
      hr = E_FAIL;
      goto done;
    }

    DXVA2_VideoDesc desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.SampleWidth = m_pAVCtx->coded_width;
    desc.SampleHeight = m_pAVCtx->coded_height;
    desc.Format = output;

    DXVA2_ConfigPictureDecode config;
    hr = FindDecoderConfiguration(input, &desc, &config);
    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> No decoder configuration available for codec '%S'", avcodec_get_name(m_pAVCtx->codec_id)));
      goto done;
    }

    LPDIRECT3DSURFACE9 pSurfaces[DXVA2_MAX_SURFACES] = {0};
    UINT numSurfaces = max(config.ConfigMinRenderTargetBuffCount, 1);
    hr = m_pDXVADecoderService->CreateSurface(m_dwSurfaceWidth, m_dwSurfaceHeight, numSurfaces, output, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, pSurfaces, NULL);
    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> Creation of surfaces failed with hr: %X", hr));
      goto done;
    }

    IDirectXVideoDecoder *decoder = NULL;
    hr = m_pDXVADecoderService->CreateVideoDecoder(input, &desc, &config, pSurfaces, numSurfaces, &decoder);

    // Release resources, decoder and surfaces
    SafeRelease(&decoder);
    int i = DXVA2_MAX_SURFACES;
    while (i > 0) {
      SafeRelease(&pSurfaces[--i]);
    }

    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> Creation of decoder failed with hr: %X", hr));
      goto done;
    }
  }

done:
  return hr;
}
Example #3
0
STDMETHODIMP CDecD3D11::CreateD3D11Decoder()
{
  HRESULT hr = S_OK;
  AVD3D11VADeviceContext *pDeviceContext = (AVD3D11VADeviceContext *)((AVHWDeviceContext *)m_pDevCtx->data)->hwctx;

  // release the old decoder, it needs to be re-created
  SafeRelease(&m_pDecoder);

  // find a decoder configuration
  GUID profileGUID = GUID_NULL;
  DXGI_FORMAT surface_format = d3d11va_map_sw_to_hw_format(m_pAVCtx->sw_pix_fmt);
  hr = FindVideoServiceConversion(m_pAVCtx->codec_id, m_pAVCtx->profile, surface_format, &profileGUID);
  if (FAILED(hr))
  {
    DbgLog((LOG_ERROR, 10, L"-> No video service profile found"));
    return hr;
  }

  // get decoder configuration
  D3D11_VIDEO_DECODER_DESC desc = { 0 };
  desc.Guid = profileGUID;
  desc.OutputFormat = surface_format;
  desc.SampleWidth = m_pAVCtx->coded_width;
  desc.SampleHeight = m_pAVCtx->coded_height;

  D3D11_VIDEO_DECODER_CONFIG decoder_config = { 0 };
  hr = FindDecoderConfiguration(&desc, &decoder_config);
  if (FAILED(hr))
  {
    DbgLog((LOG_ERROR, 10, L"-> No valid video decoder configuration found"));
    return hr;
  }

  m_DecoderConfig = decoder_config;

  // update surface properties
  m_dwSurfaceWidth = dxva_align_dimensions(m_pAVCtx->codec_id, m_pAVCtx->coded_width);
  m_dwSurfaceHeight = dxva_align_dimensions(m_pAVCtx->codec_id, m_pAVCtx->coded_height);
  m_DecodePixelFormat = m_pAVCtx->sw_pix_fmt;
  m_SurfaceFormat = surface_format;

  if (m_bReadBackFallback == false && m_pAllocator)
  {
    ALLOCATOR_PROPERTIES properties;
    hr = m_pAllocator->GetProperties(&properties);
    if (FAILED(hr))
      return hr;

    m_dwSurfaceCount = properties.cBuffers;
  }
  else
  {
    m_dwSurfaceCount = GetBufferCount();
  }

  // allocate a new frames context for the dimensions and format
  hr = AllocateFramesContext(m_dwSurfaceWidth, m_dwSurfaceHeight, m_DecodePixelFormat, m_dwSurfaceCount, &m_pFramesCtx);
  if (FAILED(hr))
  {
    DbgLog((LOG_ERROR, 10, L"-> Error allocating frames context"));
    return hr;
  }

  // release any old output views and allocate memory for the new ones
  if (m_pOutputViews)
  {
    for (int i = 0; i < m_nOutputViews; i++)
    {
      SafeRelease(&m_pOutputViews[i]);
    }
    av_freep(&m_pOutputViews);
  }

  m_pOutputViews = (ID3D11VideoDecoderOutputView **)av_mallocz_array(m_dwSurfaceCount, sizeof(*m_pOutputViews));
  m_nOutputViews = m_dwSurfaceCount;

  // allocate output views for the frames
  AVD3D11VAFramesContext *pFramesContext = (AVD3D11VAFramesContext *)((AVHWFramesContext *)m_pFramesCtx->data)->hwctx;
  for (int i = 0; i < m_nOutputViews; i++)
  {
    D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc = { 0 };
    viewDesc.DecodeProfile = profileGUID;
    viewDesc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
    viewDesc.Texture2D.ArraySlice = i;

    hr = pDeviceContext->video_device->CreateVideoDecoderOutputView(pFramesContext->texture, &viewDesc, &m_pOutputViews[i]);
    if (FAILED(hr))
    {
      DbgLog((LOG_ERROR, 10, L"-> Failed to create video decoder output views"));
      return E_FAIL;
    }
  }

  // create the decoder
  hr = pDeviceContext->video_device->CreateVideoDecoder(&desc, &decoder_config, &m_pDecoder);
  if (FAILED(hr))
  {
    DbgLog((LOG_ERROR, 10, L"-> Failed to create video decoder object"));
    return E_FAIL;
  }

  FillHWContext((AVD3D11VAContext *)m_pAVCtx->hwaccel_context);

  return S_OK;
}
Example #4
0
HRESULT CDecDXVA2::CreateDXVA2Decoder(int nSurfaces, IDirect3DSurface9 **ppSurfaces)
{
  DbgLog((LOG_TRACE, 10, L"-> CDecDXVA2::CreateDXVA2Decoder"));
  HRESULT hr = S_OK;
  LPDIRECT3DSURFACE9 pSurfaces[DXVA2_MAX_SURFACES];

  if (!m_pDXVADecoderService)
    return E_FAIL;

  DestroyDecoder(false, true);

  GUID input = GUID_NULL;
  D3DFORMAT output;
  FindVideoServiceConversion(m_pAVCtx->codec_id, &input, &output);

  if (!nSurfaces) {
    m_dwSurfaceWidth = GetAlignedDimension(m_pAVCtx->coded_width);
    m_dwSurfaceHeight = GetAlignedDimension(m_pAVCtx->coded_height);

    m_NumSurfaces = GetBufferCount();
    hr = m_pDXVADecoderService->CreateSurface(m_dwSurfaceWidth, m_dwSurfaceHeight, m_NumSurfaces - 1, output, D3DPOOL_DEFAULT, 0, DXVA2_VideoDecoderRenderTarget, pSurfaces, nullptr);
    if (FAILED(hr)) {
      DbgLog((LOG_TRACE, 10, L"-> Creation of surfaces failed with hr: %X", hr));
      m_NumSurfaces = 0;
      return E_FAIL;
    }
    ppSurfaces = pSurfaces;
  } else {
    m_NumSurfaces = nSurfaces;
    for (int i = 0; i < m_NumSurfaces; i++) {
      ppSurfaces[i]->AddRef();
    }
  }

  if (m_NumSurfaces <= 0) {
    DbgLog((LOG_TRACE, 10, L"-> No surfaces? No good!"));
    return E_FAIL;
  }

  // get the device, for ColorFill() to init the surfaces in black
  IDirect3DDevice9 *pDev = nullptr;
  ppSurfaces[0]->GetDevice(&pDev);

  for (int i = 0; i < m_NumSurfaces; i++) {
    m_pSurfaces[i].index = i;
    m_pSurfaces[i].d3d = ppSurfaces[i];
    m_pSurfaces[i].age = 0;
    m_pSurfaces[i].used = false;

    // fill the surface in black, to avoid the "green screen" in case the first frame fails to decode.
    if (pDev) pDev->ColorFill(ppSurfaces[i], NULL, D3DCOLOR_XYUV(0, 128, 128));
  }

  // and done with the device
  SafeRelease(&pDev);

  DbgLog((LOG_TRACE, 10, L"-> Successfully created %d surfaces (%dx%d)", m_NumSurfaces, m_dwSurfaceWidth, m_dwSurfaceHeight));

  DXVA2_VideoDesc desc;
  ZeroMemory(&desc, sizeof(desc));
  desc.SampleWidth = m_pAVCtx->coded_width;
  desc.SampleHeight = m_pAVCtx->coded_height;
  desc.Format = output;

  hr = FindDecoderConfiguration(input, &desc, &m_DXVAVideoDecoderConfig);
  if (FAILED(hr)) {
    DbgLog((LOG_TRACE, 10, L"-> FindDecoderConfiguration failed with hr: %X", hr));
    return hr;
  }

  IDirectXVideoDecoder *decoder = nullptr;
  hr = m_pDXVADecoderService->CreateVideoDecoder(input, &desc, &m_DXVAVideoDecoderConfig, ppSurfaces, m_NumSurfaces, &decoder);
  if (FAILED(hr)) {
    DbgLog((LOG_TRACE, 10, L"-> CreateVideoDecoder failed with hr: %X", hr));
    return E_FAIL;
  }
  m_pDecoder = decoder;
  m_guidDecoderDevice = input;

  /* fill hwaccel_context */
  FillHWContext((dxva_context *)m_pAVCtx->hwaccel_context);

  memset(m_pRawSurface, 0, sizeof(m_pRawSurface));
  for (int i = 0; i < m_NumSurfaces; i++) {
    m_pRawSurface[i] = m_pSurfaces[i].d3d;
  }

  return S_OK;
}
Example #5
0
STDMETHODIMP CDecD3D11::PostConnect(IPin *pPin)
{
  DbgLog((LOG_TRACE, 10, L"CDecD3D11::PostConnect()"));
  HRESULT hr = S_OK;

  ID3D11DecoderConfiguration *pD3D11DecoderConfiguration = nullptr;
  hr = pPin->QueryInterface(&pD3D11DecoderConfiguration);
  if (FAILED(hr)) {
    DbgLog((LOG_ERROR, 10, L"-> ID3D11DecoderConfiguration not available, using fallback mode"));
  }

  // Release old D3D resources, we're about to re-init
  m_pCallback->ReleaseAllDXVAResources();

  // free the decoder to force a re-init down the line
  SafeRelease(&m_pDecoder);

  // and the old device
  av_buffer_unref(&m_pDevCtx);

  // device id
  UINT nDevice = m_pSettings->GetHWAccelDeviceIndex(HWAccel_D3D11, nullptr);

  // in automatic mode use the device the renderer gives us
  if (nDevice == LAVHWACCEL_DEVICE_DEFAULT && pD3D11DecoderConfiguration)
  {
    nDevice = pD3D11DecoderConfiguration->GetD3D11AdapterIndex();
  }
  else
  {
    // if a device is specified manually, fallback to copy-back and use the selected device
    SafeRelease(&pD3D11DecoderConfiguration);

    // use the configured device
    if (nDevice == LAVHWACCEL_DEVICE_DEFAULT)
      nDevice = 0;
  }

  // create the device
  ID3D11Device *pD3D11Device = nullptr;
  hr = CreateD3D11Device(nDevice, &pD3D11Device, &m_AdapterDesc);
  if (FAILED(hr))
  {
    goto fail;
  }

  // allocate and fill device context
  m_pDevCtx = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_D3D11VA);
  AVD3D11VADeviceContext *pDeviceContext = (AVD3D11VADeviceContext *)((AVHWDeviceContext *)m_pDevCtx->data)->hwctx;
  pDeviceContext->device = pD3D11Device;

  // finalize the context
  int ret = av_hwdevice_ctx_init(m_pDevCtx);
  if (ret < 0)
  {
    av_buffer_unref(&m_pDevCtx);
    goto fail;
  }

  // check if the connection supports native mode
  if (pD3D11DecoderConfiguration)
  {
    CMediaType mt = m_pCallback->GetOutputMediaType();
    if ((m_SurfaceFormat == DXGI_FORMAT_NV12 && mt.subtype != MEDIASUBTYPE_NV12)
      || (m_SurfaceFormat == DXGI_FORMAT_P010 && mt.subtype != MEDIASUBTYPE_P010)
      || (m_SurfaceFormat == DXGI_FORMAT_P016 && mt.subtype != MEDIASUBTYPE_P016)) {
      DbgLog((LOG_ERROR, 10, L"-> Connection is not the appropriate pixel format for D3D11 Native"));

      SafeRelease(&pD3D11DecoderConfiguration);
    }
  }

  // verify hardware support
  {
    GUID guidConversion = GUID_NULL;
    hr = FindVideoServiceConversion(m_pAVCtx->codec_id, m_pAVCtx->profile, m_SurfaceFormat, &guidConversion);
    if (FAILED(hr))
    {
      goto fail;
    }

    // get decoder configuration
    D3D11_VIDEO_DECODER_DESC desc = { 0 };
    desc.Guid = guidConversion;
    desc.OutputFormat = m_SurfaceFormat;
    desc.SampleWidth = m_pAVCtx->coded_width;
    desc.SampleHeight = m_pAVCtx->coded_height;

    D3D11_VIDEO_DECODER_CONFIG decoder_config = { 0 };
    hr = FindDecoderConfiguration(&desc, &decoder_config);
    if (FAILED(hr))
    {
      goto fail;
    }

    // test creating a texture
    D3D11_TEXTURE2D_DESC texDesc = { 0 };
    texDesc.Width = m_pAVCtx->coded_width;
    texDesc.Height = m_pAVCtx->coded_height;
    texDesc.MipLevels = 1;
    texDesc.ArraySize = 10;
    texDesc.Format = m_SurfaceFormat;
    texDesc.SampleDesc.Count = 1;
    texDesc.Usage = D3D11_USAGE_DEFAULT;
    texDesc.BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
    texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;

    ID3D11Texture2D *pTexture2D = nullptr;
    hr = pD3D11Device->CreateTexture2D(&texDesc, nullptr, &pTexture2D);
    if (FAILED(hr))
    {
      goto fail;
    }
    SafeRelease(&pTexture2D);
  }

  // Notice the connected pin that we're sending D3D11 textures
  if (pD3D11DecoderConfiguration)
  {
    hr = pD3D11DecoderConfiguration->ActivateD3D11Decoding(pDeviceContext->device, pDeviceContext->device_context, pDeviceContext->lock_ctx, 0);
    SafeRelease(&pD3D11DecoderConfiguration);

    m_bReadBackFallback = FAILED(hr);
  }
  else
  {
    m_bReadBackFallback = true;
  }

  return S_OK;

fail:
  SafeRelease(&pD3D11DecoderConfiguration);
  return E_FAIL;
}