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
HNsToFrames(int64_t aHNs,uint32_t aRate,int64_t * aOutFrames)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
GetDefaultStride(IMFMediaType * aType,uint32_t aWidth,uint32_t * aOutStride)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
GetYUVColorSpace(IMFMediaType * aType)68 YUVColorSpace GetYUVColorSpace(IMFMediaType* aType) {
69 UINT32 yuvColorMatrix;
70 HRESULT hr = aType->GetUINT32(MF_MT_YUV_MATRIX, &yuvColorMatrix);
71 NS_ENSURE_TRUE(SUCCEEDED(hr), YUVColorSpace::BT601);
72
73 switch (yuvColorMatrix) {
74 case MFVideoTransferMatrix_BT709:
75 return YUVColorSpace::BT709;
76 case MFVideoTransferMatrix_BT601:
77 default:
78 return YUVColorSpace::BT601;
79 }
80 }
81
MFOffsetToInt32(const MFOffset & aOffset)82 int32_t MFOffsetToInt32(const MFOffset& aOffset) {
83 return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
84 }
85
GetSampleDuration(IMFSample * aSample)86 TimeUnit GetSampleDuration(IMFSample* aSample) {
87 NS_ENSURE_TRUE(aSample, TimeUnit::Invalid());
88 int64_t duration = 0;
89 aSample->GetSampleDuration(&duration);
90 return TimeUnit::FromMicroseconds(HNsToUsecs(duration));
91 }
92
GetSampleTime(IMFSample * aSample)93 TimeUnit GetSampleTime(IMFSample* aSample) {
94 NS_ENSURE_TRUE(aSample, TimeUnit::Invalid());
95 LONGLONG timestampHns = 0;
96 HRESULT hr = aSample->GetSampleTime(×tampHns);
97 NS_ENSURE_TRUE(SUCCEEDED(hr), TimeUnit::Invalid());
98 return TimeUnit::FromMicroseconds(HNsToUsecs(timestampHns));
99 }
100
101 // Gets the sub-region of the video frame that should be displayed.
102 // See:
103 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
104 HRESULT
GetPictureRegion(IMFMediaType * aMediaType,gfx::IntRect & aOutPictureRegion)105 GetPictureRegion(IMFMediaType* aMediaType, gfx::IntRect& aOutPictureRegion) {
106 // Determine if "pan and scan" is enabled for this media. If it is, we
107 // only display a region of the video frame, not the entire frame.
108 BOOL panScan =
109 MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
110
111 // If pan and scan mode is enabled. Try to get the display region.
112 HRESULT hr = E_FAIL;
113 MFVideoArea videoArea;
114 memset(&videoArea, 0, sizeof(MFVideoArea));
115 if (panScan) {
116 hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)&videoArea,
117 sizeof(MFVideoArea), nullptr);
118 }
119
120 // If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
121 // check for a minimimum display aperture.
122 if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
123 hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&videoArea,
124 sizeof(MFVideoArea), nullptr);
125 }
126
127 if (hr == MF_E_ATTRIBUTENOTFOUND) {
128 // Minimum display aperture is not set, for "backward compatibility with
129 // some components", check for a geometric aperture.
130 hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&videoArea,
131 sizeof(MFVideoArea), nullptr);
132 }
133
134 if (SUCCEEDED(hr)) {
135 // The media specified a picture region, return it.
136 aOutPictureRegion = gfx::IntRect(MFOffsetToInt32(videoArea.OffsetX),
137 MFOffsetToInt32(videoArea.OffsetY),
138 videoArea.Area.cx, videoArea.Area.cy);
139 return S_OK;
140 }
141
142 // No picture region defined, fall back to using the entire video area.
143 UINT32 width = 0, height = 0;
144 hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
145 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
146 NS_ENSURE_TRUE(width <= MAX_VIDEO_WIDTH, E_FAIL);
147 NS_ENSURE_TRUE(height <= MAX_VIDEO_HEIGHT, E_FAIL);
148
149 aOutPictureRegion = gfx::IntRect(0, 0, width, height);
150 return S_OK;
151 }
152
GetProgramW6432Path()153 nsString GetProgramW6432Path() {
154 char* programPath = PR_GetEnvSecure("ProgramW6432");
155 if (!programPath) {
156 programPath = PR_GetEnvSecure("ProgramFiles");
157 }
158
159 if (!programPath) {
160 return NS_LITERAL_STRING("C:\\Program Files");
161 }
162 return NS_ConvertUTF8toUTF16(programPath);
163 }
164
165 namespace wmf {
166
167 static const wchar_t* sDLLs[] = {
168 L"mfplat.dll",
169 L"mf.dll",
170 L"dxva2.dll",
171 L"evr.dll",
172 };
173
174 HRESULT
LoadDLLs()175 LoadDLLs() {
176 static bool sDLLsLoaded = false;
177 static bool sFailedToLoadDlls = false;
178
179 if (sDLLsLoaded) {
180 return S_OK;
181 }
182 if (sFailedToLoadDlls) {
183 return E_FAIL;
184 }
185
186 // Try to load all the required DLLs. If we fail to load any dll,
187 // unload the dlls we succeeded in loading.
188 nsTArray<const wchar_t*> loadedDlls;
189 for (const wchar_t* dll : sDLLs) {
190 if (!LoadLibrarySystem32(dll)) {
191 NS_WARNING("Failed to load WMF DLLs");
192 for (const wchar_t* loadedDll : loadedDlls) {
193 FreeLibrary(GetModuleHandleW(loadedDll));
194 }
195 sFailedToLoadDlls = true;
196 return E_FAIL;
197 }
198 loadedDlls.AppendElement(dll);
199 }
200 sDLLsLoaded = true;
201
202 return S_OK;
203 }
204
205 #define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \
206 static FunctionType FunctionName##Ptr = nullptr; \
207 if (!FunctionName##Ptr) { \
208 FunctionName##Ptr = (FunctionType)GetProcAddress( \
209 GetModuleHandleW(L## #DLL), #FunctionName); \
210 if (!FunctionName##Ptr) { \
211 NS_WARNING("Failed to get GetProcAddress of " #FunctionName \
212 " from " #DLL); \
213 return E_FAIL; \
214 } \
215 }
216
217 #define ENSURE_FUNCTION_PTR(FunctionName, DLL) \
218 ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL)
219
220 #define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \
221 ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL)
222
223 #define DECL_FUNCTION_PTR(FunctionName, ...) \
224 typedef HRESULT(STDMETHODCALLTYPE* FunctionName##Ptr_t)(__VA_ARGS__)
225
226 HRESULT
MFStartup()227 MFStartup() {
228 if (IsWin7AndPre2000Compatible()) {
229 /*
230 * Specific exclude the usage of WMF on Win 7 with compatibility mode
231 * prior to Win 2000 as we may crash while trying to startup WMF.
232 * Using GetVersionEx API which takes compatibility mode into account.
233 * See Bug 1279171.
234 */
235 return E_FAIL;
236 }
237
238 HRESULT hr = LoadDLLs();
239 if (FAILED(hr)) {
240 return hr;
241 }
242
243 const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION);
244
245 // decltype is unusable for functions having default parameters
246 DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD);
247 ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll)
248
249 hr = E_FAIL;
250 mozilla::mscom::EnsureMTA(
251 [&]() -> void { hr = MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL); });
252 return hr;
253 }
254
255 HRESULT
MFShutdown()256 MFShutdown() {
257 ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll)
258 HRESULT hr = E_FAIL;
259 mozilla::mscom::EnsureMTA([&]() -> void { hr = (MFShutdownPtr)(); });
260 return hr;
261 }
262
263 HRESULT
MFCreateMediaType(IMFMediaType ** aOutMFType)264 MFCreateMediaType(IMFMediaType** aOutMFType) {
265 ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll)
266 return (MFCreateMediaTypePtr)(aOutMFType);
267 }
268
269 HRESULT
MFGetStrideForBitmapInfoHeader(DWORD aFormat,DWORD aWidth,LONG * aOutStride)270 MFGetStrideForBitmapInfoHeader(DWORD aFormat, DWORD aWidth, LONG* aOutStride) {
271 ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, evr.dll)
272 return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride);
273 }
274
MFGetService(IUnknown * punkObject,REFGUID guidService,REFIID riid,LPVOID * ppvObject)275 HRESULT MFGetService(IUnknown* punkObject, REFGUID guidService, REFIID riid,
276 LPVOID* ppvObject) {
277 ENSURE_FUNCTION_PTR(MFGetService, mf.dll)
278 return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject);
279 }
280
281 HRESULT
DXVA2CreateDirect3DDeviceManager9(UINT * pResetToken,IDirect3DDeviceManager9 ** ppDXVAManager)282 DXVA2CreateDirect3DDeviceManager9(UINT* pResetToken,
283 IDirect3DDeviceManager9** ppDXVAManager) {
284 ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll)
285 return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager);
286 }
287
288 HRESULT
MFCreateSample(IMFSample ** ppIMFSample)289 MFCreateSample(IMFSample** ppIMFSample) {
290 ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll)
291 return (MFCreateSamplePtr)(ppIMFSample);
292 }
293
294 HRESULT
MFCreateAlignedMemoryBuffer(DWORD cbMaxLength,DWORD fAlignmentFlags,IMFMediaBuffer ** ppBuffer)295 MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, DWORD fAlignmentFlags,
296 IMFMediaBuffer** ppBuffer) {
297 ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll)
298 return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags,
299 ppBuffer);
300 }
301
302 HRESULT
MFCreateDXGIDeviceManager(UINT * pResetToken,IMFDXGIDeviceManager ** ppDXVAManager)303 MFCreateDXGIDeviceManager(UINT* pResetToken,
304 IMFDXGIDeviceManager** ppDXVAManager) {
305 ENSURE_FUNCTION_PTR(MFCreateDXGIDeviceManager, mfplat.dll)
306 return (MFCreateDXGIDeviceManagerPtr)(pResetToken, ppDXVAManager);
307 }
308
309 HRESULT
MFCreateDXGISurfaceBuffer(REFIID riid,IUnknown * punkSurface,UINT uSubresourceIndex,BOOL fButtomUpWhenLinear,IMFMediaBuffer ** ppBuffer)310 MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown* punkSurface,
311 UINT uSubresourceIndex, BOOL fButtomUpWhenLinear,
312 IMFMediaBuffer** ppBuffer) {
313 ENSURE_FUNCTION_PTR(MFCreateDXGISurfaceBuffer, mfplat.dll)
314 return (MFCreateDXGISurfaceBufferPtr)(riid, punkSurface, uSubresourceIndex,
315 fButtomUpWhenLinear, ppBuffer);
316 }
317
318 } // end namespace wmf
319 } // end namespace mozilla
320