/* 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/gfx/gfxVars.h"
#include "mozilla/MFMediaEngineParent.h"
#include "mozilla/MFMediaEngineUtils.h"
#include "mozilla/RemoteDecoderManagerChild.h"
#include "mozilla/RemoteDecoderModule.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<PlatformDecoderModule> MFMediaEngineDecoderModule::Create() {
RefPtr<MFMediaEngineDecoderModule> module =
new MFMediaEngineDecoderModule();
return module.forget();
}
/* static */
bool MFMediaEngineDecoderModule::SupportsConfig(
const TrackInfo& aConfig) {
RefPtr<PlatformDecoderModule> module = RemoteDecoderModule::Create(
RemoteDecodeIn::UtilityProcess_MFMediaEngineCDM);
return !module->Supports(SupportDecoderParams(aConfig), nullptr).isEmpty();
}
already_AddRefed<MediaDataDecoder>
MFMediaEngineDecoderModule::CreateVideoDecoder(
const CreateDecoderParams& aParams) {
if (!aParams.mMediaEngineId ||
!StaticPrefs::media_wmf_media_engine_enabled()) {
return nullptr;
}
RefPtr<MFMediaEngineParent> 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<MediaDataDecoder> decoder = mediaEngine->GetMediaEngineStream(
TrackInfo::TrackType::kVideoTrack, aParams);
return decoder.forget();
}
already_AddRefed<MediaDataDecoder>
MFMediaEngineDecoderModule::CreateAudioDecoder(
const CreateDecoderParams& aParams) {
if (!aParams.mMediaEngineId ||
!StaticPrefs::media_wmf_media_engine_enabled()) {
return nullptr;
}
RefPtr<MFMediaEngineParent> 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<MediaDataDecoder> decoder = mediaEngine->GetMediaEngineStream(
TrackInfo::TrackType::kAudioTrack, aParams);
return decoder.forget();
}
media::DecodeSupportSet MFMediaEngineDecoderModule::SupportsMimeType(
const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics)
const {
UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
if (!trackInfo) {
return media::DecodeSupportSet{};
}
return SupportInternal(SupportDecoderParams(*trackInfo), aDiagnostics);
}
media::DecodeSupportSet MFMediaEngineDecoderModule::Supports(
const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics)
const {
return SupportInternal(aParams, aDiagnostics);
}
media::DecodeSupportSet MFMediaEngineDecoderModule::SupportInternal(
const SupportDecoderParams& aParams,
DecoderDoctorDiagnostics* aDiagnostics)
const {
if (!StaticPrefs::media_wmf_media_engine_enabled()) {
return media::DecodeSupportSet{};
}
// Only support hardware decoding.
if (!gfx::gfxVars::CanUseHardwareVideoDecoding() &&
!StaticPrefs::media_wmf_media_engine_bypass_gfx_blocklist()) {
return media::DecodeSupportSet{};
}
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()));
if (!supports) {
return media::DecodeSupportSet{};
}
return StreamTypeIsVideo(type) ? media::DecodeSupport::HardwareDecode
: media::DecodeSupport::SoftwareDecode;
}
static bool CreateMFTDecoderOnMTA(
const WMFStreamType& aType) {
RefPtr<MFTDecoder> decoder =
new MFTDecoder();
static std::unordered_map<WMFStreamType,
bool> 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 (IsWindows10BuildOrLater(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
case WMFStreamType::HEVC:
if (StaticPrefs::media_wmf_hevc_enabled()) {
result =
SUCCEEDED(decoder->Create(MFT_CATEGORY_VIDEO_DECODER,
MFVideoFormat_HEVC, MFVideoFormat_NV12));
}
break;
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