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