Source code

Revision control

Copy as Markdown

Other Tools

/* 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.
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