]> git.sesse.net Git - vlc/blob - src/control/media_player.c
libvlc: Don't raise an exception if there is no vout in set_drawable.
[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 <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     {
729         vout_Control( p_vout , VOUT_REPARENT, drawable);
730         vlc_object_release( p_vout );
731     }
732     vlc_object_release( p_input_thread );
733 }
734
735 /**************************************************************************
736  * Get Drawable
737  **************************************************************************/
738 libvlc_drawable_t
739 libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi, libvlc_exception_t *p_e )
740 {
741     VLC_UNUSED(p_e);
742     return p_mi->drawable;
743 }
744
745 /**************************************************************************
746  * Getters for stream information
747  **************************************************************************/
748 libvlc_time_t libvlc_media_player_get_length(
749                              libvlc_media_player_t *p_mi,
750                              libvlc_exception_t *p_e )
751 {
752     input_thread_t *p_input_thread;
753     vlc_value_t val;
754
755     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
756     if( !p_input_thread )
757         return -1;
758
759     var_Get( p_input_thread, "length", &val );
760     vlc_object_release( p_input_thread );
761
762     return (val.i_time+500LL)/1000LL;
763 }
764
765 libvlc_time_t libvlc_media_player_get_time(
766                                    libvlc_media_player_t *p_mi,
767                                    libvlc_exception_t *p_e )
768 {
769     input_thread_t *p_input_thread;
770     vlc_value_t val;
771
772     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
773     if( !p_input_thread )
774         return -1;
775
776     var_Get( p_input_thread , "time", &val );
777     vlc_object_release( p_input_thread );
778     return (val.i_time+500LL)/1000LL;
779 }
780
781 void libvlc_media_player_set_time(
782                                  libvlc_media_player_t *p_mi,
783                                  libvlc_time_t time,
784                                  libvlc_exception_t *p_e )
785 {
786     input_thread_t *p_input_thread;
787     vlc_value_t value;
788
789     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
790     if( !p_input_thread )
791         return;
792
793     value.i_time = time*1000LL;
794     var_Set( p_input_thread, "time", value );
795     vlc_object_release( p_input_thread );
796 }
797
798 void libvlc_media_player_set_position(
799                                 libvlc_media_player_t *p_mi,
800                                 float position,
801                                 libvlc_exception_t *p_e )
802 {
803     input_thread_t *p_input_thread;
804     vlc_value_t val;
805     val.f_float = position;
806
807     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
808     if( !p_input_thread )
809         return;
810
811     var_Set( p_input_thread, "position", val );
812     vlc_object_release( p_input_thread );
813 }
814
815 float libvlc_media_player_get_position(
816                                  libvlc_media_player_t *p_mi,
817                                  libvlc_exception_t *p_e )
818 {
819     input_thread_t *p_input_thread;
820     vlc_value_t val;
821
822     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
823     if( !p_input_thread )
824         return -1.0;
825
826     var_Get( p_input_thread, "position", &val );
827     vlc_object_release( p_input_thread );
828
829     return val.f_float;
830 }
831
832 void libvlc_media_player_set_chapter(
833                                  libvlc_media_player_t *p_mi,
834                                  int chapter,
835                                  libvlc_exception_t *p_e )
836 {
837     input_thread_t *p_input_thread;
838     vlc_value_t val;
839     val.i_int = chapter;
840
841     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
842     if( !p_input_thread )
843         return;
844
845     var_Set( p_input_thread, "chapter", val );
846     vlc_object_release( p_input_thread );
847 }
848
849 int libvlc_media_player_get_chapter(
850                                  libvlc_media_player_t *p_mi,
851                                  libvlc_exception_t *p_e )
852 {
853     input_thread_t *p_input_thread;
854     vlc_value_t val;
855
856     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
857     if( !p_input_thread )
858         return -1.0;
859
860     var_Get( p_input_thread, "chapter", &val );
861     vlc_object_release( p_input_thread );
862
863     return val.i_int;
864 }
865
866 int libvlc_media_player_get_chapter_count(
867                                  libvlc_media_player_t *p_mi,
868                                  libvlc_exception_t *p_e )
869 {
870     input_thread_t *p_input_thread;
871     vlc_value_t val;
872
873     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
874     if( !p_input_thread )
875         return -1.0;
876
877     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
878     vlc_object_release( p_input_thread );
879
880     return val.i_int;
881 }
882
883 float libvlc_media_player_get_fps(
884                                  libvlc_media_player_t *p_mi,
885                                  libvlc_exception_t *p_e)
886 {
887     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
888     double f_fps = 0.0;
889
890     if( p_input_thread )
891     {
892         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
893             f_fps = 0.0;
894         vlc_object_release( p_input_thread );
895     }
896     return f_fps;
897 }
898
899 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
900                                      libvlc_exception_t *p_e)
901 {
902     input_thread_t *p_input_thread =
903                             libvlc_get_input_thread ( p_mi, p_e);
904     if ( !p_input_thread )
905         return false;
906
907     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
908     {
909         vlc_object_release( p_input_thread );
910         return true;
911     }
912     vlc_object_release( p_input_thread );
913     return false;
914 }
915
916 void libvlc_media_player_set_rate(
917                                  libvlc_media_player_t *p_mi,
918                                  float rate,
919                                  libvlc_exception_t *p_e )
920 {
921     input_thread_t *p_input_thread;
922     vlc_value_t val;
923
924     if( rate <= 0 )
925         RAISEVOID( "Rate value is invalid" );
926
927     val.i_int = 1000.0f/rate;
928
929     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
930     if ( !p_input_thread )
931         return;
932
933     var_Set( p_input_thread, "rate", val );
934     vlc_object_release( p_input_thread );
935 }
936
937 float libvlc_media_player_get_rate(
938                                  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         return -1.0;
947
948     var_Get( p_input_thread, "rate", &val );
949     vlc_object_release( p_input_thread );
950
951     return (float)1000.0f/val.i_int;
952 }
953
954 libvlc_state_t libvlc_media_player_get_state(
955                                  libvlc_media_player_t *p_mi,
956                                  libvlc_exception_t *p_e )
957 {
958     input_thread_t *p_input_thread;
959     vlc_value_t val;
960
961     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
962     if ( !p_input_thread )
963     {
964         /* We do return the right value, no need to throw an exception */
965         if( libvlc_exception_raised( p_e ) )
966             libvlc_exception_clear( p_e );
967         return libvlc_Ended;
968     }
969
970     var_Get( p_input_thread, "state", &val );
971     vlc_object_release( p_input_thread );
972
973     return vlc_to_libvlc_state(val.i_int);
974 }
975
976 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
977                                        libvlc_exception_t *p_e )
978 {
979     input_thread_t *p_input_thread;
980     vlc_value_t val;
981
982     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
983     if ( !p_input_thread )
984     {
985         /* We do return the right value, no need to throw an exception */
986         if( libvlc_exception_raised( p_e ) )
987             libvlc_exception_clear( p_e );
988         return false;
989     }
990     var_Get( p_input_thread, "seekable", &val );
991     vlc_object_release( p_input_thread );
992
993     return val.b_bool;
994 }
995
996 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
997                                      libvlc_exception_t *p_e )
998 {
999     input_thread_t *p_input_thread;
1000     vlc_value_t val;
1001
1002     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1003     if ( !p_input_thread )
1004     {
1005         /* We do return the right value, no need to throw an exception */
1006         if( libvlc_exception_raised( p_e ) )
1007             libvlc_exception_clear( p_e );
1008         return false;
1009     }
1010     var_Get( p_input_thread, "can-pause", &val );
1011     vlc_object_release( p_input_thread );
1012
1013     return val.b_bool;
1014 }