2015-01-16 00:37:54 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2013, Mozilla Foundation and contributors
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
#include "WMFUtils.h"
|
2015-04-20 11:07:24 +03:00
|
|
|
#include "ClearKeyUtils.h"
|
2015-04-29 18:39:35 +03:00
|
|
|
#include <versionhelpers.h>
|
2015-01-16 00:37:54 +03:00
|
|
|
|
2015-09-01 08:31:48 +03:00
|
|
|
#include <algorithm>
|
2015-01-16 00:37:54 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#define INITGUID
|
|
|
|
#include <guiddef.h>
|
|
|
|
|
|
|
|
#pragma comment(lib, "mfuuid.lib")
|
|
|
|
#pragma comment(lib, "wmcodecdspuuid")
|
|
|
|
|
|
|
|
void LOG(const char* format, ...)
|
2015-01-16 00:37:54 +03:00
|
|
|
{
|
2015-01-16 00:37:54 +03:00
|
|
|
#ifdef WMF_DECODER_LOG
|
2015-01-16 00:37:54 +03:00
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
2015-01-16 00:37:54 +03:00
|
|
|
vprintf(format, args);
|
|
|
|
#endif
|
|
|
|
}
|
2015-01-16 00:37:54 +03:00
|
|
|
|
2015-04-13 04:39:53 +03:00
|
|
|
DEFINE_GUID(CLSID_CMSH264DecMFT, 0x62CE7E72, 0x4C71, 0x4d20, 0xB1, 0x5D, 0x45, 0x28, 0x31, 0xA8, 0x7D, 0x9D);
|
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
namespace wmf {
|
|
|
|
|
|
|
|
|
2015-04-20 11:07:24 +03:00
|
|
|
#define MFPLAT_FUNC(_func, _dllname) \
|
2015-01-16 00:37:54 +03:00
|
|
|
decltype(::_func)* _func;
|
|
|
|
#include "WMFSymbols.h"
|
|
|
|
#undef MFPLAT_FUNC
|
2015-01-16 00:37:54 +03:00
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
static bool
|
|
|
|
LinkMfplat()
|
|
|
|
{
|
|
|
|
static bool sInitDone = false;
|
|
|
|
static bool sInitOk = false;
|
|
|
|
if (!sInitDone) {
|
|
|
|
sInitDone = true;
|
2015-04-20 11:07:24 +03:00
|
|
|
HMODULE handle;
|
|
|
|
|
|
|
|
#define MFPLAT_FUNC(_func, _dllname) \
|
|
|
|
handle = GetModuleHandleA(_dllname); \
|
|
|
|
if (!(_func = (decltype(_func))(GetProcAddress(handle, #_func)))) { \
|
|
|
|
return false; \
|
|
|
|
}
|
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
#include "WMFSymbols.h"
|
|
|
|
#undef MFPLAT_FUNC
|
|
|
|
sInitOk = true;
|
|
|
|
}
|
|
|
|
return sInitOk;
|
|
|
|
}
|
2015-01-16 00:37:54 +03:00
|
|
|
|
2015-04-20 11:07:24 +03:00
|
|
|
const char*
|
2016-11-22 04:32:26 +03:00
|
|
|
WMFDecoderDllName()
|
2015-04-20 11:07:24 +03:00
|
|
|
{
|
2016-11-22 04:32:26 +03:00
|
|
|
// For H.264 decoding, we need msmpeg2vdec.dll on Win 7 & 8,
|
|
|
|
// and mfh264dec.dll on Vista.
|
|
|
|
if (IsWindows7OrGreater()) {
|
|
|
|
return "msmpeg2vdec.dll";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return "mfh264dec.dll";
|
2015-04-20 11:07:24 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
bool
|
|
|
|
EnsureLibs()
|
|
|
|
{
|
|
|
|
static bool sInitDone = false;
|
|
|
|
static bool sInitOk = false;
|
|
|
|
if (!sInitDone) {
|
|
|
|
sInitOk = LinkMfplat() &&
|
2016-11-22 04:32:26 +03:00
|
|
|
!!GetModuleHandleA(WMFDecoderDllName());
|
2015-01-16 00:37:54 +03:00
|
|
|
sInitDone = true;
|
|
|
|
}
|
|
|
|
return sInitOk;
|
|
|
|
}
|
2015-01-16 00:37:54 +03:00
|
|
|
|
|
|
|
int32_t
|
|
|
|
MFOffsetToInt32(const MFOffset& aOffset)
|
|
|
|
{
|
|
|
|
return int32_t(aOffset.value + (aOffset.fract / 65536.0f));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the sub-region of the video frame that should be displayed.
|
|
|
|
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb530115(v=vs.85).aspx
|
|
|
|
HRESULT
|
|
|
|
GetPictureRegion(IMFMediaType* aMediaType, IntRect& aOutPictureRegion)
|
|
|
|
{
|
|
|
|
// Determine if "pan and scan" is enabled for this media. If it is, we
|
|
|
|
// only display a region of the video frame, not the entire frame.
|
|
|
|
BOOL panScan = MFGetAttributeUINT32(aMediaType, MF_MT_PAN_SCAN_ENABLED, FALSE);
|
|
|
|
|
|
|
|
// If pan and scan mode is enabled. Try to get the display region.
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
MFVideoArea videoArea;
|
|
|
|
memset(&videoArea, 0, sizeof(MFVideoArea));
|
|
|
|
if (panScan) {
|
|
|
|
hr = aMediaType->GetBlob(MF_MT_PAN_SCAN_APERTURE,
|
|
|
|
(UINT8*)&videoArea,
|
|
|
|
sizeof(MFVideoArea),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we're not in pan-and-scan mode, or the pan-and-scan region is not set,
|
|
|
|
// check for a minimimum display aperture.
|
|
|
|
if (!panScan || hr == MF_E_ATTRIBUTENOTFOUND) {
|
|
|
|
hr = aMediaType->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE,
|
|
|
|
(UINT8*)&videoArea,
|
|
|
|
sizeof(MFVideoArea),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hr == MF_E_ATTRIBUTENOTFOUND) {
|
|
|
|
// Minimum display aperture is not set, for "backward compatibility with
|
|
|
|
// some components", check for a geometric aperture.
|
|
|
|
hr = aMediaType->GetBlob(MF_MT_GEOMETRIC_APERTURE,
|
|
|
|
(UINT8*)&videoArea,
|
|
|
|
sizeof(MFVideoArea),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
|
|
// The media specified a picture region, return it.
|
2017-05-01 07:12:27 +03:00
|
|
|
IntRect picture = IntRect(MFOffsetToInt32(videoArea.OffsetX),
|
|
|
|
MFOffsetToInt32(videoArea.OffsetY),
|
|
|
|
videoArea.Area.cx,
|
|
|
|
videoArea.Area.cy);
|
|
|
|
ENSURE(picture.width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
|
|
|
|
ENSURE(picture.height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
|
|
|
|
aOutPictureRegion = picture;
|
2015-01-16 00:37:54 +03:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// No picture region defined, fall back to using the entire video area.
|
|
|
|
UINT32 width = 0, height = 0;
|
|
|
|
hr = MFGetAttributeSize(aMediaType, MF_MT_FRAME_SIZE, &width, &height);
|
|
|
|
ENSURE(SUCCEEDED(hr), hr);
|
2017-05-01 07:12:27 +03:00
|
|
|
ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
|
|
|
|
ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
|
2015-01-16 00:37:54 +03:00
|
|
|
aOutPictureRegion = IntRect(0, 0, width, height);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
|
|
GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride)
|
|
|
|
{
|
|
|
|
// Try to get the default stride from the media type.
|
2017-05-01 07:12:27 +03:00
|
|
|
UINT32 stride = 0;
|
|
|
|
HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, &stride);
|
2015-01-16 00:37:54 +03:00
|
|
|
if (SUCCEEDED(hr)) {
|
2017-05-01 07:12:27 +03:00
|
|
|
ENSURE(stride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
|
|
|
|
*aOutStride = stride;
|
2015-01-16 00:37:54 +03:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stride attribute not set, calculate it.
|
|
|
|
GUID subtype = GUID_NULL;
|
|
|
|
uint32_t width = 0;
|
|
|
|
uint32_t height = 0;
|
|
|
|
|
|
|
|
hr = aType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
|
|
|
ENSURE(SUCCEEDED(hr), hr);
|
|
|
|
|
|
|
|
hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height);
|
|
|
|
ENSURE(SUCCEEDED(hr), hr);
|
2017-05-01 07:12:27 +03:00
|
|
|
ENSURE(width <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
|
|
|
|
ENSURE(height <= mozilla::MAX_VIDEO_HEIGHT, E_FAIL);
|
2015-01-16 00:37:54 +03:00
|
|
|
|
2017-05-01 07:12:27 +03:00
|
|
|
LONG lstride = 0;
|
|
|
|
hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lstride);
|
2015-01-16 00:37:54 +03:00
|
|
|
ENSURE(SUCCEEDED(hr), hr);
|
2017-05-01 07:12:27 +03:00
|
|
|
ENSURE(lstride <= mozilla::MAX_VIDEO_WIDTH, E_FAIL);
|
|
|
|
ENSURE(lstride >= 0, E_FAIL);
|
|
|
|
*aOutStride = lstride;
|
2015-01-16 00:37:54 +03:00
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dump(const uint8_t* data, uint32_t len, const char* filename)
|
|
|
|
{
|
|
|
|
FILE* f = 0;
|
|
|
|
fopen_s(&f, filename, "wb");
|
|
|
|
fwrite(data, len, 1, f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
|
|
CreateMFT(const CLSID& clsid,
|
2015-01-16 00:37:54 +03:00
|
|
|
const char* aDllName,
|
2015-01-16 00:37:54 +03:00
|
|
|
CComPtr<IMFTransform>& aOutMFT)
|
|
|
|
{
|
2015-03-08 22:27:05 +03:00
|
|
|
HMODULE module = ::GetModuleHandleA(aDllName);
|
2015-01-16 00:37:54 +03:00
|
|
|
if (!module) {
|
2015-01-16 00:37:54 +03:00
|
|
|
LOG("Failed to get %S\n", aDllName);
|
2015-01-16 00:37:54 +03:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef HRESULT (WINAPI* DllGetClassObjectFnPtr)(const CLSID& clsid,
|
|
|
|
const IID& iid,
|
|
|
|
void** object);
|
|
|
|
|
|
|
|
DllGetClassObjectFnPtr GetClassObjPtr =
|
|
|
|
reinterpret_cast<DllGetClassObjectFnPtr>(GetProcAddress(module, "DllGetClassObject"));
|
|
|
|
if (!GetClassObjPtr) {
|
2015-01-16 00:37:54 +03:00
|
|
|
LOG("Failed to get DllGetClassObject\n");
|
2015-01-16 00:37:54 +03:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CComPtr<IClassFactory> classFactory;
|
|
|
|
HRESULT hr = GetClassObjPtr(clsid,
|
|
|
|
__uuidof(IClassFactory),
|
|
|
|
reinterpret_cast<void**>(static_cast<IClassFactory**>(&classFactory)));
|
|
|
|
if (FAILED(hr)) {
|
2015-01-16 00:37:54 +03:00
|
|
|
LOG("Failed to get H264 IClassFactory\n");
|
2015-01-16 00:37:54 +03:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = classFactory->CreateInstance(NULL,
|
|
|
|
__uuidof(IMFTransform),
|
|
|
|
reinterpret_cast<void**>(static_cast<IMFTransform**>(&aOutMFT)));
|
|
|
|
if (FAILED(hr)) {
|
2015-01-16 00:37:54 +03:00
|
|
|
LOG("Failed to get create MFT\n");
|
2015-01-16 00:37:54 +03:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
2015-01-16 00:37:54 +03:00
|
|
|
}
|
|
|
|
|
2015-09-01 08:31:48 +03:00
|
|
|
int32_t
|
|
|
|
GetNumThreads(int32_t aCoreCount)
|
|
|
|
{
|
|
|
|
return aCoreCount > 4 ? -1 : (std::max)(aCoreCount - 1, 1);
|
|
|
|
}
|
|
|
|
|
2015-01-16 00:37:54 +03:00
|
|
|
} // namespace
|