|
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 <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> |
|
18 |
|
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 |
|
24 |
|
25 namespace mozilla { |
|
26 |
|
27 struct GuidToName { |
|
28 GUID guid; |
|
29 const char* name; |
|
30 }; |
|
31 |
|
32 #define GUID_TO_NAME_ENTRY(g) { g, #g } |
|
33 #define INTERFACE_TO_NAME_ENTRY(i) {IID_##i, #i } |
|
34 |
|
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), |
|
106 |
|
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), |
|
116 |
|
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), |
|
163 |
|
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), |
|
178 |
|
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 }; |
|
186 |
|
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 } |
|
195 |
|
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 } |
|
205 |
|
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 } |
|
213 |
|
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 } |
|
223 |
|
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 } |
|
236 |
|
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 } |
|
248 |
|
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 } |
|
257 |
|
258 // Stride attribute not set, calculate it. |
|
259 GUID subtype = GUID_NULL; |
|
260 uint32_t width = 0; |
|
261 uint32_t height = 0; |
|
262 |
|
263 hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype); |
|
264 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
265 |
|
266 hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height); |
|
267 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
268 |
|
269 hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride)); |
|
270 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
271 |
|
272 return hr; |
|
273 } |
|
274 |
|
275 int32_t |
|
276 MFOffsetToInt32(const MFOffset& aOffset) |
|
277 { |
|
278 return int32_t(aOffset.value + (aOffset.fract / 65536.0f)); |
|
279 } |
|
280 |
|
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 } |
|
289 |
|
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 } |
|
299 |
|
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); |
|
308 |
|
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 } |
|
319 |
|
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 } |
|
328 |
|
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 } |
|
337 |
|
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 } |
|
346 |
|
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 } |
|
354 |
|
355 namespace wmf { |
|
356 |
|
357 static bool |
|
358 IsSupportedDecoder(const GUID& aDecoderGUID) |
|
359 { |
|
360 return aDecoderGUID == CLSID_CMSH264DecoderMFT || |
|
361 aDecoderGUID == CLSID_CMSAACDecMFT || |
|
362 aDecoderGUID == CLSID_CMP3DecMediaObject; |
|
363 } |
|
364 |
|
365 static HRESULT |
|
366 DisableBlockedDecoders(IMFPluginControl* aPluginControl, |
|
367 const GUID& aCategory) |
|
368 { |
|
369 HRESULT hr = S_OK; |
|
370 |
|
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); |
|
379 |
|
380 if (SUCCEEDED(hr) && numMFTs == 0) { |
|
381 hr = MF_E_TOPO_CODEC_NOT_FOUND; |
|
382 } |
|
383 |
|
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); |
|
400 |
|
401 return hr; |
|
402 } |
|
403 |
|
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); |
|
413 |
|
414 hr = DisableBlockedDecoders(pluginControl, |
|
415 MFT_CATEGORY_AUDIO_DECODER); |
|
416 NS_ENSURE_TRUE(SUCCEEDED(hr), hr); |
|
417 } |
|
418 |
|
419 return S_OK; |
|
420 } |
|
421 |
|
422 static bool sDLLsLoaded = false; |
|
423 static bool sFailedToLoadDlls = false; |
|
424 |
|
425 struct WMFModule { |
|
426 const wchar_t* name; |
|
427 HMODULE handle; |
|
428 }; |
|
429 |
|
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 }; |
|
437 |
|
438 HRESULT |
|
439 LoadDLLs() |
|
440 { |
|
441 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
|
442 |
|
443 if (sDLLsLoaded) { |
|
444 return S_OK; |
|
445 } |
|
446 if (sFailedToLoadDlls) { |
|
447 return E_FAIL; |
|
448 } |
|
449 |
|
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 } |
|
461 |
|
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 } |
|
470 |
|
471 sDLLsLoaded = true; |
|
472 |
|
473 return S_OK; |
|
474 } |
|
475 |
|
476 HRESULT |
|
477 UnloadDLLs() |
|
478 { |
|
479 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
|
480 |
|
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 } |
|
491 |
|
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 } |
|
501 |
|
502 #define ENSURE_FUNCTION_PTR(FunctionName, DLL) \ |
|
503 ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \ |
|
504 |
|
505 #define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \ |
|
506 ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \ |
|
507 |
|
508 #define DECL_FUNCTION_PTR(FunctionName, ...) \ |
|
509 typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__) |
|
510 |
|
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); |
|
516 |
|
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 } |
|
525 |
|
526 HRESULT |
|
527 MFShutdown() |
|
528 { |
|
529 ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll) |
|
530 return (MFShutdownPtr)(); |
|
531 } |
|
532 |
|
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 } |
|
542 |
|
543 HRESULT |
|
544 MFInvokeCallback(IMFAsyncResult *aAsyncResult) |
|
545 { |
|
546 ENSURE_FUNCTION_PTR(MFInvokeCallback, Mfplat.dll); |
|
547 return (MFInvokeCallbackPtr)(aAsyncResult); |
|
548 } |
|
549 |
|
550 HRESULT |
|
551 MFCreateMediaType(IMFMediaType **aOutMFType) |
|
552 { |
|
553 ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll) |
|
554 return (MFCreateMediaTypePtr)(aOutMFType); |
|
555 } |
|
556 |
|
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 } |
|
567 |
|
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 } |
|
576 |
|
577 HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL) |
|
578 { |
|
579 ENSURE_FUNCTION_PTR(PropVariantToInt64, Propsys.dll) |
|
580 return (PropVariantToInt64Ptr)(aPropVar, aOutLL); |
|
581 } |
|
582 |
|
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 } |
|
601 |
|
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 } |
|
610 |
|
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 } |
|
619 |
|
620 HRESULT |
|
621 MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize) |
|
622 { |
|
623 ENSURE_FUNCTION_PTR(MFCreateAttributes, mfplat.dll) |
|
624 return (MFCreateAttributesPtr)(ppMFAttributes, cInitialSize); |
|
625 } |
|
626 |
|
627 HRESULT |
|
628 MFGetPluginControl(IMFPluginControl **aOutPluginControl) |
|
629 { |
|
630 ENSURE_FUNCTION_PTR(MFGetPluginControl, mfplat.dll) |
|
631 return (MFGetPluginControlPtr)(aOutPluginControl); |
|
632 } |
|
633 |
|
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 } |
|
645 |
|
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 } |
|
654 |
|
655 HRESULT |
|
656 DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken, |
|
657 IDirect3DDeviceManager9 **ppDXVAManager) |
|
658 { |
|
659 ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll) |
|
660 return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager); |
|
661 } |
|
662 |
|
663 HRESULT |
|
664 MFCreateSample(IMFSample **ppIMFSample) |
|
665 { |
|
666 ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll) |
|
667 return (MFCreateSamplePtr)(ppIMFSample); |
|
668 } |
|
669 |
|
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 } |
|
678 |
|
679 } // end namespace wmf |
|
680 } // end namespace mozilla |