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