]> git.sesse.net Git - vlc/blob - src/misc/objects.c
* src/input/demux.c, src/misc/objects.c: demux2 has the VLC_OBJECT_DEMUX type.
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /**
25  * \file
26  * This file contains the functions to handle the vlc_object_t type
27  */
28
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <vlc/vlc.h>
34
35 #ifdef HAVE_STDLIB_H
36 #   include <stdlib.h>                                          /* realloc() */
37 #endif
38
39 #include "stream_control.h"
40 #include "input_ext-intf.h"
41 #include "input_ext-dec.h"
42
43 #include "vlc_video.h"
44 #include "video_output.h"
45
46 #include "audio_output.h"
47 #include "aout_internal.h"
48 #include "stream_output.h"
49
50 #include "vlc_playlist.h"
51 #include "vlc_interface.h"
52 #include "vlc_codec.h"
53
54 #include "vlc_httpd.h"
55 #include "vlc_vlm.h"
56 /*****************************************************************************
57  * Local prototypes
58  *****************************************************************************/
59 static int  DumpCommand( vlc_object_t *, char const *,
60                          vlc_value_t, vlc_value_t, void * );
61
62 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
63 static void           DetachObject  ( vlc_object_t * );
64 static void           PrintObject   ( vlc_object_t *, const char * );
65 static void           DumpStructure ( vlc_object_t *, int, char * );
66 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
67 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
68
69 static vlc_list_t   * NewList       ( int );
70 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
71 static void           ListAppend    ( vlc_list_t *, vlc_object_t * );
72 static int            CountChildren ( vlc_object_t *, int );
73 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
74
75 /*****************************************************************************
76  * Local structure lock
77  *****************************************************************************/
78 static vlc_mutex_t    structure_lock;
79
80 /*****************************************************************************
81  * vlc_object_create: initialize a vlc object
82  *****************************************************************************
83  * This function allocates memory for a vlc object and initializes it. If
84  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
85  * so on, vlc_object_create will use its value for the object size.
86  *****************************************************************************/
87
88 /**
89  * Initialize a vlc object
90  *
91  * This function allocates memory for a vlc object and initializes it. If
92  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
93  * so on, vlc_object_create will use its value for the object size.
94  */
95 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
96 {
97     vlc_object_t * p_new;
98     char *         psz_type;
99     size_t         i_size;
100
101     switch( i_type )
102     {
103         case VLC_OBJECT_ROOT:
104             i_size = sizeof(libvlc_t);
105             psz_type = "root";
106             break;
107         case VLC_OBJECT_VLC:
108             i_size = sizeof(vlc_t);
109             psz_type = "vlc";
110             break;
111         case VLC_OBJECT_MODULE:
112             i_size = sizeof(module_t);
113             psz_type = "module";
114             break;
115         case VLC_OBJECT_INTF:
116             i_size = sizeof(intf_thread_t);
117             psz_type = "interface";
118             break;
119         case VLC_OBJECT_DIALOGS:
120             i_size = sizeof(intf_thread_t);
121             psz_type = "dialogs provider";
122             break;
123         case VLC_OBJECT_PLAYLIST:
124             i_size = sizeof(playlist_t);
125             psz_type = "playlist";
126             break;
127         case VLC_OBJECT_INPUT:
128             i_size = sizeof(input_thread_t);
129             psz_type = "input";
130             break;
131         case VLC_OBJECT_DEMUX:
132             i_size = sizeof(demux_t);
133             psz_type = "demux";
134             break;
135         case VLC_OBJECT_DECODER:
136             i_size = sizeof(decoder_t);
137             psz_type = "decoder";
138             break;
139         case VLC_OBJECT_PACKETIZER:
140             i_size = sizeof(decoder_t);
141             psz_type = "packetizer";
142             break;
143         case VLC_OBJECT_ENCODER:
144             i_size = sizeof(encoder_t);
145             psz_type = "encoder";
146             break;
147         case VLC_OBJECT_VOUT:
148             i_size = sizeof(vout_thread_t);
149             psz_type = "video output";
150             break;
151         case VLC_OBJECT_AOUT:
152             i_size = sizeof(aout_instance_t);
153             psz_type = "audio output";
154             break;
155         case VLC_OBJECT_SOUT:
156             i_size = sizeof(sout_instance_t);
157             psz_type = "stream output";
158             break;
159         case VLC_OBJECT_HTTPD:
160             i_size = sizeof( httpd_t );
161             psz_type = "http daemon";
162             break;
163         case VLC_OBJECT_VLM:
164             i_size = sizeof( vlm_t );
165             psz_type = "vlm dameon";
166             break;
167         case VLC_OBJECT_ANNOUNCE:
168             i_size = sizeof( announce_handler_t );
169             psz_type = "announce handler";
170             break;
171         default:
172             i_size = i_type > 0
173                       ? i_type > (int)sizeof(vlc_object_t)
174                          ? i_type : (int)sizeof(vlc_object_t)
175                       : (int)sizeof(vlc_object_t);
176             i_type = VLC_OBJECT_GENERIC;
177             psz_type = "generic";
178             break;
179     }
180
181     if( i_type == VLC_OBJECT_ROOT )
182     {
183         p_new = p_this;
184     }
185     else
186     {
187         p_new = malloc( i_size );
188
189         if( !p_new )
190         {
191             return NULL;
192         }
193
194         memset( p_new, 0, i_size );
195     }
196
197     p_new->i_object_type = i_type;
198     p_new->psz_object_type = psz_type;
199
200     p_new->psz_object_name = NULL;
201
202     p_new->b_die = VLC_FALSE;
203     p_new->b_error = VLC_FALSE;
204     p_new->b_dead = VLC_FALSE;
205     p_new->b_attached = VLC_FALSE;
206
207     p_new->i_vars = 0;
208     p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
209
210     if( !p_new->p_vars )
211     {
212         free( p_new );
213         return NULL;
214     }
215
216     if( i_type == VLC_OBJECT_ROOT )
217     {
218         /* If i_type is root, then p_new is actually p_libvlc */
219         p_new->p_libvlc = (libvlc_t*)p_new;
220         p_new->p_vlc = NULL;
221
222         p_new->p_libvlc->i_counter = 0;
223         p_new->i_object_id = 0;
224
225         p_new->p_libvlc->i_objects = 1;
226         p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) );
227         p_new->p_libvlc->pp_objects[0] = p_new;
228         p_new->b_attached = VLC_TRUE;
229     }
230     else
231     {
232         p_new->p_libvlc = p_this->p_libvlc;
233         p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new
234                                                     : p_this->p_vlc;
235
236         vlc_mutex_lock( &structure_lock );
237
238         p_new->p_libvlc->i_counter++;
239         p_new->i_object_id = p_new->p_libvlc->i_counter;
240
241         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
242          * useless to try and recover anything if pp_objects gets smashed. */
243         INSERT_ELEM( p_new->p_libvlc->pp_objects,
244                      p_new->p_libvlc->i_objects,
245                      p_new->p_libvlc->i_objects,
246                      p_new );
247
248         vlc_mutex_unlock( &structure_lock );
249     }
250
251     p_new->i_refcount = 0;
252     p_new->p_parent = NULL;
253     p_new->pp_children = NULL;
254     p_new->i_children = 0;
255
256     p_new->p_private = NULL;
257
258     /* Initialize mutexes and condvars */
259     vlc_mutex_init( p_new, &p_new->object_lock );
260     vlc_cond_init( p_new, &p_new->object_wait );
261     vlc_mutex_init( p_new, &p_new->var_lock );
262
263     if( i_type == VLC_OBJECT_ROOT )
264     {
265         vlc_mutex_init( p_new, &structure_lock );
266
267         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
268         var_AddCallback( p_new, "list", DumpCommand, NULL );
269         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
270         var_AddCallback( p_new, "tree", DumpCommand, NULL );
271     }
272
273     return p_new;
274 }
275
276 /**
277  ****************************************************************************
278  * Destroy a vlc object
279  *
280  * This function destroys an object that has been previously allocated with
281  * vlc_object_create. The object's refcount must be zero and it must not be
282  * attached to other objects in any way.
283  *****************************************************************************/
284 void __vlc_object_destroy( vlc_object_t *p_this )
285 {
286     int i_delay = 0;
287
288     if( p_this->i_children )
289     {
290         msg_Err( p_this, "cannot delete object (%i, %s) with children" ,
291                  p_this->i_object_id, p_this->psz_object_name );
292         return;
293     }
294
295     if( p_this->p_parent )
296     {
297         msg_Err( p_this, "cannot delete object (%i, %s) with a parent",
298                  p_this->i_object_id, p_this->psz_object_name );
299         return;
300     }
301
302     while( p_this->i_refcount )
303     {
304         i_delay++;
305
306         /* Don't warn immediately ... 100ms seems OK */
307         if( i_delay == 2 )
308         {
309             msg_Warn( p_this, "refcount is %i, delaying before deletion",
310                               p_this->i_refcount );
311         }
312         else if( i_delay == 12 )
313         {
314             msg_Err( p_this, "refcount is %i, I have a bad feeling about this",
315                              p_this->i_refcount );
316         }
317         else if( i_delay == 42 )
318         {
319             msg_Err( p_this, "we waited too long, cancelling destruction" );
320             return;
321         }
322
323         msleep( 100000 );
324     }
325
326     /* Destroy the associated variables, starting from the end so that
327      * no memmove calls have to be done. */
328     while( p_this->i_vars )
329     {
330         var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
331     }
332
333     free( p_this->p_vars );
334     vlc_mutex_destroy( &p_this->var_lock );
335
336     if( p_this->i_object_type == VLC_OBJECT_ROOT )
337     {
338         /* We are the root object ... no need to lock. */
339         free( p_this->p_libvlc->pp_objects );
340         p_this->p_libvlc->pp_objects = NULL;
341         p_this->p_libvlc->i_objects--;
342
343         vlc_mutex_destroy( &structure_lock );
344     }
345     else
346     {
347         int i_index;
348
349         vlc_mutex_lock( &structure_lock );
350
351         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
352          * useless to try and recover anything if pp_objects gets smashed. */
353         i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects,
354                              p_this->p_libvlc->i_objects );
355         REMOVE_ELEM( p_this->p_libvlc->pp_objects,
356                      p_this->p_libvlc->i_objects, i_index );
357
358         vlc_mutex_unlock( &structure_lock );
359     }
360
361     vlc_mutex_destroy( &p_this->object_lock );
362     vlc_cond_destroy( &p_this->object_wait );
363
364     free( p_this );
365 }
366
367 /**
368  * find an object given its ID
369  *
370  * This function looks for the object whose i_object_id field is i_id. We
371  * use a dichotomy so that lookups are in log2(n).
372  *****************************************************************************/
373 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
374 {
375     int i_max, i_middle;
376     vlc_object_t **pp_objects;
377
378     vlc_mutex_lock( &structure_lock );
379
380     pp_objects = p_this->p_libvlc->pp_objects;
381
382     /* Perform our dichotomy */
383     for( i_max = p_this->p_libvlc->i_objects - 1 ; ; )
384     {
385         i_middle = i_max / 2;
386
387         if( pp_objects[i_middle]->i_object_id > i_id )
388         {
389             i_max = i_middle;
390         }
391         else if( pp_objects[i_middle]->i_object_id < i_id )
392         {
393             if( i_middle )
394             {
395                 pp_objects += i_middle;
396                 i_max -= i_middle;
397             }
398             else
399             {
400                 /* This happens when there are only two remaining objects */
401                 if( pp_objects[i_middle+1]->i_object_id == i_id )
402                 {
403                     vlc_mutex_unlock( &structure_lock );
404                     pp_objects[i_middle+1]->i_refcount++;
405                     return pp_objects[i_middle+1];
406                 }
407                 break;
408             }
409         }
410         else
411         {
412             vlc_mutex_unlock( &structure_lock );
413             pp_objects[i_middle]->i_refcount++;
414             return pp_objects[i_middle];
415         }
416
417         if( i_max == 0 )
418         {
419             /* this means that i_max == i_middle, and since we have already
420              * tested pp_objects[i_middle]), p_found is properly set. */
421             break;
422         }
423     }
424
425     vlc_mutex_unlock( &structure_lock );
426     return NULL;
427 }
428
429 /**
430  ****************************************************************************
431  * find a typed object and increment its refcount
432  *****************************************************************************
433  * This function recursively looks for a given object type. i_mode can be one
434  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
435  *****************************************************************************/
436 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
437 {
438     vlc_object_t *p_found;
439
440     vlc_mutex_lock( &structure_lock );
441
442     /* If we are of the requested type ourselves, don't look further */
443     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
444     {
445         p_this->i_refcount++;
446         vlc_mutex_unlock( &structure_lock );
447         return p_this;
448     }
449
450     /* Otherwise, recursively look for the object */
451     if( (i_mode & 0x000f) == FIND_ANYWHERE )
452     {
453         vlc_object_t *p_root = p_this;
454
455         /* Find the root */
456         while( p_root->p_parent != NULL &&
457                p_root != VLC_OBJECT( p_this->p_vlc ) )
458         {
459             p_root = p_root->p_parent;
460         }
461
462         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
463         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_vlc ) )
464         {
465             p_found = FindObject( VLC_OBJECT( p_this->p_vlc ),
466                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
467         }
468     }
469     else
470     {
471         p_found = FindObject( p_this, i_type, i_mode );
472     }
473
474     vlc_mutex_unlock( &structure_lock );
475
476     return p_found;
477 }
478
479 /**
480  ****************************************************************************
481  * increment an object refcount
482  *****************************************************************************/
483 void __vlc_object_yield( vlc_object_t *p_this )
484 {
485     vlc_mutex_lock( &structure_lock );
486     p_this->i_refcount++;
487     vlc_mutex_unlock( &structure_lock );
488 }
489
490 /**
491  ****************************************************************************
492  * decrement an object refcount
493  *****************************************************************************/
494 void __vlc_object_release( vlc_object_t *p_this )
495 {
496     vlc_mutex_lock( &structure_lock );
497     p_this->i_refcount--;
498     vlc_mutex_unlock( &structure_lock );
499 }
500
501 /**
502  ****************************************************************************
503  * attach object to a parent object
504  *****************************************************************************
505  * This function sets p_this as a child of p_parent, and p_parent as a parent
506  * of p_this. This link can be undone using vlc_object_detach.
507  *****************************************************************************/
508 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
509 {
510     vlc_mutex_lock( &structure_lock );
511
512     /* Attach the parent to its child */
513     p_this->p_parent = p_parent;
514
515     /* Attach the child to its parent */
516     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
517                  p_parent->i_children, p_this );
518
519     /* Climb up the tree to see whether we are connected with the root */
520     if( p_parent->b_attached )
521     {
522         SetAttachment( p_this, VLC_TRUE );
523     }
524
525     vlc_mutex_unlock( &structure_lock );
526 }
527
528 /**
529  ****************************************************************************
530  * detach object from its parent
531  *****************************************************************************
532  * This function removes all links between an object and its parent.
533  *****************************************************************************/
534 void __vlc_object_detach( vlc_object_t *p_this )
535 {
536     vlc_mutex_lock( &structure_lock );
537     if( !p_this->p_parent )
538     {
539         msg_Err( p_this, "object is not attached" );
540         vlc_mutex_unlock( &structure_lock );
541         return;
542     }
543
544     /* Climb up the tree to see whether we are connected with the root */
545     if( p_this->p_parent->b_attached )
546     {
547         SetAttachment( p_this, VLC_FALSE );
548     }
549
550     DetachObject( p_this );
551     vlc_mutex_unlock( &structure_lock );
552 }
553
554 /**
555  ****************************************************************************
556  * find a list typed objects and increment their refcount
557  *****************************************************************************
558  * This function recursively looks for a given object type. i_mode can be one
559  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
560  *****************************************************************************/
561 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
562 {
563     vlc_list_t *p_list;
564     vlc_object_t **pp_current, **pp_end;
565     int i_count = 0, i_index = 0;
566
567     vlc_mutex_lock( &structure_lock );
568
569     /* Look for the objects */
570     switch( i_mode & 0x000f )
571     {
572     case FIND_ANYWHERE:
573         pp_current = p_this->p_libvlc->pp_objects;
574         pp_end = pp_current + p_this->p_libvlc->i_objects;
575
576         for( ; pp_current < pp_end ; pp_current++ )
577         {
578             if( (*pp_current)->b_attached
579                  && (*pp_current)->i_object_type == i_type )
580             {
581                 i_count++;
582             }
583         }
584
585         p_list = NewList( i_count );
586         pp_current = p_this->p_libvlc->pp_objects;
587
588         for( ; pp_current < pp_end ; pp_current++ )
589         {
590             if( (*pp_current)->b_attached
591                  && (*pp_current)->i_object_type == i_type )
592             {
593                 ListReplace( p_list, *pp_current, i_index );
594                 if( i_index < i_count ) i_index++;
595             }
596         }
597     break;
598
599     case FIND_CHILD:
600         i_count = CountChildren( p_this, i_type );
601         p_list = NewList( i_count );
602
603         /* Check allocation was successful */
604         if( p_list->i_count != i_count )
605         {
606             msg_Err( p_this, "list allocation failed!" );
607             p_list->i_count = 0;
608             break;
609         }
610
611         p_list->i_count = 0;
612         ListChildren( p_list, p_this, i_type );
613         break;
614
615     default:
616         msg_Err( p_this, "unimplemented!" );
617         p_list = NewList( 0 );
618         break;
619     }
620
621     vlc_mutex_unlock( &structure_lock );
622
623     return p_list;
624 }
625
626 /*****************************************************************************
627  * DumpCommand: print the current vlc structure
628  *****************************************************************************
629  * This function prints either an ASCII tree showing the connections between
630  * vlc objects, and additional information such as their refcount, thread ID,
631  * etc. (command "tree"), or the same data as a simple list (command "list").
632  *****************************************************************************/
633 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
634                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
635 {
636     if( *psz_cmd == 't' )
637     {
638         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
639         vlc_object_t *p_object;
640
641         if( *newval.psz_string )
642         {
643             p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
644
645             if( !p_object )
646             {
647                 return VLC_ENOOBJ;
648             }
649         }
650         else
651         {
652             p_object = p_this->p_vlc ? VLC_OBJECT(p_this->p_vlc) : p_this;
653         }
654
655         vlc_mutex_lock( &structure_lock );
656
657         psz_foo[0] = '|';
658         DumpStructure( p_object, 0, psz_foo );
659
660         vlc_mutex_unlock( &structure_lock );
661
662         if( *newval.psz_string )
663         {
664             vlc_object_release( p_this );
665         }
666     }
667     else if( *psz_cmd == 'l' )
668     {
669         vlc_object_t **pp_current, **pp_end;
670
671         vlc_mutex_lock( &structure_lock );
672
673         pp_current = p_this->p_libvlc->pp_objects;
674         pp_end = pp_current + p_this->p_libvlc->i_objects;
675
676         for( ; pp_current < pp_end ; pp_current++ )
677         {
678             if( (*pp_current)->b_attached )
679             {
680                 PrintObject( *pp_current, "" );
681             }
682             else
683             {
684                 printf( " o %.8i %s (not attached)\n",
685                         (*pp_current)->i_object_id,
686                         (*pp_current)->psz_object_type );
687             }
688         }
689
690         vlc_mutex_unlock( &structure_lock );
691     }
692
693     return VLC_SUCCESS;
694 }
695
696 /*****************************************************************************
697  * vlc_list_release: free a list previously allocated by vlc_list_find
698  *****************************************************************************
699  * This function decreases the refcount of all objects in the list and
700  * frees the list.
701  *****************************************************************************/
702 void vlc_list_release( vlc_list_t *p_list )
703 {
704     int i_index;
705
706     for( i_index = 0; i_index < p_list->i_count; i_index++ )
707     {
708         vlc_mutex_lock( &structure_lock );
709
710         p_list->p_values[i_index].p_object->i_refcount--;
711
712         vlc_mutex_unlock( &structure_lock );
713     }
714
715     free( p_list->p_values );
716     free( p_list );
717 }
718
719 /* Following functions are local */
720
721 /*****************************************************************************
722  * FindIndex: find the index of an object in an array of objects
723  *****************************************************************************
724  * This function assumes that p_this can be found in pp_objects. It will not
725  * crash if p_this cannot be found, but will return a wrong value. It is your
726  * duty to check the return value if you are not certain that the object could
727  * be found for sure.
728  *****************************************************************************/
729 static int FindIndex( vlc_object_t *p_this,
730                       vlc_object_t **pp_objects, int i_count )
731 {
732     int i_middle = i_count / 2;
733
734     if( i_count == 0 )
735     {
736         return 0;
737     }
738
739     if( pp_objects[i_middle] == p_this )
740     {
741         return i_middle;
742     }
743
744     if( i_count == 1 )
745     {
746         return 0;
747     }
748
749     /* We take advantage of the sorted array */
750     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
751     {
752         return i_middle + FindIndex( p_this, pp_objects + i_middle,
753                                              i_count - i_middle );
754     }
755     else
756     {
757         return FindIndex( p_this, pp_objects, i_middle );
758     }
759 }
760
761 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
762 {
763     int i;
764     vlc_object_t *p_tmp;
765
766     switch( i_mode & 0x000f )
767     {
768     case FIND_PARENT:
769         p_tmp = p_this->p_parent;
770         if( p_tmp )
771         {
772             if( p_tmp->i_object_type == i_type )
773             {
774                 p_tmp->i_refcount++;
775                 return p_tmp;
776             }
777             else
778             {
779                 return FindObject( p_tmp, i_type, i_mode );
780             }
781         }
782         break;
783
784     case FIND_CHILD:
785         for( i = p_this->i_children; i--; )
786         {
787             p_tmp = p_this->pp_children[i];
788             if( p_tmp->i_object_type == i_type )
789             {
790                 p_tmp->i_refcount++;
791                 return p_tmp;
792             }
793             else if( p_tmp->i_children )
794             {
795                 p_tmp = FindObject( p_tmp, i_type, i_mode );
796                 if( p_tmp )
797                 {
798                     return p_tmp;
799                 }
800             }
801         }
802         break;
803
804     case FIND_ANYWHERE:
805         /* Handled in vlc_object_find */
806         break;
807     }
808
809     return NULL;
810 }
811
812 static void DetachObject( vlc_object_t *p_this )
813 {
814     vlc_object_t *p_parent = p_this->p_parent;
815     int i_index, i;
816
817     /* Remove p_this's parent */
818     p_this->p_parent = NULL;
819
820     /* Remove all of p_parent's children which are p_this */
821     for( i_index = p_parent->i_children ; i_index-- ; )
822     {
823         if( p_parent->pp_children[i_index] == p_this )
824         {
825             p_parent->i_children--;
826             for( i = i_index ; i < p_parent->i_children ; i++ )
827             {
828                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
829             }
830         }
831     }
832
833     if( p_parent->i_children )
834     {
835         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
836                                p_parent->i_children * sizeof(vlc_object_t *) );
837     }
838     else
839     {
840         free( p_parent->pp_children );
841         p_parent->pp_children = NULL;
842     }
843 }
844
845 /*****************************************************************************
846  * SetAttachment: recursively set the b_attached flag of a subtree.
847  *****************************************************************************
848  * This function is used by the attach and detach functions to propagate
849  * the b_attached flag in a subtree.
850  *****************************************************************************/
851 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
852 {
853     int i_index;
854
855     for( i_index = p_this->i_children ; i_index-- ; )
856     {
857         SetAttachment( p_this->pp_children[i_index], b_attached );
858     }
859
860     p_this->b_attached = b_attached;
861 }
862
863 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
864 {
865     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
866
867     psz_name[0] = '\0';
868     if( p_this->psz_object_name )
869     {
870         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
871         psz_name[48] = '\"';
872         psz_name[49] = '\0';
873     }
874
875     psz_children[0] = '\0';
876     switch( p_this->i_children )
877     {
878         case 0:
879             break;
880         case 1:
881             strcpy( psz_children, ", 1 child" );
882             break;
883         default:
884             snprintf( psz_children, 20,
885                       ", %i children", p_this->i_children );
886             psz_children[19] = '\0';
887             break;
888     }
889
890     psz_refcount[0] = '\0';
891     if( p_this->i_refcount )
892     {
893         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
894         psz_refcount[19] = '\0';
895     }
896
897     psz_thread[0] = '\0';
898     if( p_this->b_thread )
899     {
900         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
901         psz_thread[19] = '\0';
902     }
903
904     printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
905             p_this->i_object_id, p_this->psz_object_type,
906             psz_name, psz_thread, psz_refcount, psz_children );
907 }
908
909 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
910 {
911     int i;
912     char i_back = psz_foo[i_level];
913     psz_foo[i_level] = '\0';
914
915     PrintObject( p_this, psz_foo );
916
917     psz_foo[i_level] = i_back;
918
919     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
920     {
921         msg_Warn( p_this, "structure tree is too deep" );
922         return;
923     }
924
925     for( i = 0 ; i < p_this->i_children ; i++ )
926     {
927         if( i_level )
928         {
929             psz_foo[i_level-1] = ' ';
930
931             if( psz_foo[i_level-2] == '`' )
932             {
933                 psz_foo[i_level-2] = ' ';
934             }
935         }
936
937         if( i == p_this->i_children - 1 )
938         {
939             psz_foo[i_level] = '`';
940         }
941         else
942         {
943             psz_foo[i_level] = '|';
944         }
945
946         psz_foo[i_level+1] = '-';
947         psz_foo[i_level+2] = '\0';
948
949         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
950     }
951 }
952
953 static vlc_list_t * NewList( int i_count )
954 {
955     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
956     if( p_list == NULL )
957     {
958         return NULL;
959     }
960
961     p_list->i_count = i_count;
962
963     if( i_count == 0 )
964     {
965         p_list->p_values = NULL;
966         return p_list;
967     }
968
969     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
970     if( p_list->p_values == NULL )
971     {
972         p_list->i_count = 0;
973         return p_list;
974     }
975
976     return p_list;
977 }
978
979 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
980                          int i_index )
981 {
982     if( p_list == NULL || i_index >= p_list->i_count )
983     {
984         return;
985     }
986
987     p_object->i_refcount++;
988
989     p_list->p_values[i_index].p_object = p_object;
990
991     return;
992 }
993
994 static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
995 {
996     if( p_list == NULL )
997     {
998         return;
999     }
1000
1001     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1002                                 * sizeof( vlc_value_t ) );
1003     if( p_list->p_values == NULL )
1004     {
1005         p_list->i_count = 0;
1006         return;
1007     }
1008
1009     p_object->i_refcount++;
1010
1011     p_list->p_values[p_list->i_count].p_object = p_object;
1012     p_list->i_count++;
1013
1014     return;
1015 }
1016
1017 static int CountChildren( vlc_object_t *p_this, int i_type )
1018 {
1019     vlc_object_t *p_tmp;
1020     int i, i_count = 0;
1021
1022     for( i = 0; i < p_this->i_children; i++ )
1023     {
1024         p_tmp = p_this->pp_children[i];
1025
1026         if( p_tmp->i_object_type == i_type )
1027         {
1028             i_count++;
1029         }
1030
1031         if( p_tmp->i_children )
1032         {
1033             i_count += CountChildren( p_tmp, i_type );
1034         }
1035     }
1036
1037     return i_count;
1038 }
1039
1040 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1041 {
1042     vlc_object_t *p_tmp;
1043     int i;
1044
1045     for( i = 0; i < p_this->i_children; i++ )
1046     {
1047         p_tmp = p_this->pp_children[i];
1048
1049         if( p_tmp->i_object_type == i_type )
1050         {
1051             ListReplace( p_list, p_tmp, p_list->i_count++ );
1052         }
1053
1054         if( p_tmp->i_children )
1055         {
1056             ListChildren( p_list, p_tmp, i_type );
1057         }
1058     }
1059 }