1 | /* GStreamer |
---|
2 | * Copyright (C) 2001 RidgeRun (http://www.ridgerun.com/) |
---|
3 | * Written by Erik Walthinsen <omega@ridgerun.com> |
---|
4 | * |
---|
5 | * gstindex.c: Index for mappings and other data |
---|
6 | * |
---|
7 | * This library is free software; you can redistribute it and/or |
---|
8 | * modify it under the terms of the GNU Library General Public |
---|
9 | * License as published by the Free Software Foundation; either |
---|
10 | * version 2 of the License, or (at your option) any later version. |
---|
11 | * |
---|
12 | * This library is distributed in the hope that it will be useful, |
---|
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
15 | * Library General Public License for more details. |
---|
16 | * |
---|
17 | * You should have received a copy of the GNU Library General Public |
---|
18 | * License along with this library; if not, write to the |
---|
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | * Boston, MA 02111-1307, USA. |
---|
21 | */ |
---|
22 | |
---|
23 | #include "gst_private.h" |
---|
24 | |
---|
25 | #include "gstinfo.h" |
---|
26 | #include "gstregistrypool.h" |
---|
27 | #include "gstpad.h" |
---|
28 | #include "gstindex.h" |
---|
29 | #include "gstmarshal.h" |
---|
30 | |
---|
31 | /* Index signals and args */ |
---|
32 | enum |
---|
33 | { |
---|
34 | ENTRY_ADDED, |
---|
35 | LAST_SIGNAL |
---|
36 | }; |
---|
37 | |
---|
38 | enum |
---|
39 | { |
---|
40 | ARG_0, |
---|
41 | ARG_RESOLVER |
---|
42 | /* FILL ME */ |
---|
43 | }; |
---|
44 | |
---|
45 | static void gst_index_class_init (GstIndexClass * klass); |
---|
46 | static void gst_index_init (GstIndex * index); |
---|
47 | |
---|
48 | static void gst_index_set_property (GObject * object, guint prop_id, |
---|
49 | const GValue * value, GParamSpec * pspec); |
---|
50 | static void gst_index_get_property (GObject * object, guint prop_id, |
---|
51 | GValue * value, GParamSpec * pspec); |
---|
52 | |
---|
53 | static GstIndexGroup *gst_index_group_new (guint groupnum); |
---|
54 | |
---|
55 | static gboolean gst_index_path_resolver (GstIndex * index, GstObject * writer, |
---|
56 | gchar ** writer_string, gpointer data); |
---|
57 | static gboolean gst_index_gtype_resolver (GstIndex * index, GstObject * writer, |
---|
58 | gchar ** writer_string, gpointer data); |
---|
59 | static void gst_index_add_entry (GstIndex * index, GstIndexEntry * entry); |
---|
60 | |
---|
61 | static GstObject *parent_class = NULL; |
---|
62 | static guint gst_index_signals[LAST_SIGNAL] = { 0 }; |
---|
63 | |
---|
64 | typedef struct |
---|
65 | { |
---|
66 | GstIndexResolverMethod method; |
---|
67 | GstIndexResolver resolver; |
---|
68 | gpointer user_data; |
---|
69 | } |
---|
70 | ResolverEntry; |
---|
71 | |
---|
72 | static const ResolverEntry resolvers[] = { |
---|
73 | {GST_INDEX_RESOLVER_CUSTOM, NULL, NULL}, |
---|
74 | {GST_INDEX_RESOLVER_GTYPE, gst_index_gtype_resolver, NULL}, |
---|
75 | {GST_INDEX_RESOLVER_PATH, gst_index_path_resolver, NULL}, |
---|
76 | }; |
---|
77 | |
---|
78 | #define GST_TYPE_INDEX_RESOLVER (gst_index_resolver_get_type()) |
---|
79 | static GType |
---|
80 | gst_index_resolver_get_type (void) |
---|
81 | { |
---|
82 | static GType index_resolver_type = 0; |
---|
83 | static GEnumValue index_resolver[] = { |
---|
84 | {GST_INDEX_RESOLVER_CUSTOM, "GST_INDEX_RESOLVER_CUSTOM", |
---|
85 | "Use a custom resolver"}, |
---|
86 | {GST_INDEX_RESOLVER_GTYPE, "GST_INDEX_RESOLVER_GTYPE", |
---|
87 | "Resolve an object to its GType[.padname]"}, |
---|
88 | {GST_INDEX_RESOLVER_PATH, "GST_INDEX_RESOLVER_PATH", |
---|
89 | "Resolve an object to its path in the pipeline"}, |
---|
90 | {0, NULL, NULL}, |
---|
91 | }; |
---|
92 | |
---|
93 | if (!index_resolver_type) { |
---|
94 | index_resolver_type = |
---|
95 | g_enum_register_static ("GstIndexResolver", index_resolver); |
---|
96 | } |
---|
97 | return index_resolver_type; |
---|
98 | } |
---|
99 | |
---|
100 | GType |
---|
101 | gst_index_entry_get_type (void) |
---|
102 | { |
---|
103 | static GType index_entry_type = 0; |
---|
104 | |
---|
105 | if (!index_entry_type) { |
---|
106 | index_entry_type = g_boxed_type_register_static ("GstIndexEntry", |
---|
107 | (GBoxedCopyFunc) gst_index_entry_copy, |
---|
108 | (GBoxedFreeFunc) gst_index_entry_free); |
---|
109 | } |
---|
110 | return index_entry_type; |
---|
111 | } |
---|
112 | |
---|
113 | |
---|
114 | GType |
---|
115 | gst_index_get_type (void) |
---|
116 | { |
---|
117 | static GType index_type = 0; |
---|
118 | |
---|
119 | if (!index_type) { |
---|
120 | static const GTypeInfo index_info = { |
---|
121 | sizeof (GstIndexClass), |
---|
122 | NULL, |
---|
123 | NULL, |
---|
124 | (GClassInitFunc) gst_index_class_init, |
---|
125 | NULL, |
---|
126 | NULL, |
---|
127 | sizeof (GstIndex), |
---|
128 | 0, |
---|
129 | (GInstanceInitFunc) gst_index_init, |
---|
130 | NULL |
---|
131 | }; |
---|
132 | |
---|
133 | index_type = |
---|
134 | g_type_register_static (GST_TYPE_OBJECT, "GstIndex", &index_info, 0); |
---|
135 | } |
---|
136 | return index_type; |
---|
137 | } |
---|
138 | |
---|
139 | static void |
---|
140 | gst_index_class_init (GstIndexClass * klass) |
---|
141 | { |
---|
142 | GObjectClass *gobject_class; |
---|
143 | GstElementClass *gstelement_class; |
---|
144 | |
---|
145 | gobject_class = (GObjectClass *) klass; |
---|
146 | gstelement_class = (GstElementClass *) klass; |
---|
147 | |
---|
148 | parent_class = g_type_class_ref (GST_TYPE_OBJECT); |
---|
149 | |
---|
150 | gst_index_signals[ENTRY_ADDED] = |
---|
151 | g_signal_new ("entry-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, |
---|
152 | G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL, |
---|
153 | gst_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_INDEX_ENTRY); |
---|
154 | |
---|
155 | gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_index_set_property); |
---|
156 | gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_index_get_property); |
---|
157 | |
---|
158 | g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RESOLVER, |
---|
159 | g_param_spec_enum ("resolver", "Resolver", |
---|
160 | "Select a predefined object to string mapper", |
---|
161 | GST_TYPE_INDEX_RESOLVER, GST_INDEX_RESOLVER_PATH, G_PARAM_READWRITE)); |
---|
162 | } |
---|
163 | |
---|
164 | static void |
---|
165 | gst_index_init (GstIndex * index) |
---|
166 | { |
---|
167 | index->curgroup = gst_index_group_new (0); |
---|
168 | index->maxgroup = 0; |
---|
169 | index->groups = g_list_prepend (NULL, index->curgroup); |
---|
170 | |
---|
171 | index->writers = g_hash_table_new (NULL, NULL); |
---|
172 | index->last_id = 0; |
---|
173 | |
---|
174 | index->method = GST_INDEX_RESOLVER_PATH; |
---|
175 | index->resolver = resolvers[index->method].resolver; |
---|
176 | index->resolver_user_data = resolvers[index->method].user_data; |
---|
177 | |
---|
178 | GST_FLAG_SET (index, GST_INDEX_WRITABLE); |
---|
179 | GST_FLAG_SET (index, GST_INDEX_READABLE); |
---|
180 | |
---|
181 | GST_DEBUG ("created new index"); |
---|
182 | } |
---|
183 | |
---|
184 | static void |
---|
185 | gst_index_set_property (GObject * object, guint prop_id, |
---|
186 | const GValue * value, GParamSpec * pspec) |
---|
187 | { |
---|
188 | GstIndex *index; |
---|
189 | |
---|
190 | index = GST_INDEX (object); |
---|
191 | |
---|
192 | switch (prop_id) { |
---|
193 | case ARG_RESOLVER: |
---|
194 | index->method = g_value_get_enum (value); |
---|
195 | index->resolver = resolvers[index->method].resolver; |
---|
196 | index->resolver_user_data = resolvers[index->method].user_data; |
---|
197 | break; |
---|
198 | default: |
---|
199 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
200 | break; |
---|
201 | } |
---|
202 | } |
---|
203 | |
---|
204 | static void |
---|
205 | gst_index_get_property (GObject * object, guint prop_id, |
---|
206 | GValue * value, GParamSpec * pspec) |
---|
207 | { |
---|
208 | GstIndex *index; |
---|
209 | |
---|
210 | index = GST_INDEX (object); |
---|
211 | |
---|
212 | switch (prop_id) { |
---|
213 | case ARG_RESOLVER: |
---|
214 | g_value_set_enum (value, index->method); |
---|
215 | break; |
---|
216 | default: |
---|
217 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
218 | break; |
---|
219 | } |
---|
220 | } |
---|
221 | |
---|
222 | static GstIndexGroup * |
---|
223 | gst_index_group_new (guint groupnum) |
---|
224 | { |
---|
225 | GstIndexGroup *indexgroup = g_new (GstIndexGroup, 1); |
---|
226 | |
---|
227 | indexgroup->groupnum = groupnum; |
---|
228 | indexgroup->entries = NULL; |
---|
229 | indexgroup->certainty = GST_INDEX_UNKNOWN; |
---|
230 | indexgroup->peergroup = -1; |
---|
231 | |
---|
232 | GST_DEBUG ("created new index group %d", groupnum); |
---|
233 | |
---|
234 | return indexgroup; |
---|
235 | } |
---|
236 | |
---|
237 | /** |
---|
238 | * gst_index_new: |
---|
239 | * |
---|
240 | * Create a new tileindex object |
---|
241 | * |
---|
242 | * Returns: a new index object |
---|
243 | */ |
---|
244 | GstIndex * |
---|
245 | gst_index_new (void) |
---|
246 | { |
---|
247 | GstIndex *index; |
---|
248 | |
---|
249 | index = g_object_new (gst_index_get_type (), NULL); |
---|
250 | |
---|
251 | return index; |
---|
252 | } |
---|
253 | |
---|
254 | /** |
---|
255 | * gst_index_commit: |
---|
256 | * @index: the index to commit |
---|
257 | * @id: the writer that commited the index |
---|
258 | * |
---|
259 | * Tell the index that the writer with the given id is done |
---|
260 | * with this index and is not going to write any more entries |
---|
261 | * to it. |
---|
262 | */ |
---|
263 | void |
---|
264 | gst_index_commit (GstIndex * index, gint id) |
---|
265 | { |
---|
266 | GstIndexClass *iclass; |
---|
267 | |
---|
268 | iclass = GST_INDEX_GET_CLASS (index); |
---|
269 | |
---|
270 | if (iclass->commit) |
---|
271 | iclass->commit (index, id); |
---|
272 | } |
---|
273 | |
---|
274 | |
---|
275 | /** |
---|
276 | * gst_index_get_group: |
---|
277 | * @index: the index to get the current group from |
---|
278 | * |
---|
279 | * Get the id of the current group. |
---|
280 | * |
---|
281 | * Returns: the id of the current group. |
---|
282 | */ |
---|
283 | gint |
---|
284 | gst_index_get_group (GstIndex * index) |
---|
285 | { |
---|
286 | return index->curgroup->groupnum; |
---|
287 | } |
---|
288 | |
---|
289 | /** |
---|
290 | * gst_index_new_group: |
---|
291 | * @index: the index to create the new group in |
---|
292 | * |
---|
293 | * Create a new group for the given index. It will be |
---|
294 | * set as the current group. |
---|
295 | * |
---|
296 | * Returns: the id of the newly created group. |
---|
297 | */ |
---|
298 | gint |
---|
299 | gst_index_new_group (GstIndex * index) |
---|
300 | { |
---|
301 | index->curgroup = gst_index_group_new (++index->maxgroup); |
---|
302 | index->groups = g_list_append (index->groups, index->curgroup); |
---|
303 | GST_DEBUG ("created new group %d in index", index->maxgroup); |
---|
304 | return index->maxgroup; |
---|
305 | } |
---|
306 | |
---|
307 | /** |
---|
308 | * gst_index_set_group: |
---|
309 | * @index: the index to set the new group in |
---|
310 | * @groupnum: the groupnumber to set |
---|
311 | * |
---|
312 | * Set the current groupnumber to the given argument. |
---|
313 | * |
---|
314 | * Returns: TRUE if the operation succeeded, FALSE if the group |
---|
315 | * did not exist. |
---|
316 | */ |
---|
317 | gboolean |
---|
318 | gst_index_set_group (GstIndex * index, gint groupnum) |
---|
319 | { |
---|
320 | GList *list; |
---|
321 | GstIndexGroup *indexgroup; |
---|
322 | |
---|
323 | /* first check for null change */ |
---|
324 | if (groupnum == index->curgroup->groupnum) |
---|
325 | return TRUE; |
---|
326 | |
---|
327 | /* else search for the proper group */ |
---|
328 | list = index->groups; |
---|
329 | while (list) { |
---|
330 | indexgroup = (GstIndexGroup *) (list->data); |
---|
331 | list = g_list_next (list); |
---|
332 | if (indexgroup->groupnum == groupnum) { |
---|
333 | index->curgroup = indexgroup; |
---|
334 | GST_DEBUG ("switched to index group %d", indexgroup->groupnum); |
---|
335 | return TRUE; |
---|
336 | } |
---|
337 | } |
---|
338 | |
---|
339 | /* couldn't find the group in question */ |
---|
340 | GST_DEBUG ("couldn't find index group %d", groupnum); |
---|
341 | return FALSE; |
---|
342 | } |
---|
343 | |
---|
344 | /** |
---|
345 | * gst_index_set_certainty: |
---|
346 | * @index: the index to set the certainty on |
---|
347 | * @certainty: the certainty to set |
---|
348 | * |
---|
349 | * Set the certainty of the given index. |
---|
350 | */ |
---|
351 | void |
---|
352 | gst_index_set_certainty (GstIndex * index, GstIndexCertainty certainty) |
---|
353 | { |
---|
354 | index->curgroup->certainty = certainty; |
---|
355 | } |
---|
356 | |
---|
357 | /** |
---|
358 | * gst_index_get_certainty: |
---|
359 | * @index: the index to get the certainty of |
---|
360 | * |
---|
361 | * Get the certainty of the given index. |
---|
362 | * |
---|
363 | * Returns: the certainty of the index. |
---|
364 | */ |
---|
365 | GstIndexCertainty |
---|
366 | gst_index_get_certainty (GstIndex * index) |
---|
367 | { |
---|
368 | return index->curgroup->certainty; |
---|
369 | } |
---|
370 | |
---|
371 | /** |
---|
372 | * gst_index_set_filter: |
---|
373 | * @index: the index to register the filter on |
---|
374 | * @filter: the filter to register |
---|
375 | * @user_data: data passed to the filter function |
---|
376 | * |
---|
377 | * Lets the app register a custom filter function so that |
---|
378 | * it can select what entries should be stored in the index. |
---|
379 | */ |
---|
380 | void |
---|
381 | gst_index_set_filter (GstIndex * index, |
---|
382 | GstIndexFilter filter, gpointer user_data) |
---|
383 | { |
---|
384 | g_return_if_fail (GST_IS_INDEX (index)); |
---|
385 | |
---|
386 | index->filter = filter; |
---|
387 | index->filter_user_data = user_data; |
---|
388 | } |
---|
389 | |
---|
390 | /** |
---|
391 | * gst_index_set_resolver: |
---|
392 | * @index: the index to register the resolver on |
---|
393 | * @resolver: the resolver to register |
---|
394 | * @user_data: data passed to the resolver function |
---|
395 | * |
---|
396 | * Lets the app register a custom function to map index |
---|
397 | * ids to writer descriptions. |
---|
398 | */ |
---|
399 | void |
---|
400 | gst_index_set_resolver (GstIndex * index, |
---|
401 | GstIndexResolver resolver, gpointer user_data) |
---|
402 | { |
---|
403 | g_return_if_fail (GST_IS_INDEX (index)); |
---|
404 | |
---|
405 | index->resolver = resolver; |
---|
406 | index->resolver_user_data = user_data; |
---|
407 | index->method = GST_INDEX_RESOLVER_CUSTOM; |
---|
408 | } |
---|
409 | |
---|
410 | /** |
---|
411 | * gst_index_entry_copy: |
---|
412 | * @entry: the entry to copy |
---|
413 | * |
---|
414 | * Copies an entry and returns the result. |
---|
415 | * |
---|
416 | * Returns: a newly allocated #GstIndexEntry. |
---|
417 | */ |
---|
418 | GstIndexEntry * |
---|
419 | gst_index_entry_copy (GstIndexEntry * entry) |
---|
420 | { |
---|
421 | return g_memdup (entry, sizeof (*entry)); |
---|
422 | } |
---|
423 | |
---|
424 | /** |
---|
425 | * gst_index_entry_free: |
---|
426 | * @entry: the entry to free |
---|
427 | * |
---|
428 | * Free the memory used by the given entry. |
---|
429 | */ |
---|
430 | void |
---|
431 | gst_index_entry_free (GstIndexEntry * entry) |
---|
432 | { |
---|
433 | g_free (entry); |
---|
434 | } |
---|
435 | |
---|
436 | /** |
---|
437 | * gst_index_add_format: |
---|
438 | * @index: the index to add the entry to |
---|
439 | * @id: the id of the index writer |
---|
440 | * @format: the format to add to the index |
---|
441 | * |
---|
442 | * Adds a format entry into the index. This function is |
---|
443 | * used to map dynamic GstFormat ids to their original |
---|
444 | * format key. |
---|
445 | * |
---|
446 | * Returns: a pointer to the newly added entry in the index. |
---|
447 | */ |
---|
448 | GstIndexEntry * |
---|
449 | gst_index_add_format (GstIndex * index, gint id, GstFormat format) |
---|
450 | { |
---|
451 | GstIndexEntry *entry; |
---|
452 | const GstFormatDefinition *def; |
---|
453 | |
---|
454 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
455 | g_return_val_if_fail (format != 0, NULL); |
---|
456 | |
---|
457 | if (!GST_INDEX_IS_WRITABLE (index) || id == -1) |
---|
458 | return NULL; |
---|
459 | |
---|
460 | entry = g_new0 (GstIndexEntry, 1); |
---|
461 | entry->type = GST_INDEX_ENTRY_FORMAT; |
---|
462 | entry->id = id; |
---|
463 | entry->data.format.format = format; |
---|
464 | |
---|
465 | def = gst_format_get_details (format); |
---|
466 | entry->data.format.key = def->nick; |
---|
467 | |
---|
468 | gst_index_add_entry (index, entry); |
---|
469 | |
---|
470 | return entry; |
---|
471 | } |
---|
472 | |
---|
473 | /** |
---|
474 | * gst_index_add_id: |
---|
475 | * @index: the index to add the entry to |
---|
476 | * @id: the id of the index writer |
---|
477 | * @description: the description of the index writer |
---|
478 | * |
---|
479 | * Add an id entry into the index. |
---|
480 | * |
---|
481 | * Returns: a pointer to the newly added entry in the index. |
---|
482 | */ |
---|
483 | GstIndexEntry * |
---|
484 | gst_index_add_id (GstIndex * index, gint id, gchar * description) |
---|
485 | { |
---|
486 | GstIndexEntry *entry; |
---|
487 | |
---|
488 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
489 | g_return_val_if_fail (description != NULL, NULL); |
---|
490 | |
---|
491 | if (!GST_INDEX_IS_WRITABLE (index) || id == -1) |
---|
492 | return NULL; |
---|
493 | |
---|
494 | entry = g_new0 (GstIndexEntry, 1); |
---|
495 | entry->type = GST_INDEX_ENTRY_ID; |
---|
496 | entry->id = id; |
---|
497 | entry->data.id.description = description; |
---|
498 | |
---|
499 | gst_index_add_entry (index, entry); |
---|
500 | |
---|
501 | return entry; |
---|
502 | } |
---|
503 | |
---|
504 | static gboolean |
---|
505 | gst_index_path_resolver (GstIndex * index, GstObject * writer, |
---|
506 | gchar ** writer_string, gpointer data) |
---|
507 | { |
---|
508 | *writer_string = gst_object_get_path_string (writer); |
---|
509 | |
---|
510 | return TRUE; |
---|
511 | } |
---|
512 | |
---|
513 | static gboolean |
---|
514 | gst_index_gtype_resolver (GstIndex * index, GstObject * writer, |
---|
515 | gchar ** writer_string, gpointer data) |
---|
516 | { |
---|
517 | if (GST_IS_PAD (writer)) { |
---|
518 | GstElement *element = gst_pad_get_parent (GST_PAD (writer)); |
---|
519 | |
---|
520 | *writer_string = g_strdup_printf ("%s.%s", |
---|
521 | g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer)); |
---|
522 | } else { |
---|
523 | *writer_string = |
---|
524 | g_strdup_printf ("%s", g_type_name (G_OBJECT_TYPE (writer))); |
---|
525 | } |
---|
526 | |
---|
527 | return TRUE; |
---|
528 | } |
---|
529 | |
---|
530 | /** |
---|
531 | * gst_index_get_writer_id: |
---|
532 | * @index: the index to get a unique write id for |
---|
533 | * @writer: the GstObject to allocate an id for |
---|
534 | * @id: a pointer to a gint to hold the id |
---|
535 | * |
---|
536 | * Before entries can be added to the index, a writer |
---|
537 | * should obtain a unique id. The methods to add new entries |
---|
538 | * to the index require this id as an argument. |
---|
539 | * |
---|
540 | * The application can implement a custom function to map the writer object |
---|
541 | * to a string. That string will be used to register or look up an id |
---|
542 | * in the index. |
---|
543 | * |
---|
544 | * Returns: TRUE if the writer would be mapped to an id. |
---|
545 | */ |
---|
546 | gboolean |
---|
547 | gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id) |
---|
548 | { |
---|
549 | gchar *writer_string = NULL; |
---|
550 | GstIndexEntry *entry; |
---|
551 | GstIndexClass *iclass; |
---|
552 | gboolean success = FALSE; |
---|
553 | |
---|
554 | g_return_val_if_fail (GST_IS_INDEX (index), FALSE); |
---|
555 | g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE); |
---|
556 | g_return_val_if_fail (id, FALSE); |
---|
557 | |
---|
558 | *id = -1; |
---|
559 | |
---|
560 | /* first try to get a previously cached id */ |
---|
561 | entry = g_hash_table_lookup (index->writers, writer); |
---|
562 | if (entry == NULL) { |
---|
563 | |
---|
564 | iclass = GST_INDEX_GET_CLASS (index); |
---|
565 | |
---|
566 | /* let the app make a string */ |
---|
567 | if (index->resolver) { |
---|
568 | gboolean res; |
---|
569 | |
---|
570 | res = |
---|
571 | index->resolver (index, writer, &writer_string, |
---|
572 | index->resolver_user_data); |
---|
573 | if (!res) |
---|
574 | return FALSE; |
---|
575 | } else { |
---|
576 | g_warning ("no resolver found"); |
---|
577 | return FALSE; |
---|
578 | } |
---|
579 | |
---|
580 | /* if the index has a resolver, make it map this string to an id */ |
---|
581 | if (iclass->get_writer_id) { |
---|
582 | success = iclass->get_writer_id (index, id, writer_string); |
---|
583 | } |
---|
584 | /* if the index could not resolve, we allocate one ourselves */ |
---|
585 | if (!success) { |
---|
586 | *id = ++index->last_id; |
---|
587 | } |
---|
588 | |
---|
589 | entry = gst_index_add_id (index, *id, writer_string); |
---|
590 | if (!entry) { |
---|
591 | /* index is probably not writable, make an entry anyway |
---|
592 | * to keep it in our cache */ |
---|
593 | entry = g_new0 (GstIndexEntry, 1); |
---|
594 | entry->type = GST_INDEX_ENTRY_ID; |
---|
595 | entry->id = *id; |
---|
596 | entry->data.id.description = writer_string; |
---|
597 | } |
---|
598 | g_hash_table_insert (index->writers, writer, entry); |
---|
599 | } else { |
---|
600 | *id = entry->id; |
---|
601 | } |
---|
602 | |
---|
603 | return TRUE; |
---|
604 | } |
---|
605 | |
---|
606 | static void |
---|
607 | gst_index_add_entry (GstIndex * index, GstIndexEntry * entry) |
---|
608 | { |
---|
609 | GstIndexClass *iclass; |
---|
610 | |
---|
611 | iclass = GST_INDEX_GET_CLASS (index); |
---|
612 | |
---|
613 | if (iclass->add_entry) { |
---|
614 | iclass->add_entry (index, entry); |
---|
615 | } |
---|
616 | |
---|
617 | g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry); |
---|
618 | } |
---|
619 | |
---|
620 | /** |
---|
621 | * gst_index_add_associationv: |
---|
622 | * @index: the index to add the entry to |
---|
623 | * @id: the id of the index writer |
---|
624 | * @flags: optinal flags for this entry |
---|
625 | * @n: number of associations |
---|
626 | * @list: list of associations |
---|
627 | * @...: other format/value pairs or 0 to end the list |
---|
628 | * |
---|
629 | * Associate given format/value pairs with each other. |
---|
630 | * |
---|
631 | * Returns: a pointer to the newly added entry in the index. |
---|
632 | */ |
---|
633 | GstIndexEntry * |
---|
634 | gst_index_add_associationv (GstIndex * index, gint id, GstAssocFlags flags, |
---|
635 | int n, const GstIndexAssociation * list) |
---|
636 | { |
---|
637 | GstIndexEntry *entry; |
---|
638 | |
---|
639 | g_return_val_if_fail (n > 0, NULL); |
---|
640 | g_return_val_if_fail (list != NULL, NULL); |
---|
641 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
642 | |
---|
643 | if (!GST_INDEX_IS_WRITABLE (index) || id == -1) |
---|
644 | return NULL; |
---|
645 | |
---|
646 | entry = g_malloc (sizeof (GstIndexEntry)); |
---|
647 | |
---|
648 | entry->type = GST_INDEX_ENTRY_ASSOCIATION; |
---|
649 | entry->id = id; |
---|
650 | entry->data.assoc.flags = flags; |
---|
651 | entry->data.assoc.assocs = g_memdup (list, sizeof (GstIndexAssociation) * n); |
---|
652 | entry->data.assoc.nassocs = n; |
---|
653 | |
---|
654 | gst_index_add_entry (index, entry); |
---|
655 | |
---|
656 | return entry; |
---|
657 | } |
---|
658 | |
---|
659 | /** |
---|
660 | * gst_index_add_association: |
---|
661 | * @index: the index to add the entry to |
---|
662 | * @id: the id of the index writer |
---|
663 | * @flags: optinal flags for this entry |
---|
664 | * @format: the format of the value |
---|
665 | * @value: the value |
---|
666 | * @...: other format/value pairs or 0 to end the list |
---|
667 | * |
---|
668 | * Associate given format/value pairs with each other. |
---|
669 | * Be sure to pass gint64 values to this functions varargs, |
---|
670 | * you might want to use a gint64 cast to be sure. |
---|
671 | * |
---|
672 | * Returns: a pointer to the newly added entry in the index. |
---|
673 | */ |
---|
674 | GstIndexEntry * |
---|
675 | gst_index_add_association (GstIndex * index, gint id, GstAssocFlags flags, |
---|
676 | GstFormat format, gint64 value, ...) |
---|
677 | { |
---|
678 | va_list args; |
---|
679 | GstIndexEntry *entry; |
---|
680 | GstIndexAssociation *list; |
---|
681 | gint n_assocs = 0; |
---|
682 | GstFormat cur_format; |
---|
683 | GArray *array; |
---|
684 | |
---|
685 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
686 | g_return_val_if_fail (format != 0, NULL); |
---|
687 | |
---|
688 | if (!GST_INDEX_IS_WRITABLE (index) || id == -1) |
---|
689 | return NULL; |
---|
690 | |
---|
691 | array = g_array_new (FALSE, FALSE, sizeof (GstIndexAssociation)); |
---|
692 | |
---|
693 | va_start (args, value); |
---|
694 | |
---|
695 | cur_format = format; |
---|
696 | n_assocs = 0; |
---|
697 | while (cur_format) { |
---|
698 | GstIndexAssociation a; |
---|
699 | |
---|
700 | n_assocs++; |
---|
701 | cur_format = va_arg (args, GstFormat); |
---|
702 | if (cur_format) { |
---|
703 | a.format = cur_format; |
---|
704 | a.value = va_arg (args, gint64); |
---|
705 | |
---|
706 | g_array_append_val (array, a); |
---|
707 | } |
---|
708 | } |
---|
709 | va_end (args); |
---|
710 | |
---|
711 | list = (GstIndexAssociation *) g_array_free (array, FALSE); |
---|
712 | |
---|
713 | entry = gst_index_add_associationv (index, id, flags, n_assocs, list); |
---|
714 | g_free (list); |
---|
715 | |
---|
716 | return entry; |
---|
717 | } |
---|
718 | |
---|
719 | /** |
---|
720 | * gst_index_add_object: |
---|
721 | * @index: the index to add the object to |
---|
722 | * @id: the id of the index writer |
---|
723 | * @key: a key for the object |
---|
724 | * @type: the GType of the object |
---|
725 | * @object: a pointer to the object to add |
---|
726 | * |
---|
727 | * Add the given object to the index with the given key. |
---|
728 | * |
---|
729 | * Returns: a pointer to the newly added entry in the index. |
---|
730 | */ |
---|
731 | GstIndexEntry * |
---|
732 | gst_index_add_object (GstIndex * index, gint id, gchar * key, |
---|
733 | GType type, gpointer object) |
---|
734 | { |
---|
735 | if (!GST_INDEX_IS_WRITABLE (index) || id == -1) |
---|
736 | return NULL; |
---|
737 | |
---|
738 | return NULL; |
---|
739 | } |
---|
740 | |
---|
741 | static gint |
---|
742 | gst_index_compare_func (gconstpointer a, gconstpointer b, gpointer user_data) |
---|
743 | { |
---|
744 | if (a < b) |
---|
745 | return -1; |
---|
746 | if (a > b) |
---|
747 | return 1; |
---|
748 | return 0; |
---|
749 | } |
---|
750 | |
---|
751 | /** |
---|
752 | * gst_index_get_assoc_entry: |
---|
753 | * @index: the index to search |
---|
754 | * @id: the id of the index writer |
---|
755 | * @method: The lookup method to use |
---|
756 | * @flags: Flags for the entry |
---|
757 | * @format: the format of the value |
---|
758 | * @value: the value to find |
---|
759 | * |
---|
760 | * Finds the given format/value in the index |
---|
761 | * |
---|
762 | * Returns: the entry associated with the value or NULL if the |
---|
763 | * value was not found. |
---|
764 | */ |
---|
765 | GstIndexEntry * |
---|
766 | gst_index_get_assoc_entry (GstIndex * index, gint id, |
---|
767 | GstIndexLookupMethod method, GstAssocFlags flags, |
---|
768 | GstFormat format, gint64 value) |
---|
769 | { |
---|
770 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
771 | |
---|
772 | if (id == -1) |
---|
773 | return NULL; |
---|
774 | |
---|
775 | return gst_index_get_assoc_entry_full (index, id, method, flags, format, |
---|
776 | value, gst_index_compare_func, NULL); |
---|
777 | } |
---|
778 | |
---|
779 | /** |
---|
780 | * gst_index_get_assoc_entry_full: |
---|
781 | * @index: the index to search |
---|
782 | * @id: the id of the index writer |
---|
783 | * @method: The lookup method to use |
---|
784 | * @flags: Flags for the entry |
---|
785 | * @format: the format of the value |
---|
786 | * @value: the value to find |
---|
787 | * @func: the function used to compare entries |
---|
788 | * @user_data: user data passed to the compare function |
---|
789 | * |
---|
790 | * Finds the given format/value in the index with the given |
---|
791 | * compare function and user_data. |
---|
792 | * |
---|
793 | * Returns: the entry associated with the value or NULL if the |
---|
794 | * value was not found. |
---|
795 | */ |
---|
796 | GstIndexEntry * |
---|
797 | gst_index_get_assoc_entry_full (GstIndex * index, gint id, |
---|
798 | GstIndexLookupMethod method, GstAssocFlags flags, |
---|
799 | GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data) |
---|
800 | { |
---|
801 | GstIndexClass *iclass; |
---|
802 | |
---|
803 | g_return_val_if_fail (GST_IS_INDEX (index), NULL); |
---|
804 | |
---|
805 | if (id == -1) |
---|
806 | return NULL; |
---|
807 | |
---|
808 | iclass = GST_INDEX_GET_CLASS (index); |
---|
809 | |
---|
810 | if (iclass->get_assoc_entry) |
---|
811 | return iclass->get_assoc_entry (index, id, method, flags, format, value, |
---|
812 | func, user_data); |
---|
813 | |
---|
814 | return NULL; |
---|
815 | } |
---|
816 | |
---|
817 | /** |
---|
818 | * gst_index_entry_assoc_map: |
---|
819 | * @entry: the index to search |
---|
820 | * @format: the format of the value the find |
---|
821 | * @value: a pointer to store the value |
---|
822 | * |
---|
823 | * Gets alternative formats associated with the indexentry. |
---|
824 | * |
---|
825 | * Returns: TRUE if there was a value associated with the given |
---|
826 | * format. |
---|
827 | */ |
---|
828 | gboolean |
---|
829 | gst_index_entry_assoc_map (GstIndexEntry * entry, |
---|
830 | GstFormat format, gint64 * value) |
---|
831 | { |
---|
832 | gint i; |
---|
833 | |
---|
834 | g_return_val_if_fail (entry != NULL, FALSE); |
---|
835 | g_return_val_if_fail (value != NULL, FALSE); |
---|
836 | |
---|
837 | for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) { |
---|
838 | if (GST_INDEX_ASSOC_FORMAT (entry, i) == format) { |
---|
839 | *value = GST_INDEX_ASSOC_VALUE (entry, i); |
---|
840 | return TRUE; |
---|
841 | } |
---|
842 | } |
---|
843 | return FALSE; |
---|
844 | } |
---|
845 | |
---|
846 | |
---|
847 | static void gst_index_factory_class_init (GstIndexFactoryClass * klass); |
---|
848 | static void gst_index_factory_init (GstIndexFactory * factory); |
---|
849 | |
---|
850 | static GstPluginFeatureClass *factory_parent_class = NULL; |
---|
851 | |
---|
852 | /* static guint gst_index_factory_signals[LAST_SIGNAL] = { 0 }; */ |
---|
853 | |
---|
854 | GType |
---|
855 | gst_index_factory_get_type (void) |
---|
856 | { |
---|
857 | static GType indexfactory_type = 0; |
---|
858 | |
---|
859 | if (!indexfactory_type) { |
---|
860 | static const GTypeInfo indexfactory_info = { |
---|
861 | sizeof (GstIndexFactoryClass), |
---|
862 | NULL, |
---|
863 | NULL, |
---|
864 | (GClassInitFunc) gst_index_factory_class_init, |
---|
865 | NULL, |
---|
866 | NULL, |
---|
867 | sizeof (GstIndexFactory), |
---|
868 | 0, |
---|
869 | (GInstanceInitFunc) gst_index_factory_init, |
---|
870 | NULL |
---|
871 | }; |
---|
872 | |
---|
873 | indexfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, |
---|
874 | "GstIndexFactory", &indexfactory_info, 0); |
---|
875 | } |
---|
876 | return indexfactory_type; |
---|
877 | } |
---|
878 | |
---|
879 | static void |
---|
880 | gst_index_factory_class_init (GstIndexFactoryClass * klass) |
---|
881 | { |
---|
882 | GObjectClass *gobject_class; |
---|
883 | GstObjectClass *gstobject_class; |
---|
884 | GstPluginFeatureClass *gstpluginfeature_class; |
---|
885 | |
---|
886 | gobject_class = (GObjectClass *) klass; |
---|
887 | gstobject_class = (GstObjectClass *) klass; |
---|
888 | gstpluginfeature_class = (GstPluginFeatureClass *) klass; |
---|
889 | |
---|
890 | factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE); |
---|
891 | } |
---|
892 | |
---|
893 | static void |
---|
894 | gst_index_factory_init (GstIndexFactory * factory) |
---|
895 | { |
---|
896 | } |
---|
897 | |
---|
898 | /** |
---|
899 | * gst_index_factory_new: |
---|
900 | * @name: name of indexfactory to create |
---|
901 | * @longdesc: long description of indexfactory to create |
---|
902 | * @type: the GType of the GstIndex element of this factory |
---|
903 | * |
---|
904 | * Create a new indexfactory with the given parameters |
---|
905 | * |
---|
906 | * Returns: a new #GstIndexFactory. |
---|
907 | */ |
---|
908 | GstIndexFactory * |
---|
909 | gst_index_factory_new (const gchar * name, const gchar * longdesc, GType type) |
---|
910 | { |
---|
911 | GstIndexFactory *factory; |
---|
912 | |
---|
913 | g_return_val_if_fail (name != NULL, NULL); |
---|
914 | factory = gst_index_factory_find (name); |
---|
915 | if (!factory) { |
---|
916 | factory = GST_INDEX_FACTORY (g_object_new (GST_TYPE_INDEX_FACTORY, NULL)); |
---|
917 | } |
---|
918 | |
---|
919 | GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name); |
---|
920 | if (factory->longdesc) |
---|
921 | g_free (factory->longdesc); |
---|
922 | factory->longdesc = g_strdup (longdesc); |
---|
923 | factory->type = type; |
---|
924 | |
---|
925 | return factory; |
---|
926 | } |
---|
927 | |
---|
928 | /** |
---|
929 | * gst_index_factory_destroy: |
---|
930 | * @factory: factory to destroy |
---|
931 | * |
---|
932 | * Removes the index from the global list. |
---|
933 | */ |
---|
934 | void |
---|
935 | gst_index_factory_destroy (GstIndexFactory * factory) |
---|
936 | { |
---|
937 | g_return_if_fail (factory != NULL); |
---|
938 | |
---|
939 | /* we don't free the struct bacause someone might have a handle to it.. */ |
---|
940 | } |
---|
941 | |
---|
942 | /** |
---|
943 | * gst_index_factory_find: |
---|
944 | * @name: name of indexfactory to find |
---|
945 | * |
---|
946 | * Search for an indexfactory of the given name. |
---|
947 | * |
---|
948 | * Returns: #GstIndexFactory if found, NULL otherwise |
---|
949 | */ |
---|
950 | GstIndexFactory * |
---|
951 | gst_index_factory_find (const gchar * name) |
---|
952 | { |
---|
953 | GstPluginFeature *feature; |
---|
954 | |
---|
955 | g_return_val_if_fail (name != NULL, NULL); |
---|
956 | |
---|
957 | GST_DEBUG ("gstindex: find \"%s\"", name); |
---|
958 | |
---|
959 | feature = gst_registry_pool_find_feature (name, GST_TYPE_INDEX_FACTORY); |
---|
960 | if (feature) |
---|
961 | return GST_INDEX_FACTORY (feature); |
---|
962 | |
---|
963 | return NULL; |
---|
964 | } |
---|
965 | |
---|
966 | /** |
---|
967 | * gst_index_factory_create: |
---|
968 | * @factory: the factory used to create the instance |
---|
969 | * |
---|
970 | * Create a new #GstIndex instance from the |
---|
971 | * given indexfactory. |
---|
972 | * |
---|
973 | * Returns: A new #GstIndex instance. |
---|
974 | */ |
---|
975 | GstIndex * |
---|
976 | gst_index_factory_create (GstIndexFactory * factory) |
---|
977 | { |
---|
978 | GstIndex *new = NULL; |
---|
979 | |
---|
980 | g_return_val_if_fail (factory != NULL, NULL); |
---|
981 | |
---|
982 | if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) { |
---|
983 | g_return_val_if_fail (factory->type != 0, NULL); |
---|
984 | |
---|
985 | new = GST_INDEX (g_object_new (factory->type, NULL)); |
---|
986 | } |
---|
987 | |
---|
988 | return new; |
---|
989 | } |
---|
990 | |
---|
991 | /** |
---|
992 | * gst_index_factory_make: |
---|
993 | * @name: the name of the factory used to create the instance |
---|
994 | * |
---|
995 | * Create a new #GstIndex instance from the |
---|
996 | * indexfactory with the given name. |
---|
997 | * |
---|
998 | * Returns: A new #GstIndex instance. |
---|
999 | */ |
---|
1000 | GstIndex * |
---|
1001 | gst_index_factory_make (const gchar * name) |
---|
1002 | { |
---|
1003 | GstIndexFactory *factory; |
---|
1004 | |
---|
1005 | g_return_val_if_fail (name != NULL, NULL); |
---|
1006 | |
---|
1007 | factory = gst_index_factory_find (name); |
---|
1008 | |
---|
1009 | if (factory == NULL) |
---|
1010 | return NULL; |
---|
1011 | |
---|
1012 | return gst_index_factory_create (factory); |
---|
1013 | } |
---|