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