mozilla-gstreamer-760140.patch
changeset 529 4812378b5646
child 541 830e50bbfc79
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mozilla-gstreamer-760140.patch	Mon Aug 20 08:55:43 2012 +0200
@@ -0,0 +1,566 @@
+From: Alessandro Decina <alessandro.d@gmail.com>
+Bug 760140 - Query the GstRegistry for the required demuxers/decoders from canPlayType
+
+diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp
+--- a/content/base/src/nsContentUtils.cpp
++++ b/content/base/src/nsContentUtils.cpp
+@@ -137,16 +137,19 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
+ #include "xpcprivate.h" // nsXPConnect
+ #include "nsScriptSecurityManager.h"
+ #include "nsIChannelPolicy.h"
+ #include "nsChannelPolicy.h"
+ #include "nsIContentSecurityPolicy.h"
+ #include "nsContentDLF.h"
+ #ifdef MOZ_MEDIA
+ #include "nsHTMLMediaElement.h"
++#ifdef MOZ_GSTREAMER
++#include "nsGStreamerDecoder.h"
++#endif
+ #endif
+ #include "nsDOMTouchEvent.h"
+ #include "nsIContentViewer.h"
+ #include "nsIObjectLoadingContent.h"
+ #include "nsCCUncollectableMarker.h"
+ #include "mozilla/Base64.h"
+ #include "mozilla/Preferences.h"
+ #include "nsDOMMutationObserver.h"
+@@ -6511,26 +6514,23 @@ nsContentUtils::FindInternalContentViewe
+         }
+         return docFactory.forget();
+       }
+     }
+   }
+ #endif
+ 
+ #ifdef MOZ_GSTREAMER
+-  if (nsHTMLMediaElement::IsH264Enabled()) {
+-    for (unsigned int i = 0; i < ArrayLength(nsHTMLMediaElement::gH264Types); ++i) {
+-      const char* type = nsHTMLMediaElement::gH264Types[i];
+-      if (!strcmp(aType, type)) {
+-        docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
+-        if (docFactory && aLoaderType) {
+-          *aLoaderType = TYPE_CONTENT;
+-        }
+-        return docFactory.forget();
++  if (nsHTMLMediaElement::IsGStreamerEnabled()) {
++    if (nsGStreamerDecoder::CanHandleMediaType(aType, NULL)) {
++      docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
++      if (docFactory && aLoaderType) {
++        *aLoaderType = TYPE_CONTENT;
+       }
++      return docFactory.forget();
+     }
+   }
+ #endif
+ #endif // MOZ_MEDIA
+ 
+   return NULL;
+ }
+ 
+diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h
+--- a/content/html/content/public/nsHTMLMediaElement.h
++++ b/content/html/content/public/nsHTMLMediaElement.h
+@@ -250,17 +250,19 @@ public:
+   void UpdateMediaSize(nsIntSize size);
+ 
+   // Returns the CanPlayStatus indicating if we can handle this
+   // MIME type. The MIME type should not include the codecs parameter.
+   // If it returns anything other than CANPLAY_NO then it also
+   // returns a null-terminated list of supported codecs
+   // in *aSupportedCodecs. This list should not be freed, it is static data.
+   static CanPlayStatus CanHandleMediaType(const char* aMIMEType,
+-                                          char const *const ** aSupportedCodecs);
++                                          const char* aCodecs,
++                                          char const *const ** aSupportedCodecs,
++                                          bool* aCheckSupportedCodecs);
+ 
+   // Returns the CanPlayStatus indicating if we can handle the
+   // full MIME type including the optional codecs parameter.
+   static CanPlayStatus GetCanPlay(const nsAString& aType);
+ 
+   // Returns true if we should handle this MIME type when it appears
+   // as an <object> or as a toplevel page. If, in practice, our support
+   // for the type is more limited than appears in the wild, we should return
+@@ -290,20 +292,17 @@ public:
+ #ifdef MOZ_WEBM
+   static bool IsWebMEnabled();
+   static bool IsWebMType(const nsACString& aType);
+   static const char gWebMTypes[2][17];
+   static char const *const gWebMCodecs[4];
+ #endif
+ 
+ #ifdef MOZ_GSTREAMER
+-  static bool IsH264Enabled();
+-  static bool IsH264Type(const nsACString& aType);
+-  static const char gH264Types[3][17];
+-  static char const *const gH264Codecs[7];
++  static bool IsGStreamerEnabled();
+ #endif
+ 
+ #ifdef MOZ_MEDIA_PLUGINS
+   static bool IsMediaPluginsEnabled();
+   static bool IsMediaPluginsType(const nsACString& aType);
+ #endif
+ 
+   /**
+diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp
+--- a/content/html/content/src/nsHTMLMediaElement.cpp
++++ b/content/html/content/src/nsHTMLMediaElement.cpp
+@@ -2070,68 +2070,40 @@ nsHTMLMediaElement::IsWebMType(const nsA
+     }
+   }
+ 
+   return false;
+ }
+ #endif
+ 
+ #ifdef MOZ_GSTREAMER
+-const char nsHTMLMediaElement::gH264Types[3][17] = {
+-  "video/mp4",
+-  "video/3gpp",
+-  "video/quicktime",
+-};
+-
+-char const *const nsHTMLMediaElement::gH264Codecs[7] = {
+-  "avc1.42E01E",
+-  "avc1.42001E",
+-  "avc1.58A01E",
+-  "avc1.4D401E",
+-  "avc1.64001E",
+-  "mp4a.40.2",
+-  nsnull
+-};
+-
+ bool
+-nsHTMLMediaElement::IsH264Enabled()
++nsHTMLMediaElement::IsGStreamerEnabled()
+ {
+-  return Preferences::GetBool("media.h264.enabled");
+-}
+-
+-bool
+-nsHTMLMediaElement::IsH264Type(const nsACString& aType)
+-{
+-  if (!IsH264Enabled()) {
+-    return false;
+-  }
+-
+-  for (PRUint32 i = 0; i < ArrayLength(gH264Types); ++i) {
+-    if (aType.EqualsASCII(gH264Types[i])) {
+-      return true;
+-    }
+-  }
+-
+-  return false;
++  return Preferences::GetBool("media.gstreamer.enabled");
+ }
+ #endif
+ 
+ #ifdef MOZ_MEDIA_PLUGINS
+ bool
+ nsHTMLMediaElement::IsMediaPluginsEnabled()
+ {
+   return Preferences::GetBool("media.plugins.enabled");
+ }
+ #endif
+ 
+ /* static */
+ nsHTMLMediaElement::CanPlayStatus 
+ nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType,
+-                                       char const *const ** aCodecList)
++                                       const char *aCodecs,
++                                       char const *const ** aCodecList,
++                                       bool* aCheckCodecList)
+ {
++  if (aCheckCodecList)
++    *aCheckCodecList = true;
+ #ifdef MOZ_RAW
+   if (IsRawType(nsDependentCString(aMIMEType))) {
+     *aCodecList = gRawCodecs;
+     return CANPLAY_MAYBE;
+   }
+ #endif
+ #ifdef MOZ_OGG
+   if (IsOggType(nsDependentCString(aMIMEType))) {
+@@ -2148,20 +2120,22 @@ nsHTMLMediaElement::CanHandleMediaType(c
+ #ifdef MOZ_WEBM
+   if (IsWebMType(nsDependentCString(aMIMEType))) {
+     *aCodecList = gWebMCodecs;
+     return CANPLAY_YES;
+   }
+ #endif
+ 
+ #ifdef MOZ_GSTREAMER
+-  if (IsH264Type(nsDependentCString(aMIMEType))) {
+-    *aCodecList = gH264Codecs;
+-    return CANPLAY_MAYBE;
+-  }
++  if (aCheckCodecList)
++    *aCheckCodecList = false;
++  if (aCodecList)
++    *aCodecList = NULL;
++  if (nsGStreamerDecoder::CanHandleMediaType(aMIMEType, aCodecs))
++    return CANPLAY_YES;
+ #endif
+ #ifdef MOZ_MEDIA_PLUGINS
+   if (GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), aCodecList))
+     return CANPLAY_MAYBE;
+ #endif
+   return CANPLAY_NO;
+ }
+ 
+@@ -2176,17 +2150,17 @@ bool nsHTMLMediaElement::ShouldHandleMed
+   if (IsOggType(nsDependentCString(aMIMEType)))
+     return true;
+ #endif
+ #ifdef MOZ_WEBM
+   if (IsWebMType(nsDependentCString(aMIMEType)))
+     return true;
+ #endif
+ #ifdef MOZ_GSTREAMER
+-  if (IsH264Type(nsDependentCString(aMIMEType)))
++  if (nsGStreamerDecoder::CanHandleMediaType(aMIMEType, NULL))
+     return true;
+ #endif
+ #ifdef MOZ_MEDIA_PLUGINS
+   if (GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), NULL))
+     return true;
+ #endif
+   // We should not return true for Wave types, since there are some
+   // Wave codecs actually in use in the wild that we don't support, and
+@@ -2212,26 +2186,31 @@ nsHTMLMediaElement::GetCanPlay(const nsA
+ {
+   nsContentTypeParser parser(aType);
+   nsAutoString mimeType;
+   nsresult rv = parser.GetType(mimeType);
+   if (NS_FAILED(rv))
+     return CANPLAY_NO;
+ 
+   NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
++  nsAutoString codecs;
++  rv = parser.GetParameter("codecs", codecs);
++  NS_ConvertUTF16toUTF8 codecsUTF8(codecs);
+   char const *const * supportedCodecs;
++  bool checkSupportedCodecs = true;
+   CanPlayStatus status = CanHandleMediaType(mimeTypeUTF8.get(),
+-                                            &supportedCodecs);
++                                            codecsUTF8.get(),
++                                            &supportedCodecs,
++                                            &checkSupportedCodecs);
+   if (status == CANPLAY_NO)
+     return CANPLAY_NO;
+ 
+-  nsAutoString codecs;
+-  rv = parser.GetParameter("codecs", codecs);
+-  if (NS_FAILED(rv)) {
+-    // Parameter not found or whatever
++  if (codecs.IsEmpty() || !checkSupportedCodecs) {
++    /* no codecs to check for or they were already checked in CanHandleMediaType
++     * above */
+     return status;
+   }
+ 
+   CanPlayStatus result = CANPLAY_YES;
+   // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
+   // of the 'codecs' parameter
+   nsCharSeparatedTokenizer tokenizer(codecs, ',');
+   bool expectMoreTokens = false;
+@@ -2309,17 +2288,19 @@ nsHTMLMediaElement::CreateDecoder(const 
+     nsRefPtr<nsWebMDecoder> decoder = new nsWebMDecoder();
+     if (decoder->Init(this)) {
+       return decoder.forget();
+     }
+   }
+ #endif
+ 
+ #ifdef MOZ_GSTREAMER 
+-  if (IsH264Type(aType)) {
++  const char *type;
++  NS_CStringGetData(aType, &type, NULL);
++  if (nsGStreamerDecoder::CanHandleMediaType(type, NULL)) {
+     nsRefPtr<nsGStreamerDecoder> decoder = new nsGStreamerDecoder();
+     if (decoder->Init(this)) {
+       return decoder.forget();
+     }
+   }
+ #endif
+   return nsnull;
+ }
+diff --git a/content/media/gstreamer/Makefile.in b/content/media/gstreamer/Makefile.in
+--- a/content/media/gstreamer/Makefile.in
++++ b/content/media/gstreamer/Makefile.in
+@@ -16,16 +16,17 @@ LIBXUL_LIBRARY 	= 1
+ 
+ EXPORTS		+= \
+ 		nsGStreamerDecoder.h \
+ 		$(NULL)
+ 
+ CPPSRCS		= \
+ 		nsGStreamerReader.cpp \
+ 		nsGStreamerDecoder.cpp \
++		nsGStreamerFormatHelper.cpp \
+ 		$(NULL)
+ 
+ FORCE_STATIC_LIB = 1
+ 
+ include $(topsrcdir)/config/rules.mk
+ 
+ CFLAGS		+= $(GSTREAMER_CFLAGS)
+ CXXFLAGS	+= $(GSTREAMER_CFLAGS)
+diff --git a/content/media/gstreamer/nsGStreamerDecoder.cpp b/content/media/gstreamer/nsGStreamerDecoder.cpp
+--- a/content/media/gstreamer/nsGStreamerDecoder.cpp
++++ b/content/media/gstreamer/nsGStreamerDecoder.cpp
+@@ -2,13 +2,19 @@
+ /* 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 "nsBuiltinDecoderStateMachine.h"
+ #include "nsGStreamerReader.h"
+ #include "nsGStreamerDecoder.h"
++#include "nsGStreamerFormatHelper.h"
+ 
+ nsDecoderStateMachine* nsGStreamerDecoder::CreateStateMachine()
+ {
+   return new nsBuiltinDecoderStateMachine(this, new nsGStreamerReader(this));
+ }
++
++bool nsGStreamerDecoder::CanHandleMediaType(const char* aMIMEType,
++                                            const char* aCodecs) {
++  return nsGStreamerFormatHelper::Instance()->CanHandleMediaType(aMIMEType, aCodecs);
++}
+diff --git a/content/media/gstreamer/nsGStreamerDecoder.h b/content/media/gstreamer/nsGStreamerDecoder.h
+--- a/content/media/gstreamer/nsGStreamerDecoder.h
++++ b/content/media/gstreamer/nsGStreamerDecoder.h
+@@ -9,11 +9,12 @@
+ 
+ #include "nsBuiltinDecoder.h"
+ 
+ class nsGStreamerDecoder : public nsBuiltinDecoder
+ {
+ public:
+   virtual nsMediaDecoder* Clone() { return new nsGStreamerDecoder(); }
+   virtual nsDecoderStateMachine* CreateStateMachine();
++  static bool CanHandleMediaType(const char* aMIMEType, const char* aCodecs);
+ };
+ 
+ #endif
+diff --git a/content/media/gstreamer/nsGStreamerFormatHelper.cpp b/content/media/gstreamer/nsGStreamerFormatHelper.cpp
+new file mode 100644
+--- /dev/null
++++ b/content/media/gstreamer/nsGStreamerFormatHelper.cpp
+@@ -0,0 +1,149 @@
++/* -*- 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 "nsGStreamerFormatHelper.h"
++#include "nsCharSeparatedTokenizer.h"
++#include "nsXPCOMStrings.h"
++
++#define ENTRY_FORMAT(entry) entry[0]
++#define ENTRY_CAPS(entry) entry[1]
++
++nsGStreamerFormatHelper* nsGStreamerFormatHelper::gInstance = NULL;
++
++nsGStreamerFormatHelper *nsGStreamerFormatHelper::Instance() {
++  if (!gInstance) {
++    gst_init(NULL, NULL);
++    gInstance = new nsGStreamerFormatHelper();
++  }
++
++  return gInstance;
++}
++
++nsGStreamerFormatHelper::nsGStreamerFormatHelper()
++  : mFactories(NULL),
++    mCookie(0)
++{
++  const char *containers[3][2] = {
++    {"video/mp4", "video/quicktime"},
++    {"audio/mp4", "audio/mpeg, mpegversion=(int)4"},
++    {"audio/mpeg", "audio/mpeg, mpegversion=(int)1"},
++  };
++  memcpy(mContainers, containers, sizeof(containers));
++
++  const char *codecs[7][2] = {
++    {"avc1.42E01E", "video/x-h264"},
++    {"avc1.42001E", "video/x-h264"},
++    {"avc1.58A01E", "video/x-h264"},
++    {"avc1.4D401E", "video/x-h264"},
++    {"avc1.64001E", "video/x-h264"},
++    {"mp4a.40.2", "audio/mpeg, mpegversion=(int)4"},
++    {"mp3", "audio/mpeg, mpegversion=(int)1"},
++  };
++  memcpy(mCodecs, codecs, sizeof(codecs));
++}
++
++nsGStreamerFormatHelper::~nsGStreamerFormatHelper() {
++  if (mFactories)
++    g_list_free(mFactories);
++}
++
++bool nsGStreamerFormatHelper::CanHandleMediaType(const char* aMIMEType,
++                                                 const char *aCodecs) {
++  GstCaps *caps = ConvertFormatsToCaps(aMIMEType, aCodecs);
++  if (!caps) {
++    return false;
++  }
++
++  bool ret = HaveElementsToProcessCaps(caps);
++  gst_caps_unref(caps);
++
++  return ret;
++}
++
++GstCaps *nsGStreamerFormatHelper::ConvertFormatsToCaps(const char *aMIMEType,
++                                                       const char *aCodecs) {
++  unsigned int i;
++
++  /* convert aMIMEType to gst container caps */
++  const char *capsString = NULL;
++  for (i = 0; i < G_N_ELEMENTS(mContainers); i++) {
++    if (!strcmp(ENTRY_FORMAT(mContainers[i]), aMIMEType)) {
++      capsString = ENTRY_CAPS(mContainers[i]);
++      break;
++    }
++  }
++
++  if (!capsString) {
++    /* we couldn't find any matching caps */
++    return NULL;
++  }
++
++  GstCaps *caps = gst_caps_from_string(capsString);
++  /* container only */
++  if (!aCodecs) {
++    return caps;
++  }
++
++  nsDependentCSubstring codecs(aCodecs, strlen(aCodecs));
++  nsCCharSeparatedTokenizer tokenizer(codecs, ',');
++  while (tokenizer.hasMoreTokens()) {
++    const nsCSubstring& codec = tokenizer.nextToken();
++    capsString = NULL;
++
++    for (i = 0; i < G_N_ELEMENTS(mCodecs); i++) {
++      if (codec.Equals(ENTRY_FORMAT(mCodecs[i]))) {
++        capsString = ENTRY_CAPS(mCodecs[i]);
++        break;
++      }
++    }
++
++    if (!capsString) {
++      gst_caps_unref(caps);
++      return NULL;
++    }
++
++    GstCaps *tmp = gst_caps_from_string(capsString);
++    /* appends and frees tmp */
++    gst_caps_append(caps, tmp);
++  }
++
++  return caps;
++}
++
++bool nsGStreamerFormatHelper::HaveElementsToProcessCaps(GstCaps *aCaps) {
++
++  GList *factories = GetFactories();
++
++  GList *list;
++  /* here aCaps contains [containerCaps, [codecCaps1, [codecCaps2, ...]]] so process
++   * caps structures individually as we want one element for _each_
++   * structure */
++  for (unsigned int i = 0; i < gst_caps_get_size(aCaps); i++) {
++    GstStructure *s = gst_caps_get_structure(aCaps, i);
++    GstCaps *caps = gst_caps_new_full(gst_structure_copy(s), NULL);
++    list = gst_element_factory_list_filter (factories, caps, GST_PAD_SINK, FALSE);
++    gst_caps_unref(caps);
++    if (!list) {
++      return false;
++    }
++    g_list_free(list);
++  }
++
++  return true;
++}
++
++GList * nsGStreamerFormatHelper::GetFactories() {
++  uint32_t cookie = gst_default_registry_get_feature_list_cookie ();
++  if (cookie != mCookie) {
++    g_list_free(mFactories);
++    mFactories = gst_element_factory_list_get_elements
++        (GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_DECODER,
++         GST_RANK_MARGINAL);
++    mCookie = cookie;
++  }
++
++  return mFactories;
++}
+diff --git a/content/media/gstreamer/nsGStreamerFormatHelper.h b/content/media/gstreamer/nsGStreamerFormatHelper.h
+new file mode 100644
+--- /dev/null
++++ b/content/media/gstreamer/nsGStreamerFormatHelper.h
+@@ -0,0 +1,37 @@
++/* -*- 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/. */
++
++#if !defined(nsGStreamerFormatHelper_h_)
++#define nsGStreamerFormatHelper_h_
++
++#include <gst/gst.h>
++#include <mozilla/Types.h>
++
++class nsGStreamerFormatHelper {
++  public:
++    static nsGStreamerFormatHelper *Instance();
++    ~nsGStreamerFormatHelper();
++
++    bool CanHandleMediaType(const char *aMIMEType,
++                            const char *aCodecs);
++
++  private:
++    nsGStreamerFormatHelper();
++    GstCaps *ConvertFormatsToCaps(const char *aMIMEType,
++                                  const char *aCodecs);
++    char * const *CodecListFromCaps(GstCaps *aCaps);
++    bool HaveElementsToProcessCaps(GstCaps *aCaps);
++    GList *GetFactories();
++
++    static nsGStreamerFormatHelper *gInstance;
++
++    const char *mContainers[3][2];
++    const char *mCodecs[7][2];
++    GList *mFactories;
++    uint32_t mCookie;
++};
++
++#endif
+diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js
+--- a/modules/libpref/src/init/all.js
++++ b/modules/libpref/src/init/all.js
+@@ -159,17 +159,17 @@ pref("media.opus.enabled", true);
+ #endif
+ #ifdef MOZ_WAVE
+ pref("media.wave.enabled", true);
+ #endif
+ #ifdef MOZ_WEBM
+ pref("media.webm.enabled", true);
+ #endif
+ #ifdef MOZ_GSTREAMER
+-pref("media.h264.enabled", true);
++pref("media.gstreamer.enabled", true);
+ #endif
+ 
+ 
+ // Whether to autostart a media element with an |autoplay| attribute
+ pref("media.autoplay.enabled", true);
+ 
+ // 0 = Off, 1 = Full, 2 = Tagged Images Only. 
+ // See eCMSMode in gfx/thebes/gfxPlatform.h