0

我正在开发一个应用程序,它使用应用程序中的 DXGI 机制捕获帧。

第一次创建 IDXGIOutputDuplication 是正确的。当应用程序更改其显示(例如从全屏到窗口或反之亦然)时,帧获取失败(预期行为),然后我重新创建 IDXGIOutputDuplication 并定期调用 DuplicateOutput 崩溃。

下面创建 D3d11 设备

D3D_FEATURE_LEVEL FeatureLevels[] =
{
  D3D_FEATURE_LEVEL_11_1,
  D3D_FEATURE_LEVEL_11_0,
  D3D_FEATURE_LEVEL_10_1,
  D3D_FEATURE_LEVEL_10_0,
  D3D_FEATURE_LEVEL_9_1
};
UINT NumFeatureLevels = ARRAYSIZE( FeatureLevels );
D3D_FEATURE_LEVEL FeatureLevel = D3D_FEATURE_LEVEL_11_1;
D3D11CreateDevice( _pDxgiAdapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, FeatureLevels, NumFeatureLevels, D3D11_SDK_VERSION, &_pD3D11Device, &FeatureLevel, &_pD3D11DeviceCtx );

_pDxgiAdapter 在设备之前创建。

下面创建 IDXGIOutputDuplication

int DxgiVideoCapture::open() {
  findDxgiAdapter();

  if( nullptr != _pDxgiAdapter ) {
    // Duplicate output
    uint32_t ui32OutputIndex = 0;
    HRESULT hr = S_OK;
    while( SUCCEEDED( hr ) ) {
      IDXGIOutput* pDxgiOutput = nullptr;
      hr = _pDxgiAdapter->EnumOutputs( ui32OutputIndex, &pDxgiOutput );
      if( SUCCEEDED( hr ) ) {
        IDXGIOutput1* pDxgiOutput1 = nullptr;
        if( SUCCEEDED ( pDxgiOutput->QueryInterface( __uuidof( IDXGIOutput1 ), ( void** )&pDxgiOutput1 ) ) ) {
          uint32_t ui32EnumMode = 0;
          uint32_t ui32Flags = 0xffffffff;
        }

        if( SUCCEEDED ( pDxgiOutput->QueryInterface( __uuidof( IDXGIOutput1 ), ( void** )&_pDxgiOutput1 ) ) ) {
          LOGI( "/!\\ Call which crash regularly /!\\" );
          HRESULT hrDup = _pDxgiOutput1->DuplicateOutput( _pD3D11Device, &_pOutputDuplication ); 
          if( SUCCEEDED( hrDup ) ) {
            LOGI( "Output duplication created." );
          } else {
            switch( hrDup ) {
              case E_INVALIDARG :
                {
                  LOGW( "Invalid device or output already duplicated" );
                }
                break;
              case E_ACCESSDENIED :
                {
                  LOGW( "Access denied" );
                
                }
                break;
              case DXGI_ERROR_UNSUPPORTED :
                {
                  LOGW( "DXGI_ERROR_UNSUPPORTED" );
                }
                break;
              case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE :
                {
                   LOGW( "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE" );
                }
                break;
              case DXGI_ERROR_SESSION_DISCONNECTED :
                {
                   LOGW( "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE" );
                }
                break;
              default:
                {
                   LOGW( "default" );
                }
            }
        } else {
          LOGE( "Unable to retrieve interface creating the ouput duplication" );
        }
      }
      pDxgiOutput->Release();
    }
    ui32OutputIndex++;
  }

  return RET_OK;
}

帧采集下方:

int DxgiVideoCapture::captureGameFrame() {
  int iRet = RET_ERROR;

  ID3D11Texture2D* pCapturedTexture = nullptr;

  DXGI_OUTDUPL_FRAME_INFO frameInfo;
  ZeroMemory(&frameInfo, sizeof(frameInfo));

  HRESULT hr = _pOutputDuplication->AcquireNextFrame( 1000, &frameInfo, &_pDxgiResource );
  if( FAILED( hr ) )    {
    if( hr == DXGI_ERROR_WAIT_TIMEOUT ) {
      LOGW( "Wait for %d ms timed out", 1000);
    }
    if (hr == DXGI_ERROR_INVALID_CALL) {
      LOGW( "Invalid Call, previous frame not released?" );
    }
    if (hr == DXGI_ERROR_ACCESS_LOST) {
      LOGW( "Error Access lost - is it a game end ?" );
    }
    iRet = RET_RESET_CAPTURE;

    return iRet;
  }

  if( FAILED( hr = _pDxgiResource->QueryInterface( __uuidof( ID3D11Texture2D ), ( void** ) &pCapturedTexture ) ) ) {
    LOGW( "unable to retrieve D3D11 texture 0x%x", hr );
    return RET_WARNING;
  } else {
    // Store window of the game
    D3D11_TEXTURE2D_DESC d3D11TextureDesc;
    pCapturedTexture->GetDesc( &d3D11TextureDesc );

    // Compute the zone to extract.
    D3D11_BOX srcBox;
    memset( &srcBox, 0, sizeof( srcBox ) );
    if( _pGameWindow->getLeftPos()  > 0 ) {
      srcBox.left = _pGameWindow->getLeftPos();
    }
    if( _pGameWindow->getTopPos() > 0 ) {
      srcBox.top = _pGameWindow->getTopPos();
    }
    srcBox.front = 0;
    srcBox.right = _pGameWindow->getLeftPos() + _pGameWindow->getWidth();
    if( srcBox.right > _pGameWindow->getMonitorWidth() ) {
      srcBox.right = _pGameWindow->getMonitorWidth();
    }
    if( ( srcBox.right - srcBox.left ) % 2 != 0 ) {
      srcBox.right--;
    } 
    srcBox.bottom = _pGameWindow->getTopPos() + _pGameWindow->getHeight();
    if( srcBox.bottom > _pGameWindow->getMonitorHeight() ) {
      srcBox.bottom = _pGameWindow->getMonitorHeight();
    }
    if( ( srcBox.bottom - srcBox.top ) % 2 != 0 ) {
      srcBox.bottom--;
    } 
    srcBox.back = 1;

    // AVFrame info are udpate just when the captured game window and the texture are diffrent.
    // In the same time texture is reallocated.
    if( ( ( srcBox.right - srcBox.left ) != _CapturedTextureDesc.Width )
        || ( ( srcBox.bottom - srcBox.top ) != _CapturedTextureDesc.Height )
      ) {
      LOGD( "Game window: %dx%d ; %d->%d", _pGameWindow->getLeftPos(), _pGameWindow->getTopPos(), _pGameWindow->getWidth(), _pGameWindow->getHeight() );
      LOGD( "Texture creation %dx%d -> %dx%d", srcBox.left, srcBox.top, srcBox.right, srcBox.bottom );

      // Create the new texture
      iRet = createCapturedTexture( srcBox.right - srcBox.left, srcBox.bottom - srcBox.top );
    }

    DirectX11Util::GetInstance()->getD3D11DeviceContext()->CopySubresourceRegion( _pGameTexture, 0, 0, 0, 0, pCapturedTexture, 0, &srcBox );
  }

  if( nullptr != _pDxgiResource ) {
    _pOutputDuplication->ReleaseFrame();
    pCapturedTexture->Release();
    _pDxgiResource->Release();
    _pDxgiResource = nullptr;
  }

  iRet = RET_OK;
  return iRet;
}

在重新创建 IDXGIOutputDuplication 之前发布 D3d11 捕获的下方

int DxgiVideoCapture::close() {
  if( nullptr != _pGameTexture ) {
    ZeroMemory( &_CapturedTextureDesc, sizeof( D3D11_TEXTURE2D_DESC ) );
    _pGameTexture->Release();
    _pGameTexture = nullptr;
  }

  if( nullptr != _pDxgiResource ){
    _pOutputDuplication->ReleaseFrame();
    _pDxgiResource->Release();
    _pDxgiResource = nullptr;
  }

  if( nullptr != _pOutputDuplication ) {
    _pOutputDuplication->Release();
    _pOutputDuplication = nullptr;
  }

  return RET_OK;
}

我想知道的是如何投资这个崩溃(应用程序结束时没有任何消息)。为了更准确,我交叉编译了我的应用程序,但行为似乎相同。你知道如何投资这个问题吗?如果您想了解更多详情,请告诉我。

提前致谢 !

4

0 回答 0