aboutsummaryrefslogtreecommitdiffstats
path: root/tag-reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'tag-reader.c')
-rw-r--r--tag-reader.c649
1 files changed, 0 insertions, 649 deletions
diff --git a/tag-reader.c b/tag-reader.c
deleted file mode 100644
index ee6a4da..0000000
--- a/tag-reader.c
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Copyright (C) 2006 OpenedHand Ltd.
- *
- * 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.
- *
- * Author: Jorn Baayen <jorn@openedhand.com>
- */
-
-#include <gst/gst.h>
-#include <string.h>
-
-#include "marshal.h"
-
-#include "tag-reader.h"
-
-G_DEFINE_TYPE (TagReader,
- tag_reader,
- G_TYPE_OBJECT);
-
-struct _TagReaderPrivate {
- GstElement *pipeline;
- GstElement *src;
- GstElement *decodebin;
- GstElement *sink;
-
- GQueue *queue;
-
- guint next_id;
-
- GError *current_error;
- GstTagList *current_tag_list;
-};
-
-enum {
- SIGNAL_URI_SCANNED,
- SIGNAL_LAST
-};
-
-static guint signals[SIGNAL_LAST];
-
-typedef struct {
- char *uri;
- guint id;
-} ScanUriData;
-
-static void
-scan_uri_data_free (ScanUriData *data)
-{
- g_free (data->uri);
-
- g_slice_free (ScanUriData, data);
-}
-
-/**
- * Feed the head of the queue to the pipeline.
- **/
-static void
-feed_head (TagReader *tag_reader)
-{
- ScanUriData *data;
-
- data = g_queue_peek_head (tag_reader->priv->queue);
- if (!data)
- return;
-
- /**
- * Get appropriate src element.
- **/
- tag_reader->priv->src =
- gst_element_make_from_uri (GST_URI_SRC, data->uri, "src");
-
- /**
- * Add to pipeline & link up.
- **/
- gst_bin_add (GST_BIN (tag_reader->priv->pipeline),
- tag_reader->priv->src);
- gst_element_link (tag_reader->priv->src, tag_reader->priv->decodebin);
-
- /**
- * Play pipeline.
- **/
- gst_element_set_state (tag_reader->priv->pipeline,
- GST_STATE_PLAYING);
-}
-
-/**
- * Purge the head of the queue.
- **/
-static void
-flush_head (TagReader *tag_reader)
-{
- ScanUriData *data;
-
- /**
- * Stop pipeline.
- **/
- gst_element_set_state (tag_reader->priv->pipeline,
- GST_STATE_NULL);
-
- /**
- * Remove source element.
- **/
- gst_element_unlink (tag_reader->priv->src, tag_reader->priv->decodebin);
- gst_bin_remove (GST_BIN (tag_reader->priv->pipeline),
- tag_reader->priv->src);
-
- /**
- * Pop head from queue.
- **/
- data = g_queue_pop_head (tag_reader->priv->queue);
-
- /**
- * Call callback.
- **/
- g_signal_emit (tag_reader,
- signals[SIGNAL_URI_SCANNED],
- 0,
- data->uri,
- tag_reader->priv->current_error,
- tag_reader->priv->current_tag_list);
-
- /**
- * Free data.
- **/
- if (tag_reader->priv->current_error) {
- g_error_free (tag_reader->priv->current_error);
- tag_reader->priv->current_error = NULL;
- }
-
- if (tag_reader->priv->current_tag_list) {
- gst_tag_list_free (tag_reader->priv->current_tag_list);
- tag_reader->priv->current_tag_list = NULL;
- }
-
- scan_uri_data_free (data);
-}
-
-/**
- * An error occured.
- **/
-static void
-bus_message_error_cb (GstBus *bus,
- GstMessage *message,
- TagReader *tag_reader)
-{
- ScanUriData *data;
-
- data = g_queue_peek_head (tag_reader->priv->queue);
-
- gst_message_parse_error (message,
- &tag_reader->priv->current_error,
- NULL);
-
- flush_head (tag_reader);
- feed_head (tag_reader);
-}
-
-/**
- * End of stream reached.
- **/
-static void
-bus_message_eos_cb (GstBus *bus,
- GstMessage *message,
- TagReader *tag_reader)
-{
- flush_head (tag_reader);
- feed_head (tag_reader);
-}
-
-/**
- * Tag list available.
- **/
-static void
-bus_message_tag_cb (GstBus *bus,
- GstMessage *message,
- TagReader *tag_reader)
-{
- GstTagList *tags, *new_tags;
-
- gst_message_parse_tag (message, &tags);
-
- new_tags = gst_tag_list_merge (tag_reader->priv->current_tag_list, tags, GST_TAG_MERGE_REPLACE);
-
- if (tag_reader->priv->current_tag_list)
- gst_tag_list_free (tag_reader->priv->current_tag_list);
- gst_tag_list_free (tags);
-
- tag_reader->priv->current_tag_list = new_tags;
-}
-
-/**
- * Application message received.
- **/
-static void
-bus_message_application_cb (GstBus *bus,
- GstMessage *message,
- TagReader *tag_reader)
-{
- gpointer src;
- const GstStructure *structure;
- const char *structure_name;
- ScanUriData *data;
- GstQuery *query;
-
- /**
- * Verify this is the fakesink handoff event.
- **/
- src = GST_MESSAGE_SRC (message);
- if (src != tag_reader->priv->sink)
- return;
-
- structure = gst_message_get_structure (message);
- structure_name = gst_structure_get_name (structure);
- if (strcmp (structure_name, "handoff"))
- return;
-
- /**
- * Get relevant ScanUriData.
- **/
- data = g_queue_peek_head (tag_reader->priv->queue);
-
- /**
- * Determine the duration.
- **/
- query = gst_query_new_duration (GST_FORMAT_TIME);
-
- if (gst_element_query (tag_reader->priv->pipeline, query)) {
- gint64 duration;
-
- gst_query_parse_duration (query,
- NULL,
- &duration);
-
- /**
- * Create tag list if none exists yet.
- **/
- if (!tag_reader->priv->current_tag_list) {
- tag_reader->priv->current_tag_list =
- gst_tag_list_new ();
- }
-
- /**
- * Merge duration info into tag list.
- **/
- gst_tag_list_add (tag_reader->priv->current_tag_list,
- GST_TAG_MERGE_REPLACE,
- GST_TAG_DURATION,
- duration,
- NULL);
- }
-
- gst_query_unref (query);
-
- /**
- * Next, please.
- **/
- flush_head (tag_reader);
- feed_head (tag_reader);
-}
-
-/**
- * New decoded pad: Hook up to fakesink.
- **/
-static void
-decodebin_new_decoded_pad_cb (GstElement *decodebin,
- GstPad *pad,
- gboolean last,
- TagReader *tag_reader)
-{
- GstPad *sink_pad;
-
- /**
- * The last discovered pad will always be the one hooked up to
- * the sink.
- **/
- sink_pad = gst_element_get_pad (tag_reader->priv->sink, "sink");
- gst_pad_link (pad, sink_pad);
-}
-
-/**
- * Data of an unknown type fed.
- **/
-static void
-decodebin_unknown_type_cb (GstElement *decodebin,
- GstPad *pad,
- GstCaps *caps,
- TagReader *tag_reader)
-{
- tag_reader->priv->current_error =
- g_error_new (TAG_READER_ERROR,
- TAG_READER_ERROR_UNKNOWN_TYPE,
- "Unknown type");
-
- flush_head (tag_reader);
- feed_head (tag_reader);
-}
-
-/**
- * Fakesink hands over a buffer.
- **/
-static void
-fakesink_handoff_cb (GstElement *fakesink,
- GstBuffer *buffer,
- GstPad *pad,
- TagReader *tag_reader)
-{
- GstStructure *structure;
- GstMessage *message;
- GstBus *bus;
-
- /**
- * Post a message to the bus, as we are in another thread here.
- **/
- structure = gst_structure_new ("handoff", NULL);
- message = gst_message_new_application (GST_OBJECT (fakesink),
- structure);
-
- bus = gst_pipeline_get_bus (GST_PIPELINE (tag_reader->priv->pipeline));
- gst_bus_post (bus, message);
- gst_object_unref (GST_OBJECT (bus));
-}
-
-/**
- * Constructs the GStreamer pipeline.
- **/
-static void
-construct_pipeline (TagReader *tag_reader)
-{
-
- GstBus *bus;
-
- /**
- * The pipeline.
- **/
- tag_reader->priv->pipeline = gst_pipeline_new ("pipeline");
-
- /**
- * No src element yet.
- **/
- tag_reader->priv->src = NULL;
-
- /**
- * A decodebin.
- **/
- tag_reader->priv->decodebin =
- gst_element_factory_make ("decodebin", "decodebin");
- if (!tag_reader->priv->decodebin) {
- g_warning ("No decodebin found. Tag reading will not work.");
-
- return;
- }
-
- gst_bin_add (GST_BIN (tag_reader->priv->pipeline),
- tag_reader->priv->decodebin);
-
- g_signal_connect_object (tag_reader->priv->decodebin,
- "new-decoded-pad",
- G_CALLBACK (decodebin_new_decoded_pad_cb),
- tag_reader,
- 0);
- g_signal_connect_object (tag_reader->priv->decodebin,
- "unknown-type",
- G_CALLBACK (decodebin_unknown_type_cb),
- tag_reader,
- 0);
-
- /**
- * A fakesink.
- **/
- tag_reader->priv->sink =
- gst_element_factory_make ("fakesink", "fakesink");
- if (!tag_reader->priv->sink) {
- g_warning ("No fakesink found. Tag reading will not work.");
-
- return;
- }
-
- gst_bin_add (GST_BIN (tag_reader->priv->pipeline),
- tag_reader->priv->sink);
-
- g_object_set (tag_reader->priv->sink,
- "signal-handoffs", TRUE,
- NULL);
-
- g_signal_connect_object (tag_reader->priv->sink,
- "handoff",
- G_CALLBACK (fakesink_handoff_cb),
- tag_reader,
- 0);
-
- /**
- * Connect to signals on bus.
- **/
- bus = gst_pipeline_get_bus (GST_PIPELINE (tag_reader->priv->pipeline));
-
- gst_bus_add_signal_watch (bus);
-
- g_signal_connect_object (bus,
- "message::error",
- G_CALLBACK (bus_message_error_cb),
- tag_reader,
- 0);
- g_signal_connect_object (bus,
- "message::eos",
- G_CALLBACK (bus_message_eos_cb),
- tag_reader,
- 0);
- g_signal_connect_object (bus,
- "message::tag",
- G_CALLBACK (bus_message_tag_cb),
- tag_reader,
- 0);
- g_signal_connect_object (bus,
- "message::application",
- G_CALLBACK (bus_message_application_cb),
- tag_reader,
- 0);
-
- gst_object_unref (GST_OBJECT (bus));
-}
-
-static void
-tag_reader_init (TagReader *tag_reader)
-{
- /**
- * Create pointer to private data.
- **/
- tag_reader->priv =
- G_TYPE_INSTANCE_GET_PRIVATE (tag_reader,
- TYPE_TAG_READER,
- TagReaderPrivate);
-
- /**
- * Create scanning queue.
- **/
- tag_reader->priv->queue = g_queue_new ();
-
- /**
- * Initialize next ScanUriData ID.
- **/
- tag_reader->priv->next_id = 1;
-
- /**
- * No current URI yet.
- **/
- tag_reader->priv->current_error = NULL;
- tag_reader->priv->current_tag_list = NULL;
-
- /**
- * Construct GStreamer pipeline.
- **/
- construct_pipeline (tag_reader);
-}
-
-static void
-tag_reader_dispose (GObject *object)
-{
- TagReader *tag_reader;
- GObjectClass *object_class;
-
- tag_reader = TAG_READER (object);
-
- if (tag_reader->priv->pipeline) {
- gst_element_set_state (tag_reader->priv->pipeline,
- GST_STATE_NULL);
-
- gst_object_unref (GST_OBJECT (tag_reader->priv->pipeline));
- tag_reader->priv->pipeline = NULL;
- }
-
- object_class = G_OBJECT_CLASS (tag_reader_parent_class);
- object_class->dispose (object);
-}
-
-static void
-tag_reader_finalize (GObject *object)
-{
- TagReader *tag_reader;
- GObjectClass *object_class;
-
- tag_reader = TAG_READER (object);
-
- if (tag_reader->priv->current_error)
- g_error_free (tag_reader->priv->current_error);
- if (tag_reader->priv->current_tag_list)
- gst_tag_list_free (tag_reader->priv->current_tag_list);
-
- g_queue_foreach (tag_reader->priv->queue,
- (GFunc) scan_uri_data_free,
- NULL);
- g_queue_free (tag_reader->priv->queue);
-
- object_class = G_OBJECT_CLASS (tag_reader_parent_class);
- object_class->finalize (object);
-}
-
-static void
-tag_reader_class_init (TagReaderClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
-
- object_class->dispose = tag_reader_dispose;
- object_class->finalize = tag_reader_finalize;
-
- g_type_class_add_private (klass, sizeof (TagReaderPrivate));
-
- signals[SIGNAL_URI_SCANNED] =
- g_signal_new ("uri-scanned",
- TYPE_TAG_READER,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TagReaderClass, uri_scanned),
- NULL,
- NULL,
- marshal_VOID__STRING_POINTER_POINTER,
- G_TYPE_NONE,
- 3,
- G_TYPE_STRING,
- G_TYPE_POINTER,
- G_TYPE_POINTER);
-}
-
-/**
- * tag_reader_new
- *
- * Return value: A new #TagReader.
- **/
-TagReader *
-tag_reader_new (void)
-{
- return g_object_new (TYPE_TAG_READER, NULL);
-}
-
-/**
- * tag_reader_scan_uri
- * @tag_reader: A #TagReader
- * @uri: An URI
- *
- * Queues @uri up for tag reading.
- *
- * Return value: A scan ID as @guint.
- **/
-guint
-tag_reader_scan_uri (TagReader *tag_reader,
- const char *uri)
-{
- ScanUriData *data;
-
- g_return_val_if_fail (IS_TAG_READER (tag_reader), 0);
- g_return_val_if_fail (uri != NULL, 0);
-
- data = g_slice_new (ScanUriData);
-
- data->uri = g_strdup (uri);
- data->id = tag_reader->priv->next_id++;
-
- g_queue_push_tail (tag_reader->priv->queue, data);
-
- if (g_queue_get_length (tag_reader->priv->queue) == 1) {
- /**
- * The queue was empty, so we were idle. This means
- * we need to start the pump again by feeding the new
- * uri to the pipeline.
- **/
- feed_head (tag_reader);
- }
-
- return data->id;
-}
-
-/**
- * Find a ScanUriData by its ID.
- **/
-static int
-find_scan_uri_data (gconstpointer a,
- gconstpointer b)
-{
- guint ai = GPOINTER_TO_UINT (a);
- guint bi = GPOINTER_TO_UINT (b);
-
- if (ai < bi)
- return -1;
- else if (ai > bi)
- return 1;
- else
- return 0;
-}
-
-/**
- * tag_reader_cancal_scan_uri
- * @tag_reader: A #TagReader
- * @scan_id: The #guint scan ID as returned by #tag_reader_scan_uri
- *
- * Cancels the scanning of URI with ID @scan_id.
- **/
-void
-tag_reader_cancel_scan_uri (TagReader *tag_reader,
- guint scan_id)
-{
- GList *link;
-
- g_return_if_fail (IS_TAG_READER (tag_reader));
-
- link = g_queue_find_custom (tag_reader->priv->queue,
- GUINT_TO_POINTER (scan_id),
- find_scan_uri_data);
- if (!link) {
- g_warning ("Not scanning URI with ID %u", scan_id);
-
- return;
- }
-
- if (!link->prev) {
- /**
- * We were just processing this one. Use standard
- * flushing process.
- **/
- flush_head (tag_reader);
- } else {
- /**
- * This one is queued up. Dequeue.
- **/
- scan_uri_data_free (link->data);
- g_queue_delete_link (tag_reader->priv->queue, link);
- }
-}
-
-/**
- * Returns the tag reader error quark.
- **/
-GQuark
-tag_reader_error_quark (void)
-{
- return g_quark_from_static_string ("tag-reader-error");
-}