From 7014015bf58ef40ad1b854acc105d62362bbb1c5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Wed, 17 Jul 2013 15:58:32 +0200 Subject: [PATCH] WebKitSourceGStreamer improved gstreamer 1.0 integration --- .../gstreamer/WebKitWebSourceGStreamer.cpp | 121 ++++++++++++++++----- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp index 4cc158d..7a4fd24 100644 --- a/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009, 2010 Sebastian Dröge + * Copyright (C) 2013 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,6 +24,7 @@ #include "Document.h" #include "Frame.h" +#include "FrameLoader.h" #include "GRefPtrGStreamer.h" #include "GStreamerVersioning.h" #include "MediaPlayer.h" @@ -32,10 +34,9 @@ #include "ResourceHandleInternal.h" #include "ResourceRequest.h" #include "ResourceResponse.h" - #include +#include #include - #include #include #include @@ -44,13 +45,16 @@ using namespace WebCore; class StreamingClient : public ResourceHandleClient { - WTF_MAKE_NONCOPYABLE(StreamingClient); + WTF_MAKE_NONCOPYABLE(StreamingClient); WTF_MAKE_FAST_ALLOCATED; public: StreamingClient(WebKitWebSrc*); virtual ~StreamingClient(); virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&); virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); + + virtual char* getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize); + virtual void didReceiveData(ResourceHandle*, const char*, int, int); virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/); virtual void didFail(ResourceHandle*, const ResourceError&); @@ -84,6 +88,8 @@ struct _WebKitWebSrcPrivate { guint enoughDataID; guint seekID; + GRefPtr buffer; + // icecast stuff gboolean iradioMode; gchar* iradioName; @@ -115,6 +121,7 @@ GST_DEBUG_CATEGORY_STATIC(webkit_web_src_debug); static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData); +static void webKitWebSrcDispose(GObject*); static void webKitWebSrcFinalize(GObject*); static void webKitWebSrcSetProperty(GObject*, guint propertyID, const GValue*, GParamSpec*); static void webKitWebSrcGetProperty(GObject*, guint propertyID, GValue*, GParamSpec*); @@ -150,6 +157,7 @@ static void webkit_web_src_class_init(WebKitWebSrcClass* klass) GObjectClass* oklass = G_OBJECT_CLASS(klass); GstElementClass* eklass = GST_ELEMENT_CLASS(klass); + oklass->dispose = webKitWebSrcDispose; oklass->finalize = webKitWebSrcFinalize; oklass->set_property = webKitWebSrcSetProperty; oklass->get_property = webKitWebSrcGetProperty; @@ -274,6 +282,21 @@ static void webkit_web_src_init(WebKitWebSrc* src) webKitWebSrcStop(src, false); } +static void webKitWebSrcDispose(GObject* object) +{ + WebKitWebSrc* src = WEBKIT_WEB_SRC(object); + WebKitWebSrcPrivate* priv = src->priv; + + if (priv->buffer) { +#ifdef GST_API_VERSION_1 + unmapGstBuffer(priv->buffer.get()); +#endif + priv->buffer.clear(); + } + + GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object)); +} + static void webKitWebSrcFinalize(GObject* object) { WebKitWebSrc* src = WEBKIT_WEB_SRC(object); @@ -283,7 +306,7 @@ static void webKitWebSrcFinalize(GObject* object) g_free(priv->uri); - GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject* )(src))); + GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); } static void webKitWebSrcSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* pspec) @@ -338,19 +361,29 @@ static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value } } + static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking) { WebKitWebSrcPrivate* priv = src->priv; + if (priv->resourceHandle) { priv->resourceHandle->cancel(); priv->resourceHandle.release(); } priv->resourceHandle = 0; + if (priv->frame && !seeking) priv->frame.clear(); priv->player = 0; + if (priv->buffer) { +#ifdef GST_API_VERSION_1 + unmapGstBuffer(priv->buffer.get()); +#endif + priv->buffer.clear(); + } + GST_OBJECT_LOCK(src); if (priv->needDataID) g_source_remove(priv->needDataID); @@ -431,6 +464,7 @@ static bool webKitWebSrcStart(WebKitWebSrc* src) val.set(g_strdup_printf("bytes=%" G_GUINT64_FORMAT "-", priv->requestedOffset)); request.setHTTPHeaderField("Range", val.get()); } + priv->offset = priv->requestedOffset; if (priv->iradioMode) request.setHTTPHeaderField("icy-metadata", "1"); @@ -443,6 +477,7 @@ static bool webKitWebSrcStart(WebKitWebSrc* src) GST_ERROR_OBJECT(src, "Failed to create ResourceHandle"); return false; } + GST_DEBUG_OBJECT(src, "Started request"); return true; @@ -625,7 +660,7 @@ static gboolean webKitWebSrcSetUri(GstURIHandler* handler, const gchar* uri) } #endif -static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer ifaceData) +static void webKitWebSrcUriHandlerInit(gpointer gIface, gpointer) { GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface; @@ -650,7 +685,7 @@ static gboolean webKitWebSrcNeedDataMainCb(WebKitWebSrc* src) return FALSE; } -static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer userData) +static void webKitWebSrcNeedDataCb(GstAppSrc*, guint length, gpointer userData) { WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); WebKitWebSrcPrivate* priv = src->priv; @@ -681,7 +716,7 @@ static gboolean webKitWebSrcEnoughDataMainCb(WebKitWebSrc* src) return FALSE; } -static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData) +static void webKitWebSrcEnoughDataCb(GstAppSrc*, gpointer userData) { WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); WebKitWebSrcPrivate* priv = src->priv; @@ -706,13 +741,13 @@ static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src) return FALSE; } -static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData) +static gboolean webKitWebSrcSeekDataCb(GstAppSrc*, guint64 offset, gpointer userData) { WebKitWebSrc* src = WEBKIT_WEB_SRC(userData); WebKitWebSrcPrivate* priv = src->priv; GST_DEBUG_OBJECT(src, "Seeking to offset: %" G_GUINT64_FORMAT, offset); - if (offset == priv->offset) + if (offset == priv->offset && priv->requestedOffset == priv->offset) return TRUE; if (!priv->seekable) @@ -757,7 +792,6 @@ StreamingClient::~StreamingClient() void StreamingClient::willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&) { - } void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) @@ -778,22 +812,20 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse if (length > 0) { length += priv->requestedOffset; gst_app_src_set_size(priv->appsrc, length); + +#ifndef GST_API_VERSION_1 if (!priv->haveAppSrc27) { -#ifdef GST_API_VERSION_1 - GstSegment* segment = &GST_BASE_SRC(priv->appsrc)->segment; - segment->duration = length; - segment->format = GST_FORMAT_BYTES; -#else gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length); -#endif gst_element_post_message(GST_ELEMENT(priv->appsrc), gst_message_new_duration(GST_OBJECT(priv->appsrc), GST_FORMAT_BYTES, length)); } +#endif } priv->size = length >= 0 ? length : 0; priv->seekable = length > 0 && g_ascii_strcasecmp("none", response.httpHeaderField("Accept-Ranges").utf8().data()); + // icecast stuff String value = response.httpHeaderField("icy-metaint"); if (!value.isEmpty()) { @@ -851,28 +883,45 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse notifyGstTagsOnPad(GST_ELEMENT(m_src), m_src->priv->srcpad, tags); } -void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int encodedDataLength) +void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, int length, int) { WebKitWebSrcPrivate* priv = m_src->priv; - GST_LOG_OBJECT(m_src, "Have %d bytes of data", length); + GST_LOG_OBJECT(m_src, "Have %d bytes of data", priv->buffer ? getGstBufferSize(priv->buffer.get()) : length); + + ASSERT(!priv->buffer || data == getGstBufferDataPointer(priv->buffer.get())); + +#ifdef GST_API_VERSION_1 + if (priv->buffer) + unmapGstBuffer(priv->buffer.get()); +#endif if (priv->seekID || handle != priv->resourceHandle) { GST_DEBUG_OBJECT(m_src, "Seek in progress, ignoring data"); + priv->buffer.clear(); return; } - GstBuffer* buffer = gst_buffer_new_and_alloc(length); -#ifdef GST_API_VERSION_1 - gst_buffer_fill(buffer, 0, data, length); -#else - memcpy(GST_BUFFER_DATA(buffer), data, length); -#endif - GST_BUFFER_OFFSET(buffer) = priv->offset; + // Ports using the GStreamer backend but not the soup implementation of ResourceHandle + // won't be using buffers provided by this client, the buffer is created here in that case. + if (!priv->buffer) + priv->buffer = adoptGRef(createGstBufferForData(data, length)); + else + setGstBufferSize(priv->buffer.get(), length); + + GST_BUFFER_OFFSET(priv->buffer.get()) = priv->offset; + if (priv->requestedOffset == priv->offset) + priv->requestedOffset += length; priv->offset += length; - GST_BUFFER_OFFSET_END(buffer) = priv->offset; + // priv->size == 0 if received length on didReceiveResponse < 0. + if (priv->size > 0 && priv->offset > priv->size) { + GST_DEBUG_OBJECT(m_src, "Updating internal size from %" G_GUINT64_FORMAT " to %" G_GUINT64_FORMAT, priv->size, priv->offset); + gst_app_src_set_size(priv->appsrc, priv->offset); + priv->size = priv->offset; + } + GST_BUFFER_OFFSET_END(priv->buffer.get()) = priv->offset; - GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, buffer); + GstFlowReturn ret = gst_app_src_push_buffer(priv->appsrc, priv->buffer.leakRef()); #ifdef GST_API_VERSION_1 if (ret != GST_FLOW_OK && ret != GST_FLOW_EOS) #else @@ -881,6 +930,24 @@ void StreamingClient::didReceiveData(ResourceHandle* handle, const char* data, i GST_ELEMENT_ERROR(m_src, CORE, FAILED, (0), (0)); } +char* StreamingClient::getOrCreateReadBuffer(size_t requestedSize, size_t& actualSize) +{ + WebKitWebSrcPrivate* priv = m_src->priv; + + ASSERT(!priv->buffer); + + GstBuffer* buffer = gst_buffer_new_and_alloc(requestedSize); + +#ifdef GST_API_VERSION_1 + mapGstBuffer(buffer); +#endif + + priv->buffer = adoptGRef(buffer); + + actualSize = getGstBufferSize(buffer); + return getGstBufferDataPointer(buffer); +} + void StreamingClient::didFinishLoading(ResourceHandle*, double) { WebKitWebSrcPrivate* priv = m_src->priv; -- 2.7.4