Diff
Modified: trunk/LayoutTests/ChangeLog (261921 => 261922)
--- trunk/LayoutTests/ChangeLog 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/LayoutTests/ChangeLog 2020-05-20 15:52:36 UTC (rev 261922)
@@ -1,3 +1,17 @@
+2020-05-20 Philippe Normand <[email protected]>
+
+ [GStreamer] <img> tag needs to support video formats
+ https://bugs.webkit.org/show_bug.cgi?id=180370
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ Update TestExpectations for tests using videos for the <img> tag.
+
+ * http/conf/flatpak-httpd.conf:
+ * platform/glib/TestExpectations:
+ * platform/gtk/TestExpectations:
+ * platform/wpe/TestExpectations:
+
2020-05-20 Alan Kinsley <[email protected]>
[LFC][TFC] Internal table boxes should take collapsed border into account
Modified: trunk/LayoutTests/http/conf/flatpak-httpd.conf (261921 => 261922)
--- trunk/LayoutTests/http/conf/flatpak-httpd.conf 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/LayoutTests/http/conf/flatpak-httpd.conf 2020-05-20 15:52:36 UTC (rev 261922)
@@ -52,8 +52,6 @@
UseCanonicalName On
HostnameLookups Off
-TypesConfig /usr/conf/mime.types
-
LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
Modified: trunk/LayoutTests/platform/glib/TestExpectations (261921 => 261922)
--- trunk/LayoutTests/platform/glib/TestExpectations 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/LayoutTests/platform/glib/TestExpectations 2020-05-20 15:52:36 UTC (rev 261922)
@@ -74,6 +74,8 @@
# 2. EXPECTED FAILURES
#////////////////////////////////////////////////////////////////////////////////////////
+webkit.org/b/211995 fast/images/animated-image-mp4.html [ Failure ]
+
#////////////////////////////////////////////////////////////////////////////////////////
# End of Expected Failures
#////////////////////////////////////////////////////////////////////////////////////////
Modified: trunk/LayoutTests/platform/gtk/TestExpectations (261921 => 261922)
--- trunk/LayoutTests/platform/gtk/TestExpectations 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/LayoutTests/platform/gtk/TestExpectations 2020-05-20 15:52:36 UTC (rev 261922)
@@ -1068,11 +1068,6 @@
webkit.org/b/175419 imported/w3c/web-platform-tests/background-fetch/interfaces.html [ Failure ]
webkit.org/b/175419 imported/w3c/web-platform-tests/fetch/api/abort/serviceworker-intercepted.https.html [ Failure Pass ]
-# Loading MP4 as an image is not supported by GTK
-webkit.org/b/180370 fast/images/animated-image-mp4.html [ Skip ]
-webkit.org/b/180370 http/tests/images/image-supports-video.html [ Skip ]
-webkit.org/b/180370 fast/images/animated-image-mp4-crash.html [ Skip ]
-
# GTK ought to support async clipboard
webkit.org/b/211979 editing/async-clipboard/clipboard-change-data-while-writing.html [ Failure ]
webkit.org/b/211979 editing/async-clipboard/clipboard-read-text-from-platform.html [ Failure ]
Modified: trunk/LayoutTests/platform/wpe/TestExpectations (261921 => 261922)
--- trunk/LayoutTests/platform/wpe/TestExpectations 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/LayoutTests/platform/wpe/TestExpectations 2020-05-20 15:52:36 UTC (rev 261922)
@@ -369,11 +369,6 @@
Bug(WPE) fast/hidpi/pdf-image-scaled.html [ Skip ]
-# Loading MP4 as an image is not supported
-webkit.org/b/180370 fast/images/animated-image-mp4.html [ Skip ]
-webkit.org/b/180370 fast/images/animated-image-mp4-crash.html [ Skip ]
-webkit.org/b/180370 http/tests/images/image-supports-video.html [ Skip ]
-
# Only Mac has implemented DictionaryLookup
fast/layers/prevent-hit-test-during-layout.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (261921 => 261922)
--- trunk/Source/WebCore/ChangeLog 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/ChangeLog 2020-05-20 15:52:36 UTC (rev 261922)
@@ -1,3 +1,56 @@
+2020-05-20 Philippe Normand <[email protected]>
+
+ [GStreamer] <img> tag needs to support video formats
+ https://bugs.webkit.org/show_bug.cgi?id=180370
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ GStreamer implementation of the ImageDecoder. It currently doesn't support zero-copy
+ rendering though due to the the NativeImagePtr requirement.
+
+ * platform/GStreamer.cmake:
+ * platform/MIMETypeRegistry.cpp:
+ (WebCore::MIMETypeRegistry::isSupportedImageVideoOrSVGMIMEType):
+ * platform/graphics/ImageDecoder.cpp:
+ (WebCore::ImageDecoder::create):
+ (WebCore::ImageDecoder::supportsMediaType):
+ * platform/graphics/gstreamer/ImageDecoderGStreamer.cpp: Added.
+ (WebCore::toSample):
+ (WebCore::ImageDecoderGStreamer::create):
+ (WebCore::ImageDecoderGStreamer::ImageDecoderGStreamer):
+ (WebCore::ImageDecoderGStreamer::supportsContainerType):
+ (WebCore::ImageDecoderGStreamer::canDecodeType):
+ (WebCore::ImageDecoderGStreamer::encodedDataStatus const):
+ (WebCore::ImageDecoderGStreamer::size const):
+ (WebCore::ImageDecoderGStreamer::repetitionCount const):
+ (WebCore::ImageDecoderGStreamer::uti const):
+ (WebCore::ImageDecoderGStreamer::frameOrientationAtIndex const):
+ (WebCore::ImageDecoderGStreamer::frameDurationAtIndex const):
+ (WebCore::ImageDecoderGStreamer::frameHasAlphaAtIndex const):
+ (WebCore::ImageDecoderGStreamer::frameBytesAtIndex const):
+ (WebCore::ImageDecoderGStreamer::createFrameImageAtIndex):
+ (WebCore::ImageDecoderGStreamer::setData):
+ (WebCore::ImageDecoderGStreamer::clearFrameBufferCache):
+ (WebCore::ImageDecoderGStreamer::sampleAtIndex const):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::decodebinPadAddedCallback):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::connectDecoderPad):
+ (WebCore::ImageDecoderGStreamer::handleSample):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::handleMessage):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::preparePipeline):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::run):
+ (WebCore::ImageDecoderGStreamer::InnerDecoder::encodedDataStatus const):
+ (WebCore::ImageDecoderGStreamer::pushEncodedData):
+ * platform/graphics/gstreamer/ImageDecoderGStreamer.h: Added.
+ * platform/graphics/gstreamer/ImageGStreamer.h:
+ (WebCore::ImageGStreamer::createImage):
+ (WebCore::ImageGStreamer::image):
+ (WebCore::ImageGStreamer::setCropRect):
+ (WebCore::ImageGStreamer::rect):
+ (WebCore::ImageGStreamer::hasAlpha const):
+ * platform/graphics/gstreamer/ImageGStreamerCairo.cpp:
+ (WebCore::ImageGStreamer::ImageGStreamer):
+ * platform/graphics/gstreamer/MediaSampleGStreamer.h:
+
2020-05-20 Andy Estes <[email protected]>
[Mac] UI processes spin when creating the "Share" context menu item
Modified: trunk/Source/WebCore/platform/GStreamer.cmake (261921 => 261922)
--- trunk/Source/WebCore/platform/GStreamer.cmake 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/GStreamer.cmake 2020-05-20 15:52:36 UTC (rev 261922)
@@ -13,6 +13,7 @@
platform/graphics/gstreamer/GstAllocatorFastMalloc.cpp
platform/graphics/gstreamer/GStreamerRegistryScanner.cpp
platform/graphics/gstreamer/GStreamerVideoFrameHolder.cpp
+ platform/graphics/gstreamer/ImageDecoderGStreamer.cpp
platform/graphics/gstreamer/InbandTextTrackPrivateGStreamer.cpp
platform/graphics/gstreamer/MediaEngineConfigurationFactoryGStreamer.cpp
platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp
Modified: trunk/Source/WebCore/platform/MIMETypeRegistry.cpp (261921 => 261922)
--- trunk/Source/WebCore/platform/MIMETypeRegistry.cpp 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/MIMETypeRegistry.cpp 2020-05-20 15:52:36 UTC (rev 261922)
@@ -58,6 +58,10 @@
#include "PreviewConverter.h"
#endif
+#if USE(GSTREAMER)
+#include "ImageDecoderGStreamer.h"
+#endif
+
namespace WebCore {
const HashSet<String, ASCIICaseInsensitiveHash>& MIMETypeRegistry::supportedImageMIMETypes()
@@ -436,6 +440,11 @@
return true;
#endif
+#if USE(GSTREAMER)
+ if (ImageDecoderGStreamer::supportsContainerType(mimeType))
+ return true;
+#endif
+
return false;
}
Modified: trunk/Source/WebCore/platform/graphics/ImageDecoder.cpp (261921 => 261922)
--- trunk/Source/WebCore/platform/graphics/ImageDecoder.cpp 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/graphics/ImageDecoder.cpp 2020-05-20 15:52:36 UTC (rev 261922)
@@ -38,6 +38,10 @@
#include "ImageDecoderAVFObjC.h"
#endif
+#if USE(GSTREAMER)
+#include "ImageDecoderGStreamer.h"
+#endif
+
namespace WebCore {
RefPtr<ImageDecoder> ImageDecoder::create(SharedBuffer& data, const String& mimeType, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
@@ -49,6 +53,11 @@
return ImageDecoderAVFObjC::create(data, mimeType, alphaOption, gammaAndColorProfileOption);
#endif
+#if USE(GSTREAMER)
+ if (ImageDecoderGStreamer::canDecodeType(mimeType))
+ return ImageDecoderGStreamer::create(data, mimeType, alphaOption, gammaAndColorProfileOption);
+#endif
+
#if USE(CG)
return ImageDecoderCG::create(data, alphaOption, gammaAndColorProfileOption);
#elif USE(DIRECT2D)
@@ -76,6 +85,11 @@
return true;
#endif
+#if USE(GSTREAMER)
+ if (ImageDecoderGStreamer::supportsMediaType(type))
+ return true;
+#endif
+
return false;
}
Added: trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp (0 => 261922)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.cpp 2020-05-20 15:52:36 UTC (rev 261922)
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2020 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 "ImageDecoderGStreamer.h"
+
+#if USE(GSTREAMER)
+
+#include "FloatSize.h"
+#include "GStreamerCommon.h"
+#include "GStreamerRegistryScanner.h"
+#include "ImageGStreamer.h"
+#include "MediaSampleGStreamer.h"
+#include "NotImplemented.h"
+#include <gst/app/gstappsink.h>
+#include <wtf/MainThread.h>
+#include <wtf/Optional.h>
+#include <wtf/Threading.h>
+
+namespace WebCore {
+
+GST_DEBUG_CATEGORY(webkit_image_decoder_debug);
+#define GST_CAT_DEFAULT webkit_image_decoder_debug
+
+class ImageDecoderGStreamerSample final : public MediaSampleGStreamer {
+public:
+ static Ref<ImageDecoderGStreamerSample> create(GRefPtr<GstSample>&& sample, const FloatSize& presentationSize)
+ {
+ return adoptRef(*new ImageDecoderGStreamerSample(WTFMove(sample), presentationSize));
+ }
+
+ NativeImagePtr image() const
+ {
+ if (!m_image)
+ return nullptr;
+ return m_image->image().nativeImage();
+ }
+ void dropImage() { m_image = nullptr; }
+
+ SampleFlags flags() const override
+ {
+ return (SampleFlags)(MediaSampleGStreamer::flags() | (m_image && m_image->hasAlpha() ? HasAlpha : 0));
+ }
+
+private:
+ ImageDecoderGStreamerSample(GRefPtr<GstSample>&& sample, const FloatSize& presentationSize)
+ : MediaSampleGStreamer(WTFMove(sample), presentationSize, { })
+ {
+ m_image = ImageGStreamer::createImage(platformSample().sample.gstSample);
+ }
+
+ RefPtr<ImageGStreamer> m_image;
+};
+
+static ImageDecoderGStreamerSample* toSample(const PresentationOrderSampleMap::value_type& pair)
+{
+ return (ImageDecoderGStreamerSample*)pair.second.get();
+}
+
+template <typename Iterator>
+ImageDecoderGStreamerSample* toSample(Iterator iter)
+{
+ return (ImageDecoderGStreamerSample*)iter->second.get();
+}
+
+RefPtr<ImageDecoderGStreamer> ImageDecoderGStreamer::create(SharedBuffer& data, const String& mimeType, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
+{
+ return adoptRef(*new ImageDecoderGStreamer(data, mimeType, alphaOption, gammaAndColorProfileOption));
+}
+
+ImageDecoderGStreamer::ImageDecoderGStreamer(SharedBuffer& data, const String& mimeType, AlphaOption, GammaAndColorProfileOption)
+ : m_mimeType(mimeType)
+{
+ static std::once_flag onceFlag;
+ std::call_once(onceFlag, [] {
+ GST_DEBUG_CATEGORY_INIT(webkit_image_decoder_debug, "webkitimagedecoder", 0, "WebKit image decoder");
+ });
+
+ pushEncodedData(data);
+}
+
+bool ImageDecoderGStreamer::supportsContainerType(const String& type)
+{
+ return GStreamerRegistryScanner::singleton().isContainerTypeSupported(type);
+}
+
+bool ImageDecoderGStreamer::canDecodeType(const String& mimeType)
+{
+ if (mimeType.isEmpty())
+ return false;
+
+ return GStreamerRegistryScanner::singleton().isContainerTypeSupported(mimeType);
+}
+
+EncodedDataStatus ImageDecoderGStreamer::encodedDataStatus() const
+{
+ if (m_eos)
+ return EncodedDataStatus::Complete;
+ if (m_size)
+ return EncodedDataStatus::SizeAvailable;
+ if (m_innerDecoder)
+ return m_innerDecoder->encodedDataStatus();
+ return EncodedDataStatus::Unknown;
+}
+
+IntSize ImageDecoderGStreamer::size() const
+{
+ if (m_size)
+ return m_size.value();
+ return { };
+}
+
+RepetitionCount ImageDecoderGStreamer::repetitionCount() const
+{
+ // In the absence of instructions to the contrary, assume all media formats repeat infinitely.
+ return frameCount() > 1 ? RepetitionCountInfinite : RepetitionCountNone;
+}
+
+String ImageDecoderGStreamer::uti() const
+{
+ notImplemented();
+ return { };
+}
+
+ImageOrientation ImageDecoderGStreamer::frameOrientationAtIndex(size_t) const
+{
+ notImplemented();
+ return ImageOrientation::None;
+}
+
+Seconds ImageDecoderGStreamer::frameDurationAtIndex(size_t index) const
+{
+ auto* sampleData = sampleAtIndex(index);
+ if (!sampleData)
+ return { };
+
+ return Seconds(sampleData->duration().toDouble());
+}
+
+bool ImageDecoderGStreamer::frameHasAlphaAtIndex(size_t index) const
+{
+ auto* sampleData = sampleAtIndex(index);
+ return sampleData ? sampleData->hasAlpha() : false;
+}
+
+unsigned ImageDecoderGStreamer::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
+{
+ if (!frameIsCompleteAtIndex(index))
+ return 0;
+
+ IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel);
+ return (frameSize.area() * 4).unsafeGet();
+}
+
+NativeImagePtr ImageDecoderGStreamer::createFrameImageAtIndex(size_t index, SubsamplingLevel, const DecodingOptions&)
+{
+ LockHolder holder { m_sampleGeneratorLock };
+
+ auto* sampleData = sampleAtIndex(index);
+ if (!sampleData)
+ return nullptr;
+
+ if (auto image = sampleData->image())
+ return image;
+
+ return nullptr;
+}
+
+void ImageDecoderGStreamer::setData(SharedBuffer& data, bool)
+{
+ pushEncodedData(data);
+}
+
+void ImageDecoderGStreamer::clearFrameBufferCache(size_t index)
+{
+ size_t i = 0;
+ for (auto& samplePair : m_sampleData.presentationOrder()) {
+ toSample(samplePair)->dropImage();
+ if (++i > index)
+ break;
+ }
+}
+
+const ImageDecoderGStreamerSample* ImageDecoderGStreamer::sampleAtIndex(size_t index) const
+{
+ if (index >= m_sampleData.presentationOrder().size())
+ return nullptr;
+
+ // FIXME: std::map is not random-accessible; this can get expensive if callers repeatedly call
+ // with monotonically increasing indexes. Investigate adding an O(1) side structure to make this
+ // style of access faster.
+ auto iter = m_sampleData.presentationOrder().begin();
+ for (size_t i = 0; i != index; ++i)
+ ++iter;
+
+ return toSample(iter);
+}
+
+void ImageDecoderGStreamer::InnerDecoder::decodebinPadAddedCallback(ImageDecoderGStreamer::InnerDecoder* decoder, GstPad* pad)
+{
+ decoder->connectDecoderPad(pad);
+}
+
+void ImageDecoderGStreamer::InnerDecoder::connectDecoderPad(GstPad* pad)
+{
+ auto padCaps = adoptGRef(gst_pad_get_current_caps(pad));
+ GST_DEBUG_OBJECT(m_pipeline.get(), "New decodebin pad %" GST_PTR_FORMAT " caps: %" GST_PTR_FORMAT, pad, padCaps.get());
+ RELEASE_ASSERT(doCapsHaveType(padCaps.get(), "video"));
+
+ GstElement* sink = gst_element_factory_make("appsink", nullptr);
+ static GstAppSinkCallbacks callbacks = {
+ nullptr,
+ [](GstAppSink* sink, gpointer userData) -> GstFlowReturn {
+ auto sample = adoptGRef(gst_app_sink_try_pull_preroll(sink, 0));
+ static_cast<ImageDecoderGStreamer*>(userData)->handleSample(WTFMove(sample));
+ return GST_FLOW_OK;
+ },
+ [](GstAppSink* sink, gpointer userData) -> GstFlowReturn {
+ auto sample = adoptGRef(gst_app_sink_try_pull_sample(sink, 0));
+ static_cast<ImageDecoderGStreamer*>(userData)->handleSample(WTFMove(sample));
+ return GST_FLOW_OK;
+ },
+ { nullptr }
+ };
+ gst_app_sink_set_callbacks(GST_APP_SINK(sink), &callbacks, m_decoder.get(), nullptr);
+
+ GRefPtr<GstCaps> caps = adoptGRef(gst_caps_from_string("video/x-raw, format=(string)RGBA"));
+ g_object_set(sink, "sync", false, "caps", caps.get(), nullptr);
+
+ GstElement* videoconvert = gst_element_factory_make("videoconvert", nullptr);
+
+ gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), videoconvert, sink, nullptr);
+ gst_element_link(videoconvert, sink);
+ auto sinkPad = adoptGRef(gst_element_get_static_pad(videoconvert, "sink"));
+ gst_pad_link(pad, sinkPad.get());
+ gst_element_sync_state_with_parent(videoconvert);
+ gst_element_sync_state_with_parent(sink);
+}
+
+void ImageDecoderGStreamer::handleSample(GRefPtr<GstSample>&& sample)
+{
+ auto* caps = gst_sample_get_caps(sample.get());
+ GST_DEBUG("Handling sample with caps %" GST_PTR_FORMAT, caps);
+ auto presentationSize = getVideoResolutionFromCaps(caps);
+ if (presentationSize && !presentationSize->isEmpty() && (!m_size || m_size != roundedIntSize(*presentationSize)))
+ m_size = roundedIntSize(*presentationSize);
+ m_sampleData.addSample(ImageDecoderGStreamerSample::create(WTFMove(sample), *m_size));
+}
+
+void ImageDecoderGStreamer::InnerDecoder::handleMessage(GstMessage* message)
+{
+ ASSERT(&m_runLoop == &RunLoop::current());
+
+ GUniqueOutPtr<GError> error;
+ GUniqueOutPtr<gchar> debug;
+
+ switch (GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_EOS:
+ gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
+ m_runLoop.stop();
+ break;
+ case GST_MESSAGE_WARNING:
+ gst_message_parse_warning(message, &error.outPtr(), &debug.outPtr());
+ g_warning("Warning: %d, %s. Debug output: %s", error->code, error->message, debug.get());
+ break;
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error(message, &error.outPtr(), &debug.outPtr());
+ g_warning("Error: %d, %s. Debug output: %s", error->code, error->message, debug.get());
+ gst_element_set_state(m_pipeline.get(), GST_STATE_NULL);
+ m_runLoop.stop();
+ break;
+ default:
+ break;
+ }
+}
+
+void ImageDecoderGStreamer::InnerDecoder::preparePipeline()
+{
+ static Atomic<uint32_t> pipelineId;
+ m_pipeline = gst_pipeline_new(makeString("image-decoder-", pipelineId.exchangeAdd(1)).utf8().data());
+
+ GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
+ ASSERT(bus);
+
+ gst_bus_set_sync_handler(bus.get(), [](GstBus*, GstMessage* message, gpointer userData) {
+ auto& decoder = *static_cast<ImageDecoderGStreamer::InnerDecoder*>(userData);
+ if (&decoder.m_runLoop == &RunLoop::current())
+ decoder.handleMessage(message);
+ else {
+ GRefPtr<GstMessage> protectedMessage(message);
+ auto weakThis = makeWeakPtr(decoder);
+ decoder.m_runLoop.dispatch([weakThis, protectedMessage] {
+ if (weakThis)
+ weakThis->handleMessage(protectedMessage.get());
+ });
+ }
+ gst_message_unref(message);
+ return GST_BUS_DROP;
+ }, this, nullptr);
+
+ GstElement* source = gst_element_factory_make("giostreamsrc", nullptr);
+ g_object_set(source, "stream", m_memoryStream.get(), nullptr);
+
+ GstElement* decoder = gst_element_factory_make("decodebin", nullptr);
+ auto allowedCaps = adoptGRef(gst_caps_new_empty_simple("video/x-raw"));
+ g_object_set(decoder, "caps", allowedCaps.get(), "expose-all-streams", false, nullptr);
+ g_signal_connect_swapped(decoder, "pad-added", G_CALLBACK(decodebinPadAddedCallback), this);
+
+ gst_bin_add_many(GST_BIN_CAST(m_pipeline.get()), source, decoder, nullptr);
+ gst_element_link(source, decoder);
+ gst_element_set_state(m_pipeline.get(), GST_STATE_PLAYING);
+}
+
+void ImageDecoderGStreamer::InnerDecoder::run()
+{
+ m_runLoop.dispatch([this]() {
+ preparePipeline();
+ });
+
+ m_runLoop.run();
+}
+
+EncodedDataStatus ImageDecoderGStreamer::InnerDecoder::encodedDataStatus() const
+{
+ GstState state;
+ gst_element_get_state(m_pipeline.get(), &state, nullptr, 0);
+ if (state >= GST_STATE_READY)
+ return EncodedDataStatus::TypeAvailable;
+ return EncodedDataStatus::Unknown;
+}
+
+void ImageDecoderGStreamer::pushEncodedData(const SharedBuffer& buffer)
+{
+ m_eos = false;
+ auto thread = Thread::create("ImageDecoderGStreamer", [this, data = "" size = buffer.size()] {
+ m_innerDecoder = ImageDecoderGStreamer::InnerDecoder::create(*this, data, size);
+ m_innerDecoder->run();
+ });
+ thread->waitForCompletion();
+ m_eos = true;
+ m_innerDecoder = nullptr;
+ callOnMainThread([this] {
+ if (m_encodedDataStatusChangedCallback)
+ m_encodedDataStatusChangedCallback(encodedDataStatus());
+ });
+}
+
+}
+#endif
Added: trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.h (0 => 261922)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageDecoderGStreamer.h 2020-05-20 15:52:36 UTC (rev 261922)
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2020 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 "GRefPtrGStreamer.h"
+#include "ImageDecoder.h"
+#include "MIMETypeRegistry.h"
+#include "SampleMap.h"
+#include "SharedBuffer.h"
+#include <wtf/Forward.h>
+#include <wtf/RunLoop.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class ContentType;
+class ImageDecoderGStreamerSample;
+
+class ImageDecoderGStreamer final : public ImageDecoder, public CanMakeWeakPtr<ImageDecoderGStreamer> {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(ImageDecoderGStreamer);
+public:
+ static RefPtr<ImageDecoderGStreamer> create(SharedBuffer&, const String& mimeType, AlphaOption, GammaAndColorProfileOption);
+ ImageDecoderGStreamer(SharedBuffer&, const String& mimeType, AlphaOption, GammaAndColorProfileOption);
+ virtual ~ImageDecoderGStreamer() = default;
+
+ static bool supportsMediaType(MediaType type) { return type == MediaType::Video; }
+ static bool supportsContainerType(const String&);
+
+ size_t bytesDecodedToDetermineProperties() const override { return 0; }
+ static bool canDecodeType(const String& mimeType);
+
+ void setEncodedDataStatusChangeCallback(WTF::Function<void(EncodedDataStatus)>&& callback) final { m_encodedDataStatusChangedCallback = WTFMove(callback); }
+ EncodedDataStatus encodedDataStatus() const final;
+ IntSize size() const final;
+ size_t frameCount() const final { return m_sampleData.size(); }
+ RepetitionCount repetitionCount() const final;
+ String uti() const final;
+ String filenameExtension() const final { return MIMETypeRegistry::getPreferredExtensionForMIMEType(m_mimeType); }
+ Optional<IntPoint> hotSpot() const final { return WTF::nullopt; }
+
+ IntSize frameSizeAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const final { return size(); }
+ bool frameIsCompleteAtIndex(size_t index) const final { return sampleAtIndex(index); }
+ ImageOrientation frameOrientationAtIndex(size_t) const final;
+
+ Seconds frameDurationAtIndex(size_t) const final;
+ bool frameHasAlphaAtIndex(size_t) const final;
+ bool frameAllowSubsamplingAtIndex(size_t index) const final { return index <= m_sampleData.size(); }
+ unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const final;
+
+ NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const DecodingOptions& = DecodingOptions(DecodingMode::Synchronous)) final;
+
+ void setExpectedContentSize(long long) final { }
+ void setData(SharedBuffer&, bool allDataReceived) final;
+ bool isAllDataReceived() const final { return m_eos; }
+ void clearFrameBufferCache(size_t) final;
+
+private:
+ class InnerDecoder : public ThreadSafeRefCounted<InnerDecoder>, public CanMakeWeakPtr<InnerDecoder> {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(InnerDecoder);
+ public:
+ static RefPtr<InnerDecoder> create(ImageDecoderGStreamer& decoder, const char* data, gssize size)
+ {
+ return adoptRef(*new InnerDecoder(decoder, data, size));
+ }
+
+ InnerDecoder(ImageDecoderGStreamer& decoder, const char* data, gssize size)
+ : m_decoder(makeWeakPtr(decoder))
+ , m_runLoop(RunLoop::current())
+ {
+ m_memoryStream = adoptGRef(g_memory_input_stream_new_from_data(data, size, nullptr));
+ }
+
+ void run();
+ EncodedDataStatus encodedDataStatus() const;
+
+ private :
+ static void decodebinPadAddedCallback(ImageDecoderGStreamer::InnerDecoder*, GstPad*);
+ void handleMessage(GstMessage*);
+ void preparePipeline();
+ void connectDecoderPad(GstPad*);
+
+ WeakPtr<ImageDecoderGStreamer> m_decoder;
+ GRefPtr<GstElement> m_pipeline;
+ GRefPtr<GInputStream> m_memoryStream;
+ RunLoop& m_runLoop;
+ };
+
+ void handleSample(GRefPtr<GstSample>&&);
+ void pushEncodedData(const SharedBuffer&);
+
+ const ImageDecoderGStreamerSample* sampleAtIndex(size_t) const;
+
+ WTF::Function<void(EncodedDataStatus)> m_encodedDataStatusChangedCallback;
+ SampleMap m_sampleData;
+ DecodeOrderSampleMap::iterator m_cursor;
+ Lock m_sampleGeneratorLock;
+ bool m_eos { false };
+ Optional<IntSize> m_size;
+ String m_mimeType;
+ RefPtr<ImageDecoderGStreamer::InnerDecoder> m_innerDecoder;
+};
+
+}
+#endif
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h (261921 => 261922)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamer.h 2020-05-20 15:52:36 UTC (rev 261922)
@@ -17,8 +17,7 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef ImageGStreamer_h
-#define ImageGStreamer_h
+#pragma once
#if ENABLE(VIDEO) && USE(GSTREAMER)
@@ -37,42 +36,44 @@
class IntSize;
class ImageGStreamer : public RefCounted<ImageGStreamer> {
- public:
- static RefPtr<ImageGStreamer> createImage(GstSample* sample)
- {
- auto image = adoptRef(new ImageGStreamer(sample));
- if (!image->m_image)
- return nullptr;
+public:
+ static RefPtr<ImageGStreamer> createImage(GstSample* sample)
+ {
+ auto image = adoptRef(new ImageGStreamer(sample));
+ if (!image->m_image)
+ return nullptr;
- return image;
- }
- ~ImageGStreamer();
+ return image;
+ }
+ ~ImageGStreamer();
- BitmapImage& image()
- {
- ASSERT(m_image);
- return *m_image.get();
- }
+ BitmapImage& image()
+ {
+ ASSERT(m_image);
+ return *m_image.get();
+ }
- void setCropRect(FloatRect rect) { m_cropRect = rect; }
- FloatRect rect()
- {
- ASSERT(m_image);
- if (!m_cropRect.isEmpty())
- return FloatRect(m_cropRect);
- return FloatRect(0, 0, m_image->size().width(), m_image->size().height());
- }
+ void setCropRect(FloatRect rect) { m_cropRect = rect; }
+ FloatRect rect()
+ {
+ ASSERT(m_image);
+ if (!m_cropRect.isEmpty())
+ return FloatRect(m_cropRect);
+ return FloatRect(0, 0, m_image->size().width(), m_image->size().height());
+ }
- private:
- ImageGStreamer(GstSample*);
- RefPtr<BitmapImage> m_image;
- FloatRect m_cropRect;
+ bool hasAlpha() const { return m_hasAlpha; }
+
+private:
+ ImageGStreamer(GstSample*);
+ RefPtr<BitmapImage> m_image;
+ FloatRect m_cropRect;
#if USE(CAIRO)
- GstVideoFrame m_videoFrame;
- bool m_frameMapped { false };
+ GstVideoFrame m_videoFrame;
+ bool m_frameMapped { false };
#endif
- };
+ bool m_hasAlpha { false };
+};
+
}
-
-#endif // USE(GSTREAMER)
-#endif
+#endif // ENABLE(VIDEO) && USE(GSTREAMER)
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp (261921 => 261922)
--- trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/ImageGStreamerCairo.cpp 2020-05-20 15:52:36 UTC (rev 261922)
@@ -42,6 +42,8 @@
// Right now the TextureMapper only supports chromas with one plane
ASSERT(GST_VIDEO_INFO_N_PLANES(&videoInfo) == 1);
+ m_hasAlpha = GST_VIDEO_INFO_HAS_ALPHA(&videoInfo);
+
GstBuffer* buffer = gst_sample_get_buffer(sample);
if (UNLIKELY(!GST_IS_BUFFER(buffer)))
return;
Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h (261921 => 261922)
--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h 2020-05-20 15:43:19 UTC (rev 261921)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h 2020-05-20 15:52:36 UTC (rev 261922)
@@ -29,7 +29,7 @@
namespace WebCore {
-class MediaSampleGStreamer final : public MediaSample {
+class MediaSampleGStreamer : public MediaSample {
public:
static Ref<MediaSampleGStreamer> create(GRefPtr<GstSample>&& sample, const FloatSize& presentationSize, const AtomString& trackId)
{
@@ -55,11 +55,13 @@
PlatformSample platformSample() override;
void dump(PrintStream&) const override;
-private:
+protected:
MediaSampleGStreamer(GRefPtr<GstSample>&&, const FloatSize& presentationSize, const AtomString& trackId);
- MediaSampleGStreamer(const FloatSize& presentationSize, const AtomString& trackId);
virtual ~MediaSampleGStreamer() = default;
+private:
+ MediaSampleGStreamer(const FloatSize& presentationSize, const AtomString& trackId);
+
MediaTime m_pts;
MediaTime m_dts;
MediaTime m_duration;