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 #ifndef __MINGW32__
28 #pragma comment(lib, "mfuuid.lib")
29 #pragma comment(lib, "wmcodecdspuuid")
30 #endif
31 
LOG(const char * format,...)32 void LOG(const char* format, ...) {
33 #ifdef WMF_DECODER_LOG
34   va_list args;
35   va_start(args, format);
36   vprintf(format, args);
37 #endif
38 }
39 
40 DEFINE_GUID(CLSID_CMSH264DecMFT, 0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45,
41             0x28, 0x31, 0xA8, 0x7D, 0x9D);
42 
43 namespace wmf {
44 
45 #define MFPLAT_FUNC(_func, _dllname) decltype(::_func)* _func;
46 #include "WMFSymbols.h"
47 #undef MFPLAT_FUNC
48 
LinkMfplat()49 static bool LinkMfplat() {
50   static bool sInitDone = false;
51   static bool sInitOk = false;
52   if (!sInitDone) {
53     sInitDone = true;
54     HMODULE handle;
55 
56 #define MFPLAT_FUNC(_func, _dllname)                                  \
57   handle = GetModuleHandleA(_dllname);                                \
58   if (!(_func = (decltype(_func))(GetProcAddress(handle, #_func)))) { \
59     return false;                                                     \
60   }
61 
62 #include "WMFSymbols.h"
63 #undef MFPLAT_FUNC
64     sInitOk = true;
65   }
66   return sInitOk;
67 }
68 
WMFDecoderDllName()69 const char* WMFDecoderDllName() {
70   // For H.264 decoding, we need msmpeg2vdec.dll on Win 7 & 8,
71   // and mfh264dec.dll on Vista.
72   if (IsWindows7OrGreater()) {
73     return "msmpeg2vdec.dll";
74   } else {
75     return "mfh264dec.dll";
76   }
77 }
78 
EnsureLibs()79 bool EnsureLibs() {
80   static bool sInitDone = false;
81   static bool sInitOk = false;
82   if (!sInitDone) {
83     sInitOk = LinkMfplat() && !!GetModuleHandleA(WMFDecoderDllName());
84     sInitDone = true;
85   }
86   return sInitOk;
87 }
88 
MFOffsetToInt32(const MFOffset & aOffset)89 int32_t MFOffsetToInt32(const MFOffset& aOffset) {
90   return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
91 }
92 
93 // Gets the sub-region of the video frame that should be displayed.
94 // See:
95 // http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
96 HRESULT
GetPictureRegion(IMFMediaType * aMediaType,IntRect & aOutPictureRegion)97 GetPictureRegion(IMFMediaType* aMediaType, IntRect& aOutPictureRegion) {
98   // Determine if "pan and scan" is enabled for this media. If it is, we
99   // only display a region of the video frame, not the entire frame.
100   BOOL panScan =
101       MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
102 
103   // If pan and scan mode is enabled. Try to get the display region.
104   HRESULT hr = E_FAIL;
105   MFVideoArea videoArea;
106   memset(&videoArea, 0, sizeof(MFVideoArea));
107   if (panScan) {
108     hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE, (UINT8*)&videoArea,
109                              sizeof(MFVideoArea), NULL);
110   }
111 
112   // If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
113   // check for a minimimum display aperture.
114   if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
115     hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&videoArea,
116                              sizeof(MFVideoArea), NULL);
117   }
118 
119   if (hr == MF_E_ATTRIBUTENOTFOUND) {
120     // Minimum display aperture is not set, for "backward compatibility with
121     // some components", check for a geometric aperture.
122     hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE, (UINT8*)&videoArea,
123                              sizeof(MFVideoArea), NULL);
124   }
125 
126   if (SUCCEEDED(hr)) {
127     // The media specified a picture region, return it.
128     IntRect picture = IntRect(MFOffsetToInt32(videoArea.OffsetX),
129                               MFOffsetToInt32(videoArea.OffsetY),
130                               videoArea.Area.cx, videoArea.Area.cy);
131     ENSURE(picture.width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
132     ENSURE(picture.height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
133     aOutPictureRegion = picture;
134     return S_OK;
135   }
136 
137   // No picture region defined, fall back to using the entire video area.
138   UINT32 width = 0, height = 0;
139   hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
140   ENSURE(SUCCEEDED(hr), hr);
141   ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
142   ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
143   aOutPictureRegion = IntRect(0, 0, width, height);
144   return S_OK;
145 }
146 
147 HRESULT
GetDefaultStride(IMFMediaType * aType,uint32_t * aOutStride)148 GetDefaultStride(IMFMediaType* aType, uint32_t* aOutStride) {
149   // Try to get the default stride from the media type.
150   UINT32 stride = 0;
151   HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, &stride);
152   if (SUCCEEDED(hr)) {
153     ENSURE(stride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
154     *aOutStride = stride;
155     return S_OK;
156   }
157 
158   // Stride attribute not set, calculate it.
159   GUID subtype = GUID_NULL;
160   uint32_t width = 0;
161   uint32_t height = 0;
162 
163   hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
164   ENSURE(SUCCEEDED(hr), hr);
165 
166   hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
167   ENSURE(SUCCEEDED(hr), hr);
168   ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
169   ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
170 
171   LONG lstride = 0;
172   hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lstride);
173   ENSURE(SUCCEEDED(hr), hr);
174   ENSURE(lstride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
175   ENSURE(lstride >= 0, E_FAIL);
176   *aOutStride = lstride;
177 
178   return hr;
179 }
180 
dump(const uint8_t * data,uint32_t len,const char * filename)181 void dump(const uint8_t* data, uint32_t len, const char* filename) {
182   FILE* f = 0;
183   fopen_s(&f, filename, "wb");
184   fwrite(data, len, 1, f);
185   fclose(f);
186 }
187 
188 HRESULT
CreateMFT(const CLSID & clsid,const char * aDllName,CComPtr<IMFTransform> & aOutMFT)189 CreateMFT(const CLSID& clsid, const char* aDllName,
190           CComPtr<IMFTransform>& aOutMFT) {
191   HMODULE module = ::GetModuleHandleA(aDllName);
192   if (!module) {
193     LOG("Failed to get %S\n", aDllName);
194     return E_FAIL;
195   }
196 
197   typedef HRESULT(WINAPI * DllGetClassObjectFnPtr)(
198       const CLSID& clsid, const IID& iid, void** object);
199 
200   DllGetClassObjectFnPtr GetClassObjPtr =
201       reinterpret_cast<DllGetClassObjectFnPtr>(
202           GetProcAddress(module, "DllGetClassObject"));
203   if (!GetClassObjPtr) {
204     LOG("Failed to get DllGetClassObject\n");
205     return E_FAIL;
206   }
207 
208   CComPtr<IClassFactory> classFactory;
209   HRESULT hr = GetClassObjPtr(
210       clsid, __uuidof(IClassFactory),
211       reinterpret_cast<void**>(static_cast<IClassFactory**>(&classFactory)));
212   if (FAILED(hr)) {
213     LOG("Failed to get H264 IClassFactory\n");
214     return E_FAIL;
215   }
216 
217   hr = classFactory->CreateInstance(
218       NULL, __uuidof(IMFTransform),
219       reinterpret_cast<void**>(static_cast<IMFTransform**>(&aOutMFT)));
220   if (FAILED(hr)) {
221     LOG("Failed to get create MFT\n");
222     return E_FAIL;
223   }
224 
225   return S_OK;
226 }
227 
GetNumThreads(int32_t aCoreCount)228 int32_t GetNumThreads(int32_t aCoreCount) {
229   return aCoreCount > 4 ? -1 : (std::max)(aCoreCount - 1, 1);
230 }
231 
232 }  // namespace
233