1 /* GStreamer data:// uri source element
2 * Copyright (C) 2009 Igalia S.L
3 * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:element-dataurisrc
25 * dataurisrc handles data: URIs, see [RFC 2397](http://tools.ietf.org/html/rfc2397) for more information.
27 * ## Example launch line
30 * gst-launch-1.0 -v dataurisrc uri="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAfElEQVQ4je2MwQnAIAxFgziA4EnczIsO4MEROo/gzZWc4xdTbe1R6LGRR74heYS7iKElzfcMiRnt4hf8gk8EayB6luefue/HzlJfCA50XsNjYRxprZmenXNIKSGEsC+QUqK1hhgj521BzhnWWiilUGvdF5RS4L2HMQZCCJy8sHMm2TYdJAAAAABJRU5ErkJggg==" ! pngdec ! videoconvert ! imagefreeze ! videoconvert ! autovideosink
33 * This pipeline displays a small 16x16 PNG image from the data URI.
40 #include "gstdataurisrc.h"
43 #include <gst/base/gsttypefindhelper.h>
45 GST_DEBUG_CATEGORY (data_uri_src_debug);
46 #define GST_CAT_DEFAULT (data_uri_src_debug)
48 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
59 static void gst_data_uri_src_finalize (GObject * object);
60 static void gst_data_uri_src_set_property (GObject * object,
61 guint prop_id, const GValue * value, GParamSpec * pspec);
62 static void gst_data_uri_src_get_property (GObject * object,
63 guint prop_id, GValue * value, GParamSpec * pspec);
65 static GstCaps *gst_data_uri_src_get_caps (GstBaseSrc * src, GstCaps * filter);
66 static gboolean gst_data_uri_src_get_size (GstBaseSrc * src, guint64 * size);
67 static gboolean gst_data_uri_src_is_seekable (GstBaseSrc * src);
68 static GstFlowReturn gst_data_uri_src_create (GstBaseSrc * src, guint64 offset,
69 guint size, GstBuffer ** buf);
70 static gboolean gst_data_uri_src_start (GstBaseSrc * src);
72 static void gst_data_uri_src_handler_init (gpointer g_iface,
74 static GstURIType gst_data_uri_src_get_uri_type (GType type);
75 static const gchar *const *gst_data_uri_src_get_protocols (GType type);
76 static gchar *gst_data_uri_src_get_uri (GstURIHandler * handler);
77 static gboolean gst_data_uri_src_set_uri (GstURIHandler * handler,
78 const gchar * uri, GError ** error);
81 #define gst_data_uri_src_parent_class parent_class
82 G_DEFINE_TYPE_WITH_CODE (GstDataURISrc, gst_data_uri_src, GST_TYPE_BASE_SRC,
83 G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
84 gst_data_uri_src_handler_init));
87 gst_data_uri_src_class_init (GstDataURISrcClass * klass)
89 GObjectClass *gobject_class = (GObjectClass *) klass;
90 GstElementClass *element_class = (GstElementClass *) klass;
91 GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass;
93 gobject_class->finalize = gst_data_uri_src_finalize;
94 gobject_class->set_property = gst_data_uri_src_set_property;
95 gobject_class->get_property = gst_data_uri_src_get_property;
97 g_object_class_install_property (gobject_class, PROP_URI,
98 g_param_spec_string ("uri",
100 "URI that should be used",
101 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
103 gst_element_class_add_static_pad_template (element_class, &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_take_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 caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (basesrc));
182 caps = gst_caps_new_any ();
183 GST_OBJECT_UNLOCK (src);
189 gst_data_uri_src_get_size (GstBaseSrc * basesrc, guint64 * size)
191 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
194 GST_OBJECT_LOCK (src);
200 *size = gst_buffer_get_size (src->buffer);
202 GST_OBJECT_UNLOCK (src);
208 gst_data_uri_src_is_seekable (GstBaseSrc * basesrc)
214 gst_data_uri_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
217 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
220 GST_OBJECT_LOCK (src);
225 /* This is only correct because GstBaseSrc already clips size for us to be no
226 * larger than the max. available size if a segment at the end is requested */
227 if (offset + size > gst_buffer_get_size (src->buffer)) {
229 } else if (*buf != NULL) {
231 GstMapInfo dest_info;
234 gst_buffer_map (src->buffer, &src_info, GST_MAP_READ);
235 gst_buffer_map (*buf, &dest_info, GST_MAP_WRITE);
237 fill_size = gst_buffer_fill (*buf, 0, src_info.data + offset, size);
239 gst_buffer_unmap (*buf, &dest_info);
240 gst_buffer_unmap (src->buffer, &src_info);
241 gst_buffer_set_size (*buf, fill_size);
245 gst_buffer_copy_region (src->buffer, GST_BUFFER_COPY_ALL, offset, size);
248 GST_OBJECT_UNLOCK (src);
255 GST_OBJECT_UNLOCK (src);
256 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
257 return GST_FLOW_NOT_NEGOTIATED;
262 gst_data_uri_src_start (GstBaseSrc * basesrc)
264 GstDataURISrc *src = GST_DATA_URI_SRC (basesrc);
266 GST_OBJECT_LOCK (src);
268 if (src->uri == NULL || *src->uri == '\0' || src->buffer == NULL)
271 GST_OBJECT_UNLOCK (src);
278 GST_OBJECT_UNLOCK (src);
279 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
280 ("No valid data URI specified, or the data URI could not be parsed."),
287 gst_data_uri_src_get_uri_type (GType type)
292 static const gchar *const *
293 gst_data_uri_src_get_protocols (GType type)
295 static const gchar *protocols[] = { "data", 0 };
301 gst_data_uri_src_get_uri (GstURIHandler * handler)
303 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
304 gchar *src_uri = NULL;
306 GST_OBJECT_LOCK (src);
307 src_uri = g_strdup (src->uri);
308 GST_OBJECT_UNLOCK (src);
313 gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri,
316 GstDataURISrc *src = GST_DATA_URI_SRC (handler);
317 gboolean ret = FALSE;
318 gchar *mimetype = NULL;
319 const gchar *parameters_start;
320 const gchar *data_start;
321 const gchar *orig_uri = uri;
324 gboolean base64 = FALSE;
325 gchar *charset = NULL;
329 GST_OBJECT_LOCK (src);
330 if (GST_STATE (src) >= GST_STATE_PAUSED)
332 GST_OBJECT_UNLOCK (src);
334 /* uri must be an URI as defined in RFC 2397
335 * data:[<mediatype>][;base64],<data>
337 if (strncmp ("data:", uri, 5) != 0)
342 parameters_start = strchr (uri, ';');
343 data_start = strchr (uri, ',');
344 if (data_start == NULL)
347 if (data_start != uri && parameters_start != uri)
350 (parameters_start ? parameters_start : data_start) - uri);
352 mimetype = g_strdup ("text/plain");
354 GST_DEBUG_OBJECT (src, "Mimetype: %s", mimetype);
356 if (parameters_start != NULL) {
359 g_strndup (parameters_start + 1, data_start - parameters_start - 1);
360 gchar **parameters_strv;
362 parameters_strv = g_strsplit (parameters, ";", -1);
364 GST_DEBUG_OBJECT (src, "Parameters: ");
365 walk = parameters_strv;
367 GST_DEBUG_OBJECT (src, "\t %s", *walk);
368 if (strcmp ("base64", *walk) == 0) {
370 } else if (strncmp ("charset=", *walk, 8) == 0) {
371 charset = g_strdup (*walk + 8);
376 g_strfreev (parameters_strv);
382 bdata = g_base64_decode (data_start, &bsize);
384 /* URI encoded, i.e. "percent" encoding */
385 bdata = g_uri_unescape_string (data_start, NULL);
387 goto invalid_uri_encoded_data;
388 bsize = strlen (bdata) + 1;
390 /* Convert to UTF8 */
391 if (strcmp ("text/plain", mimetype) == 0 &&
392 charset && g_ascii_strcasecmp ("US-ASCII", charset) != 0
393 && g_ascii_strcasecmp ("UTF-8", charset) != 0) {
399 g_convert_with_fallback (bdata, -1, "UTF-8", charset, (char *) "*",
400 &read, &written, NULL);
406 buffer = gst_buffer_new_wrapped (bdata, bsize);
408 caps = gst_type_find_helper_for_buffer (GST_OBJECT (src), buffer, NULL);
410 caps = gst_caps_new_empty_simple (mimetype);
411 gst_base_src_set_caps (GST_BASE_SRC_CAST (src), caps);
412 gst_caps_unref (caps);
414 GST_OBJECT_LOCK (src);
415 gst_buffer_replace (&src->buffer, buffer);
416 gst_buffer_unref (buffer);
418 src->uri = g_strdup (orig_uri);
419 GST_OBJECT_UNLOCK (src);
432 GST_WARNING_OBJECT (src, "Can't set URI in %s state",
433 gst_element_state_get_name (GST_STATE (src)));
434 GST_OBJECT_UNLOCK (src);
435 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE,
436 "Changing the 'uri' property on dataurisrc while it is running "
442 GST_WARNING_OBJECT (src, "invalid URI '%s'", uri);
443 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
447 invalid_uri_encoded_data:
449 GST_WARNING_OBJECT (src, "Failed to parse data encoded in URI '%s'", uri);
450 g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI,
451 "Could not parse data encoded in data URI");
457 gst_data_uri_src_handler_init (gpointer g_iface, gpointer iface_data)
459 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
461 iface->get_type = gst_data_uri_src_get_uri_type;
462 iface->get_protocols = gst_data_uri_src_get_protocols;
463 iface->get_uri = gst_data_uri_src_get_uri;
464 iface->set_uri = gst_data_uri_src_set_uri;