summaryrefslogtreecommitdiffstats
path: root/dom/media/platforms/PDMFactory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/platforms/PDMFactory.cpp')
-rw-r--r--dom/media/platforms/PDMFactory.cpp710
1 files changed, 710 insertions, 0 deletions
diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp
new file mode 100644
index 0000000000..9b66f7f12b
--- /dev/null
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -0,0 +1,710 @@
+/* -*- 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 "PDMFactory.h"
+
+#ifdef MOZ_AV1
+# include "AOMDecoder.h"
+#endif
+#include "AgnosticDecoderModule.h"
+#include "AudioTrimmer.h"
+#include "BlankDecoderModule.h"
+#include "DecoderDoctorDiagnostics.h"
+#include "EMEDecoderModule.h"
+#include "GMPDecoderModule.h"
+#include "H264.h"
+#include "MP4Decoder.h"
+#include "MediaChangeMonitor.h"
+#include "MediaInfo.h"
+#include "OpusDecoder.h"
+#include "TheoraDecoder.h"
+#include "VPXDecoder.h"
+#include "VideoUtils.h"
+#include "VorbisDecoder.h"
+#include "WAVDecoder.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/RemoteDecoderManagerChild.h"
+#include "mozilla/RemoteDecoderModule.h"
+#include "mozilla/SharedThreadPool.h"
+#include "mozilla/StaticPrefs_media.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/SyncRunnable.h"
+#include "mozilla/TaskQueue.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart
+#include "nsPrintfCString.h"
+
+#ifdef XP_WIN
+# include "WMFDecoderModule.h"
+# include "mozilla/WindowsVersion.h"
+#endif
+#ifdef MOZ_FFVPX
+# include "FFVPXRuntimeLinker.h"
+#endif
+#ifdef MOZ_FFMPEG
+# include "FFmpegRuntimeLinker.h"
+#endif
+#ifdef MOZ_APPLEMEDIA
+# include "AppleDecoderModule.h"
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+# include "AndroidDecoderModule.h"
+#endif
+#ifdef MOZ_OMX
+# include "OmxDecoderModule.h"
+#endif
+
+#include <functional>
+
+namespace mozilla {
+
+extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
+
+class PDMFactoryImpl final {
+ public:
+ PDMFactoryImpl() {
+ if (XRE_IsGPUProcess()) {
+ InitGpuPDMs();
+ } else if (XRE_IsRDDProcess()) {
+ InitRddPDMs();
+ } else if (XRE_IsContentProcess()) {
+ InitContentPDMs();
+ } else {
+ MOZ_DIAGNOSTIC_ASSERT(
+ XRE_IsParentProcess(),
+ "PDMFactory is only usable in the Parent/GPU/RDD/Content process");
+ InitDefaultPDMs();
+ }
+ }
+
+ private:
+ void InitGpuPDMs() {
+#ifdef XP_WIN
+ if (!IsWin7AndPre2000Compatible()) {
+ WMFDecoderModule::Init();
+ }
+#endif
+ }
+
+ void InitRddPDMs() {
+#ifdef XP_WIN
+ if (!IsWin7AndPre2000Compatible()) {
+ WMFDecoderModule::Init();
+ }
+#endif
+#ifdef MOZ_APPLEMEDIA
+ AppleDecoderModule::Init();
+#endif
+#ifdef MOZ_FFVPX
+ FFVPXRuntimeLinker::Init();
+#endif
+#ifdef MOZ_FFMPEG
+ if (StaticPrefs::media_rdd_ffmpeg_enabled()) {
+ FFmpegRuntimeLinker::Init();
+ }
+#endif
+ }
+
+ void InitContentPDMs() {
+#ifdef XP_WIN
+ if (!IsWin7AndPre2000Compatible()) {
+ WMFDecoderModule::Init();
+ }
+#endif
+#ifdef MOZ_APPLEMEDIA
+ AppleDecoderModule::Init();
+#endif
+#ifdef MOZ_OMX
+ OmxDecoderModule::Init();
+#endif
+#ifdef MOZ_FFVPX
+ FFVPXRuntimeLinker::Init();
+#endif
+#ifdef MOZ_FFMPEG
+ FFmpegRuntimeLinker::Init();
+#endif
+ RemoteDecoderManagerChild::Init();
+ }
+
+ void InitDefaultPDMs() {
+#ifdef XP_WIN
+ if (!IsWin7AndPre2000Compatible()) {
+ WMFDecoderModule::Init();
+ }
+#endif
+#ifdef MOZ_APPLEMEDIA
+ AppleDecoderModule::Init();
+#endif
+#ifdef MOZ_OMX
+ OmxDecoderModule::Init();
+#endif
+#ifdef MOZ_FFVPX
+ FFVPXRuntimeLinker::Init();
+#endif
+#ifdef MOZ_FFMPEG
+ FFmpegRuntimeLinker::Init();
+#endif
+ }
+};
+
+StaticAutoPtr<PDMFactoryImpl> PDMFactory::sInstance;
+StaticMutex PDMFactory::sMonitor;
+
+class SupportChecker {
+ public:
+ enum class Reason : uint8_t {
+ kSupported,
+ kVideoFormatNotSupported,
+ kAudioFormatNotSupported,
+ kUnknown,
+ };
+
+ struct CheckResult {
+ explicit CheckResult(Reason aReason,
+ MediaResult aResult = MediaResult(NS_OK))
+ : mReason(aReason), mMediaResult(std::move(aResult)) {}
+ CheckResult(const CheckResult& aOther) = default;
+ CheckResult(CheckResult&& aOther) = default;
+ CheckResult& operator=(const CheckResult& aOther) = default;
+ CheckResult& operator=(CheckResult&& aOther) = default;
+
+ Reason mReason;
+ MediaResult mMediaResult;
+ };
+
+ template <class Func>
+ void AddToCheckList(Func&& aChecker) {
+ mCheckerList.AppendElement(std::forward<Func>(aChecker));
+ }
+
+ void AddMediaFormatChecker(const TrackInfo& aTrackConfig) {
+ if (aTrackConfig.IsVideo()) {
+ auto mimeType = aTrackConfig.GetAsVideoInfo()->mMimeType;
+ RefPtr<MediaByteBuffer> extraData =
+ aTrackConfig.GetAsVideoInfo()->mExtraData;
+ AddToCheckList([mimeType, extraData]() {
+ if (MP4Decoder::IsH264(mimeType)) {
+ SPSData spsdata;
+ // WMF H.264 Video Decoder and Apple ATDecoder
+ // do not support YUV444 format.
+ // For consistency, all decoders should be checked.
+ if (H264::DecodeSPSFromExtraData(extraData, spsdata) &&
+ (spsdata.profile_idc == 244 /* Hi444PP */ ||
+ spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
+ return CheckResult(
+ SupportChecker::Reason::kVideoFormatNotSupported,
+ MediaResult(
+ NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL("Decoder may not have the capability "
+ "to handle the requested video format "
+ "with YUV444 chroma subsampling.")));
+ }
+ }
+ return CheckResult(SupportChecker::Reason::kSupported);
+ });
+ }
+ }
+
+ SupportChecker::CheckResult Check() {
+ for (auto& checker : mCheckerList) {
+ auto result = checker();
+ if (result.mReason != SupportChecker::Reason::kSupported) {
+ return result;
+ }
+ }
+ return CheckResult(SupportChecker::Reason::kSupported);
+ }
+
+ void Clear() { mCheckerList.Clear(); }
+
+ private:
+ nsTArray<std::function<CheckResult()>> mCheckerList;
+}; // SupportChecker
+
+PDMFactory::PDMFactory() {
+ EnsureInit();
+ CreatePDMs();
+ CreateNullPDM();
+}
+
+PDMFactory::~PDMFactory() = default;
+
+/* static */
+void PDMFactory::EnsureInit() {
+ {
+ StaticMutexAutoLock mon(sMonitor);
+ if (sInstance) {
+ // Quick exit if we already have an instance.
+ return;
+ }
+ }
+
+ auto initalization = []() {
+ MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
+ StaticMutexAutoLock mon(sMonitor);
+ if (!sInstance) {
+ // Ensure that all system variables are initialized.
+ gfx::gfxVars::Initialize();
+ // Prime the preferences system from the main thread.
+ Unused << BrowserTabsRemoteAutostart();
+ // On the main thread and holding the lock -> Create instance.
+ sInstance = new PDMFactoryImpl();
+ ClearOnShutdown(&sInstance);
+ }
+ };
+ if (NS_IsMainThread()) {
+ initalization();
+ return;
+ }
+
+ // Not on the main thread -> Sync-dispatch creation to main thread.
+ nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
+ nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
+ "PDMFactory::EnsureInit", std::move(initalization));
+ SyncRunnable::DispatchToThread(mainTarget, runnable);
+}
+
+RefPtr<PlatformDecoderModule::CreateDecoderPromise> PDMFactory::CreateDecoder(
+ const CreateDecoderParams& aParams) {
+ if (aParams.mUseNullDecoder.mUse) {
+ MOZ_ASSERT(mNullPDM);
+ return CreateDecoderWithPDM(mNullPDM, aParams);
+ }
+ bool isEncrypted = mEMEPDM && aParams.mConfig.mCrypto.IsEncrypted();
+
+ if (isEncrypted) {
+ return CreateDecoderWithPDM(mEMEPDM, aParams);
+ }
+
+ return CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync(aParams), 0);
+}
+
+RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+PDMFactory::CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync&& aParams,
+ uint32_t aIndex) {
+ uint32_t i = aIndex;
+ auto params = SupportDecoderParams(aParams);
+ for (; i < mCurrentPDMs.Length(); i++) {
+ if (!mCurrentPDMs[i]->Supports(params, nullptr /* diagnostic */)) {
+ continue;
+ }
+ RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
+ CreateDecoderWithPDM(mCurrentPDMs[i], aParams)
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [](RefPtr<MediaDataDecoder>&& aDecoder) {
+ return PlatformDecoderModule::CreateDecoderPromise::
+ CreateAndResolve(std::move(aDecoder), __func__);
+ },
+ [self = RefPtr{this}, i, params = std::move(aParams)](
+ const MediaResult& aError) mutable {
+ // Try the next PDM.
+ return self->CheckAndMaybeCreateDecoder(std::move(params),
+ i + 1);
+ });
+ return p;
+ }
+ return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
+ MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ nsPrintfCString("Error no decoder found for %s",
+ aParams.mConfig->mMimeType.get())
+ .get()),
+ __func__);
+}
+
+RefPtr<PlatformDecoderModule::CreateDecoderPromise>
+PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
+ const CreateDecoderParams& aParams) {
+ MOZ_ASSERT(aPDM);
+ MediaResult result = NS_OK;
+
+ SupportChecker supportChecker;
+ const TrackInfo& config = aParams.mConfig;
+ supportChecker.AddMediaFormatChecker(config);
+
+ auto checkResult = supportChecker.Check();
+ if (checkResult.mReason != SupportChecker::Reason::kSupported) {
+ if (checkResult.mReason ==
+ SupportChecker::Reason::kVideoFormatNotSupported) {
+ result = checkResult.mMediaResult;
+ } else if (checkResult.mReason ==
+ SupportChecker::Reason::kAudioFormatNotSupported) {
+ result = checkResult.mMediaResult;
+ }
+ return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
+ result, __func__);
+ }
+
+ if (config.IsAudio()) {
+ RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
+ p = aPDM->AsyncCreateDecoder(aParams)->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [params = CreateDecoderParamsForAsync(aParams)](
+ RefPtr<MediaDataDecoder>&& aDecoder) {
+ RefPtr<MediaDataDecoder> decoder = std::move(aDecoder);
+ if (!params.mNoWrapper.mDontUseWrapper) {
+ decoder =
+ new AudioTrimmer(decoder.forget(), CreateDecoderParams(params));
+ }
+ return PlatformDecoderModule::CreateDecoderPromise::CreateAndResolve(
+ decoder, __func__);
+ },
+ [](const MediaResult& aError) {
+ return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
+ aError, __func__);
+ });
+ return p;
+ }
+
+ if (!config.IsVideo()) {
+ return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
+ MediaResult(
+ NS_ERROR_DOM_MEDIA_FATAL_ERR,
+ RESULT_DETAIL(
+ "Decoder configuration error, expected audio or video.")),
+ __func__);
+ }
+
+ if ((MP4Decoder::IsH264(config.mMimeType) ||
+ VPXDecoder::IsVPX(config.mMimeType)) &&
+ !aParams.mUseNullDecoder.mUse && !aParams.mNoWrapper.mDontUseWrapper) {
+ return MediaChangeMonitor::Create(aPDM, aParams);
+ }
+ return aPDM->AsyncCreateDecoder(aParams);
+}
+
+bool PDMFactory::SupportsMimeType(
+ const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const {
+ UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
+ if (!trackInfo) {
+ return false;
+ }
+ return Supports(SupportDecoderParams(*trackInfo), aDiagnostics);
+}
+
+bool PDMFactory::Supports(const SupportDecoderParams& aParams,
+ DecoderDoctorDiagnostics* aDiagnostics) const {
+ if (mEMEPDM) {
+ return mEMEPDM->Supports(aParams, aDiagnostics);
+ }
+
+ RefPtr<PlatformDecoderModule> current =
+ GetDecoderModule(aParams, aDiagnostics);
+ return !!current;
+}
+
+void PDMFactory::CreatePDMs() {
+ if (StaticPrefs::media_use_blank_decoder()) {
+ CreateAndStartupPDM<BlankDecoderModule>();
+ // The Blank PDM SupportsMimeType reports true for all codecs; the creation
+ // of its decoder is infallible. As such it will be used for all media, we
+ // can stop creating more PDM from this point.
+ return;
+ }
+
+ if (XRE_IsGPUProcess()) {
+ CreateGpuPDMs();
+ } else if (XRE_IsRDDProcess()) {
+ CreateRddPDMs();
+ } else if (XRE_IsContentProcess()) {
+ CreateContentPDMs();
+ } else {
+ MOZ_DIAGNOSTIC_ASSERT(
+ XRE_IsParentProcess(),
+ "PDMFactory is only usable in the Parent/GPU/RDD/Content process");
+ CreateDefaultPDMs();
+ }
+}
+
+void PDMFactory::CreateGpuPDMs() {
+#ifdef XP_WIN
+ if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
+ CreateAndStartupPDM<WMFDecoderModule>();
+ }
+#endif
+}
+
+void PDMFactory::CreateRddPDMs() {
+#ifdef XP_WIN
+ if (StaticPrefs::media_wmf_enabled() &&
+ StaticPrefs::media_rdd_wmf_enabled()) {
+ CreateAndStartupPDM<WMFDecoderModule>();
+ }
+#endif
+#ifdef MOZ_APPLEMEDIA
+ if (StaticPrefs::media_rdd_applemedia_enabled()) {
+ CreateAndStartupPDM<AppleDecoderModule>();
+ }
+#endif
+#ifdef MOZ_FFVPX
+ if (StaticPrefs::media_ffvpx_enabled() &&
+ StaticPrefs::media_rdd_ffvpx_enabled()) {
+ CreateAndStartupPDM<FFVPXRuntimeLinker>();
+ }
+#endif
+#ifdef MOZ_FFMPEG
+ if (StaticPrefs::media_ffmpeg_enabled() &&
+ StaticPrefs::media_rdd_ffmpeg_enabled() &&
+ !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
+ } else {
+ mFailureFlags -= DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
+ }
+#endif
+ CreateAndStartupPDM<AgnosticDecoderModule>();
+}
+
+void PDMFactory::CreateContentPDMs() {
+ if (StaticPrefs::media_gpu_process_decoder()) {
+ CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::GpuProcess);
+ }
+
+ if (StaticPrefs::media_rdd_process_enabled()) {
+ CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::RddProcess);
+ }
+
+#ifdef XP_WIN
+ if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
+ RefPtr<WMFDecoderModule> m = MakeAndAddRef<WMFDecoderModule>();
+ if (!StartupPDM(m.forget())) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
+ }
+ } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
+ }
+#endif
+
+#ifdef MOZ_APPLEMEDIA
+ CreateAndStartupPDM<AppleDecoderModule>();
+#endif
+#ifdef MOZ_OMX
+ if (StaticPrefs::media_omx_enabled()) {
+ CreateAndStartupPDM<OmxDecoderModule>();
+ }
+#endif
+#ifdef MOZ_FFVPX
+ if (StaticPrefs::media_ffvpx_enabled()) {
+ CreateAndStartupPDM<FFVPXRuntimeLinker>();
+ }
+#endif
+#ifdef MOZ_FFMPEG
+ if (StaticPrefs::media_ffmpeg_enabled() &&
+ !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
+ }
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+ if (StaticPrefs::media_android_media_codec_enabled()) {
+ StartupPDM(AndroidDecoderModule::Create(),
+ StaticPrefs::media_android_media_codec_preferred());
+ }
+#endif
+
+ CreateAndStartupPDM<AgnosticDecoderModule>();
+
+ if (StaticPrefs::media_gmp_decoder_enabled() &&
+ !CreateAndStartupPDM<GMPDecoderModule>()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
+ }
+}
+
+void PDMFactory::CreateDefaultPDMs() {
+#ifdef XP_WIN
+ if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
+ RefPtr<WMFDecoderModule> m = MakeAndAddRef<WMFDecoderModule>();
+ if (!StartupPDM(m.forget())) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
+ }
+ } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
+ }
+#endif
+
+#ifdef MOZ_APPLEMEDIA
+ CreateAndStartupPDM<AppleDecoderModule>();
+#endif
+#ifdef MOZ_OMX
+ if (StaticPrefs::media_omx_enabled()) {
+ CreateAndStartupPDM<OmxDecoderModule>();
+ }
+#endif
+#ifdef MOZ_FFVPX
+ if (StaticPrefs::media_ffvpx_enabled()) {
+ CreateAndStartupPDM<FFVPXRuntimeLinker>();
+ }
+#endif
+#ifdef MOZ_FFMPEG
+ if (StaticPrefs::media_ffmpeg_enabled() &&
+ !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::FFmpegFailedToLoad;
+ }
+#endif
+#ifdef MOZ_WIDGET_ANDROID
+ if (StaticPrefs::media_android_media_codec_enabled()) {
+ StartupPDM(AndroidDecoderModule::Create(),
+ StaticPrefs::media_android_media_codec_preferred());
+ }
+#endif
+
+ CreateAndStartupPDM<AgnosticDecoderModule>();
+
+ if (StaticPrefs::media_gmp_decoder_enabled() &&
+ !CreateAndStartupPDM<GMPDecoderModule>()) {
+ mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
+ }
+}
+
+void PDMFactory::CreateNullPDM() {
+ mNullPDM = CreateNullDecoderModule();
+ MOZ_ASSERT(mNullPDM && NS_SUCCEEDED(mNullPDM->Startup()));
+}
+
+bool PDMFactory::StartupPDM(already_AddRefed<PlatformDecoderModule> aPDM,
+ bool aInsertAtBeginning) {
+ RefPtr<PlatformDecoderModule> pdm = aPDM;
+ if (pdm && NS_SUCCEEDED(pdm->Startup())) {
+ if (aInsertAtBeginning) {
+ mCurrentPDMs.InsertElementAt(0, pdm);
+ } else {
+ mCurrentPDMs.AppendElement(pdm);
+ }
+ return true;
+ }
+ return false;
+}
+
+already_AddRefed<PlatformDecoderModule> PDMFactory::GetDecoderModule(
+ const SupportDecoderParams& aParams,
+ DecoderDoctorDiagnostics* aDiagnostics) const {
+ if (aDiagnostics) {
+ // If libraries failed to load, the following loop over mCurrentPDMs
+ // will not even try to use them. So we record failures now.
+ aDiagnostics->SetFailureFlags(mFailureFlags);
+ }
+
+ RefPtr<PlatformDecoderModule> pdm;
+ for (auto& current : mCurrentPDMs) {
+ if (current->Supports(aParams, aDiagnostics)) {
+ pdm = current;
+ break;
+ }
+ }
+ return pdm.forget();
+}
+
+void PDMFactory::SetCDMProxy(CDMProxy* aProxy) {
+ MOZ_ASSERT(aProxy);
+
+#ifdef MOZ_WIDGET_ANDROID
+ if (IsWidevineKeySystem(aProxy->KeySystem())) {
+ mEMEPDM = AndroidDecoderModule::Create(aProxy);
+ return;
+ }
+#endif
+ auto m = MakeRefPtr<PDMFactory>();
+ mEMEPDM = MakeRefPtr<EMEDecoderModule>(aProxy, m);
+}
+
+/* static */
+PDMFactory::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ static auto calculate = []() {
+ auto pdm = MakeRefPtr<PDMFactory>();
+ MediaCodecsSupported supported;
+ // H264 and AAC depends on external framework that must be dynamically
+ // loaded.
+ // We currently only ship a single PDM per platform able to decode AAC or
+ // H264. As such we can assert that being able to create a H264 or AAC
+ // decoder indicates that with WMF on Windows or FFmpeg on Unixes is
+ // available.
+ // This logic will have to be revisited if a PDM supporting either codec
+ // will be added in addition to the WMF and FFmpeg PDM (such as OpenH264)
+ if (pdm->SupportsMimeType("video/avc"_ns, nullptr)) {
+ supported += MediaCodecs::H264;
+ }
+ if (pdm->SupportsMimeType("video/vp9"_ns, nullptr)) {
+ supported += MediaCodecs::VP9;
+ }
+ if (pdm->SupportsMimeType("video/vp8"_ns, nullptr)) {
+ supported += MediaCodecs::VP8;
+ }
+ if (pdm->SupportsMimeType("video/av1"_ns, nullptr)) {
+ supported += MediaCodecs::AV1;
+ }
+ if (pdm->SupportsMimeType("video/theora"_ns, nullptr)) {
+ supported += MediaCodecs::Theora;
+ }
+ if (pdm->SupportsMimeType("audio/mp4a-latm"_ns, nullptr)) {
+ supported += MediaCodecs::AAC;
+ }
+ // MP3 can be either decoded by ffvpx or WMF/FFmpeg
+ if (pdm->SupportsMimeType("audio/mpeg"_ns, nullptr)) {
+ supported += MediaCodecs::MP3;
+ }
+ if (pdm->SupportsMimeType("audio/opus"_ns, nullptr)) {
+ supported += MediaCodecs::Opus;
+ }
+ if (pdm->SupportsMimeType("audio/vorbis"_ns, nullptr)) {
+ supported += MediaCodecs::Vorbis;
+ }
+ if (pdm->SupportsMimeType("audio/flac"_ns, nullptr)) {
+ supported += MediaCodecs::Flac;
+ }
+ if (pdm->SupportsMimeType("audio/x-wav"_ns, nullptr)) {
+ supported += MediaCodecs::Wave;
+ }
+ return supported;
+ };
+ static MediaCodecsSupported supported = calculate();
+ if (aForceRefresh) {
+ supported = calculate();
+ }
+ return supported;
+}
+
+/* static */
+bool PDMFactory::SupportsMimeType(const nsACString& aMimeType,
+ const MediaCodecsSupported& aSupported) {
+ if (MP4Decoder::IsH264(aMimeType)) {
+ return aSupported.contains(MediaCodecs::H264);
+ }
+ if (VPXDecoder::IsVP9(aMimeType)) {
+ return aSupported.contains(MediaCodecs::VP9);
+ }
+ if (VPXDecoder::IsVP8(aMimeType)) {
+ return aSupported.contains(MediaCodecs::VP8);
+ }
+#ifdef MOZ_AV1
+ if (AOMDecoder::IsAV1(aMimeType)) {
+ return aSupported.contains(MediaCodecs::AV1);
+ }
+#endif
+ if (TheoraDecoder::IsTheora(aMimeType)) {
+ return aSupported.contains(MediaCodecs::Theora);
+ }
+ if (MP4Decoder::IsAAC(aMimeType)) {
+ return aSupported.contains(MediaCodecs::AAC);
+ }
+ if (aMimeType.EqualsLiteral("audio/mpeg")) {
+ return aSupported.contains(MediaCodecs::MP3);
+ }
+ if (OpusDataDecoder::IsOpus(aMimeType)) {
+ return aSupported.contains(MediaCodecs::Opus);
+ }
+ if (VorbisDataDecoder::IsVorbis(aMimeType)) {
+ return aSupported.contains(MediaCodecs::Vorbis);
+ }
+ if (aMimeType.EqualsLiteral("audio/flac")) {
+ return aSupported.contains(MediaCodecs::Flac);
+ }
+ if (WaveDataDecoder::IsWave(aMimeType)) {
+ return aSupported.contains(MediaCodecs::Wave);
+ }
+ return false;
+}
+
+} // namespace mozilla