Source code

Revision control

Other Tools

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 "WMFUtils.h"
8
#include "VideoUtils.h"
9
#include "mozilla/ArrayUtils.h"
10
#include "mozilla/CheckedInt.h"
11
#include "mozilla/Logging.h"
12
#include "mozilla/RefPtr.h"
13
#include "nsTArray.h"
14
#include "nsThreadUtils.h"
15
#include "nsWindowsHelpers.h"
16
#include "prenv.h"
17
#include <shlobj.h>
18
#include <shlwapi.h>
19
#include <initguid.h>
20
#include <stdint.h>
21
#include "mozilla/mscom/EnsureMTA.h"
22
#include "mozilla/WindowsVersion.h"
23
24
#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
25
// Some SDK versions don't define the AAC decoder CLSID.
26
// {32D186A7-218F-4C75-8876-DD77273A8999}
27
DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD,
28
0x77, 0x27, 0x3A, 0x89, 0x99);
29
#endif
30
31
namespace mozilla {
32
33
using media::TimeUnit;
34
35
HRESULT
36
HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames) {
37
MOZ_ASSERT(aOutFrames);
38
const int64_t HNS_PER_S = USECS_PER_S * 10;
39
CheckedInt<int64_t> i = aHNs;
40
i *= aRate;
41
i /= HNS_PER_S;
42
NS_ENSURE_TRUE(i.isValid(), E_FAIL);
43
*aOutFrames = i.value();
44
return S_OK;
45
}
46
47
HRESULT
48
GetDefaultStride(IMFMediaType* aType, uint32_t aWidth, uint32_t* aOutStride) {
49
// Try to get the default stride from the media type.
50
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
51
if (SUCCEEDED(hr)) {
52
return S_OK;
53
}
54
55
// Stride attribute not set, calculate it.
56
GUID subtype = GUID_NULL;
57
58
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
59
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
60
61
hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, aWidth,
62
(LONG*)(aOutStride));
63
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
64
65
return hr;
66
}
67
68
gfx::YUVColorSpace GetYUVColorSpace(IMFMediaType* aType) {
69
UINT32 yuvColorMatrix;
70
HRESULT hr = aType->GetUINT32(MF_MT_YUV_MATRIX, &yuvColorMatrix);
71
NS_ENSURE_TRUE(SUCCEEDED(hr), gfx::YUVColorSpace::UNKNOWN);
72
73
switch (yuvColorMatrix) {
74
case MFVideoTransferMatrix_BT2020_10:
75
case MFVideoTransferMatrix_BT2020_12:
76
return gfx::YUVColorSpace::BT2020;
77
case MFVideoTransferMatrix_BT709:
78
return gfx::YUVColorSpace::BT709;
79
case MFVideoTransferMatrix_BT601:
80
return gfx::YUVColorSpace::BT601;
81
default:
82
return gfx::YUVColorSpace::UNKNOWN;
83
}
84
}
85
86
int32_t MFOffsetToInt32(const MFOffset& aOffset) {
87
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
88
}
89
90
TimeUnit GetSampleDuration(IMFSample* aSample) {
91
NS_ENSURE_TRUE(aSample, TimeUnit::Invalid());
92
int64_t duration = 0;
93
aSample->GetSampleDuration(&duration);
94
return TimeUnit::FromMicroseconds(HNsToUsecs(duration));
95
}
96
97
TimeUnit GetSampleTime(IMFSample* aSample) {
98
NS_ENSURE_TRUE(aSample, TimeUnit::Invalid());
99
LONGLONG timestampHns = 0;
100
HRESULT hr = aSample->GetSampleTime(&timestampHns);
101
NS_ENSURE_TRUE(SUCCEEDED(hr), TimeUnit::Invalid());
102
return TimeUnit::FromMicroseconds(HNsToUsecs(timestampHns));
103
}
104
105
// Gets the sub-region of the video frame that should be displayed.
106
// See:
108
HRESULT
109
GetPictureRegion(IMFMediaType* aMediaType, gfx::IntRect& aOutPictureRegion) {
110
// Determine if "pan and scan" is enabled for this media. If it is, we
111
// only display a region of the video frame, not the entire frame.
112
BOOL panScan =
113
MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
114
115
// If pan and scan mode is enabled. Try to get the display region.
116
HRESULT hr = E_FAIL;
117
MFVideoArea videoArea;
118
memset(&videoArea, 0, sizeof(MFVideoArea));
119
if (panScan) {
120
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)&videoArea,
121
sizeof(MFVideoArea), nullptr);
122
}
123
124
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
125
// check for a minimimum display aperture.
126
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
127
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&videoArea,
128
sizeof(MFVideoArea), nullptr);
129
}
130
131
if (hr == MF_E_ATTRIBUTENOTFOUND) {
132
// Minimum display aperture is not set, for "backward compatibility with
133
// some components", check for a geometric aperture.
134
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&videoArea,
135
sizeof(MFVideoArea), nullptr);
136
}
137
138
if (SUCCEEDED(hr)) {
139
// The media specified a picture region, return it.
140
aOutPictureRegion = gfx::IntRect(MFOffsetToInt32(videoArea.OffsetX),
141
MFOffsetToInt32(videoArea.OffsetY),
142
videoArea.Area.cx, videoArea.Area.cy);
143
return S_OK;
144
}
145
146
// No picture region defined, fall back to using the entire video area.
147
UINT32 width = 0, height = 0;
148
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
149
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
150
NS_ENSURE_TRUE(width <= MAX_VIDEO_WIDTH, E_FAIL);
151
NS_ENSURE_TRUE(height <= MAX_VIDEO_HEIGHT, E_FAIL);
152
153
aOutPictureRegion = gfx::IntRect(0, 0, width, height);
154
return S_OK;
155
}
156
157
nsString GetProgramW6432Path() {
158
char* programPath = PR_GetEnvSecure("ProgramW6432");
159
if (!programPath) {
160
programPath = PR_GetEnvSecure("ProgramFiles");
161
}
162
163
if (!programPath) {
164
return NS_LITERAL_STRING("C:\\Program Files");
165
}
166
return NS_ConvertUTF8toUTF16(programPath);
167
}
168
169
namespace wmf {
170
171
static const wchar_t* sDLLs[] = {
172
L"mfplat.dll",
173
L"mf.dll",
174
L"dxva2.dll",
175
L"evr.dll",
176
};
177
178
HRESULT
179
LoadDLLs() {
180
static bool sDLLsLoaded = false;
181
static bool sFailedToLoadDlls = false;
182
183
if (sDLLsLoaded) {
184
return S_OK;
185
}
186
if (sFailedToLoadDlls) {
187
return E_FAIL;
188
}
189
190
// Try to load all the required DLLs. If we fail to load any dll,
191
// unload the dlls we succeeded in loading.
192
nsTArray<const wchar_t*> loadedDlls;
193
for (const wchar_t* dll : sDLLs) {
194
if (!LoadLibrarySystem32(dll)) {
195
NS_WARNING("Failed to load WMF DLLs");
196
for (const wchar_t* loadedDll : loadedDlls) {
197
FreeLibrary(GetModuleHandleW(loadedDll));
198
}
199
sFailedToLoadDlls = true;
200
return E_FAIL;
201
}
202
loadedDlls.AppendElement(dll);
203
}
204
sDLLsLoaded = true;
205
206
return S_OK;
207
}
208
209
#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
210
static FunctionType FunctionName##Ptr = nullptr; \
211
if (!FunctionName##Ptr) { \
212
FunctionName##Ptr = (FunctionType)GetProcAddress( \
213
GetModuleHandleW(L## #DLL), #FunctionName); \
214
if (!FunctionName##Ptr) { \
215
NS_WARNING("Failed to get GetProcAddress of " #FunctionName \
216
" from " #DLL); \
217
return E_FAIL; \
218
} \
219
}
220
221
#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
222
ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL)
223
224
#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
225
ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL)
226
227
#define DECL_FUNCTION_PTR(FunctionName, ...) \
228
typedef HRESULT(STDMETHODCALLTYPE* FunctionName##Ptr_t)(__VA_ARGS__)
229
230
HRESULT
231
MFStartup() {
232
if (IsWin7AndPre2000Compatible()) {
233
/*
234
* Specific exclude the usage of WMF on Win 7 with compatibility mode
235
* prior to Win 2000 as we may crash while trying to startup WMF.
236
* Using GetVersionEx API which takes compatibility mode into account.
237
* See Bug 1279171.
238
*/
239
return E_FAIL;
240
}
241
242
HRESULT hr = LoadDLLs();
243
if (FAILED(hr)) {
244
return hr;
245
}
246
247
const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
248
249
// decltype is unusable for functions having default parameters
250
DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
251
ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
252
253
hr = E_FAIL;
254
mozilla::mscom::EnsureMTA(
255
[&]() -> void { hr = MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL); });
256
return hr;
257
}
258
259
HRESULT
260
MFShutdown() {
261
ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
262
HRESULT hr = E_FAIL;
263
mozilla::mscom::EnsureMTA([&]() -> void { hr = (MFShutdownPtr)(); });
264
return hr;
265
}
266
267
HRESULT
268
MFCreateMediaType(IMFMediaType** aOutMFType) {
269
ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
270
return (MFCreateMediaTypePtr)(aOutMFType);
271
}
272
273
HRESULT
274
MFGetStrideForBitmapInfoHeader(DWORD aFormat, DWORD aWidth, LONG* aOutStride) {
275
ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, evr.dll)
276
return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
277
}
278
279
HRESULT MFGetService(IUnknown* punkObject, REFGUID guidService, REFIID riid,
280
LPVOID* ppvObject) {
281
ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
282
return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
283
}
284
285
HRESULT
286
DXVA2CreateDirect3DDeviceManager9(UINT* pResetToken,
287
IDirect3DDeviceManager9** ppDXVAManager) {
288
ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
289
return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
290
}
291
292
HRESULT
293
MFCreateSample(IMFSample** ppIMFSample) {
294
ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
295
return (MFCreateSamplePtr)(ppIMFSample);
296
}
297
298
HRESULT
299
MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, DWORD fAlignmentFlags,
300
IMFMediaBuffer** ppBuffer) {
301
ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
302
return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags,
303
ppBuffer);
304
}
305
306
HRESULT
307
MFCreateDXGIDeviceManager(UINT* pResetToken,
308
IMFDXGIDeviceManager** ppDXVAManager) {
309
ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
310
return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
311
}
312
313
HRESULT
314
MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown* punkSurface,
315
UINT uSubresourceIndex, BOOL fButtomUpWhenLinear,
316
IMFMediaBuffer** ppBuffer) {
317
ENSURE_FUNCTION_PTR(MFCreateDXGISurfaceBuffer, mfplat.dll)
318
return (MFCreateDXGISurfaceBufferPtr)(riid, punkSurface, uSubresourceIndex,
319
fButtomUpWhenLinear, ppBuffer);
320
}
321
322
} // end namespace wmf
323
} // end namespace mozilla