From 566025b9935ad591811550aef8a1db7069fdf93e Mon Sep 17 00:00:00 2001 From: Alexander Saprykin Date: Wed, 14 Mar 2012 20:45:35 +0400 Subject: [PATCH] Add new GstTocSetter interface --- gst/Makefile.am | 2 + gst/gst.h | 1 + gst/gsttocsetter.c | 362 +++++++++++++++++++++++++++++++++++++++++++++ gst/gsttocsetter.h | 67 +++++++++ 4 files changed, 432 insertions(+) create mode 100644 gst/gsttocsetter.c create mode 100644 gst/gsttocsetter.h diff --git a/gst/Makefile.am b/gst/Makefile.am index a9852de903..0da40a0e45 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -99,6 +99,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \ gsttask.c \ gsttaskpool.c \ gsttoc.c \ + gsttocsetter.c \ $(GST_TRACE_SRC) \ gsttypefind.c \ gsttypefindfactory.c \ @@ -190,6 +191,7 @@ gst_headers = \ gsttask.h \ gsttaskpool.h \ gsttoc.h \ + gsttocsetter.h \ gsttrace.h \ gsttypefind.h \ gsttypefindfactory.h \ diff --git a/gst/gst.h b/gst/gst.h index afe276fe8e..422cbfb317 100644 --- a/gst/gst.h +++ b/gst/gst.h @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include diff --git a/gst/gsttocsetter.c b/gst/gsttocsetter.c new file mode 100644 index 0000000000..bee9b34ff1 --- /dev/null +++ b/gst/gsttocsetter.c @@ -0,0 +1,362 @@ +/* GStreamer + * Copyright (C) 2010, 2012 Alexander Saprykin + * + * gsttocsetter.c: interface for TOC setting on elements + * + * 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. + */ + +/** + * SECTION:gsttocsetter + * @short_description: Element interface that allows setting and retrieval + * of the TOC + * + * Element interface that allows setting of the TOC. + * + * Elements that support some kind of chapters or editions (or tracks like in + * the FLAC cue sheet) will implement this interface. + * + * If you just want to retrieve the TOC in your application then all you + * need to do is watch for TOC messages on your pipeline's bus (or you can + * perform TOC query). This interface is only for setting TOC data, not for + * extracting it. To set TOC from the application, find proper tocsetter element + * and set TOC using gst_toc_setter_set_toc(). + * + * Elements implementing the #GstTocSetter interface can extend existing TOC + * by getting extend UID for that (you can use gst_toc_find_entry() to retrieve it) + * with any TOC entries received from downstream. + */ + + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "gst_private.h" +#include "gsttocsetter.h" +#include +#include + +GST_DEBUG_CATEGORY_STATIC (gst_toc_interface_debug); +#define GST_CAT_DEFAULT tag_toc_interface_debug + +static GQuark gst_toc_key; + +typedef struct +{ + GstToc *toc; + GStaticMutex lock; +} GstTocData; + +GType +gst_toc_setter_get_type (void) +{ + static volatile gsize toc_setter_type = 0; + + if (g_once_init_enter (&toc_setter_type)) { + GType _type; + static const GTypeInfo toc_setter_info = { + sizeof (GstTocSetterIFace), /* class_size */ + NULL, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (gst_toc_interface_debug, "GstTocInterface", 0, + "interfaces for the TOC"); + + _type = g_type_register_static (G_TYPE_INTERFACE, "GstTocSetter", + &toc_setter_info, 0); + + g_type_interface_add_prerequisite (_type, GST_TYPE_ELEMENT); + + gst_toc_key = g_quark_from_static_string ("GST_TOC_SETTER"); + g_once_init_leave (&toc_setter_type, _type); + } + + return toc_setter_type; +} + +static void +gst_toc_data_free (gpointer p) +{ + GstTocData *data = (GstTocData *) p; + + if (data->toc) + gst_toc_free (data->toc); + + g_static_mutex_free (&data->lock); + + g_slice_free (GstTocData, data); +} + +static GstTocData * +gst_toc_setter_get_data (GstTocSetter * setter) +{ + GstTocData *data; + + data = g_object_get_qdata (G_OBJECT (setter), gst_toc_key); + if (!data) { + static GStaticMutex create_mutex = G_STATIC_MUTEX_INIT; + + /* make sure no other thread is creating a GstTocData at the same time */ + g_static_mutex_lock (&create_mutex); + data = g_object_get_qdata (G_OBJECT (setter), gst_toc_key); + if (!data) { + data = g_slice_new (GstTocData); + g_static_mutex_init (&data->lock); + data->toc = NULL; + g_object_set_qdata_full (G_OBJECT (setter), gst_toc_key, data, + gst_toc_data_free); + } + g_static_mutex_unlock (&create_mutex); + } + + return data; +} + +/** + * gst_toc_setter_reset_toc: + * @setter: a #GstTocSetter. + * + * Reset the internal TOC. Elements should call this from within the + * state-change handler. + * + * Since: 0.10.37 + */ +void +gst_toc_setter_reset_toc (GstTocSetter * setter) +{ + GstTocData *data; + + g_return_if_fail (GST_IS_TOC_SETTER (setter)); + + data = gst_toc_setter_get_data (setter); + + g_static_mutex_lock (&data->lock); + if (data->toc) { + gst_toc_free (data->toc); + data->toc = NULL; + } + g_static_mutex_unlock (&data->lock); +} + +/** + * gst_toc_setter_get_toc: + * @setter: a #GstTocSetter. + * + * Return current TOC the setter uses. The TOC should not be + * modified or freed. + * + * This function is not thread-safe. Use gst_toc_setter_get_toc_copy() instead. + * + * Returns: a current snapshot of the TOC used in the setter + * or NULL if none is used. + * + * Since: 0.10.37 + */ +const GstToc * +gst_toc_setter_get_toc (GstTocSetter * setter) +{ + g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL); + + return gst_toc_setter_get_data (setter)->toc; +} + +/** + * gst_toc_setter_get_toc_copy: + * @setter: a #GstTocSetter. + * + * Return current TOC the setter uses. The difference between this + * function and gst_toc_setter_get_toc() is that this function returns deep + * copy of the TOC, so you can modify it in any way. This function is thread-safe. + * Free it when done with gst_toc_free(). + * + * Returns: a copy of the current snapshot of the TOC used in the setter + * or NULL if none is used. + * + * Since: 0.10.37 + */ +GstToc * +gst_toc_setter_get_toc_copy (GstTocSetter * setter) +{ + GstTocData *data; + GstToc *ret = NULL; + + g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL); + + data = gst_toc_setter_get_data (setter); + g_static_mutex_lock (&data->lock); + + if (data->toc != NULL) + ret = gst_toc_copy (data->toc); + + g_static_mutex_unlock (&data->lock); + + return ret; +} + +/** + * gst_toc_setter_set_toc: + * @setter: a #GstTocSetter. + * @toc: a #GstToc to set. + * + * Set the given TOC on the setter. Previously setted TOC will be + * freed before setting a new one. + * + * Since: 0.10.37 + */ +void +gst_toc_setter_set_toc (GstTocSetter * setter, const GstToc * toc) +{ + GstTocData *data; + + g_return_if_fail (GST_IS_TOC_SETTER (setter)); + + data = gst_toc_setter_get_data (setter); + + g_static_mutex_lock (&data->lock); + if (data->toc) + gst_toc_free (data->toc); + + data->toc = gst_toc_copy (toc); + + g_static_mutex_unlock (&data->lock); +} + +/** + * gst_toc_setter_get_toc_entry: + * @setter: a #GstTocSetter. + * @uid: UID to find entry with. + * + * Return #GstTocEntry (if any) with given @uid. Returned entry should + * not be modified or freed. + * + * This function is not thread-safe. Use gst_toc_setter_get_toc_entry_copy() instead. + * + * Returns: a TOC entry with given @uid from the TOC in the setter + * or NULL if none entry with such @uid was found. + * + * Since: 0.10.37 + */ +const GstTocEntry * +gst_toc_setter_get_toc_entry (GstTocSetter * setter, const gchar * uid) +{ + GstTocData *data; + const GstTocEntry *ret; + + g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL); + g_return_val_if_fail (uid != NULL, NULL); + + data = gst_toc_setter_get_data (setter); + + g_static_mutex_lock (&data->lock); + + ret = gst_toc_find_entry (data->toc, uid); + + g_static_mutex_unlock (&data->lock); + + return ret; +} + +/** + * gst_toc_setter_get_toc_entry_copy: + * @setter: a #GstTocSetter. + * @uid: UID to find entry with. + * + * Return #GstTocEntry (if any) with given @uid. It perform a deep copying, + * so you can modify returned value. Free it when done with gst_toc_entry_free(). + * This function is thread-safe. + * + * Returns: a TOC entry with given @uid from the TOC in the setter + * or NULL if none entry with such @uid was found. + * + * Since: 0.10.37 + */ +GstTocEntry * +gst_toc_setter_get_toc_entry_copy (GstTocSetter * setter, const gchar * uid) +{ + GstTocData *data; + GstTocEntry *ret = NULL; + const GstTocEntry *search; + + g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL); + g_return_val_if_fail (uid != NULL, NULL); + + data = gst_toc_setter_get_data (setter); + + g_static_mutex_lock (&data->lock); + + search = gst_toc_find_entry (data->toc, uid); + if (search != NULL) + ret = gst_toc_entry_copy (search); + + g_static_mutex_unlock (&data->lock); + + return ret; +} + +/** + * gst_toc_setter_add_toc_entry: + * @setter: a #GstTocSetter. + * @parent_uid: UID of the parent entry to append given @entry. Use 0 for the TOC root level. + * @entry: #GstTocEntry to append. + * + * Try to find entry with given @parent_uid and append an @entry to that #GstTocEntry. + * + * Returns: TRUE if entry with @parent_uid was found, FALSE otherwise. + * + * Since: 0.10.37 + */ +gboolean +gst_toc_setter_add_toc_entry (GstTocSetter * setter, const gchar * parent_uid, + const GstTocEntry * entry) +{ + GstTocData *data; + GstTocEntry *parent; + GstTocEntry *copy_entry; + gboolean ret = FALSE; + + g_return_val_if_fail (GST_IS_TOC_SETTER (setter), FALSE); + g_return_val_if_fail (parent_uid != NULL, FALSE); + g_return_val_if_fail (entry != NULL, FALSE); + + data = gst_toc_setter_get_data (setter); + + g_static_mutex_lock (&data->lock); + + copy_entry = gst_toc_entry_copy (entry); + + if (g_strcmp0 (parent_uid, "0") == 0) + data->toc->entries = g_list_append (data->toc->entries, copy_entry); + else { + parent = gst_toc_find_entry (data->toc, parent_uid); + + if (parent != NULL) { + parent->subentries = g_list_append (parent->subentries, copy_entry); + ret = TRUE; + } + } + + g_static_mutex_unlock (&data->lock); + + return ret; +} diff --git a/gst/gsttocsetter.h b/gst/gsttocsetter.h new file mode 100644 index 0000000000..2174e0d00f --- /dev/null +++ b/gst/gsttocsetter.h @@ -0,0 +1,67 @@ +/* GStreamer + * Copyright (C) 2010, 2012 Alexander Saprykin + * + * gsttocsetter.h: Interfaces for TOC + * + * 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. + */ + +#ifndef __GST_TOC_SETTER_H__ +#define __GST_TOC_SETTER_H__ + +#include + +G_BEGIN_DECLS +#define GST_TYPE_TOC_SETTER (gst_toc_setter_get_type ()) +#define GST_TOC_SETTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TOC_SETTER, GstTocSetter)) +#define GST_IS_TOC_SETTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TOC_SETTER)) +#define GST_TOC_SETTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_TOC_SETTER, GstTocSetterIFace)) +/** + * GstTocSetter: + * + * Opaque #GstTocSetter data structure. + */ +typedef struct _GstTocSetter GstTocSetter; +typedef struct _GstTocSetterIFace GstTocSetterIFace; + +/** + * GstTocSetterIFace: + * @g_iface: parent interface type. + * + * #GstTocSetterIFace interface. + */ + +struct _GstTocSetterIFace +{ + GTypeInterface g_iface; + + /* signals */ + + /* virtual table */ +}; + +GType gst_toc_setter_get_type (void); +void gst_toc_setter_reset_toc (GstTocSetter *setter); +const GstToc * gst_toc_setter_get_toc (GstTocSetter *setter); +GstToc * gst_toc_setter_get_toc_copy (GstTocSetter *setter); +void gst_toc_setter_set_toc (GstTocSetter *setter, const GstToc *toc); +const GstTocEntry * gst_toc_setter_get_toc_entry (GstTocSetter *setter, const gchar *uid); +GstTocEntry * gst_toc_setter_get_toc_entry_copy (GstTocSetter *setter, const gchar *uid); +gboolean gst_toc_setter_add_toc_entry (GstTocSetter *setter, const gchar *parent_uid, const GstTocEntry *entry); + +G_END_DECLS +#endif /* __GST_TOC_SETTER_H__ */ +