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., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, 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 ! videoconvert ! freeze ! videoconvert ! 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, GstCaps * filter);
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_start (GstBaseSrc * src);
71 static void gst_data_uri_src_handler_init (gpointer g_iface,
73 static GstURIType gst_data_uri_src_get_uri_type (GType type);
74 static const gchar *const *gst_data_uri_src_get_protocols (GType type);
75 static gchar *gst_data_uri_src_get_uri (GstURIHandler * handler);
76 static gboolean gst_data_uri_src_set_uri (GstURIHandler * handler,
77 const gchar * uri, GError ** error);
80 #define gst_data_uri_src_parent_class parent_class
81 G_DEFINE_TYPE_WITH_CODE (GstDataURISrc, gst_data_uri_src, GST_TYPE_BASE_SRC,
82 G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
83 gst_data_uri_src_handler_init));
86 gst_data_uri_src_class_init (GstDataURISrcClass * klass)
88 GObjectClass *gobject_class = (GObjectClass *) klass;
89 GstElementClass *element_class = (GstElementClass *) klass;
90 GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass;
92 gobject_class->finalize = gst_data_uri_src_finalize;
93 gobject_class->set_property = gst_data_uri_src_set_property;
94 gobject_class->get_property = gst_data_uri_src_get_property;
96 g_object_class_install_property (gobject_class, PROP_URI,
97 g_param_spec_string ("uri",
99 "URI that should be used",
100 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102 gst_element_class_add_pad_template (element_class,
103 gst_static_pad_template_get (&src_template));
104 gst_element_class_set_static_metadata (element_class,
105 "data: URI source element", "Source", "Handles data: uris",
106 "Philippe Normand <pnormand@igalia.com>, "
107 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
109 GST_DEBUG_CATEGORY_INIT (data_uri_src_debug, "dataurisrc", 0,
112 basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_caps);
113 basesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_size);
114 basesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_data_uri_src_is_seekable);
115 basesrc_class->create = GST_DEBUG_FUNCPTR (gst_data_uri_src_create);
116 basesrc_class->start = GST_DEBUG_FUNCPTR (gst_data_uri_src_start);
120 gst_data_uri_src_init (GstDataURISrc * src)
125 gst_data_uri_src_finalize (GObject * object)
127 GstDataURISrc *src = GST_DATA_URI_SRC (object);
133 gst_buffer_unref (src->buffer);
136 G_OBJECT_CLASS (parent_class)->finalize (object);
140 gst_data_uri_src_set_property (GObject * object, guint prop_id,
141 const GValue * value, GParamSpec * pspec)
143 GstDataURISrc *src = GST_DATA_URI_SRC (object);
147 gst_data_uri_src_set_uri (GST_URI_HANDLER (src),
148 g_value_get_string (value), NULL);
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157 gst_data_uri_src_get_property (GObject * object,
158 guint prop_id, GValue * value, GParamSpec * pspec)
160 GstDataURISrc *src = GST_DATA_URI_SRC (object);
164 g_value_set_string (value,
165 gst_data_uri_src_get_uri (GST_URI_HANDLER (src)));
168 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174 gst_data_uri_src_get_caps (GstBaseSrc * basesrc, GstCaps * filter)
176 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
179 GST_OBJECT_LOCK (src);
180 if (gst_pad_has_current_caps (GST_BASE_SRC_PAD (basesrc)))
181 caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (basesrc));
183 caps = gst_caps_new_any ();
184 GST_OBJECT_UNLOCK (src);
190 gst_data_uri_src_get_size (GstBaseSrc * basesrc, guint64 * size)
192 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
195 GST_OBJECT_LOCK (src);
201 *size = gst_buffer_get_size (src->buffer);
203 GST_OBJECT_UNLOCK (src);
209 gst_data_uri_src_is_seekable (GstBaseSrc * basesrc)
215 gst_data_uri_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
218 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
221 GST_OBJECT_LOCK (src);
226 /* This is only correct because GstBaseSrc already clips size for us to be no
227 * larger than the max. available size if a segment at the end is requested */
228 if (offset + size > gst_buffer_get_size (src->buffer)) {
230 } else if (*buf != NULL) {
232 GstMapInfo dest_info;
235 gst_buffer_map (src->buffer, &src_info, GST_MAP_READ);
236 gst_buffer_map (*buf, &dest_info, GST_MAP_WRITE);
238 fill_size = gst_buffer_fill (*buf, 0, src_info.data + offset, size);
240 gst_buffer_unmap (*buf, &dest_info);
241 gst_buffer_unmap (src->buffer, &src_info);
242 gst_buffer_set_size (*buf, fill_size);
246 gst_buffer_copy_region (src->buffer, GST_BUFFER_COPY_ALL, offset, size);
249 GST_OBJECT_UNLOCK (src);
256 GST_OBJECT_UNLOCK (src);
257 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
258 return GST_FLOW_NOT_NEGOTIATED;
263 gst_data_uri_src_start (GstBaseSrc * basesrc)
265 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
267 GST_OBJECT_LOCK (src);
269 if (src->uri == NULL || *src->uri == '\0' || src->buffer == NULL)
272 GST_OBJECT_UNLOCK (src);
279 GST_OBJECT_UNLOCK (src);
280 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
281 ("No valid data URI specified, or the data URI could not be parsed."),
288 gst_data_uri_src_get_uri_type (GType type)
293 static const gchar *const *
294 gst_data_uri_src_get_protocols (GType type)
296 static const gchar *protocols[] = { "data", 0 };
302 gst_data_uri_src_get_uri (GstURIHandler * handler)
304 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
305 gchar *src_uri = NULL;
307 GST_OBJECT_LOCK (src);
308 src_uri = g_strdup (src->uri);
309 GST_OBJECT_UNLOCK (src);
314 gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri,
317 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
318 gboolean ret = FALSE;
319 gchar *mimetype = NULL;
320 const gchar *parameters_start;
321 const gchar *data_start;
322 const gchar *orig_uri = uri;
325 gboolean base64 = FALSE;
326 gchar *charset = NULL;
330 GST_OBJECT_LOCK (src);
331 if (GST_STATE (src) >= GST_STATE_PAUSED)
333 GST_OBJECT_UNLOCK (src);
335 /* uri must be an URI as defined in RFC 2397
336 * data:[<mediatype>][;base64],<data>
338 if (strncmp ("data:", uri, 5) != 0)
343 parameters_start = strchr (uri, ';');
344 data_start = strchr (uri, ',');
345 if (data_start == NULL)
348 if (data_start != uri && parameters_start != uri)
351 (parameters_start ? parameters_start : data_start) - uri);
353 mimetype = g_strdup ("text/plain");
355 GST_DEBUG_OBJECT (src, "Mimetype: %s", mimetype);
357 if (parameters_start != NULL) {
360 g_strndup (parameters_start + 1, data_start - parameters_start - 1);
361 gchar **parameters_strv;
363 parameters_strv = g_strsplit (parameters, ";", -1);
365 GST_DEBUG_OBJECT (src, "Parameters: ");
366 walk = parameters_strv;
368 GST_DEBUG_OBJECT (src, "\t %s", *walk);
369 if (strcmp ("base64", *walk) == 0) {
371 } else if (strncmp ("charset=", *walk, 8) == 0) {
372 charset = g_strdup (*walk + 8);
377 g_strfreev (parameters_strv);
383 bdata = g_base64_decode (data_start, &bsize);
385 /* URI encoded, i.e. "percent" encoding */
386 bdata = g_uri_unescape_string (data_start, NULL);
388 goto invalid_uri_encoded_data;
389 bsize = strlen (bdata) + 1;
391 /* Convert to UTF8 */
392 if (strcmp ("text/plain", mimetype) == 0 &&
393 charset && g_ascii_strcasecmp ("US-ASCII", charset) != 0
394 && g_ascii_strcasecmp ("UTF-8", charset) != 0) {
400 g_convert_with_fallback (bdata, -1, "UTF-8", charset, (char *) "*",
401 &read, &written, NULL);
407 buffer = gst_buffer_new_wrapped (bdata, bsize);
409 caps = gst_type_find_helper_for_buffer (GST_OBJECT (src), buffer, NULL);
411 caps = gst_caps_new_empty_simple (mimetype);
412 gst_base_src_set_caps (GST_BASE_SRC_CAST (src), caps);
413 gst_caps_unref (caps);
415 GST_OBJECT_LOCK (src);
416 gst_buffer_replace (&src->buffer, buffer);
417 gst_buffer_unref (buffer);
419 src->uri = g_strdup (orig_uri);
420 GST_OBJECT_UNLOCK (src);
433 GST_WARNING_OBJECT (src, "Can't set URI in %s state",
434 gst_element_state_get_name (GST_STATE (src)));
435 GST_OBJECT_UNLOCK (src);
436 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
437 "Changing the 'uri' property on dataurisrc while it is running "
443 GST_WARNING_OBJECT (src, "invalid URI '%s'", uri);
444 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
448 invalid_uri_encoded_data:
450 GST_WARNING_OBJECT (src, "Failed to parse data encoded in URI '%s'", uri);
451 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
452 "Could not parse data encoded in data URI");
458 gst_data_uri_src_handler_init (gpointer g_iface, gpointer iface_data)
460 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
462 iface->get_type = gst_data_uri_src_get_uri_type;
463 iface->get_protocols = gst_data_uri_src_get_protocols;
464 iface->get_uri = gst_data_uri_src_get_uri;
465 iface->set_uri = gst_data_uri_src_set_uri;
469 plugin_init (GstPlugin * plugin)
471 return gst_element_register (plugin, "dataurisrc",
472 GST_RANK_PRIMARY, GST_TYPE_DATA_URI_SRC);
475 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
479 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);