content/media/wmf/DXVA2Manager.cpp

branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
equal deleted inserted replaced
-1:000000000000 0:6026b3d048e3
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/. */
6
7 #include "DXVA2Manager.h"
8 #include "nsThreadUtils.h"
9 #include "ImageContainer.h"
10 #include "D3D9SurfaceImage.h"
11 #include "mozilla/Preferences.h"
12
13 namespace mozilla {
14
15 using layers::Image;
16 using layers::ImageContainer;
17 using layers::D3D9SurfaceImage;
18
19 class D3D9DXVA2Manager : public DXVA2Manager
20 {
21 public:
22 D3D9DXVA2Manager();
23 virtual ~D3D9DXVA2Manager();
24
25 HRESULT Init();
26
27 IUnknown* GetDXVADeviceManager() MOZ_OVERRIDE;
28
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;
35
36 private:
37 nsRefPtr<IDirect3D9Ex> mD3D9;
38 nsRefPtr<IDirect3DDevice9Ex> mDevice;
39 nsRefPtr<IDirect3DDeviceManager9> mDeviceManager;
40 UINT32 mResetToken;
41 };
42
43 D3D9DXVA2Manager::D3D9DXVA2Manager()
44 : mResetToken(0)
45 {
46 MOZ_COUNT_CTOR(D3D9DXVA2Manager);
47 MOZ_ASSERT(NS_IsMainThread());
48 }
49
50 D3D9DXVA2Manager::~D3D9DXVA2Manager()
51 {
52 MOZ_COUNT_DTOR(D3D9DXVA2Manager);
53 MOZ_ASSERT(NS_IsMainThread());
54 }
55
56 IUnknown*
57 D3D9DXVA2Manager::GetDXVADeviceManager()
58 {
59 MutexAutoLock lock(mLock);
60 return mDeviceManager;
61 }
62
63 HRESULT
64 D3D9DXVA2Manager::Init()
65 {
66 MOZ_ASSERT(NS_IsMainThread());
67
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 }
79
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);
87
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;
98
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);
110
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;
116
117 hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
118 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
119
120 // Create and initialize IDirect3DDeviceManager9.
121 UINT resetToken = 0;
122 nsRefPtr<IDirect3DDeviceManager9> deviceManager;
123
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);
129
130 mResetToken = resetToken;
131 mD3D9 = d3d9Ex;
132 mDevice = device;
133 mDeviceManager = deviceManager;
134
135 return S_OK;
136 }
137
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);
147
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);
154
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?");
159
160 D3D9SurfaceImage* videoImage = static_cast<D3D9SurfaceImage*>(image.get());
161 hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aRegion));
162
163 image.forget(aOutImage);
164
165 return S_OK;
166 }
167
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;
171
172 /* static */
173 DXVA2Manager*
174 DXVA2Manager::Create()
175 {
176 MOZ_ASSERT(NS_IsMainThread());
177 HRESULT hr;
178
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 }
186
187 nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
188 hr = d3d9Manager->Init();
189 if (SUCCEEDED(hr)) {
190 return d3d9Manager.forget();
191 }
192
193 // No hardware accelerated video decoding. :(
194 return nullptr;
195 }
196
197 DXVA2Manager::DXVA2Manager()
198 : mLock("DXVA2Manager")
199 {
200 MOZ_ASSERT(NS_IsMainThread());
201 ++sDXVAVideosCount;
202 }
203
204 DXVA2Manager::~DXVA2Manager()
205 {
206 MOZ_ASSERT(NS_IsMainThread());
207 --sDXVAVideosCount;
208 }
209
210 } // namespace mozilla

mercurial