3 * Copyright (C) 2009 Igalia S.L
4 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:element-dataurisrc
25 * dataurisrc handles data: URIs, see <ulink url="http://tools.ietf.org/html/rfc2397">RFC 2397</ulink> for more information.
28 * <title>Example launch line</title>
30 * gst-launch-0.10 -v dataurisrc uri="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAfElEQVQ4je2MwQnAIAxFgziA4EnczIsO4MEROo/gzZWc4xdTbe1R6LGRR74heYS7iKElzfcMiRnt4hf8gk8EayB6luefue/HzlJfCA50XsNjYRxprZmenXNIKSGEsC+QUqK1hhgj521BzhnWWiilUGvdF5RS4L2HMQZCCJy8sHMm2TYdJAAAAABJRU5ErkJggg==" ! pngdec ! ffmpegcolorspace ! freeze ! ffmpegcolorspace ! autovideosink
31 * ]| This pipeline displays a small 16x16 PNG image from the data URI.
39 #include "gstdataurisrc.h"
42 #include <gst/base/gsttypefindhelper.h>
44 GST_DEBUG_CATEGORY (data_uri_src_debug);
45 #define GST_CAT_DEFAULT (data_uri_src_debug)
47 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
58 static void gst_data_uri_src_finalize (GObject * object);
59 static void gst_data_uri_src_set_property (GObject * object,
60 guint prop_id, const GValue * value, GParamSpec * pspec);
61 static void gst_data_uri_src_get_property (GObject * object,
62 guint prop_id, GValue * value, GParamSpec * pspec);
64 static GstCaps *gst_data_uri_src_get_caps (GstBaseSrc * src);
65 static gboolean gst_data_uri_src_get_size (GstBaseSrc * src, guint64 * size);
66 static gboolean gst_data_uri_src_is_seekable (GstBaseSrc * src);
67 static GstFlowReturn gst_data_uri_src_create (GstBaseSrc * src, guint64 offset,
68 guint size, GstBuffer ** buf);
69 static gboolean gst_data_uri_src_check_get_range (GstBaseSrc * src);
71 static void gst_data_uri_src_handler_init (gpointer g_iface,
73 static GstURIType gst_data_uri_src_get_uri_type (void);
74 static gchar **gst_data_uri_src_get_protocols (void);
75 static const gchar *gst_data_uri_src_get_uri (GstURIHandler * handler);
76 static gboolean gst_data_uri_src_set_uri (GstURIHandler * handler,
80 _do_init (GType gtype)
82 static const GInterfaceInfo urihandler_info = {
83 gst_data_uri_src_handler_init,
87 GST_DEBUG_CATEGORY_INIT (data_uri_src_debug, "dataurisrc", 0,
89 g_type_add_interface_static (gtype, GST_TYPE_URI_HANDLER, &urihandler_info);
92 GST_BOILERPLATE_FULL (GstDataURISrc, gst_data_uri_src, GstBaseSrc,
93 GST_TYPE_BASE_SRC, _do_init);
96 gst_data_uri_src_base_init (gpointer klass)
98 GstElementClass *element_class = (GstElementClass *) (klass);
100 gst_element_class_add_pad_template (element_class,
101 gst_static_pad_template_get (&src_template));
102 gst_element_class_set_details_simple (element_class,
103 "data: URI source element", "Source", "Handles data: uris",
104 "Philippe Normand <pnormand@igalia.com>, "
105 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
110 gst_data_uri_src_class_init (GstDataURISrcClass * klass)
112 GObjectClass *gobject_class = (GObjectClass *) klass;
113 GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass;
115 gobject_class->finalize = gst_data_uri_src_finalize;
116 gobject_class->set_property = gst_data_uri_src_set_property;
117 gobject_class->get_property = gst_data_uri_src_get_property;
119 g_object_class_install_property (gobject_class, PROP_URI,
120 g_param_spec_string ("uri",
122 "URI that should be used",
123 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125 basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_caps);
126 basesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_size);
127 basesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_data_uri_src_is_seekable);
128 basesrc_class->create = GST_DEBUG_FUNCPTR (gst_data_uri_src_create);
129 basesrc_class->check_get_range =
130 GST_DEBUG_FUNCPTR (gst_data_uri_src_check_get_range);
134 gst_data_uri_src_init (GstDataURISrc * src, GstDataURISrcClass * g_class)
136 gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_BYTES);
140 gst_data_uri_src_finalize (GObject * object)
142 GstDataURISrc *src = GST_DATA_URI_SRC (object);
148 gst_buffer_unref (src->buffer);
151 G_OBJECT_CLASS (parent_class)->finalize (object);
155 gst_data_uri_src_set_property (GObject * object, guint prop_id,
156 const GValue * value, GParamSpec * pspec)
158 GstDataURISrc *src = GST_DATA_URI_SRC (object);
162 gst_data_uri_src_set_uri (GST_URI_HANDLER (src),
163 g_value_get_string (value));
166 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172 gst_data_uri_src_get_property (GObject * object,
173 guint prop_id, GValue * value, GParamSpec * pspec)
175 GstDataURISrc *src = GST_DATA_URI_SRC (object);
179 g_value_set_string (value,
180 gst_data_uri_src_get_uri (GST_URI_HANDLER (src)));
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 gst_data_uri_src_get_caps (GstBaseSrc * basesrc)
191 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
194 GST_OBJECT_LOCK (src);
195 if (!src->buffer || !GST_BUFFER_CAPS (src->buffer))
196 caps = gst_caps_new_empty ();
198 caps = gst_buffer_get_caps (src->buffer);
199 GST_OBJECT_UNLOCK (src);
205 gst_data_uri_src_get_size (GstBaseSrc * basesrc, guint64 * size)
207 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
210 GST_OBJECT_LOCK (src);
216 *size = GST_BUFFER_SIZE (src->buffer);
218 GST_OBJECT_UNLOCK (src);
224 gst_data_uri_src_is_seekable (GstBaseSrc * basesrc)
230 gst_data_uri_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
233 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
236 GST_OBJECT_LOCK (src);
241 /* This is only correct because GstBaseSrc already clips size for us to be no
242 * larger than the max. available size if a segment at the end is requested */
243 if (offset + size > GST_BUFFER_SIZE (src->buffer)) {
244 ret = GST_FLOW_UNEXPECTED;
247 *buf = gst_buffer_create_sub (src->buffer, offset, size);
248 gst_buffer_set_caps (*buf, GST_BUFFER_CAPS (src->buffer));
251 GST_OBJECT_UNLOCK (src);
258 GST_OBJECT_UNLOCK (src);
259 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
260 return GST_FLOW_NOT_NEGOTIATED;
265 gst_data_uri_src_check_get_range (GstBaseSrc * basesrc)
271 gst_data_uri_src_handler_init (gpointer g_iface, gpointer iface_data)
273 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
275 iface->get_type = gst_data_uri_src_get_uri_type;
276 iface->get_protocols = gst_data_uri_src_get_protocols;
277 iface->get_uri = gst_data_uri_src_get_uri;
278 iface->set_uri = gst_data_uri_src_set_uri;
282 gst_data_uri_src_get_uri_type (void)
288 gst_data_uri_src_get_protocols (void)
290 static gchar *protocols[] = { "data", 0 };
296 gst_data_uri_src_get_uri (GstURIHandler * handler)
298 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
304 gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri)
306 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
307 gboolean ret = FALSE;
308 gchar *mimetype = NULL;
309 const gchar *parameters_start;
310 const gchar *data_start;
312 gboolean base64 = FALSE;
313 gchar *charset = NULL;
315 GST_OBJECT_LOCK (src);
316 if (GST_STATE (src) >= GST_STATE_PAUSED)
319 /* uri must be an URI as defined in RFC 2397
320 * data:[<mediatype>][;base64],<data>
322 if (strncmp ("data:", uri, 5) != 0)
327 parameters_start = strchr (uri, ';');
328 data_start = strchr (uri, ',');
329 if (data_start == NULL)
332 if (data_start != uri && parameters_start != uri)
335 (parameters_start ? parameters_start : data_start) - uri);
337 mimetype = g_strdup ("text/plain");
339 GST_DEBUG_OBJECT (src, "Mimetype: %s", mimetype);
341 if (parameters_start != NULL) {
344 g_strndup (parameters_start + 1, data_start - parameters_start - 1);
345 gchar **parameters_strv;
347 parameters_strv = g_strsplit (parameters, ";", -1);
349 GST_DEBUG_OBJECT (src, "Parameters: ");
350 walk = parameters_strv;
352 GST_DEBUG_OBJECT (src, "\t %s", *walk);
353 if (strcmp ("base64", *walk) == 0) {
355 } else if (strncmp ("charset=", *walk, 8) == 0) {
356 charset = g_strdup (*walk + 8);
361 g_strfreev (parameters_strv);
369 src->buffer = gst_buffer_new ();
370 GST_BUFFER_DATA (src->buffer) =
371 (guint8 *) g_base64_decode (data_start, &bsize);
372 GST_BUFFER_MALLOCDATA (src->buffer) = GST_BUFFER_DATA (src->buffer);
373 GST_BUFFER_SIZE (src->buffer) = bsize;
377 /* URI encoded, i.e. "percent" encoding */
378 data = g_uri_unescape_string (data_start, NULL);
380 goto invalid_uri_encoded_data;
382 src->buffer = gst_buffer_new ();
383 GST_BUFFER_DATA (src->buffer) = (guint8 *) data;
384 GST_BUFFER_MALLOCDATA (src->buffer) = GST_BUFFER_DATA (src->buffer);
385 GST_BUFFER_SIZE (src->buffer) = strlen (data) + 1;
388 /* Convert to UTF8 */
389 if (strcmp ("text/plain", mimetype) == 0 &&
390 charset && strcasecmp ("US-ASCII", charset) != 0
391 && strcasecmp ("UTF-8", charset) != 0) {
394 gchar *old_data = (gchar *) GST_BUFFER_DATA (src->buffer);
398 g_convert_with_fallback (old_data, -1, "UTF-8", charset, "*", &read,
401 GST_BUFFER_DATA (src->buffer) = GST_BUFFER_MALLOCDATA (src->buffer) =
403 GST_BUFFER_SIZE (src->buffer) = written;
406 caps = gst_type_find_helper_for_buffer (GST_OBJECT (src), src->buffer, NULL);
408 caps = gst_caps_new_simple (mimetype, NULL);
409 gst_buffer_set_caps (src->buffer, caps);
410 gst_caps_unref (caps);
413 GST_OBJECT_UNLOCK (src);
423 GST_OBJECT_UNLOCK (src);
424 GST_ELEMENT_ERROR (src, STREAM, FORMAT, (NULL), (NULL));
429 GST_OBJECT_UNLOCK (src);
430 GST_ELEMENT_ERROR (src, CORE, FAILED, (NULL), (NULL));
433 invalid_uri_encoded_data:
435 GST_OBJECT_UNLOCK (src);
436 GST_ELEMENT_ERROR (src, STREAM, FORMAT, (NULL), (NULL));
442 plugin_init (GstPlugin * plugin)
444 return gst_element_register (plugin, "dataurisrc",
445 GST_RANK_PRIMARY, GST_TYPE_DATA_URI_SRC);
448 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
452 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);