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