content/media/wmf/DXVA2Manager.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial