Diff
Modified: trunk/Source/WebCore/ChangeLog (241584 => 241585)
--- trunk/Source/WebCore/ChangeLog 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/ChangeLog 2019-02-15 14:24:21 UTC (rev 241585)
@@ -1,3 +1,82 @@
+2019-02-15 Philippe Normand <[email protected]>
+
+ [GStreamer] Decoding media-capabilities configuration initial support
+ https://bugs.webkit.org/show_bug.cgi?id=191191
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ This patch enables basic platform probing for GStreamer decoders,
+ optionally using Hardware decoding capabilities. The previous code
+ for decoders/demuxers probing partially duplicated between the MSE
+ player and its parent class was moved to a new module called
+ GStreamerRegistryScanner. There is one instance of it for the MSE player
+ and one for the parent class.
+
+ The scanner can check for the presence of the GstElement Hardware
+ metadata classifier in decoders and thus advise the
+ MediaEngineConfigurationFactoryGStreamer that hardware decoding is
+ supported or not. This is only a first step though. The scanner
+ should also probably attempt a NULL->READY transition on decoders
+ to validate specific input caps are supported. As this might
+ require changes in GStreamer, this part of the patch wasn't
+ included.
+
+ This patch is covered by the existing media tests.
+
+ * platform/GStreamer.cmake: New files.
+ * platform/graphics/MediaPlayer.cpp: Add support for converting
+ SupportsType enum to string.
+ (WebCore::convertEnumerationToString):
+ * platform/graphics/MediaPlayer.h: Ditto.
+ * platform/graphics/MediaPlayerEnums.h: Ditto.
+ * platform/graphics/gstreamer/GStreamerCommon.cpp: Move
+ gstRegistryHasElementForMediaType to GStreamerRegistryScanner.
+ * platform/graphics/gstreamer/GStreamerCommon.h: Ditto.
+ * platform/graphics/gstreamer/GStreamerRegistryScanner.cpp: Added.
+ (WebCore::GStreamerRegistryScanner::singleton):
+ (WebCore::GStreamerRegistryScanner::GStreamerRegistryScanner): Initialize
+ supported mime-types and codecs from the GStreamer registry.
+ (WebCore::GStreamerRegistryScanner::~GStreamerRegistryScanner): Free the element factories.
+ (WebCore::GStreamerRegistryScanner::gstRegistryHasElementForMediaType):
+ Check the input caps are supported, optionally using hardware
+ device.
+ (WebCore::GStreamerRegistryScanner::fillMimeTypeSetFromCapsMapping):
+ Moved from MediaPlayerPrivateGStreamer{,MSE}.
+ (WebCore::GStreamerRegistryScanner::initialize): Ditto.
+ (WebCore::GStreamerRegistryScanner::supportsCodec const): Ditto.
+ (WebCore::GStreamerRegistryScanner::supportsAllCodecs const): Ditto.
+ (WebCore::GStreamerRegistryScanner::isDecodingSupported const): Check
+ the given configuration is supported. For now hardware support is
+ checked for video configurations only as it is quite uncommon
+ anyway to have hardware-enabled audio decoders.
+ * platform/graphics/gstreamer/GStreamerRegistryScanner.h: Added.
+ (WebCore::GStreamerRegistryScanner::mimeTypeSet):
+ (WebCore::GStreamerRegistryScanner::supportsContainerType const):
+ (WebCore::GStreamerRegistryScanner::RegistryLookupResult::operator bool const):
+ * platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp: Added.
+ (WebCore::createMediaPlayerDecodingConfigurationGStreamer):
+ * platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.h: Added.
+ * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+ Rely on new GStreamerRegistryScanner and add some debugging macros.
+ (WebCore::MediaPlayerPrivateGStreamer::getSupportedTypes):
+ (WebCore::MediaPlayerPrivateGStreamer::supportsType):
+ * platform/graphics/gstreamer/mse/AppendPipeline.cpp: Ditto. Also
+ plug qtdemux for AAC containers, this is an explicit consequence
+ of finer-grained codecs probing.
+ (WebCore::AppendPipeline::AppendPipeline):
+ (WebCore::AppendPipeline::parseDemuxerSrcPadCaps):
+ * platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.cpp: Added.
+ (WebCore::GStreamerRegistryScannerMSE::singleton):
+ (WebCore::GStreamerRegistryScannerMSE::GStreamerRegistryScannerMSE):
+ * platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.h: Added.
+ * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp:
+ Rely on new GStreamerRegistryScanner and add some debugging macros.
+ (WebCore::MediaPlayerPrivateGStreamerMSE::getSupportedTypes):
+ (WebCore::MediaPlayerPrivateGStreamerMSE::supportsType):
+ * platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h:
+ * platform/mediacapabilities/MediaEngineConfigurationFactory.cpp:
+ (WebCore::factories): GStreamer support.
+
2019-02-14 Joseph Pecoraro <[email protected]>
Web Inspector: Occasional crash under WebCore::CSSStyleSheet::item called from Inspector
Modified: trunk/Source/WebCore/platform/GStreamer.cmake (241584 => 241585)
--- trunk/Source/WebCore/platform/GStreamer.cmake 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/GStreamer.cmake 2019-02-15 14:24:21 UTC (rev 241585)
@@ -10,7 +10,9 @@
platform/graphics/gstreamer/GRefPtrGStreamer.cpp
platform/graphics/gstreamer/GStreamerCommon.cpp
platform/graphics/gstreamer/GstAllocatorFastMalloc.cpp
+ platform/graphics/gstreamer/GStreamerRegistryScanner.cpp
platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp
+ platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp
platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
platform/graphics/gstreamer/MediaPlayerPrivateGStreamerBase.cpp
platform/graphics/gstreamer/MediaSampleGStreamer.cpp
@@ -26,6 +28,7 @@
platform/graphics/gstreamer/mse/AppendPipeline.cpp
platform/graphics/gstreamer/mse/GStreamerMediaDescription.cpp
+ platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.cpp
platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp
platform/graphics/gstreamer/mse/MediaSourceClientGStreamerMSE.cpp
platform/graphics/gstreamer/mse/MediaSourceGStreamer.cpp
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -1618,6 +1618,20 @@
return values[static_cast<size_t>(enumerationValue)];
}
+String convertEnumerationToString(MediaPlayerEnums::SupportsType enumerationValue)
+{
+ static const NeverDestroyed<String> values[] = {
+ MAKE_STATIC_STRING_IMPL("IsNotSupported"),
+ MAKE_STATIC_STRING_IMPL("IsSupported"),
+ MAKE_STATIC_STRING_IMPL("MayBeSupported"),
+ };
+ static_assert(!static_cast<size_t>(MediaPlayerEnums::IsNotSupported), "MediaPlayerEnums::IsNotSupported is not 0 as expected");
+ static_assert(static_cast<size_t>(MediaPlayerEnums::IsSupported) == 1, "MediaPlayerEnums::IsSupported is not 1 as expected");
+ static_assert(static_cast<size_t>(MediaPlayerEnums::MayBeSupported) == 2, "MediaPlayerEnums::MayBeSupported is not 2 as expected");
+ ASSERT(static_cast<size_t>(enumerationValue) < WTF_ARRAY_LENGTH(values));
+ return values[static_cast<size_t>(enumerationValue)];
}
+}
+
#endif
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -253,8 +253,8 @@
void invalidate();
// Media engine support.
- enum SupportsType { IsNotSupported, IsSupported, MayBeSupported };
- static MediaPlayer::SupportsType supportsType(const MediaEngineSupportParameters&);
+ using MediaPlayerEnums::SupportsType;
+ static SupportsType supportsType(const MediaEngineSupportParameters&);
static void getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>&);
static bool isAvailable();
static HashSet<RefPtr<SecurityOrigin>> originsInMediaCache(const String& path);
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerEnums.h (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/MediaPlayerEnums.h 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerEnums.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -36,6 +36,7 @@
enum MovieLoadType { Unknown, Download, StoredStream, LiveStream };
enum Preload { None, MetaData, Auto };
enum VideoGravity { VideoGravityResize, VideoGravityResizeAspect, VideoGravityResizeAspectFill };
+ enum SupportsType { IsNotSupported, IsSupported, MayBeSupported };
enum {
VideoFullscreenModeNone = 0,
VideoFullscreenModeStandard = 1 << 0,
@@ -47,6 +48,7 @@
WTF::String convertEnumerationToString(MediaPlayerEnums::ReadyState);
WTF::String convertEnumerationToString(MediaPlayerEnums::NetworkState);
WTF::String convertEnumerationToString(MediaPlayerEnums::Preload);
+WTF::String convertEnumerationToString(MediaPlayerEnums::SupportsType);
} // namespace WebCore
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -302,16 +302,6 @@
return time.timeValue();
}
-bool gstRegistryHasElementForMediaType(GList* elementFactories, const char* capsString)
-{
- GRefPtr<GstCaps> caps = adoptGRef(gst_caps_from_string(capsString));
- GList* candidates = gst_element_factory_list_filter(elementFactories, caps.get(), GST_PAD_SINK, false);
- bool result = candidates;
-
- gst_plugin_feature_list_free(candidates);
- return result;
-}
-
static void simpleBusMessageCallback(GstBus*, GstMessage* message, GstBin* pipeline)
{
switch (GST_MESSAGE_TYPE(message)) {
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -216,7 +216,6 @@
};
-bool gstRegistryHasElementForMediaType(GList* elementFactories, const char* capsString);
void connectSimpleBusMessageCallback(GstElement* pipeline);
void disconnectSimpleBusMessageCallback(GstElement* pipeline);
Added: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2019 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "GStreamerRegistryScanner.h"
+
+#if USE(GSTREAMER)
+#include "ContentType.h"
+#include "GStreamerCommon.h"
+#include <fnmatch.h>
+#include <wtf/PrintStream.h>
+
+namespace WebCore {
+
+GST_DEBUG_CATEGORY_STATIC(webkit_media_gst_registry_scanner_debug);
+#define GST_CAT_DEFAULT webkit_media_gst_registry_scanner_debug
+
+GStreamerRegistryScanner& GStreamerRegistryScanner::singleton()
+{
+ static NeverDestroyed<GStreamerRegistryScanner> sharedInstance;
+ return sharedInstance;
+}
+
+GStreamerRegistryScanner::GStreamerRegistryScanner(bool isMediaSource)
+ : m_isMediaSource(isMediaSource)
+{
+ GST_DEBUG_CATEGORY_INIT(webkit_media_gst_registry_scanner_debug, "webkitregistryscanner", 0, "WebKit GStreamer registry scanner");
+ m_audioDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
+ m_audioParserFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_PARSER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_NONE);
+ m_videoDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, GST_RANK_MARGINAL);
+ m_videoParserFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_PARSER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, GST_RANK_MARGINAL);
+ m_demuxerFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEMUXER, GST_RANK_MARGINAL);
+
+ initialize();
+#ifndef GST_DISABLE_GST_DEBUG
+ GST_DEBUG("%s registry scanner initialized", m_isMediaSource ? "MSE" : "Regular playback");
+ for (auto& mimeType : m_mimeTypeSet)
+ GST_DEBUG("Mime-type registered: %s", mimeType.utf8().data());
+ for (auto& item : m_codecMap)
+ GST_DEBUG("%s codec pattern registered: %s", item.value ? "Hardware" : "Software", item.key.string().utf8().data());
+#endif
+}
+
+GStreamerRegistryScanner::~GStreamerRegistryScanner()
+{
+ gst_plugin_feature_list_free(m_audioDecoderFactories);
+ gst_plugin_feature_list_free(m_audioParserFactories);
+ gst_plugin_feature_list_free(m_videoDecoderFactories);
+ gst_plugin_feature_list_free(m_videoParserFactories);
+ gst_plugin_feature_list_free(m_demuxerFactories);
+}
+
+GStreamerRegistryScanner::RegistryLookupResult GStreamerRegistryScanner::hasElementForMediaType(GList* elementFactories, const char* capsString, bool shouldCheckHardwareClassifier)
+{
+ GRefPtr<GstCaps> caps = adoptGRef(gst_caps_from_string(capsString));
+ GList* candidates = gst_element_factory_list_filter(elementFactories, caps.get(), GST_PAD_SINK, false);
+ bool isSupported = candidates;
+ bool isUsingHardware = false;
+
+ if (shouldCheckHardwareClassifier) {
+ for (GList* factories = candidates; factories; factories = g_list_next(factories)) {
+ auto* factory = reinterpret_cast<GstElementFactory*>(factories->data);
+ String metadata = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
+ auto components = metadata.split('/');
+ if (components.contains("Hardware")) {
+ isUsingHardware = true;
+ break;
+ }
+ }
+ }
+
+ gst_plugin_feature_list_free(candidates);
+#ifndef GST_DISABLE_GST_DEBUG
+ const char* elementType = "";
+ if (elementFactories == m_audioParserFactories)
+ elementType = "Audio parser";
+ else if (elementFactories == m_audioDecoderFactories)
+ elementType = "Audio decoder";
+ else if (elementFactories == m_videoParserFactories)
+ elementType = "Video parser";
+ else if (elementFactories == m_videoDecoderFactories)
+ elementType = "Video decoder";
+ else if (elementFactories == m_demuxerFactories)
+ elementType = "Demuxer";
+ else
+ ASSERT_NOT_REACHED();
+ GST_LOG("%s lookup result for caps %" GST_PTR_FORMAT " : isSupported=%s, isUsingHardware=%s", elementType, caps.get(), boolForPrinting(isSupported), boolForPrinting(isUsingHardware));
+#endif
+ return GStreamerRegistryScanner::RegistryLookupResult { isSupported, isUsingHardware };
+}
+
+void GStreamerRegistryScanner::fillMimeTypeSetFromCapsMapping(Vector<GstCapsWebKitMapping>& mapping)
+{
+ for (auto& current : mapping) {
+ GList* factories;
+ switch (current.elementType) {
+ case Demuxer:
+ factories = m_demuxerFactories;
+ break;
+ case AudioDecoder:
+ factories = m_audioDecoderFactories;
+ break;
+ case VideoDecoder:
+ factories = m_videoDecoderFactories;
+ break;
+ }
+
+ if (hasElementForMediaType(factories, current.capsString)) {
+ if (!current.webkitCodecPatterns.isEmpty()) {
+ for (const auto& pattern : current.webkitCodecPatterns)
+ m_codecMap.add(pattern, false);
+ }
+ if (!current.webkitMimeTypes.isEmpty()) {
+ for (const auto& mimeType : current.webkitMimeTypes)
+ m_mimeTypeSet.add(mimeType);
+ } else
+ m_mimeTypeSet.add(AtomicString(current.capsString));
+ }
+ }
+}
+
+void GStreamerRegistryScanner::initialize()
+{
+ if (hasElementForMediaType(m_audioDecoderFactories, "audio/mpeg, mpegversion=(int)4")) {
+ m_mimeTypeSet.add(AtomicString("audio/aac"));
+ m_mimeTypeSet.add(AtomicString("audio/mp4"));
+ m_mimeTypeSet.add(AtomicString("audio/x-m4a"));
+ m_codecMap.add(AtomicString("mpeg"), false);
+ m_codecMap.add(AtomicString("mp4a*"), false);
+ }
+
+ auto opusSupported = hasElementForMediaType(m_audioDecoderFactories, "audio/x-opus");
+ if (opusSupported && (!m_isMediaSource || hasElementForMediaType(m_audioParserFactories, "audio/x-opus"))) {
+ m_mimeTypeSet.add(AtomicString("audio/opus"));
+ m_codecMap.add(AtomicString("opus"), false);
+ m_codecMap.add(AtomicString("x-opus"), false);
+ }
+
+ auto vorbisSupported = hasElementForMediaType(m_audioDecoderFactories, "audio/x-vorbis");
+ if (vorbisSupported && (!m_isMediaSource || hasElementForMediaType(m_audioParserFactories, "audio/x-vorbis"))) {
+ m_codecMap.add(AtomicString("vorbis"), false);
+ m_codecMap.add(AtomicString("x-vorbis"), false);
+ }
+
+ if (hasElementForMediaType(m_demuxerFactories, "video/x-matroska")) {
+ auto vp8DecoderAvailable = hasElementForMediaType(m_videoDecoderFactories, "video/x-vp8", true);
+ auto vp9DecoderAvailable = hasElementForMediaType(m_videoDecoderFactories, "video/x-vp9", true);
+
+ if (vp8DecoderAvailable || vp9DecoderAvailable)
+ m_mimeTypeSet.add(AtomicString("video/webm"));
+
+ if (vp8DecoderAvailable) {
+ m_codecMap.add(AtomicString("vp8"), vp8DecoderAvailable.isUsingHardware);
+ m_codecMap.add(AtomicString("x-vp8"), vp8DecoderAvailable.isUsingHardware);
+ }
+ if (vp9DecoderAvailable) {
+ m_codecMap.add(AtomicString("vp9"), vp9DecoderAvailable.isUsingHardware);
+ m_codecMap.add(AtomicString("x-vp9"), vp9DecoderAvailable.isUsingHardware);
+ }
+ if (opusSupported)
+ m_mimeTypeSet.add(AtomicString("audio/webm"));
+ }
+
+ auto h264DecoderAvailable = hasElementForMediaType(m_videoDecoderFactories, "video/x-h264, profile="" constrained-baseline, baseline, high }", true);
+ if (h264DecoderAvailable && (!m_isMediaSource || hasElementForMediaType(m_videoParserFactories, "video/x-h264"))) {
+ m_mimeTypeSet.add(AtomicString("video/mp4"));
+ m_mimeTypeSet.add(AtomicString("video/x-m4v"));
+ m_codecMap.add(AtomicString("x-h264"), h264DecoderAvailable.isUsingHardware);
+ m_codecMap.add(AtomicString("avc*"), h264DecoderAvailable.isUsingHardware);
+ m_codecMap.add(AtomicString("mp4v*"), h264DecoderAvailable.isUsingHardware);
+ }
+
+ if (m_isMediaSource)
+ return;
+
+ // The mime-types initialized below are not supported by the MSE backend.
+
+ Vector<GstCapsWebKitMapping> mapping = {
+ {AudioDecoder, "audio/midi", {"audio/midi", "audio/riff-midi"}, { }},
+ {AudioDecoder, "audio/x-ac3", { }, { }},
+ {AudioDecoder, "audio/x-dts", { }, { }},
+ {AudioDecoder, "audio/x-eac3", {"audio/x-ac3"}, { }},
+ {AudioDecoder, "audio/x-flac", {"audio/x-flac", "audio/flac"}, { }},
+ {AudioDecoder, "audio/x-sbc", { }, { }},
+ {AudioDecoder, "audio/x-sid", { }, { }},
+ {AudioDecoder, "audio/x-speex", {"audio/speex", "audio/x-speex"}, { }},
+ {AudioDecoder, "audio/x-wavpack", {"audio/x-wavpack"}, { }},
+ {VideoDecoder, "video/mpeg, mpegversion=(int){1,2}, systemstream=(boolean)false", {"video/mpeg"}, {"mpeg"}},
+ {VideoDecoder, "video/mpegts", { }, { }},
+ {VideoDecoder, "video/x-dirac", { }, { }},
+ {VideoDecoder, "video/x-flash-video", {"video/flv", "video/x-flv"}, { }},
+ {VideoDecoder, "video/x-h263", { }, { }},
+ {VideoDecoder, "video/x-msvideocodec", {"video/x-msvideo"}, { }},
+ {Demuxer, "application/vnd.rn-realmedia", { }, { }},
+ {Demuxer, "application/x-3gp", { }, { }},
+ {Demuxer, "application/x-hls", {"application/vnd.apple.mpegurl", "application/x-mpegurl"}, { }},
+ {Demuxer, "application/x-pn-realaudio", { }, { }},
+ {Demuxer, "audio/x-aiff", { }, { }},
+ {Demuxer, "audio/x-wav", {"audio/x-wav", "audio/wav", "audio/vnd.wave"}, {"1"}},
+ {Demuxer, "video/quicktime", { }, { }},
+ {Demuxer, "video/quicktime, variant=(string)3gpp", {"video/3gpp"}, { }},
+ {Demuxer, "video/x-ms-asf", { }, { }},
+ };
+ fillMimeTypeSetFromCapsMapping(mapping);
+
+ if (hasElementForMediaType(m_demuxerFactories, "application/ogg")) {
+ m_mimeTypeSet.add(AtomicString("application/ogg"));
+
+ if (vorbisSupported) {
+ m_mimeTypeSet.add(AtomicString("audio/ogg"));
+ m_mimeTypeSet.add(AtomicString("audio/x-vorbis+ogg"));
+ }
+
+ if (hasElementForMediaType(m_audioDecoderFactories, "audio/x-speex")) {
+ m_mimeTypeSet.add(AtomicString("audio/ogg"));
+ m_codecMap.add(AtomicString("speex"), false);
+ }
+
+ if (hasElementForMediaType(m_videoDecoderFactories, "video/x-theora")) {
+ m_mimeTypeSet.add(AtomicString("video/ogg"));
+ m_codecMap.add(AtomicString("theora"), false);
+ }
+ }
+
+ bool audioMpegSupported = false;
+ if (hasElementForMediaType(m_audioDecoderFactories, "audio/mpeg, mpegversion=(int)1, layer=(int)[1, 3]")) {
+ audioMpegSupported = true;
+ m_mimeTypeSet.add(AtomicString("audio/mp1"));
+ m_mimeTypeSet.add(AtomicString("audio/mp3"));
+ m_mimeTypeSet.add(AtomicString("audio/x-mp3"));
+ m_codecMap.add(AtomicString("audio/mp3"), false);
+ }
+
+ if (hasElementForMediaType(m_audioDecoderFactories, "audio/mpeg, mpegversion=(int)2")) {
+ audioMpegSupported = true;
+ m_mimeTypeSet.add(AtomicString("audio/mp2"));
+ }
+
+ audioMpegSupported |= isContainerTypeSupported("audio/mp4");
+ if (audioMpegSupported) {
+ m_mimeTypeSet.add(AtomicString("audio/mpeg"));
+ m_mimeTypeSet.add(AtomicString("audio/x-mpeg"));
+ }
+
+ bool matroskaSupported = hasElementForMediaType(m_demuxerFactories, "video/x-matroska");
+ if (matroskaSupported) {
+ m_mimeTypeSet.add(AtomicString("video/x-matroska"));
+
+ if (hasElementForMediaType(m_videoDecoderFactories, "video/x-vp10"))
+ m_mimeTypeSet.add(AtomicString("video/webm"));
+ }
+
+ if ((matroskaSupported || isContainerTypeSupported("video/mp4")) && hasElementForMediaType(m_videoDecoderFactories, "video/x-av1"))
+ m_codecMap.add(AtomicString("av01*"), false);
+}
+
+bool GStreamerRegistryScanner::isCodecSupported(String codec, bool shouldCheckForHardwareUse) const
+{
+ // If the codec is named like a mimetype (eg: video/avc) remove the "video/" part.
+ size_t slashIndex = codec.find('/');
+ if (slashIndex != WTF::notFound)
+ codec = codec.substring(slashIndex + 1);
+
+ bool supported = false;
+ for (const auto& item : m_codecMap) {
+ if (!fnmatch(item.key.string().utf8().data(), codec.utf8().data(), 0)) {
+ supported = shouldCheckForHardwareUse ? item.value : true;
+ if (supported)
+ break;
+ }
+ }
+
+ GST_LOG("Checked %s codec \"%s\" supported %s", shouldCheckForHardwareUse ? "hardware" : "software", codec.utf8().data(), boolForPrinting(supported));
+ return supported;
+}
+
+bool GStreamerRegistryScanner::areAllCodecsSupported(const Vector<String>& codecs, bool shouldCheckForHardwareUse) const
+{
+ for (String codec : codecs) {
+ if (!isCodecSupported(codec, shouldCheckForHardwareUse))
+ return false;
+ }
+
+ return true;
+}
+
+GStreamerRegistryScanner::RegistryLookupResult GStreamerRegistryScanner::isDecodingSupported(MediaConfiguration& configuration) const
+{
+ bool isSupported = false;
+ bool isUsingHardware = false;
+
+ if (configuration.video) {
+ auto& videoConfiguration = configuration.video.value();
+ GST_DEBUG("Checking support for video configuration: \"%s\" size: %ux%u bitrate: %" G_GUINT64_FORMAT " framerate: %f",
+ videoConfiguration.contentType.utf8().data(),
+ videoConfiguration.width, videoConfiguration.height,
+ videoConfiguration.bitrate, videoConfiguration.framerate);
+
+ auto contentType = ContentType(videoConfiguration.contentType);
+ isSupported = isContainerTypeSupported(contentType.containerType());
+ auto codecs = contentType.codecs();
+ if (!codecs.isEmpty())
+ isUsingHardware = areAllCodecsSupported(codecs, true);
+ }
+
+ if (configuration.audio) {
+ auto& audioConfiguration = configuration.audio.value();
+ GST_DEBUG("Checking support for audio configuration: \"%s\" %s channels, bitrate: %" G_GUINT64_FORMAT " samplerate: %u",
+ audioConfiguration.contentType.utf8().data(), audioConfiguration.channels.utf8().data(),
+ audioConfiguration.bitrate, audioConfiguration.samplerate);
+ auto contentType = ContentType(audioConfiguration.contentType);
+ isSupported = isContainerTypeSupported(contentType.containerType());
+ }
+
+ return GStreamerRegistryScanner::RegistryLookupResult { isSupported, isUsingHardware };
+}
+
+}
+#endif
Added: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerRegistryScanner.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if USE(GSTREAMER)
+
+#include "MediaConfiguration.h"
+
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/AtomicStringHash.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebCore {
+class ContentType;
+
+class GStreamerRegistryScanner {
+ friend NeverDestroyed<GStreamerRegistryScanner>;
+public:
+ static GStreamerRegistryScanner& singleton();
+
+ HashSet<String, ASCIICaseInsensitiveHash>& mimeTypeSet() { return m_mimeTypeSet; }
+
+ bool isContainerTypeSupported(String containerType) const { return m_mimeTypeSet.contains(containerType); }
+
+ struct RegistryLookupResult {
+ bool isSupported;
+ bool isUsingHardware;
+
+ operator bool() const { return isSupported; }
+ };
+ RegistryLookupResult isDecodingSupported(MediaConfiguration&) const;
+
+ bool isCodecSupported(String codec, bool usingHardware = false) const;
+ bool areAllCodecsSupported(const Vector<String>& codecs, bool shouldCheckForHardwareUse = false) const;
+
+protected:
+ GStreamerRegistryScanner(bool isMediaSource = false);
+ ~GStreamerRegistryScanner();
+
+ void initialize();
+
+ enum ElementType {
+ AudioDecoder = 0,
+ VideoDecoder,
+ Demuxer
+ };
+ struct GstCapsWebKitMapping {
+ ElementType elementType;
+ const char* capsString;
+ Vector<AtomicString> webkitMimeTypes;
+ Vector<AtomicString> webkitCodecPatterns;
+ };
+ void fillMimeTypeSetFromCapsMapping(Vector<GstCapsWebKitMapping>&);
+
+ RegistryLookupResult hasElementForMediaType(GList* elementFactories, const char* capsString, bool shouldCheckHardwareClassifier = false);
+
+private:
+ bool m_isMediaSource;
+ GList* m_audioDecoderFactories;
+ GList* m_audioParserFactories;
+ GList* m_videoDecoderFactories;
+ GList* m_videoParserFactories;
+ GList* m_demuxerFactories;
+ HashSet<String, ASCIICaseInsensitiveHash> m_mimeTypeSet;
+ HashMap<AtomicString, bool> m_codecMap;
+};
+
+} // namespace WebCore
+
+#endif // USE(GSTREAMER)
Added: trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MediaEngineConfigurationFactoryGStreamer.h"
+
+#if USE(GSTREAMER)
+
+#include "GStreamerRegistryScanner.h"
+#include "MediaCapabilitiesInfo.h"
+#include "MediaDecodingConfiguration.h"
+#include "MediaPlayer.h"
+#include <wtf/Function.h>
+
+#if ENABLE(MEDIA_SOURCE)
+#include "GStreamerRegistryScannerMSE.h"
+#endif
+
+namespace WebCore {
+
+void createMediaPlayerDecodingConfigurationGStreamer(MediaDecodingConfiguration& configuration, WTF::Function<void(MediaCapabilitiesInfo&&)>&& callback)
+{
+ bool isMediaSource = configuration.type == MediaDecodingType::MediaSource;
+#if ENABLE(MEDIA_SOURCE)
+ auto& scanner = isMediaSource ? GStreamerRegistryScannerMSE::singleton() : GStreamerRegistryScanner::singleton();
+#else
+ if (isMediaSource) {
+ callback({ });
+ return;
+ }
+ auto& scanner = GStreamerRegistryScanner::singleton();
+#endif
+ auto lookupResult = scanner.isDecodingSupported(configuration);
+ MediaCapabilitiesInfo info;
+ info.supported = lookupResult.isSupported;
+ info.powerEfficient = lookupResult.isUsingHardware;
+
+ callback(WTFMove(info));
+}
+
+}
+#endif
Added: trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.h (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if USE(GSTREAMER)
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+struct MediaCapabilitiesInfo;
+struct MediaDecodingConfiguration;
+
+extern void createMediaPlayerDecodingConfigurationGStreamer(MediaDecodingConfiguration&, WTF::Function<void(MediaCapabilitiesInfo&&)>&&);
+
+}
+
+#endif
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -29,6 +29,7 @@
#if ENABLE(VIDEO) && USE(GSTREAMER)
#include "GStreamerCommon.h"
+#include "GStreamerRegistryScanner.h"
#include "HTTPHeaderNames.h"
#include "MIMETypeRegistry.h"
#include "MediaPlayer.h"
@@ -2229,137 +2230,10 @@
m_readyTimerHandler.stop();
}
-static HashSet<String, ASCIICaseInsensitiveHash>& mimeTypeSet()
-{
- static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> mimeTypes = []()
- {
- initializeGStreamerAndRegisterWebKitElements();
- HashSet<String, ASCIICaseInsensitiveHash> set;
-
- GList* audioDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
- GList* videoDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, GST_RANK_MARGINAL);
- GList* demuxerFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEMUXER, GST_RANK_MARGINAL);
-
- enum ElementType {
- AudioDecoder = 0,
- VideoDecoder,
- Demuxer
- };
- struct GstCapsWebKitMapping {
- ElementType elementType;
- const char* capsString;
- Vector<AtomicString> webkitMimeTypes;
- };
-
- Vector<GstCapsWebKitMapping> mapping = {
- {AudioDecoder, "audio/midi", {"audio/midi", "audio/riff-midi"}},
- {AudioDecoder, "audio/x-sbc", { }},
- {AudioDecoder, "audio/x-sid", { }},
- {AudioDecoder, "audio/x-flac", {"audio/x-flac", "audio/flac"}},
- {AudioDecoder, "audio/x-wav", {"audio/x-wav", "audio/wav", "audio/vnd.wave"}},
- {AudioDecoder, "audio/x-wavpack", {"audio/x-wavpack"}},
- {AudioDecoder, "audio/x-speex", {"audio/speex", "audio/x-speex"}},
- {AudioDecoder, "audio/x-ac3", { }},
- {AudioDecoder, "audio/x-eac3", {"audio/x-ac3"}},
- {AudioDecoder, "audio/x-dts", { }},
- {VideoDecoder, "video/x-h264, profile="" {"video/mp4", "video/x-m4v"}},
- {VideoDecoder, "video/x-msvideocodec", {"video/x-msvideo"}},
- {VideoDecoder, "video/x-h263", { }},
- {VideoDecoder, "video/mpegts", { }},
- {VideoDecoder, "video/mpeg, mpegversion=(int){1,2}, systemstream=(boolean)false", {"video/mpeg"}},
- {VideoDecoder, "video/x-dirac", { }},
- {VideoDecoder, "video/x-flash-video", {"video/flv", "video/x-flv"}},
- {Demuxer, "video/quicktime", { }},
- {Demuxer, "video/quicktime, variant=(string)3gpp", {"video/3gpp"}},
- {Demuxer, "application/x-3gp", { }},
- {Demuxer, "video/x-ms-asf", { }},
- {Demuxer, "audio/x-aiff", { }},
- {Demuxer, "application/x-pn-realaudio", { }},
- {Demuxer, "application/vnd.rn-realmedia", { }},
- {Demuxer, "audio/x-wav", {"audio/x-wav", "audio/wav", "audio/vnd.wave"}},
- {Demuxer, "application/x-hls", {"application/vnd.apple.mpegurl", "application/x-mpegurl"}}
- };
-
- for (auto& current : mapping) {
- GList* factories = demuxerFactories;
- if (current.elementType == AudioDecoder)
- factories = audioDecoderFactories;
- else if (current.elementType == VideoDecoder)
- factories = videoDecoderFactories;
-
- if (gstRegistryHasElementForMediaType(factories, current.capsString)) {
- if (!current.webkitMimeTypes.isEmpty()) {
- for (const auto& mimeType : current.webkitMimeTypes)
- set.add(mimeType);
- } else
- set.add(AtomicString(current.capsString));
- }
- }
-
- bool opusSupported = false;
- if (gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/x-opus")) {
- opusSupported = true;
- set.add(AtomicString("audio/opus"));
- }
-
- bool vorbisSupported = false;
- if (gstRegistryHasElementForMediaType(demuxerFactories, "application/ogg")) {
- set.add(AtomicString("application/ogg"));
-
- vorbisSupported = gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/x-vorbis");
- if (vorbisSupported) {
- set.add(AtomicString("audio/ogg"));
- set.add(AtomicString("audio/x-vorbis+ogg"));
- }
-
- if (gstRegistryHasElementForMediaType(videoDecoderFactories, "video/x-theora"))
- set.add(AtomicString("video/ogg"));
- }
-
- bool audioMpegSupported = false;
- if (gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/mpeg, mpegversion=(int)1, layer=(int)[1, 3]")) {
- audioMpegSupported = true;
- set.add(AtomicString("audio/mp1"));
- set.add(AtomicString("audio/mp3"));
- set.add(AtomicString("audio/x-mp3"));
- }
-
- if (gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/mpeg, mpegversion=(int){2, 4}")) {
- audioMpegSupported = true;
- set.add(AtomicString("audio/aac"));
- set.add(AtomicString("audio/mp2"));
- set.add(AtomicString("audio/mp4"));
- set.add(AtomicString("audio/x-m4a"));
- }
-
- if (audioMpegSupported) {
- set.add(AtomicString("audio/mpeg"));
- set.add(AtomicString("audio/x-mpeg"));
- }
-
- if (gstRegistryHasElementForMediaType(demuxerFactories, "video/x-matroska")) {
- set.add(AtomicString("video/x-matroska"));
-
- if (gstRegistryHasElementForMediaType(videoDecoderFactories, "video/x-vp8")
- || gstRegistryHasElementForMediaType(videoDecoderFactories, "video/x-vp9")
- || gstRegistryHasElementForMediaType(videoDecoderFactories, "video/x-vp10"))
- set.add(AtomicString("video/webm"));
-
- if (vorbisSupported || opusSupported)
- set.add(AtomicString("audio/webm"));
- }
-
- gst_plugin_feature_list_free(audioDecoderFactories);
- gst_plugin_feature_list_free(videoDecoderFactories);
- gst_plugin_feature_list_free(demuxerFactories);
- return set;
- }();
- return mimeTypes;
-}
-
void MediaPlayerPrivateGStreamer::getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>& types)
{
- types = mimeTypeSet();
+ auto& gstRegistryScanner = GStreamerRegistryScanner::singleton();
+ types = gstRegistryScanner.mimeTypeSet();
}
MediaPlayer::SupportsType MediaPlayerPrivateGStreamer::supportsType(const MediaEngineSupportParameters& parameters)
@@ -2379,30 +2253,18 @@
if (parameters.type.isEmpty())
return result;
- // Spec says we should not return "probably" if the codecs string is empty.
- if (mimeTypeSet().contains(parameters.type.containerType()))
- result = parameters.type.codecs().isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
-
+ GST_DEBUG("Checking mime-type \"%s\"", parameters.type.raw().utf8().data());
auto containerType = parameters.type.containerType();
- if (containerType == "video/mp4"_s || containerType == "video/webm"_s) {
- if (mimeTypeSet().contains(containerType)) {
- GList* videoDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, GST_RANK_MARGINAL);
- bool av1DecoderFound = gstRegistryHasElementForMediaType(videoDecoderFactories, "video/x-av1"_s);
- gst_plugin_feature_list_free(videoDecoderFactories);
- for (auto& codec : parameters.type.codecs()) {
- if (codec.startsWith("av01"_s)) {
- result = av1DecoderFound ? MediaPlayer::IsSupported : MediaPlayer::IsNotSupported;
- break;
- }
- if (codec.startsWith("av1"_s)) {
- result = MediaPlayer::IsNotSupported;
- break;
- }
- }
- }
+ auto& gstRegistryScanner = GStreamerRegistryScanner::singleton();
+ if (gstRegistryScanner.isContainerTypeSupported(containerType)) {
+ // Spec says we should not return "probably" if the codecs string is empty.
+ Vector<String> codecs = parameters.type.codecs();
+ result = codecs.isEmpty() ? MediaPlayer::MayBeSupported : (gstRegistryScanner.areAllCodecsSupported(codecs) ? MediaPlayer::IsSupported : MediaPlayer::IsNotSupported);
}
- return extendedSupportsType(parameters, result);
+ auto finalResult = extendedSupportsType(parameters, result);
+ GST_DEBUG("Supported: %s", convertEnumerationToString(finalResult).utf8().data());
+ return finalResult;
}
void MediaPlayerPrivateGStreamer::setDownloadBuffering()
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -27,6 +27,7 @@
#include "GStreamerCommon.h"
#include "GStreamerEMEUtilities.h"
#include "GStreamerMediaDescription.h"
+#include "GStreamerRegistryScannerMSE.h"
#include "MediaSampleGStreamer.h"
#include "InbandTextTrackPrivateGStreamer.h"
#include "MediaDescription.h"
@@ -141,7 +142,8 @@
}, this, nullptr);
const String& type = m_sourceBufferPrivate->type().containerType();
- if (type.endsWith("mp4"))
+ GST_DEBUG("SourceBuffer containerType: %s", type.utf8().data());
+ if (type.endsWith("mp4") || type.endsWith("aac"))
m_demux = gst_element_factory_make("qtdemux", nullptr);
else if (type.endsWith("webm"))
m_demux = gst_element_factory_make("matroskademux", nullptr);
@@ -379,7 +381,8 @@
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Unknown;
const char* originalMediaType = capsMediaType(m_demuxerSrcPadCaps.get());
- if (!MediaPlayerPrivateGStreamerMSE::supportsCodec(originalMediaType)) {
+ auto& gstRegistryScanner = GStreamerRegistryScannerMSE::singleton();
+ if (!gstRegistryScanner.isCodecSupported(originalMediaType)) {
m_presentationSize = WebCore::FloatSize();
m_streamType = WebCore::MediaSourceStreamTypeGStreamer::Invalid;
} else if (doCapsHaveType(m_demuxerSrcPadCaps.get(), GST_VIDEO_CAPS_TYPE_PREFIX)) {
Added: trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.cpp (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#if USE(GSTREAMER) && ENABLE(MEDIA_SOURCE)
+#include "GStreamerRegistryScannerMSE.h"
+
+#include <wtf/NeverDestroyed.h>
+
+namespace WebCore {
+
+GStreamerRegistryScannerMSE& GStreamerRegistryScannerMSE::singleton()
+{
+ static NeverDestroyed<GStreamerRegistryScannerMSE> sharedInstance;
+ return sharedInstance;
+}
+
+GStreamerRegistryScannerMSE::GStreamerRegistryScannerMSE()
+ : GStreamerRegistryScanner::GStreamerRegistryScanner(true)
+{
+}
+
+}
+#endif
Added: trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.h (0 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/GStreamerRegistryScannerMSE.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 Igalia S.L
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * aint with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if USE(GSTREAMER) && ENABLE(MEDIA_SOURCE)
+
+#include "GStreamerRegistryScanner.h"
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class GStreamerRegistryScannerMSE : public GStreamerRegistryScanner {
+ friend NeverDestroyed<GStreamerRegistryScannerMSE>;
+public:
+ static GStreamerRegistryScannerMSE& singleton();
+protected:
+ GStreamerRegistryScannerMSE();
+};
+
+} // namespace WebCore
+
+#endif // USE(GSTREAMER)
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -31,6 +31,7 @@
#include "AppendPipeline.h"
#include "AudioTrackPrivateGStreamer.h"
#include "GStreamerCommon.h"
+#include "GStreamerRegistryScannerMSE.h"
#include "InbandTextTrackPrivateGStreamer.h"
#include "MIMETypeRegistry.h"
#include "MediaDescription.h"
@@ -41,7 +42,6 @@
#include "TimeRanges.h"
#include "VideoTrackPrivateGStreamer.h"
-#include <fnmatch.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <gst/gst.h>
@@ -682,30 +682,6 @@
}
}
-static HashSet<String, ASCIICaseInsensitiveHash>& mimeTypeCache()
-{
- static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> cache = []()
- {
- initializeGStreamerAndRegisterWebKitElements();
- HashSet<String, ASCIICaseInsensitiveHash> set;
- const char* mimeTypes[] = {
- "video/mp4",
- "audio/mp4",
- "video/webm",
- "audio/webm"
- };
- for (auto& type : mimeTypes)
- set.add(type);
- return set;
- }();
- return cache;
-}
-
-void MediaPlayerPrivateGStreamerMSE::getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>& types)
-{
- types = mimeTypeCache();
-}
-
void MediaPlayerPrivateGStreamerMSE::trackDetected(RefPtr<AppendPipeline> appendPipeline, RefPtr<WebCore::TrackPrivateBase> newTrack, bool firstTrackDetected)
{
ASSERT(appendPipeline->track() == newTrack);
@@ -726,111 +702,12 @@
m_playbackPipeline->reattachTrack(appendPipeline->sourceBufferPrivate(), newTrack, caps);
}
-const static HashSet<AtomicString>& codecSet()
+void MediaPlayerPrivateGStreamerMSE::getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>& types)
{
- static NeverDestroyed<HashSet<AtomicString>> codecTypes = []()
- {
- initializeGStreamerAndRegisterWebKitElements();
- HashSet<AtomicString> set;
-
- GList* audioDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
- GList* videoDecoderFactories = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, GST_RANK_MARGINAL);
-
- enum ElementType {
- AudioDecoder = 0,
- VideoDecoder
- };
- struct GstCapsWebKitMapping {
- ElementType elementType;
- const char* capsString;
- Vector<AtomicString> webkitCodecs;
- };
-
- GstCapsWebKitMapping mapping[] = {
- { VideoDecoder, "video/x-h264, profile="" constrained-baseline, baseline }", { "x-h264", "avc*" } },
- { VideoDecoder, "video/mpeg, mpegversion=(int){1,2}, systemstream=(boolean)false", { "mpeg" } },
- { VideoDecoder, "video/x-vp8", { "vp8", "x-vp8" } },
- { VideoDecoder, "video/x-vp9", { "vp9", "x-vp9" } },
- { AudioDecoder, "audio/x-vorbis", { "vorbis", "x-vorbis" } },
- { AudioDecoder, "audio/x-opus", { "opus", "x-opus" } }
- };
-
- for (auto& current : mapping) {
- GList* factories = nullptr;
- switch (current.elementType) {
- case AudioDecoder:
- factories = audioDecoderFactories;
- break;
- case VideoDecoder:
- factories = videoDecoderFactories;
- break;
- default:
- g_assert_not_reached();
- break;
- }
-
- g_assert_nonnull(factories);
-
- if (gstRegistryHasElementForMediaType(factories, current.capsString) && factories != nullptr) {
- if (!current.webkitCodecs.isEmpty()) {
- for (const auto& mimeType : current.webkitCodecs)
- set.add(mimeType);
- } else
- set.add(AtomicString(current.capsString));
- }
- }
-
- bool audioMpegSupported = false;
- if (gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/mpeg, mpegversion=(int)1, layer=(int)[1, 3]")) {
- audioMpegSupported = true;
- set.add(AtomicString("audio/mp3"));
- }
-
- if (gstRegistryHasElementForMediaType(audioDecoderFactories, "audio/mpeg, mpegversion=(int){2, 4}")) {
- audioMpegSupported = true;
- set.add(AtomicString("mp4a*"));
- }
-
- if (audioMpegSupported) {
- set.add(AtomicString("audio/mpeg"));
- set.add(AtomicString("audio/x-mpeg"));
- }
-
-
- gst_plugin_feature_list_free(audioDecoderFactories);
- gst_plugin_feature_list_free(videoDecoderFactories);
-
- return set;
- }();
- return codecTypes;
+ auto& gstRegistryScanner = GStreamerRegistryScannerMSE::singleton();
+ types = gstRegistryScanner.mimeTypeSet();
}
-bool MediaPlayerPrivateGStreamerMSE::supportsCodec(String codec)
-{
- // If the codec is named like a mimetype (eg: video/avc) remove the "video/" part.
- size_t slashIndex = codec.find('/');
- if (slashIndex != WTF::notFound)
- codec = codec.substring(slashIndex+1);
-
- for (const auto& pattern : codecSet()) {
- bool codecMatchesPattern = !fnmatch(pattern.string().utf8().data(), codec.utf8().data(), 0);
- if (codecMatchesPattern)
- return true;
- }
-
- return false;
-}
-
-bool MediaPlayerPrivateGStreamerMSE::supportsAllCodecs(const Vector<String>& codecs)
-{
- for (String codec : codecs) {
- if (!supportsCodec(codec))
- return false;
- }
-
- return true;
-}
-
MediaPlayer::SupportsType MediaPlayerPrivateGStreamerMSE::supportsType(const MediaEngineSupportParameters& parameters)
{
MediaPlayer::SupportsType result = MediaPlayer::IsNotSupported;
@@ -842,19 +719,21 @@
// YouTube TV provides empty types for some videos and we want to be selected as best media engine for them.
if (containerType.isEmpty()) {
result = MediaPlayer::MayBeSupported;
+ GST_DEBUG("mime-type \"%s\" supported: %s", parameters.type.raw().utf8().data(), convertEnumerationToString(result).utf8().data());
return result;
}
+ GST_DEBUG("Checking mime-type \"%s\"", parameters.type.raw().utf8().data());
+ auto& gstRegistryScanner = GStreamerRegistryScannerMSE::singleton();
// Spec says we should not return "probably" if the codecs string is empty.
- if (mimeTypeCache().contains(containerType)) {
+ if (gstRegistryScanner.isContainerTypeSupported(containerType)) {
Vector<String> codecs = parameters.type.codecs();
- if (codecs.isEmpty())
- result = MediaPlayer::MayBeSupported;
- else
- result = supportsAllCodecs(codecs) ? MediaPlayer::IsSupported : MediaPlayer::IsNotSupported;
+ result = codecs.isEmpty() ? MediaPlayer::MayBeSupported : (gstRegistryScanner.areAllCodecsSupported(codecs) ? MediaPlayer::IsSupported : MediaPlayer::IsNotSupported);
}
- return extendedSupportsType(parameters, result);
+ auto finalResult = extendedSupportsType(parameters, result);
+ GST_DEBUG("Supported: %s", convertEnumerationToString(finalResult).utf8().data());
+ return finalResult;
}
void MediaPlayerPrivateGStreamerMSE::markEndOfStream(MediaSourcePrivate::EndOfStreamStatus status)
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h (241584 => 241585)
--- trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/mse/MediaPlayerPrivateGStreamerMSE.h 2019-02-15 14:24:21 UTC (rev 241585)
@@ -82,9 +82,6 @@
void trackDetected(RefPtr<AppendPipeline>, RefPtr<WebCore::TrackPrivateBase>, bool firstTrackDetected);
void notifySeekNeedsDataForTime(const MediaTime&);
- static bool supportsCodec(String codec);
- static bool supportsAllCodecs(const Vector<String>& codecs);
-
private:
static void getSupportedTypes(HashSet<String, ASCIICaseInsensitiveHash>&);
static MediaPlayer::SupportsType supportsType(const MediaEngineSupportParameters&);
Modified: trunk/Source/WebCore/platform/mediacapabilities/MediaEngineConfigurationFactory.cpp (241584 => 241585)
--- trunk/Source/WebCore/platform/mediacapabilities/MediaEngineConfigurationFactory.cpp 2019-02-15 13:49:48 UTC (rev 241584)
+++ trunk/Source/WebCore/platform/mediacapabilities/MediaEngineConfigurationFactory.cpp 2019-02-15 14:24:21 UTC (rev 241585)
@@ -39,6 +39,10 @@
#include "MediaEngineConfigurationFactoryCocoa.h"
#endif
+#if USE(GSTREAMER)
+#include "MediaEngineConfigurationFactoryGStreamer.h"
+#endif
+
namespace WebCore {
static bool& mockEnabled()
@@ -59,6 +63,9 @@
#if PLATFORM(COCOA)
{ &createMediaPlayerDecodingConfigurationCocoa, nullptr },
#endif
+#if USE(GSTREAMER)
+ { &createMediaPlayerDecodingConfigurationGStreamer, nullptr },
+#endif
}));
return factories;
}