content/media/wmf/DXVA2Manager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/wmf/DXVA2Manager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,210 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "DXVA2Manager.h"
    1.11 +#include "nsThreadUtils.h"
    1.12 +#include "ImageContainer.h"
    1.13 +#include "D3D9SurfaceImage.h"
    1.14 +#include "mozilla/Preferences.h"
    1.15 +
    1.16 +namespace mozilla {
    1.17 +
    1.18 +using layers::Image;
    1.19 +using layers::ImageContainer;
    1.20 +using layers::D3D9SurfaceImage;
    1.21 +
    1.22 +class D3D9DXVA2Manager : public DXVA2Manager
    1.23 +{
    1.24 +public:
    1.25 +  D3D9DXVA2Manager();
    1.26 +  virtual ~D3D9DXVA2Manager();
    1.27 +
    1.28 +  HRESULT Init();
    1.29 +
    1.30 +  IUnknown* GetDXVADeviceManager() MOZ_OVERRIDE;
    1.31 +
    1.32 +  // Copies a region (aRegion) of the video frame stored in aVideoSample
    1.33 +  // into an image which is returned by aOutImage.
    1.34 +  HRESULT CopyToImage(IMFSample* aVideoSample,
    1.35 +                      const nsIntRect& aRegion,
    1.36 +                      ImageContainer* aContainer,
    1.37 +                      Image** aOutImage) MOZ_OVERRIDE;
    1.38 +
    1.39 +private:
    1.40 +  nsRefPtr<IDirect3D9Ex> mD3D9;
    1.41 +  nsRefPtr<IDirect3DDevice9Ex> mDevice;
    1.42 +  nsRefPtr<IDirect3DDeviceManager9> mDeviceManager;
    1.43 +  UINT32 mResetToken;
    1.44 +};
    1.45 +
    1.46 +D3D9DXVA2Manager::D3D9DXVA2Manager()
    1.47 +  : mResetToken(0)
    1.48 +{
    1.49 +  MOZ_COUNT_CTOR(D3D9DXVA2Manager);
    1.50 +  MOZ_ASSERT(NS_IsMainThread());
    1.51 +}
    1.52 +
    1.53 +D3D9DXVA2Manager::~D3D9DXVA2Manager()
    1.54 +{
    1.55 +  MOZ_COUNT_DTOR(D3D9DXVA2Manager);
    1.56 +  MOZ_ASSERT(NS_IsMainThread());
    1.57 +}
    1.58 +
    1.59 +IUnknown*
    1.60 +D3D9DXVA2Manager::GetDXVADeviceManager()
    1.61 +{
    1.62 +  MutexAutoLock lock(mLock);
    1.63 +  return mDeviceManager;
    1.64 +}
    1.65 +
    1.66 +HRESULT
    1.67 +D3D9DXVA2Manager::Init()
    1.68 +{
    1.69 +  MOZ_ASSERT(NS_IsMainThread());
    1.70 +
    1.71 +  // Create D3D9Ex.
    1.72 +  HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
    1.73 +  NS_ENSURE_TRUE(d3d9lib, E_FAIL);
    1.74 +  decltype(Direct3DCreate9Ex)* d3d9Create =
    1.75 +    (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
    1.76 +  nsRefPtr<IDirect3D9Ex> d3d9Ex;
    1.77 +  HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex));
    1.78 +  if (!d3d9Ex) {
    1.79 +    NS_WARNING("Direct3DCreate9 failed");
    1.80 +    return E_FAIL;
    1.81 +  }
    1.82 +
    1.83 +  // Ensure we can do the YCbCr->RGB conversion in StretchRect.
    1.84 +  // Fail if we can't.
    1.85 +  hr = d3d9Ex->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT,
    1.86 +                                           D3DDEVTYPE_HAL,
    1.87 +                                           (D3DFORMAT)MAKEFOURCC('N','V','1','2'),
    1.88 +                                           D3DFMT_X8R8G8B8);
    1.89 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    1.90 +
    1.91 +  // Create D3D9DeviceEx.
    1.92 +  D3DPRESENT_PARAMETERS params = {0};
    1.93 +  params.BackBufferWidth = 1;
    1.94 +  params.BackBufferHeight = 1;
    1.95 +  params.BackBufferFormat = D3DFMT_UNKNOWN;
    1.96 +  params.BackBufferCount = 1;
    1.97 +  params.SwapEffect = D3DSWAPEFFECT_DISCARD;
    1.98 +  params.hDeviceWindow = ::GetShellWindow();
    1.99 +  params.Windowed = TRUE;
   1.100 +  params.Flags = D3DPRESENTFLAG_VIDEO;
   1.101 +
   1.102 +  nsRefPtr<IDirect3DDevice9Ex> device;
   1.103 +  hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
   1.104 +                              D3DDEVTYPE_HAL,
   1.105 +                              ::GetShellWindow(),
   1.106 +                              D3DCREATE_FPU_PRESERVE |
   1.107 +                              D3DCREATE_MULTITHREADED |
   1.108 +                              D3DCREATE_MIXED_VERTEXPROCESSING,
   1.109 +                              &params,
   1.110 +                              nullptr,
   1.111 +                              getter_AddRefs(device));
   1.112 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.113 +
   1.114 +  // Ensure we can create queries to synchronize operations between devices.
   1.115 +  // Without this, when we make a copy of the frame in order to share it with
   1.116 +  // another device, we can't be sure that the copy has finished before the
   1.117 +  // other device starts using it.
   1.118 +  nsRefPtr<IDirect3DQuery9> query;
   1.119 +
   1.120 +  hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
   1.121 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.122 +
   1.123 +  // Create and initialize IDirect3DDeviceManager9.
   1.124 +  UINT resetToken = 0;
   1.125 +  nsRefPtr<IDirect3DDeviceManager9> deviceManager;
   1.126 +
   1.127 +  hr = wmf::DXVA2CreateDirect3DDeviceManager9(&resetToken,
   1.128 +                                              getter_AddRefs(deviceManager));
   1.129 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.130 +  hr = deviceManager->ResetDevice(device, resetToken);
   1.131 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.132 +
   1.133 +  mResetToken = resetToken;
   1.134 +  mD3D9 = d3d9Ex;
   1.135 +  mDevice = device;
   1.136 +  mDeviceManager = deviceManager;
   1.137 +
   1.138 +  return S_OK;
   1.139 +}
   1.140 +
   1.141 +HRESULT
   1.142 +D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
   1.143 +                              const nsIntRect& aRegion,
   1.144 +                              ImageContainer* aImageContainer,
   1.145 +                              Image** aOutImage)
   1.146 +{
   1.147 +  nsRefPtr<IMFMediaBuffer> buffer;
   1.148 +  HRESULT hr = aSample->GetBufferByIndex(0, getter_AddRefs(buffer));
   1.149 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.150 +
   1.151 +  nsRefPtr<IDirect3DSurface9> surface;
   1.152 +  hr = wmf::MFGetService(buffer,
   1.153 +                         MR_BUFFER_SERVICE,
   1.154 +                         IID_IDirect3DSurface9,
   1.155 +                         getter_AddRefs(surface));
   1.156 +  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1.157 +
   1.158 +  nsRefPtr<Image> image = aImageContainer->CreateImage(ImageFormat::D3D9_RGB32_TEXTURE);
   1.159 +  NS_ENSURE_TRUE(image, E_FAIL);
   1.160 +  NS_ASSERTION(image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE,
   1.161 +               "Wrong format?");
   1.162 +
   1.163 +  D3D9SurfaceImage* videoImage = static_cast<D3D9SurfaceImage*>(image.get());
   1.164 +  hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aRegion));
   1.165 +
   1.166 +  image.forget(aOutImage);
   1.167 +
   1.168 +  return S_OK;
   1.169 +}
   1.170 +
   1.171 +// Count of the number of DXVAManager's we've created. This is also the
   1.172 +// number of videos we're decoding with DXVA. Use on main thread only.
   1.173 +static uint32_t sDXVAVideosCount = 0;
   1.174 +
   1.175 +/* static */
   1.176 +DXVA2Manager*
   1.177 +DXVA2Manager::Create()
   1.178 +{
   1.179 +  MOZ_ASSERT(NS_IsMainThread());
   1.180 +  HRESULT hr;
   1.181 +
   1.182 +  // DXVA processing takes up a lot of GPU resources, so limit the number of
   1.183 +  // videos we use DXVA with at any one time.
   1.184 +  const uint32_t dxvaLimit =
   1.185 +    Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8);
   1.186 +  if (sDXVAVideosCount == dxvaLimit) {
   1.187 +    return nullptr;
   1.188 +  }
   1.189 +
   1.190 +  nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
   1.191 +  hr = d3d9Manager->Init();
   1.192 +  if (SUCCEEDED(hr)) {
   1.193 +    return d3d9Manager.forget();
   1.194 +  }
   1.195 +
   1.196 +  // No hardware accelerated video decoding. :(
   1.197 +  return nullptr;
   1.198 +}
   1.199 +
   1.200 +DXVA2Manager::DXVA2Manager()
   1.201 +  : mLock("DXVA2Manager")
   1.202 +{
   1.203 +  MOZ_ASSERT(NS_IsMainThread());
   1.204 +  ++sDXVAVideosCount;
   1.205 +}
   1.206 +
   1.207 +DXVA2Manager::~DXVA2Manager()
   1.208 +{
   1.209 +  MOZ_ASSERT(NS_IsMainThread());
   1.210 +  --sDXVAVideosCount;
   1.211 +}
   1.212 +
   1.213 +} // namespace mozilla

mercurial