Bug 1195723: [ogg] P2. Refactor mimetype parsing for ogg. r?kamidphish draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 04 Aug 2016 17:14:28 +1000
changeset 404111 d88bfebd53174ad8cd95ed78e9da52cc7828153e
parent 404110 0b6231660e489f7966e001d50e48d58ec5705dba
child 404112 4b81c49f90233885c494df0e3c6bcf244532a1b6
push id27118
push userbmo:jyavenard@mozilla.com
push dateMon, 22 Aug 2016 22:58:57 +0000
reviewerskamidphish
bugs1195723
milestone51.0a1
Bug 1195723: [ogg] P2. Refactor mimetype parsing for ogg. r?kamidphish Make it just like MP4, WebM and all the others new demuxers. Additionally, make the ogg related preferences part of MediaPrefs. MozReview-Commit-ID: DTedHyIMv9I
dom/media/DecoderTraits.cpp
dom/media/MediaPrefs.h
dom/media/ogg/OggDecoder.cpp
dom/media/ogg/OggDecoder.h
--- a/dom/media/DecoderTraits.cpp
+++ b/dom/media/DecoderTraits.cpp
@@ -49,16 +49,17 @@
 #include "WaveDecoder.h"
 #include "WaveDemuxer.h"
 #include "WaveReader.h"
 
 #include "ADTSDecoder.h"
 #include "ADTSDemuxer.h"
 
 #include "nsPluginHost.h"
