Bug 1835804 - Completely block from doing audio decoding on Content and RDD r=alwu
[gecko.git] / dom / media / platforms / PDMFactory.cpp
blobbb488b53a2542e2045ac593e9d88bae618cd2949
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "PDMFactory.h"
9 #ifdef MOZ_AV1
10 # include "AOMDecoder.h"
11 #endif
12 #include "AgnosticDecoderModule.h"
13 #include "AudioTrimmer.h"
14 #include "BlankDecoderModule.h"
15 #include "DecoderDoctorDiagnostics.h"
16 #include "EMEDecoderModule.h"
17 #include "GMPDecoderModule.h"
18 #include "H264.h"
19 #include "MP4Decoder.h"
20 #include "MediaChangeMonitor.h"
21 #include "MediaInfo.h"
22 #include "OpusDecoder.h"
23 #include "TheoraDecoder.h"
24 #include "VPXDecoder.h"
25 #include "VideoUtils.h"
26 #include "VorbisDecoder.h"
27 #include "WAVDecoder.h"
28 #include "mozilla/ClearOnShutdown.h"
29 #include "mozilla/RemoteDecodeUtils.h"
30 #include "mozilla/RemoteDecoderManagerChild.h"
31 #include "mozilla/RemoteDecoderModule.h"
32 #include "mozilla/SharedThreadPool.h"
33 #include "mozilla/StaticPrefs_media.h"
34 #include "mozilla/SyncRunnable.h"
35 #include "mozilla/TaskQueue.h"
36 #include "mozilla/gfx/gfxVars.h"
37 #include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart
38 #include "nsPrintfCString.h"
40 #include "mozilla/ipc/UtilityAudioDecoderParent.h"
42 #ifdef XP_WIN
43 # include "WMFDecoderModule.h"
44 # include "mozilla/WindowsVersion.h"
45 # ifdef MOZ_WMF_MEDIA_ENGINE
46 # include "MFMediaEngineDecoderModule.h"
47 # endif
48 # ifdef MOZ_WMF_CDM
49 # include "mozilla/CDMProxy.h"
50 # endif
51 #endif
52 #ifdef MOZ_FFVPX
53 # include "FFVPXRuntimeLinker.h"
54 #endif
55 #ifdef MOZ_FFMPEG
56 # include "FFmpegRuntimeLinker.h"
57 #endif
58 #ifdef MOZ_APPLEMEDIA
59 # include "AppleDecoderModule.h"
60 #endif
61 #ifdef MOZ_WIDGET_ANDROID
62 # include "AndroidDecoderModule.h"
63 #endif
64 #ifdef MOZ_OMX
65 # include "OmxDecoderModule.h"
66 #endif
68 #include <functional>
70 using DecodeSupport = mozilla::media::DecodeSupport;
71 using DecodeSupportSet = mozilla::media::DecodeSupportSet;
72 using MediaCodec = mozilla::media::MediaCodec;
73 using MediaCodecsSupport = mozilla::media::MediaCodecsSupport;
74 using MediaCodecsSupported = mozilla::media::MediaCodecsSupported;
75 using MCSInfo = mozilla::media::MCSInfo;
77 namespace mozilla {
79 #define PDM_INIT_LOG(msg, ...) \
80 MOZ_LOG(sPDMLog, LogLevel::Debug, ("PDMInitializer, " msg, ##__VA_ARGS__))
82 extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
84 class PDMInitializer final {
85 public:
86 // This function should only be executed ONCE per process.
87 static void InitPDMs();
89 // Return true if we've finished PDMs initialization.
90 static bool HasInitializedPDMs();
92 private:
93 static void InitGpuPDMs() {
94 #ifdef XP_WIN
95 if (!IsWin7AndPre2000Compatible()) {
96 WMFDecoderModule::Init();
98 #endif
101 static void InitRddPDMs() {
102 #ifdef XP_WIN
103 if (!IsWin7AndPre2000Compatible()) {
104 WMFDecoderModule::Init();
106 #endif
107 #ifdef MOZ_APPLEMEDIA
108 AppleDecoderModule::Init();
109 #endif
110 #ifdef MOZ_FFVPX
111 FFVPXRuntimeLinker::Init();
112 #endif
113 #ifdef MOZ_FFMPEG
114 if (StaticPrefs::media_rdd_ffmpeg_enabled()) {
115 FFmpegRuntimeLinker::Init();
117 #endif
120 static void InitUtilityPDMs() {
121 const ipc::SandboxingKind kind = GetCurrentSandboxingKind();
122 #ifdef XP_WIN
123 if (!IsWin7AndPre2000Compatible() &&
124 kind == ipc::SandboxingKind::UTILITY_AUDIO_DECODING_WMF) {
125 WMFDecoderModule::Init();
127 # ifdef MOZ_WMF_MEDIA_ENGINE
128 if (IsWin10OrLater() && StaticPrefs::media_wmf_media_engine_enabled() &&
129 kind == ipc::SandboxingKind::MF_MEDIA_ENGINE_CDM) {
130 MFMediaEngineDecoderModule::Init();
132 # endif
133 #endif
134 #ifdef MOZ_APPLEMEDIA
135 if (kind == ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA) {
136 AppleDecoderModule::Init();
138 #endif
139 #ifdef MOZ_FFVPX
140 if (kind == ipc::SandboxingKind::GENERIC_UTILITY) {
141 FFVPXRuntimeLinker::Init();
143 #endif
144 #ifdef MOZ_FFMPEG
145 if (StaticPrefs::media_utility_ffmpeg_enabled() &&
146 kind == ipc::SandboxingKind::GENERIC_UTILITY) {
147 FFmpegRuntimeLinker::Init();
149 #endif
152 static void InitContentPDMs() {
153 if (StaticPrefs::media_allow_audio_non_utility()) {
154 #ifdef XP_WIN
155 if (!IsWin7AndPre2000Compatible()) {
156 # ifdef MOZ_WMF
157 if (!StaticPrefs::media_rdd_process_enabled() ||
158 !StaticPrefs::media_rdd_wmf_enabled() ||
159 !StaticPrefs::media_utility_process_enabled() ||
160 !StaticPrefs::media_utility_wmf_enabled()) {
161 WMFDecoderModule::Init();
163 # endif
165 #endif
166 #ifdef MOZ_APPLEMEDIA
167 AppleDecoderModule::Init();
168 #endif
169 #ifdef MOZ_OMX
170 OmxDecoderModule::Init();
171 #endif
172 #ifdef MOZ_FFVPX
173 FFVPXRuntimeLinker::Init();
174 #endif
175 #ifdef MOZ_FFMPEG
176 FFmpegRuntimeLinker::Init();
177 #endif
180 RemoteDecoderManagerChild::Init();
183 static void InitDefaultPDMs() {
184 #ifdef XP_WIN
185 if (!IsWin7AndPre2000Compatible()) {
186 WMFDecoderModule::Init();
188 #endif
189 #ifdef MOZ_APPLEMEDIA
190 AppleDecoderModule::Init();
191 #endif
192 #ifdef MOZ_OMX
193 OmxDecoderModule::Init();
194 #endif
195 #ifdef MOZ_FFVPX
196 FFVPXRuntimeLinker::Init();
197 #endif
198 #ifdef MOZ_FFMPEG
199 FFmpegRuntimeLinker::Init();
200 #endif
203 static bool sHasInitializedPDMs;
204 static StaticMutex sMonitor MOZ_UNANNOTATED;
207 bool PDMInitializer::sHasInitializedPDMs = false;
208 StaticMutex PDMInitializer::sMonitor;
210 /* static */
211 void PDMInitializer::InitPDMs() {
212 StaticMutexAutoLock mon(sMonitor);
213 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
214 MOZ_ASSERT(!sHasInitializedPDMs);
215 if (XRE_IsGPUProcess()) {
216 PDM_INIT_LOG("Init PDMs in GPU process");
217 InitGpuPDMs();
218 } else if (XRE_IsRDDProcess()) {
219 PDM_INIT_LOG("Init PDMs in RDD process");
220 InitRddPDMs();
221 } else if (XRE_IsUtilityProcess()) {
222 PDM_INIT_LOG("Init PDMs in Utility process");
223 InitUtilityPDMs();
224 } else if (XRE_IsContentProcess()) {
225 PDM_INIT_LOG("Init PDMs in Content process");
226 InitContentPDMs();
227 } else {
228 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess(),
229 "PDMFactory is only usable in the "
230 "Parent/GPU/RDD/Utility/Content process");
231 PDM_INIT_LOG("Init PDMs in Chrome process");
232 InitDefaultPDMs();
234 sHasInitializedPDMs = true;
237 /* static */
238 bool PDMInitializer::HasInitializedPDMs() {
239 StaticMutexAutoLock mon(sMonitor);
240 return sHasInitializedPDMs;
243 class SupportChecker {
244 public:
245 enum class Reason : uint8_t {
246 kSupported,
247 kVideoFormatNotSupported,
248 kAudioFormatNotSupported,
249 kUnknown,
252 struct CheckResult {
253 explicit CheckResult(Reason aReason,
254 MediaResult aResult = MediaResult(NS_OK))
255 : mReason(aReason), mMediaResult(std::move(aResult)) {}
256 CheckResult(const CheckResult& aOther) = default;
257 CheckResult(CheckResult&& aOther) = default;
258 CheckResult& operator=(const CheckResult& aOther) = default;
259 CheckResult& operator=(CheckResult&& aOther) = default;
261 Reason mReason;
262 MediaResult mMediaResult;
265 template <class Func>
266 void AddToCheckList(Func&& aChecker) {
267 mCheckerList.AppendElement(std::forward<Func>(aChecker));
270 void AddMediaFormatChecker(const TrackInfo& aTrackConfig) {
271 if (aTrackConfig.IsVideo()) {
272 auto mimeType = aTrackConfig.GetAsVideoInfo()->mMimeType;
273 RefPtr<MediaByteBuffer> extraData =
274 aTrackConfig.GetAsVideoInfo()->mExtraData;
275 AddToCheckList([mimeType, extraData]() {
276 if (MP4Decoder::IsH264(mimeType)) {
277 SPSData spsdata;
278 // WMF H.264 Video Decoder and Apple ATDecoder
279 // do not support YUV444 format.
280 // For consistency, all decoders should be checked.
281 if (H264::DecodeSPSFromExtraData(extraData, spsdata) &&
282 (spsdata.profile_idc == 244 /* Hi444PP */ ||
283 spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
284 return CheckResult(
285 SupportChecker::Reason::kVideoFormatNotSupported,
286 MediaResult(
287 NS_ERROR_DOM_MEDIA_FATAL_ERR,
288 RESULT_DETAIL("Decoder may not have the capability "
289 "to handle the requested video format "
290 "with YUV444 chroma subsampling.")));
293 return CheckResult(SupportChecker::Reason::kSupported);
298 SupportChecker::CheckResult Check() {
299 for (auto& checker : mCheckerList) {
300 auto result = checker();
301 if (result.mReason != SupportChecker::Reason::kSupported) {
302 return result;
305 return CheckResult(SupportChecker::Reason::kSupported);
308 void Clear() { mCheckerList.Clear(); }
310 private:
311 nsTArray<std::function<CheckResult()>> mCheckerList;
312 }; // SupportChecker
314 PDMFactory::PDMFactory() {
315 EnsureInit();
316 CreatePDMs();
317 CreateNullPDM();
320 PDMFactory::~PDMFactory() = default;
322 /* static */
323 void PDMFactory::EnsureInit() {
324 if (PDMInitializer::HasInitializedPDMs()) {
325 return;
327 auto initalization = []() {
328 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
329 if (!PDMInitializer::HasInitializedPDMs()) {
330 // Ensure that all system variables are initialized.
331 gfx::gfxVars::Initialize();
332 // Prime the preferences system from the main thread.
333 Unused << BrowserTabsRemoteAutostart();
334 PDMInitializer::InitPDMs();
337 // If on the main thread, then initialize PDMs. Otherwise, do a sync-dispatch
338 // to main thread.
339 if (NS_IsMainThread()) {
340 initalization();
341 return;
343 nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadSerialEventTarget();
344 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
345 "PDMFactory::EnsureInit", std::move(initalization));
346 SyncRunnable::DispatchToThread(mainTarget, runnable);
349 RefPtr<PlatformDecoderModule::CreateDecoderPromise> PDMFactory::CreateDecoder(
350 const CreateDecoderParams& aParams) {
351 if (aParams.mUseNullDecoder.mUse) {
352 MOZ_ASSERT(mNullPDM);
353 return CreateDecoderWithPDM(mNullPDM, aParams);
355 bool isEncrypted = mEMEPDM && aParams.mConfig.mCrypto.IsEncrypted();
357 if (isEncrypted) {
358 return CreateDecoderWithPDM(mEMEPDM, aParams);
361 return CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync(aParams), 0);
364 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
365 PDMFactory::CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync&& aParams,
366 uint32_t aIndex,
367 Maybe<MediaResult> aEarlierError) {
368 uint32_t i = aIndex;
369 auto params = SupportDecoderParams(aParams);
370 for (; i < mCurrentPDMs.Length(); i++) {
371 if (mCurrentPDMs[i]->Supports(params, nullptr /* diagnostic */) ==
372 media::DecodeSupport::Unsupported) {
373 continue;
375 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
376 CreateDecoderWithPDM(mCurrentPDMs[i], aParams)
377 ->Then(
378 GetCurrentSerialEventTarget(), __func__,
379 [](RefPtr<MediaDataDecoder>&& aDecoder) {
380 return PlatformDecoderModule::CreateDecoderPromise::
381 CreateAndResolve(std::move(aDecoder), __func__);
383 [self = RefPtr{this}, i, params = std::move(aParams)](
384 const MediaResult& aError) mutable {
385 // Try the next PDM.
386 return self->CheckAndMaybeCreateDecoder(std::move(params),
387 i + 1, Some(aError));
389 return p;
391 if (aEarlierError) {
392 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
393 std::move(*aEarlierError), __func__);
395 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
396 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
397 nsPrintfCString("Error no decoder found for %s",
398 aParams.mConfig->mMimeType.get())
399 .get()),
400 __func__);
403 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
404 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
405 const CreateDecoderParams& aParams) {
406 MOZ_ASSERT(aPDM);
407 MediaResult result = NS_OK;
409 SupportChecker supportChecker;
410 const TrackInfo& config = aParams.mConfig;
411 supportChecker.AddMediaFormatChecker(config);
413 auto checkResult = supportChecker.Check();
414 if (checkResult.mReason != SupportChecker::Reason::kSupported) {
415 if (checkResult.mReason ==
416 SupportChecker::Reason::kVideoFormatNotSupported) {
417 result = checkResult.mMediaResult;
418 } else if (checkResult.mReason ==
419 SupportChecker::Reason::kAudioFormatNotSupported) {
420 result = checkResult.mMediaResult;
422 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
423 result, __func__);
426 if (config.IsAudio()) {
427 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
428 p = aPDM->AsyncCreateDecoder(aParams)->Then(
429 GetCurrentSerialEventTarget(), __func__,
430 [params = CreateDecoderParamsForAsync(aParams)](
431 RefPtr<MediaDataDecoder>&& aDecoder) {
432 RefPtr<MediaDataDecoder> decoder = std::move(aDecoder);
433 if (!params.mNoWrapper.mDontUseWrapper) {
434 decoder =
435 new AudioTrimmer(decoder.forget(), CreateDecoderParams(params));
437 return PlatformDecoderModule::CreateDecoderPromise::CreateAndResolve(
438 decoder, __func__);
440 [](const MediaResult& aError) {
441 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
442 aError, __func__);
444 return p;
447 if (!config.IsVideo()) {
448 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
449 MediaResult(
450 NS_ERROR_DOM_MEDIA_FATAL_ERR,
451 RESULT_DETAIL(
452 "Decoder configuration error, expected audio or video.")),
453 __func__);
456 if ((MP4Decoder::IsH264(config.mMimeType) ||
457 #ifdef MOZ_AV1
458 AOMDecoder::IsAV1(config.mMimeType) ||
459 #endif
460 VPXDecoder::IsVPX(config.mMimeType)) &&
461 !aParams.mUseNullDecoder.mUse && !aParams.mNoWrapper.mDontUseWrapper) {
462 return MediaChangeMonitor::Create(this, aParams);
464 return aPDM->AsyncCreateDecoder(aParams);
467 DecodeSupportSet PDMFactory::SupportsMimeType(
468 const nsACString& aMimeType) const {
469 UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
470 if (!trackInfo) {
471 return DecodeSupport::Unsupported;
473 return Supports(SupportDecoderParams(*trackInfo), nullptr);
476 DecodeSupportSet PDMFactory::Supports(
477 const SupportDecoderParams& aParams,
478 DecoderDoctorDiagnostics* aDiagnostics) const {
479 if (mEMEPDM) {
480 return mEMEPDM->Supports(aParams, aDiagnostics);
483 RefPtr<PlatformDecoderModule> current =
484 GetDecoderModule(aParams, aDiagnostics);
486 if (!current) {
487 return DecodeSupport::Unsupported;
490 // We have a PDM - check for + return SW/HW support info
491 return current->Supports(aParams, aDiagnostics);
494 void PDMFactory::CreatePDMs() {
495 if (StaticPrefs::media_use_blank_decoder()) {
496 CreateAndStartupPDM<BlankDecoderModule>();
497 // The Blank PDM SupportsMimeType reports true for all codecs; the creation
498 // of its decoder is infallible. As such it will be used for all media, we
499 // can stop creating more PDM from this point.
500 return;
503 if (XRE_IsGPUProcess()) {
504 CreateGpuPDMs();
505 } else if (XRE_IsRDDProcess()) {
506 CreateRddPDMs();
507 } else if (XRE_IsUtilityProcess()) {
508 CreateUtilityPDMs();
509 } else if (XRE_IsContentProcess()) {
510 CreateContentPDMs();
511 } else {
512 MOZ_DIAGNOSTIC_ASSERT(
513 XRE_IsParentProcess(),
514 "PDMFactory is only usable in the Parent/GPU/RDD/Content process");
515 CreateDefaultPDMs();
519 void PDMFactory::CreateGpuPDMs() {
520 #ifdef XP_WIN
521 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
522 CreateAndStartupPDM<WMFDecoderModule>();
524 #endif
527 #if defined(MOZ_FFMPEG)
528 static DecoderDoctorDiagnostics::Flags GetFailureFlagBasedOnFFmpegStatus(
529 const FFmpegRuntimeLinker::LinkStatus& aStatus) {
530 switch (aStatus) {
531 case FFmpegRuntimeLinker::LinkStatus_INVALID_FFMPEG_CANDIDATE:
532 case FFmpegRuntimeLinker::LinkStatus_UNUSABLE_LIBAV57:
533 case FFmpegRuntimeLinker::LinkStatus_INVALID_LIBAV_CANDIDATE:
534 case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_FFMPEG:
535 case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_LIBAV:
536 case FFmpegRuntimeLinker::LinkStatus_INVALID_CANDIDATE:
537 return DecoderDoctorDiagnostics::Flags::LibAVCodecUnsupported;
538 default:
539 MOZ_DIAGNOSTIC_ASSERT(
540 aStatus == FFmpegRuntimeLinker::LinkStatus_NOT_FOUND,
541 "Only call this method when linker fails.");
542 return DecoderDoctorDiagnostics::Flags::FFmpegNotFound;
545 #endif
547 void PDMFactory::CreateRddPDMs() {
548 #ifdef XP_WIN
549 if (StaticPrefs::media_wmf_enabled() &&
550 StaticPrefs::media_rdd_wmf_enabled()) {
551 CreateAndStartupPDM<WMFDecoderModule>();
553 #endif
554 #ifdef MOZ_APPLEMEDIA
555 if (StaticPrefs::media_rdd_applemedia_enabled()) {
556 CreateAndStartupPDM<AppleDecoderModule>();
558 #endif
559 #ifdef MOZ_FFVPX
560 if (StaticPrefs::media_ffvpx_enabled() &&
561 StaticPrefs::media_rdd_ffvpx_enabled()) {
562 CreateAndStartupPDM<FFVPXRuntimeLinker>();
564 #endif
565 #ifdef MOZ_FFMPEG
566 if (StaticPrefs::media_ffmpeg_enabled() &&
567 StaticPrefs::media_rdd_ffmpeg_enabled() &&
568 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
569 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
570 FFmpegRuntimeLinker::LinkStatusCode());
572 #endif
573 CreateAndStartupPDM<AgnosticDecoderModule>();
576 void PDMFactory::CreateUtilityPDMs() {
577 const ipc::SandboxingKind aKind = GetCurrentSandboxingKind();
578 #ifdef XP_WIN
579 if (StaticPrefs::media_wmf_enabled() &&
580 StaticPrefs::media_utility_wmf_enabled() &&
581 aKind == ipc::SandboxingKind::UTILITY_AUDIO_DECODING_WMF) {
582 CreateAndStartupPDM<WMFDecoderModule>();
584 #endif
585 #ifdef MOZ_APPLEMEDIA
586 if (StaticPrefs::media_utility_applemedia_enabled() &&
587 aKind == ipc::SandboxingKind::UTILITY_AUDIO_DECODING_APPLE_MEDIA) {
588 CreateAndStartupPDM<AppleDecoderModule>();
590 #endif
591 if (aKind == ipc::SandboxingKind::GENERIC_UTILITY) {
592 #ifdef MOZ_FFVPX
593 if (StaticPrefs::media_ffvpx_enabled() &&
594 StaticPrefs::media_utility_ffvpx_enabled()) {
595 CreateAndStartupPDM<FFVPXRuntimeLinker>();
597 #endif
598 #ifdef MOZ_FFMPEG
599 if (StaticPrefs::media_ffmpeg_enabled() &&
600 StaticPrefs::media_utility_ffmpeg_enabled() &&
601 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
602 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
603 FFmpegRuntimeLinker::LinkStatusCode());
605 #endif
606 #ifdef MOZ_WIDGET_ANDROID
607 if (StaticPrefs::media_utility_android_media_codec_enabled()) {
608 StartupPDM(AndroidDecoderModule::Create(),
609 StaticPrefs::media_android_media_codec_preferred());
611 #endif
612 CreateAndStartupPDM<AgnosticDecoderModule>();
614 #ifdef MOZ_WMF_MEDIA_ENGINE
615 if (aKind == ipc::SandboxingKind::MF_MEDIA_ENGINE_CDM) {
616 if (IsWin10OrLater() && StaticPrefs::media_wmf_media_engine_enabled()) {
617 CreateAndStartupPDM<MFMediaEngineDecoderModule>();
620 #endif
623 void PDMFactory::CreateContentPDMs() {
624 if (StaticPrefs::media_gpu_process_decoder()) {
625 CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::GpuProcess);
628 if (StaticPrefs::media_rdd_process_enabled()) {
629 CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::RddProcess);
632 if (StaticPrefs::media_utility_process_enabled()) {
633 #ifdef MOZ_APPLEMEDIA
634 CreateAndStartupPDM<RemoteDecoderModule>(
635 RemoteDecodeIn::UtilityProcess_AppleMedia);
636 #endif
637 #ifdef XP_WIN
638 CreateAndStartupPDM<RemoteDecoderModule>(
639 RemoteDecodeIn::UtilityProcess_WMF);
640 #endif
641 // WMF and AppleMedia should be created before Generic because the order
642 // affects what decoder module would be chose first.
643 CreateAndStartupPDM<RemoteDecoderModule>(
644 RemoteDecodeIn::UtilityProcess_Generic);
646 #ifdef MOZ_WMF_MEDIA_ENGINE
647 if (StaticPrefs::media_wmf_media_engine_enabled()) {
648 CreateAndStartupPDM<RemoteDecoderModule>(
649 RemoteDecodeIn::UtilityProcess_MFMediaEngineCDM);
651 #endif
653 #if !defined(MOZ_WIDGET_ANDROID)
654 if (StaticPrefs::media_allow_audio_non_utility()) {
655 #endif // !defined(MOZ_WIDGET_ANDROID)
656 #ifdef XP_WIN
657 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
658 # ifdef MOZ_WMF
659 if (!StaticPrefs::media_rdd_process_enabled() ||
660 !StaticPrefs::media_rdd_wmf_enabled()) {
661 if (!CreateAndStartupPDM<WMFDecoderModule>()) {
662 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
665 # endif
666 } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
667 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
669 #endif
671 #ifdef MOZ_APPLEMEDIA
672 CreateAndStartupPDM<AppleDecoderModule>();
673 #endif
674 #ifdef MOZ_OMX
675 if (StaticPrefs::media_omx_enabled()) {
676 CreateAndStartupPDM<OmxDecoderModule>();
678 #endif
679 #ifdef MOZ_FFVPX
680 if (StaticPrefs::media_ffvpx_enabled()) {
681 CreateAndStartupPDM<FFVPXRuntimeLinker>();
683 #endif
684 #ifdef MOZ_FFMPEG
685 if (StaticPrefs::media_ffmpeg_enabled() &&
686 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
687 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
688 FFmpegRuntimeLinker::LinkStatusCode());
690 #endif
692 CreateAndStartupPDM<AgnosticDecoderModule>();
693 #if !defined(MOZ_WIDGET_ANDROID)
695 #endif // !defined(MOZ_WIDGET_ANDROID)
697 // Android still needs this, the actual decoder is remoted on java side
698 #ifdef MOZ_WIDGET_ANDROID
699 if (StaticPrefs::media_android_media_codec_enabled()) {
700 StartupPDM(AndroidDecoderModule::Create(),
701 StaticPrefs::media_android_media_codec_preferred());
703 #endif
705 // TODO: Should this be also under media_allow_audio_non_utility ?
706 if (StaticPrefs::media_gmp_decoder_enabled() &&
707 !StartupPDM(GMPDecoderModule::Create(),
708 StaticPrefs::media_gmp_decoder_preferred())) {
709 mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
713 void PDMFactory::CreateDefaultPDMs() {
714 #ifdef XP_WIN
715 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
716 if (!CreateAndStartupPDM<WMFDecoderModule>()) {
717 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
719 } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
720 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
722 #endif
724 #ifdef MOZ_APPLEMEDIA
725 CreateAndStartupPDM<AppleDecoderModule>();
726 #endif
727 #ifdef MOZ_OMX
728 if (StaticPrefs::media_omx_enabled()) {
729 CreateAndStartupPDM<OmxDecoderModule>();
731 #endif
732 #ifdef MOZ_FFVPX
733 if (StaticPrefs::media_ffvpx_enabled()) {
734 CreateAndStartupPDM<FFVPXRuntimeLinker>();
736 #endif
737 #ifdef MOZ_FFMPEG
738 if (StaticPrefs::media_ffmpeg_enabled() &&
739 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
740 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
741 FFmpegRuntimeLinker::LinkStatusCode());
743 #endif
744 #ifdef MOZ_WIDGET_ANDROID
745 if (StaticPrefs::media_android_media_codec_enabled()) {
746 StartupPDM(AndroidDecoderModule::Create(),
747 StaticPrefs::media_android_media_codec_preferred());
749 #endif
751 CreateAndStartupPDM<AgnosticDecoderModule>();
753 if (StaticPrefs::media_gmp_decoder_enabled() &&
754 !StartupPDM(GMPDecoderModule::Create(),
755 StaticPrefs::media_gmp_decoder_preferred())) {
756 mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
760 void PDMFactory::CreateNullPDM() {
761 mNullPDM = CreateNullDecoderModule();
762 MOZ_ASSERT(mNullPDM && NS_SUCCEEDED(mNullPDM->Startup()));
765 bool PDMFactory::StartupPDM(already_AddRefed<PlatformDecoderModule> aPDM,
766 bool aInsertAtBeginning) {
767 RefPtr<PlatformDecoderModule> pdm = aPDM;
768 if (pdm && NS_SUCCEEDED(pdm->Startup())) {
769 if (aInsertAtBeginning) {
770 mCurrentPDMs.InsertElementAt(0, pdm);
771 } else {
772 mCurrentPDMs.AppendElement(pdm);
774 return true;
776 return false;
779 already_AddRefed<PlatformDecoderModule> PDMFactory::GetDecoderModule(
780 const SupportDecoderParams& aParams,
781 DecoderDoctorDiagnostics* aDiagnostics) const {
782 if (aDiagnostics) {
783 // If libraries failed to load, the following loop over mCurrentPDMs
784 // will not even try to use them. So we record failures now.
785 aDiagnostics->SetFailureFlags(mFailureFlags);
788 RefPtr<PlatformDecoderModule> pdm;
789 for (const auto& current : mCurrentPDMs) {
790 if (current->Supports(aParams, aDiagnostics) !=
791 media::DecodeSupport::Unsupported) {
792 pdm = current;
793 break;
796 return pdm.forget();
799 void PDMFactory::SetCDMProxy(CDMProxy* aProxy) {
800 MOZ_ASSERT(aProxy);
802 #ifdef MOZ_WIDGET_ANDROID
803 if (IsWidevineKeySystem(aProxy->KeySystem())) {
804 mEMEPDM = AndroidDecoderModule::Create(aProxy);
805 return;
807 #endif
808 #ifdef MOZ_WMF_CDM
809 if (IsPlayReadyKeySystemAndSupported(aProxy->KeySystem())) {
810 mEMEPDM = RemoteDecoderModule::Create(
811 RemoteDecodeIn::UtilityProcess_MFMediaEngineCDM);
812 return;
814 #endif
815 auto m = MakeRefPtr<PDMFactory>();
816 mEMEPDM = MakeRefPtr<EMEDecoderModule>(aProxy, m);
819 /* static */
820 media::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
821 MOZ_ASSERT(NS_IsMainThread());
823 static auto calculate = []() {
824 auto pdm = MakeRefPtr<PDMFactory>();
825 MediaCodecsSupported supported;
826 // H264 and AAC depends on external framework that must be dynamically
827 // loaded.
828 // We currently only ship a single PDM per platform able to decode AAC or
829 // H264. As such we can assert that being able to create a H264 or AAC
830 // decoder indicates that with WMF on Windows or FFmpeg on Unixes is
831 // available.
832 // This logic will have to be revisited if a PDM supporting either codec
833 // will be added in addition to the WMF and FFmpeg PDM (such as OpenH264)
834 for (const auto& cd : MCSInfo::GetAllCodecDefinitions()) {
835 supported += MCSInfo::GetDecodeMediaCodecsSupported(
836 cd.codec, pdm->SupportsMimeType(nsCString(cd.mimeTypeString)));
838 return supported;
841 static MediaCodecsSupported supported = calculate();
842 if (aForceRefresh) {
843 supported = calculate();
846 return supported;
849 /* static */
850 DecodeSupportSet PDMFactory::SupportsMimeType(
851 const nsACString& aMimeType, const MediaCodecsSupported& aSupported,
852 RemoteDecodeIn aLocation) {
853 const TrackSupportSet supports =
854 RemoteDecoderManagerChild::GetTrackSupport(aLocation);
856 if (supports.contains(TrackSupport::Video)) {
857 if (MP4Decoder::IsH264(aMimeType)) {
858 return MCSInfo::GetDecodeSupportSet(MediaCodec::H264, aSupported);
860 if (VPXDecoder::IsVP9(aMimeType)) {
861 return MCSInfo::GetDecodeSupportSet(MediaCodec::VP9, aSupported);
863 if (VPXDecoder::IsVP8(aMimeType)) {
864 return MCSInfo::GetDecodeSupportSet(MediaCodec::VP8, aSupported);
866 #ifdef MOZ_AV1
867 if (AOMDecoder::IsAV1(aMimeType)) {
868 return MCSInfo::GetDecodeSupportSet(MediaCodec::AV1, aSupported);
870 #endif
871 if (TheoraDecoder::IsTheora(aMimeType)) {
872 return MCSInfo::GetDecodeSupportSet(MediaCodec::Theora, aSupported);
876 if (supports.contains(TrackSupport::Audio)) {
877 if (MP4Decoder::IsAAC(aMimeType)) {
878 return MCSInfo::GetDecodeSupportSet(MediaCodec::AAC, aSupported);
880 if (aMimeType.EqualsLiteral("audio/mpeg")) {
881 return MCSInfo::GetDecodeSupportSet(MediaCodec::MP3, aSupported);
883 if (OpusDataDecoder::IsOpus(aMimeType)) {
884 return MCSInfo::GetDecodeSupportSet(MediaCodec::Opus, aSupported);
886 if (VorbisDataDecoder::IsVorbis(aMimeType)) {
887 return MCSInfo::GetDecodeSupportSet(MediaCodec::Vorbis, aSupported);
889 if (aMimeType.EqualsLiteral("audio/flac")) {
890 return MCSInfo::GetDecodeSupportSet(MediaCodec::FLAC, aSupported);
892 if (WaveDataDecoder::IsWave(aMimeType)) {
893 return MCSInfo::GetDecodeSupportSet(MediaCodec::Wave, aSupported);
896 return DecodeSupport::Unsupported;
899 /* static */
900 bool PDMFactory::AllDecodersAreRemote() {
901 return StaticPrefs::media_rdd_process_enabled() &&
902 #if defined(MOZ_FFVPX)
903 StaticPrefs::media_rdd_ffvpx_enabled() &&
904 #endif
905 StaticPrefs::media_rdd_opus_enabled() &&
906 StaticPrefs::media_rdd_theora_enabled() &&
907 StaticPrefs::media_rdd_vorbis_enabled() &&
908 StaticPrefs::media_rdd_vpx_enabled() &&
909 #if defined(MOZ_WMF)
910 StaticPrefs::media_rdd_wmf_enabled() &&
911 #endif
912 StaticPrefs::media_rdd_wav_enabled();
915 #undef PDM_INIT_LOG
916 } // namespace mozilla