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/. */
6
7 #include "PDMFactory.h"
8
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/RemoteDecoderManagerChild.h"
30 #include "mozilla/RemoteDecoderModule.h"
31 #include "mozilla/SharedThreadPool.h"
32 #include "mozilla/StaticPrefs_media.h"
33 #include "mozilla/SyncRunnable.h"
34 #include "mozilla/TaskQueue.h"
35 #include "mozilla/gfx/gfxVars.h"
36 #include "nsIXULRuntime.h" // for BrowserTabsRemoteAutostart
37 #include "nsPrintfCString.h"
38
39 #ifdef XP_WIN
40 # include "WMFDecoderModule.h"
41 # include "mozilla/WindowsVersion.h"
42 #endif
43 #ifdef MOZ_FFVPX
44 # include "FFVPXRuntimeLinker.h"
45 #endif
46 #ifdef MOZ_FFMPEG
47 # include "FFmpegRuntimeLinker.h"
48 #endif
49 #ifdef MOZ_APPLEMEDIA
50 # include "AppleDecoderModule.h"
51 #endif
52 #ifdef MOZ_WIDGET_ANDROID
53 # include "AndroidDecoderModule.h"
54 #endif
55 #ifdef MOZ_OMX
56 # include "OmxDecoderModule.h"
57 #endif
58
59 #include <functional>
60
61 namespace mozilla {
62
63 #define PDM_INIT_LOG(msg, ...) \
64 MOZ_LOG(sPDMLog, LogLevel::Debug, ("PDMInitializer, " msg, ##__VA_ARGS__))
65
66 extern already_AddRefed<PlatformDecoderModule> CreateNullDecoderModule();
67
68 class PDMInitializer final {
69 public:
70 // This function should only be executed ONCE per process.
71 static void InitPDMs();
72
73 // Return true if we've finished PDMs initialization.
74 static bool HasInitializedPDMs();
75
76 private:
InitGpuPDMs()77 static void InitGpuPDMs() {
78 #ifdef XP_WIN
79 if (!IsWin7AndPre2000Compatible()) {
80 WMFDecoderModule::Init();
81 }
82 #endif
83 }
84
InitRddPDMs()85 static void InitRddPDMs() {
86 #ifdef XP_WIN
87 if (!IsWin7AndPre2000Compatible()) {
88 WMFDecoderModule::Init();
89 }
90 #endif
91 #ifdef MOZ_APPLEMEDIA
92 AppleDecoderModule::Init();
93 #endif
94 #ifdef MOZ_FFVPX
95 FFVPXRuntimeLinker::Init();
96 #endif
97 #ifdef MOZ_FFMPEG
98 if (StaticPrefs::media_rdd_ffmpeg_enabled()) {
99 FFmpegRuntimeLinker::Init();
100 }
101 #endif
102 }
103
InitContentPDMs()104 static void InitContentPDMs() {
105 #ifdef XP_WIN
106 if (!IsWin7AndPre2000Compatible()) {
107 # ifdef MOZ_WMF
108 if (!StaticPrefs::media_rdd_process_enabled() ||
109 !StaticPrefs::media_rdd_wmf_enabled()) {
110 WMFDecoderModule::Init();
111 }
112 # endif
113 }
114 #endif
115 #ifdef MOZ_APPLEMEDIA
116 AppleDecoderModule::Init();
117 #endif
118 #ifdef MOZ_OMX
119 OmxDecoderModule::Init();
120 #endif
121 #ifdef MOZ_FFVPX
122 FFVPXRuntimeLinker::Init();
123 #endif
124 #ifdef MOZ_FFMPEG
125 FFmpegRuntimeLinker::Init();
126 #endif
127 RemoteDecoderManagerChild::Init();
128 }
129
InitDefaultPDMs()130 static void InitDefaultPDMs() {
131 #ifdef XP_WIN
132 if (!IsWin7AndPre2000Compatible()) {
133 WMFDecoderModule::Init();
134 }
135 #endif
136 #ifdef MOZ_APPLEMEDIA
137 AppleDecoderModule::Init();
138 #endif
139 #ifdef MOZ_OMX
140 OmxDecoderModule::Init();
141 #endif
142 #ifdef MOZ_FFVPX
143 FFVPXRuntimeLinker::Init();
144 #endif
145 #ifdef MOZ_FFMPEG
146 FFmpegRuntimeLinker::Init();
147 #endif
148 }
149
150 static bool sHasInitializedPDMs;
151 static StaticMutex sMonitor;
152 };
153
154 bool PDMInitializer::sHasInitializedPDMs = false;
155 StaticMutex PDMInitializer::sMonitor;
156
157 /* static */
InitPDMs()158 void PDMInitializer::InitPDMs() {
159 StaticMutexAutoLock mon(sMonitor);
160 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
161 MOZ_ASSERT(!sHasInitializedPDMs);
162 if (XRE_IsGPUProcess()) {
163 PDM_INIT_LOG("Init PDMs in GPU process");
164 InitGpuPDMs();
165 } else if (XRE_IsRDDProcess()) {
166 PDM_INIT_LOG("Init PDMs in RDD process");
167 InitRddPDMs();
168 } else if (XRE_IsContentProcess()) {
169 PDM_INIT_LOG("Init PDMs in Content process");
170 InitContentPDMs();
171 } else {
172 MOZ_DIAGNOSTIC_ASSERT(
173 XRE_IsParentProcess(),
174 "PDMFactory is only usable in the Parent/GPU/RDD/Content process");
175 PDM_INIT_LOG("Init PDMs in Chrome process");
176 InitDefaultPDMs();
177 }
178 sHasInitializedPDMs = true;
179 }
180
181 /* static */
HasInitializedPDMs()182 bool PDMInitializer::HasInitializedPDMs() {
183 StaticMutexAutoLock mon(sMonitor);
184 return sHasInitializedPDMs;
185 }
186
187 class SupportChecker {
188 public:
189 enum class Reason : uint8_t {
190 kSupported,
191 kVideoFormatNotSupported,
192 kAudioFormatNotSupported,
193 kUnknown,
194 };
195
196 struct CheckResult {
CheckResultmozilla::SupportChecker::CheckResult197 explicit CheckResult(Reason aReason,
198 MediaResult aResult = MediaResult(NS_OK))
199 : mReason(aReason), mMediaResult(std::move(aResult)) {}
200 CheckResult(const CheckResult& aOther) = default;
201 CheckResult(CheckResult&& aOther) = default;
202 CheckResult& operator=(const CheckResult& aOther) = default;
203 CheckResult& operator=(CheckResult&& aOther) = default;
204
205 Reason mReason;
206 MediaResult mMediaResult;
207 };
208
209 template <class Func>
AddToCheckList(Func && aChecker)210 void AddToCheckList(Func&& aChecker) {
211 mCheckerList.AppendElement(std::forward<Func>(aChecker));
212 }
213
AddMediaFormatChecker(const TrackInfo & aTrackConfig)214 void AddMediaFormatChecker(const TrackInfo& aTrackConfig) {
215 if (aTrackConfig.IsVideo()) {
216 auto mimeType = aTrackConfig.GetAsVideoInfo()->mMimeType;
217 RefPtr<MediaByteBuffer> extraData =
218 aTrackConfig.GetAsVideoInfo()->mExtraData;
219 AddToCheckList([mimeType, extraData]() {
220 if (MP4Decoder::IsH264(mimeType)) {
221 SPSData spsdata;
222 // WMF H.264 Video Decoder and Apple ATDecoder
223 // do not support YUV444 format.
224 // For consistency, all decoders should be checked.
225 if (H264::DecodeSPSFromExtraData(extraData, spsdata) &&
226 (spsdata.profile_idc == 244 /* Hi444PP */ ||
227 spsdata.chroma_format_idc == PDMFactory::kYUV444)) {
228 return CheckResult(
229 SupportChecker::Reason::kVideoFormatNotSupported,
230 MediaResult(
231 NS_ERROR_DOM_MEDIA_FATAL_ERR,
232 RESULT_DETAIL("Decoder may not have the capability "
233 "to handle the requested video format "
234 "with YUV444 chroma subsampling.")));
235 }
236 }
237 return CheckResult(SupportChecker::Reason::kSupported);
238 });
239 }
240 }
241
Check()242 SupportChecker::CheckResult Check() {
243 for (auto& checker : mCheckerList) {
244 auto result = checker();
245 if (result.mReason != SupportChecker::Reason::kSupported) {
246 return result;
247 }
248 }
249 return CheckResult(SupportChecker::Reason::kSupported);
250 }
251
Clear()252 void Clear() { mCheckerList.Clear(); }
253
254 private:
255 nsTArray<std::function<CheckResult()>> mCheckerList;
256 }; // SupportChecker
257
PDMFactory()258 PDMFactory::PDMFactory() {
259 EnsureInit();
260 CreatePDMs();
261 CreateNullPDM();
262 }
263
264 PDMFactory::~PDMFactory() = default;
265
266 /* static */
EnsureInit()267 void PDMFactory::EnsureInit() {
268 if (PDMInitializer::HasInitializedPDMs()) {
269 return;
270 }
271 auto initalization = []() {
272 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
273 if (!PDMInitializer::HasInitializedPDMs()) {
274 // Ensure that all system variables are initialized.
275 gfx::gfxVars::Initialize();
276 // Prime the preferences system from the main thread.
277 Unused << BrowserTabsRemoteAutostart();
278 PDMInitializer::InitPDMs();
279 }
280 };
281 // If on the main thread, then initialize PDMs. Otherwise, do a sync-dispatch
282 // to main thread.
283 if (NS_IsMainThread()) {
284 initalization();
285 return;
286 }
287 nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadEventTarget();
288 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
289 "PDMFactory::EnsureInit", std::move(initalization));
290 SyncRunnable::DispatchToThread(mainTarget, runnable);
291 }
292
CreateDecoder(const CreateDecoderParams & aParams)293 RefPtr<PlatformDecoderModule::CreateDecoderPromise> PDMFactory::CreateDecoder(
294 const CreateDecoderParams& aParams) {
295 if (aParams.mUseNullDecoder.mUse) {
296 MOZ_ASSERT(mNullPDM);
297 return CreateDecoderWithPDM(mNullPDM, aParams);
298 }
299 bool isEncrypted = mEMEPDM && aParams.mConfig.mCrypto.IsEncrypted();
300
301 if (isEncrypted) {
302 return CreateDecoderWithPDM(mEMEPDM, aParams);
303 }
304
305 return CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync(aParams), 0);
306 }
307
308 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync && aParams,uint32_t aIndex,Maybe<MediaResult> aEarlierError)309 PDMFactory::CheckAndMaybeCreateDecoder(CreateDecoderParamsForAsync&& aParams,
310 uint32_t aIndex,
311 Maybe<MediaResult> aEarlierError) {
312 uint32_t i = aIndex;
313 auto params = SupportDecoderParams(aParams);
314 for (; i < mCurrentPDMs.Length(); i++) {
315 if (!mCurrentPDMs[i]->Supports(params, nullptr /* diagnostic */)) {
316 continue;
317 }
318 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p =
319 CreateDecoderWithPDM(mCurrentPDMs[i], aParams)
320 ->Then(
321 GetCurrentSerialEventTarget(), __func__,
322 [](RefPtr<MediaDataDecoder>&& aDecoder) {
323 return PlatformDecoderModule::CreateDecoderPromise::
324 CreateAndResolve(std::move(aDecoder), __func__);
325 },
326 [self = RefPtr{this}, i, params = std::move(aParams)](
327 const MediaResult& aError) mutable {
328 // Try the next PDM.
329 return self->CheckAndMaybeCreateDecoder(std::move(params),
330 i + 1, Some(aError));
331 });
332 return p;
333 }
334 if (aEarlierError) {
335 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
336 std::move(*aEarlierError), __func__);
337 }
338 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
339 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
340 nsPrintfCString("Error no decoder found for %s",
341 aParams.mConfig->mMimeType.get())
342 .get()),
343 __func__);
344 }
345
346 RefPtr<PlatformDecoderModule::CreateDecoderPromise>
CreateDecoderWithPDM(PlatformDecoderModule * aPDM,const CreateDecoderParams & aParams)347 PDMFactory::CreateDecoderWithPDM(PlatformDecoderModule* aPDM,
348 const CreateDecoderParams& aParams) {
349 MOZ_ASSERT(aPDM);
350 MediaResult result = NS_OK;
351
352 SupportChecker supportChecker;
353 const TrackInfo& config = aParams.mConfig;
354 supportChecker.AddMediaFormatChecker(config);
355
356 auto checkResult = supportChecker.Check();
357 if (checkResult.mReason != SupportChecker::Reason::kSupported) {
358 if (checkResult.mReason ==
359 SupportChecker::Reason::kVideoFormatNotSupported) {
360 result = checkResult.mMediaResult;
361 } else if (checkResult.mReason ==
362 SupportChecker::Reason::kAudioFormatNotSupported) {
363 result = checkResult.mMediaResult;
364 }
365 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
366 result, __func__);
367 }
368
369 if (config.IsAudio()) {
370 RefPtr<PlatformDecoderModule::CreateDecoderPromise> p;
371 p = aPDM->AsyncCreateDecoder(aParams)->Then(
372 GetCurrentSerialEventTarget(), __func__,
373 [params = CreateDecoderParamsForAsync(aParams)](
374 RefPtr<MediaDataDecoder>&& aDecoder) {
375 RefPtr<MediaDataDecoder> decoder = std::move(aDecoder);
376 if (!params.mNoWrapper.mDontUseWrapper) {
377 decoder =
378 new AudioTrimmer(decoder.forget(), CreateDecoderParams(params));
379 }
380 return PlatformDecoderModule::CreateDecoderPromise::CreateAndResolve(
381 decoder, __func__);
382 },
383 [](const MediaResult& aError) {
384 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
385 aError, __func__);
386 });
387 return p;
388 }
389
390 if (!config.IsVideo()) {
391 return PlatformDecoderModule::CreateDecoderPromise::CreateAndReject(
392 MediaResult(
393 NS_ERROR_DOM_MEDIA_FATAL_ERR,
394 RESULT_DETAIL(
395 "Decoder configuration error, expected audio or video.")),
396 __func__);
397 }
398
399 if ((MP4Decoder::IsH264(config.mMimeType) ||
400 VPXDecoder::IsVPX(config.mMimeType)) &&
401 !aParams.mUseNullDecoder.mUse && !aParams.mNoWrapper.mDontUseWrapper) {
402 return MediaChangeMonitor::Create(aPDM, aParams);
403 }
404 return aPDM->AsyncCreateDecoder(aParams);
405 }
406
SupportsMimeType(const nsACString & aMimeType) const407 bool PDMFactory::SupportsMimeType(const nsACString& aMimeType) const {
408 UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType);
409 if (!trackInfo) {
410 return false;
411 }
412 return Supports(SupportDecoderParams(*trackInfo), nullptr);
413 }
414
Supports(const SupportDecoderParams & aParams,DecoderDoctorDiagnostics * aDiagnostics) const415 bool PDMFactory::Supports(const SupportDecoderParams& aParams,
416 DecoderDoctorDiagnostics* aDiagnostics) const {
417 if (mEMEPDM) {
418 return mEMEPDM->Supports(aParams, aDiagnostics);
419 }
420
421 RefPtr<PlatformDecoderModule> current =
422 GetDecoderModule(aParams, aDiagnostics);
423 return !!current;
424 }
425
CreatePDMs()426 void PDMFactory::CreatePDMs() {
427 if (StaticPrefs::media_use_blank_decoder()) {
428 CreateAndStartupPDM<BlankDecoderModule>();
429 // The Blank PDM SupportsMimeType reports true for all codecs; the creation
430 // of its decoder is infallible. As such it will be used for all media, we
431 // can stop creating more PDM from this point.
432 return;
433 }
434
435 if (XRE_IsGPUProcess()) {
436 CreateGpuPDMs();
437 } else if (XRE_IsRDDProcess()) {
438 CreateRddPDMs();
439 } else if (XRE_IsContentProcess()) {
440 CreateContentPDMs();
441 } else {
442 MOZ_DIAGNOSTIC_ASSERT(
443 XRE_IsParentProcess(),
444 "PDMFactory is only usable in the Parent/GPU/RDD/Content process");
445 CreateDefaultPDMs();
446 }
447 }
448
CreateGpuPDMs()449 void PDMFactory::CreateGpuPDMs() {
450 #ifdef XP_WIN
451 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
452 CreateAndStartupPDM<WMFDecoderModule>();
453 }
454 #endif
455 }
456
457 #if defined(MOZ_FFMPEG)
GetFailureFlagBasedOnFFmpegStatus(const FFmpegRuntimeLinker::LinkStatus & aStatus)458 static DecoderDoctorDiagnostics::Flags GetFailureFlagBasedOnFFmpegStatus(
459 const FFmpegRuntimeLinker::LinkStatus& aStatus) {
460 switch (aStatus) {
461 case FFmpegRuntimeLinker::LinkStatus_INVALID_FFMPEG_CANDIDATE:
462 case FFmpegRuntimeLinker::LinkStatus_UNUSABLE_LIBAV57:
463 case FFmpegRuntimeLinker::LinkStatus_INVALID_LIBAV_CANDIDATE:
464 case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_FFMPEG:
465 case FFmpegRuntimeLinker::LinkStatus_OBSOLETE_LIBAV:
466 case FFmpegRuntimeLinker::LinkStatus_INVALID_CANDIDATE:
467 return DecoderDoctorDiagnostics::Flags::LibAVCodecUnsupported;
468 default:
469 MOZ_DIAGNOSTIC_ASSERT(
470 aStatus == FFmpegRuntimeLinker::LinkStatus_NOT_FOUND,
471 "Only call this method when linker fails.");
472 return DecoderDoctorDiagnostics::Flags::FFmpegNotFound;
473 }
474 }
475 #endif
476
CreateRddPDMs()477 void PDMFactory::CreateRddPDMs() {
478 #ifdef XP_WIN
479 if (StaticPrefs::media_wmf_enabled() &&
480 StaticPrefs::media_rdd_wmf_enabled()) {
481 CreateAndStartupPDM<WMFDecoderModule>();
482 }
483 #endif
484 #ifdef MOZ_APPLEMEDIA
485 if (StaticPrefs::media_rdd_applemedia_enabled()) {
486 CreateAndStartupPDM<AppleDecoderModule>();
487 }
488 #endif
489 #ifdef MOZ_FFVPX
490 if (StaticPrefs::media_ffvpx_enabled() &&
491 StaticPrefs::media_rdd_ffvpx_enabled()) {
492 CreateAndStartupPDM<FFVPXRuntimeLinker>();
493 }
494 #endif
495 #ifdef MOZ_FFMPEG
496 if (StaticPrefs::media_ffmpeg_enabled() &&
497 StaticPrefs::media_rdd_ffmpeg_enabled() &&
498 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
499 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
500 FFmpegRuntimeLinker::LinkStatusCode());
501 }
502 #endif
503 CreateAndStartupPDM<AgnosticDecoderModule>();
504 }
505
CreateContentPDMs()506 void PDMFactory::CreateContentPDMs() {
507 if (StaticPrefs::media_gpu_process_decoder()) {
508 CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::GpuProcess);
509 }
510
511 if (StaticPrefs::media_rdd_process_enabled()) {
512 CreateAndStartupPDM<RemoteDecoderModule>(RemoteDecodeIn::RddProcess);
513 }
514
515 #ifdef XP_WIN
516 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
517 # ifdef MOZ_WMF
518 if (!StaticPrefs::media_rdd_process_enabled() ||
519 !StaticPrefs::media_rdd_wmf_enabled()) {
520 if (!CreateAndStartupPDM<WMFDecoderModule>()) {
521 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
522 }
523 }
524 # endif
525 } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
526 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
527 }
528 #endif
529
530 #ifdef MOZ_APPLEMEDIA
531 CreateAndStartupPDM<AppleDecoderModule>();
532 #endif
533 #ifdef MOZ_OMX
534 if (StaticPrefs::media_omx_enabled()) {
535 CreateAndStartupPDM<OmxDecoderModule>();
536 }
537 #endif
538 #ifdef MOZ_FFVPX
539 if (StaticPrefs::media_ffvpx_enabled()) {
540 CreateAndStartupPDM<FFVPXRuntimeLinker>();
541 }
542 #endif
543 #ifdef MOZ_FFMPEG
544 if (StaticPrefs::media_ffmpeg_enabled() &&
545 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
546 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
547 FFmpegRuntimeLinker::LinkStatusCode());
548 }
549 #endif
550 #ifdef MOZ_WIDGET_ANDROID
551 if (StaticPrefs::media_android_media_codec_enabled()) {
552 StartupPDM(AndroidDecoderModule::Create(),
553 StaticPrefs::media_android_media_codec_preferred());
554 }
555 #endif
556
557 CreateAndStartupPDM<AgnosticDecoderModule>();
558
559 if (StaticPrefs::media_gmp_decoder_enabled() &&
560 !CreateAndStartupPDM<GMPDecoderModule>()) {
561 mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
562 }
563 }
564
CreateDefaultPDMs()565 void PDMFactory::CreateDefaultPDMs() {
566 #ifdef XP_WIN
567 if (StaticPrefs::media_wmf_enabled() && !IsWin7AndPre2000Compatible()) {
568 if (!CreateAndStartupPDM<WMFDecoderModule>()) {
569 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
570 }
571 } else if (StaticPrefs::media_decoder_doctor_wmf_disabled_is_failure()) {
572 mFailureFlags += DecoderDoctorDiagnostics::Flags::WMFFailedToLoad;
573 }
574 #endif
575
576 #ifdef MOZ_APPLEMEDIA
577 CreateAndStartupPDM<AppleDecoderModule>();
578 #endif
579 #ifdef MOZ_OMX
580 if (StaticPrefs::media_omx_enabled()) {
581 CreateAndStartupPDM<OmxDecoderModule>();
582 }
583 #endif
584 #ifdef MOZ_FFVPX
585 if (StaticPrefs::media_ffvpx_enabled()) {
586 CreateAndStartupPDM<FFVPXRuntimeLinker>();
587 }
588 #endif
589 #ifdef MOZ_FFMPEG
590 if (StaticPrefs::media_ffmpeg_enabled() &&
591 !CreateAndStartupPDM<FFmpegRuntimeLinker>()) {
592 mFailureFlags += GetFailureFlagBasedOnFFmpegStatus(
593 FFmpegRuntimeLinker::LinkStatusCode());
594 }
595 #endif
596 #ifdef MOZ_WIDGET_ANDROID
597 if (StaticPrefs::media_android_media_codec_enabled()) {
598 StartupPDM(AndroidDecoderModule::Create(),
599 StaticPrefs::media_android_media_codec_preferred());
600 }
601 #endif
602
603 CreateAndStartupPDM<AgnosticDecoderModule>();
604
605 if (StaticPrefs::media_gmp_decoder_enabled() &&
606 !CreateAndStartupPDM<GMPDecoderModule>()) {
607 mFailureFlags += DecoderDoctorDiagnostics::Flags::GMPPDMFailedToStartup;
608 }
609 }
610
CreateNullPDM()611 void PDMFactory::CreateNullPDM() {
612 mNullPDM = CreateNullDecoderModule();
613 MOZ_ASSERT(mNullPDM && NS_SUCCEEDED(mNullPDM->Startup()));
614 }
615
StartupPDM(already_AddRefed<PlatformDecoderModule> aPDM,bool aInsertAtBeginning)616 bool PDMFactory::StartupPDM(already_AddRefed<PlatformDecoderModule> aPDM,
617 bool aInsertAtBeginning) {
618 RefPtr<PlatformDecoderModule> pdm = aPDM;
619 if (pdm && NS_SUCCEEDED(pdm->Startup())) {
620 if (aInsertAtBeginning) {
621 mCurrentPDMs.InsertElementAt(0, pdm);
622 } else {
623 mCurrentPDMs.AppendElement(pdm);
624 }
625 return true;
626 }
627 return false;
628 }
629
GetDecoderModule(const SupportDecoderParams & aParams,DecoderDoctorDiagnostics * aDiagnostics) const630 already_AddRefed<PlatformDecoderModule> PDMFactory::GetDecoderModule(
631 const SupportDecoderParams& aParams,
632 DecoderDoctorDiagnostics* aDiagnostics) const {
633 if (aDiagnostics) {
634 // If libraries failed to load, the following loop over mCurrentPDMs
635 // will not even try to use them. So we record failures now.
636 aDiagnostics->SetFailureFlags(mFailureFlags);
637 }
638
639 RefPtr<PlatformDecoderModule> pdm;
640 for (auto& current : mCurrentPDMs) {
641 if (current->Supports(aParams, aDiagnostics)) {
642 pdm = current;
643 break;
644 }
645 }
646 return pdm.forget();
647 }
648
SetCDMProxy(CDMProxy * aProxy)649 void PDMFactory::SetCDMProxy(CDMProxy* aProxy) {
650 MOZ_ASSERT(aProxy);
651
652 #ifdef MOZ_WIDGET_ANDROID
653 if (IsWidevineKeySystem(aProxy->KeySystem())) {
654 mEMEPDM = AndroidDecoderModule::Create(aProxy);
655 return;
656 }
657 #endif
658 auto m = MakeRefPtr<PDMFactory>();
659 mEMEPDM = MakeRefPtr<EMEDecoderModule>(aProxy, m);
660 }
661
662 /* static */
Supported(bool aForceRefresh)663 PDMFactory::MediaCodecsSupported PDMFactory::Supported(bool aForceRefresh) {
664 MOZ_ASSERT(NS_IsMainThread());
665
666 static auto calculate = []() {
667 auto pdm = MakeRefPtr<PDMFactory>();
668 MediaCodecsSupported supported;
669 // H264 and AAC depends on external framework that must be dynamically
670 // loaded.
671 // We currently only ship a single PDM per platform able to decode AAC or
672 // H264. As such we can assert that being able to create a H264 or AAC
673 // decoder indicates that with WMF on Windows or FFmpeg on Unixes is
674 // available.
675 // This logic will have to be revisited if a PDM supporting either codec
676 // will be added in addition to the WMF and FFmpeg PDM (such as OpenH264)
677 if (pdm->SupportsMimeType("video/avc"_ns)) {
678 supported += MediaCodecs::H264;
679 }
680 if (pdm->SupportsMimeType("video/vp9"_ns)) {
681 supported += MediaCodecs::VP9;
682 }
683 if (pdm->SupportsMimeType("video/vp8"_ns)) {
684 supported += MediaCodecs::VP8;
685 }
686 if (pdm->SupportsMimeType("video/av1"_ns)) {
687 supported += MediaCodecs::AV1;
688 }
689 if (pdm->SupportsMimeType("video/theora"_ns)) {
690 supported += MediaCodecs::Theora;
691 }
692 if (pdm->SupportsMimeType("audio/mp4a-latm"_ns)) {
693 supported += MediaCodecs::AAC;
694 }
695 // MP3 can be either decoded by ffvpx or WMF/FFmpeg
696 if (pdm->SupportsMimeType("audio/mpeg"_ns)) {
697 supported += MediaCodecs::MP3;
698 }
699 if (pdm->SupportsMimeType("audio/opus"_ns)) {
700 supported += MediaCodecs::Opus;
701 }
702 if (pdm->SupportsMimeType("audio/vorbis"_ns)) {
703 supported += MediaCodecs::Vorbis;
704 }
705 if (pdm->SupportsMimeType("audio/flac"_ns)) {
706 supported += MediaCodecs::Flac;
707 }
708 if (pdm->SupportsMimeType("audio/x-wav"_ns)) {
709 supported += MediaCodecs::Wave;
710 }
711 return supported;
712 };
713 static MediaCodecsSupported supported = calculate();
714 if (aForceRefresh) {
715 supported = calculate();
716 }
717 return supported;
718 }
719
720 /* static */
SupportsMimeType(const nsACString & aMimeType,const MediaCodecsSupported & aSupported)721 bool PDMFactory::SupportsMimeType(const nsACString& aMimeType,
722 const MediaCodecsSupported& aSupported) {
723 if (MP4Decoder::IsH264(aMimeType)) {
724 return aSupported.contains(MediaCodecs::H264);
725 }
726 if (VPXDecoder::IsVP9(aMimeType)) {
727 return aSupported.contains(MediaCodecs::VP9);
728 }
729 if (VPXDecoder::IsVP8(aMimeType)) {
730 return aSupported.contains(MediaCodecs::VP8);
731 }
732 #ifdef MOZ_AV1
733 if (AOMDecoder::IsAV1(aMimeType)) {
734 return aSupported.contains(MediaCodecs::AV1);
735 }
736 #endif
737 if (TheoraDecoder::IsTheora(aMimeType)) {
738 return aSupported.contains(MediaCodecs::Theora);
739 }
740 if (MP4Decoder::IsAAC(aMimeType)) {
741 return aSupported.contains(MediaCodecs::AAC);
742 }
743 if (aMimeType.EqualsLiteral("audio/mpeg")) {
744 return aSupported.contains(MediaCodecs::MP3);
745 }
746 if (OpusDataDecoder::IsOpus(aMimeType)) {
747 return aSupported.contains(MediaCodecs::Opus);
748 }
749 if (VorbisDataDecoder::IsVorbis(aMimeType)) {
750 return aSupported.contains(MediaCodecs::Vorbis);
751 }
752 if (aMimeType.EqualsLiteral("audio/flac")) {
753 return aSupported.contains(MediaCodecs::Flac);
754 }
755 if (WaveDataDecoder::IsWave(aMimeType)) {
756 return aSupported.contains(MediaCodecs::Wave);
757 }
758 return false;
759 }
760
761 /* static */
AllDecodersAreRemote()762 bool PDMFactory::AllDecodersAreRemote() {
763 return StaticPrefs::media_rdd_process_enabled() &&
764 #if defined(MOZ_FFVPX)
765 StaticPrefs::media_rdd_ffvpx_enabled() &&
766 #endif
767 StaticPrefs::media_rdd_opus_enabled() &&
768 StaticPrefs::media_rdd_theora_enabled() &&
769 StaticPrefs::media_rdd_vorbis_enabled() &&
770 StaticPrefs::media_rdd_vpx_enabled() &&
771 #if defined(MOZ_WMF)
772 StaticPrefs::media_rdd_wmf_enabled() &&
773 #endif
774 StaticPrefs::media_rdd_wav_enabled();
775 }
776
777 #undef PDM_INIT_LOG
778 } // namespace mozilla
779