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