content/media/wmf/DXVA2Manager.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "DXVA2Manager.h"
     8 #include "nsThreadUtils.h"
     9 #include "ImageContainer.h"
    10 #include "D3D9SurfaceImage.h"
    11 #include "mozilla/Preferences.h"
    13 namespace mozilla {
    15 using layers::Image;
    16 using layers::ImageContainer;
    17 using layers::D3D9SurfaceImage;
    19 class D3D9DXVA2Manager : public DXVA2Manager
    20 {
    21 public:
    22   D3D9DXVA2Manager();
    23   virtual ~D3D9DXVA2Manager();
    25   HRESULT Init();
    27   IUnknown* GetDXVADeviceManager() MOZ_OVERRIDE;
    29   // Copies a region (aRegion) of the video frame stored in aVideoSample
    30   // into an image which is returned by aOutImage.
    31   HRESULT CopyToImage(IMFSample* aVideoSample,
    32                       const nsIntRect& aRegion,
    33                       ImageContainer* aContainer,
    34                       Image** aOutImage) MOZ_OVERRIDE;
    36 private:
    37   nsRefPtr<IDirect3D9Ex> mD3D9;
    38   nsRefPtr<IDirect3DDevice9Ex> mDevice;
    39   nsRefPtr<IDirect3DDeviceManager9> mDeviceManager;
    40   UINT32 mResetToken;
    41 };
    43 D3D9DXVA2Manager::D3D9DXVA2Manager()
    44   : mResetToken(0)
    45 {
    46   MOZ_COUNT_CTOR(D3D9DXVA2Manager);
    47   MOZ_ASSERT(NS_IsMainThread());
    48 }
    50 D3D9DXVA2Manager::~D3D9DXVA2Manager()
    51 {
    52   MOZ_COUNT_DTOR(D3D9DXVA2Manager);
    53   MOZ_ASSERT(NS_IsMainThread());
    54 }
    56 IUnknown*
    57 D3D9DXVA2Manager::GetDXVADeviceManager()
    58 {
    59   MutexAutoLock lock(mLock);
    60   return mDeviceManager;
    61 }
    63 HRESULT
    64 D3D9DXVA2Manager::Init()
    65 {
    66   MOZ_ASSERT(NS_IsMainThread());
    68   // Create D3D9Ex.
    69   HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
    70   NS_ENSURE_TRUE(d3d9lib, E_FAIL);
    71   decltype(Direct3DCreate9Ex)* d3d9Create =
    72     (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
    73   nsRefPtr<IDirect3D9Ex> d3d9Ex;
    74   HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex));
    75   if (!d3d9Ex) {
    76     NS_WARNING("Direct3DCreate9 failed");
    77     return E_FAIL;
    78   }
    80   // Ensure we can do the YCbCr->RGB conversion in StretchRect.
    81   // Fail if we can't.
    82   hr = d3d9Ex->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT,
    83                                            D3DDEVTYPE_HAL,
    84                                            (D3DFORMAT)MAKEFOURCC('N','V','1','2'),
    85                                            D3DFMT_X8R8G8B8);
    86   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    88   // Create D3D9DeviceEx.
    89   D3DPRESENT_PARAMETERS params = {0};
    90   params.BackBufferWidth = 1;
    91   params.BackBufferHeight = 1;
    92   params.BackBufferFormat = D3DFMT_UNKNOWN;
    93   params.BackBufferCount = 1;
    94   params.SwapEffect = D3DSWAPEFFECT_DISCARD;
    95   params.hDeviceWindow = ::GetShellWindow();
    96   params.Windowed = TRUE;
    97   params.Flags = D3DPRESENTFLAG_VIDEO;
    99   nsRefPtr<IDirect3DDevice9Ex> device;
   100   hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
   101                               D3DDEVTYPE_HAL,
   102                               ::GetShellWindow(),
   103                               D3DCREATE_FPU_PRESERVE |
   104                               D3DCREATE_MULTITHREADED |
   105                               D3DCREATE_MIXED_VERTEXPROCESSING,
   106                               &params,
   107                               nullptr,
   108                               getter_AddRefs(device));
   109   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   111   // Ensure we can create queries to synchronize operations between devices.
   112   // Without this, when we make a copy of the frame in order to share it with
   113   // another device, we can't be sure that the copy has finished before the
   114   // other device starts using it.
   115   nsRefPtr<IDirect3DQuery9> query;
   117   hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
   118   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   120   // Create and initialize IDirect3DDeviceManager9.
   121   UINT resetToken = 0;
   122   nsRefPtr<IDirect3DDeviceManager9> deviceManager;
   124   hr = wmf::DXVA2CreateDirect3DDeviceManager9(&resetToken,
   125                                               getter_AddRefs(deviceManager));
   126   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   127   hr = deviceManager->ResetDevice(device, resetToken);
   128   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   130   mResetToken = resetToken;
   131   mD3D9 = d3d9Ex;
   132   mDevice = device;
   133   mDeviceManager = deviceManager;
   135   return S_OK;
   136 }
   138 HRESULT
   139 D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
   140                               const nsIntRect& aRegion,
   141                               ImageContainer* aImageContainer,
   142                               Image** aOutImage)
   143 {
   144   nsRefPtr<IMFMediaBuffer> buffer;
   145   HRESULT hr = aSample->GetBufferByIndex(0, getter_AddRefs(buffer));
   146   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   148   nsRefPtr<IDirect3DSurface9> surface;
   149   hr = wmf::MFGetService(buffer,
   150                          MR_BUFFER_SERVICE,
   151                          IID_IDirect3DSurface9,
   152                          getter_AddRefs(surface));
   153   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   155   nsRefPtr<Image> image = aImageContainer->CreateImage(ImageFormat::D3D9_RGB32_TEXTURE);
   156   NS_ENSURE_TRUE(image, E_FAIL);
   157   NS_ASSERTION(image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE,
   158                "Wrong format?");
   160   D3D9SurfaceImage* videoImage = static_cast<D3D9SurfaceImage*>(image.get());
   161   hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aRegion));
   163   image.forget(aOutImage);
   165   return S_OK;
   166 }
   168 // Count of the number of DXVAManager's we've created. This is also the
   169 // number of videos we're decoding with DXVA. Use on main thread only.
   170 static uint32_t sDXVAVideosCount = 0;
   172 /* static */
   173 DXVA2Manager*
   174 DXVA2Manager::Create()
   175 {
   176   MOZ_ASSERT(NS_IsMainThread());
   177   HRESULT hr;
   179   // DXVA processing takes up a lot of GPU resources, so limit the number of
   180   // videos we use DXVA with at any one time.
   181   const uint32_t dxvaLimit =
   182     Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8);
   183   if (sDXVAVideosCount == dxvaLimit) {
   184     return nullptr;
   185   }
   187   nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
   188   hr = d3d9Manager->Init();
   189   if (SUCCEEDED(hr)) {
   190     return d3d9Manager.forget();
   191   }
   193   // No hardware accelerated video decoding. :(
   194   return nullptr;
   195 }
   197 DXVA2Manager::DXVA2Manager()
   198   : mLock("DXVA2Manager")
   199 {
   200   MOZ_ASSERT(NS_IsMainThread());
   201   ++sDXVAVideosCount;
   202 }
   204 DXVA2Manager::~DXVA2Manager()
   205 {
   206   MOZ_ASSERT(NS_IsMainThread());
   207   --sDXVAVideosCount;
   208 }
   210 } // namespace mozilla

mercurial