Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
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 "WMFUtils.h"
8 #include <stdint.h>
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/RefPtr.h"
11 #include "mozilla/WindowsVersion.h"
12 #include "prlog.h"
13 #include "nsThreadUtils.h"
14 #include "nsWindowsHelpers.h"
15 #include "mozilla/CheckedInt.h"
16 #include "VideoUtils.h"
17 #include <initguid.h>
19 #ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
20 // Some SDK versions don't define the AAC decoder CLSID.
21 // {32D186A7-218F-4C75-8876-DD77273A8999}
22 DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
23 #endif
25 namespace mozilla {
27 struct GuidToName {
28 GUID guid;
29 const char* name;
30 };
32 #define GUID_TO_NAME_ENTRY(g) { g, #g }
33 #define INTERFACE_TO_NAME_ENTRY(i) {IID_##i, #i }
35 GuidToName GuidToNameTable[] = {
36 GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE),
37 GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE),
38 GUID_TO_NAME_ENTRY(MF_MT_SUBTYPE),
39 GUID_TO_NAME_ENTRY(MF_MT_ALL_SAMPLES_INDEPENDENT),
40 GUID_TO_NAME_ENTRY(MF_MT_FIXED_SIZE_SAMPLES),
41 GUID_TO_NAME_ENTRY(MF_MT_COMPRESSED),
42 GUID_TO_NAME_ENTRY(MF_MT_SAMPLE_SIZE),
43 GUID_TO_NAME_ENTRY(MF_MT_WRAPPED_TYPE),
44 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_NUM_CHANNELS),
45 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_SECOND),
46 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND),
47 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_AVG_BYTES_PER_SECOND),
48 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BLOCK_ALIGNMENT),
49 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BITS_PER_SAMPLE),
50 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE),
51 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_BLOCK),
52 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_CHANNEL_MASK),
53 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FOLDDOWN_MATRIX),
54 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKREF),
55 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKTARGET),
56 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGREF),
57 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGTARGET),
58 GUID_TO_NAME_ENTRY(MF_MT_AUDIO_PREFER_WAVEFORMATEX),
59 GUID_TO_NAME_ENTRY(MF_MT_AAC_PAYLOAD_TYPE),
60 GUID_TO_NAME_ENTRY(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION),
61 GUID_TO_NAME_ENTRY(MF_MT_FRAME_SIZE),
62 GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE),
63 GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MAX),
64 GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MIN),
65 GUID_TO_NAME_ENTRY(MF_MT_PIXEL_ASPECT_RATIO),
66 GUID_TO_NAME_ENTRY(MF_MT_DRM_FLAGS),
67 GUID_TO_NAME_ENTRY(MF_MT_PAD_CONTROL_FLAGS),
68 GUID_TO_NAME_ENTRY(MF_MT_SOURCE_CONTENT_HINT),
69 GUID_TO_NAME_ENTRY(MF_MT_VIDEO_CHROMA_SITING),
70 GUID_TO_NAME_ENTRY(MF_MT_INTERLACE_MODE),
71 GUID_TO_NAME_ENTRY(MF_MT_TRANSFER_FUNCTION),
72 GUID_TO_NAME_ENTRY(MF_MT_VIDEO_PRIMARIES),
73 GUID_TO_NAME_ENTRY(MF_MT_CUSTOM_VIDEO_PRIMARIES),
74 GUID_TO_NAME_ENTRY(MF_MT_YUV_MATRIX),
75 GUID_TO_NAME_ENTRY(MF_MT_VIDEO_LIGHTING),
76 GUID_TO_NAME_ENTRY(MF_MT_VIDEO_NOMINAL_RANGE),
77 GUID_TO_NAME_ENTRY(MF_MT_GEOMETRIC_APERTURE),
78 GUID_TO_NAME_ENTRY(MF_MT_MINIMUM_DISPLAY_APERTURE),
79 GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_APERTURE),
80 GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_ENABLED),
81 GUID_TO_NAME_ENTRY(MF_MT_AVG_BITRATE),
82 GUID_TO_NAME_ENTRY(MF_MT_AVG_BIT_ERROR_RATE),
83 GUID_TO_NAME_ENTRY(MF_MT_MAX_KEYFRAME_SPACING),
84 GUID_TO_NAME_ENTRY(MF_MT_DEFAULT_STRIDE),
85 GUID_TO_NAME_ENTRY(MF_MT_PALETTE),
86 GUID_TO_NAME_ENTRY(MF_MT_USER_DATA),
87 GUID_TO_NAME_ENTRY(MF_MT_AM_FORMAT_TYPE),
88 GUID_TO_NAME_ENTRY(MF_MT_MPEG_START_TIME_CODE),
89 GUID_TO_NAME_ENTRY(MF_MT_MPEG2_PROFILE),
90 GUID_TO_NAME_ENTRY(MF_MT_MPEG2_LEVEL),
91 GUID_TO_NAME_ENTRY(MF_MT_MPEG2_FLAGS),
92 GUID_TO_NAME_ENTRY(MF_MT_MPEG_SEQUENCE_HEADER),
93 GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_0),
94 GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_0),
95 GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_1),
96 GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_1),
97 GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_SRC_PACK),
98 GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_CTRL_PACK),
99 GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_HEADER),
100 GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_FORMAT),
101 GUID_TO_NAME_ENTRY(MF_MT_IMAGE_LOSS_TOLERANT),
102 GUID_TO_NAME_ENTRY(MF_MT_MPEG4_SAMPLE_DESCRIPTION),
103 GUID_TO_NAME_ENTRY(MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY),
104 GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_4CC),
105 GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_WAVE_FORMAT_TAG),
107 GUID_TO_NAME_ENTRY(MFMediaType_Audio),
108 GUID_TO_NAME_ENTRY(MFMediaType_Video),
109 GUID_TO_NAME_ENTRY(MFMediaType_Protected),
110 GUID_TO_NAME_ENTRY(MFMediaType_SAMI),
111 GUID_TO_NAME_ENTRY(MFMediaType_Script),
112 GUID_TO_NAME_ENTRY(MFMediaType_Image),
113 GUID_TO_NAME_ENTRY(MFMediaType_HTML),
114 GUID_TO_NAME_ENTRY(MFMediaType_Binary),
115 GUID_TO_NAME_ENTRY(MFMediaType_FileTransfer),
117 GUID_TO_NAME_ENTRY(MFVideoFormat_AI44),
118 GUID_TO_NAME_ENTRY(MFVideoFormat_ARGB32),
119 GUID_TO_NAME_ENTRY(MFVideoFormat_AYUV),
120 GUID_TO_NAME_ENTRY(MFVideoFormat_DV25),
121 GUID_TO_NAME_ENTRY(MFVideoFormat_DV50),
122 GUID_TO_NAME_ENTRY(MFVideoFormat_DVH1),
123 GUID_TO_NAME_ENTRY(MFVideoFormat_DVSD),
124 GUID_TO_NAME_ENTRY(MFVideoFormat_DVSL),
125 GUID_TO_NAME_ENTRY(MFVideoFormat_H264),
126 GUID_TO_NAME_ENTRY(MFVideoFormat_I420),
127 GUID_TO_NAME_ENTRY(MFVideoFormat_IYUV),
128 GUID_TO_NAME_ENTRY(MFVideoFormat_M4S2),
129 GUID_TO_NAME_ENTRY(MFVideoFormat_MJPG),
130 GUID_TO_NAME_ENTRY(MFVideoFormat_MP43),
131 GUID_TO_NAME_ENTRY(MFVideoFormat_MP4S),
132 GUID_TO_NAME_ENTRY(MFVideoFormat_MP4V),
133 GUID_TO_NAME_ENTRY(MFVideoFormat_MPG1),
134 GUID_TO_NAME_ENTRY(MFVideoFormat_MSS1),
135 GUID_TO_NAME_ENTRY(MFVideoFormat_MSS2),
136 GUID_TO_NAME_ENTRY(MFVideoFormat_NV11),
137 GUID_TO_NAME_ENTRY(MFVideoFormat_NV12),
138 GUID_TO_NAME_ENTRY(MFVideoFormat_P010),
139 GUID_TO_NAME_ENTRY(MFVideoFormat_P016),
140 GUID_TO_NAME_ENTRY(MFVideoFormat_P210),
141 GUID_TO_NAME_ENTRY(MFVideoFormat_P216),
142 GUID_TO_NAME_ENTRY(MFVideoFormat_RGB24),
143 GUID_TO_NAME_ENTRY(MFVideoFormat_RGB32),
144 GUID_TO_NAME_ENTRY(MFVideoFormat_RGB555),
145 GUID_TO_NAME_ENTRY(MFVideoFormat_RGB565),
146 GUID_TO_NAME_ENTRY(MFVideoFormat_RGB8),
147 GUID_TO_NAME_ENTRY(MFVideoFormat_UYVY),
148 GUID_TO_NAME_ENTRY(MFVideoFormat_v210),
149 GUID_TO_NAME_ENTRY(MFVideoFormat_v410),
150 GUID_TO_NAME_ENTRY(MFVideoFormat_WMV1),
151 GUID_TO_NAME_ENTRY(MFVideoFormat_WMV2),
152 GUID_TO_NAME_ENTRY(MFVideoFormat_WMV3),
153 GUID_TO_NAME_ENTRY(MFVideoFormat_WVC1),
154 GUID_TO_NAME_ENTRY(MFVideoFormat_Y210),
155 GUID_TO_NAME_ENTRY(MFVideoFormat_Y216),
156 GUID_TO_NAME_ENTRY(MFVideoFormat_Y410),
157 GUID_TO_NAME_ENTRY(MFVideoFormat_Y416),
158 GUID_TO_NAME_ENTRY(MFVideoFormat_Y41P),
159 GUID_TO_NAME_ENTRY(MFVideoFormat_Y41T),
160 GUID_TO_NAME_ENTRY(MFVideoFormat_YUY2),
161 GUID_TO_NAME_ENTRY(MFVideoFormat_YV12),
162 GUID_TO_NAME_ENTRY(MFVideoFormat_YVYU),
164 GUID_TO_NAME_ENTRY(MFAudioFormat_PCM),
165 GUID_TO_NAME_ENTRY(MFAudioFormat_Float),
166 GUID_TO_NAME_ENTRY(MFAudioFormat_DTS),
167 GUID_TO_NAME_ENTRY(MFAudioFormat_Dolby_AC3_SPDIF),
168 GUID_TO_NAME_ENTRY(MFAudioFormat_DRM),
169 GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV8),
170 GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV9),
171 GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudio_Lossless),
172 GUID_TO_NAME_ENTRY(MFAudioFormat_WMASPDIF),
173 GUID_TO_NAME_ENTRY(MFAudioFormat_MSP1),
174 GUID_TO_NAME_ENTRY(MFAudioFormat_MP3),
175 GUID_TO_NAME_ENTRY(MFAudioFormat_MPEG),
176 GUID_TO_NAME_ENTRY(MFAudioFormat_AAC),
177 GUID_TO_NAME_ENTRY(MFAudioFormat_ADTS),
179 // Interfaces which may be implemented by WMFByteStream.
180 INTERFACE_TO_NAME_ENTRY(IUnknown),
181 INTERFACE_TO_NAME_ENTRY(IMFByteStream),
182 INTERFACE_TO_NAME_ENTRY(IMFMediaSource),
183 INTERFACE_TO_NAME_ENTRY(IMFAttributes),
184 INTERFACE_TO_NAME_ENTRY(IMFByteStreamBuffering),
185 };
187 nsCString GetGUIDName(const GUID& guid)
188 {
189 const unsigned numTypes = ArrayLength(GuidToNameTable);
190 for (unsigned i = 0; i < numTypes; i++) {
191 if (guid == GuidToNameTable[i].guid) {
192 return nsDependentCString(GuidToNameTable[i].name);
193 }
194 }
196 WCHAR* name = nullptr;
197 HRESULT hr = StringFromCLSID(guid , &name);
198 if (FAILED(hr)) {
199 return nsDependentCString("GuidUnknown");
200 }
201 nsCString name_u8(NS_ConvertUTF16toUTF8(nsDependentString((char16_t*)(name))));
202 CoTaskMemFree(name);
203 return name_u8;
204 }
206 bool
207 SourceReaderHasStream(IMFSourceReader* aReader, const DWORD aIndex)
208 {
209 RefPtr<IMFMediaType> nativeType;
210 HRESULT hr = aReader->GetNativeMediaType(aIndex, 0, byRef(nativeType));
211 return FAILED(hr) ? false : true;
212 }
214 HRESULT
215 DoGetInterface(IUnknown* aUnknown, void** aInterface)
216 {
217 if (!aInterface)
218 return E_POINTER;
219 *aInterface = aUnknown;
220 aUnknown->AddRef();
221 return S_OK;
222 }
224 HRESULT
225 HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames)
226 {
227 MOZ_ASSERT(aOutFrames);
228 const int64_t HNS_PER_S = USECS_PER_S * 10;
229 CheckedInt<int64_t> i = aHNs;
230 i *= aRate;
231 i /= HNS_PER_S;
232 NS_ENSURE_TRUE(i.isValid(), E_FAIL);
233 *aOutFrames = i.value();
234 return S_OK;
235 }
237 HRESULT
238 FramesToUsecs(int64_t aSamples, uint32_t aRate, int64_t* aOutUsecs)
239 {
240 MOZ_ASSERT(aOutUsecs);
241 CheckedInt<int64_t> i = aSamples;
242 i *= USECS_PER_S;
243 i /= aRate;
244 NS_ENSURE_TRUE(i.isValid(), E_FAIL);
245 *aOutUsecs = i.value();
246 return S_OK;
247 }
249 HRESULT
250 GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
251 {
252 // Try to get the default stride from the media type.
253 HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride);
254 if (SUCCEEDED(hr)) {
255 return S_OK;
256 }
258 // Stride attribute not set, calculate it.
259 GUID subtype = GUID_NULL;
260 uint32_t width = 0;
261 uint32_t height = 0;
263 hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
264 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
266 hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
267 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
269 hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride));
270 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
272 return hr;
273 }
275 int32_t
276 MFOffsetToInt32(const MFOffset& aOffset)
277 {
278 return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
279 }
281 int64_t
282 GetSampleDuration(IMFSample* aSample)
283 {
284 NS_ENSURE_TRUE(aSample, -1);
285 int64_t duration = 0;
286 aSample->GetSampleDuration(&duration);
287 return HNsToUsecs(duration);
288 }
290 int64_t
291 GetSampleTime(IMFSample* aSample)
292 {
293 NS_ENSURE_TRUE(aSample, -1);
294 LONGLONG timestampHns = 0;
295 HRESULT hr = aSample->GetSampleTime(×tampHns);
296 NS_ENSURE_TRUE(SUCCEEDED(hr), -1);
297 return HNsToUsecs(timestampHns);
298 }
300 // Gets the sub-region of the video frame that should be displayed.
301 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
302 HRESULT
303 GetPictureRegion(IMFMediaType* aMediaType, nsIntRect& aOutPictureRegion)
304 {
305 // Determine if "pan and scan" is enabled for this media. If it is, we
306 // only display a region of the video frame, not the entire frame.
307 BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
309 // If pan and scan mode is enabled. Try to get the display region.
310 HRESULT hr = E_FAIL;
311 MFVideoArea videoArea;
312 memset(&videoArea, 0, sizeof(MFVideoArea));
313 if (panScan) {
314 hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
315 (UINT8*)&videoArea,
316 sizeof(MFVideoArea),
317 nullptr);
318 }
320 // If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
321 // check for a minimimum display aperture.
322 if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
323 hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
324 (UINT8*)&videoArea,
325 sizeof(MFVideoArea),
326 nullptr);
327 }
329 if (hr == MF_E_ATTRIBUTENOTFOUND) {
330 // Minimum display aperture is not set, for "backward compatibility with
331 // some components", check for a geometric aperture.
332 hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
333 (UINT8*)&videoArea,
334 sizeof(MFVideoArea),
335 nullptr);
336 }
338 if (SUCCEEDED(hr)) {
339 // The media specified a picture region, return it.
340 aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX),
341 MFOffsetToInt32(videoArea.OffsetY),
342 videoArea.Area.cx,
343 videoArea.Area.cy);
344 return S_OK;
345 }
347 // No picture region defined, fall back to using the entire video area.
348 UINT32 width = 0, height = 0;
349 hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
350 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
351 aOutPictureRegion = nsIntRect(0, 0, width, height);
352 return S_OK;
353 }
355 namespace wmf {
357 static bool
358 IsSupportedDecoder(const GUID& aDecoderGUID)
359 {
360 return aDecoderGUID == CLSID_CMSH264DecoderMFT ||
361 aDecoderGUID == CLSID_CMSAACDecMFT ||
362 aDecoderGUID == CLSID_CMP3DecMediaObject;
363 }
365 static HRESULT
366 DisableBlockedDecoders(IMFPluginControl* aPluginControl,
367 const GUID& aCategory)
368 {
369 HRESULT hr = S_OK;
371 UINT32 numMFTs = 0;
372 IMFActivate **ppActivate = nullptr;
373 hr = wmf::MFTEnumEx(aCategory,
374 MFT_ENUM_FLAG_ALL,
375 nullptr, // Input type, nullptr -> match all.
376 nullptr, // Output type, nullptr -> match all.
377 &ppActivate,
378 &numMFTs);
380 if (SUCCEEDED(hr) && numMFTs == 0) {
381 hr = MF_E_TOPO_CODEC_NOT_FOUND;
382 }
384 for (UINT32 i = 0; i < numMFTs; i++) {
385 // Note: We must release all IMFActivate objects in the list, hence
386 // we're putting individual IMFActivate objects in into a smart ptr.
387 RefPtr<IMFActivate> activate = ppActivate[i];
388 GUID guid = GUID_NULL;
389 hr = activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid);
390 if (FAILED(hr)) {
391 NS_WARNING("FAILED to get IMFActivate clsid");
392 continue;
393 }
394 if (!IsSupportedDecoder(guid)) {
395 hr = aPluginControl->SetDisabled(MF_Plugin_Type_MFT, guid, TRUE);
396 NS_ASSERTION(SUCCEEDED(hr), "Failed to disable plugin!");
397 }
398 }
399 CoTaskMemFree(ppActivate);
401 return hr;
402 }
404 static HRESULT
405 DisableBlockedDecoders()
406 {
407 RefPtr<IMFPluginControl> pluginControl;
408 HRESULT hr = wmf::MFGetPluginControl(byRef(pluginControl));
409 if (SUCCEEDED(hr) && pluginControl) {
410 hr = DisableBlockedDecoders(pluginControl,
411 MFT_CATEGORY_VIDEO_DECODER);
412 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
414 hr = DisableBlockedDecoders(pluginControl,
415 MFT_CATEGORY_AUDIO_DECODER);
416 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
417 }
419 return S_OK;
420 }
422 static bool sDLLsLoaded = false;
423 static bool sFailedToLoadDlls = false;
425 struct WMFModule {
426 const wchar_t* name;
427 HMODULE handle;
428 };
430 static WMFModule sDLLs[] = {
431 { L"mfplat.dll", nullptr },
432 { L"mfreadwrite.dll", nullptr },
433 { L"propsys.dll", nullptr },
434 { L"mf.dll", nullptr },
435 { L"dxva2.dll", nullptr }
436 };
438 HRESULT
439 LoadDLLs()
440 {
441 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
443 if (sDLLsLoaded) {
444 return S_OK;
445 }
446 if (sFailedToLoadDlls) {
447 return E_FAIL;
448 }
450 // Try to load all the required DLLs.
451 const uint32_t dllLength = ArrayLength(sDLLs);
452 for (uint32_t i = 0; i < dllLength; i++) {
453 sDLLs[i].handle = LoadLibrarySystem32(sDLLs[i].name);
454 if (!sDLLs[i].handle) {
455 sFailedToLoadDlls = true;
456 NS_WARNING("Failed to load WMF DLLs");
457 UnloadDLLs();
458 return E_FAIL;
459 }
460 }
462 // Enumerate all the decoders on the system, and disable the ones except
463 // those which we expect to use, the MP3, AAC and H.264 decoders.
464 if (FAILED(DisableBlockedDecoders())) {
465 sFailedToLoadDlls = true;
466 NS_WARNING("Failed to disable non whitelisted WMF decoders");
467 UnloadDLLs();
468 return E_FAIL;
469 }
471 sDLLsLoaded = true;
473 return S_OK;
474 }
476 HRESULT
477 UnloadDLLs()
478 {
479 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
481 const uint32_t length = ArrayLength(sDLLs);
482 for (uint32_t i = 0; i < length; i++) {
483 if (sDLLs[i].handle) {
484 FreeLibrary(sDLLs[i].handle);
485 sDLLs[i].handle = nullptr;
486 }
487 sDLLsLoaded = false;
488 }
489 return S_OK;
490 }
492 #define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
493 static FunctionType FunctionName##Ptr = nullptr; \
494 if (!FunctionName##Ptr) { \
495 FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandle(#DLL), #FunctionName); \
496 if (!FunctionName##Ptr) { \
497 NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \
498 return E_FAIL; \
499 } \
500 }
502 #define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
503 ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \
505 #define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
506 ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \
508 #define DECL_FUNCTION_PTR(FunctionName, ...) \
509 typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__)
511 HRESULT
512 MFStartup()
513 {
514 const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION);
515 const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
517 // decltype is unusable for functions having default parameters
518 DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
519 ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
520 if (!IsWin7OrLater())
521 return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL);
522 else
523 return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL);
524 }
526 HRESULT
527 MFShutdown()
528 {
529 ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
530 return (MFShutdownPtr)();
531 }
533 HRESULT
534 MFCreateAsyncResult(IUnknown *aUnkObject,
535 IMFAsyncCallback *aCallback,
536 IUnknown *aUnkState,
537 IMFAsyncResult **aOutAsyncResult)
538 {
539 ENSURE_FUNCTION_PTR(MFCreateAsyncResult, Mfplat.dll)
540 return (MFCreateAsyncResultPtr)(aUnkObject, aCallback, aUnkState, aOutAsyncResult);
541 }
543 HRESULT
544 MFInvokeCallback(IMFAsyncResult *aAsyncResult)
545 {
546 ENSURE_FUNCTION_PTR(MFInvokeCallback, Mfplat.dll);
547 return (MFInvokeCallbackPtr)(aAsyncResult);
548 }
550 HRESULT
551 MFCreateMediaType(IMFMediaType **aOutMFType)
552 {
553 ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
554 return (MFCreateMediaTypePtr)(aOutMFType);
555 }
557 HRESULT
558 MFCreateSourceReaderFromByteStream(IMFByteStream *aByteStream,
559 IMFAttributes *aAttributes,
560 IMFSourceReader **aOutSourceReader)
561 {
562 ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromByteStream, Mfreadwrite.dll)
563 return (MFCreateSourceReaderFromByteStreamPtr)(aByteStream,
564 aAttributes,
565 aOutSourceReader);
566 }
568 HRESULT
569 PropVariantToUInt32(REFPROPVARIANT aPropvar, ULONG *aOutUL)
570 {
571 // decltype is unusable for overloaded functions
572 DECL_FUNCTION_PTR(PropVariantToUInt32, REFPROPVARIANT, ULONG *);
573 ENSURE_FUNCTION_PTR_(PropVariantToUInt32, Propsys.dll)
574 return (PropVariantToUInt32Ptr)(aPropvar, aOutUL);
575 }
577 HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL)
578 {
579 ENSURE_FUNCTION_PTR(PropVariantToInt64, Propsys.dll)
580 return (PropVariantToInt64Ptr)(aPropVar, aOutLL);
581 }
583 HRESULT
584 MFTGetInfo(CLSID aClsidMFT,
585 LPWSTR *aOutName,
586 MFT_REGISTER_TYPE_INFO **aOutInputTypes,
587 UINT32 *aOutNumInputTypes,
588 MFT_REGISTER_TYPE_INFO **aOutOutputTypes,
589 UINT32 *aOutNumOutputTypes,
590 IMFAttributes **aOutAttributes)
591 {
592 ENSURE_FUNCTION_PTR(MFTGetInfo, Mfplat.dll)
593 return (MFTGetInfoPtr)(aClsidMFT,
594 aOutName,
595 aOutInputTypes,
596 aOutNumInputTypes,
597 aOutOutputTypes,
598 aOutNumOutputTypes,
599 aOutAttributes);
600 }
602 HRESULT
603 MFGetStrideForBitmapInfoHeader(DWORD aFormat,
604 DWORD aWidth,
605 LONG *aOutStride)
606 {
607 ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, Mfplat.dll)
608 return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
609 }
611 HRESULT
612 MFCreateSourceReaderFromURL(LPCWSTR aURL,
613 IMFAttributes *aAttributes,
614 IMFSourceReader **aSourceReader)
615 {
616 ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromURL, Mfreadwrite.dll)
617 return (MFCreateSourceReaderFromURLPtr)(aURL, aAttributes, aSourceReader);
618 }
620 HRESULT
621 MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize)
622 {
623 ENSURE_FUNCTION_PTR(MFCreateAttributes, mfplat.dll)
624 return (MFCreateAttributesPtr)(ppMFAttributes, cInitialSize);
625 }
627 HRESULT
628 MFGetPluginControl(IMFPluginControl **aOutPluginControl)
629 {
630 ENSURE_FUNCTION_PTR(MFGetPluginControl, mfplat.dll)
631 return (MFGetPluginControlPtr)(aOutPluginControl);
632 }
634 HRESULT
635 MFTEnumEx(GUID guidCategory,
636 UINT32 Flags,
637 const MFT_REGISTER_TYPE_INFO *pInputType,
638 const MFT_REGISTER_TYPE_INFO *pOutputType,
639 IMFActivate ***pppMFTActivate,
640 UINT32 *pcMFTActivate)
641 {
642 ENSURE_FUNCTION_PTR(MFTEnumEx, mfplat.dll)
643 return (MFTEnumExPtr)(guidCategory, Flags, pInputType, pOutputType, pppMFTActivate, pcMFTActivate);
644 }
646 HRESULT MFGetService(IUnknown *punkObject,
647 REFGUID guidService,
648 REFIID riid,
649 LPVOID *ppvObject)
650 {
651 ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
652 return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
653 }
655 HRESULT
656 DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken,
657 IDirect3DDeviceManager9 **ppDXVAManager)
658 {
659 ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
660 return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
661 }
663 HRESULT
664 MFCreateSample(IMFSample **ppIMFSample)
665 {
666 ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
667 return (MFCreateSamplePtr)(ppIMFSample);
668 }
670 HRESULT
671 MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,
672 DWORD fAlignmentFlags,
673 IMFMediaBuffer **ppBuffer)
674 {
675 ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
676 return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer);
677 }
679 } // end namespace wmf
680 } // end namespace mozilla