# HG changeset patch # Parent 9fe99f8a584f2369a88bfb5281fd6bc95eb2593c Bug 760140 - Query the GstRegistry for the required demuxers/decoders from canPlayType diff --git a/content/media/DecoderTraits.cpp b/content/media/DecoderTraits.cpp --- a/content/media/DecoderTraits.cpp +++ b/content/media/DecoderTraits.cpp @@ -7,16 +7,18 @@ #include "DecoderTraits.h" #include "MediaDecoder.h" #include "nsCharSeparatedTokenizer.h" #ifdef MOZ_MEDIA_PLUGINS #include "MediaPluginHost.h" #endif #ifdef MOZ_GSTREAMER #include "mozilla/Preferences.h" +#include "GStreamerDecoder.h" +#include "nsXPCOMStrings.h" #endif #ifdef MOZ_WMF #include "WMFDecoder.h" #endif namespace mozilla { @@ -137,48 +139,35 @@ return false; } return CodecListContains(gWebMTypes, aType); } #endif #ifdef MOZ_GSTREAMER -static const char* const gH264Types[4] = { - "video/mp4", - "video/3gpp", - "video/quicktime", - nullptr -}; - bool DecoderTraits::IsGStreamerSupportedType(const nsACString& aMimeType) { if (!MediaDecoder::IsGStreamerEnabled()) return false; - if (IsH264Type(aMimeType)) + if (GStreamerDecoder::CanHandleMediaType(aMimeType, nullptr)) return true; if (!Preferences::GetBool("media.prefer-gstreamer", false)) return false; #ifdef MOZ_WEBM if (IsWebMType(aMimeType)) return true; #endif #ifdef MOZ_OGG if (IsOggType(aMimeType)) return true; #endif return false; } - -bool -DecoderTraits::IsH264Type(const nsACString& aType) -{ - return CodecListContains(gH264Types, aType); -} #endif #ifdef MOZ_WIDGET_GONK static const char* const gOmxTypes[6] = { "audio/mpeg", "audio/mp4", "video/mp4", "video/3gpp", @@ -190,19 +179,17 @@ DecoderTraits::IsOmxSupportedType(const nsACString& aType) { if (!MediaDecoder::IsOmxEnabled()) { return false; } return CodecListContains(gOmxTypes, aType); } -#endif -#if defined(MOZ_GSTREAMER) || defined(MOZ_WIDGET_GONK) static char const *const gH264Codecs[9] = { "avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0 "avc1.42001E", // H.264 Baseline Profile Level 3.0 "avc1.58A01E", // H.264 Extended Profile Level 3.0 "avc1.4D401E", // H.264 Main Profile Level 3.0 "avc1.64001E", // H.264 High Profile Level 3.0 "avc1.64001F", // H.264 High Profile Level 3.1 "mp4v.20.3", // 3GPP @@ -303,19 +290,19 @@ #ifdef MOZ_DASH if (IsDASHMPDType(nsDependentCString(aMIMEType))) { // DASH manifest uses WebM codecs only. codecList = gWebMCodecs; result = CANPLAY_YES; } #endif #ifdef MOZ_GSTREAMER - if (IsH264Type(nsDependentCString(aMIMEType))) { - codecList = gH264Codecs; - result = CANPLAY_MAYBE; + if (GStreamerDecoder::CanHandleMediaType(nsDependentCString(aMIMEType), + aHaveRequestedCodecs ? &aRequestedCodecs : nullptr)) { + return CANPLAY_YES; } #endif #ifdef MOZ_WIDGET_GONK if (IsOmxSupportedType(nsDependentCString(aMIMEType))) { codecList = gH264Codecs; result = CANPLAY_MAYBE; } #endif @@ -324,17 +311,17 @@ result = CANPLAY_MAYBE; } #endif #ifdef MOZ_MEDIA_PLUGINS if (MediaDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList)) result = CANPLAY_MAYBE; #endif - if (result == CANPLAY_NO || !aHaveRequestedCodecs) { + if (result == CANPLAY_NO || !aHaveRequestedCodecs || !codecList) { return result; } // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description // of the 'codecs' parameter nsCharSeparatedTokenizer tokenizer(aRequestedCodecs, ','); bool expectMoreTokens = false; while (tokenizer.hasMoreTokens()) { diff --git a/content/media/DecoderTraits.h b/content/media/DecoderTraits.h --- a/content/media/DecoderTraits.h +++ b/content/media/DecoderTraits.h @@ -49,17 +49,16 @@ #endif #ifdef MOZ_WEBM static bool IsWebMType(const nsACString& aType); #endif #ifdef MOZ_GSTREAMER static bool IsGStreamerSupportedType(const nsACString& aType); - static bool IsH264Type(const nsACString& aType); #endif #ifdef MOZ_WIDGET_GONK static bool IsOmxSupportedType(const nsACString& aType); #endif #ifdef MOZ_MEDIA_PLUGINS static bool IsMediaPluginsType(const nsACString& aType); diff --git a/content/media/gstreamer/GStreamerDecoder.cpp b/content/media/gstreamer/GStreamerDecoder.cpp --- a/content/media/gstreamer/GStreamerDecoder.cpp +++ b/content/media/gstreamer/GStreamerDecoder.cpp @@ -2,18 +2,26 @@ /* 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 "MediaDecoderStateMachine.h" #include "GStreamerReader.h" #include "GStreamerDecoder.h" +#include "GStreamerFormatHelper.h" namespace mozilla { MediaDecoderStateMachine* GStreamerDecoder::CreateStateMachine() { return new MediaDecoderStateMachine(this, new GStreamerReader(this)); } +bool +GStreamerDecoder::CanHandleMediaType(const nsACString& aMIMEType, + const nsAString* aCodecs) +{ + return GStreamerFormatHelper::Instance()->CanHandleMediaType(aMIMEType, aCodecs); +} + } // namespace mozilla diff --git a/content/media/gstreamer/GStreamerDecoder.h b/content/media/gstreamer/GStreamerDecoder.h --- a/content/media/gstreamer/GStreamerDecoder.h +++ b/content/media/gstreamer/GStreamerDecoder.h @@ -3,21 +3,23 @@ /* 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(GStreamerDecoder_h_) #define GStreamerDecoder_h_ #include "MediaDecoder.h" +#include "nsXPCOMStrings.h" namespace mozilla { class GStreamerDecoder : public MediaDecoder { public: virtual MediaDecoder* Clone() { return new GStreamerDecoder(); } virtual MediaDecoderStateMachine* CreateStateMachine(); + static bool CanHandleMediaType(const nsACString& aMIMEType, const nsAString* aCodecs); }; } // namespace mozilla #endif diff --git a/content/media/gstreamer/GStreamerFormatHelper.cpp b/content/media/gstreamer/GStreamerFormatHelper.cpp new file mode 100644 --- /dev/null +++ b/content/media/gstreamer/GStreamerFormatHelper.cpp @@ -0,0 +1,159 @@ +/* -*- 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 "GStreamerFormatHelper.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsXPCOMStrings.h" + +#define ENTRY_FORMAT(entry) entry[0] +#define ENTRY_CAPS(entry) entry[1] + +GStreamerFormatHelper* GStreamerFormatHelper::gInstance = nullptr; + +GStreamerFormatHelper* GStreamerFormatHelper::Instance() { + if (!gInstance) { + gst_init(nullptr, nullptr); + gInstance = new GStreamerFormatHelper(); + } + + return gInstance; +} + +void GStreamerFormatHelper::Shutdown() { + if (gInstance) { + delete gInstance; + gInstance = nullptr; + } +} + +char const *const GStreamerFormatHelper::mContainers[4][2] = { + {"video/mp4", "video/quicktime"}, + {"video/quicktime", "video/quicktime"}, + {"audio/mp4", "audio/mpeg, mpegversion=(int)4"}, + {"audio/mpeg", "audio/mpeg, mpegversion=(int)1"}, +}; + +char const *const GStreamerFormatHelper::mCodecs[8][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"}, + {"avc1.64001F", "video/x-h264"}, + {"mp4v.20.3", "video/3gpp"}, + {"mp4a.40.2", "audio/mpeg, mpegversion=(int)4"}, +}; + +GStreamerFormatHelper::GStreamerFormatHelper() + : mFactories(nullptr), + mCookie(static_cast(-1)) +{ +} + +GStreamerFormatHelper::~GStreamerFormatHelper() { + if (mFactories) + g_list_free(mFactories); +} + +bool GStreamerFormatHelper::CanHandleMediaType(const nsACString& aMIMEType, + const nsAString* aCodecs) { + const char *type; + NS_CStringGetData(aMIMEType, &type, NULL); + + GstCaps* caps = ConvertFormatsToCaps(type, aCodecs); + if (!caps) { + return false; + } + + bool ret = HaveElementsToProcessCaps(caps); + gst_caps_unref(caps); + + return ret; +} + +GstCaps* GStreamerFormatHelper::ConvertFormatsToCaps(const char* aMIMEType, + const nsAString* aCodecs) { + unsigned int i; + + /* convert aMIMEType to gst container caps */ + const char* capsString = nullptr; + 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 nullptr; + } + + GstCaps* caps = gst_caps_from_string(capsString); + /* container only */ + if (!aCodecs) { + return caps; + } + + nsCharSeparatedTokenizer tokenizer(*aCodecs, ','); + while (tokenizer.hasMoreTokens()) { + const nsSubstring& codec = tokenizer.nextToken(); + capsString = nullptr; + + for (i = 0; i < G_N_ELEMENTS(mCodecs); i++) { + if (codec.EqualsASCII(ENTRY_FORMAT(mCodecs[i]))) { + capsString = ENTRY_CAPS(mCodecs[i]); + break; + } + } + + if (!capsString) { + gst_caps_unref(caps); + return nullptr; + } + + GstCaps* tmp = gst_caps_from_string(capsString); + /* appends and frees tmp */ + gst_caps_append(caps, tmp); + } + + return caps; +} + +bool GStreamerFormatHelper::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), nullptr); + 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* GStreamerFormatHelper::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/GStreamerFormatHelper.h b/content/media/gstreamer/GStreamerFormatHelper.h new file mode 100644 --- /dev/null +++ b/content/media/gstreamer/GStreamerFormatHelper.h @@ -0,0 +1,60 @@ +/* -*- 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(GStreamerFormatHelper_h_) +#define GStreamerFormatHelper_h_ + +#include +#include +#include "nsXPCOMStrings.h" + +class GStreamerFormatHelper { + /* This class can be used to query the GStreamer registry for the required + * demuxers/decoders from nsHTMLMediaElement::CanPlayType. + * It implements looking at the GstRegistry to check if elements to + * demux/decode the formats passed to CanPlayType() are actually installed. + */ + public: + static GStreamerFormatHelper* Instance(); + ~GStreamerFormatHelper(); + + bool CanHandleMediaType(const nsACString& aMIMEType, + const nsAString* aCodecs); + + static void Shutdown(); + + private: + GStreamerFormatHelper(); + GstCaps* ConvertFormatsToCaps(const char* aMIMEType, + const nsAString* aCodecs); + char* const *CodecListFromCaps(GstCaps* aCaps); + bool HaveElementsToProcessCaps(GstCaps* aCaps); + GList* GetFactories(); + + static GStreamerFormatHelper* gInstance; + + /* table to convert from container MIME types to GStreamer elements */ + static char const *const mContainers[4][2]; + + /* table to convert from codec MIME types to GStreamer elements */ + static char const *const mCodecs[8][2]; + + /* list of GStreamer element factories + * Element factories are the basic types retrieved from the GStreamer + * registry, they describe all plugins and elements that GStreamer can + * create. + * This means that element factories are useful for automated element + * instancing, such as what autopluggers do, + * and for creating lists of available elements. */ + GList* mFactories; + + /* Storage for the default registrys feature list cookie. + * It changes every time a feature is added to or removed from the + * GStreamer registry. */ + uint32_t mCookie; +}; + +#endif 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 @@ -13,21 +13,23 @@ MODULE = content LIBRARY_NAME = gkcongstreamer_s LIBXUL_LIBRARY = 1 EXPORTS += \ GStreamerDecoder.h \ GStreamerReader.h \ + GStreamerFormatHelper.h \ $(NULL) CPPSRCS = \ GStreamerReader.cpp \ GStreamerDecoder.cpp \ + GStreamerFormatHelper.cpp \ $(NULL) FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk CFLAGS += $(GSTREAMER_CFLAGS) CXXFLAGS += $(GSTREAMER_CFLAGS) diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -316,16 +316,20 @@ -I$(topsrcdir)/js/xpconnect/loader \ -I$(topsrcdir)/caps/include \ -I$(topsrcdir)/netwerk/base/src \ -I$(topsrcdir)/content/svg/content/src \ -I$(topsrcdir)/extensions/cookie \ -I$(topsrcdir)/netwerk/cookie \ $(NULL) +ifdef MOZ_GSTREAMER +LOCAL_INCLUDES += $(GSTREAMER_CFLAGS) +endif + ifdef MOZ_B2G_RIL #{ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/gonk endif #} ifdef MOZ_B2G_FM #{ LOCAL_INCLUDES += -I$(topsrcdir)/dom/fm endif #} diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -78,16 +78,20 @@ #ifdef MOZ_MEDIA_PLUGINS #include "MediaPluginHost.h" #endif #ifdef MOZ_WMF #include "WMFDecoder.h" #endif +#ifdef MOZ_GSTREAMER +#include "GStreamerFormatHelper.h" +#endif + #ifdef MOZ_SYDNEYAUDIO #include "AudioStream.h" #endif #include "nsError.h" #include "nsCycleCollector.h" #include "nsJSEnvironment.h" @@ -336,16 +340,20 @@ nsXBLService::Shutdown(); nsAutoCopyListener::Shutdown(); FrameLayerBuilder::Shutdown(); #ifdef MOZ_MEDIA_PLUGINS MediaPluginHost::Shutdown(); #endif +#ifdef MOZ_GSTREAMER + GStreamerFormatHelper::Shutdown(); +#endif + #ifdef MOZ_SYDNEYAUDIO AudioStream::ShutdownLibrary(); #endif #ifdef MOZ_WMF WMFDecoder::UnloadDLLs(); #endif