/* 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 "MFMediaEngineDecoderModule.h" #include "MFTDecoder.h" #include "VideoUtils.h" #include "mozilla/MFMediaEngineParent.h" #include "mozilla/MFMediaEngineUtils.h" #include "mozilla/StaticPrefs_media.h" #include "mozilla/WindowsVersion.h" #include "mozilla/mscom/EnsureMTA.h" namespace mozilla { #define LOG(msg, ...) \ MOZ_LOG(gMFMediaEngineLog, LogLevel::Debug, (msg, ##__VA_ARGS__)) /* static */ void MFMediaEngineDecoderModule::Init() { // TODO : Init any thing that media engine would need. Implement this when we // start implementing media engine in following patches. } /* static */ already_AddRefed MFMediaEngineDecoderModule::Create() { RefPtr module = new MFMediaEngineDecoderModule(); return module.forget(); } /* static */ bool MFMediaEngineDecoderModule::SupportsConfig(const TrackInfo& aConfig) { RefPtr module = new MFMediaEngineDecoderModule(); return module->SupportInternal(SupportDecoderParams(aConfig), nullptr) != media::DecodeSupport::Unsupported; } already_AddRefed MFMediaEngineDecoderModule::CreateVideoDecoder( const CreateDecoderParams& aParams) { if (!aParams.mMediaEngineId || !StaticPrefs::media_wmf_media_engine_enabled()) { return nullptr; } RefPtr mediaEngine = MFMediaEngineParent::GetMediaEngineById(*aParams.mMediaEngineId); if (!mediaEngine) { LOG("Can't find media engine %" PRIu64 " for video decoder", *aParams.mMediaEngineId); return nullptr; } LOG("MFMediaEngineDecoderModule, CreateVideoDecoder"); RefPtr decoder = mediaEngine->GetMediaEngineStream( TrackInfo::TrackType::kVideoTrack, aParams); return decoder.forget(); } already_AddRefed MFMediaEngineDecoderModule::CreateAudioDecoder( const CreateDecoderParams& aParams) { if (!aParams.mMediaEngineId || !StaticPrefs::media_wmf_media_engine_enabled()) { return nullptr; } RefPtr mediaEngine = MFMediaEngineParent::GetMediaEngineById(*aParams.mMediaEngineId); if (!mediaEngine) { LOG("Can't find media engine %" PRIu64 " for audio decoder", *aParams.mMediaEngineId); return nullptr; } LOG("MFMediaEngineDecoderModule, CreateAudioDecoder"); RefPtr decoder = mediaEngine->GetMediaEngineStream( TrackInfo::TrackType::kAudioTrack, aParams); return decoder.forget(); } media::DecodeSupportSet MFMediaEngineDecoderModule::SupportsMimeType( const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const { UniquePtr trackInfo = CreateTrackInfoWithMIMEType(aMimeType); if (!trackInfo) { return media::DecodeSupport::Unsupported; } return SupportInternal(SupportDecoderParams(*trackInfo), aDiagnostics); } media::DecodeSupportSet MFMediaEngineDecoderModule::Supports( const SupportDecoderParams& aParams, DecoderDoctorDiagnostics* aDiagnostics) const { if (!aParams.mMediaEngineId) { return media::DecodeSupport::Unsupported; } return SupportInternal(aParams, aDiagnostics); } media::DecodeSupportSet MFMediaEngineDecoderModule::SupportInternal( const SupportDecoderParams& aParams, DecoderDoctorDiagnostics* aDiagnostics) const { if (!StaticPrefs::media_wmf_media_engine_enabled()) { return media::DecodeSupport::Unsupported; } bool supports = false; WMFStreamType type = GetStreamTypeFromMimeType(aParams.MimeType()); if (type != WMFStreamType::Unknown) { supports = CanCreateMFTDecoder(type); } MOZ_LOG(sPDMLog, LogLevel::Debug, ("MFMediaEngine decoder %s requested type '%s'", supports ? "supports" : "rejects", aParams.MimeType().get())); return supports ? media::DecodeSupport::SoftwareDecode : media::DecodeSupport::Unsupported; } static bool CreateMFTDecoderOnMTA(const WMFStreamType& aType) { RefPtr decoder = new MFTDecoder(); static std::unordered_map sResults; if (auto rv = sResults.find(aType); rv != sResults.end()) { return rv->second; } bool result = false; switch (aType) { case WMFStreamType::MP3: result = SUCCEEDED(decoder->Create(CLSID_CMP3DecMediaObject)); break; case WMFStreamType::AAC: result = SUCCEEDED(decoder->Create(CLSID_CMSAACDecMFT)); break; // Opus and vorbis are supported via extension. // https://www.microsoft.com/en-us/p/web-media-extensions/9n5tdp8vcmhs case WMFStreamType::OPUS: result = SUCCEEDED(decoder->Create(CLSID_MSOpusDecoder)); break; case WMFStreamType::VORBIS: result = SUCCEEDED(decoder->Create( MFT_CATEGORY_AUDIO_DECODER, MFAudioFormat_Vorbis, MFAudioFormat_PCM)); break; case WMFStreamType::H264: result = SUCCEEDED(decoder->Create(CLSID_CMSH264DecoderMFT)); break; case WMFStreamType::VP8: case WMFStreamType::VP9: { static const uint32_t VPX_USABLE_BUILD = 16287; if (IsWindowsBuildOrLater(VPX_USABLE_BUILD)) { result = SUCCEEDED(decoder->Create(CLSID_CMSVPXDecMFT)); } break; } #ifdef MOZ_AV1 case WMFStreamType::AV1: result = SUCCEEDED(decoder->Create(MFT_CATEGORY_VIDEO_DECODER, MFVideoFormat_AV1, GUID_NULL)); break; #endif default: MOZ_ASSERT_UNREACHABLE("Unexpected type"); } sResults.insert({aType, result}); return result; } bool MFMediaEngineDecoderModule::CanCreateMFTDecoder( const WMFStreamType& aType) const { // TODO : caching the result to prevent performing on MTA thread everytime. bool canCreateDecoder = false; mozilla::mscom::EnsureMTA( [&]() { canCreateDecoder = CreateMFTDecoderOnMTA(aType); }); return canCreateDecoder; } #undef LOG } // namespace mozilla