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