From 120c49401838ccf14eb39fbb36e238a0c6965c9b Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Wed, 30 Sep 2009 10:51:08 +0200 Subject: [PATCH] GTK: data: uris support in media player --- ChangeLog | 11 + LayoutTests/ChangeLog | 11 + LayoutTests/platform/gtk/Skipped | 1 - WebCore/ChangeLog | 30 +++ WebCore/GNUmakefile.am | 7 +- .../platform/graphics/gtk/DataSourceGStreamer.cpp | 267 ++++++++++++++++++++ .../platform/graphics/gtk/DataSourceGStreamer.h | 54 ++++ .../graphics/gtk/MediaPlayerPrivateGStreamer.cpp | 24 ++- configure.ac | 1 + 9 files changed, 394 insertions(+), 12 deletions(-) create mode 100644 WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp create mode 100644 WebCore/platform/graphics/gtk/DataSourceGStreamer.h diff --git a/ChangeLog b/ChangeLog index e2c1ef5..94cf2e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2009-09-30 Philippe Normand + + Reviewed by NOBODY (OOPS!). + + [GTK] data: uri support in media player + https://bugs.webkit.org/show_bug.cgi?id=29842 + + Check presence of gstreamer-pbutils-0.10. + + * configure.ac: + 2009-09-26 David Kilzer GTK BUILD FIX: add ENABLE_ORIENTATION_EVENTS support to configure.ac diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index a5aa373..6cde74b 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,14 @@ +2009-09-30 Philippe Normand + + Reviewed by NOBODY (OOPS!). + + [GTK] data: uri support in media player + https://bugs.webkit.org/show_bug.cgi?id=29842 + + Re-enable media/audio-data-url.html. + + * platform/gtk/Skipped: + 2009-09-29 Shinichiro Hamaji Reviewed by Eric Seidel. diff --git a/LayoutTests/platform/gtk/Skipped b/LayoutTests/platform/gtk/Skipped index 36620ff..ef65b41 100644 --- a/LayoutTests/platform/gtk/Skipped +++ b/LayoutTests/platform/gtk/Skipped @@ -3804,7 +3804,6 @@ media/video-controls-transformed.html media/video-controls-zoomed.html media/video-size-intrinsic-scale.html # Tests timing out -media/audio-data-url.html media/controls-drag-timebar.html media/event-attributes.html media/unsupported-rtsp.html diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog index aacc3dc..3d4411d 100644 --- a/WebCore/ChangeLog +++ b/WebCore/ChangeLog @@ -1,3 +1,33 @@ +2009-09-30 Philippe Normand + + Reviewed by NOBODY (OOPS!). + + [GTK] data: uri support in media player + https://bugs.webkit.org/show_bug.cgi?id=29842 + + New GStreamer element to handle data: uris. For now only base64 + encoded data is supported. Decoded data is handed over to + giostreamsrc. + + * GNUmakefile.am: + * platform/graphics/gtk/DataSourceGStreamer.cpp: Added. + (_do_init): + (webkit_data_src_base_init): + (webkit_data_src_class_init): + (webkit_data_src_reset): + (webkit_data_src_init): + (webkit_data_src_finalize): + (webkit_data_src_uri_get_type): + (webkit_data_src_uri_get_protocols): + (webkit_data_src_uri_get_uri): + (webkit_data_src_uri_set_uri): + (webkit_data_src_uri_handler_init): + * platform/graphics/gtk/DataSourceGStreamer.h: Added. + * platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp: + (WebCore::do_gst_init): + (WebCore::MediaPlayerPrivate::MediaPlayerPrivate): + (WebCore::MediaPlayerPrivate::mimeTypeCache): + 2009-09-29 Dave Hyatt Reviewed by Jon Honeycutt. diff --git a/WebCore/GNUmakefile.am b/WebCore/GNUmakefile.am index 6060851..5169e5f 100644 --- a/WebCore/GNUmakefile.am +++ b/WebCore/GNUmakefile.am @@ -2315,11 +2315,14 @@ webcoregtk_sources += \ WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp \ WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h \ WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp \ - WebCore/platform/graphics/gtk/VideoSinkGStreamer.h + WebCore/platform/graphics/gtk/VideoSinkGStreamer.h \ + WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp \ + WebCore/platform/graphics/gtk/DataSourceGstreamer.h webcore_libadd += \ -lgstinterfaces-0.10 \ - -lgstvideo-0.10 + -lgstvideo-0.10 \ + -lgstpbutils-0.10 endif # END ENABLE_VIDEO diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp new file mode 100644 index 0000000..7fe8cd6 --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2009 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DataSourceGStreamer.h" + +#include +#include +#include +#include + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +GST_DEBUG_CATEGORY_STATIC(webkit_data_src_debug); +#define GST_CAT_DEFAULT webkit_data_src_debug + +static void webkit_data_src_uri_handler_init(gpointer g_iface, + gpointer iface_data); + +static void webkit_data_src_dispose(GObject* object); +static void webkit_data_src_finalize(WebkitDataSrc* src); +static GstStateChangeReturn webkit_data_src_change_state(GstElement* element, + GstStateChange transition); + +static const GInterfaceInfo urihandler_info = { + webkit_data_src_uri_handler_init, + 0, 0 +}; + + +static void +_do_init(GType datasrc_type) +{ + GST_DEBUG_CATEGORY_INIT(webkit_data_src_debug, "webkit_data_src", 0, "datasrc element"); + g_type_add_interface_static(datasrc_type, GST_TYPE_URI_HANDLER, + &urihandler_info); +} + +GST_BOILERPLATE_FULL(WebkitDataSrc, webkit_data_src, GstBin, GST_TYPE_BIN, _do_init); + +static void +webkit_data_src_base_init(gpointer klass) +{ + GstElementClass* element_class = GST_ELEMENT_CLASS(klass); + + gst_element_class_add_pad_template(element_class, + gst_static_pad_template_get(&src_template)); + gst_element_class_set_details_simple(element_class, (gchar*) "WebKit data source element", + (gchar*) "Source", + (gchar*) "Handles data: uris", + (gchar*) "Philippe Normand "); + +} + +static void +webkit_data_src_class_init(WebkitDataSrcClass* klass) +{ + GObjectClass* oklass = G_OBJECT_CLASS(klass); + GstElementClass* eklass = GST_ELEMENT_CLASS(klass); + + oklass->finalize = (GObjectFinalizeFunc) webkit_data_src_finalize; + eklass->change_state = webkit_data_src_change_state; +} + + +static gboolean +webkit_data_src_reset(WebkitDataSrc* src) +{ + GstPad* targetpad; + + if (src->kid) { + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + } + + src->kid = gst_element_factory_make("giostreamsrc", "streamsrc"); + if (!src->kid) { + GST_ERROR_OBJECT(src, "Failed to create giostreamsrc"); + return FALSE; + } + + gst_bin_add(GST_BIN(src), src->kid); + + targetpad = gst_element_get_static_pad(src->kid, "src"); + gst_ghost_pad_set_target(GST_GHOST_PAD(src->pad), targetpad); + gst_object_unref(targetpad); + + return TRUE; +} + +static void +webkit_data_src_init(WebkitDataSrc* src, + WebkitDataSrcClass* g_class) +{ + GstPadTemplate* pad_template = gst_static_pad_template_get(&src_template); + src->pad = gst_ghost_pad_new_no_target_from_template("src", + pad_template); + + gst_element_add_pad(GST_ELEMENT(src), src->pad); + + webkit_data_src_reset(src); +} + +static void +webkit_data_src_finalize(WebkitDataSrc* src) +{ + g_free(src->uri); + + if (src->kid) { + GST_DEBUG_OBJECT(src, "Removing giostreamsrc element"); + gst_element_set_state(src->kid, GST_STATE_NULL); + gst_bin_remove(GST_BIN(src), src->kid); + src->kid = 0; + } + + GST_CALL_PARENT(G_OBJECT_CLASS, finalize, ((GObject *)(src))); +} + +static GstStateChangeReturn +webkit_data_src_change_state(GstElement* element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + WebkitDataSrc* src = WEBKIT_DATA_SRC(element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + if (!src->kid) { + gst_element_post_message(element, + gst_missing_element_message_new(element, "giostreamsrc")); + GST_ELEMENT_ERROR(src, CORE, MISSING_PLUGIN, (0), ("no giostreamsrc!")); + return GST_STATE_CHANGE_FAILURE; + } + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + default: + break; + } + + { + ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); + if (G_UNLIKELY(ret == GST_STATE_CHANGE_FAILURE)) + return ret; + } + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + case GST_STATE_CHANGE_PAUSED_TO_READY: + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + +/*** GSTURIHANDLER INTERFACE *************************************************/ + +static GstURIType +webkit_data_src_uri_get_type(void) +{ + return GST_URI_SRC; +} + +static gchar ** +webkit_data_src_uri_get_protocols(void) +{ + static gchar* protocols[] = {(gchar*) "data", 0 }; + + return protocols; +} + +static const gchar * +webkit_data_src_uri_get_uri(GstURIHandler* handler) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + return src->uri; +} + +static gboolean +webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar* uri) +{ + WebkitDataSrc* src = WEBKIT_DATA_SRC(handler); + + // URI as defined in RFC2397: + // "data:" [ mediatype ] [ ";base64" ] "," data + // we parse URIs like this one: + // data:audio/3gpp;base64,AA... + + gchar** scheme_and_remains = g_strsplit(uri, ":", 2); + gchar** mime_type_and_options = g_strsplit(scheme_and_remains[1], ";", 0); + gint options_size = g_strv_length(mime_type_and_options); + gchar* data = 0; + gchar* mime_type = 0; + gint ret = FALSE; + + // we require uris with a specified mime-type and base64-encoded + // data. It doesn't make much sense anyway to play plain/text data + // with very few allowed characters (as per the RFC). + + if (GST_STATE(src) >= GST_STATE_PAUSED) { + GST_ERROR_OBJECT(src, "Element already configured. Reset it and retry"); + } else if (!options_size) + GST_ERROR_OBJECT(src, "A mime-type is needed in %s", uri); + else { + mime_type = mime_type_and_options[0]; + data = mime_type_and_options[options_size-1]; + + guchar* decoded_data = 0; + gsize decoded_size; + + if (!g_str_has_prefix(data, "base64")) + GST_ERROR_OBJECT(src, "Data has to be base64-encoded in %s", uri); + else { + decoded_data = g_base64_decode(data+7, &decoded_size); + GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data, + decoded_size, + g_free); + g_object_set(src->kid, "stream", stream, 0); + g_object_unref(stream); + + if (src->uri) { + g_free(src->uri); + src->uri = 0; + } + + src->uri = g_strdup(uri); + ret = TRUE; + } + } + + g_strfreev(scheme_and_remains); + g_strfreev(mime_type_and_options); + return ret; +} + +static void +webkit_data_src_uri_handler_init(gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface* iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = webkit_data_src_uri_get_type; + iface->get_protocols = webkit_data_src_uri_get_protocols; + iface->get_uri = webkit_data_src_uri_get_uri; + iface->set_uri = webkit_data_src_uri_set_uri; +} diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.h b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h new file mode 100644 index 0000000..a9532fe --- /dev/null +++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DATA_SOURCE_GSTREAMER_H +#define DATA_SOURCE_GSTREAMER_H + +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_DATA_SRC (webkit_data_src_get_type ()) +#define WEBKIT_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), WEBKIT_TYPE_DATA_SRC, WebkitDataSrc)) +#define WEBKIT_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), WEBKIT_TYPE_DATA_SRC, WebkitDataSrcClass)) +#define WEBKIT_IS_DATA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WEBKIT_TYPE_DATA_SRC)) +#define WEBKIT_IS_DATA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WEBKIT_TYPE_DATA_SRC)) + +typedef struct _WebkitDataSrc WebkitDataSrc; +typedef struct _WebkitDataSrcClass WebkitDataSrcClass; + + +struct _WebkitDataSrc { + GstBin parent; + + /* explicit pointers to stuff used */ + GstElement* kid; + GstPad* pad; + gchar* uri; +}; + +struct _WebkitDataSrcClass { + GstBinClass parent_class; +}; + +GType webkit_data_src_get_type(void); + +G_END_DECLS + +#endif diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp index 00d8242..64c41d1 100644 --- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -25,6 +25,7 @@ #if ENABLE(VIDEO) #include "MediaPlayerPrivateGStreamer.h" +#include "DataSourceGStreamer.h" #include "CString.h" #include "GraphicsContext.h" @@ -122,6 +123,17 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) static bool gstInitialized = false; +static void do_gst_init() { + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + gst_init(0, 0); + gstInitialized = true; + gst_element_register(0, "webkitmediasrc", GST_RANK_PRIMARY, + WEBKIT_TYPE_DATA_SRC); + + } +} + MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_playBin(0) @@ -140,11 +152,7 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) , m_seeking(false) , m_errorOccured(false) { - // FIXME: We should pass the arguments from the command line - if (!gstInitialized) { - gst_init(0, 0); - gstInitialized = true; - } + do_gst_init(); // FIXME: The size shouldn't be fixed here, this is just a quick hack. m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); @@ -652,10 +660,8 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) static HashSet mimeTypeCache() { - if (!gstInitialized) { - gst_init(0, NULL); - gstInitialized = true; - } + + do_gst_init(); static HashSet cache; static bool typeListInitialized = false; diff --git a/configure.ac b/configure.ac index a65c65d..1096dc4 100644 --- a/configure.ac +++ b/configure.ac @@ -680,6 +680,7 @@ if test "$enable_video" = "yes"; then PKG_CHECK_MODULES([GSTREAMER], [gstreamer-0.10 >= $GSTREAMER_REQUIRED_VERSION gstreamer-base-0.10 + gstreamer-pbutils-0.10 gstreamer-plugins-base-0.10 gstreamer-video-0.10]) AC_SUBST([GSTREAMER_CFLAGS]) -- 1.6.0.4