]> git.sesse.net Git - vlc/blob - src/control/media_player.c
0928900ec7d7e3f0ac68dda0d3a6c562f331cd16
[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         vlc_thread_join( p_input_thread );
101
102         var_Destroy( p_input_thread, "drawable" );
103     }
104
105     vlc_object_release( p_input_thread );
106
107     p_mi->p_input_thread = NULL;
108 }
109
110 /*
111  * Retrieve the input thread. Be sure to release the object
112  * once you are done with it. (libvlc Internal)
113  *
114  * Object lock is held.
115  */
116 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
117                                          libvlc_exception_t *p_e )
118 {
119     input_thread_t *p_input_thread;
120
121     if( !p_mi ) RAISENULL( "Media Instance is NULL" );
122
123     vlc_mutex_lock( &p_mi->object_lock );
124
125     if( !p_mi->p_input_thread )
126     {
127         vlc_mutex_unlock( &p_mi->object_lock );
128         RAISENULL( "Input is NULL" );
129     }
130
131     p_input_thread = p_mi->p_input_thread;
132     vlc_object_yield( p_input_thread );
133
134     vlc_mutex_unlock( &p_mi->object_lock );
135
136     return p_input_thread;
137 }
138
139 /*
140  * input_state_changed (Private) (vlc_InputStateChanged callback)
141  */
142 static void
143 input_state_changed( const vlc_event_t * event, void * p_userdata )
144 {
145     libvlc_media_player_t * p_mi = p_userdata;
146     libvlc_event_t forwarded_event;
147     libvlc_event_type_t type = event->u.input_state_changed.new_state;
148
149     switch ( type )
150     {
151         case INIT_S:
152             libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
153             forwarded_event.type = libvlc_MediaPlayerNothingSpecial;
154             break;
155         case OPENING_S:
156             libvlc_media_set_state( p_mi->p_md, libvlc_Opening, NULL);
157             forwarded_event.type = libvlc_MediaPlayerOpening;
158             break;
159         case BUFFERING_S:
160             libvlc_media_set_state( p_mi->p_md, libvlc_Buffering, NULL);
161             forwarded_event.type = libvlc_MediaPlayerBuffering;
162             break;
163         case PLAYING_S:
164             libvlc_media_set_state( p_mi->p_md, libvlc_Playing, NULL);
165             forwarded_event.type = libvlc_MediaPlayerPlaying;
166             break;
167         case PAUSE_S:
168             libvlc_media_set_state( p_mi->p_md, libvlc_Paused, NULL);
169             forwarded_event.type = libvlc_MediaPlayerPaused;
170             break;
171         case STOP_S:
172             libvlc_media_set_state( p_mi->p_md, libvlc_Stopped, NULL);
173             forwarded_event.type = libvlc_MediaPlayerStopped;
174             break;
175         case FORWARD_S:
176             libvlc_media_set_state( p_mi->p_md, libvlc_Forward, NULL);
177             forwarded_event.type = libvlc_MediaPlayerForward;
178             break;
179         case BACKWARD_S:
180             libvlc_media_set_state( p_mi->p_md, libvlc_Backward, NULL);
181             forwarded_event.type = libvlc_MediaPlayerBackward;
182             break;
183         case END_S:
184             libvlc_media_set_state( p_mi->p_md, libvlc_Ended, NULL);
185             forwarded_event.type = libvlc_MediaPlayerEndReached;
186             break;
187         case ERROR_S:
188             libvlc_media_set_state( p_mi->p_md, libvlc_Error, NULL);
189             forwarded_event.type = libvlc_MediaPlayerEncounteredError;
190             break;
191
192         default:
193             return;
194     }
195
196     libvlc_event_send( p_mi->p_event_manager, &forwarded_event );
197     return;
198 }
199
200 static int
201 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
202                         vlc_value_t oldval, vlc_value_t newval,
203                         void * p_userdata )
204 {
205     VLC_UNUSED(oldval);
206     VLC_UNUSED(p_this);
207     VLC_UNUSED(psz_cmd);
208     libvlc_media_player_t * p_mi = p_userdata;
209     libvlc_event_t event;
210
211     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
212     event.type = libvlc_MediaPlayerSeekableChanged;
213     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
214
215     libvlc_event_send( p_mi->p_event_manager, &event );
216     return VLC_SUCCESS;
217 }
218
219 static int
220 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
221                         vlc_value_t oldval, vlc_value_t newval,
222                         void * p_userdata )
223 {
224     VLC_UNUSED(oldval);
225     VLC_UNUSED(p_this);
226     VLC_UNUSED(psz_cmd);
227     libvlc_media_player_t * p_mi = p_userdata;
228     libvlc_event_t event;
229
230     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
231     event.type = libvlc_MediaPlayerPausableChanged;
232     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
233
234     libvlc_event_send( p_mi->p_event_manager, &event );
235     return VLC_SUCCESS;
236 }
237
238 /*
239  * input_position_changed (Private) (input var "intf-change" Callback)
240  */
241 static int
242 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
243                      vlc_value_t oldval, vlc_value_t newval,
244                      void * p_userdata )
245 {
246     VLC_UNUSED(oldval);
247     libvlc_media_player_t * p_mi = p_userdata;
248     vlc_value_t val;
249
250     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
251     {
252         input_thread_t * p_input = (input_thread_t *)p_this;
253
254         var_Get( p_input, "state", &val );
255         if( val.i_int != PLAYING_S )
256             return VLC_SUCCESS; /* Don't send the position while stopped */
257
258         var_Get( p_input, "position", &val );
259     }
260     else
261         val.i_time = newval.i_time;
262
263     libvlc_event_t event;
264     event.type = libvlc_MediaPlayerPositionChanged;
265     event.u.media_player_position_changed.new_position = val.f_float;
266
267     libvlc_event_send( p_mi->p_event_manager, &event );
268     return VLC_SUCCESS;
269 }
270
271 /*
272  * input_time_changed (Private) (input var "intf-change" Callback)
273  */
274 static int
275 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
276                      vlc_value_t oldval, vlc_value_t newval,
277                      void * p_userdata )
278 {
279     VLC_UNUSED(oldval);
280     libvlc_media_player_t * p_mi = p_userdata;
281     vlc_value_t val;
282
283     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
284     {
285         input_thread_t * p_input = (input_thread_t *)p_this;
286
287         var_Get( p_input, "state", &val );
288         if( val.i_int != PLAYING_S )
289             return VLC_SUCCESS; /* Don't send the position while stopped */
290
291         var_Get( p_input, "time", &val );
292     }
293     else
294         val.i_time = newval.i_time;
295
296     libvlc_event_t event;
297     event.type = libvlc_MediaPlayerTimeChanged;
298     event.u.media_player_time_changed.new_time = val.i_time;
299     libvlc_event_send( p_mi->p_event_manager, &event );
300     return VLC_SUCCESS;
301 }
302
303 /**************************************************************************
304  * Create a Media Instance object
305  **************************************************************************/
306 libvlc_media_player_t *
307 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
308                            libvlc_exception_t * p_e )
309 {
310     libvlc_media_player_t * p_mi;
311
312     if( !p_libvlc_instance )
313     {
314         libvlc_exception_raise( p_e, "invalid libvlc instance" );
315         return NULL;
316     }
317
318     p_mi = malloc( sizeof(libvlc_media_player_t) );
319     if( !p_mi )
320     {
321         libvlc_exception_raise( p_e, "Not enough memory" );
322         return NULL;
323     }
324     p_mi->p_md = NULL;
325     p_mi->drawable = 0;
326     p_mi->p_libvlc_instance = p_libvlc_instance;
327     p_mi->p_input_thread = NULL;
328     /* refcount strategy:
329      * - All items created by _new start with a refcount set to 1
330      * - Accessor _release decrease the refcount by 1, if after that
331      *   operation the refcount is 0, the object is destroyed.
332      * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
333     p_mi->i_refcount = 1;
334     p_mi->b_own_its_input_thread = true;
335     /* object_lock strategy:
336      * - No lock held in constructor
337      * - Lock when accessing all variable this lock is held
338      * - Lock when attempting to destroy the object the lock is also held */
339     vlc_mutex_init( &p_mi->object_lock );
340     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
341             p_libvlc_instance, p_e );
342     if( libvlc_exception_raised( p_e ) )
343     {
344         free( p_mi );
345         return NULL;
346     }
347
348     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
349             libvlc_MediaPlayerNothingSpecial, p_e );
350     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
351             libvlc_MediaPlayerOpening, p_e );
352     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
353             libvlc_MediaPlayerBuffering, p_e );
354     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
355             libvlc_MediaPlayerPlaying, p_e );
356     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
357             libvlc_MediaPlayerPaused, p_e );
358     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
359             libvlc_MediaPlayerStopped, p_e );
360     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
361             libvlc_MediaPlayerForward, p_e );
362     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
363             libvlc_MediaPlayerBackward, p_e );
364     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
365             libvlc_MediaPlayerEndReached, p_e );
366     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
367             libvlc_MediaPlayerEncounteredError, p_e );
368
369     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
370             libvlc_MediaPlayerPositionChanged, p_e );
371     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
372             libvlc_MediaPlayerTimeChanged, p_e );
373     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
374             libvlc_MediaPlayerSeekableChanged, p_e );
375     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
376             libvlc_MediaPlayerPausableChanged, p_e );
377
378     return p_mi;
379 }
380
381 /**************************************************************************
382  * Create a Media Instance object with a media descriptor
383  **************************************************************************/
384 libvlc_media_player_t *
385 libvlc_media_player_new_from_media(
386                                     libvlc_media_t * p_md,
387                                     libvlc_exception_t *p_e )
388 {
389     libvlc_media_player_t * p_mi;
390     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
391
392     if( !p_mi )
393         return NULL;
394
395     libvlc_media_retain( p_md );
396     p_mi->p_md = p_md;
397
398     return p_mi;
399 }
400
401 /**************************************************************************
402  * Create a new media instance object from an input_thread (Libvlc Internal)
403  **************************************************************************/
404 libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
405                                    struct libvlc_instance_t *p_libvlc_instance,
406                                    input_thread_t *p_input,
407                                    libvlc_exception_t *p_e )
408 {
409     libvlc_media_player_t * p_mi;
410
411     if( !p_input )
412     {
413         libvlc_exception_raise( p_e, "invalid input thread" );
414         return NULL;
415     }
416
417     p_mi = libvlc_media_player_new( p_libvlc_instance, p_e );
418
419     if( !p_mi )
420         return NULL;
421
422     p_mi->p_md = libvlc_media_new_from_input_item(
423                     p_libvlc_instance,
424                     input_GetItem( p_input ), p_e );
425
426     if( !p_mi->p_md )
427     {
428         libvlc_media_player_destroy( p_mi );
429         return NULL;
430     }
431
432     /* will be released in media_player_release() */
433     vlc_object_yield( p_input );
434
435     p_mi->p_input_thread = p_input;
436     p_mi->b_own_its_input_thread = false;
437
438     return p_mi;
439 }
440
441 /**************************************************************************
442  * Destroy a Media Instance object (libvlc internal)
443  *
444  * Warning: No lock held here, but hey, this is internal.
445  **************************************************************************/
446 void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
447 {
448     input_thread_t *p_input_thread;
449     libvlc_exception_t p_e;
450
451     libvlc_exception_init( &p_e );
452
453     if( !p_mi )
454         return;
455
456     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
457
458     if( libvlc_exception_raised( &p_e ) )
459     {
460         libvlc_event_manager_release( p_mi->p_event_manager );
461         libvlc_exception_clear( &p_e );
462         free( p_mi );
463         return; /* no need to worry about no input thread */
464     }
465     vlc_mutex_destroy( &p_mi->object_lock );
466
467     vlc_object_release( p_input_thread );
468
469     libvlc_media_release( p_mi->p_md );
470
471     free( p_mi );
472 }
473
474 /**************************************************************************
475  * Release a Media Instance object
476  **************************************************************************/
477 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
478 {
479     if( !p_mi )
480         return;
481
482     vlc_mutex_lock( &p_mi->object_lock );
483
484     p_mi->i_refcount--;
485
486     if( p_mi->i_refcount > 0 )
487     {
488         vlc_mutex_unlock( &p_mi->object_lock );
489         return;
490     }
491     vlc_mutex_unlock( &p_mi->object_lock );
492     vlc_mutex_destroy( &p_mi->object_lock );
493
494     release_input_thread( p_mi );
495
496     libvlc_event_manager_release( p_mi->p_event_manager );
497
498     libvlc_media_release( p_mi->p_md );
499
500     free( p_mi );
501 }
502
503 /**************************************************************************
504  * Retain a Media Instance object
505  **************************************************************************/
506 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
507 {
508     if( !p_mi )
509         return;
510
511     p_mi->i_refcount++;
512 }
513
514 /**************************************************************************
515  * Set the Media descriptor associated with the instance
516  **************************************************************************/
517 void libvlc_media_player_set_media(
518                             libvlc_media_player_t *p_mi,
519                             libvlc_media_t *p_md,
520                             libvlc_exception_t *p_e )
521 {
522     VLC_UNUSED(p_e);
523
524     if( !p_mi )
525         return;
526
527     vlc_mutex_lock( &p_mi->object_lock );
528
529     release_input_thread( p_mi );
530
531     if( p_mi->p_md )
532         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
533
534     libvlc_media_release( p_mi->p_md );
535
536     if( !p_md )
537     {
538         p_mi->p_md = NULL;
539         vlc_mutex_unlock( &p_mi->object_lock );
540         return; /* It is ok to pass a NULL md */
541     }
542
543     libvlc_media_retain( p_md );
544     p_mi->p_md = p_md;
545
546     /* The policy here is to ignore that we were created using a different
547      * libvlc_instance, because we don't really care */
548     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
549
550     vlc_mutex_unlock( &p_mi->object_lock );
551 }
552
553 /**************************************************************************
554  * Get the Media descriptor associated with the instance
555  **************************************************************************/
556 libvlc_media_t *
557 libvlc_media_player_get_media(
558                             libvlc_media_player_t *p_mi,
559                             libvlc_exception_t *p_e )
560 {
561     VLC_UNUSED(p_e);
562
563     if( !p_mi->p_md )
564         return NULL;
565
566     libvlc_media_retain( p_mi->p_md );
567     return p_mi->p_md;
568 }
569
570 /**************************************************************************
571  * Get the event Manager
572  **************************************************************************/
573 libvlc_event_manager_t *
574 libvlc_media_player_event_manager(
575                             libvlc_media_player_t *p_mi,
576                             libvlc_exception_t *p_e )
577 {
578     VLC_UNUSED(p_e);
579
580     return p_mi->p_event_manager;
581 }
582
583 /**************************************************************************
584  * Play
585  **************************************************************************/
586 void libvlc_media_player_play( libvlc_media_player_t *p_mi,
587                                  libvlc_exception_t *p_e )
588 {
589     input_thread_t * p_input_thread;
590
591     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
592     {
593         /* A thread already exists, send it a play message */
594         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
595         vlc_object_release( p_input_thread );
596         return;
597     }
598
599     /* Ignore previous exception */
600     libvlc_exception_clear( p_e );
601
602     vlc_mutex_lock( &p_mi->object_lock );
603
604     if( !p_mi->p_md )
605     {
606         libvlc_exception_raise( p_e, "no associated media descriptor" );
607         vlc_mutex_unlock( &p_mi->object_lock );
608         return;
609     }
610
611     p_mi->p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
612                       p_mi->p_md->p_input_item );
613
614
615     if( !p_mi->p_input_thread )
616     {
617         vlc_mutex_unlock( &p_mi->object_lock );
618         return;
619     }
620
621     p_input_thread = p_mi->p_input_thread;
622
623     if( p_mi->drawable )
624     {
625         vlc_value_t val;
626         val.i_int = p_mi->drawable;
627         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
628         var_Set( p_input_thread, "drawable", val );
629     }
630
631     vlc_event_manager_t * p_em = input_get_event_manager( p_input_thread );
632     vlc_event_attach( p_em, vlc_InputStateChanged, input_state_changed, p_mi );
633
634     var_AddCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
635     var_AddCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
636     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
637     var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
638
639     vlc_mutex_unlock( &p_mi->object_lock );
640 }
641
642 /**************************************************************************
643  * Pause
644  **************************************************************************/
645 void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
646                                   libvlc_exception_t *p_e )
647 {
648     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
649
650     if( !p_input_thread )
651         return;
652
653     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
654
655     if( state == libvlc_Playing )
656     {
657         if( libvlc_media_player_can_pause( p_mi, p_e ) )
658             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
659         else
660             libvlc_media_player_stop( p_mi, p_e );
661     }
662     else
663         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
664
665     vlc_object_release( p_input_thread );
666 }
667
668 /**************************************************************************
669  * Stop
670  **************************************************************************/
671 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
672                                  libvlc_exception_t *p_e )
673 {
674     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
675
676     if( state == libvlc_Playing || state == libvlc_Paused )
677     {
678         /* Send a stop notification event only of we are in playing or paused states */
679         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
680
681         /* Construct and send the event */
682         libvlc_event_t event;
683         event.type = libvlc_MediaPlayerEndReached;
684         libvlc_event_send( p_mi->p_event_manager, &event );
685     }
686
687     if( p_mi->b_own_its_input_thread )
688     {
689         vlc_mutex_lock( &p_mi->object_lock );
690         release_input_thread( p_mi ); /* This will stop the input thread */
691         vlc_mutex_unlock( &p_mi->object_lock );
692     }
693     else
694     {
695         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
696
697         if( !p_input_thread )
698             return;
699
700         input_StopThread( p_input_thread );
701         vlc_object_release( p_input_thread );
702     }
703 }
704
705 /**************************************************************************
706  * Set Drawable
707  **************************************************************************/
708 void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
709                                        libvlc_drawable_t drawable,
710                                        libvlc_exception_t *p_e )
711 {
712     input_thread_t *p_input_thread;
713     vout_thread_t *p_vout = NULL;
714
715     p_mi->drawable = drawable;
716
717     /* Allow on the fly drawable changing. This is tricky has this may
718      * not be supported by every vout. We though can't disable it
719      * because of some creepy drawable type that are not flexible enough
720      * (Win32 HWND for instance) */
721     p_input_thread = libvlc_get_input_thread( p_mi, p_e );
722     if( !p_input_thread ) {
723         /* No input, nothing more to do, we are fine */
724         libvlc_exception_clear( p_e );
725         return;
726     }
727
728     p_vout = vlc_object_find( p_input_thread, VLC_OBJECT_VOUT, FIND_CHILD );
729     if( p_vout )
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 }