]> git.sesse.net Git - vlc/blob - src/control/media_instance.c
451265d1a3c8b007b1b057141abc3f691aca3faf
[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( p_mi->i_input_id );
75
76     p_mi->i_input_id = -1;
77
78     if( !p_input_thread )
79         return;
80  
81     /* release for previous vlc_object_get */
82     vlc_object_release( p_input_thread );
83
84     /* release for initial p_input_thread yield (see _new()) */
85     vlc_object_release( p_input_thread );
86
87     /* No one is tracking this input_thread appart us. Destroy it */
88     if( p_mi->b_own_its_input_thread )
89     {
90         var_DelCallback( p_input_thread, "state", input_state_changed, p_mi );
91         var_DelCallback( p_input_thread, "seekable", input_state_changed, p_mi );
92         var_DelCallback( p_input_thread, "pausable", input_state_changed, p_mi );
93         var_DelCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
94         var_DelCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
95         /* We owned this one */
96         input_StopThread( p_input_thread );
97         var_Destroy( p_input_thread, "drawable" );
98         //input_DestroyThread( p_input_thread );
99     }
100     else
101     {
102         /* XXX: hack the playlist doesn't retain the input thread,
103          * so we did it for the playlist (see _new_from_input_thread),
104          * revert that here. This will be deleted with the playlist API */
105         vlc_object_release( p_input_thread );
106     }
107
108 }
109
110 /*
111  * Retrieve the input thread. Be sure to release the object
112  * once you are done with it. (libvlc Internal)
113  *
114  * Object lock is held.
115  */
116 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
117                                          libvlc_exception_t *p_e )
118 {
119     input_thread_t *p_input_thread;
120
121     vlc_mutex_lock( &p_mi->object_lock );
122
123     if( !p_mi || p_mi->i_input_id == -1 )
124     {
125         vlc_mutex_unlock( &p_mi->object_lock );
126         RAISENULL( "Input is NULL" );
127     }
128
129     p_input_thread = (input_thread_t*)vlc_object_get( p_mi->i_input_id );
130     if( !p_input_thread )
131     {
132         vlc_mutex_unlock( &p_mi->object_lock );
133         RAISENULL( "Input does not exist" );
134     }
135
136     vlc_mutex_unlock( &p_mi->object_lock );
137     return p_input_thread;
138 }
139
140 /*
141  * input_state_changed (Private) (input var "state" Callback)
142  */
143 static int
144 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
145                      vlc_value_t oldval, vlc_value_t newval,
146                      void * p_userdata )
147 {
148     VLC_UNUSED(oldval);
149     libvlc_media_instance_t * p_mi = p_userdata;
150     libvlc_event_t event;
151     libvlc_event_type_t type = newval.i_int;
152
153     if( strcmp( psz_cmd, "state" ) )
154         type = var_GetInteger( p_this, "state" );
155
156     switch ( type )
157     {
158         case END_S:
159             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
160             event.type = libvlc_MediaInstanceReachedEnd;
161             break;
162         case PAUSE_S:
163             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
164             event.type = libvlc_MediaInstancePaused;
165             break;
166         case PLAYING_S:
167             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
168             event.type = libvlc_MediaInstancePlayed;
169             break;
170         case ERROR_S:
171             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Error, NULL);
172             event.type = libvlc_MediaInstanceEncounteredError;
173             break;
174         default:
175             return VLC_SUCCESS;
176     }
177
178     libvlc_event_send( p_mi->p_event_manager, &event );
179     return VLC_SUCCESS;
180 }
181
182 /*
183  * input_position_changed (Private) (input var "intf-change" Callback)
184  */
185 static int
186 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
187                      vlc_value_t oldval, vlc_value_t newval,
188                      void * p_userdata )
189 {
190     VLC_UNUSED(oldval);
191     libvlc_media_instance_t * p_mi = p_userdata;
192     vlc_value_t val;
193
194     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
195     {
196         input_thread_t * p_input = (input_thread_t *)p_this;
197
198         var_Get( p_input, "state", &val );
199         if( val.i_int != PLAYING_S )
200             return VLC_SUCCESS; /* Don't send the position while stopped */
201
202         var_Get( p_input, "position", &val );
203     }
204     else
205         val.i_time = newval.i_time;
206
207     libvlc_event_t event;
208     event.type = libvlc_MediaInstancePositionChanged;
209     event.u.media_instance_position_changed.new_position = val.f_float;
210
211     libvlc_event_send( p_mi->p_event_manager, &event );
212     return VLC_SUCCESS;
213 }
214
215 /*
216  * input_time_changed (Private) (input var "intf-change" Callback)
217  */
218 static int
219 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
220                      vlc_value_t oldval, vlc_value_t newval,
221                      void * p_userdata )
222 {
223     VLC_UNUSED(oldval);
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->i_input_id );
543
544     if( !p_input_thread )
545     {
546         return;
547         vlc_mutex_unlock( &p_mi->object_lock );
548     }
549
550     if( p_mi->drawable )
551     {
552         vlc_value_t val;
553         val.i_int = p_mi->drawable;
554         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
555         var_Set( p_input_thread, "drawable", val );
556     }
557     var_AddCallback( p_input_thread, "state", input_state_changed, p_mi );
558     var_AddCallback( p_input_thread, "seekable", input_state_changed, p_mi );
559     var_AddCallback( p_input_thread, "pausable", input_state_changed, p_mi );
560     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
561     var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
562
563     vlc_mutex_unlock( &p_mi->object_lock );
564 }
565
566 /**************************************************************************
567  * Pause
568  **************************************************************************/
569 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
570                                   libvlc_exception_t *p_e )
571 {
572     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
573
574     if( !p_input_thread )
575         return;
576
577     int state = var_GetInteger( p_input_thread, "state" );
578
579     if( state == PLAYING_S )
580     {
581         if( libvlc_media_instance_can_pause( p_mi, p_e ) )
582             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
583         else
584             libvlc_media_instance_stop( p_mi, p_e );
585     }
586     else
587         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
588
589     vlc_object_release( p_input_thread );
590 }
591
592 /**************************************************************************
593  * Stop
594  **************************************************************************/
595 void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi,
596                                  libvlc_exception_t *p_e )
597 {
598     if( p_mi->b_own_its_input_thread )
599         release_input_thread( p_mi ); /* This will stop the input thread */
600     else
601     {
602         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
603
604         if( !p_input_thread )
605             return;
606
607         input_StopThread( p_input_thread );
608         vlc_object_release( p_input_thread );
609     }
610 }
611
612 /**************************************************************************
613  * Set Drawable
614  **************************************************************************/
615 void libvlc_media_instance_set_drawable( libvlc_media_instance_t *p_mi,
616                                          libvlc_drawable_t drawable,
617                                          libvlc_exception_t *p_e )
618 {
619     p_mi->drawable = drawable;
620 }
621
622 /**************************************************************************
623  * Get Drawable
624  **************************************************************************/
625 libvlc_drawable_t
626 libvlc_media_instance_get_drawable ( libvlc_media_instance_t *p_mi, libvlc_exception_t *p_e )
627 {
628     return p_mi->drawable;
629 }
630
631 /**************************************************************************
632  * Getters for stream information
633  **************************************************************************/
634 libvlc_time_t libvlc_media_instance_get_length(
635                              libvlc_media_instance_t *p_mi,
636                              libvlc_exception_t *p_e )
637 {
638     input_thread_t *p_input_thread;
639     vlc_value_t val;
640
641     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
642     if( !p_input_thread )
643         return -1;
644
645     var_Get( p_input_thread, "length", &val );
646     vlc_object_release( p_input_thread );
647
648     return (val.i_time+500LL)/1000LL;
649 }
650
651 libvlc_time_t libvlc_media_instance_get_time(
652                                    libvlc_media_instance_t *p_mi,
653                                    libvlc_exception_t *p_e )
654 {
655     input_thread_t *p_input_thread;
656     vlc_value_t val;
657
658     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
659     if( !p_input_thread )
660         return -1;
661
662     var_Get( p_input_thread , "time", &val );
663     vlc_object_release( p_input_thread );
664     return (val.i_time+500LL)/1000LL;
665 }
666
667 void libvlc_media_instance_set_time(
668                                  libvlc_media_instance_t *p_mi,
669                                  libvlc_time_t time,
670                                  libvlc_exception_t *p_e )
671 {
672     input_thread_t *p_input_thread;
673     vlc_value_t value;
674
675     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
676     if( !p_input_thread )
677         return;
678
679     value.i_time = time*1000LL;
680     var_Set( p_input_thread, "time", value );
681     vlc_object_release( p_input_thread );
682 }
683
684 void libvlc_media_instance_set_position(
685                                 libvlc_media_instance_t *p_mi,
686                                 float position,
687                                 libvlc_exception_t *p_e )
688 {
689     input_thread_t *p_input_thread;
690     vlc_value_t val;
691     val.f_float = position;
692
693     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
694     if( !p_input_thread )
695         return;
696
697     var_Set( p_input_thread, "position", val );
698     vlc_object_release( p_input_thread );
699 }
700
701 float libvlc_media_instance_get_position(
702                                  libvlc_media_instance_t *p_mi,
703                                  libvlc_exception_t *p_e )
704 {
705     input_thread_t *p_input_thread;
706     vlc_value_t val;
707
708     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
709     if( !p_input_thread )
710         return -1.0;
711
712     var_Get( p_input_thread, "position", &val );
713     vlc_object_release( p_input_thread );
714
715     return val.f_float;
716 }
717
718 void libvlc_media_instance_set_chapter(
719                                  libvlc_media_instance_t *p_mi,
720                                  int chapter,
721                                  libvlc_exception_t *p_e )
722 {
723     input_thread_t *p_input_thread;
724     vlc_value_t val;
725     val.i_int = chapter;
726
727     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
728     if( !p_input_thread )
729         return;
730
731     var_Set( p_input_thread, "chapter", val );
732     vlc_object_release( p_input_thread );
733 }
734
735 int libvlc_media_instance_get_chapter(
736                                  libvlc_media_instance_t *p_mi,
737                                  libvlc_exception_t *p_e )
738 {
739     input_thread_t *p_input_thread;
740     vlc_value_t val;
741
742     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
743     if( !p_input_thread )
744         return -1.0;
745
746     var_Get( p_input_thread, "chapter", &val );
747     vlc_object_release( p_input_thread );
748
749     return val.i_int;
750 }
751
752 int libvlc_media_instance_get_chapter_count(
753                                  libvlc_media_instance_t *p_mi,
754                                  libvlc_exception_t *p_e )
755 {
756     input_thread_t *p_input_thread;
757     vlc_value_t val;
758
759     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
760     if( !p_input_thread )
761         return -1.0;
762
763     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
764     vlc_object_release( p_input_thread );
765
766     return val.i_int;
767 }
768
769 float libvlc_media_instance_get_fps(
770                                  libvlc_media_instance_t *p_mi,
771                                  libvlc_exception_t *p_e)
772 {
773     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
774     double f_fps = 0.0;
775
776     if( p_input_thread )
777     {
778         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
779             f_fps = 0.0;
780         vlc_object_release( p_input_thread );
781     }
782     return f_fps;
783 }
784
785 vlc_bool_t libvlc_media_instance_will_play(
786                                  libvlc_media_instance_t *p_mi,
787                                  libvlc_exception_t *p_e)
788 {
789     input_thread_t *p_input_thread =
790                             libvlc_get_input_thread ( p_mi, p_e);
791     if ( !p_input_thread )
792         return VLC_FALSE;
793
794     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
795     {
796         vlc_object_release( p_input_thread );
797         return VLC_TRUE;
798     }
799     vlc_object_release( p_input_thread );
800     return VLC_FALSE;
801 }
802
803 void libvlc_media_instance_set_rate(
804                                  libvlc_media_instance_t *p_mi,
805                                  float rate,
806                                  libvlc_exception_t *p_e )
807 {
808     input_thread_t *p_input_thread;
809     vlc_value_t val;
810
811     if( rate <= 0 )
812         RAISEVOID( "Rate value is invalid" );
813
814     val.i_int = 1000.0f/rate;
815
816     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
817     if ( !p_input_thread )
818         return;
819
820     var_Set( p_input_thread, "rate", val );
821     vlc_object_release( p_input_thread );
822 }
823
824 float libvlc_media_instance_get_rate(
825                                  libvlc_media_instance_t *p_mi,
826                                  libvlc_exception_t *p_e )
827 {
828     input_thread_t *p_input_thread;
829     vlc_value_t val;
830
831     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
832     if ( !p_input_thread )
833         return -1.0;
834
835     var_Get( p_input_thread, "rate", &val );
836     vlc_object_release( p_input_thread );
837
838     return (float)1000.0f/val.i_int;
839 }
840
841 libvlc_state_t libvlc_media_instance_get_state(
842                                  libvlc_media_instance_t *p_mi,
843                                  libvlc_exception_t *p_e )
844 {
845     input_thread_t *p_input_thread;
846     vlc_value_t val;
847
848     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
849     if ( !p_input_thread )
850     {
851         /* We do return the right value, no need to throw an exception */
852         if( libvlc_exception_raised( p_e ) )
853             libvlc_exception_clear( p_e );
854         return libvlc_Stopped;
855     }
856
857     var_Get( p_input_thread, "state", &val );
858     vlc_object_release( p_input_thread );
859
860     return vlc_to_libvlc_state(val.i_int);
861 }
862
863 vlc_bool_t libvlc_media_instance_is_seekable(
864                                  libvlc_media_instance_t *p_mi,
865                                  libvlc_exception_t *p_e )
866 {
867     input_thread_t *p_input_thread;
868     vlc_value_t val;
869
870     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
871     if ( !p_input_thread )
872     {
873         /* We do return the right value, no need to throw an exception */
874         if( libvlc_exception_raised( p_e ) )
875             libvlc_exception_clear( p_e );
876         return VLC_FALSE;
877     }
878     var_Get( p_input_thread, "seekable", &val );
879     vlc_object_release( p_input_thread );
880
881     return val.b_bool;
882 }
883
884 vlc_bool_t libvlc_media_instance_can_pause(
885                                  libvlc_media_instance_t *p_mi,
886                                  libvlc_exception_t *p_e )
887 {
888     input_thread_t *p_input_thread;
889     vlc_value_t val;
890
891     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
892     if ( !p_input_thread )
893     {
894         /* We do return the right value, no need to throw an exception */
895         if( libvlc_exception_raised( p_e ) )
896             libvlc_exception_clear( p_e );
897         return VLC_FALSE;
898     }
899     var_Get( p_input_thread, "can-pause", &val );
900     vlc_object_release( p_input_thread );
901
902     return val.b_bool;
903 }