Bug 1191833: P1. Properly check webm mimetype against codec type. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 03 Dec 2015 17:36:36 +1100
changeset 275587 f23035b9e6bd5ef0bf0be87f96c4c2b9b7417908
parent 275586 0ea205e989559a0e791a9fdaef35146739466cde
child 275588 60230ebb71eb8a238237491271dce0d02ed2a3bb
push id68884
push userjyavenard@mozilla.com
push dateFri, 04 Dec 2015 03:44:44 +0000
treeherdermozilla-inbound@3021d7cf0c80 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1191833
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1191833: P1. Properly check webm mimetype against codec type. r=cpearce Also move the logic inside WebMDecoder, this continue on with the logic used by MP4Decoder
dom/media/DecoderTraits.cpp
dom/media/webm/WebMDecoder.cpp
dom/media/webm/WebMDecoder.h
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -149,42 +149,29 @@ IsWaveType(const nsACString& aType)
     return false;
   }
 
   return CodecListContains(gWaveTypes, aType);
 }
 #endif
 
 #ifdef MOZ_WEBM
-static const char* const gWebMTypes[3] = {
-  "video/webm",
-  "audio/webm",
-  nullptr
-};
-
-static char const *const gWebMCodecs[7] = {
-  "vp8",
-  "vp8.0",
-  "vp9",
-  "vp9.0",
-  "vorbis",
-  "opus",
-  nullptr
-};
+static bool
+IsWebMSupportedType(const nsACString& aType,
+                    const nsAString& aCodecs = EmptyString())
+{
+  return WebMDecoder::CanHandleMediaType(aType, aCodecs);
+}
 #endif
 
 /* static */ bool
 DecoderTraits::IsWebMTypeAndEnabled(const nsACString& aType)
 {
 #ifdef MOZ_WEBM
-  if (!MediaDecoder::IsWebMEnabled()) {
-    return false;
-  }
-
-  return CodecListContains(gWebMTypes, aType);
+  return IsWebMSupportedType(aType);
 #endif
   return false;
 }
 
 #ifdef MOZ_GSTREAMER
 static bool
 IsGStreamerSupportedType(const nsACString& aMimeType)
 {
@@ -390,17 +377,23 @@ DecoderTraits::CanHandleCodecsType(const
   }
 #ifdef MOZ_WAVE
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     codecList = gWaveCodecs;
   }
 #endif
 #if !defined(MOZ_OMX_WEBM_DECODER)
   if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
-    codecList = gWebMCodecs;
+    if (IsWebMSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
+      return CANPLAY_YES;
+    } else {
+      // We can only reach this position if a particular codec was requested,
+      // webm is supported and working: the codec must be invalid.
+      return CANPLAY_NO;
+    }
   }
 #endif
 #ifdef MOZ_FMP4
   if (IsMP4TypeAndEnabled(nsDependentCString(aMIMEType))) {
     if (IsMP4SupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
       return CANPLAY_YES;
     } else {
       // We can only reach this position if a particular codec was requested,
@@ -596,20 +589,22 @@ InstantiateDecoder(const nsACString& aTy
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoder = new AndroidMediaDecoder(aOwner, aType);
     return decoder.forget();
   }
 #endif
-  if (DecoderTraits::IsWebMTypeAndEnabled(aType)) {
+#ifdef MOZ_WEBM
+  if (IsWebMSupportedType(aType)) {
     decoder = new WebMDecoder(aOwner);
     return decoder.forget();
   }
+#endif
 #ifdef MOZ_DIRECTSHOW
   // Note: DirectShow should come before WMF, so that we prefer DirectShow's
   // MP3 support over WMF's.
   if (IsDirectShowSupportedType(aType)) {
     decoder = new DirectShowDecoder(aOwner);
     return decoder.forget();
   }
 #endif
@@ -666,21 +661,23 @@ MediaDecoderReader* DecoderTraits::Creat
   } else
 #endif
 #ifdef MOZ_ANDROID_OMX
   if (MediaDecoder::IsAndroidMediaEnabled() &&
       EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
     decoderReader = new AndroidMediaReader(aDecoder, aType);
   } else
 #endif
-  if (IsWebMTypeAndEnabled(aType)) {
+#ifdef MOZ_WEBM
+  if (IsWebMSupportedType(aType)) {
     decoderReader = Preferences::GetBool("media.format-reader.webm", true) ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()))) :
       new WebMReader(aDecoder);
   } else
