1 /*
2 * Copyright 2013, Mozilla Foundation and contributors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "WMFUtils.h"
18 #include "ClearKeyUtils.h"
19 #include <versionhelpers.h>
20
21 #include <algorithm>
22 #include <stdio.h>
23
24 #define INITGUID
25 #include <guiddef.h>
26
27 #pragma comment(lib, "mfuuid.lib")
28 #pragma comment(lib, "wmcodecdspuuid")
29
LOG(const char * format,...)30 void LOG(const char* format, ...)
31 {
32 #ifdef WMF_DECODER_LOG
33 va_list args;
34 va_start(args, format);
35 vprintf(format, args);
36 #endif
37 }
38
39 #ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID
40 // Some SDK versions don't define the AAC decoder CLSID.
41 // {32D186A7-218F-4C75-8876-DD77273A8999}
42 DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99);
43 #endif
44
45 DEFINE_GUID(CLSID_CMSH264DecMFT, 0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45, 0x28, 0x31, 0xA8, 0x7D, 0x9D);
46
47 namespace wmf {
48
49
50 #define MFPLAT_FUNC(_func, _dllname) \
51 decltype(::_func)* _func;
52 #include "WMFSymbols.h"
53 #undef MFPLAT_FUNC
54
55 static bool
LinkMfplat()56 LinkMfplat()
57 {
58 static bool sInitDone = false;
59 static bool sInitOk = false;
60 if (!sInitDone) {
61 sInitDone = true;
62 HMODULE handle;
63
64 #define MFPLAT_FUNC(_func, _dllname) \
65 handle = GetModuleHandleA(_dllname); \
66 if (!(_func = (decltype(_func))(GetProcAddress(handle, #_func)))) { \
67 return false; \
68 }
69
70 #include "WMFSymbols.h"
71 #undef MFPLAT_FUNC
72 sInitOk = true;
73 }
74 return sInitOk;
75 }
76
77 const char*
WMFDecoderDllNameFor(CodecType aCodec)78 WMFDecoderDllNameFor(CodecType aCodec)
79 {
80 if (aCodec == H264) {
81 // For H.264 decoding, we need msmpeg2vdec.dll on Win 7 & 8,
82 // and mfh264dec.dll on Vista.
83 if (IsWindows7OrGreater()) {
84 return "msmpeg2vdec.dll";
85 } else {
86 return "mfh264dec.dll";
87 }
88 } else if (aCodec == AAC) {
89 // For AAC decoding, we need to use msauddecmft.dll on Win8,
90 // msmpeg2adec.dll on Win7, and msheaacdec.dll on Vista.
91 if (IsWindows8OrGreater()) {
92 return "msauddecmft.dll";
93 } else if (IsWindows7OrGreater()) {
94 return "msmpeg2adec.dll";
95 } else {
96 return "mfheaacdec.dll";
97 }
98 } else {
99 return "";
100 }
101 }
102
103
104 bool
EnsureLibs()105 EnsureLibs()
106 {
107 static bool sInitDone = false;
108 static bool sInitOk = false;
109 if (!sInitDone) {
110 sInitOk = LinkMfplat() &&
111 !!GetModuleHandleA(WMFDecoderDllNameFor(AAC)) &&
112 !!GetModuleHandleA(WMFDecoderDllNameFor(H264));
113 sInitDone = true;
114 }
115 return sInitOk;
116 }
117
118 int32_t
MFOffsetToInt32(const MFOffset & aOffset)119 MFOffsetToInt32(const MFOffset& aOffset)
120 {
121 return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
122 }
123
124 // Gets the sub-region of the video frame that should be displayed.
125 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
126 HRESULT
GetPictureRegion(IMFMediaType * aMediaType,IntRect & aOutPictureRegion)127 GetPictureRegion(IMFMediaType* aMediaType, IntRect& aOutPictureRegion)
128 {
129 // Determine if "pan and scan" is enabled for this media. If it is, we
130 // only display a region of the video frame, not the entire frame.
131 BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
132
133 // If pan and scan mode is enabled. Try to get the display region.
134 HRESULT hr = E_FAIL;
135 MFVideoArea videoArea;
136 memset(&videoArea, 0, sizeof(MFVideoArea));
137 if (panScan) {
138 hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
139 (UINT8*)&videoArea,
140 sizeof(MFVideoArea),
141 NULL);
142 }
143
144 // If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
145 // check for a minimimum display aperture.
146 if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
147 hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
148 (UINT8*)&videoArea,
149 sizeof(MFVideoArea),
150 NULL);
151 }
152
153 if (hr == MF_E_ATTRIBUTENOTFOUND) {
154 // Minimum display aperture is not set, for "backward compatibility with
155 // some components", check for a geometric aperture.
156 hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
157 (UINT8*)&videoArea,
158 sizeof(MFVideoArea),
159 NULL);
160 }
161
162 if (SUCCEEDED(hr)) {
163 // The media specified a picture region, return it.
164 IntRect picture = IntRect(MFOffsetToInt32(videoArea.OffsetX),
165 MFOffsetToInt32(videoArea.OffsetY),
166 videoArea.Area.cx,
167 videoArea.Area.cy);
168 ENSURE(picture.width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
169 ENSURE(picture.height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
170 aOutPictureRegion = picture;
171 return S_OK;
172 }
173
174 // No picture region defined, fall back to using the entire video area.
175 UINT32 width = 0, height = 0;
176 hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
177 ENSURE(SUCCEEDED(hr), hr);
178 ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
179 ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
180 aOutPictureRegion = IntRect(0, 0, width, height);
181 return S_OK;
182 }
183
184
185 HRESULT
GetDefaultStride(IMFMediaType * aType,uint32_t * aOutStride)186 GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
187 {
188 // Try to get the default stride from the media type.
189 UINT32 stride = 0;
190 HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, &stride);
191 if (SUCCEEDED(hr)) {
192 ENSURE(stride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
193 *aOutStride = stride;
194 return S_OK;
195 }
196
197 // Stride attribute not set, calculate it.
198 GUID subtype = GUID_NULL;
199 uint32_t width = 0;
200 uint32_t height = 0;
201
202 hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
203 ENSURE(SUCCEEDED(hr), hr);
204
205 hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
206 ENSURE(SUCCEEDED(hr), hr);
207 ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
208 ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
209
210 LONG lstride = 0;
211 hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lstride);
212 ENSURE(SUCCEEDED(hr), hr);
213 ENSURE(lstride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
214 ENSURE(lstride >= 0, E_FAIL);
215 *aOutStride = lstride;
216
217 return hr;
218 }
219
dump(const uint8_t * data,uint32_t len,const char * filename)220 void dump(const uint8_t* data, uint32_t len, const char* filename)
221 {
222 FILE* f = 0;
223 fopen_s(&f, filename, "wb");
224 fwrite(data, len, 1, f);
225 fclose(f);
226 }
227
228 HRESULT
CreateMFT(const CLSID & clsid,const char * aDllName,CComPtr<IMFTransform> & aOutMFT)229 CreateMFT(const CLSID& clsid,
230 const char* aDllName,
231 CComPtr<IMFTransform>& aOutMFT)
232 {
233 HMODULE module = ::GetModuleHandleA(aDllName);
234 if (!module) {
235 LOG("Failed to get %S\n", aDllName);
236 return E_FAIL;
237 }
238
239 typedef HRESULT (WINAPI* DllGetClassObjectFnPtr)(const CLSID& clsid,
240 const IID& iid,
241 void** object);
242
243 DllGetClassObjectFnPtr GetClassObjPtr =
244 reinterpret_cast<DllGetClassObjectFnPtr>(GetProcAddress(module, "DllGetClassObject"));
245 if (!GetClassObjPtr) {
246 LOG("Failed to get DllGetClassObject\n");
247 return E_FAIL;
248 }
249
250 CComPtr<IClassFactory> classFactory;
251 HRESULT hr = GetClassObjPtr(clsid,
252 __uuidof(IClassFactory),
253 reinterpret_cast<void**>(static_cast<IClassFactory**>(&classFactory)));
254 if (FAILED(hr)) {
255 LOG("Failed to get H264 IClassFactory\n");
256 return E_FAIL;
257 }
258
259 hr = classFactory->CreateInstance(NULL,
260 __uuidof(IMFTransform),
261 reinterpret_cast<void**>(static_cast<IMFTransform**>(&aOutMFT)));
262 if (FAILED(hr)) {
263 LOG("Failed to get create MFT\n");
264 return E_FAIL;
265 }
266
267 return S_OK;
268 }
269
270 int32_t
GetNumThreads(int32_t aCoreCount)271 GetNumThreads(int32_t aCoreCount)
272 {
273 return aCoreCount > 4 ? -1 : (std::max)(aCoreCount - 1, 1);
274 }
275
276 } // namespace
277