diff --git a/plugins/elements/gstdataurisrc.c b/plugins/elements/gstdataurisrc.c new file mode 100644 index 0000000000..84ec894537 --- /dev/null +++ b/plugins/elements/gstdataurisrc.c @@ -0,0 +1,477 @@ +/* GStreamer + * + * Copyright (C) 2009 Igalia S.L + * Copyright (C) 2009 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:element-dataurisrc + * + * dataurisrc handles data: URIs, see RFC 2397 for more information. + * + * + * Example launch line + * |[ + * gst-launch-1.0 -v dataurisrc uri="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAfElEQVQ4je2MwQnAIAxFgziA4EnczIsO4MEROo/gzZWc4xdTbe1R6LGRR74heYS7iKElzfcMiRnt4hf8gk8EayB6luefue/HzlJfCA50XsNjYRxprZmenXNIKSGEsC+QUqK1hhgj521BzhnWWiilUGvdF5RS4L2HMQZCCJy8sHMm2TYdJAAAAABJRU5ErkJggg==" ! pngdec ! videoconvert ! imagefreeze ! videoconvert ! autovideosink + * ]| This pipeline displays a small 16x16 PNG image from the data URI. + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdataurisrc.h" + +#include +#include + +GST_DEBUG_CATEGORY (data_uri_src_debug); +#define GST_CAT_DEFAULT (data_uri_src_debug) + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +enum +{ + PROP_0, + PROP_URI, +}; + +static void gst_data_uri_src_finalize (GObject * object); +static void gst_data_uri_src_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_data_uri_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); + +static GstCaps *gst_data_uri_src_get_caps (GstBaseSrc * src, GstCaps * filter); +static gboolean gst_data_uri_src_get_size (GstBaseSrc * src, guint64 * size); +static gboolean gst_data_uri_src_is_seekable (GstBaseSrc * src); +static GstFlowReturn gst_data_uri_src_create (GstBaseSrc * src, guint64 offset, + guint size, GstBuffer ** buf); +static gboolean gst_data_uri_src_start (GstBaseSrc * src); + +static void gst_data_uri_src_handler_init (gpointer g_iface, + gpointer iface_data); +static GstURIType gst_data_uri_src_get_uri_type (GType type); +static const gchar *const *gst_data_uri_src_get_protocols (GType type); +static gchar *gst_data_uri_src_get_uri (GstURIHandler * handler); +static gboolean gst_data_uri_src_set_uri (GstURIHandler * handler, + const gchar * uri, GError ** error); + + +#define gst_data_uri_src_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstDataURISrc, gst_data_uri_src, GST_TYPE_BASE_SRC, + G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, + gst_data_uri_src_handler_init)); + +static void +gst_data_uri_src_class_init (GstDataURISrcClass * klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *element_class = (GstElementClass *) klass; + GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass; + + gobject_class->finalize = gst_data_uri_src_finalize; + gobject_class->set_property = gst_data_uri_src_set_property; + gobject_class->get_property = gst_data_uri_src_get_property; + + g_object_class_install_property (gobject_class, PROP_URI, + g_param_spec_string ("uri", + "URI", + "URI that should be used", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_add_static_pad_template (element_class, &src_template); + gst_element_class_set_static_metadata (element_class, + "data: URI source element", "Source", "Handles data: uris", + "Philippe Normand , " + "Sebastian Dröge "); + + GST_DEBUG_CATEGORY_INIT (data_uri_src_debug, "dataurisrc", 0, + "data: URI source"); + + basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_caps); + basesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_data_uri_src_get_size); + basesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_data_uri_src_is_seekable); + basesrc_class->create = GST_DEBUG_FUNCPTR (gst_data_uri_src_create); + basesrc_class->start = GST_DEBUG_FUNCPTR (gst_data_uri_src_start); +} + +static void +gst_data_uri_src_init (GstDataURISrc * src) +{ +} + +static void +gst_data_uri_src_finalize (GObject * object) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (object); + + g_free (src->uri); + src->uri = NULL; + + if (src->buffer) + gst_buffer_unref (src->buffer); + src->buffer = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_data_uri_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (object); + + switch (prop_id) { + case PROP_URI: + gst_data_uri_src_set_uri (GST_URI_HANDLER (src), + g_value_get_string (value), NULL); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_data_uri_src_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (object); + + switch (prop_id) { + case PROP_URI: + g_value_set_string (value, + gst_data_uri_src_get_uri (GST_URI_HANDLER (src))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_data_uri_src_get_caps (GstBaseSrc * basesrc, GstCaps * filter) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (basesrc); + GstCaps *caps; + + GST_OBJECT_LOCK (src); + caps = gst_pad_get_current_caps (GST_BASE_SRC_PAD (basesrc)); + if (!caps) + caps = gst_caps_new_any (); + GST_OBJECT_UNLOCK (src); + + return caps; +} + +static gboolean +gst_data_uri_src_get_size (GstBaseSrc * basesrc, guint64 * size) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (basesrc); + gboolean ret; + + GST_OBJECT_LOCK (src); + if (!src->buffer) { + ret = FALSE; + *size = -1; + } else { + ret = TRUE; + *size = gst_buffer_get_size (src->buffer); + } + GST_OBJECT_UNLOCK (src); + + return ret; +} + +static gboolean +gst_data_uri_src_is_seekable (GstBaseSrc * basesrc) +{ + return TRUE; +} + +static GstFlowReturn +gst_data_uri_src_create (GstBaseSrc * basesrc, guint64 offset, guint size, + GstBuffer ** buf) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (basesrc); + GstFlowReturn ret; + + GST_OBJECT_LOCK (src); + + if (!src->buffer) + goto no_buffer; + + /* This is only correct because GstBaseSrc already clips size for us to be no + * larger than the max. available size if a segment at the end is requested */ + if (offset + size > gst_buffer_get_size (src->buffer)) { + ret = GST_FLOW_EOS; + } else if (*buf != NULL) { + GstMapInfo src_info; + GstMapInfo dest_info; + gsize fill_size; + + gst_buffer_map (src->buffer, &src_info, GST_MAP_READ); + gst_buffer_map (*buf, &dest_info, GST_MAP_WRITE); + + fill_size = gst_buffer_fill (*buf, 0, src_info.data + offset, size); + + gst_buffer_unmap (*buf, &dest_info); + gst_buffer_unmap (src->buffer, &src_info); + gst_buffer_set_size (*buf, fill_size); + ret = GST_FLOW_OK; + } else { + *buf = + gst_buffer_copy_region (src->buffer, GST_BUFFER_COPY_ALL, offset, size); + ret = GST_FLOW_OK; + } + GST_OBJECT_UNLOCK (src); + + return ret; + +/* ERRORS */ +no_buffer: + { + GST_OBJECT_UNLOCK (src); + GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL)); + return GST_FLOW_NOT_NEGOTIATED; + } +} + +static gboolean +gst_data_uri_src_start (GstBaseSrc * basesrc) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (basesrc); + + GST_OBJECT_LOCK (src); + + if (src->uri == NULL || *src->uri == '\0' || src->buffer == NULL) + goto no_uri; + + GST_OBJECT_UNLOCK (src); + + return TRUE; + +/* ERRORS */ +no_uri: + { + GST_OBJECT_UNLOCK (src); + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, + ("No valid data URI specified, or the data URI could not be parsed."), + ("%s", src->uri)); + return FALSE; + } +} + +static GstURIType +gst_data_uri_src_get_uri_type (GType type) +{ + return GST_URI_SRC; +} + +static const gchar *const * +gst_data_uri_src_get_protocols (GType type) +{ + static const gchar *protocols[] = { "data", 0 }; + + return protocols; +} + +static gchar * +gst_data_uri_src_get_uri (GstURIHandler * handler) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (handler); + gchar *src_uri = NULL; + + GST_OBJECT_LOCK (src); + src_uri = g_strdup (src->uri); + GST_OBJECT_UNLOCK (src); + return src_uri; +} + +static gboolean +gst_data_uri_src_set_uri (GstURIHandler * handler, const gchar * uri, + GError ** error) +{ + GstDataURISrc *src = GST_DATA_URI_SRC (handler); + gboolean ret = FALSE; + gchar *mimetype = NULL; + const gchar *parameters_start; + const gchar *data_start; + const gchar *orig_uri = uri; + GstCaps *caps; + GstBuffer *buffer; + gboolean base64 = FALSE; + gchar *charset = NULL; + gpointer bdata; + gsize bsize; + + GST_OBJECT_LOCK (src); + if (GST_STATE (src) >= GST_STATE_PAUSED) + goto wrong_state; + GST_OBJECT_UNLOCK (src); + + /* uri must be an URI as defined in RFC 2397 + * data:[][;base64], + */ + if (strncmp ("data:", uri, 5) != 0) + goto invalid_uri; + + uri += 5; + + parameters_start = strchr (uri, ';'); + data_start = strchr (uri, ','); + if (data_start == NULL) + goto invalid_uri; + + if (data_start != uri && parameters_start != uri) + mimetype = + g_strndup (uri, + (parameters_start ? parameters_start : data_start) - uri); + else + mimetype = g_strdup ("text/plain"); + + GST_DEBUG_OBJECT (src, "Mimetype: %s", mimetype); + + if (parameters_start != NULL) { + gchar **walk; + gchar *parameters = + g_strndup (parameters_start + 1, data_start - parameters_start - 1); + gchar **parameters_strv; + + parameters_strv = g_strsplit (parameters, ";", -1); + + GST_DEBUG_OBJECT (src, "Parameters: "); + walk = parameters_strv; + while (*walk) { + GST_DEBUG_OBJECT (src, "\t %s", *walk); + if (strcmp ("base64", *walk) == 0) { + base64 = TRUE; + } else if (strncmp ("charset=", *walk, 8) == 0) { + charset = g_strdup (*walk + 8); + } + walk++; + } + g_free (parameters); + g_strfreev (parameters_strv); + } + + /* Skip comma */ + data_start += 1; + if (base64) { + bdata = g_base64_decode (data_start, &bsize); + } else { + /* URI encoded, i.e. "percent" encoding */ + bdata = g_uri_unescape_string (data_start, NULL); + if (bdata == NULL) + goto invalid_uri_encoded_data; + bsize = strlen (bdata) + 1; + } + /* Convert to UTF8 */ + if (strcmp ("text/plain", mimetype) == 0 && + charset && g_ascii_strcasecmp ("US-ASCII", charset) != 0 + && g_ascii_strcasecmp ("UTF-8", charset) != 0) { + gsize read; + gsize written; + gpointer data; + + data = + g_convert_with_fallback (bdata, -1, "UTF-8", charset, (char *) "*", + &read, &written, NULL); + g_free (bdata); + + bdata = data; + bsize = written; + } + buffer = gst_buffer_new_wrapped (bdata, bsize); + + caps = gst_type_find_helper_for_buffer (GST_OBJECT (src), buffer, NULL); + if (!caps) + caps = gst_caps_new_empty_simple (mimetype); + gst_base_src_set_caps (GST_BASE_SRC_CAST (src), caps); + gst_caps_unref (caps); + + GST_OBJECT_LOCK (src); + gst_buffer_replace (&src->buffer, buffer); + gst_buffer_unref (buffer); + g_free (src->uri); + src->uri = g_strdup (orig_uri); + GST_OBJECT_UNLOCK (src); + + ret = TRUE; + +out: + + g_free (mimetype); + g_free (charset); + + return ret; + +wrong_state: + { + GST_WARNING_OBJECT (src, "Can't set URI in %s state", + gst_element_state_get_name (GST_STATE (src))); + GST_OBJECT_UNLOCK (src); + g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_STATE, + "Changing the 'uri' property on dataurisrc while it is running " + "is not supported"); + goto out; + } +invalid_uri: + { + GST_WARNING_OBJECT (src, "invalid URI '%s'", uri); + g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "Invalid data URI"); + goto out; + } +invalid_uri_encoded_data: + { + GST_WARNING_OBJECT (src, "Failed to parse data encoded in URI '%s'", uri); + g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_URI, + "Could not parse data encoded in data URI"); + goto out; + } +} + +static void +gst_data_uri_src_handler_init (gpointer g_iface, gpointer iface_data) +{ + GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface; + + iface->get_type = gst_data_uri_src_get_uri_type; + iface->get_protocols = gst_data_uri_src_get_protocols; + iface->get_uri = gst_data_uri_src_get_uri; + iface->set_uri = gst_data_uri_src_set_uri; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "dataurisrc", + GST_RANK_PRIMARY, GST_TYPE_DATA_URI_SRC); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + dataurisrc, + "data: URI source", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/plugins/elements/gstdataurisrc.h b/plugins/elements/gstdataurisrc.h new file mode 100644 index 0000000000..c2cfd902cb --- /dev/null +++ b/plugins/elements/gstdataurisrc.h @@ -0,0 +1,61 @@ +/* GStreamer + * + * Copyright (C) 2009 Igalia S.L + * Copyright (C) 2009 Sebastian Dröge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_DATA_URI_SRC__ +#define __GST_DATA_URI_SRC__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DATA_URI_SRC \ + (gst_data_uri_src_get_type()) +#define GST_DATA_URI_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DATA_URI_SRC,GstDataURISrc)) +#define GST_DATA_URI_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DATA_URI_SRC,GstDataURISrcClass)) +#define GST_IS_DATA_URI_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DATA_URI_SRC)) +#define GST_IS_DATA_URI_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DATA_URI_SRC)) +typedef struct _GstDataURISrc GstDataURISrc; +typedef struct _GstDataURISrcClass GstDataURISrcClass; + +struct _GstDataURISrc +{ + GstBaseSrc parent; + + /* */ + gchar *uri; + GstBuffer *buffer; +}; + +struct _GstDataURISrcClass +{ + GstBaseSrcClass parent_class; +}; + +GType gst_data_uri_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_DATA_URI_SRC__ */ diff --git a/tests/check/elements/dataurisrc.c b/tests/check/elements/dataurisrc.c new file mode 100644 index 0000000000..b034b2effc --- /dev/null +++ b/tests/check/elements/dataurisrc.c @@ -0,0 +1,233 @@ +/* GStreamer unit test for dataurisrc + * + * Copyright (C) 2010 Tim-Philipp Müller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +#include + +/* sine wave encoded in ogg/vorbis, created with: + * gst-launch-1.0 audiotestsrc num-buffers=110 ! audioconvert ! \ + * audio/x-raw,channels=1 ! vorbisenc ! oggmux ! \ + * filesink location=sine.ogg + * and then encoded to base64 */ +const gchar data_uri[] = "data:audio/ogg;base64," + "T2dnUwACAAAAAAAAAACVWbd7AAAAAHgH02kBHgF2b3JiaXMAAAAAAUSsAAAAAAAAgDgBAAAAAAC4" + "AU9nZ1MAAAAAAAAAAAAAlVm3ewEAAADrU8FRDkv///////////////+BA3ZvcmJpcx0AAABYaXBo" + "Lk9yZyBsaWJWb3JiaXMgSSAyMDA5MDcwOQEAAAAaAAAAREVTQ1JJUFRJT049YXVkaW90ZXN0IHdh" + "dmUBBXZvcmJpcyJCQ1YBAEAAACRzGCpGpXMWhBAaQlAZ4xxCzmvsGUJMEYIcMkxbyyVzkCGkoEKI" + "WyiB0JBVAABAAACHQXgUhIpBCCGEJT1YkoMnPQghhIg5eBSEaUEIIYQQQgghhBBCCCGERTlokoMn" + "QQgdhOMwOAyD5Tj4HIRFOVgQgydB6CCED0K4moOsOQghhCQ1SFCDBjnoHITCLCiKgsQwuBaEBDUo" + "jILkMMjUgwtCiJqDSTX4GoRnQXgWhGlBCCGEJEFIkIMGQcgYhEZBWJKDBjm4FITLQagahCo5CB+E" + "IDRkFQCQAACgoiiKoigKEBqyCgDIAAAQQFEUx3EcyZEcybEcCwgNWQUAAAEACAAAoEiKpEiO5EiS" + "JFmSJVmSJVmS5omqLMuyLMuyLMsyEBqyCgBIAABQUQxFcRQHCA1ZBQBkAAAIoDiKpViKpWiK54iO" + "CISGrAIAgAAABAAAEDRDUzxHlETPVFXXtm3btm3btm3btm3btm1blmUZCA1ZBQBAAAAQ0mlmqQaI" + "MAMZBkJDVgEACAAAgBGKMMSA0JBVAABAAACAGEoOogmtOd+c46BZDppKsTkdnEi1eZKbirk555xz" + "zsnmnDHOOeecopxZDJoJrTnnnMSgWQqaCa0555wnsXnQmiqtOeeccc7pYJwRxjnnnCateZCajbU5" + "55wFrWmOmkuxOeecSLl5UptLtTnnnHPOOeecc84555zqxekcnBPOOeecqL25lpvQxTnnnE/G6d6c" + "EM4555xzzjnnnHPOOeecIDRkFQAABABAEIaNYdwpCNLnaCBGEWIaMulB9+gwCRqDnELq0ehopJQ6" + "CCWVcVJKJwgNWQUAAAIAQAghhRRSSCGFFFJIIYUUYoghhhhyyimnoIJKKqmooowyyyyzzDLLLLPM" + "Ouyssw47DDHEEEMrrcRSU2011lhr7jnnmoO0VlprrbVSSimllFIKQkNWAQAgAAAEQgYZZJBRSCGF" + "FGKIKaeccgoqqIDQkFUAACAAgAAAAABP8hzRER3RER3RER3RER3R8RzPESVREiVREi3TMjXTU0VV" + "dWXXlnVZt31b2IVd933d933d+HVhWJZlWZZlWZZlWZZlWZZlWZYgNGQVAAACAAAghBBCSCGFFFJI" + "KcYYc8w56CSUEAgNWQUAAAIACAAAAHAUR3EcyZEcSbIkS9IkzdIsT/M0TxM9URRF0zRV0RVdUTdt" + "UTZl0zVdUzZdVVZtV5ZtW7Z125dl2/d93/d93/d93/d93/d9XQdCQ1YBABIAADqSIymSIimS4ziO" + "JElAaMgqAEAGAEAAAIriKI7jOJIkSZIlaZJneZaomZrpmZ4qqkBoyCoAABAAQAAAAAAAAIqmeIqp" + "eIqoeI7oiJJomZaoqZoryqbsuq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq4LhIas" + "AgAkAAB0JEdyJEdSJEVSJEdygNCQVQCADACAAAAcwzEkRXIsy9I0T/M0TxM90RM901NFV3SB0JBV" + "AAAgAIAAAAAAAAAMybAUy9EcTRIl1VItVVMt1VJF1VNVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" + "VVVVVVVVVVVN0zRNEwgNWQkAAAEA0FpzzK2XjkHorJfIKKSg10455qTXzCiCnOcQMWOYx1IxQwzG" + "lkGElAVCQ1YEAFEAAIAxyDHEHHLOSeokRc45Kh2lxjlHqaPUUUqxplo7SqW2VGvjnKPUUcoopVpL" + "qx2lVGuqsQAAgAAHAIAAC6HQkBUBQBQAAIEMUgophZRizinnkFLKOeYcYoo5p5xjzjkonZTKOSed" + "kxIppZxjzinnnJTOSeack9JJKAAAIMABACDAQig0ZEUAECcA4HAcTZM0TRQlTRNFTxRd1xNF1ZU0" + "zTQ1UVRVTRRN1VRVWRZNVZYlTTNNTRRVUxNFVRVVU5ZNVbVlzzRt2VRV3RZV1bZlW/Z9V5Z13TNN" + "2RZV1bZNVbV1V5Z1XbZt3Zc0zTQ1UVRVTRRV11RV2zZV1bY1UXRdUVVlWVRVWXZdWddVV9Z9TRRV" + "1VNN2RVVVZZV2dVlVZZ1X3RV3VZd2ddVWdZ929aFX9Z9wqiqum7Krq6rsqz7si77uu3rlEnTTFMT" + "RVXVRFFVTVe1bVN1bVsTRdcVVdWWRVN1ZVWWfV91ZdnXRNF1RVWVZVFVZVmVZV13ZVe3RVXVbVV2" + "fd90XV2XdV1YZlv3hdN1dV2VZd9XZVn3ZV3H1nXf90zTtk3X1XXTVXXf1nXlmW3b+EVV1XVVloVf" + "lWXf14XheW7dF55RVXXdlF1fV2VZF25fN9q+bjyvbWPbPrKvIwxHvrAsXds2ur5NmHXd6BtD4TeG" + "NNO0bdNVdd10XV+Xdd1o67pQVFVdV2XZ91VX9n1b94Xh9n3fGFXX91VZFobVlp1h932l7guVVbaF" + "39Z155htXVh+4+j8vjJ0dVto67qxzL6uPLtxdIY+AgAABhwAAAJMKAOFhqwIAOIEABiEnENMQYgU" + "gxBCSCmEkFLEGITMOSkZc1JCKamFUlKLGIOQOSYlc05KKKGlUEpLoYTWQimxhVJabK3VmlqLNYTS" + "WiiltVBKi6mlGltrNUaMQcick5I5J6WU0loopbXMOSqdg5Q6CCmllFosKcVYOSclg45KByGlkkpM" + "JaUYQyqxlZRiLCnF2FpsucWYcyilxZJKbCWlWFtMObYYc44Yg5A5JyVzTkoopbVSUmuVc1I6CCll" + "DkoqKcVYSkoxc05KByGlDkJKJaUYU0qxhVJiKynVWEpqscWYc0sx1lBSiyWlGEtKMbYYc26x5dZB" + "aC2kEmMoJcYWY66ttRpDKbGVlGIsKdUWY629xZhzKCXGkkqNJaVYW425xhhzTrHlmlqsucXYa225" + "9Zpz0Km1WlNMubYYc465BVlz7r2D0FoopcVQSoyttVpbjDmHUmIrKdVYSoq1xZhza7H2UEqMJaVY" + "S0o1thhrjjX2mlqrtcWYa2qx5ppz7zHm2FNrNbcYa06x5Vpz7r3m1mMBAAADDgAAASaUgUJDVgIA" + "UQAABCFKMQahQYgx56Q0CDHmnJSKMecgpFIx5hyEUjLnIJSSUuYchFJSCqWkklJroZRSUmqtAACA" + "AgcAgAAbNCUWByg0ZCUAkAoAYHAcy/I8UTRV2XYsyfNE0TRV1bYdy/I8UTRNVbVty/NE0TRV1XV1" + "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"; + +GST_START_TEST (test_playbin) +{ + GstElement *playbin, *sink; + int loops = 2; + + playbin = gst_element_factory_make ("playbin", NULL); + sink = gst_element_factory_make ("fakesink", NULL); + + if (playbin == NULL || sink == NULL) { + GST_WARNING ("skipping test, no playbin or fakesink element(s)"); + return; + } + + g_object_set (playbin, "uri", data_uri, "audio-sink", sink, NULL); + + do { + GstMessage *msg; + + /* not checking return val on purpose, should always get an error on bus */ + gst_element_set_state (playbin, GST_STATE_PLAYING); + + msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (playbin), + GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR); + + GST_INFO ("message: %" GST_PTR_FORMAT, msg); + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GError *err = NULL; + + gst_message_parse_error (msg, &err, NULL); + fail_unless (err->code == GST_CORE_ERROR_MISSING_PLUGIN || + err->code == GST_STREAM_ERROR_CODEC_NOT_FOUND, + "Got unexpected error: %s", err->message); + g_error_free (err); + } + + gst_message_unref (msg); + gst_element_set_state (playbin, GST_STATE_NULL); + + --loops; + GST_INFO ("done, %d rounds left", loops); + } while (loops > 0); + + gst_element_set_state (playbin, GST_STATE_NULL); + gst_object_unref (playbin); +} + +GST_END_TEST; + +static Suite * +dataurisrc_suite (void) +{ + Suite *s = suite_create ("dataurisrc"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_playbin); + + return s; +} + +GST_CHECK_MAIN (dataurisrc);