+#endif
 #ifdef MOZ_DIRECTSHOW
   if (IsDirectShowSupportedType(aType)) {
     decoderReader = new DirectShowReader(aDecoder);
   } else
 #endif
   if (false) {} // dummy if to take care of the dangling else
 
   return decoderReader;
@@ -701,17 +698,19 @@ bool DecoderTraits::IsSupportedInVideoDo
     IsOggType(aType) ||
 #ifdef MOZ_OMX_DECODER
     // We support the formats in gB2GOnlyTypes only inside WebApps on firefoxOS
     // but not in general web content. Ensure we dont create a VideoDocument
     // when accessing those format URLs directly.
     (IsOmxSupportedType(aType) &&
      !IsB2GSupportOnlyType(aType)) ||
 #endif
-    IsWebMTypeAndEnabled(aType) ||
+#ifdef MOZ_WEBM
+    IsWebMSupportedType(aType) ||
+#endif
 #ifdef MOZ_GSTREAMER
     IsGStreamerSupportedType(aType) ||
 #endif
 #ifdef MOZ_ANDROID_OMX
     (MediaDecoder::IsAndroidMediaEnabled() && IsAndroidMediaType(aType)) ||
 #endif
 #ifdef MOZ_FMP4
     IsMP4SupportedType(aType) ||
--- a/dom/media/webm/WebMDecoder.cpp
+++ b/dom/media/webm/WebMDecoder.cpp
@@ -5,23 +5,75 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Preferences.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaFormatReader.h"
 #include "WebMDemuxer.h"
 #include "WebMReader.h"
 #include "WebMDecoder.h"
+#include "VideoUtils.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* WebMDecoder::CreateStateMachine()
 {
   bool useFormatDecoder =
     Preferences::GetBool("media.format-reader.webm", true);
   RefPtr<MediaDecoderReader> reader = useFormatDecoder ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(this, new WebMDemuxer(GetResource()), GetVideoFrameContainer())) :
       new WebMReader(this);
   return new MediaDecoderStateMachine(this, reader);
 }
 
+/* static */
+bool
+WebMDecoder::IsEnabled()
+{
+  return Preferences::GetBool("media.webm.enabled");
+}
+
+/* static */
+bool
+WebMDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                                const nsAString& aCodecs)
+{
+  if (!IsEnabled()) {
+    return false;
+  }
+
+  const bool isWebMAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/webm");
+  const bool isWebMVideo = aMIMETypeExcludingCodecs.EqualsASCII("video/webm");
+  if (!isWebMAudio && !isWebMVideo) {
+    return false;
+  }
+
+  nsTArray<nsCString> codecMimes;
+  if (aCodecs.IsEmpty()) {
+    // WebM guarantees that the only codecs it contained are vp8, vp9, opus or vorbis.
+    return true;
+  }
+  // Verify that all the codecs specified are ones that we expect that
+  // we can play.
+  nsTArray<nsString> codecs;
+  if (!ParseCodecsString(aCodecs, codecs)) {
+    return false;
+  }
+  for (const nsString& codec : codecs) {
+    if (codec.EqualsLiteral("opus") || codec.EqualsLiteral("vorbis")) {
+      continue;
+    }
+    // Note: Only accept VP8/VP9 in a video content type, not in an audio
+    // content type.
+    if (isWebMVideo &&
+        (codec.EqualsLiteral("vp8") || codec.EqualsLiteral("vp8.0") ||
+         codec.EqualsLiteral("vp9") || codec.EqualsLiteral("vp9.0"))) {
+
+      continue;
+    }
+    // Some unsupported codec.
+    return false;
+  }
+  return true;
+}
+
 } // namespace mozilla
 
--- a/dom/media/webm/WebMDecoder.h
+++ b/dom/media/webm/WebMDecoder.h
@@ -16,13 +16,23 @@ public:
   explicit WebMDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
   virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
     if (!IsWebMEnabled()) {
       return nullptr;
     }
     return new WebMDecoder(aOwner);
   }
   virtual MediaDecoderStateMachine* CreateStateMachine();
+
+  // Returns true if the WebM backend is preffed on.
+  static bool IsEnabled();
+
+  // Returns true if aMIMEType is a type that we think we can render with the
+  // a WebM platform decoder backend. If aCodecs is non emtpy, it is filled
+  // with a comma-delimited list of codecs to check support for. Notes in
+  // out params whether the codecs string contains Opus/Vorbis or VP8/VP9.
+  static bool CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                                 const nsAString& aCodecs);
 };
 
 } // namespace mozilla
 
 #endif