]> git.sesse.net Git - vlc/blob - src/control/media_instance.c
control/media_instance.c: Make sure we initialize every md's variables in _new_from_i...
[vlc] / src / control / media_instance.c
1 /*****************************************************************************
2  * media_instance.c: Libvlc API Media Instance management functions
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
26 #include <vlc_demux.h>
27 #include <vlc_input.h>
28 #include "input/input_internal.h"
29
30 /*
31  * Release the associated input thread
32  *
33  * Object lock is NOT held.
34  */
35 static void release_input_thread( libvlc_media_instance_t *p_mi ) 
36 {
37     input_thread_t *p_input_thread;
38     vlc_bool_t should_destroy;
39
40     if( !p_mi || p_mi->i_input_id == -1 )
41         return;
42
43     p_input_thread = (input_thread_t*)vlc_object_get(
44                                              p_mi->p_libvlc_instance->p_libvlc_int,
45                                              p_mi->i_input_id );
46
47     p_mi->i_input_id = -1;
48
49     if( !p_input_thread )
50         return;
51
52     /* release for previous vlc_object_get */
53     vlc_object_release( p_input_thread );
54
55     should_destroy = p_input_thread->i_refcount == 1;
56
57     /* release for initial p_input_thread yield (see _new()) */
58     vlc_object_release( p_input_thread );
59
60     /* No one is tracking this input_thread appart us. Destroy it */
61     if( should_destroy )
62         input_DestroyThread( p_input_thread );
63 }
64
65 /*
66  * Retrieve the input thread. Be sure to release the object
67  * once you are done with it. (libvlc Internal)
68  *
69  * Object lock is held.
70  */
71 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
72                                          libvlc_exception_t *p_e ) 
73 {
74     input_thread_t *p_input_thread;
75
76     vlc_mutex_lock( &p_mi->object_lock );
77
78     if( !p_mi || p_mi->i_input_id == -1 )
79     {
80         vlc_mutex_unlock( &p_mi->object_lock );
81         RAISENULL( "Input is NULL" );
82     }
83
84     p_input_thread = (input_thread_t*)vlc_object_get(
85                                              p_mi->p_libvlc_instance->p_libvlc_int,
86                                              p_mi->i_input_id );
87     if( !p_input_thread )
88     {
89         vlc_mutex_unlock( &p_mi->object_lock );
90         RAISENULL( "Input does not exist" );
91     }
92
93     vlc_mutex_unlock( &p_mi->object_lock );
94     return p_input_thread;
95 }
96
97
98 /**************************************************************************
99  * Create a Media Instance object
100  **************************************************************************/
101 libvlc_media_instance_t *
102 libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance,
103                            libvlc_exception_t *p_e )
104 {
105     libvlc_media_instance_t * p_mi;
106
107     if( !p_libvlc_instance )
108     {
109         libvlc_exception_raise( p_e, "invalid libvlc instance" );
110         return NULL;
111     }
112
113     p_mi = malloc( sizeof(libvlc_media_instance_t) );
114     p_mi->p_md = NULL;
115     p_mi->p_libvlc_instance = p_libvlc_instance;
116     p_mi->i_input_id = -1;
117     /* refcount strategy:
118      * - All items created by _new start with a refcount set to 1
119      * - Accessor _release decrease the refcount by 1, if after that
120      *   operation the refcount is 0, the object is destroyed.
121      * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
122     p_mi->i_refcount = 1;
123     /* object_lock strategy:
124      * - No lock held in constructor
125      * - Lock when accessing all variable this lock is held
126      * - Lock when attempting to destroy the object the lock is also held */
127     vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
128                     &p_mi->object_lock );
129
130     return p_mi;
131 }
132
133 /**************************************************************************
134  * Create a Media Instance object with a media descriptor
135  **************************************************************************/
136 libvlc_media_instance_t *
137 libvlc_media_instance_new_from_media_descriptor(
138                                     libvlc_media_descriptor_t * p_md,
139                                     libvlc_exception_t *p_e )
140 {
141     libvlc_media_instance_t * p_mi;
142
143     if( !p_md )
144     {
145         libvlc_exception_raise( p_e, "invalid media descriptor" );
146         return NULL;
147     }
148
149     p_mi = malloc( sizeof(libvlc_media_instance_t) );
150     p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
151     p_mi->p_libvlc_instance = p_mi->p_md->p_libvlc_instance;
152     p_mi->i_input_id = -1;
153     /* same strategy as before */
154     p_mi->i_refcount = 1;
155     /* same strategy as before */
156     vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
157                     &p_mi->object_lock );
158
159     return p_mi;
160 }
161
162 /**************************************************************************
163  * Create a new media instance object from an input_thread (Libvlc Internal)
164  **************************************************************************/
165 libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread(
166                                    struct libvlc_instance_t *p_libvlc_instance,
167                                    input_thread_t *p_input,
168                                    libvlc_exception_t *p_e )
169 {
170     libvlc_media_instance_t * p_mi;
171
172     if( !p_input )
173     {
174         libvlc_exception_raise( p_e, "invalid input thread" );
175         return NULL;
176     }
177
178     p_mi = malloc( sizeof(libvlc_media_instance_t) );
179     p_mi->p_md = libvlc_media_descriptor_new_from_input_item(
180                     p_libvlc_instance,
181                     p_input->p->input.p_item, p_e );
182
183     if( !p_mi->p_md )
184     {
185         free( p_mi );
186         return NULL;
187     }
188
189     p_mi->p_libvlc_instance = p_libvlc_instance;
190     p_mi->i_input_id = p_input->i_object_id;
191     /* same strategy as before */
192     p_mi->i_refcount = 1;
193     /* same strategy as before */
194     vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
195                     &p_mi->object_lock );
196
197     /* will be released in media_instance_release() */
198     vlc_object_yield( p_input );
199
200     return p_mi;
201 }
202
203 /**************************************************************************
204  * Destroy a Media Instance object (libvlc internal)
205  *
206  * Warning: No lock held here, but hey, this is internal.
207  **************************************************************************/
208 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
209 {
210     input_thread_t *p_input_thread;
211     libvlc_exception_t p_e;
212
213     libvlc_exception_init( &p_e );
214
215     if( !p_mi )
216         return;
217
218     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
219
220     if( libvlc_exception_raised( &p_e ) )
221         return; /* no need to worry about no input thread */
222     
223     input_DestroyThread( p_input_thread );
224
225     libvlc_media_descriptor_destroy( p_mi->p_md );
226
227     free( p_mi );
228 }
229
230 /**************************************************************************
231  * Release a Media Instance object
232  **************************************************************************/
233 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
234 {
235     if( !p_mi )
236         return;
237
238     vlc_mutex_lock( &p_mi->object_lock );
239     
240     p_mi->i_refcount--;
241
242     /* We hold the mutex, as a waiter to make sure pending operations
243      * are finished. We can't hold it longer as the get_input_thread
244      * function holds a lock.  */
245
246     vlc_mutex_unlock( &p_mi->object_lock );
247     
248     if( p_mi->i_refcount > 0 )
249         return;
250
251     release_input_thread( p_mi );
252
253     libvlc_media_descriptor_destroy( p_mi->p_md );
254
255     free( p_mi );
256 }
257
258 /**************************************************************************
259  * Set the Media descriptor associated with the instance
260  **************************************************************************/
261 void libvlc_media_instance_set_media_descriptor(
262                             libvlc_media_instance_t *p_mi,
263                             libvlc_media_descriptor_t *p_md,
264                             libvlc_exception_t *p_e )
265 {
266     (void)p_e;
267
268     if( !p_mi )
269         return;
270
271     vlc_mutex_lock( &p_mi->object_lock );
272     
273     release_input_thread( p_mi );
274
275     libvlc_media_descriptor_destroy( p_mi->p_md );
276
277     if( !p_md )
278     {
279         p_mi->p_md = NULL;
280         vlc_mutex_unlock( &p_mi->object_lock );
281         return; /* It is ok to pass a NULL md */
282     }
283
284     p_mi->p_md = libvlc_media_descriptor_duplicate( p_md );
285     
286     /* The policy here is to ignore that we were created using a different
287      * libvlc_instance, because we don't really care */
288     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
289
290     vlc_mutex_unlock( &p_mi->object_lock );
291 }
292
293 /**************************************************************************
294  * Set the Media descriptor associated with the instance
295  **************************************************************************/
296 libvlc_media_descriptor_t *
297 libvlc_media_instance_get_media_descriptor(
298                             libvlc_media_instance_t *p_mi,
299                             libvlc_exception_t *p_e )
300 {
301     (void)p_e;
302
303     if( !p_mi->p_md )
304         return NULL;
305
306     return libvlc_media_descriptor_duplicate( p_mi->p_md );
307 }
308
309 /**************************************************************************
310  * Play
311  **************************************************************************/
312 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
313                                  libvlc_exception_t *p_e )
314 {
315     input_thread_t * p_input_thread;
316
317     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) ) 
318     {
319         /* A thread alread exists, send it a play message */        
320         vlc_value_t val;
321         val.i_int = PLAYING_S;
322
323         input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, PLAYING_S );
324         vlc_object_release( p_input_thread );
325         return;
326     }
327
328     vlc_mutex_lock( &p_mi->object_lock );
329     
330     if( !p_mi->p_md )
331     {
332         libvlc_exception_raise( p_e, "no associated media descriptor" );
333         vlc_mutex_unlock( &p_mi->object_lock );
334         return;
335     }
336
337     p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
338                                          p_mi->p_md->p_input_item );
339     p_mi->i_input_id = p_input_thread->i_object_id;
340
341     /* will be released in media_instance_release() */
342     vlc_object_yield( p_input_thread );
343
344     vlc_mutex_unlock( &p_mi->object_lock );
345 }
346
347 /**************************************************************************
348  * Pause
349  **************************************************************************/
350 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
351                                   libvlc_exception_t *p_e )
352 {
353     input_thread_t * p_input_thread;
354     vlc_value_t val;
355     val.i_int = PAUSE_S;
356
357     p_input_thread = libvlc_get_input_thread( p_mi, p_e );
358
359     if( !p_input_thread )
360         return;
361
362     input_Control( p_input_thread, INPUT_CONTROL_SET_STATE, val );
363     vlc_object_release( p_input_thread );
364 }
365
366 /**************************************************************************
367  * Getters for stream information
368  **************************************************************************/
369 vlc_int64_t libvlc_media_instance_get_length(
370                              libvlc_media_instance_t *p_mi,
371                              libvlc_exception_t *p_e )
372 {
373     input_thread_t *p_input_thread;
374     vlc_value_t val;
375
376     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
377     if( !p_input_thread )
378         return -1;
379
380     var_Get( p_input_thread, "length", &val );
381     vlc_object_release( p_input_thread );
382
383     return (val.i_time+500LL)/1000LL;
384 }
385
386 vlc_int64_t libvlc_media_instance_get_time(
387                                    libvlc_media_instance_t *p_mi,
388                                    libvlc_exception_t *p_e )
389 {
390     input_thread_t *p_input_thread;
391     vlc_value_t val;
392
393     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
394     if( !p_input_thread )
395         return -1;
396
397     var_Get( p_input_thread , "time", &val );
398     vlc_object_release( p_input_thread );
399     return (val.i_time+500LL)/1000LL;
400 }
401
402 void libvlc_media_instance_set_time(
403                                  libvlc_media_instance_t *p_mi,
404                                  vlc_int64_t time,
405                                  libvlc_exception_t *p_e )
406 {
407     input_thread_t *p_input_thread;
408     vlc_value_t value;
409
410     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
411     if( !p_input_thread )
412         return;
413
414     value.i_time = time*1000LL;
415     var_Set( p_input_thread, "time", value );
416     vlc_object_release( p_input_thread );
417 }
418
419 void libvlc_media_instance_set_position(
420                                 libvlc_media_instance_t *p_mi,
421                                 float position,
422                                 libvlc_exception_t *p_e ) 
423 {
424     input_thread_t *p_input_thread;
425     vlc_value_t val;
426     val.f_float = position;
427
428     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
429     if( !p_input_thread )
430         return;
431
432     var_Set( p_input_thread, "position", val );
433     vlc_object_release( p_input_thread );
434 }
435
436 float libvlc_media_instance_get_position(
437                                  libvlc_media_instance_t *p_mi,
438                                  libvlc_exception_t *p_e )
439 {
440     input_thread_t *p_input_thread;
441     vlc_value_t val;
442
443     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
444     if( !p_input_thread )
445         return -1.0;
446
447     var_Get( p_input_thread, "position", &val );
448     vlc_object_release( p_input_thread );
449
450     return val.f_float;
451 }
452
453 float libvlc_media_instance_get_fps(
454                                  libvlc_media_instance_t *p_mi,
455                                  libvlc_exception_t *p_e) 
456 {
457     double f_fps = 0.0;
458     input_thread_t *p_input_thread;
459
460     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
461     if( !p_input_thread )
462         return 0.0;
463
464     if( (NULL == p_input_thread->p->input.p_demux)
465         || demux2_Control( p_input_thread->p->input.p_demux, DEMUX_GET_FPS, &f_fps )
466         || f_fps < 0.1 )
467     {
468         vlc_object_release( p_input_thread );
469         return 0.0;
470     }
471     else
472     {
473         vlc_object_release( p_input_thread );
474         return( f_fps );
475     }
476 }
477
478 vlc_bool_t libvlc_media_instance_will_play(
479                                  libvlc_media_instance_t *p_mi,
480                                  libvlc_exception_t *p_e) 
481 {
482     input_thread_t *p_input_thread =
483                             libvlc_get_input_thread ( p_mi, p_e);
484     if ( !p_input_thread )
485         return VLC_FALSE;
486
487     if ( !p_input_thread->b_die && !p_input_thread->b_dead ) 
488     {
489         vlc_object_release( p_input_thread );
490         return VLC_TRUE;
491     }
492     vlc_object_release( p_input_thread );
493     return VLC_FALSE;
494 }
495
496 void libvlc_media_instance_set_rate(
497                                  libvlc_media_instance_t *p_mi,
498                                  float rate,
499                                  libvlc_exception_t *p_e ) 
500 {
501     input_thread_t *p_input_thread;
502     vlc_value_t val;
503
504     if( rate <= 0 )
505         RAISEVOID( "Rate value is invalid" );
506
507     val.i_int = 1000.0f/rate;
508
509     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
510     if ( !p_input_thread )
511         return;
512
513     var_Set( p_input_thread, "rate", val );
514     vlc_object_release( p_input_thread );
515 }
516
517 float libvlc_media_instance_get_rate(
518                                  libvlc_media_instance_t *p_mi,
519                                  libvlc_exception_t *p_e )
520 {
521     input_thread_t *p_input_thread;
522     vlc_value_t val;
523
524     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
525     if ( !p_input_thread )
526         return -1.0;
527
528     var_Get( p_input_thread, "rate", &val );
529     vlc_object_release( p_input_thread );
530
531     return (float)1000.0f/val.i_int;
532 }
533
534 int libvlc_media_instance_get_state(
535                                  libvlc_media_instance_t *p_mi,
536                                  libvlc_exception_t *p_e )
537 {
538     input_thread_t *p_input_thread;
539     vlc_value_t val;
540
541     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
542     if ( !p_input_thread )
543         return 0;
544
545     var_Get( p_input_thread, "state", &val );
546     vlc_object_release( p_input_thread );
547
548     return val.i_int;
549 }
550