]> git.sesse.net Git - vlc/blob - src/control/media_player.c
Unused parameter
[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 #include <assert.h>
32
33 static int
34 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
35                         vlc_value_t oldval, vlc_value_t newval,
36                         void * p_userdata );
37 static int
38 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
39                         vlc_value_t oldval, vlc_value_t newval,
40                         void * p_userdata );
41 static int
42 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
43                      vlc_value_t oldval, vlc_value_t newval,
44                      void * p_userdata );
45
46 static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
47                        vlc_value_t oldval, vlc_value_t newval, void *p_data );
48
49 static const libvlc_state_t vlc_to_libvlc_state_array[] =
50 {
51     [INIT_S]        = libvlc_NothingSpecial,
52     [OPENING_S]     = libvlc_Opening,
53     [PLAYING_S]     = libvlc_Playing,
54     [PAUSE_S]       = libvlc_Paused,
55     [END_S]         = libvlc_Ended,
56     [ERROR_S]       = libvlc_Error,
57 };
58
59 static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
60 {
61     if( vlc_state < 0 || vlc_state > 6 )
62         return libvlc_Ended;
63
64     return vlc_to_libvlc_state_array[vlc_state];
65 }
66
67 /*
68  * Release the associated input thread.
69  *
70  * Object lock is NOT held.
71  */
72 static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
73 {
74     input_thread_t * p_input_thread;
75
76     if( !p_mi || !p_mi->p_input_thread )
77         return;
78
79     p_input_thread = p_mi->p_input_thread;
80
81     /* No one is tracking this input_thread apart from us. Destroy it. */
82     if( p_mi->b_own_its_input_thread )
83     {
84         var_DelCallback( p_input_thread, "can-seek",
85                          input_seekable_changed, p_mi );
86         var_DelCallback( p_input_thread, "can-pause",
87                          input_pausable_changed, p_mi );
88         var_DelCallback( p_input_thread, "intf-event",
89                          input_event_changed, p_mi );
90
91         /* We owned this one */
92         input_StopThread( p_input_thread, b_input_abort );
93         vlc_thread_join( p_input_thread );
94
95         var_Destroy( p_input_thread, "drawable-hwnd" );
96         var_Destroy( p_input_thread, "drawable-xid" );
97         var_Destroy( p_input_thread, "drawable-agl" );
98     }
99
100     vlc_object_release( p_input_thread );
101
102     p_mi->p_input_thread = NULL;
103 }
104
105 /*
106  * Retrieve the input thread. Be sure to release the object
107  * once you are done with it. (libvlc Internal)
108  *
109  * Function will lock the object.
110  */
111 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
112                                          libvlc_exception_t *p_e )
113 {
114     input_thread_t *p_input_thread;
115
116     if( !p_mi ) RAISENULL( "Media Instance is NULL" );
117
118     vlc_mutex_lock( &p_mi->object_lock );
119
120     if( !p_mi->p_input_thread )
121     {
122         vlc_mutex_unlock( &p_mi->object_lock );
123         RAISENULL( "Input is NULL" );
124     }
125
126     p_input_thread = p_mi->p_input_thread;
127     vlc_object_hold( p_input_thread );
128
129     vlc_mutex_unlock( &p_mi->object_lock );
130
131     return p_input_thread;
132 }
133
134 static int
135 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
136                         vlc_value_t oldval, vlc_value_t newval,
137                         void * p_userdata )
138 {
139     VLC_UNUSED(oldval);
140     VLC_UNUSED(p_this);
141     VLC_UNUSED(psz_cmd);
142     libvlc_media_player_t * p_mi = p_userdata;
143     libvlc_event_t event;
144
145     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
146     event.type = libvlc_MediaPlayerSeekableChanged;
147     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
148
149     libvlc_event_send( p_mi->p_event_manager, &event );
150     return VLC_SUCCESS;
151 }
152
153 static int
154 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
155                         vlc_value_t oldval, vlc_value_t newval,
156                         void * p_userdata )
157 {
158     VLC_UNUSED(oldval);
159     VLC_UNUSED(p_this);
160     VLC_UNUSED(psz_cmd);
161     libvlc_media_player_t * p_mi = p_userdata;
162     libvlc_event_t event;
163
164     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
165     event.type = libvlc_MediaPlayerPausableChanged;
166     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
167
168     libvlc_event_send( p_mi->p_event_manager, &event );
169     return VLC_SUCCESS;
170 }
171
172 static int
173 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
174                      vlc_value_t oldval, vlc_value_t newval,
175                      void * p_userdata )
176 {
177     VLC_UNUSED(oldval);
178     input_thread_t * p_input = (input_thread_t *)p_this;
179     libvlc_media_player_t * p_mi = p_userdata;
180     libvlc_event_t event;
181
182     assert( !strcmp( psz_cmd, "intf-event" ) );
183
184     if( newval.i_int == INPUT_EVENT_STATE )
185     {
186         libvlc_state_t libvlc_state;
187
188         switch ( var_GetInteger( p_input, "state" ) )
189         {
190             case INIT_S:
191                 libvlc_state = libvlc_NothingSpecial;
192                 event.type = libvlc_MediaPlayerNothingSpecial;
193                 break;
194             case OPENING_S:
195                 libvlc_state = libvlc_Opening;
196                 event.type = libvlc_MediaPlayerOpening;
197                 break;
198             case PLAYING_S:
199                 libvlc_state = libvlc_Playing;
200                 event.type = libvlc_MediaPlayerPlaying;
201                 break;
202             case PAUSE_S:
203                 libvlc_state = libvlc_Paused;
204                 event.type = libvlc_MediaPlayerPaused;
205                 break;
206             case END_S:
207                 libvlc_state = libvlc_Ended;
208                 event.type = libvlc_MediaPlayerEndReached;
209                 break;
210             case ERROR_S:
211                 libvlc_state = libvlc_Error;
212                 event.type = libvlc_MediaPlayerEncounteredError;
213                 break;
214
215             default:
216                 return VLC_SUCCESS;
217         }
218
219         libvlc_media_set_state( p_mi->p_md, libvlc_state, NULL );
220         libvlc_event_send( p_mi->p_event_manager, &event );
221     }
222     else if( newval.i_int == INPUT_EVENT_TIMES )
223     {
224         if( var_GetInteger( p_input, "state" ) != PLAYING_S )
225             return VLC_SUCCESS; /* Don't send the position while stopped */
226
227         /* */
228         event.type = libvlc_MediaPlayerPositionChanged;
229         event.u.media_player_position_changed.new_position =
230                                           var_GetFloat( p_input, "position" );
231         libvlc_event_send( p_mi->p_event_manager, &event );
232
233         /* */
234         event.type = libvlc_MediaPlayerTimeChanged;
235         event.u.media_player_time_changed.new_time =
236                                                var_GetTime( p_input, "time" );
237         libvlc_event_send( p_mi->p_event_manager, &event );
238     }
239
240     return VLC_SUCCESS;
241
242 }
243
244
245 /**************************************************************************
246  * Create a Media Instance object.
247  *
248  * Refcount strategy:
249  * - All items created by _new start with a refcount set to 1.
250  * - Accessor _release decrease the refcount by 1, if after that
251  *   operation the refcount is 0, the object is destroyed.
252  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
253  *
254  * Object locking strategy:
255  * - No lock held while in constructor.
256  * - When accessing any member variable this lock is held. (XXX who locks?)
257  * - When attempting to destroy the object the lock is also held.
258  **************************************************************************/
259 libvlc_media_player_t *
260 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
261                            libvlc_exception_t * p_e )
262 {
263     libvlc_media_player_t * p_mi;
264
265     if( !p_libvlc_instance )
266     {
267         libvlc_exception_raise( p_e, "invalid libvlc instance" );
268         return NULL;
269     }
270
271     p_mi = malloc( sizeof(libvlc_media_player_t) );
272     if( !p_mi )
273     {
274         libvlc_exception_raise( p_e, "Not enough memory" );
275         return NULL;
276     }
277     p_mi->p_md = NULL;
278     p_mi->drawable.agl = 0;
279     p_mi->drawable.xid = 0;
280     p_mi->drawable.hwnd = NULL;
281     p_mi->p_libvlc_instance = p_libvlc_instance;
282     p_mi->p_input_thread = NULL;
283     p_mi->i_refcount = 1;
284     p_mi->b_own_its_input_thread = true;
285     vlc_mutex_init( &p_mi->object_lock );
286     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
287             p_libvlc_instance, p_e );
288     if( libvlc_exception_raised( p_e ) )
289     {
290         free( p_mi );
291         return NULL;
292     }
293
294     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
295             libvlc_MediaPlayerNothingSpecial, p_e );
296     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
297             libvlc_MediaPlayerOpening, p_e );
298     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
299             libvlc_MediaPlayerBuffering, p_e );
300     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
301             libvlc_MediaPlayerPlaying, p_e );
302     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
303             libvlc_MediaPlayerPaused, p_e );
304     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
305             libvlc_MediaPlayerStopped, p_e );
306     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
307             libvlc_MediaPlayerForward, p_e );
308     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
309             libvlc_MediaPlayerBackward, p_e );
310     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
311             libvlc_MediaPlayerEndReached, p_e );
312     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
313             libvlc_MediaPlayerEncounteredError, p_e );
314
315     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
316             libvlc_MediaPlayerPositionChanged, p_e );
317     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
318             libvlc_MediaPlayerTimeChanged, p_e );
319      libvlc_event_manager_register_event_type( p_mi->p_event_manager,
320             libvlc_MediaPlayerTitleChanged, p_e );
321     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
322             libvlc_MediaPlayerSeekableChanged, p_e );
323     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
324             libvlc_MediaPlayerPausableChanged, p_e );
325
326     /* Snapshot initialization */
327     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
328            libvlc_MediaPlayerSnapshotTaken, p_e );
329     /* Attach a var callback to the global object to provide the glue between
330         vout_thread that generates the event and media_player that re-emits it
331         with its own event manager
332     */
333     var_Create( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
334                 VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
335     var_AddCallback( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
336                      SnapshotTakenCallback, p_mi );
337
338     return p_mi;
339 }
340
341 /**************************************************************************
342  * Create a Media Instance object with a media descriptor.
343  **************************************************************************/
344 libvlc_media_player_t *
345 libvlc_media_player_new_from_media(
346                                     libvlc_media_t * p_md,
347                                     libvlc_exception_t *p_e )
348 {
349     libvlc_media_player_t * p_mi;
350     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
351
352     if( !p_mi )
353         return NULL;
354
355     libvlc_media_retain( p_md );
356     p_mi->p_md = p_md;
357
358     return p_mi;
359 }
360
361 /**************************************************************************
362  * Create a new media instance object from an input_thread (Libvlc Internal).
363  **************************************************************************/
364 libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
365                                    struct libvlc_instance_t *p_libvlc_instance,
366                                    input_thread_t *p_input,
367                                    libvlc_exception_t *p_e )
368 {
369     libvlc_media_player_t * p_mi;
370
371     if( !p_input )
372     {
373         libvlc_exception_raise( p_e, "invalid input thread" );
374         return NULL;
375     }
376
377     p_mi = libvlc_media_player_new( p_libvlc_instance, p_e );
378
379     if( !p_mi )
380         return NULL;
381
382     p_mi->p_md = libvlc_media_new_from_input_item(
383                     p_libvlc_instance,
384                     input_GetItem( p_input ), p_e );
385
386     if( !p_mi->p_md )
387     {
388         libvlc_media_player_destroy( p_mi );
389         return NULL;
390     }
391
392     /* will be released in media_player_release() */
393     vlc_object_hold( p_input );
394
395     p_mi->p_input_thread = p_input;
396     p_mi->b_own_its_input_thread = false;
397
398     return p_mi;
399 }
400
401 /**************************************************************************
402  * Destroy a Media Instance object (libvlc internal)
403  *
404  * Warning: No lock held here, but hey, this is internal. Caller must lock.
405  **************************************************************************/
406 void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
407 {
408     input_thread_t *p_input_thread;
409     libvlc_exception_t p_e;
410
411     libvlc_exception_init( &p_e );
412
413     if( !p_mi )
414         return;
415
416         /* Detach Callback from the main libvlc object */
417     var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int,
418                      "vout-snapshottaken", SnapshotTakenCallback, p_mi );
419
420     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
421
422     if( libvlc_exception_raised( &p_e ) )
423     {
424         libvlc_event_manager_release( p_mi->p_event_manager );
425         libvlc_exception_clear( &p_e );
426         free( p_mi );
427         return; /* no need to worry about no input thread */
428     }
429     vlc_mutex_destroy( &p_mi->object_lock );
430
431     vlc_object_release( p_input_thread );
432
433     libvlc_media_release( p_mi->p_md );
434
435     free( p_mi );
436 }
437
438 /**************************************************************************
439  * Release a Media Instance object.
440  *
441  * Function does the locking.
442  **************************************************************************/
443 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
444 {
445     if( !p_mi )
446         return;
447
448     vlc_mutex_lock( &p_mi->object_lock );
449
450     p_mi->i_refcount--;
451
452     if( p_mi->i_refcount > 0 )
453     {
454         vlc_mutex_unlock( &p_mi->object_lock );
455         return;
456     }
457     vlc_mutex_unlock( &p_mi->object_lock );
458     vlc_mutex_destroy( &p_mi->object_lock );
459
460     release_input_thread( p_mi, true );
461
462     libvlc_event_manager_release( p_mi->p_event_manager );
463
464     libvlc_media_release( p_mi->p_md );
465
466     free( p_mi );
467 }
468
469 /**************************************************************************
470  * Retain a Media Instance object.
471  *
472  * Caller must hold the lock.
473  **************************************************************************/
474 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
475 {
476     if( !p_mi )
477         return;
478
479     p_mi->i_refcount++;
480 }
481
482 /**************************************************************************
483  * Set the Media descriptor associated with the instance.
484  *
485  * Enter without lock -- function will lock the object.
486  **************************************************************************/
487 void libvlc_media_player_set_media(
488                             libvlc_media_player_t *p_mi,
489                             libvlc_media_t *p_md,
490                             libvlc_exception_t *p_e )
491 {
492     VLC_UNUSED(p_e);
493
494     if( !p_mi )
495         return;
496
497     vlc_mutex_lock( &p_mi->object_lock );
498
499     /* FIXME I am not sure if it is a user request or on die(eof/error)
500      * request here */
501     release_input_thread( p_mi,
502                           p_mi->p_input_thread &&
503                           !p_mi->p_input_thread->b_eof &&
504                           !p_mi->p_input_thread->b_error );
505
506     if( p_mi->p_md )
507         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
508
509     libvlc_media_release( p_mi->p_md );
510
511     if( !p_md )
512     {
513         p_mi->p_md = NULL;
514         vlc_mutex_unlock( &p_mi->object_lock );
515         return; /* It is ok to pass a NULL md */
516     }
517
518     libvlc_media_retain( p_md );
519     p_mi->p_md = p_md;
520
521     /* The policy here is to ignore that we were created using a different
522      * libvlc_instance, because we don't really care */
523     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
524
525     vlc_mutex_unlock( &p_mi->object_lock );
526 }
527
528 /**************************************************************************
529  * Get the Media descriptor associated with the instance.
530  **************************************************************************/
531 libvlc_media_t *
532 libvlc_media_player_get_media(
533                             libvlc_media_player_t *p_mi,
534                             libvlc_exception_t *p_e )
535 {
536     VLC_UNUSED(p_e);
537
538     if( !p_mi->p_md )
539         return NULL;
540
541     libvlc_media_retain( p_mi->p_md );
542     return p_mi->p_md;
543 }
544
545 /**************************************************************************
546  * Get the event Manager.
547  **************************************************************************/
548 libvlc_event_manager_t *
549 libvlc_media_player_event_manager(
550                             libvlc_media_player_t *p_mi,
551                             libvlc_exception_t *p_e )
552 {
553     VLC_UNUSED(p_e);
554
555     return p_mi->p_event_manager;
556 }
557
558 /**************************************************************************
559  * Trigger a snapshot Taken Event.
560  *************************************************************************/
561 static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
562                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
563 {
564     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
565     VLC_UNUSED(p_this) ;
566
567     libvlc_media_player_t* p_mi = (libvlc_media_player_t*) p_data ;
568     libvlc_event_t event ;
569     event.type = libvlc_MediaPlayerSnapshotTaken ;
570     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string ;
571     /* Snapshot psz data is a vlc_variable owned by libvlc object .
572          Its memmory management is taken care by the obj*/
573     msg_Dbg( p_this, "about to emit libvlc_snapshot_taken.make psz_str=0x%p"
574              " (%s)", event.u.media_player_snapshot_taken.psz_filename,
575              event.u.media_player_snapshot_taken.psz_filename );
576     libvlc_event_send( p_mi->p_event_manager, &event );
577
578     return VLC_SUCCESS;
579 }
580
581 /**************************************************************************
582  * Tell media player to start playing.
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(
610             p_mi->p_libvlc_instance->p_libvlc_int, p_mi->p_md->p_input_item );
611
612     if( !p_mi->p_input_thread )
613     {
614         vlc_mutex_unlock( &p_mi->object_lock );
615         return;
616     }
617
618     p_input_thread = p_mi->p_input_thread;
619
620     var_Create( p_input_thread, "drawable-agl", VLC_VAR_INTEGER );
621     if( p_mi->drawable.agl )
622         var_SetInteger( p_input_thread, "drawable-agl", p_mi->drawable.agl );
623
624     var_Create( p_input_thread, "drawable-xid", VLC_VAR_INTEGER );
625     if( p_mi->drawable.xid )
626         var_SetInteger( p_input_thread, "drawable-xid", p_mi->drawable.xid );
627
628     var_Create( p_input_thread, "drawable-hwnd", VLC_VAR_ADDRESS );
629     if( p_mi->drawable.hwnd != NULL )
630     {
631         vlc_value_t val = { .p_address = p_mi->drawable.hwnd };
632         var_Set( p_input_thread, "drawable-hwnd", val );
633     }
634
635     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
636     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
637     var_AddCallback( p_input_thread, "intf-event", input_event_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  * Tells whether the media player is currently playing.
670  *
671  * Enter with lock held.
672  **************************************************************************/
673 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi,
674                                      libvlc_exception_t *p_e )
675 {
676     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
677     return libvlc_Playing == state;
678 }
679
680
681 /**************************************************************************
682  * Stop playing.
683  **************************************************************************/
684 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
685                                  libvlc_exception_t *p_e )
686 {
687     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
688
689     if( state == libvlc_Playing || state == libvlc_Paused )
690     {
691         /* Send a stop notification event only if we are in playing or
692          * paused states */
693         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
694
695         /* Construct and send the event */
696         libvlc_event_t event;
697         event.type = libvlc_MediaPlayerStopped;
698         libvlc_event_send( p_mi->p_event_manager, &event );
699     }
700
701     if( p_mi->b_own_its_input_thread )
702     {
703         vlc_mutex_lock( &p_mi->object_lock );
704         release_input_thread( p_mi, true ); /* This will stop the input thread */
705         vlc_mutex_unlock( &p_mi->object_lock );
706     }
707     else
708     {
709         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
710
711         if( !p_input_thread )
712             return;
713
714         input_StopThread( p_input_thread, true );
715         vlc_object_release( p_input_thread );
716         p_mi->p_input_thread = NULL;
717     }
718 }
719
720 /**************************************************************************
721  * set_agl
722  **************************************************************************/
723 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
724                                       uint32_t drawable,
725                                       libvlc_exception_t *p_e )
726 {
727     (void) p_e;
728     p_mi->drawable.agl = drawable;
729 }
730
731 /**************************************************************************
732  * get_agl
733  **************************************************************************/
734 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
735 {
736     return p_mi->drawable.agl;
737 }
738
739 /**************************************************************************
740  * set_xwindow
741  **************************************************************************/
742 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
743                                       uint32_t drawable,
744                                       libvlc_exception_t *p_e )
745 {
746     (void) p_e;
747     p_mi->drawable.xid = drawable;
748 }
749
750 /**************************************************************************
751  * get_xwindow
752  **************************************************************************/
753 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
754 {
755     return p_mi->drawable.xid;
756 }
757
758 /**************************************************************************
759  * set_hwnd
760  **************************************************************************/
761 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
762                                    void *drawable,
763                                    libvlc_exception_t *p_e )
764 {
765     (void) p_e;
766     p_mi->drawable.hwnd = drawable;
767 }
768
769 /**************************************************************************
770  * get_hwnd
771  **************************************************************************/
772 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
773 {
774     return p_mi->drawable.hwnd;
775 }
776
777 /**************************************************************************
778  * Set Drawable
779  **************************************************************************/
780 void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
781                                        libvlc_drawable_t drawable,
782                                        libvlc_exception_t *p_e )
783 {
784 #ifdef WIN32
785     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
786         p_mi->drawable.hwnd = (HWND)drawable;
787     else
788         libvlc_exception_raise(p_e, "Operation not supported");
789 #elif defined(__APPLE__)
790     p_mi->drawable.agl = drawable;
791     (void) p_e;
792 #else
793     p_mi->drawable.xid = drawable;
794     (void) p_e;
795 #endif
796 }
797
798 /**************************************************************************
799  * Get Drawable
800  **************************************************************************/
801 libvlc_drawable_t
802 libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi,
803                                    libvlc_exception_t *p_e )
804 {
805     VLC_UNUSED(p_e);
806
807 #ifdef WIN32
808     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
809         return (libvlc_drawable_t)p_mi->drawable.hwnd;
810     else
811         return 0;
812 #elif defined(__APPLE__)
813     return p_mi->drawable.agl;
814 #else
815     return p_mi->drawable.xid;
816 #endif
817 }
818
819 /**************************************************************************
820  * Getters for stream information
821  **************************************************************************/
822 libvlc_time_t libvlc_media_player_get_length(
823                              libvlc_media_player_t *p_mi,
824                              libvlc_exception_t *p_e )
825 {
826     input_thread_t *p_input_thread;
827     vlc_value_t val;
828
829     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
830     if( !p_input_thread )
831         return -1;
832
833     var_Get( p_input_thread, "length", &val );
834     vlc_object_release( p_input_thread );
835
836     return (val.i_time+500LL)/1000LL;
837 }
838
839 libvlc_time_t libvlc_media_player_get_time(
840                                    libvlc_media_player_t *p_mi,
841                                    libvlc_exception_t *p_e )
842 {
843     input_thread_t *p_input_thread;
844     vlc_value_t val;
845
846     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
847     if( !p_input_thread )
848         return -1;
849
850     var_Get( p_input_thread , "time", &val );
851     vlc_object_release( p_input_thread );
852     return (val.i_time+500LL)/1000LL;
853 }
854
855 void libvlc_media_player_set_time(
856                                  libvlc_media_player_t *p_mi,
857                                  libvlc_time_t time,
858                                  libvlc_exception_t *p_e )
859 {
860     input_thread_t *p_input_thread;
861     vlc_value_t value;
862
863     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
864     if( !p_input_thread )
865         return;
866
867     value.i_time = time*1000LL;
868     var_Set( p_input_thread, "time", value );
869     vlc_object_release( p_input_thread );
870 }
871
872 void libvlc_media_player_set_position(
873                                 libvlc_media_player_t *p_mi,
874                                 float position,
875                                 libvlc_exception_t *p_e )
876 {
877     input_thread_t *p_input_thread;
878     vlc_value_t val;
879     val.f_float = position;
880
881     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
882     if( !p_input_thread )
883         return;
884
885     var_Set( p_input_thread, "position", val );
886     vlc_object_release( p_input_thread );
887 }
888
889 float libvlc_media_player_get_position(
890                                  libvlc_media_player_t *p_mi,
891                                  libvlc_exception_t *p_e )
892 {
893     input_thread_t *p_input_thread;
894     vlc_value_t val;
895
896     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
897     if( !p_input_thread )
898         return -1.0;
899
900     var_Get( p_input_thread, "position", &val );
901     vlc_object_release( p_input_thread );
902
903     return val.f_float;
904 }
905
906 void libvlc_media_player_set_chapter(
907                                  libvlc_media_player_t *p_mi,
908                                  int chapter,
909                                  libvlc_exception_t *p_e )
910 {
911     input_thread_t *p_input_thread;
912     vlc_value_t val;
913     val.i_int = chapter;
914
915     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
916     if( !p_input_thread )
917         return;
918
919     var_Set( p_input_thread, "chapter", val );
920     vlc_object_release( p_input_thread );
921 }
922
923 int libvlc_media_player_get_chapter(
924                                  libvlc_media_player_t *p_mi,
925                                  libvlc_exception_t *p_e )
926 {
927     input_thread_t *p_input_thread;
928     vlc_value_t val;
929
930     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
931     if( !p_input_thread )
932         return -1;
933
934     var_Get( p_input_thread, "chapter", &val );
935     vlc_object_release( p_input_thread );
936
937     return val.i_int;
938 }
939
940 int libvlc_media_player_get_chapter_count(
941                                  libvlc_media_player_t *p_mi,
942                                  libvlc_exception_t *p_e )
943 {
944     input_thread_t *p_input_thread;
945     vlc_value_t val;
946
947     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
948     if( !p_input_thread )
949         return -1;
950
951     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
952     vlc_object_release( p_input_thread );
953
954     return val.i_int;
955 }
956
957 int libvlc_media_player_get_chapter_count_for_title(
958                                  libvlc_media_player_t *p_mi,
959                                  int i_title,
960                                  libvlc_exception_t *p_e )
961 {
962     input_thread_t *p_input_thread;
963     vlc_value_t val;
964
965     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
966     if( !p_input_thread )
967         return -1;
968
969     char *psz_name;
970     if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
971     {
972         vlc_object_release( p_input_thread );
973         return -1;
974     }
975     var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
976     vlc_object_release( p_input_thread );
977     free( psz_name );
978
979     return val.i_int;
980 }
981
982 void libvlc_media_player_set_title(
983                                  libvlc_media_player_t *p_mi,
984                                  int i_title,
985                                  libvlc_exception_t *p_e )
986 {
987     input_thread_t *p_input_thread;
988     vlc_value_t val;
989     val.i_int = i_title;
990
991     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
992     if( !p_input_thread )
993         return;
994
995     var_Set( p_input_thread, "title", val );
996     vlc_object_release( p_input_thread );
997
998     //send event
999     libvlc_event_t event;
1000     event.type = libvlc_MediaPlayerTitleChanged;
1001     event.u.media_player_title_changed.new_title = i_title;
1002     libvlc_event_send( p_mi->p_event_manager, &event );
1003 }
1004
1005 int libvlc_media_player_get_title(
1006                                  libvlc_media_player_t *p_mi,
1007                                  libvlc_exception_t *p_e )
1008 {
1009     input_thread_t *p_input_thread;
1010     vlc_value_t val;
1011
1012     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1013     if( !p_input_thread )
1014         return -1;
1015
1016     var_Get( p_input_thread, "title", &val );
1017     vlc_object_release( p_input_thread );
1018
1019     return val.i_int;
1020 }
1021
1022 int libvlc_media_player_get_title_count(
1023                                  libvlc_media_player_t *p_mi,
1024                                  libvlc_exception_t *p_e )
1025 {
1026     input_thread_t *p_input_thread;
1027     vlc_value_t val;
1028
1029     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1030     if( !p_input_thread )
1031         return -1;
1032
1033     var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1034     vlc_object_release( p_input_thread );
1035
1036     return val.i_int;
1037 }
1038
1039 void libvlc_media_player_next_chapter(
1040                                  libvlc_media_player_t *p_mi,
1041                                  libvlc_exception_t *p_e )
1042 {
1043     input_thread_t *p_input_thread;
1044
1045     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
1046     if( !p_input_thread )
1047         return;
1048
1049     int i_type = var_Type( p_input_thread, "next-chapter" );
1050     vlc_value_t val;
1051     val.b_bool = true;
1052     var_Set( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1053                             "next-chapter":"next-title", val );
1054
1055     vlc_object_release( p_input_thread );
1056 }
1057
1058 void libvlc_media_player_previous_chapter(
1059                                  libvlc_media_player_t *p_mi,
1060                                  libvlc_exception_t *p_e )
1061 {
1062     input_thread_t *p_input_thread;
1063
1064     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
1065     if( !p_input_thread )
1066         return;
1067
1068     int i_type = var_Type( p_input_thread, "next-chapter" );
1069     vlc_value_t val;
1070     val.b_bool = true;
1071     var_Set( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1072                             "prev-chapter":"prev-title", val );
1073
1074     vlc_object_release( p_input_thread );
1075 }
1076
1077 float libvlc_media_player_get_fps(
1078                                  libvlc_media_player_t *p_mi,
1079                                  libvlc_exception_t *p_e)
1080 {
1081     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1082     double f_fps = 0.0;
1083
1084     if( p_input_thread )
1085     {
1086         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
1087             f_fps = 0.0;
1088         vlc_object_release( p_input_thread );
1089     }
1090     return f_fps;
1091 }
1092
1093 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
1094                                      libvlc_exception_t *p_e)
1095 {
1096     input_thread_t *p_input_thread =
1097                             libvlc_get_input_thread ( p_mi, p_e);
1098     if ( !p_input_thread )
1099         return false;
1100
1101     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
1102     {
1103         vlc_object_release( p_input_thread );
1104         return true;
1105     }
1106     vlc_object_release( p_input_thread );
1107     return false;
1108 }
1109
1110 void libvlc_media_player_set_rate(
1111                                  libvlc_media_player_t *p_mi,
1112                                  float rate,
1113                                  libvlc_exception_t *p_e )
1114 {
1115     input_thread_t *p_input_thread;
1116     vlc_value_t val;
1117     bool b_can_rewind;
1118
1119     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1120     if( !p_input_thread )
1121         return;
1122
1123     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
1124     if( (rate < 0.0) && !b_can_rewind )
1125     {
1126         vlc_object_release( p_input_thread );
1127         libvlc_exception_raise( p_e, "Rate value is invalid" );
1128         return;
1129     }
1130
1131     val.i_int = 1000.0f/rate;
1132     var_Set( p_input_thread, "rate", val );
1133     vlc_object_release( p_input_thread );
1134 }
1135
1136 float libvlc_media_player_get_rate(
1137                                  libvlc_media_player_t *p_mi,
1138                                  libvlc_exception_t *p_e )
1139 {
1140     input_thread_t *p_input_thread;
1141     vlc_value_t val;
1142     bool b_can_rewind;
1143
1144     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1145     if( !p_input_thread )
1146         return 0.0;  /* rate < 0 indicates rewind */
1147
1148     var_Get( p_input_thread, "rate", &val );
1149     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
1150     if( (val.i_int < 0) && !b_can_rewind )
1151     {
1152         libvlc_exception_raise( p_e, "invalid rate" );
1153         return 0.0;
1154     }
1155     vlc_object_release( p_input_thread );
1156
1157     return (float)1000.0f/val.i_int;
1158 }
1159
1160 libvlc_state_t libvlc_media_player_get_state(
1161                                  libvlc_media_player_t *p_mi,
1162                                  libvlc_exception_t *p_e )
1163 {
1164     input_thread_t *p_input_thread;
1165     libvlc_state_t state = libvlc_Ended;
1166     vlc_value_t val;
1167
1168     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1169     if( !p_input_thread )
1170     {
1171         /* We do return the right value, no need to throw an exception */
1172         if( libvlc_exception_raised( p_e ) )
1173             libvlc_exception_clear( p_e );
1174         return state;
1175     }
1176
1177     var_Get( p_input_thread, "state", &val );
1178     state = vlc_to_libvlc_state(val.i_int);
1179
1180     if( state == libvlc_Playing )
1181     {
1182         float caching;
1183         caching = var_GetFloat( p_input_thread, "cache" );
1184         if( caching > 0.0 && caching < 1.0 )
1185             state = libvlc_Buffering;
1186     }
1187     vlc_object_release( p_input_thread );
1188     return state;
1189 }
1190
1191 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
1192                                        libvlc_exception_t *p_e )
1193 {
1194     input_thread_t *p_input_thread;
1195     vlc_value_t val;
1196
1197     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1198     if ( !p_input_thread )
1199     {
1200         /* We do return the right value, no need to throw an exception */
1201         if( libvlc_exception_raised( p_e ) )
1202             libvlc_exception_clear( p_e );
1203         return false;
1204     }
1205     var_Get( p_input_thread, "can-seek", &val );
1206     vlc_object_release( p_input_thread );
1207
1208     return val.b_bool;
1209 }
1210
1211 /* internal function, used by audio, video */
1212 libvlc_track_description_t *
1213         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1214                                       const char *psz_variable,
1215                                       libvlc_exception_t *p_e )
1216 {
1217     input_thread_t *p_input = libvlc_get_input_thread( p_mi, p_e );
1218
1219     if( !p_input )
1220         return NULL;
1221
1222     vlc_value_t val_list, text_list;
1223     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
1224
1225     if( val_list.p_list->i_count <= 0 ) /* no tracks */
1226         return NULL;
1227
1228     libvlc_track_description_t *p_track_description, *p_actual, *p_previous;
1229     p_track_description = ( libvlc_track_description_t * )
1230         malloc( sizeof( libvlc_track_description_t ) );
1231     if ( !p_track_description )
1232     {
1233         var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
1234                     &val_list, &text_list);
1235         vlc_object_release( p_input );
1236         libvlc_exception_raise( p_e, "no enough memory" );
1237         return NULL;
1238     }
1239     p_actual = p_track_description;
1240     p_previous = NULL;
1241     for( int i = 0; i < val_list.p_list->i_count; i++ )
1242     {
1243         if( !p_actual )
1244         {
1245             p_actual = ( libvlc_track_description_t * )
1246                 malloc( sizeof( libvlc_track_description_t ) );
1247             if ( !p_actual )
1248             {
1249                 libvlc_track_description_release( p_track_description );
1250                 var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
1251                             &val_list, &text_list);
1252                 vlc_object_release( p_input );
1253                 libvlc_exception_raise( p_e, "no enough memory" );
1254                 return NULL;
1255             }
1256         }
1257         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1258         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1259         p_actual->p_next = NULL;
1260         if( p_previous )
1261             p_previous->p_next = p_actual;
1262         p_previous = p_actual;
1263         p_actual =  NULL;
1264     }
1265     var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
1266     vlc_object_release( p_input );
1267
1268     return p_track_description;
1269 }
1270
1271 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1272 {
1273     libvlc_track_description_t *p_actual, *p_before;
1274     p_actual = p_td;
1275
1276     while ( p_actual )
1277     {
1278         free( p_actual->psz_name );
1279         p_before = p_actual;
1280         p_actual = p_before->p_next;
1281         free( p_before );
1282     }
1283 }
1284
1285 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
1286                                      libvlc_exception_t *p_e )
1287 {
1288     input_thread_t *p_input_thread;
1289     vlc_value_t val;
1290
1291     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1292     if ( !p_input_thread )
1293     {
1294         /* We do return the right value, no need to throw an exception */
1295         if( libvlc_exception_raised( p_e ) )
1296             libvlc_exception_clear( p_e );
1297         return false;
1298     }
1299     var_Get( p_input_thread, "can-pause", &val );
1300     vlc_object_release( p_input_thread );
1301
1302     return val.b_bool;
1303 }