--- /dev/null
+From aa8dd50e9c9c37476a803cd5dc530786dd2a4104 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= <tim.muller@collabora.co.uk>
+Date: Sat, 23 May 2009 00:45:33 +0100
+Subject: [PATCH] tagreading: add gst-tagread test app to examples
+
+Uses tagreadbin to extract tags from the given files/directories and
+prints them out. See #564749.
+---
+ .gitignore | 1 +
+ configure.ac | 1 +
+ tests/examples/Makefile.am | 2 +-
+ tests/examples/tagreading/Makefile.am | 6 +
+ tests/examples/tagreading/gst-tagread.c | 285 +++++++++++++++++++++++++++++++
+ 5 files changed, 294 insertions(+), 1 deletions(-)
+ create mode 100644 tests/examples/tagreading/Makefile.am
+ create mode 100644 tests/examples/tagreading/gst-tagread.c
+
+diff --git a/.gitignore b/.gitignore
+index 005392e..b8398ca 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -27,6 +27,7 @@ depcomp
+ autoregen.sh
+ ABOUT-NLS
+ _stdint.h
++tests/examples/tagreading/gst-tagread
+
+ gst-plugins-base-*.tar*
+
+diff --git a/configure.ac b/configure.ac
+index 7a6ae5a..4de8751 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1015,6 +1015,7 @@ tests/examples/snapshot/Makefile
+ tests/examples/playrec/Makefile
+ tests/examples/volume/Makefile
+ tests/examples/v4l/Makefile
++tests/examples/tagreading/Makefile
+ tests/files/Makefile
+ tests/icles/Makefile
+ tests/icles/playback/Makefile
+diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am
+index 48c38a5..87d6e15 100644
+--- a/tests/examples/Makefile.am
++++ b/tests/examples/Makefile.am
+@@ -8,7 +8,7 @@ if USE_GIO
+ GIO_SUBDIRS = gio
+ endif
+
+-SUBDIRS = app dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec volume v4l encoding
++SUBDIRS = app dynamic $(FT2_SUBDIRS) $(GIO_SUBDIRS) overlay playrec volume v4l encoding tagreading
+
+ DIST_SUBDIRS = app dynamic gio overlay seek snapshot playrec volume v4l encoding
+
+diff --git a/tests/examples/tagreading/Makefile.am b/tests/examples/tagreading/Makefile.am
+new file mode 100644
+index 0000000..2d34c54
+--- /dev/null
++++ b/tests/examples/tagreading/Makefile.am
+@@ -0,0 +1,6 @@
++noinst_PROGRAMS = gst-tagread
++
++gst_tagread_SOURCES = gst-tagread.c
++gst_tagread_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
++gst_tagread_LDFLAGS = $(GST_LIBS)
++
+diff --git a/tests/examples/tagreading/gst-tagread.c b/tests/examples/tagreading/gst-tagread.c
+new file mode 100644
+index 0000000..4576b5f
+--- /dev/null
++++ b/tests/examples/tagreading/gst-tagread.c
+@@ -0,0 +1,285 @@
++/* GStreamer Command-Line Tag Reading Example
++ * Copyright (C) 2009 Tim-Philipp Müller <tim centricular net>
++ *
++ * 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., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <gst/gst.h>
++#include <glib/gi18n.h>
++
++static gboolean print_version = FALSE;
++
++static GstElement *tagreadbin = NULL;
++
++static void
++print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
++{
++ gint i, count;
++
++ count = gst_tag_list_get_tag_size (list, tag);
++
++ for (i = 0; i < count; i++) {
++ gchar *str;
++
++ if (gst_tag_get_type (tag) == G_TYPE_STRING) {
++ if (!gst_tag_list_get_string_index (list, tag, i, &str))
++ g_assert_not_reached ();
++ } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
++ GstBuffer *img;
++
++ img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
++ if (img) {
++ gchar *caps_str;
++
++ caps_str = GST_BUFFER_CAPS (img) ?
++ gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown");
++ str = g_strdup_printf ("buffer of %u bytes, type: %s",
++ GST_BUFFER_SIZE (img), caps_str);
++ g_free (caps_str);
++ } else {
++ str = g_strdup ("NULL buffer");
++ }
++ } else {
++ str =
++ g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
++ }
++
++ if (i == 0) {
++ g_print ("%25s: %s\n", gst_tag_get_nick (tag), str);
++ } else {
++ g_print ("%25s: %s\n", "", str);
++ }
++
++ g_free (str);
++ }
++}
++
++static GList *
++extract_tags (const gchar * uri)
++{
++ GstStateChangeReturn ret;
++ gboolean got_error = FALSE;
++ gboolean got_eos = FALSE;
++ GList *list = NULL;
++
++ g_print ("\n\nURI: %s\n", uri);
++
++ if (tagreadbin == NULL) {
++ tagreadbin = gst_element_factory_make ("tagreadbin", NULL);
++ if (tagreadbin == NULL)
++ g_error ("Could not create 'tagreadbin' element, check your setup!");
++ }
++
++ g_object_set (tagreadbin, "uri", uri, NULL);
++
++ /* this might fail, but if it does there'll be an error message on the bus */
++ ret = gst_element_set_state (tagreadbin, GST_STATE_PLAYING);
++ do {
++ GstMessage *msg;
++
++ msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (tagreadbin),
++ 5 * GST_SECOND, GST_MESSAGE_TAG | GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
++
++ /* no message for 5 seconds? - bad */
++ if (msg == NULL) {
++ if (ret == GST_STATE_CHANGE_FAILURE) {
++ g_warning ("tagreadbin state change failed, but did not get an error "
++ "message! (uri: %s)", uri);
++ } else {
++ g_warning ("No tags or EOS for more than 5 seconds, bailing out! "
++ "(uri: %s)", uri);
++ }
++ break;
++ }
++
++ switch (GST_MESSAGE_TYPE (msg)) {
++ case GST_MESSAGE_TAG:{
++ GstTagList *tags = NULL;
++
++ gst_message_parse_tag (msg, &tags);
++ GST_LOG ("TAG: %" GST_PTR_FORMAT, tags);
++ list = g_list_append (list, tags);
++ break;
++ }
++ case GST_MESSAGE_EOS:
++ GST_LOG ("EOS");
++ got_eos = TRUE;
++ break;
++ case GST_MESSAGE_ERROR:{
++ GError *err = NULL;
++ gchar *dbg = NULL;
++
++ gst_message_parse_error (msg, &err, &dbg);
++ if (err) {
++ g_warning ("Failed to read tags from %s:\nError: %s\nDebug: %s\n",
++ uri, err->message, (dbg) ? dbg : "(No debug details)");
++ g_error_free (err);
++ g_free (dbg);
++ got_error = TRUE;
++ }
++ break;
++ }
++ default:
++ g_assert_not_reached ();
++ break;
++ }
++ gst_message_unref (msg);
++ }
++ while (!(got_error || got_eos));
++
++ /* In case we got here after a timeout, some applications may prefer to not
++ * set the state to NULL here and instead throw away (and leak) the
++ * tagreadbin instance and continue with a new one, in case the reason for
++ * the timeout was that the streaming thread deadlocked due to a buggy
++ * element, in which case _set_state() is likely to deadlock too). */
++ gst_element_set_state (tagreadbin, GST_STATE_NULL);
++
++ /* FIXME: should be able to re-use */
++ gst_object_unref (tagreadbin);
++ tagreadbin = NULL;
++
++ if (got_error) {
++ g_list_foreach (list, (GFunc) gst_tag_list_free, NULL);
++ g_list_free (list);
++ list = NULL;
++ }
++
++ return list;
++}
++
++static void
++process_file (const gchar * filename)
++{
++ GError *err = NULL;
++ GList *tags;
++ GDir *dir;
++ gchar *uri, *path;
++ guint i;
++
++ /* Recurse into directories */
++ if ((dir = g_dir_open (filename, 0, NULL))) {
++ const gchar *entry;
++
++ while ((entry = g_dir_read_name (dir))) {
++ gchar *path;
++
++ path = g_strconcat (filename, G_DIR_SEPARATOR_S, entry, NULL);
++ process_file (path);
++ g_free (path);
++ }
++
++ g_dir_close (dir);
++ return;
++ }
++
++ if (!g_path_is_absolute (filename)) {
++ gchar *cur_dir;
++
++ cur_dir = g_get_current_dir ();
++ path = g_build_filename (cur_dir, filename, NULL);
++ g_free (cur_dir);
++ } else {
++ path = g_strdup (filename);
++ }
++
++ uri = g_filename_to_uri (path, NULL, &err);
++ g_free (path);
++ path = NULL;
++
++ if (err) {
++ g_warning ("Couldn't convert filename to URI: %s\n", err->message);
++ g_error_free (err);
++ return;
++ }
++
++ /* now get the tags */
++ tags = extract_tags (uri);
++
++ /* .. and print them */
++ i = 0;
++ while (tags != NULL) {
++ GstTagList *taglist = tags->data;
++
++ if (i == 0)
++ g_print ("\nCONTAINER TAGS:\n");
++ else
++ g_print ("\nSTREAM #%u TAGS:\n", i);
++
++ gst_tag_list_foreach (taglist, print_tag, NULL);
++ gst_tag_list_free (taglist);
++ tags = g_list_delete_link (tags, tags);
++ ++i;
++ }
++
++ g_free (uri);
++}
++
++int
++main (int argc, char **argv)
++{
++ gchar **filenames = NULL;
++ guint num, i;
++ GError *err = NULL;
++ GOptionContext *ctx;
++ GOptionEntry options[] = {
++ {"version", 0, 0, G_OPTION_ARG_NONE, &print_version,
++ N_("Print version information and exit"), NULL},
++ {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL},
++ {NULL}
++ };
++
++#ifdef ENABLE_NLS
++ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
++ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
++ textdomain (GETTEXT_PACKAGE);
++#endif
++
++ if (!g_thread_supported ())
++ g_thread_init (NULL);
++
++ ctx = g_option_context_new ("FILES");
++ g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
++ g_option_context_add_group (ctx, gst_init_get_option_group ());
++ if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
++ g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
++ exit (1);
++ }
++ g_option_context_free (ctx);
++
++ if (print_version) {
++ g_print ("gst-tagread version " VERSION "\n");
++ exit (0);
++ }
++
++ if (filenames == NULL || *filenames == NULL) {
++ g_print ("Please pass one or more filenames to gst-tagread\n\n");
++ return 1;
++ }
++
++ num = g_strv_length (filenames);
++
++ for (i = 0; i < num; ++i) {
++ process_file (filenames[i]);
++ }
++
++ g_strfreev (filenames);
++
++ return 0;
++}