c63f33a55a92185331620c3fe20ccfc7bce868a9
[vlc.git] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: objects.c,v 1.3 2002/06/01 18:04:49 sam Exp $
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 #include <vlc/vlc.h>
25
26 #ifdef HAVE_STDLIB_H
27 #   include <stdlib.h>                                          /* realloc() */
28 #endif
29
30 #include "stream_control.h"
31 #include "input_ext-intf.h"
32 #include "input_ext-dec.h"
33
34 #include "video.h"
35 #include "video_output.h"
36
37 #include "vdec_ext-plugins.h"
38
39 #include "audio_output.h"
40
41 #include "playlist.h"
42 #include "interface.h"
43
44 static void vlc_dumpstructure_inner( vlc_object_t *, int, char * );
45 static vlc_object_t * vlc_object_find_inner( vlc_object_t *, int, int );
46 static void vlc_object_unlink_inner( vlc_object_t *, vlc_object_t * );
47
48 #define MAX_TREE_DEPTH 100
49
50 void __vlc_dumpstructure( vlc_object_t *p_this )
51 {
52     char psz_foo[2 * MAX_TREE_DEPTH + 1];
53
54     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
55     psz_foo[0] = '|';
56     vlc_dumpstructure_inner( p_this, 0, psz_foo );
57     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
58 }
59
60 static void vlc_dumpstructure_inner( vlc_object_t *p_this,
61                                      int i_level, char *psz_foo )
62 {
63     int i;
64     char i_back = psz_foo[i_level];
65     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
66
67     psz_name[0] = '\0';
68     if( p_this->psz_object_name )
69     {
70         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
71         psz_name[48] = '\"';
72         psz_name[49] = '\0';
73     }
74
75     psz_children[0] = '\0';
76     switch( p_this->i_children )
77     {
78         case 0:
79             break;
80         case 1:
81             strcpy( psz_children, ", 1 child" );
82             break;
83         default:
84             snprintf( psz_children, 20, ", %i children", p_this->i_children );
85             psz_children[19] = '\0';
86             break;
87     }
88
89     psz_refcount[0] = '\0';
90     if( p_this->i_refcount )
91     {
92         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
93         psz_refcount[19] = '\0';
94     }
95
96     psz_thread[0] = '\0';
97     if( p_this->b_thread )
98     {
99         snprintf( psz_thread, 20, " (thread %d)", p_this->i_thread );
100         psz_thread[19] = '\0';
101     }
102
103     psz_foo[i_level] = '\0';
104     msg_Info( p_this, "%so %s %p%s%s%s%s", psz_foo, p_this->psz_object_type,
105               p_this, psz_name, psz_thread, psz_refcount, psz_children );
106     psz_foo[i_level] = i_back;
107
108     if( i_level / 2 >= MAX_TREE_DEPTH )
109     {
110         msg_Warn( p_this, "structure tree is too deep" );
111         return;
112     }
113
114     for( i = 0 ; i < p_this->i_children ; i++ )
115     {
116         if( i_level )
117         {
118             psz_foo[i_level-1] = ' ';
119
120             if( psz_foo[i_level-2] == '`' )
121             {
122                 psz_foo[i_level-2] = ' ';
123             }
124         }
125
126         if( i == p_this->i_children - 1 )
127         {
128             psz_foo[i_level] = '`';
129         }
130         else
131         {
132             psz_foo[i_level] = '|';
133         }
134
135         psz_foo[i_level+1] = '-';
136         psz_foo[i_level+2] = '\0';
137
138         vlc_dumpstructure_inner( p_this->pp_children[i], i_level + 2, psz_foo );
139     }
140 }
141
142 /* vlc_object_create: initialize a vlc object */
143 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
144 {
145     vlc_object_t * p_new;
146     char *         psz_type;
147     size_t         i_size;
148
149     switch( i_type )
150     {
151         case VLC_OBJECT_ROOT:
152             i_size = sizeof(vlc_t);
153             psz_type = "root";
154             break;
155         case VLC_OBJECT_MODULE:
156             i_size = sizeof(module_t);
157             psz_type = "module";
158             break;
159         case VLC_OBJECT_INTF:
160             i_size = sizeof(intf_thread_t);
161             psz_type = "interface";
162             break;
163         case VLC_OBJECT_PLAYLIST:
164             i_size = sizeof(playlist_t);
165             psz_type = "playlist";
166             break;
167         case VLC_OBJECT_INPUT:
168             i_size = sizeof(input_thread_t);
169             psz_type = "input";
170             break;
171         case VLC_OBJECT_DECODER:
172             i_size = sizeof(decoder_fifo_t);
173             psz_type = "decoder";
174             break;
175         case VLC_OBJECT_VOUT:
176             i_size = sizeof(vout_thread_t);
177             psz_type = "video output";
178             break;
179         case VLC_OBJECT_AOUT:
180             i_size = sizeof(aout_thread_t);
181             psz_type = "audio output";
182             break;
183         default:
184             i_size = i_type > sizeof(vlc_object_t)
185                    ? i_type : sizeof(vlc_object_t);
186             i_type = VLC_OBJECT_PRIVATE;
187             psz_type = "private";
188             break;
189     }
190
191     p_new = malloc( i_size );
192
193     if( !p_new )
194     {
195         return NULL;
196     }
197
198     memset( p_new, 0, i_size );
199
200     p_new->i_object_type = i_type;
201     p_new->psz_object_type = psz_type;
202
203     p_new->psz_object_name = NULL;
204
205     p_new->i_refcount = 0;
206     p_new->b_die = 0;
207     p_new->b_error = 0;
208
209     /* If i_type is root, then p_new is our own p_vlc */
210     if( i_type == VLC_OBJECT_ROOT )
211     {
212         p_new->p_vlc = (vlc_t*)p_new;
213         p_new->p_vlc->i_counter = 0;
214         p_new->i_object_id = 0;
215     }
216     else
217     {
218         p_new->p_vlc = p_this->p_vlc;
219
220         vlc_mutex_lock( &p_this->p_vlc->structure_lock );
221         p_new->p_vlc->i_counter++;
222         p_new->i_object_id = p_new->p_vlc->i_counter;
223         vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
224     }
225
226     p_new->pp_parents = NULL;
227     p_new->i_parents = 0;
228     p_new->pp_children = NULL;
229     p_new->i_children = 0;
230
231     //msg_Dbg( p_new, "created object" );
232
233     return p_new;
234 }
235
236 /* vlc_object_destroy: initialize a vlc object and set its parent */
237 void __vlc_object_destroy( vlc_object_t *p_this )
238 {
239     if( p_this->i_refcount )
240     {
241         msg_Err( p_this, "refcount is %i", p_this->i_refcount );
242         vlc_dumpstructure( p_this );
243     }
244
245     if( p_this->i_children )
246     {
247         msg_Err( p_this, "object still has children" );
248         vlc_dumpstructure( p_this );
249     }
250
251     if( p_this->i_parents )
252     {
253         msg_Err( p_this, "object still has parents" );
254         vlc_dumpstructure( p_this );
255     }
256
257     //msg_Dbg( p_this, "destroyed object" );
258
259     free( p_this );
260 }
261
262 /* vlc_object_find: find a typed object and increment its refcount */
263 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
264 {
265     vlc_object_t *p_found;
266
267     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
268
269     /* If we are of the requested type ourselves, don't look further */
270     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
271     {
272         p_this->i_refcount++;
273         vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
274         return p_this;
275     }
276
277     /* Otherwise, recursively look for the object */
278     p_found = vlc_object_find_inner( p_this, i_type, i_mode );
279
280     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
281
282     return p_found;
283 }
284
285 static vlc_object_t * vlc_object_find_inner( vlc_object_t *p_this,
286                                              int i_type, int i_mode )
287 {
288     int i;
289     vlc_object_t *p_tmp;
290
291     switch( i_mode & 0x000f )
292     {
293     case FIND_PARENT:
294         for( i = p_this->i_parents; i--; )
295         {
296             p_tmp = p_this->pp_parents[i];
297             if( p_tmp->i_object_type == i_type )
298             {
299                 p_tmp->i_refcount++;
300                 return p_tmp;
301             }
302             else if( p_tmp->i_parents )
303             {
304                 p_tmp = vlc_object_find_inner( p_tmp, i_type, i_mode );
305                 if( p_tmp )
306                 {
307                     return p_tmp;
308                 }
309             }
310         }
311         break;
312
313     case FIND_CHILD:
314         for( i = p_this->i_children; i--; )
315         {
316             p_tmp = p_this->pp_children[i];
317             if( p_tmp->i_object_type == i_type )
318             {
319                 p_tmp->i_refcount++;
320                 return p_tmp;
321             }
322             else if( p_tmp->i_children )
323             {
324                 p_tmp = vlc_object_find_inner( p_tmp, i_type, i_mode );
325                 if( p_tmp )
326                 {
327                     return p_tmp;
328                 }
329             }
330         }
331         break;
332
333     case FIND_ANYWHERE:
334         /* FIXME: unimplemented */
335         break;
336     }
337
338     return NULL;
339 }
340
341 /* vlc_object_yield: increment an object refcount */
342 void __vlc_object_yield( vlc_object_t *p_this )
343 {
344     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
345     p_this->i_refcount++;
346     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
347 }
348
349 /* vlc_object_release: decrement an object refcount */
350 void __vlc_object_release( vlc_object_t *p_this )
351 {
352     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
353     p_this->i_refcount--;
354     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
355 }
356
357 /* vlc_object_unlink: detach object from its parents */
358 void __vlc_object_unlink_all( vlc_object_t *p_this )
359 {
360     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
361
362     /* FIXME: BORK ! BORK ! BORK !!! THIS STUFF IS BORKED !! FIXME */
363     while( p_this->i_parents )
364     {
365         /* Not very effective because we know the index, but we'd have to
366          * parse p_parent->pp_children anyway. Plus, we remove duplicates
367          * by not using the object's index */
368         vlc_object_unlink_inner( p_this, p_this->pp_parents[0] );
369     }
370
371     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
372 }
373
374 /* vlc_object_unlink: remove a parent/child link */
375 void __vlc_object_unlink( vlc_object_t *p_this, vlc_object_t *p_parent )
376 {
377     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
378     vlc_object_unlink_inner( p_this, p_parent );
379     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
380 }
381
382 static void vlc_object_unlink_inner( vlc_object_t *p_this,
383                                      vlc_object_t *p_parent )
384 {
385     int i_index, i;
386
387     /* Remove all of p_this's parents which are p_parent */
388     for( i_index = p_this->i_parents ; i_index-- ; )
389     {
390         if( p_this->pp_parents[i_index] == p_parent )
391         {
392             p_this->i_parents--;
393             for( i = i_index ; i < p_this->i_parents ; i++ )
394             {
395                 p_this->pp_parents[i] = p_this->pp_parents[i+1];
396             }
397         }
398     }
399
400     if( p_this->i_parents )
401     {
402         p_this->pp_parents = (vlc_object_t **)realloc( p_this->pp_parents,
403                                 p_this->i_parents * sizeof(vlc_object_t *) );
404     }
405     else
406     {
407         free( p_this->pp_parents );
408         p_this->pp_parents = NULL;
409     }
410
411     /* Remove all of p_parent's children which are p_this */
412     for( i_index = p_parent->i_children ; i_index-- ; )
413     {
414         if( p_parent->pp_children[i_index] == p_this )
415         {
416             p_parent->i_children--;
417             for( i = i_index ; i < p_parent->i_children ; i++ )
418             {
419                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
420             }
421         }
422     }
423
424     if( p_parent->i_children )
425     {
426         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
427                                p_parent->i_children * sizeof(vlc_object_t *) );
428     }
429     else
430     {
431         free( p_parent->pp_children );
432         p_parent->pp_children = NULL;
433     }
434 }
435
436 /* vlc_object_attach: attach object to a parent object */
437 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
438 {
439     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
440
441     p_this->i_parents++;
442     p_this->pp_parents = (vlc_object_t **)realloc( p_this->pp_parents,
443                             p_this->i_parents * sizeof(vlc_object_t *) );
444     p_this->pp_parents[p_this->i_parents - 1] = p_parent;
445
446     p_parent->i_children++;
447     p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
448                                p_parent->i_children * sizeof(vlc_object_t *) );
449     p_parent->pp_children[p_parent->i_children - 1] = p_this;
450
451     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
452 }
453
454 #if 0 /* UNUSED */
455 /* vlc_object_setchild: attach a child object */
456 void __vlc_object_setchild( vlc_object_t *p_this, vlc_object_t *p_child )
457 {
458     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
459
460     p_this->i_children++;
461     p_this->pp_children = (vlc_object_t **)realloc( p_this->pp_children,
462                              p_this->i_children * sizeof(vlc_object_t *) );
463     p_this->pp_children[p_this->i_children - 1] = p_child;
464
465     p_child->i_parents++;
466     p_child->pp_parents = (vlc_object_t **)realloc( p_child->pp_parents,
467                              p_child->i_parents * sizeof(vlc_object_t *) );
468     p_child->pp_parents[p_child->i_parents - 1] = p_this;
469
470     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
471 }
472 #endif
473