]> git.sesse.net Git - vlc/blob - src/control/media_instance.c
fix for libvlc_get_input_thread: check for null before locking. fixes #1522
[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
26 #include <vlc/libvlc.h>
27 #include <vlc_demux.h>
28 #include <vlc_input.h>
29 #include "libvlc.h"
30
31 static int
32 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
33                      vlc_value_t oldval, vlc_value_t newval,
34                      void * p_userdata );
35 static int
36 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
37                         vlc_value_t oldval, vlc_value_t newval,
38                         void * p_userdata );
39 static int
40 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
41                         vlc_value_t oldval, vlc_value_t newval,
42                         void * p_userdata );
43 static int
44 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
45                      vlc_value_t oldval, vlc_value_t newval,
46                      void * p_userdata );
47 static int
48 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
49                      vlc_value_t oldval, vlc_value_t newval,
50                      void * p_userdata );
51
52 static const libvlc_state_t vlc_to_libvlc_state_array[] =
53 {
54     [INIT_S]        = libvlc_Opening,
55     [OPENING_S]     = libvlc_Opening,
56     [BUFFERING_S]   = libvlc_Buffering,    
57     [PLAYING_S]     = libvlc_Playing,    
58     [PAUSE_S]       = libvlc_Paused,    
59     [END_S]         = libvlc_Ended,    
60     [ERROR_S]       = libvlc_Error,    
61 };
62 static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
63 {
64     if( vlc_state < 0 || vlc_state > 6 )
65         return libvlc_Stopped;
66
67     return vlc_to_libvlc_state_array[vlc_state];
68 }
69
70 /*
71  * Release the associated input thread
72  *
73  * Object lock is NOT held.
74  */
75 static void release_input_thread( libvlc_media_instance_t *p_mi )
76 {
77     input_thread_t *p_input_thread;
78
79     if( !p_mi || p_mi->i_input_id == -1 )
80         return;
81
82     p_input_thread = (input_thread_t*)vlc_object_get( p_mi->i_input_id );
83
84     p_mi->i_input_id = -1;
85
86     if( !p_input_thread )
87         return;
88  
89
90     /* No one is tracking this input_thread appart us. Destroy it */
91     if( p_mi->b_own_its_input_thread )
92     {
93         var_DelCallback( p_input_thread, "state", input_state_changed, p_mi );
94         var_DelCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
95         var_DelCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
96         var_DelCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
97         var_DelCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
98
99         /* We owned this one */
100         input_StopThread( p_input_thread );
101
102         var_Destroy( p_input_thread, "drawable" );
103     }
104     else
105     {
106         /* XXX: hack the playlist doesn't retain the input thread,
107          * so we did it for the playlist (see _new_from_input_thread),
108          * revert that here. This will be deleted with the playlist API */
109         vlc_object_release( p_input_thread );
110     }
111
112     /* release for previous vlc_object_get */
113     vlc_object_release( p_input_thread );
114 }
115
116 /*
117  * Retrieve the input thread. Be sure to release the object
118  * once you are done with it. (libvlc Internal)
119  *
120  * Object lock is held.
121  */
122 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
123                                          libvlc_exception_t *p_e )
124 {
125     input_thread_t *p_input_thread;
126
127     if ( !p_mi )
128     {
129         RAISENULL( "Input is NULL" );
130     }
131
132     vlc_mutex_lock( &p_mi->object_lock );
133
134     if( !p_mi || p_mi->i_input_id == -1 )
135     {
136         vlc_mutex_unlock( &p_mi->object_lock );
137         RAISENULL( "Input is NULL" );
138     }
139
140     p_input_thread = (input_thread_t*)vlc_object_get( p_mi->i_input_id );
141     if( !p_input_thread )
142     {
143         vlc_mutex_unlock( &p_mi->object_lock );
144         RAISENULL( "Input does not exist" );
145     }
146
147     vlc_mutex_unlock( &p_mi->object_lock );
148     return p_input_thread;
149 }
150
151 /*
152  * input_state_changed (Private) (input var "state" Callback)
153  */
154 static int
155 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
156                      vlc_value_t oldval, vlc_value_t newval,
157                      void * p_userdata )
158 {
159     VLC_UNUSED(oldval);
160     VLC_UNUSED(p_this);
161     VLC_UNUSED(psz_cmd);
162     libvlc_media_instance_t * p_mi = p_userdata;
163     libvlc_event_t event;
164     libvlc_event_type_t type = newval.i_int;
165
166     switch ( type )
167     {
168         case END_S:
169             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
170             event.type = libvlc_MediaInstanceReachedEnd;
171             break;
172         case PAUSE_S:
173             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
174             event.type = libvlc_MediaInstancePaused;
175             break;
176         case PLAYING_S:
177             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
178             event.type = libvlc_MediaInstancePlayed;
179             break;
180         case ERROR_S:
181             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Error, NULL);
182             event.type = libvlc_MediaInstanceEncounteredError;
183             break;
184         default:
185             return VLC_SUCCESS;
186     }
187
188     libvlc_event_send( p_mi->p_event_manager, &event );
189     return VLC_SUCCESS;
190 }
191
192 static int
193 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
194                         vlc_value_t oldval, vlc_value_t newval,
195                         void * p_userdata )
196 {
197     VLC_UNUSED(oldval);
198     VLC_UNUSED(p_this);
199     VLC_UNUSED(psz_cmd);
200     libvlc_media_instance_t * p_mi = p_userdata;
201     libvlc_event_t event;
202
203     libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
204     event.type = libvlc_MediaInstanceSeekableChanged;
205     event.u.media_instance_seekable_changed.new_seekable = newval.b_bool;
206
207     libvlc_event_send( p_mi->p_event_manager, &event );
208     return VLC_SUCCESS;
209 }
210
211 static int
212 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
213                         vlc_value_t oldval, vlc_value_t newval,
214                         void * p_userdata )
215 {
216     VLC_UNUSED(oldval);
217     VLC_UNUSED(p_this);
218     VLC_UNUSED(psz_cmd);
219     libvlc_media_instance_t * p_mi = p_userdata;
220     libvlc_event_t event;
221
222     libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
223     event.type = libvlc_MediaInstancePausableChanged;
224     event.u.media_instance_pausable_changed.new_pausable = newval.b_bool;
225
226     libvlc_event_send( p_mi->p_event_manager, &event );
227     return VLC_SUCCESS;
228 }
229
230 /*
231  * input_position_changed (Private) (input var "intf-change" Callback)
232  */
233 static int
234 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
235                      vlc_value_t oldval, vlc_value_t newval,
236                      void * p_userdata )
237 {
238     VLC_UNUSED(oldval);
239     libvlc_media_instance_t * p_mi = p_userdata;
240     vlc_value_t val;
241
242     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
243     {
244         input_thread_t * p_input = (input_thread_t *)p_this;
245
246         var_Get( p_input, "state", &val );
247         if( val.i_int != PLAYING_S )
248             return VLC_SUCCESS; /* Don't send the position while stopped */
249
250         var_Get( p_input, "position", &val );
251     }
252     else
253         val.i_time = newval.i_time;
254
255     libvlc_event_t event;
256     event.type = libvlc_MediaInstancePositionChanged;
257     event.u.media_instance_position_changed.new_position = val.f_float;
258
259     libvlc_event_send( p_mi->p_event_manager, &event );
260     return VLC_SUCCESS;
261 }
262
263 /*
264  * input_time_changed (Private) (input var "intf-change" Callback)
265  */
266 static int
267 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
268                      vlc_value_t oldval, vlc_value_t newval,
269                      void * p_userdata )
270 {
271     VLC_UNUSED(oldval);
272     libvlc_media_instance_t * p_mi = p_userdata;
273     vlc_value_t val;
274
275     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
276     {
277         input_thread_t * p_input = (input_thread_t *)p_this;
278     
279         var_Get( p_input, "state", &val );
280         if( val.i_int != PLAYING_S )
281             return VLC_SUCCESS; /* Don't send the position while stopped */
282
283         var_Get( p_input, "time", &val );
284     }
285     else
286         val.i_time = newval.i_time;
287
288     libvlc_event_t event;
289     event.type = libvlc_MediaInstanceTimeChanged;
290     event.u.media_instance_time_changed.new_time = val.i_time;
291     libvlc_event_send( p_mi->p_event_manager, &event );
292     return VLC_SUCCESS;
293 }
294
295 /**************************************************************************
296  * Create a Media Instance object
297  **************************************************************************/
298 libvlc_media_instance_t *
299 libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance,
300                            libvlc_exception_t * p_e )
301 {
302     libvlc_media_instance_t * p_mi;
303
304     if( !p_libvlc_instance )
305     {
306         libvlc_exception_raise( p_e, "invalid libvlc instance" );
307         return NULL;
308     }
309
310     p_mi = malloc( sizeof(libvlc_media_instance_t) );
311     p_mi->p_md = NULL;
312     p_mi->drawable = 0;
313     p_mi->p_libvlc_instance = p_libvlc_instance;
314     p_mi->i_input_id = -1;
315     /* refcount strategy:
316      * - All items created by _new start with a refcount set to 1
317      * - Accessor _release decrease the refcount by 1, if after that
318      *   operation the refcount is 0, the object is destroyed.
319      * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
320     p_mi->i_refcount = 1;
321     p_mi->b_own_its_input_thread = VLC_TRUE;
322     /* object_lock strategy:
323      * - No lock held in constructor
324      * - Lock when accessing all variable this lock is held
325      * - Lock when attempting to destroy the object the lock is also held */
326     vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
327                     &p_mi->object_lock );
328     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
329             p_libvlc_instance, p_e );
330     if( libvlc_exception_raised( p_e ) )
331     {
332         free( p_mi );
333         return NULL;
334     }
335  
336     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
337             libvlc_MediaInstanceReachedEnd, p_e );
338     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
339             libvlc_MediaInstanceEncounteredError, p_e );
340     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
341             libvlc_MediaInstancePaused, p_e );
342     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
343             libvlc_MediaInstancePlayed, p_e );
344     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
345             libvlc_MediaInstancePositionChanged, p_e );
346     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
347             libvlc_MediaInstanceTimeChanged, p_e );
348     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
349             libvlc_MediaInstanceSeekableChanged, p_e );
350     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
351             libvlc_MediaInstancePausableChanged, p_e );
352
353     return p_mi;
354 }
355
356 /**************************************************************************
357  * Create a Media Instance object with a media descriptor
358  **************************************************************************/
359 libvlc_media_instance_t *
360 libvlc_media_instance_new_from_media_descriptor(
361                                     libvlc_media_descriptor_t * p_md,
362                                     libvlc_exception_t *p_e )
363 {
364     libvlc_media_instance_t * p_mi;
365     p_mi = libvlc_media_instance_new( p_md->p_libvlc_instance, p_e );
366
367     if( !p_mi )
368         return NULL;
369
370     libvlc_media_descriptor_retain( p_md );
371     p_mi->p_md = p_md;
372
373     return p_mi;
374 }
375
376 /**************************************************************************
377  * Create a new media instance object from an input_thread (Libvlc Internal)
378  **************************************************************************/
379 libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread(
380                                    struct libvlc_instance_t *p_libvlc_instance,
381                                    input_thread_t *p_input,
382                                    libvlc_exception_t *p_e )
383 {
384     libvlc_media_instance_t * p_mi;
385
386     if( !p_input )
387     {
388         libvlc_exception_raise( p_e, "invalid input thread" );
389         return NULL;
390     }
391
392     p_mi = libvlc_media_instance_new( p_libvlc_instance, p_e );
393
394     if( !p_mi )
395         return NULL;
396
397     p_mi->p_md = libvlc_media_descriptor_new_from_input_item(
398                     p_libvlc_instance,
399                     input_GetItem( p_input ), p_e );
400
401     if( !p_mi->p_md )
402     {
403         libvlc_media_instance_destroy( p_mi );
404         return NULL;
405     }
406
407     p_mi->i_input_id = p_input->i_object_id;
408     p_mi->b_own_its_input_thread = VLC_FALSE;
409
410     /* will be released in media_instance_release() */
411     vlc_object_yield( p_input );
412
413     /* XXX: Hack as the playlist doesn't yield the input thread we retain
414      * the input for the playlist. (see corresponding hack in _release) */
415     vlc_object_yield( p_input );
416
417     return p_mi;
418 }
419
420 /**************************************************************************
421  * Destroy a Media Instance object (libvlc internal)
422  *
423  * Warning: No lock held here, but hey, this is internal.
424  **************************************************************************/
425 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
426 {
427     input_thread_t *p_input_thread;
428     libvlc_exception_t p_e;
429
430     libvlc_exception_init( &p_e );
431
432     if( !p_mi )
433         return;
434
435     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
436
437     if( libvlc_exception_raised( &p_e ) )
438     {
439         libvlc_event_manager_release( p_mi->p_event_manager );
440         libvlc_exception_clear( &p_e );
441         free( p_mi );
442         return; /* no need to worry about no input thread */
443     }
444     vlc_mutex_destroy( &p_mi->object_lock );
445
446     input_DestroyThread( p_input_thread );
447
448     libvlc_media_descriptor_release( p_mi->p_md );
449
450     free( p_mi );
451 }
452
453 /**************************************************************************
454  * Release a Media Instance object
455  **************************************************************************/
456 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
457 {
458     if( !p_mi )
459         return;
460
461     vlc_mutex_lock( &p_mi->object_lock );
462  
463     p_mi->i_refcount--;
464
465     if( p_mi->i_refcount > 0 )
466     {
467         vlc_mutex_unlock( &p_mi->object_lock );
468         return;
469     }
470     vlc_mutex_unlock( &p_mi->object_lock );
471     vlc_mutex_destroy( &p_mi->object_lock );
472
473     release_input_thread( p_mi );
474
475     libvlc_event_manager_release( p_mi->p_event_manager );
476  
477     libvlc_media_descriptor_release( p_mi->p_md );
478
479     free( p_mi );
480 }
481
482 /**************************************************************************
483  * Retain a Media Instance object
484  **************************************************************************/
485 void libvlc_media_instance_retain( libvlc_media_instance_t *p_mi )
486 {
487     if( !p_mi )
488         return;
489
490     p_mi->i_refcount++;
491 }
492
493 /**************************************************************************
494  * Set the Media descriptor associated with the instance
495  **************************************************************************/
496 void libvlc_media_instance_set_media_descriptor(
497                             libvlc_media_instance_t *p_mi,
498                             libvlc_media_descriptor_t *p_md,
499                             libvlc_exception_t *p_e )
500 {
501     (void)p_e;
502
503     if( !p_mi )
504         return;
505
506     vlc_mutex_lock( &p_mi->object_lock );
507
508     release_input_thread( p_mi );
509
510     if( p_mi->p_md )
511         libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL );
512
513     libvlc_media_descriptor_release( p_mi->p_md );
514
515     if( !p_md )
516     {
517         p_mi->p_md = NULL;
518         vlc_mutex_unlock( &p_mi->object_lock );
519         return; /* It is ok to pass a NULL md */
520     }
521
522     libvlc_media_descriptor_retain( p_md );
523     p_mi->p_md = p_md;
524  
525     /* The policy here is to ignore that we were created using a different
526      * libvlc_instance, because we don't really care */
527     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
528
529     vlc_mutex_unlock( &p_mi->object_lock );
530 }
531
532 /**************************************************************************
533  * Get the Media descriptor associated with the instance
534  **************************************************************************/
535 libvlc_media_descriptor_t *
536 libvlc_media_instance_get_media_descriptor(
537                             libvlc_media_instance_t *p_mi,
538                             libvlc_exception_t *p_e )
539 {
540     (void)p_e;
541
542     if( !p_mi->p_md )
543         return NULL;
544
545     libvlc_media_descriptor_retain( p_mi->p_md );
546     return p_mi->p_md;
547 }
548
549 /**************************************************************************
550  * Get the event Manager
551  **************************************************************************/
552 libvlc_event_manager_t *
553 libvlc_media_instance_event_manager(
554                             libvlc_media_instance_t *p_mi,
555                             libvlc_exception_t *p_e )
556 {
557     (void)p_e;
558
559     return p_mi->p_event_manager;
560 }
561
562 /**************************************************************************
563  * Play
564  **************************************************************************/
565 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
566                                  libvlc_exception_t *p_e )
567 {
568     input_thread_t * p_input_thread;
569
570     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
571     {
572         /* A thread alread exists, send it a play message */
573         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
574         vlc_object_release( p_input_thread );
575         return;
576     }
577
578     /* Ignore previous exception */
579     libvlc_exception_clear( p_e );
580
581     vlc_mutex_lock( &p_mi->object_lock );
582  
583     if( !p_mi->p_md )
584     {
585         libvlc_exception_raise( p_e, "no associated media descriptor" );
586         vlc_mutex_unlock( &p_mi->object_lock );
587         return;
588     }
589
590     p_mi->i_input_id = input_Read( p_mi->p_libvlc_instance->p_libvlc_int,
591                                    p_mi->p_md->p_input_item, VLC_FALSE );
592
593     p_input_thread = (input_thread_t*)vlc_object_get( p_mi->i_input_id );
594
595     if( !p_input_thread )
596     {
597         return;
598         vlc_mutex_unlock( &p_mi->object_lock );
599     }
600
601     if( p_mi->drawable )
602     {
603         vlc_value_t val;
604         val.i_int = p_mi->drawable;
605         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
606         var_Set( p_input_thread, "drawable", val );
607     }
608     var_AddCallback( p_input_thread, "state", input_state_changed, p_mi );
609     var_AddCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
610     var_AddCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
611     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
612     var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
613
614     vlc_object_release( p_input_thread );
615     vlc_mutex_unlock( &p_mi->object_lock );
616 }
617
618 /**************************************************************************
619  * Pause
620  **************************************************************************/
621 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
622                                   libvlc_exception_t *p_e )
623 {
624     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
625
626     if( !p_input_thread )
627         return;
628
629     int state = var_GetInteger( p_input_thread, "state" );
630
631     if( state == PLAYING_S )
632     {
633         if( libvlc_media_instance_can_pause( p_mi, p_e ) )
634             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
635         else
636             libvlc_media_instance_stop( p_mi, p_e );
637     }
638     else
639         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
640
641     vlc_object_release( p_input_thread );
642 }
643
644 /**************************************************************************
645  * Stop
646  **************************************************************************/
647 void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi,
648                                  libvlc_exception_t *p_e )
649 {
650     if( p_mi->b_own_its_input_thread )
651         release_input_thread( p_mi ); /* This will stop the input thread */
652     else
653     {
654         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
655
656         if( !p_input_thread )
657             return;
658
659         input_StopThread( p_input_thread );
660         vlc_object_release( p_input_thread );
661     }
662 }
663
664 /**************************************************************************
665  * Set Drawable
666  **************************************************************************/
667 void libvlc_media_instance_set_drawable( libvlc_media_instance_t *p_mi,
668                                          libvlc_drawable_t drawable,
669                                          libvlc_exception_t *p_e )
670 {
671     (void)p_e;
672     p_mi->drawable = drawable;
673 }
674
675 /**************************************************************************
676  * Get Drawable
677  **************************************************************************/
678 libvlc_drawable_t
679 libvlc_media_instance_get_drawable ( libvlc_media_instance_t *p_mi, libvlc_exception_t *p_e )
680 {
681     (void)p_e;
682     return p_mi->drawable;
683 }
684
685 /**************************************************************************
686  * Getters for stream information
687  **************************************************************************/
688 libvlc_time_t libvlc_media_instance_get_length(
689                              libvlc_media_instance_t *p_mi,
690                              libvlc_exception_t *p_e )
691 {
692     input_thread_t *p_input_thread;
693     vlc_value_t val;
694
695     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
696     if( !p_input_thread )
697         return -1;
698
699     var_Get( p_input_thread, "length", &val );
700     vlc_object_release( p_input_thread );
701
702     return (val.i_time+500LL)/1000LL;
703 }
704
705 libvlc_time_t libvlc_media_instance_get_time(
706                                    libvlc_media_instance_t *p_mi,
707                                    libvlc_exception_t *p_e )
708 {
709     input_thread_t *p_input_thread;
710     vlc_value_t val;
711
712     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
713     if( !p_input_thread )
714         return -1;
715
716     var_Get( p_input_thread , "time", &val );
717     vlc_object_release( p_input_thread );
718     return (val.i_time+500LL)/1000LL;
719 }
720
721 void libvlc_media_instance_set_time(
722                                  libvlc_media_instance_t *p_mi,
723                                  libvlc_time_t time,
724                                  libvlc_exception_t *p_e )
725 {
726     input_thread_t *p_input_thread;
727     vlc_value_t value;
728
729     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
730     if( !p_input_thread )
731         return;
732
733     value.i_time = time*1000LL;
734     var_Set( p_input_thread, "time", value );
735     vlc_object_release( p_input_thread );
736 }
737
738 void libvlc_media_instance_set_position(
739                                 libvlc_media_instance_t *p_mi,
740                                 float position,
741                                 libvlc_exception_t *p_e )
742 {
743     input_thread_t *p_input_thread;
744     vlc_value_t val;
745     val.f_float = position;
746
747     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
748     if( !p_input_thread )
749         return;
750
751     var_Set( p_input_thread, "position", val );
752     vlc_object_release( p_input_thread );
753 }
754
755 float libvlc_media_instance_get_position(
756                                  libvlc_media_instance_t *p_mi,
757                                  libvlc_exception_t *p_e )
758 {
759     input_thread_t *p_input_thread;
760     vlc_value_t val;
761
762     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
763     if( !p_input_thread )
764         return -1.0;
765
766     var_Get( p_input_thread, "position", &val );
767     vlc_object_release( p_input_thread );
768
769     return val.f_float;
770 }
771
772 void libvlc_media_instance_set_chapter(
773                                  libvlc_media_instance_t *p_mi,
774                                  int chapter,
775                                  libvlc_exception_t *p_e )
776 {
777     input_thread_t *p_input_thread;
778     vlc_value_t val;
779     val.i_int = chapter;
780
781     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
782     if( !p_input_thread )
783         return;
784
785     var_Set( p_input_thread, "chapter", val );
786     vlc_object_release( p_input_thread );
787 }
788
789 int libvlc_media_instance_get_chapter(
790                                  libvlc_media_instance_t *p_mi,
791                                  libvlc_exception_t *p_e )
792 {
793     input_thread_t *p_input_thread;
794     vlc_value_t val;
795
796     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
797     if( !p_input_thread )
798         return -1.0;
799
800     var_Get( p_input_thread, "chapter", &val );
801     vlc_object_release( p_input_thread );
802
803     return val.i_int;
804 }
805
806 int libvlc_media_instance_get_chapter_count(
807                                  libvlc_media_instance_t *p_mi,
808                                  libvlc_exception_t *p_e )
809 {
810     input_thread_t *p_input_thread;
811     vlc_value_t val;
812
813     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
814     if( !p_input_thread )
815         return -1.0;
816
817     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
818     vlc_object_release( p_input_thread );
819
820     return val.i_int;
821 }
822
823 float libvlc_media_instance_get_fps(
824                                  libvlc_media_instance_t *p_mi,
825                                  libvlc_exception_t *p_e)
826 {
827     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
828     double f_fps = 0.0;
829
830     if( p_input_thread )
831     {
832         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
833             f_fps = 0.0;
834         vlc_object_release( p_input_thread );
835     }
836     return f_fps;
837 }
838
839 vlc_bool_t libvlc_media_instance_will_play(
840                                  libvlc_media_instance_t *p_mi,
841                                  libvlc_exception_t *p_e)
842 {
843     input_thread_t *p_input_thread =
844                             libvlc_get_input_thread ( p_mi, p_e);
845     if ( !p_input_thread )
846         return VLC_FALSE;
847
848     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
849     {
850         vlc_object_release( p_input_thread );
851         return VLC_TRUE;
852     }
853     vlc_object_release( p_input_thread );
854     return VLC_FALSE;
855 }
856
857 void libvlc_media_instance_set_rate(
858                                  libvlc_media_instance_t *p_mi,
859                                  float rate,
860                                  libvlc_exception_t *p_e )
861 {
862     input_thread_t *p_input_thread;
863     vlc_value_t val;
864
865     if( rate <= 0 )
866         RAISEVOID( "Rate value is invalid" );
867
868     val.i_int = 1000.0f/rate;
869
870     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
871     if ( !p_input_thread )
872         return;
873
874     var_Set( p_input_thread, "rate", val );
875     vlc_object_release( p_input_thread );
876 }
877
878 float libvlc_media_instance_get_rate(
879                                  libvlc_media_instance_t *p_mi,
880                                  libvlc_exception_t *p_e )
881 {
882     input_thread_t *p_input_thread;
883     vlc_value_t val;
884
885     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
886     if ( !p_input_thread )
887         return -1.0;
888
889     var_Get( p_input_thread, "rate", &val );
890     vlc_object_release( p_input_thread );
891
892     return (float)1000.0f/val.i_int;
893 }
894
895 libvlc_state_t libvlc_media_instance_get_state(
896                                  libvlc_media_instance_t *p_mi,
897                                  libvlc_exception_t *p_e )
898 {
899     input_thread_t *p_input_thread;
900     vlc_value_t val;
901
902     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
903     if ( !p_input_thread )
904     {
905         /* We do return the right value, no need to throw an exception */
906         if( libvlc_exception_raised( p_e ) )
907             libvlc_exception_clear( p_e );
908         return libvlc_Stopped;
909     }
910
911     var_Get( p_input_thread, "state", &val );
912     vlc_object_release( p_input_thread );
913
914     return vlc_to_libvlc_state(val.i_int);
915 }
916
917 vlc_bool_t libvlc_media_instance_is_seekable(
918                                  libvlc_media_instance_t *p_mi,
919                                  libvlc_exception_t *p_e )
920 {
921     input_thread_t *p_input_thread;
922     vlc_value_t val;
923
924     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
925     if ( !p_input_thread )
926     {
927         /* We do return the right value, no need to throw an exception */
928         if( libvlc_exception_raised( p_e ) )
929             libvlc_exception_clear( p_e );
930         return VLC_FALSE;
931     }
932     var_Get( p_input_thread, "seekable", &val );
933     vlc_object_release( p_input_thread );
934
935     return val.b_bool;
936 }
937
938 vlc_bool_t libvlc_media_instance_can_pause(
939                                  libvlc_media_instance_t *p_mi,
940                                  libvlc_exception_t *p_e )
941 {
942     input_thread_t *p_input_thread;
943     vlc_value_t val;
944
945     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
946     if ( !p_input_thread )
947     {
948         /* We do return the right value, no need to throw an exception */
949         if( libvlc_exception_raised( p_e ) )
950             libvlc_exception_clear( p_e );
951         return VLC_FALSE;
952     }
953     var_Get( p_input_thread, "can-pause", &val );
954     vlc_object_release( p_input_thread );
955
956     return val.b_bool;
957 }