diff -r 000000000000 -r 6474c204b198 content/media/wmf/WMFUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/wmf/WMFUtils.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,680 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WMFUtils.h" +#include +#include "mozilla/ArrayUtils.h" +#include "mozilla/RefPtr.h" +#include "mozilla/WindowsVersion.h" +#include "prlog.h" +#include "nsThreadUtils.h" +#include "nsWindowsHelpers.h" +#include "mozilla/CheckedInt.h" +#include "VideoUtils.h" +#include + +#ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID +// Some SDK versions don't define the AAC decoder CLSID. +// {32D186A7-218F-4C75-8876-DD77273A8999} +DEFINE_GUID(CLSID_CMSAACDecMFT, 0x32D186A7, 0x218F, 0x4C75, 0x88, 0x76, 0xDD, 0x77, 0x27, 0x3A, 0x89, 0x99); +#endif + +namespace mozilla { + +struct GuidToName { + GUID guid; + const char* name; +}; + +#define GUID_TO_NAME_ENTRY(g) { g, #g } +#define INTERFACE_TO_NAME_ENTRY(i) {IID_##i, #i } + +GuidToName GuidToNameTable[] = { + GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE), + GUID_TO_NAME_ENTRY(MF_MT_MAJOR_TYPE), + GUID_TO_NAME_ENTRY(MF_MT_SUBTYPE), + GUID_TO_NAME_ENTRY(MF_MT_ALL_SAMPLES_INDEPENDENT), + GUID_TO_NAME_ENTRY(MF_MT_FIXED_SIZE_SAMPLES), + GUID_TO_NAME_ENTRY(MF_MT_COMPRESSED), + GUID_TO_NAME_ENTRY(MF_MT_SAMPLE_SIZE), + GUID_TO_NAME_ENTRY(MF_MT_WRAPPED_TYPE), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_NUM_CHANNELS), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_SECOND), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_AVG_BYTES_PER_SECOND), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BLOCK_ALIGNMENT), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_BITS_PER_SAMPLE), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_VALID_BITS_PER_SAMPLE), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_SAMPLES_PER_BLOCK), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_CHANNEL_MASK), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_FOLDDOWN_MATRIX), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKREF), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_PEAKTARGET), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGREF), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_WMADRC_AVGTARGET), + GUID_TO_NAME_ENTRY(MF_MT_AUDIO_PREFER_WAVEFORMATEX), + GUID_TO_NAME_ENTRY(MF_MT_AAC_PAYLOAD_TYPE), + GUID_TO_NAME_ENTRY(MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION), + GUID_TO_NAME_ENTRY(MF_MT_FRAME_SIZE), + GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE), + GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MAX), + GUID_TO_NAME_ENTRY(MF_MT_FRAME_RATE_RANGE_MIN), + GUID_TO_NAME_ENTRY(MF_MT_PIXEL_ASPECT_RATIO), + GUID_TO_NAME_ENTRY(MF_MT_DRM_FLAGS), + GUID_TO_NAME_ENTRY(MF_MT_PAD_CONTROL_FLAGS), + GUID_TO_NAME_ENTRY(MF_MT_SOURCE_CONTENT_HINT), + GUID_TO_NAME_ENTRY(MF_MT_VIDEO_CHROMA_SITING), + GUID_TO_NAME_ENTRY(MF_MT_INTERLACE_MODE), + GUID_TO_NAME_ENTRY(MF_MT_TRANSFER_FUNCTION), + GUID_TO_NAME_ENTRY(MF_MT_VIDEO_PRIMARIES), + GUID_TO_NAME_ENTRY(MF_MT_CUSTOM_VIDEO_PRIMARIES), + GUID_TO_NAME_ENTRY(MF_MT_YUV_MATRIX), + GUID_TO_NAME_ENTRY(MF_MT_VIDEO_LIGHTING), + GUID_TO_NAME_ENTRY(MF_MT_VIDEO_NOMINAL_RANGE), + GUID_TO_NAME_ENTRY(MF_MT_GEOMETRIC_APERTURE), + GUID_TO_NAME_ENTRY(MF_MT_MINIMUM_DISPLAY_APERTURE), + GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_APERTURE), + GUID_TO_NAME_ENTRY(MF_MT_PAN_SCAN_ENABLED), + GUID_TO_NAME_ENTRY(MF_MT_AVG_BITRATE), + GUID_TO_NAME_ENTRY(MF_MT_AVG_BIT_ERROR_RATE), + GUID_TO_NAME_ENTRY(MF_MT_MAX_KEYFRAME_SPACING), + GUID_TO_NAME_ENTRY(MF_MT_DEFAULT_STRIDE), + GUID_TO_NAME_ENTRY(MF_MT_PALETTE), + GUID_TO_NAME_ENTRY(MF_MT_USER_DATA), + GUID_TO_NAME_ENTRY(MF_MT_AM_FORMAT_TYPE), + GUID_TO_NAME_ENTRY(MF_MT_MPEG_START_TIME_CODE), + GUID_TO_NAME_ENTRY(MF_MT_MPEG2_PROFILE), + GUID_TO_NAME_ENTRY(MF_MT_MPEG2_LEVEL), + GUID_TO_NAME_ENTRY(MF_MT_MPEG2_FLAGS), + GUID_TO_NAME_ENTRY(MF_MT_MPEG_SEQUENCE_HEADER), + GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_0), + GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_0), + GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_SRC_PACK_1), + GUID_TO_NAME_ENTRY(MF_MT_DV_AAUX_CTRL_PACK_1), + GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_SRC_PACK), + GUID_TO_NAME_ENTRY(MF_MT_DV_VAUX_CTRL_PACK), + GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_HEADER), + GUID_TO_NAME_ENTRY(MF_MT_ARBITRARY_FORMAT), + GUID_TO_NAME_ENTRY(MF_MT_IMAGE_LOSS_TOLERANT), + GUID_TO_NAME_ENTRY(MF_MT_MPEG4_SAMPLE_DESCRIPTION), + GUID_TO_NAME_ENTRY(MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY), + GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_4CC), + GUID_TO_NAME_ENTRY(MF_MT_ORIGINAL_WAVE_FORMAT_TAG), + + GUID_TO_NAME_ENTRY(MFMediaType_Audio), + GUID_TO_NAME_ENTRY(MFMediaType_Video), + GUID_TO_NAME_ENTRY(MFMediaType_Protected), + GUID_TO_NAME_ENTRY(MFMediaType_SAMI), + GUID_TO_NAME_ENTRY(MFMediaType_Script), + GUID_TO_NAME_ENTRY(MFMediaType_Image), + GUID_TO_NAME_ENTRY(MFMediaType_HTML), + GUID_TO_NAME_ENTRY(MFMediaType_Binary), + GUID_TO_NAME_ENTRY(MFMediaType_FileTransfer), + + GUID_TO_NAME_ENTRY(MFVideoFormat_AI44), + GUID_TO_NAME_ENTRY(MFVideoFormat_ARGB32), + GUID_TO_NAME_ENTRY(MFVideoFormat_AYUV), + GUID_TO_NAME_ENTRY(MFVideoFormat_DV25), + GUID_TO_NAME_ENTRY(MFVideoFormat_DV50), + GUID_TO_NAME_ENTRY(MFVideoFormat_DVH1), + GUID_TO_NAME_ENTRY(MFVideoFormat_DVSD), + GUID_TO_NAME_ENTRY(MFVideoFormat_DVSL), + GUID_TO_NAME_ENTRY(MFVideoFormat_H264), + GUID_TO_NAME_ENTRY(MFVideoFormat_I420), + GUID_TO_NAME_ENTRY(MFVideoFormat_IYUV), + GUID_TO_NAME_ENTRY(MFVideoFormat_M4S2), + GUID_TO_NAME_ENTRY(MFVideoFormat_MJPG), + GUID_TO_NAME_ENTRY(MFVideoFormat_MP43), + GUID_TO_NAME_ENTRY(MFVideoFormat_MP4S), + GUID_TO_NAME_ENTRY(MFVideoFormat_MP4V), + GUID_TO_NAME_ENTRY(MFVideoFormat_MPG1), + GUID_TO_NAME_ENTRY(MFVideoFormat_MSS1), + GUID_TO_NAME_ENTRY(MFVideoFormat_MSS2), + GUID_TO_NAME_ENTRY(MFVideoFormat_NV11), + GUID_TO_NAME_ENTRY(MFVideoFormat_NV12), + GUID_TO_NAME_ENTRY(MFVideoFormat_P010), + GUID_TO_NAME_ENTRY(MFVideoFormat_P016), + GUID_TO_NAME_ENTRY(MFVideoFormat_P210), + GUID_TO_NAME_ENTRY(MFVideoFormat_P216), + GUID_TO_NAME_ENTRY(MFVideoFormat_RGB24), + GUID_TO_NAME_ENTRY(MFVideoFormat_RGB32), + GUID_TO_NAME_ENTRY(MFVideoFormat_RGB555), + GUID_TO_NAME_ENTRY(MFVideoFormat_RGB565), + GUID_TO_NAME_ENTRY(MFVideoFormat_RGB8), + GUID_TO_NAME_ENTRY(MFVideoFormat_UYVY), + GUID_TO_NAME_ENTRY(MFVideoFormat_v210), + GUID_TO_NAME_ENTRY(MFVideoFormat_v410), + GUID_TO_NAME_ENTRY(MFVideoFormat_WMV1), + GUID_TO_NAME_ENTRY(MFVideoFormat_WMV2), + GUID_TO_NAME_ENTRY(MFVideoFormat_WMV3), + GUID_TO_NAME_ENTRY(MFVideoFormat_WVC1), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y210), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y216), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y410), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y416), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y41P), + GUID_TO_NAME_ENTRY(MFVideoFormat_Y41T), + GUID_TO_NAME_ENTRY(MFVideoFormat_YUY2), + GUID_TO_NAME_ENTRY(MFVideoFormat_YV12), + GUID_TO_NAME_ENTRY(MFVideoFormat_YVYU), + + GUID_TO_NAME_ENTRY(MFAudioFormat_PCM), + GUID_TO_NAME_ENTRY(MFAudioFormat_Float), + GUID_TO_NAME_ENTRY(MFAudioFormat_DTS), + GUID_TO_NAME_ENTRY(MFAudioFormat_Dolby_AC3_SPDIF), + GUID_TO_NAME_ENTRY(MFAudioFormat_DRM), + GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV8), + GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudioV9), + GUID_TO_NAME_ENTRY(MFAudioFormat_WMAudio_Lossless), + GUID_TO_NAME_ENTRY(MFAudioFormat_WMASPDIF), + GUID_TO_NAME_ENTRY(MFAudioFormat_MSP1), + GUID_TO_NAME_ENTRY(MFAudioFormat_MP3), + GUID_TO_NAME_ENTRY(MFAudioFormat_MPEG), + GUID_TO_NAME_ENTRY(MFAudioFormat_AAC), + GUID_TO_NAME_ENTRY(MFAudioFormat_ADTS), + + // Interfaces which may be implemented by WMFByteStream. + INTERFACE_TO_NAME_ENTRY(IUnknown), + INTERFACE_TO_NAME_ENTRY(IMFByteStream), + INTERFACE_TO_NAME_ENTRY(IMFMediaSource), + INTERFACE_TO_NAME_ENTRY(IMFAttributes), + INTERFACE_TO_NAME_ENTRY(IMFByteStreamBuffering), +}; + +nsCString GetGUIDName(const GUID& guid) +{ + const unsigned numTypes = ArrayLength(GuidToNameTable); + for (unsigned i = 0; i < numTypes; i++) { + if (guid == GuidToNameTable[i].guid) { + return nsDependentCString(GuidToNameTable[i].name); + } + } + + WCHAR* name = nullptr; + HRESULT hr = StringFromCLSID(guid , &name); + if (FAILED(hr)) { + return nsDependentCString("GuidUnknown"); + } + nsCString name_u8(NS_ConvertUTF16toUTF8(nsDependentString((char16_t*)(name)))); + CoTaskMemFree(name); + return name_u8; +} + +bool +SourceReaderHasStream(IMFSourceReader* aReader, const DWORD aIndex) +{ + RefPtr nativeType; + HRESULT hr = aReader->GetNativeMediaType(aIndex, 0, byRef(nativeType)); + return FAILED(hr) ? false : true; +} + +HRESULT +DoGetInterface(IUnknown* aUnknown, void** aInterface) +{ + if (!aInterface) + return E_POINTER; + *aInterface = aUnknown; + aUnknown->AddRef(); + return S_OK; +} + +HRESULT +HNsToFrames(int64_t aHNs, uint32_t aRate, int64_t* aOutFrames) +{ + MOZ_ASSERT(aOutFrames); + const int64_t HNS_PER_S = USECS_PER_S * 10; + CheckedInt i = aHNs; + i *= aRate; + i /= HNS_PER_S; + NS_ENSURE_TRUE(i.isValid(), E_FAIL); + *aOutFrames = i.value(); + return S_OK; +} + +HRESULT +FramesToUsecs(int64_t aSamples, uint32_t aRate, int64_t* aOutUsecs) +{ + MOZ_ASSERT(aOutUsecs); + CheckedInt i = aSamples; + i *= USECS_PER_S; + i /= aRate; + NS_ENSURE_TRUE(i.isValid(), E_FAIL); + *aOutUsecs = i.value(); + return S_OK; +} + +HRESULT +GetDefaultStride(IMFMediaType *aType, uint32_t* aOutStride) +{ + // Try to get the default stride from the media type. + HRESULT hr = aType->GetUINT32(MF_MT_DEFAULT_STRIDE, aOutStride); + if (SUCCEEDED(hr)) { + 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); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + hr = MFGetAttributeSize(aType, MF_MT_FRAME_SIZE, &width, &height); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + hr = wmf::MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG*)(aOutStride)); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + return hr; +} + +int32_t +MFOffsetToInt32(const MFOffset& aOffset) +{ + return int32_t(aOffset.value + (aOffset.fract / 65536.0f)); +} + +int64_t +GetSampleDuration(IMFSample* aSample) +{ + NS_ENSURE_TRUE(aSample, -1); + int64_t duration = 0; + aSample->GetSampleDuration(&duration); + return HNsToUsecs(duration); +} + +int64_t +GetSampleTime(IMFSample* aSample) +{ + NS_ENSURE_TRUE(aSample, -1); + LONGLONG timestampHns = 0; + HRESULT hr = aSample->GetSampleTime(×tampHns); + NS_ENSURE_TRUE(SUCCEEDED(hr), -1); + return HNsToUsecs(timestampHns); +} + +// 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, nsIntRect& 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), + nullptr); + } + + // 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), + nullptr); + } + + 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), + nullptr); + } + + if (SUCCEEDED(hr)) { + // The media specified a picture region, return it. + aOutPictureRegion = nsIntRect(MFOffsetToInt32(videoArea.OffsetX), + MFOffsetToInt32(videoArea.OffsetY), + videoArea.Area.cx, + videoArea.Area.cy); + 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); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + aOutPictureRegion = nsIntRect(0, 0, width, height); + return S_OK; +} + +namespace wmf { + +static bool +IsSupportedDecoder(const GUID& aDecoderGUID) +{ + return aDecoderGUID == CLSID_CMSH264DecoderMFT || + aDecoderGUID == CLSID_CMSAACDecMFT || + aDecoderGUID == CLSID_CMP3DecMediaObject; +} + +static HRESULT +DisableBlockedDecoders(IMFPluginControl* aPluginControl, + const GUID& aCategory) +{ + HRESULT hr = S_OK; + + UINT32 numMFTs = 0; + IMFActivate **ppActivate = nullptr; + hr = wmf::MFTEnumEx(aCategory, + MFT_ENUM_FLAG_ALL, + nullptr, // Input type, nullptr -> match all. + nullptr, // Output type, nullptr -> match all. + &ppActivate, + &numMFTs); + + if (SUCCEEDED(hr) && numMFTs == 0) { + hr = MF_E_TOPO_CODEC_NOT_FOUND; + } + + for (UINT32 i = 0; i < numMFTs; i++) { + // Note: We must release all IMFActivate objects in the list, hence + // we're putting individual IMFActivate objects in into a smart ptr. + RefPtr activate = ppActivate[i]; + GUID guid = GUID_NULL; + hr = activate->GetGUID(MFT_TRANSFORM_CLSID_Attribute, &guid); + if (FAILED(hr)) { + NS_WARNING("FAILED to get IMFActivate clsid"); + continue; + } + if (!IsSupportedDecoder(guid)) { + hr = aPluginControl->SetDisabled(MF_Plugin_Type_MFT, guid, TRUE); + NS_ASSERTION(SUCCEEDED(hr), "Failed to disable plugin!"); + } + } + CoTaskMemFree(ppActivate); + + return hr; +} + +static HRESULT +DisableBlockedDecoders() +{ + RefPtr pluginControl; + HRESULT hr = wmf::MFGetPluginControl(byRef(pluginControl)); + if (SUCCEEDED(hr) && pluginControl) { + hr = DisableBlockedDecoders(pluginControl, + MFT_CATEGORY_VIDEO_DECODER); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + hr = DisableBlockedDecoders(pluginControl, + MFT_CATEGORY_AUDIO_DECODER); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + } + + return S_OK; +} + +static bool sDLLsLoaded = false; +static bool sFailedToLoadDlls = false; + +struct WMFModule { + const wchar_t* name; + HMODULE handle; +}; + +static WMFModule sDLLs[] = { + { L"mfplat.dll", nullptr }, + { L"mfreadwrite.dll", nullptr }, + { L"propsys.dll", nullptr }, + { L"mf.dll", nullptr }, + { L"dxva2.dll", nullptr } +}; + +HRESULT +LoadDLLs() +{ + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); + + if (sDLLsLoaded) { + return S_OK; + } + if (sFailedToLoadDlls) { + return E_FAIL; + } + + // Try to load all the required DLLs. + const uint32_t dllLength = ArrayLength(sDLLs); + for (uint32_t i = 0; i < dllLength; i++) { + sDLLs[i].handle = LoadLibrarySystem32(sDLLs[i].name); + if (!sDLLs[i].handle) { + sFailedToLoadDlls = true; + NS_WARNING("Failed to load WMF DLLs"); + UnloadDLLs(); + return E_FAIL; + } + } + + // Enumerate all the decoders on the system, and disable the ones except + // those which we expect to use, the MP3, AAC and H.264 decoders. + if (FAILED(DisableBlockedDecoders())) { + sFailedToLoadDlls = true; + NS_WARNING("Failed to disable non whitelisted WMF decoders"); + UnloadDLLs(); + return E_FAIL; + } + + sDLLsLoaded = true; + + return S_OK; +} + +HRESULT +UnloadDLLs() +{ + NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); + + const uint32_t length = ArrayLength(sDLLs); + for (uint32_t i = 0; i < length; i++) { + if (sDLLs[i].handle) { + FreeLibrary(sDLLs[i].handle); + sDLLs[i].handle = nullptr; + } + sDLLsLoaded = false; + } + return S_OK; +} + +#define ENSURE_FUNCTION_PTR_HELPER(FunctionType, FunctionName, DLL) \ + static FunctionType FunctionName##Ptr = nullptr; \ + if (!FunctionName##Ptr) { \ + FunctionName##Ptr = (FunctionType) GetProcAddress(GetModuleHandle(#DLL), #FunctionName); \ + if (!FunctionName##Ptr) { \ + NS_WARNING("Failed to get GetProcAddress of " #FunctionName " from " #DLL); \ + return E_FAIL; \ + } \ + } + +#define ENSURE_FUNCTION_PTR(FunctionName, DLL) \ + ENSURE_FUNCTION_PTR_HELPER(decltype(::FunctionName)*, FunctionName, DLL) \ + +#define ENSURE_FUNCTION_PTR_(FunctionName, DLL) \ + ENSURE_FUNCTION_PTR_HELPER(FunctionName##Ptr_t, FunctionName, DLL) \ + +#define DECL_FUNCTION_PTR(FunctionName, ...) \ + typedef HRESULT (STDMETHODCALLTYPE * FunctionName##Ptr_t)(__VA_ARGS__) + +HRESULT +MFStartup() +{ + const int MF_VISTA_VERSION = (0x0001 << 16 | MF_API_VERSION); + const int MF_WIN7_VERSION = (0x0002 << 16 | MF_API_VERSION); + + // decltype is unusable for functions having default parameters + DECL_FUNCTION_PTR(MFStartup, ULONG, DWORD); + ENSURE_FUNCTION_PTR_(MFStartup, Mfplat.dll) + if (!IsWin7OrLater()) + return MFStartupPtr(MF_VISTA_VERSION, MFSTARTUP_FULL); + else + return MFStartupPtr(MF_WIN7_VERSION, MFSTARTUP_FULL); +} + +HRESULT +MFShutdown() +{ + ENSURE_FUNCTION_PTR(MFShutdown, Mfplat.dll) + return (MFShutdownPtr)(); +} + +HRESULT +MFCreateAsyncResult(IUnknown *aUnkObject, + IMFAsyncCallback *aCallback, + IUnknown *aUnkState, + IMFAsyncResult **aOutAsyncResult) +{ + ENSURE_FUNCTION_PTR(MFCreateAsyncResult, Mfplat.dll) + return (MFCreateAsyncResultPtr)(aUnkObject, aCallback, aUnkState, aOutAsyncResult); +} + +HRESULT +MFInvokeCallback(IMFAsyncResult *aAsyncResult) +{ + ENSURE_FUNCTION_PTR(MFInvokeCallback, Mfplat.dll); + return (MFInvokeCallbackPtr)(aAsyncResult); +} + +HRESULT +MFCreateMediaType(IMFMediaType **aOutMFType) +{ + ENSURE_FUNCTION_PTR(MFCreateMediaType, Mfplat.dll) + return (MFCreateMediaTypePtr)(aOutMFType); +} + +HRESULT +MFCreateSourceReaderFromByteStream(IMFByteStream *aByteStream, + IMFAttributes *aAttributes, + IMFSourceReader **aOutSourceReader) +{ + ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromByteStream, Mfreadwrite.dll) + return (MFCreateSourceReaderFromByteStreamPtr)(aByteStream, + aAttributes, + aOutSourceReader); +} + +HRESULT +PropVariantToUInt32(REFPROPVARIANT aPropvar, ULONG *aOutUL) +{ + // decltype is unusable for overloaded functions + DECL_FUNCTION_PTR(PropVariantToUInt32, REFPROPVARIANT, ULONG *); + ENSURE_FUNCTION_PTR_(PropVariantToUInt32, Propsys.dll) + return (PropVariantToUInt32Ptr)(aPropvar, aOutUL); +} + +HRESULT PropVariantToInt64(REFPROPVARIANT aPropVar, LONGLONG *aOutLL) +{ + ENSURE_FUNCTION_PTR(PropVariantToInt64, Propsys.dll) + return (PropVariantToInt64Ptr)(aPropVar, aOutLL); +} + +HRESULT +MFTGetInfo(CLSID aClsidMFT, + LPWSTR *aOutName, + MFT_REGISTER_TYPE_INFO **aOutInputTypes, + UINT32 *aOutNumInputTypes, + MFT_REGISTER_TYPE_INFO **aOutOutputTypes, + UINT32 *aOutNumOutputTypes, + IMFAttributes **aOutAttributes) +{ + ENSURE_FUNCTION_PTR(MFTGetInfo, Mfplat.dll) + return (MFTGetInfoPtr)(aClsidMFT, + aOutName, + aOutInputTypes, + aOutNumInputTypes, + aOutOutputTypes, + aOutNumOutputTypes, + aOutAttributes); +} + +HRESULT +MFGetStrideForBitmapInfoHeader(DWORD aFormat, + DWORD aWidth, + LONG *aOutStride) +{ + ENSURE_FUNCTION_PTR(MFGetStrideForBitmapInfoHeader, Mfplat.dll) + return (MFGetStrideForBitmapInfoHeaderPtr)(aFormat, aWidth, aOutStride); +} + +HRESULT +MFCreateSourceReaderFromURL(LPCWSTR aURL, + IMFAttributes *aAttributes, + IMFSourceReader **aSourceReader) +{ + ENSURE_FUNCTION_PTR(MFCreateSourceReaderFromURL, Mfreadwrite.dll) + return (MFCreateSourceReaderFromURLPtr)(aURL, aAttributes, aSourceReader); +} + +HRESULT +MFCreateAttributes(IMFAttributes **ppMFAttributes, UINT32 cInitialSize) +{ + ENSURE_FUNCTION_PTR(MFCreateAttributes, mfplat.dll) + return (MFCreateAttributesPtr)(ppMFAttributes, cInitialSize); +} + +HRESULT +MFGetPluginControl(IMFPluginControl **aOutPluginControl) +{ + ENSURE_FUNCTION_PTR(MFGetPluginControl, mfplat.dll) + return (MFGetPluginControlPtr)(aOutPluginControl); +} + +HRESULT +MFTEnumEx(GUID guidCategory, + UINT32 Flags, + const MFT_REGISTER_TYPE_INFO *pInputType, + const MFT_REGISTER_TYPE_INFO *pOutputType, + IMFActivate ***pppMFTActivate, + UINT32 *pcMFTActivate) +{ + ENSURE_FUNCTION_PTR(MFTEnumEx, mfplat.dll) + return (MFTEnumExPtr)(guidCategory, Flags, pInputType, pOutputType, pppMFTActivate, pcMFTActivate); +} + +HRESULT MFGetService(IUnknown *punkObject, + REFGUID guidService, + REFIID riid, + LPVOID *ppvObject) +{ + ENSURE_FUNCTION_PTR(MFGetService, mf.dll) + return (MFGetServicePtr)(punkObject, guidService, riid, ppvObject); +} + +HRESULT +DXVA2CreateDirect3DDeviceManager9(UINT *pResetToken, + IDirect3DDeviceManager9 **ppDXVAManager) +{ + ENSURE_FUNCTION_PTR(DXVA2CreateDirect3DDeviceManager9, dxva2.dll) + return (DXVA2CreateDirect3DDeviceManager9Ptr)(pResetToken, ppDXVAManager); +} + +HRESULT +MFCreateSample(IMFSample **ppIMFSample) +{ + ENSURE_FUNCTION_PTR(MFCreateSample, mfplat.dll) + return (MFCreateSamplePtr)(ppIMFSample); +} + +HRESULT +MFCreateAlignedMemoryBuffer(DWORD cbMaxLength, + DWORD fAlignmentFlags, + IMFMediaBuffer **ppBuffer) +{ + ENSURE_FUNCTION_PTR(MFCreateAlignedMemoryBuffer, mfplat.dll) + return (MFCreateAlignedMemoryBufferPtr)(cbMaxLength, fAlignmentFlags, ppBuffer); +} + +} // end namespace wmf +} // end namespace mozilla