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