]> git.sesse.net Git - vlc/blob - src/control/media_player.c
libvlc_video_get_height: Don't use a potentially freed pointer.
[vlc] / 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     input_thread_t *p_input_thread;
675     vout_thread_t *p_vout = NULL;
676
677     p_mi->drawable = drawable;
678
679     /* Allow on the fly drawable changing. This is tricky has this may
680      * not be supported by every vout. We though can't disable it
681      * because of some creepy drawable type that are not flexible enough
682      * (Win32 HWND for instance) */
683     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
684     if( !p_input_thread ) return;
685
686     p_vout = vlc_object_find( p_input_thread, VLC_OBJECT_VOUT, FIND_CHILD );
687     if( !p_vout )
688         libvlc_exception_raise( p_exception, "No active video output" );
689     else
690     {
691         vout_Control( p_vout , VOUT_REPARENT, drawable);
692         vlc_object_release( p_vout );
693     }
694     vlc_object_release( p_input_thread );
695 }
696
697 /**************************************************************************
698  * Get Drawable
699  **************************************************************************/
700 libvlc_drawable_t
701 libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi, libvlc_exception_t *p_e )
702 {
703     VLC_UNUSED(p_e);
704     return p_mi->drawable;
705 }
706
707 /**************************************************************************
708  * Getters for stream information
709  **************************************************************************/
710 libvlc_time_t libvlc_media_player_get_length(
711                              libvlc_media_player_t *p_mi,
712                              libvlc_exception_t *p_e )
713 {
714     input_thread_t *p_input_thread;
715     vlc_value_t val;
716
717     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
718     if( !p_input_thread )
719         return -1;
720
721     var_Get( p_input_thread, "length", &val );
722     vlc_object_release( p_input_thread );
723
724     return (val.i_time+500LL)/1000LL;
725 }
726
727 libvlc_time_t libvlc_media_player_get_time(
728                                    libvlc_media_player_t *p_mi,
729                                    libvlc_exception_t *p_e )
730 {
731     input_thread_t *p_input_thread;
732     vlc_value_t val;
733
734     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
735     if( !p_input_thread )
736         return -1;
737
738     var_Get( p_input_thread , "time", &val );
739     vlc_object_release( p_input_thread );
740     return (val.i_time+500LL)/1000LL;
741 }
742
743 void libvlc_media_player_set_time(
744                                  libvlc_media_player_t *p_mi,
745                                  libvlc_time_t time,
746                                  libvlc_exception_t *p_e )
747 {
748     input_thread_t *p_input_thread;
749     vlc_value_t value;
750
751     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
752     if( !p_input_thread )
753         return;
754
755     value.i_time = time*1000LL;
756     var_Set( p_input_thread, "time", value );
757     vlc_object_release( p_input_thread );
758 }
759
760 void libvlc_media_player_set_position(
761                                 libvlc_media_player_t *p_mi,
762                                 float position,
763                                 libvlc_exception_t *p_e )
764 {
765     input_thread_t *p_input_thread;
766     vlc_value_t val;
767     val.f_float = position;
768
769     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
770     if( !p_input_thread )
771         return;
772
773     var_Set( p_input_thread, "position", val );
774     vlc_object_release( p_input_thread );
775 }
776
777 float libvlc_media_player_get_position(
778                                  libvlc_media_player_t *p_mi,
779                                  libvlc_exception_t *p_e )
780 {
781     input_thread_t *p_input_thread;
782     vlc_value_t val;
783
784     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
785     if( !p_input_thread )
786         return -1.0;
787
788     var_Get( p_input_thread, "position", &val );
789     vlc_object_release( p_input_thread );
790
791     return val.f_float;
792 }
793
794 void libvlc_media_player_set_chapter(
795                                  libvlc_media_player_t *p_mi,
796                                  int chapter,
797                                  libvlc_exception_t *p_e )
798 {
799     input_thread_t *p_input_thread;
800     vlc_value_t val;
801     val.i_int = chapter;
802
803     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
804     if( !p_input_thread )
805         return;
806
807     var_Set( p_input_thread, "chapter", val );
808     vlc_object_release( p_input_thread );
809 }
810
811 int libvlc_media_player_get_chapter(
812                                  libvlc_media_player_t *p_mi,
813                                  libvlc_exception_t *p_e )
814 {
815     input_thread_t *p_input_thread;
816     vlc_value_t val;
817
818     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
819     if( !p_input_thread )
820         return -1.0;
821
822     var_Get( p_input_thread, "chapter", &val );
823     vlc_object_release( p_input_thread );
824
825     return val.i_int;
826 }
827
828 int libvlc_media_player_get_chapter_count(
829                                  libvlc_media_player_t *p_mi,
830                                  libvlc_exception_t *p_e )
831 {
832     input_thread_t *p_input_thread;
833     vlc_value_t val;
834
835     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
836     if( !p_input_thread )
837         return -1.0;
838
839     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
840     vlc_object_release( p_input_thread );
841
842     return val.i_int;
843 }
844
845 float libvlc_media_player_get_fps(
846                                  libvlc_media_player_t *p_mi,
847                                  libvlc_exception_t *p_e)
848 {
849     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
850     double f_fps = 0.0;
851
852     if( p_input_thread )
853     {
854         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
855             f_fps = 0.0;
856         vlc_object_release( p_input_thread );
857     }
858     return f_fps;
859 }
860
861 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
862                                      libvlc_exception_t *p_e)
863 {
864     input_thread_t *p_input_thread =
865                             libvlc_get_input_thread ( p_mi, p_e);
866     if ( !p_input_thread )
867         return false;
868
869     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
870     {
871         vlc_object_release( p_input_thread );
872         return true;
873     }
874     vlc_object_release( p_input_thread );
875     return false;
876 }
877
878 void libvlc_media_player_set_rate(
879                                  libvlc_media_player_t *p_mi,
880                                  float rate,
881                                  libvlc_exception_t *p_e )
882 {
883     input_thread_t *p_input_thread;
884     vlc_value_t val;
885
886     if( rate <= 0 )
887         RAISEVOID( "Rate value is invalid" );
888
889     val.i_int = 1000.0f/rate;
890
891     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
892     if ( !p_input_thread )
893         return;
894
895     var_Set( p_input_thread, "rate", val );
896     vlc_object_release( p_input_thread );
897 }
898
899 float libvlc_media_player_get_rate(
900                                  libvlc_media_player_t *p_mi,
901                                  libvlc_exception_t *p_e )
902 {
903     input_thread_t *p_input_thread;
904     vlc_value_t val;
905
906     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
907     if ( !p_input_thread )
908         return -1.0;
909
910     var_Get( p_input_thread, "rate", &val );
911     vlc_object_release( p_input_thread );
912
913     return (float)1000.0f/val.i_int;
914 }
915
916 libvlc_state_t libvlc_media_player_get_state(
917                                  libvlc_media_player_t *p_mi,
918                                  libvlc_exception_t *p_e )
919 {
920     input_thread_t *p_input_thread;
921     vlc_value_t val;
922
923     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
924     if ( !p_input_thread )
925     {
926         /* We do return the right value, no need to throw an exception */
927         if( libvlc_exception_raised( p_e ) )
928             libvlc_exception_clear( p_e );
929         return libvlc_Stopped;
930     }
931
932     var_Get( p_input_thread, "state", &val );
933     vlc_object_release( p_input_thread );
934
935     return vlc_to_libvlc_state(val.i_int);
936 }
937
938 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
939                                        libvlc_exception_t *p_e )
940 {
941     input_thread_t *p_input_thread;
942     vlc_value_t val;
943
944     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
945     if ( !p_input_thread )
946     {
947         /* We do return the right value, no need to throw an exception */
948         if( libvlc_exception_raised( p_e ) )
949             libvlc_exception_clear( p_e );
950         return false;
951     }
952     var_Get( p_input_thread, "seekable", &val );
953     vlc_object_release( p_input_thread );
954
955     return val.b_bool;
956 }
957
958 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
959                                      libvlc_exception_t *p_e )
960 {
961     input_thread_t *p_input_thread;
962     vlc_value_t val;
963
964     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
965     if ( !p_input_thread )
966     {
967         /* We do return the right value, no need to throw an exception */
968         if( libvlc_exception_raised( p_e ) )
969             libvlc_exception_clear( p_e );
970         return false;
971     }
972     var_Get( p_input_thread, "can-pause", &val );
973     vlc_object_release( p_input_thread );
974
975     return val.b_bool;
976 }