diff options
Diffstat (limited to 'gst/flv/gstmemindex.c')
-rw-r--r-- | gst/flv/gstmemindex.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/gst/flv/gstmemindex.c b/gst/flv/gstmemindex.c new file mode 100644 index 0000000000..eef99c2c58 --- /dev/null +++ b/gst/flv/gstmemindex.c @@ -0,0 +1,432 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * 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 <gst/gst.h> + +#define GST_TYPE_MEM_INDEX \ + (gst_index_get_type ()) +#define GST_MEM_INDEX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_MEM_INDEX, GstMemIndex)) +#define GST_MEM_INDEX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_MEM_INDEX, GstMemIndexClass)) +#define GST_IS_MEM_INDEX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_MEM_INDEX)) +#define GST_IS_MEM_INDEX_CLASS(klass) \ + (GST_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_MEM_INDEX)) + +/* + * Object model: + * + * All entries are simply added to a GList first. Then we build + * an index to each entry for each id/format + * + * + * memindex + * -----------------------------... + * ! ! + * id1 id2 + * ------------ + * ! ! + * format1 format2 + * ! ! + * GTree GTree + * + * + * The memindex creates a MemIndexId object for each writer id, a + * Hashtable is kept to map the id to the MemIndexId + * + * The MemIndexId keeps a MemIndexFormatIndex for each format the + * specific writer wants indexed. + * + * The MemIndexFormatIndex keeps all the values of the particular + * format in a GTree, The values of the GTree point back to the entry. + * + * Finding a value for an id/format requires locating the correct GTree, + * then do a lookup in the Tree to get the required value. + */ + +typedef struct +{ + GstFormat format; + gint offset; + GTree *tree; +} +GstMemIndexFormatIndex; + +typedef struct +{ + gint id; + GHashTable *format_index; +} +GstMemIndexId; + +typedef struct _GstMemIndex GstMemIndex; +typedef struct _GstMemIndexClass GstMemIndexClass; + +struct _GstMemIndex +{ + GstIndex parent; + + GList *associations; + + GHashTable *id_index; +}; + +struct _GstMemIndexClass +{ + GstIndexClass parent_class; +}; + +static void gst_mem_index_finalize (GObject * object); + +static void gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry); +static GstIndexEntry *gst_mem_index_get_assoc_entry (GstIndex * index, gint id, + GstIndexLookupMethod method, GstIndexAssociationFlags flags, + GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data); + +#define CLASS(mem_index) GST_MEM_INDEX_CLASS (G_OBJECT_GET_CLASS (mem_index)) + +static GType gst_mem_index_get_type (void); + +typedef GstMemIndex GstFlvDemuxMemIndex; +typedef GstMemIndexClass GstFlvDemuxMemIndexClass; +G_DEFINE_TYPE (GstFlvDemuxMemIndex, gst_mem_index, GST_TYPE_INDEX); + +static void +gst_mem_index_class_init (GstMemIndexClass * klass) +{ + GObjectClass *gobject_class; + GstIndexClass *gstindex_class; + + gobject_class = (GObjectClass *) klass; + gstindex_class = (GstIndexClass *) klass; + + gobject_class->finalize = gst_mem_index_finalize; + + gstindex_class->add_entry = GST_DEBUG_FUNCPTR (gst_mem_index_add_entry); + gstindex_class->get_assoc_entry = + GST_DEBUG_FUNCPTR (gst_mem_index_get_assoc_entry); +} + +static void +gst_mem_index_init (GstMemIndex * index) +{ + GST_DEBUG ("created new mem index"); + + index->associations = NULL; + index->id_index = g_hash_table_new (g_int_hash, g_int_equal); +} + +static void +gst_mem_index_free_format (gpointer key, gpointer value, gpointer user_data) +{ + GstMemIndexFormatIndex *index = (GstMemIndexFormatIndex *) value; + + if (index->tree) { + g_tree_destroy (index->tree); + } + + g_slice_free (GstMemIndexFormatIndex, index); +} + +static void +gst_mem_index_free_id (gpointer key, gpointer value, gpointer user_data) +{ + GstMemIndexId *id_index = (GstMemIndexId *) value; + + if (id_index->format_index) { + g_hash_table_foreach (id_index->format_index, gst_mem_index_free_format, + NULL); + g_hash_table_destroy (id_index->format_index); + id_index->format_index = NULL; + } + + g_slice_free (GstMemIndexId, id_index); +} + +static void +gst_mem_index_finalize (GObject * object) +{ + GstMemIndex *memindex = GST_MEM_INDEX (object); + + /* Delete the trees referencing the associations first */ + if (memindex->id_index) { + g_hash_table_foreach (memindex->id_index, gst_mem_index_free_id, NULL); + g_hash_table_destroy (memindex->id_index); + memindex->id_index = NULL; + } + + /* Then delete the associations themselves */ + if (memindex->associations) { + g_list_foreach (memindex->associations, (GFunc) gst_index_entry_free, NULL); + g_list_free (memindex->associations); + memindex->associations = NULL; + } + + G_OBJECT_CLASS (gst_mem_index_parent_class)->finalize (object); +} + +static void +gst_mem_index_add_id (GstIndex * index, GstIndexEntry * entry) +{ + GstMemIndex *memindex = GST_MEM_INDEX (index); + GstMemIndexId *id_index; + + id_index = g_hash_table_lookup (memindex->id_index, &entry->id); + + if (!id_index) { + id_index = g_slice_new0 (GstMemIndexId); + + id_index->id = entry->id; + id_index->format_index = g_hash_table_new (g_int_hash, g_int_equal); + g_hash_table_insert (memindex->id_index, &id_index->id, id_index); + } +} + +static gint +mem_index_compare (gconstpointer a, gconstpointer b, gpointer user_data) +{ + GstMemIndexFormatIndex *index = user_data; + gint64 val1, val2; + gint64 diff; + + val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset); + val2 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) b), index->offset); + + diff = (val2 - val1); + + return (diff == 0 ? 0 : (diff > 0 ? 1 : -1)); +} + +static void +gst_mem_index_index_format (GstMemIndexId * id_index, GstIndexEntry * entry, + gint assoc) +{ + GstMemIndexFormatIndex *index; + GstFormat *format; + + format = &GST_INDEX_ASSOC_FORMAT (entry, assoc); + + index = g_hash_table_lookup (id_index->format_index, format); + + if (!index) { + index = g_slice_new0 (GstMemIndexFormatIndex); + + index->format = *format; + index->offset = assoc; + index->tree = g_tree_new_with_data (mem_index_compare, index); + + g_hash_table_insert (id_index->format_index, &index->format, index); + } + + g_tree_insert (index->tree, entry, entry); +} + +static void +gst_mem_index_add_association (GstIndex * index, GstIndexEntry * entry) +{ + GstMemIndex *memindex = GST_MEM_INDEX (index); + GstMemIndexId *id_index; + + memindex->associations = g_list_prepend (memindex->associations, entry); + + id_index = g_hash_table_lookup (memindex->id_index, &entry->id); + if (id_index) { + gint i; + + for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) { + gst_mem_index_index_format (id_index, entry, i); + } + } +} + +static void +gst_mem_index_add_object (GstIndex * index, GstIndexEntry * entry) +{ +} + +static void +gst_mem_index_add_format (GstIndex * index, GstIndexEntry * entry) +{ +} + +static void +gst_mem_index_add_entry (GstIndex * index, GstIndexEntry * entry) +{ + GST_LOG_OBJECT (index, "added this entry"); + + switch (entry->type) { + case GST_INDEX_ENTRY_ID: + gst_mem_index_add_id (index, entry); + break; + case GST_INDEX_ENTRY_ASSOCIATION: + gst_mem_index_add_association (index, entry); + break; + case GST_INDEX_ENTRY_OBJECT: + gst_mem_index_add_object (index, entry); + break; + case GST_INDEX_ENTRY_FORMAT: + gst_mem_index_add_format (index, entry); + break; + default: + break; + } +} + +typedef struct +{ + gint64 value; + GstMemIndexFormatIndex *index; + gboolean exact; + GstIndexEntry *lower; + gint64 low_diff; + GstIndexEntry *higher; + gint64 high_diff; +} +GstMemIndexSearchData; + +static gint +mem_index_search (gconstpointer a, gconstpointer b) +{ + GstMemIndexSearchData *data = (GstMemIndexSearchData *) b; + GstMemIndexFormatIndex *index = data->index; + gint64 val1, val2; + gint64 diff; + + val1 = GST_INDEX_ASSOC_VALUE (((GstIndexEntry *) a), index->offset); + val2 = data->value; + + diff = (val1 - val2); + if (diff == 0) + return 0; + + /* exact matching, don't update low/high */ + if (data->exact) + return (diff > 0 ? 1 : -1); + + if (diff < 0) { + if (diff > data->low_diff) { + data->low_diff = diff; + data->lower = (GstIndexEntry *) a; + } + diff = -1; + } else { + if (diff < data->high_diff) { + data->high_diff = diff; + data->higher = (GstIndexEntry *) a; + } + diff = 1; + } + + return diff; +} + +static GstIndexEntry * +gst_mem_index_get_assoc_entry (GstIndex * index, gint id, + GstIndexLookupMethod method, + GstIndexAssociationFlags flags, + GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data) +{ + GstMemIndex *memindex = GST_MEM_INDEX (index); + GstMemIndexId *id_index; + GstMemIndexFormatIndex *format_index; + GstIndexEntry *entry; + GstMemIndexSearchData data; + + id_index = g_hash_table_lookup (memindex->id_index, &id); + if (!id_index) + return NULL; + + format_index = g_hash_table_lookup (id_index->format_index, &format); + if (!format_index) + return NULL; + + data.value = value; + data.index = format_index; + data.exact = (method == GST_INDEX_LOOKUP_EXACT); + + /* setup data for low/high checks if we are not looking + * for an exact match */ + if (!data.exact) { + data.low_diff = G_MININT64; + data.lower = NULL; + data.high_diff = G_MAXINT64; + data.higher = NULL; + } + + entry = g_tree_search (format_index->tree, mem_index_search, &data); + + /* get the low/high values if we're not exact */ + if (entry == NULL && !data.exact) { + if (method == GST_INDEX_LOOKUP_BEFORE) + entry = data.lower; + else if (method == GST_INDEX_LOOKUP_AFTER) { + entry = data.higher; + } + } + + if (entry && ((GST_INDEX_ASSOC_FLAGS (entry) & flags) != flags)) { + if (method != GST_INDEX_LOOKUP_EXACT) { + GList *l_entry = g_list_find (memindex->associations, entry); + + entry = NULL; + + while (l_entry) { + entry = (GstIndexEntry *) l_entry->data; + + if (entry->id == id && (GST_INDEX_ASSOC_FLAGS (entry) & flags) == flags) + break; + + if (method == GST_INDEX_LOOKUP_BEFORE) + l_entry = g_list_next (l_entry); + else if (method == GST_INDEX_LOOKUP_AFTER) { + l_entry = g_list_previous (l_entry); + } + } + } else { + entry = NULL; + } + } + + return entry; +} + +#if 0 +gboolean +gst_mem_index_plugin_init (GstPlugin * plugin) +{ + GstIndexFactory *factory; + + factory = gst_index_factory_new ("memindex", + "A index that stores entries in memory", gst_mem_index_get_type ()); + + if (factory == NULL) { + g_warning ("failed to create memindex factory"); + return FALSE; + } + + GST_PLUGIN_FEATURE (factory)->plugin_name = plugin->desc.name; + GST_PLUGIN_FEATURE (factory)->loaded = TRUE; + + gst_registry_add_feature (gst_registry_get_default (), + GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} +#endif |