From 5d11be9eef0be8c876159a9172be72d3f70a899e Mon Sep 17 00:00:00 2001 From: Gerald Squelart Date: Tue, 19 Apr 2016 17:36:20 +1000 Subject: [PATCH] Bug 1248507 - p10. Detect and report when FFMpeg/Linux fails to load - r=jya If the FFmpeg decoder module cannot be started, the failure is recorded in the DecoderDoctorDiagnostics structure. In this case, on Linux if there are no suitable decoders for any requested format, a "platform decoder not found" notification is sent to Chrome (a separate bug will implement the actual front-end notification), and logged to the web console. Note: All front-end notifications (that could display a notification bar) are currently disabled by default. Set the following pref to true to enable them: "media.decoderdoctor.enable-notification-bar". MozReview-Commit-ID: CdaX7QUdWtd --- dom/media/DecoderDoctorDiagnostics.cpp | 37 +++++++++++++++++++++----- dom/media/DecoderDoctorDiagnostics.h | 5 ++++ dom/media/platforms/PDMFactory.cpp | 22 ++++++++++++++- dom/media/platforms/PDMFactory.h | 2 ++ 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/dom/media/DecoderDoctorDiagnostics.cpp b/dom/media/DecoderDoctorDiagnostics.cpp index 0c3ff55fa5e9..3d247ee8ae5b 100644 --- a/dom/media/DecoderDoctorDiagnostics.cpp +++ b/dom/media/DecoderDoctorDiagnostics.cpp @@ -290,7 +290,12 @@ DecoderDoctorDocumentWatcher::ReportAnalysis( params, ArrayLength(params)); - DispatchNotification(mDocument->GetInnerWindow(), aNotificationType, aFormats); + // For now, disable all front-end notifications by default. + // TODO: Future bugs will use finer-grained filtering instead. + if (Preferences::GetBool("media.decoderdoctor.enable-notification-bar", false)) { + DispatchNotification( + mDocument->GetInnerWindow(), aNotificationType, aFormats); + } } void @@ -299,11 +304,19 @@ DecoderDoctorDocumentWatcher::SynthesizeAnalysis() MOZ_ASSERT(NS_IsMainThread()); bool canPlay = false; +#if defined(MOZ_FFMPEG) + bool PlatformDecoderNeeded = false; +#endif nsAutoString formats; for (auto& diag : mDiagnosticsSequence) { if (diag.mDecoderDoctorDiagnostics.CanPlay()) { canPlay = true; } else { +#if defined(MOZ_FFMPEG) + if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) { + PlatformDecoderNeeded = true; + } +#endif if (!formats.IsEmpty()) { formats += NS_LITERAL_STRING(", "); } @@ -311,10 +324,20 @@ DecoderDoctorDocumentWatcher::SynthesizeAnalysis() } } if (!canPlay) { - DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Cannot play media, formats: %s", - this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); - ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play, - "MediaCannotPlayNoDecoders", formats); +#if defined(MOZ_FFMPEG) + if (PlatformDecoderNeeded) { + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - formats: %s -> Cannot play media because platform decoder was not found", + this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); + ReportAnalysis(dom::DecoderDoctorNotificationType::Platform_decoder_not_found, + "MediaPlatformDecoderNotFound", formats); + } else +#endif + { + DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Cannot play media, formats: %s", + this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); + ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play, + "MediaCannotPlayNoDecoders", formats); + } } else if (!formats.IsEmpty()) { DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Can play media, but no decoders for some requested formats: %s", this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); @@ -340,9 +363,9 @@ DecoderDoctorDocumentWatcher::AddDiagnostics(const nsAString& aFormat, return; } - DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::AddDiagnostics(format='%s', call site '%s', can play=%d)", + DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::AddDiagnostics(format='%s', call site '%s', can play=%d, platform lib failed to load=%d)", this, mDocument, NS_ConvertUTF16toUTF8(aFormat).get(), - aCallSite, aDiagnostics.CanPlay()); + aCallSite, aDiagnostics.CanPlay(), aDiagnostics.DidFFmpegFailToLoad()); mDiagnosticsSequence.AppendElement( Diagnostics(Move(aDiagnostics), aFormat, aCallSite)); EnsureTimerIsStarted(); diff --git a/dom/media/DecoderDoctorDiagnostics.h b/dom/media/DecoderDoctorDiagnostics.h index cffb8d01dd91..b2e9347af3b1 100644 --- a/dom/media/DecoderDoctorDiagnostics.h +++ b/dom/media/DecoderDoctorDiagnostics.h @@ -44,9 +44,14 @@ public: void SetCanPlay() { mCanPlay = true; } bool CanPlay() const { return mCanPlay; } + void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; } + bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; } + private: // True if there is at least one decoder that can play the media. bool mCanPlay = false; + + bool mFFmpegFailedToLoad = false; }; } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index f363d4669940..b32b0d4043d2 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -42,6 +42,8 @@ #include "mozilla/CDMProxy.h" #endif +#include "DecoderDoctorDiagnostics.h" + namespace mozilla { extern already_AddRefed CreateAgnosticDecoderModule(); @@ -160,6 +162,14 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig, aImageContainer); } + if (aDiagnostics) { + // If libraries failed to load, the following loop over mCurrentPDMs + // will not even try to use them. So we record failures now. + if (mFFmpegFailedToLoad) { + aDiagnostics->SetFFmpegFailedToLoad(); + } + } + for (auto& current : mCurrentPDMs) { if (!current->SupportsMimeType(aConfig.mMimeType, aDiagnostics)) { continue; @@ -292,7 +302,9 @@ PDMFactory::CreatePDMs() #ifdef MOZ_FFMPEG if (sFFmpegDecoderEnabled) { m = FFmpegRuntimeLinker::CreateDecoderModule(); - StartupPDM(m); + if (!StartupPDM(m)) { + mFFmpegFailedToLoad = true; + } } #endif #ifdef MOZ_APPLEMEDIA @@ -335,6 +347,14 @@ already_AddRefed PDMFactory::GetDecoder(const nsACString& aMimeType, 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. + if (mFFmpegFailedToLoad) { + aDiagnostics->SetFFmpegFailedToLoad(); + } + } + RefPtr pdm; for (auto& current : mCurrentPDMs) { if (current->SupportsMimeType(aMimeType, aDiagnostics)) { diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 3c433c0b2870..b4048614837d 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -94,6 +94,8 @@ private: nsTArray> mCurrentPDMs; RefPtr mEMEPDM; + + bool mFFmpegFailedToLoad = false; }; } // namespace mozilla