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
This commit is contained in:
Gerald Squelart 2016-04-19 17:36:20 +10:00
Родитель e6882cd324
Коммит 5d11be9eef
4 изменённых файлов: 58 добавлений и 8 удалений

Просмотреть файл

@ -290,7 +290,12 @@ DecoderDoctorDocumentWatcher::ReportAnalysis(
params, params,
ArrayLength(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 void
@ -299,11 +304,19 @@ DecoderDoctorDocumentWatcher::SynthesizeAnalysis()
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
bool canPlay = false; bool canPlay = false;
#if defined(MOZ_FFMPEG)
bool PlatformDecoderNeeded = false;
#endif
nsAutoString formats; nsAutoString formats;
for (auto& diag : mDiagnosticsSequence) { for (auto& diag : mDiagnosticsSequence) {
if (diag.mDecoderDoctorDiagnostics.CanPlay()) { if (diag.mDecoderDoctorDiagnostics.CanPlay()) {
canPlay = true; canPlay = true;
} else { } else {
#if defined(MOZ_FFMPEG)
if (diag.mDecoderDoctorDiagnostics.DidFFmpegFailToLoad()) {
PlatformDecoderNeeded = true;
}
#endif
if (!formats.IsEmpty()) { if (!formats.IsEmpty()) {
formats += NS_LITERAL_STRING(", "); formats += NS_LITERAL_STRING(", ");
} }
@ -311,10 +324,20 @@ DecoderDoctorDocumentWatcher::SynthesizeAnalysis()
} }
} }
if (!canPlay) { if (!canPlay) {
DD_WARN("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Cannot play media, formats: %s", #if defined(MOZ_FFMPEG)
this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); if (PlatformDecoderNeeded) {
ReportAnalysis(dom::DecoderDoctorNotificationType::Cannot_play, DD_DEBUG("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - formats: %s -> Cannot play media because platform decoder was not found",
"MediaCannotPlayNoDecoders", formats); 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()) { } else if (!formats.IsEmpty()) {
DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Can play media, but no decoders for some requested formats: %s", DD_INFO("DecoderDoctorDocumentWatcher[%p, doc=%p]::Notify() - Can play media, but no decoders for some requested formats: %s",
this, mDocument, NS_ConvertUTF16toUTF8(formats).get()); this, mDocument, NS_ConvertUTF16toUTF8(formats).get());
@ -340,9 +363,9 @@ DecoderDoctorDocumentWatcher::AddDiagnostics(const nsAString& aFormat,
return; 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(), this, mDocument, NS_ConvertUTF16toUTF8(aFormat).get(),
aCallSite, aDiagnostics.CanPlay()); aCallSite, aDiagnostics.CanPlay(), aDiagnostics.DidFFmpegFailToLoad());
mDiagnosticsSequence.AppendElement( mDiagnosticsSequence.AppendElement(
Diagnostics(Move(aDiagnostics), aFormat, aCallSite)); Diagnostics(Move(aDiagnostics), aFormat, aCallSite));
EnsureTimerIsStarted(); EnsureTimerIsStarted();

Просмотреть файл

@ -44,9 +44,14 @@ public:
void SetCanPlay() { mCanPlay = true; } void SetCanPlay() { mCanPlay = true; }
bool CanPlay() const { return mCanPlay; } bool CanPlay() const { return mCanPlay; }
void SetFFmpegFailedToLoad() { mFFmpegFailedToLoad = true; }
bool DidFFmpegFailToLoad() const { return mFFmpegFailedToLoad; }
private: private:
// True if there is at least one decoder that can play the media. // True if there is at least one decoder that can play the media.
bool mCanPlay = false; bool mCanPlay = false;
bool mFFmpegFailedToLoad = false;
}; };
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -42,6 +42,8 @@
#include "mozilla/CDMProxy.h" #include "mozilla/CDMProxy.h"
#endif #endif
#include "DecoderDoctorDiagnostics.h"
namespace mozilla { namespace mozilla {
extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule(); extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule();
@ -160,6 +162,14 @@ PDMFactory::CreateDecoder(const TrackInfo& aConfig,
aImageContainer); 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) { for (auto& current : mCurrentPDMs) {
if (!current->SupportsMimeType(aConfig.mMimeType, aDiagnostics)) { if (!current->SupportsMimeType(aConfig.mMimeType, aDiagnostics)) {
continue; continue;
@ -292,7 +302,9 @@ PDMFactory::CreatePDMs()
#ifdef MOZ_FFMPEG #ifdef MOZ_FFMPEG
if (sFFmpegDecoderEnabled) { if (sFFmpegDecoderEnabled) {
m = FFmpegRuntimeLinker::CreateDecoderModule(); m = FFmpegRuntimeLinker::CreateDecoderModule();
StartupPDM(m); if (!StartupPDM(m)) {
mFFmpegFailedToLoad = true;
}
} }
#endif #endif
#ifdef MOZ_APPLEMEDIA #ifdef MOZ_APPLEMEDIA
@ -335,6 +347,14 @@ already_AddRefed<PlatformDecoderModule>
PDMFactory::GetDecoder(const nsACString& aMimeType, PDMFactory::GetDecoder(const nsACString& aMimeType,
DecoderDoctorDiagnostics* aDiagnostics) const 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<PlatformDecoderModule> pdm; RefPtr<PlatformDecoderModule> pdm;
for (auto& current : mCurrentPDMs) { for (auto& current : mCurrentPDMs) {
if (current->SupportsMimeType(aMimeType, aDiagnostics)) { if (current->SupportsMimeType(aMimeType, aDiagnostics)) {

Просмотреть файл

@ -94,6 +94,8 @@ private:
nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs; nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs;
RefPtr<PlatformDecoderModule> mEMEPDM; RefPtr<PlatformDecoderModule> mEMEPDM;
bool mFFmpegFailedToLoad = false;
}; };
} // namespace mozilla } // namespace mozilla