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