input: Remove input_DestroyThread() as it is now handled via vlc_object_release().
[vlc.git] / 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     int i_input_id = input_Read( p_mi->p_libvlc_instance->p_libvlc_int,
569                       p_mi->p_md->p_input_item, VLC_FALSE );
570
571     /* Released in input_release */
572     p_mi->p_input_thread = (input_thread_t*)vlc_object_get( i_input_id );
573
574     if( !p_mi->p_input_thread )
575     {
576         return;
577         vlc_mutex_unlock( &p_mi->object_lock );
578     }
579
580     p_input_thread = p_mi->p_input_thread;
581
582     if( p_mi->drawable )
583     {
584         vlc_value_t val;
585         val.i_int = p_mi->drawable;
586         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
587         var_Set( p_input_thread, "drawable", val );
588     }
589     var_AddCallback( p_input_thread, "state", input_state_changed, p_mi );
590     var_AddCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
591     var_AddCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
592     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
593     var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
594
595     vlc_mutex_unlock( &p_mi->object_lock );
596 }
597
598 /**************************************************************************
599  * Pause
600  **************************************************************************/
601 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
602                                   libvlc_exception_t *p_e )
603 {
604     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
605
606     if( !p_input_thread )
607         return;
608
609     int state = var_GetInteger( p_input_thread, "state" );
610
611     if( state == PLAYING_S )
612     {
613         if( libvlc_media_instance_can_pause( p_mi, p_e ) )
614             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
615         else
616             libvlc_media_instance_stop( p_mi, p_e );
617     }
618     else
619         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
620
621     vlc_object_release( p_input_thread );
622 }
623
624 /**************************************************************************
625  * Stop
626  **************************************************************************/
627 void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi,
628                                  libvlc_exception_t *p_e )
629 {
630     if( p_mi->b_own_its_input_thread )
631         release_input_thread( p_mi ); /* This will stop the input thread */
632     else
633     {
634         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
635
636         if( !p_input_thread )
637             return;
638
639         input_StopThread( p_input_thread );
640         vlc_object_release( p_input_thread );
641     }
642 }
643
644 /**************************************************************************
645  * Set Drawable
646  **************************************************************************/
647 void libvlc_media_instance_set_drawable( libvlc_media_instance_t *p_mi,
648                                          libvlc_drawable_t drawable,
649                                          libvlc_exception_t *p_e )
650 {
651     (void)p_e;
652     p_mi->drawable = drawable;
653 }
654
655 /**************************************************************************
656  * Get Drawable
657  **************************************************************************/
658 libvlc_drawable_t
659 libvlc_media_instance_get_drawable ( libvlc_media_instance_t *p_mi, libvlc_exception_t *p_e )
660 {
661     (void)p_e;
662     return p_mi->drawable;
663 }
664
665 /**************************************************************************
666  * Getters for stream information
667  **************************************************************************/
668 libvlc_time_t libvlc_media_instance_get_length(
669                              libvlc_media_instance_t *p_mi,
670                              libvlc_exception_t *p_e )
671 {
672     input_thread_t *p_input_thread;
673     vlc_value_t val;
674
675     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
676     if( !p_input_thread )
677         return -1;
678
679     var_Get( p_input_thread, "length", &val );
680     vlc_object_release( p_input_thread );
681
682     return (val.i_time+500LL)/1000LL;
683 }
684
685 libvlc_time_t libvlc_media_instance_get_time(
686                                    libvlc_media_instance_t *p_mi,
687                                    libvlc_exception_t *p_e )
688 {
689     input_thread_t *p_input_thread;
690     vlc_value_t val;
691
692     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
693     if( !p_input_thread )
694         return -1;
695
696     var_Get( p_input_thread , "time", &val );
697     vlc_object_release( p_input_thread );
698     return (val.i_time+500LL)/1000LL;
699 }
700
701 void libvlc_media_instance_set_time(
702                                  libvlc_media_instance_t *p_mi,
703                                  libvlc_time_t time,
704                                  libvlc_exception_t *p_e )
705 {
706     input_thread_t *p_input_thread;
707     vlc_value_t value;
708
709     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
710     if( !p_input_thread )
711         return;
712
713     value.i_time = time*1000LL;
714     var_Set( p_input_thread, "time", value );
715     vlc_object_release( p_input_thread );
716 }
717
718 void libvlc_media_instance_set_position(
719                                 libvlc_media_instance_t *p_mi,
720                                 float position,
721                                 libvlc_exception_t *p_e )
722 {
723     input_thread_t *p_input_thread;
724     vlc_value_t val;
725     val.f_float = position;
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, "position", val );
732     vlc_object_release( p_input_thread );
733 }
734
735 float libvlc_media_instance_get_position(
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, "position", &val );
747     vlc_object_release( p_input_thread );
748
749     return val.f_float;
750 }
751
752 void libvlc_media_instance_set_chapter(
753                                  libvlc_media_instance_t *p_mi,
754                                  int chapter,
755                                  libvlc_exception_t *p_e )
756 {
757     input_thread_t *p_input_thread;
758     vlc_value_t val;
759     val.i_int = chapter;
760
761     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
762     if( !p_input_thread )
763         return;
764
765     var_Set( p_input_thread, "chapter", val );
766     vlc_object_release( p_input_thread );
767 }
768
769 int libvlc_media_instance_get_chapter(
770                                  libvlc_media_instance_t *p_mi,
771                                  libvlc_exception_t *p_e )
772 {
773     input_thread_t *p_input_thread;
774     vlc_value_t val;
775
776     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
777     if( !p_input_thread )
778         return -1.0;
779
780     var_Get( p_input_thread, "chapter", &val );
781     vlc_object_release( p_input_thread );
782
783     return val.i_int;
784 }
785
786 int libvlc_media_instance_get_chapter_count(
787                                  libvlc_media_instance_t *p_mi,
788                                  libvlc_exception_t *p_e )
789 {
790     input_thread_t *p_input_thread;
791     vlc_value_t val;
792
793     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
794     if( !p_input_thread )
795         return -1.0;
796
797     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
798     vlc_object_release( p_input_thread );
799
800     return val.i_int;
801 }
802
803 float libvlc_media_instance_get_fps(
804                                  libvlc_media_instance_t *p_mi,
805                                  libvlc_exception_t *p_e)
806 {
807     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
808     double f_fps = 0.0;
809
810     if( p_input_thread )
811     {
812         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
813             f_fps = 0.0;
814         vlc_object_release( p_input_thread );
815     }
816     return f_fps;
817 }
818
819 int libvlc_media_instance_will_play( libvlc_media_instance_t *p_mi,
820                                      libvlc_exception_t *p_e)
821 {
822     input_thread_t *p_input_thread =
823                             libvlc_get_input_thread ( p_mi, p_e);
824     if ( !p_input_thread )
825         return VLC_FALSE;
826
827     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
828     {
829         vlc_object_release( p_input_thread );
830         return VLC_TRUE;
831     }
832     vlc_object_release( p_input_thread );
833     return VLC_FALSE;
834 }
835
836 void libvlc_media_instance_set_rate(
837                                  libvlc_media_instance_t *p_mi,
838                                  float rate,
839                                  libvlc_exception_t *p_e )
840 {
841     input_thread_t *p_input_thread;
842     vlc_value_t val;
843
844     if( rate <= 0 )
845         RAISEVOID( "Rate value is invalid" );
846
847     val.i_int = 1000.0f/rate;
848
849     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
850     if ( !p_input_thread )
851         return;
852
853     var_Set( p_input_thread, "rate", val );
854     vlc_object_release( p_input_thread );
855 }
856
857 float libvlc_media_instance_get_rate(
858                                  libvlc_media_instance_t *p_mi,
859                                  libvlc_exception_t *p_e )
860 {
861     input_thread_t *p_input_thread;
862     vlc_value_t val;
863
864     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
865     if ( !p_input_thread )
866         return -1.0;
867
868     var_Get( p_input_thread, "rate", &val );
869     vlc_object_release( p_input_thread );
870
871     return (float)1000.0f/val.i_int;
872 }
873
874 libvlc_state_t libvlc_media_instance_get_state(
875                                  libvlc_media_instance_t *p_mi,
876                                  libvlc_exception_t *p_e )
877 {
878     input_thread_t *p_input_thread;
879     vlc_value_t val;
880
881     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
882     if ( !p_input_thread )
883     {
884         /* We do return the right value, no need to throw an exception */
885         if( libvlc_exception_raised( p_e ) )
886             libvlc_exception_clear( p_e );
887         return libvlc_Stopped;
888     }
889
890     var_Get( p_input_thread, "state", &val );
891     vlc_object_release( p_input_thread );
892
893     return vlc_to_libvlc_state(val.i_int);
894 }
895
896 int libvlc_media_instance_is_seekable( libvlc_media_instance_t *p_mi,
897                                        libvlc_exception_t *p_e )
898 {
899     input_thread_t *p_input_thread;
900     vlc_value_t val;
901
902     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
903     if ( !p_input_thread )
904     {
905         /* We do return the right value, no need to throw an exception */
906         if( libvlc_exception_raised( p_e ) )
907             libvlc_exception_clear( p_e );
908         return VLC_FALSE;
909     }
910     var_Get( p_input_thread, "seekable", &val );
911     vlc_object_release( p_input_thread );
912
913     return val.b_bool;
914 }
915
916 int libvlc_media_instance_can_pause( libvlc_media_instance_t *p_mi,
917                                      libvlc_exception_t *p_e )
918 {
919     input_thread_t *p_input_thread;
920     vlc_value_t val;
921
922     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
923     if ( !p_input_thread )
924     {
925         /* We do return the right value, no need to throw an exception */
926         if( libvlc_exception_raised( p_e ) )
927             libvlc_exception_clear( p_e );
928         return VLC_FALSE;
929     }
930     var_Get( p_input_thread, "can-pause", &val );
931     vlc_object_release( p_input_thread );
932
933     return val.b_bool;
934 }