+#include "MediaPrefs.h"
 
 namespace mozilla
 {
 
 template <class String>
 static bool
 CodecListContains(char const *const * aCodecs, const String& aCodec)
 {
@@ -86,46 +87,27 @@ IsRawType(const nsACString& aType)
   if (!MediaDecoder::IsRawEnabled()) {
     return false;
   }
 
   return CodecListContains(gRawTypes, aType);
 }
 #endif
 
-// See http://www.rfc-editor.org/rfc/rfc5334.txt for the definitions
-// of Ogg media types and codec types
-static const char* const gOggTypes[4] = {
-  "video/ogg",
-  "audio/ogg",
-  "application/ogg",
-  nullptr
-};
-
-static char const *const gOggCodecs[3] = {
-  "vorbis",
-  "theora",
-  nullptr
-};
-
-static char const *const gOggCodecsWithOpus[4] = {
-  "vorbis",
-  "opus",
-  "theora",
-  nullptr
-};
+static bool
+IsOggSupportedType(const nsACString& aType,
+                    const nsAString& aCodecs = EmptyString())
+{
+  return OggDecoder::CanHandleMediaType(aType, aCodecs);
+}
 
 static bool
-IsOggType(const nsACString& aType)
+IsOggTypeAndEnabled(const nsACString& aType)
 {
-  if (!MediaDecoder::IsOggEnabled()) {
-    return false;
-  }
-
-  return CodecListContains(gOggTypes, aType);
+  return IsOggSupportedType(aType);
 }
 
 // See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
 // of WAVE media types and codec types. However, the audio/vnd.wave
 // MIME type described there is not used.
 static const char* const gWaveTypes[5] = {
   "audio/x-wav",
   "audio/wav",
@@ -373,18 +355,24 @@ DecoderTraits::CanHandleCodecsType(const
                                    DecoderDoctorDiagnostics* aDiagnostics)
 {
   char const* const* codecList = nullptr;
 #ifdef MOZ_RAW
   if (IsRawType(nsDependentCString(aMIMEType))) {
     codecList = gRawCodecs;
   }
 #endif
-  if (IsOggType(nsDependentCString(aMIMEType))) {
-    codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
+  if (IsOggTypeAndEnabled(nsDependentCString(aMIMEType))) {
+    if (IsOggSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
+      return CANPLAY_YES;
+    } else {
+      // We can only reach this position if a particular codec was requested,
+      // ogg is supported and working: the codec must be invalid.
+      return CANPLAY_NO;
+    }
   }
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     codecList = gWaveCodecs;
   }
 #if !defined(MOZ_OMX_WEBM_DECODER)
   if (IsWebMTypeAndEnabled(nsDependentCString(aMIMEType))) {
     if (IsWebMSupportedType(nsDependentCString(aMIMEType), aRequestedCodecs)) {
       return CANPLAY_YES;
@@ -480,17 +468,17 @@ DecoderTraits::CanHandleMediaType(const 
       return result;
     }
   }
 #ifdef MOZ_RAW
   if (IsRawType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
 #endif
-  if (IsOggType(nsDependentCString(aMIMEType))) {
+  if (IsOggTypeAndEnabled(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
   if (IsWaveType(nsDependentCString(aMIMEType))) {
     return CANPLAY_MAYBE;
   }
   if (IsMP4TypeAndEnabled(nsDependentCString(aMIMEType), aDiagnostics)) {
     return CANPLAY_MAYBE;
   }
@@ -549,17 +537,17 @@ InstantiateDecoder(const nsACString& aTy
     return decoder.forget();
   }
 #ifdef MOZ_RAW
   if (IsRawType(aType)) {
     decoder = new RawDecoder(aOwner);
     return decoder.forget();
   }
 #endif
-  if (IsOggType(aType)) {
+  if (IsOggSupportedType(aType)) {
     decoder = new OggDecoder(aOwner);
     return decoder.forget();
   }
   if (IsWaveType(aType)) {
     decoder = new WaveDecoder(aOwner);
     return decoder.forget();
   }
 #ifdef MOZ_OMX_DECODER
@@ -646,18 +634,18 @@ MediaDecoderReader* DecoderTraits::Creat
   if (IsWAVSupportedType(aType)) {
     decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
   } else
 #ifdef MOZ_RAW
   if (IsRawType(aType)) {
     decoderReader = new RawReader(aDecoder);
   } else
 #endif
-  if (IsOggType(aType)) {
-    decoderReader = Preferences::GetBool("media.format-reader.ogg", true) ?
+  if (IsOggSupportedType(aType)) {
+    decoderReader = MediaPrefs::OggFormatReader() ?
       static_cast<MediaDecoderReader*>(new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()))) :
       new OggReader(aDecoder);
   } else
   if (IsWaveType(aType)) {
     decoderReader = new WaveReader(aDecoder);
   } else
 #ifdef MOZ_OMX_DECODER
   if (IsOmxSupportedType(aType)) {
@@ -691,17 +679,17 @@ bool DecoderTraits::IsSupportedInVideoDo
   // not to, using either the legacy WMF specific pref, or the newer
   // catch-all pref.
   if (!Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true) ||
       !Preferences::GetBool("media.play-stand-alone", true)) {
     return false;
   }
 
   return
-    IsOggType(aType) ||
+    IsOggSupportedType(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
     IsWebMSupportedType(aType) ||
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -139,16 +139,21 @@ private:
   DECL_MEDIA_PREF("media.webspeech.test.fake_fsm_events",     WebSpeechFakeFSMEvents, bool, false);
   DECL_MEDIA_PREF(TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE,   WebSpeechFakeRecognitionService, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.enable",       WebSpeechRecognitionEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.force_enable", WebSpeechRecognitionForceEnabled, bool, false);
 
   DECL_MEDIA_PREF("media.num-decode-threads",                 MediaThreadPoolDefaultCount, uint32_t, 4);
   DECL_MEDIA_PREF("media.decoder.limit",                      MediaDecoderLimit, int32_t, MediaDecoderLimitDefault());
 
+  // Ogg
+  DECL_MEDIA_PREF("media.ogg.enabled",                        OggEnabled, bool, true);
+  DECL_MEDIA_PREF("media.format-reader.ogg",                  OggFormatReader, bool, true);
+  DECL_MEDIA_PREF("media.ogg.flac.enabled",                   FlacInOgg, bool, false);
+
 public:
   // Manage the singleton:
   static MediaPrefs& GetSingleton();
   static bool SingletonExists();
 
 private:
   template<class T> friend class StaticAutoPtr;
   static StaticAutoPtr<MediaPrefs> sInstance;
--- a/dom/media/ogg/OggDecoder.cpp
+++ b/dom/media/ogg/OggDecoder.cpp
@@ -1,32 +1,86 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/Preferences.h"
+#include "MediaPrefs.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaFormatReader.h"
 #include "OggDemuxer.h"
 #include "OggReader.h"
 #include "OggDecoder.h"
+#include "nsContentTypeParser.h"
 
 namespace mozilla {
 
 MediaDecoderStateMachine* OggDecoder::CreateStateMachine()
 {
-  bool useFormatDecoder =
-    Preferences::GetBool("media.format-reader.ogg", true);
+  bool useFormatDecoder = MediaPrefs::OggFormatReader();
   RefPtr<OggDemuxer> demuxer =
     useFormatDecoder ? new OggDemuxer(GetResource()) : nullptr;
   RefPtr<MediaDecoderReader> reader = useFormatDecoder
     ? static_cast<MediaDecoderReader*>(new MediaFormatReader(this, demuxer, GetVideoFrameContainer()))
     : new OggReader(this);
   if (useFormatDecoder) {
     demuxer->SetChainingEvents(&reader->TimedMetadataProducer(),
                                &reader->MediaNotSeekableProducer());
   }
   return new MediaDecoderStateMachine(this, reader);
 }
 
+/* static */
+bool
+OggDecoder::IsEnabled()
+{
+  return MediaPrefs::OggEnabled();
+}
+
+/* static */
+bool
+OggDecoder::CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                               const nsAString& aCodecs)
+{
+  if (!IsEnabled()) {
+    return false;
+  }
+
+  const bool isOggAudio = aMIMETypeExcludingCodecs.EqualsASCII("audio/ogg");
+  const bool isOggVideo =
+    aMIMETypeExcludingCodecs.EqualsASCII("video/ogg") ||
+    aMIMETypeExcludingCodecs.EqualsASCII("application/ogg");
+
+  if (!isOggAudio && !isOggVideo) {
+    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 ((IsOpusEnabled() && codec.EqualsLiteral("opus")) ||
+        codec.EqualsLiteral("vorbis")) {
+      continue;
+    }
+    // Note: Only accept Theora in a video content type, not in an audio
+    // content type.
+    if (isOggVideo && codec.EqualsLiteral("theora")) {
+      continue;
+    }
+    // Some unsupported codec.
+    return false;
+  }
+  return true;
+}
+
+
+
 } // namespace mozilla
--- a/dom/media/ogg/OggDecoder.h
+++ b/dom/media/ogg/OggDecoder.h
@@ -32,16 +32,24 @@ public:
   // protect the general state with a lock, so we make a special copy and a
   // special-purpose lock. This method may be called on any thread.
   bool IsOggDecoderShutdown() override
   {
     MonitorAutoLock lock(mShutdownBitMonitor);
     return mShutdownBit;
   }
 
+  // Returns true if aMIMEType is a type that we think we can render with the
+  // a platform decoder backend. If aCodecs is non emtpy, it is filled
+  // with a comma-delimited list of codecs to check support for.
+  static bool CanHandleMediaType(const nsACString& aMIMETypeExcludingCodecs,
+                                 const nsAString& aCodecs);
+
+  static bool IsEnabled();
+
 protected:
   void ShutdownBitChanged() override
   {
     MonitorAutoLock lock(mShutdownBitMonitor);
     mShutdownBit = mStateMachineIsShutdown;
   }
 
   Monitor mShutdownBitMonitor;