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