Cleanup whitespace.
[vlc.git] / src / control / media_player.c
1 /*****************************************************************************
2  * media_player.c: Libvlc API Media Instance management functions
3  *****************************************************************************
4  * Copyright (C) 2005-2009 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_Stop( 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_POSITION )
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  * Create a Media Instance object.
246  *
247  * Refcount strategy:
248  * - All items created by _new start with a refcount set to 1.
249  * - Accessor _release decrease the refcount by 1, if after that
250  *   operation the refcount is 0, the object is destroyed.
251  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
252  *
253  * Object locking strategy:
254  * - No lock held while in constructor.
255  * - When accessing any member variable this lock is held. (XXX who locks?)
256  * - When attempting to destroy the object the lock is also held.
257  **************************************************************************/
258 libvlc_media_player_t *
259 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
260                            libvlc_exception_t * p_e )
261 {
262     libvlc_media_player_t * p_mi;
263
264     if( !p_libvlc_instance )
265     {
266         libvlc_exception_raise( p_e, "invalid libvlc instance" );
267         return NULL;
268     }
269
270     p_mi = malloc( sizeof(libvlc_media_player_t) );
271     if( !p_mi )
272     {
273         libvlc_exception_raise( p_e, "Not enough memory" );
274         return NULL;
275     }
276     p_mi->p_md = NULL;
277     p_mi->drawable.agl = 0;
278     p_mi->drawable.xid = 0;
279     p_mi->drawable.hwnd = NULL;
280     p_mi->p_libvlc_instance = p_libvlc_instance;
281     p_mi->p_input_thread = NULL;
282     p_mi->i_refcount = 1;
283     p_mi->b_own_its_input_thread = true;
284     vlc_mutex_init( &p_mi->object_lock );
285     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
286             p_libvlc_instance, p_e );
287     if( libvlc_exception_raised( p_e ) )
288     {
289         vlc_mutex_destroy( &p_mi->object_lock );
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_Create( p_mi->p_libvlc_instance->p_libvlc_int,
610                                          p_mi->p_md->p_input_item, NULL, NULL );
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_Create( p_input_thread, "drawable-nsobject", VLC_VAR_ADDRESS );
636     if( p_mi->drawable.nsobject != NULL )
637     {
638         vlc_value_t val = { .p_address = p_mi->drawable.nsobject };
639         var_Set( p_input_thread, "drawable-nsobject", val );
640     }
641         
642     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
643     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
644     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
645
646     if( input_Start( p_input_thread ) )
647     {
648         vlc_object_release( p_input_thread );
649         p_mi->p_input_thread = NULL;
650     }
651
652     vlc_mutex_unlock( &p_mi->object_lock );
653 }
654
655 /**************************************************************************
656  * Pause.
657  **************************************************************************/
658 void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
659                                   libvlc_exception_t *p_e )
660 {
661     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
662     if( !p_input_thread )
663         return;
664
665     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
666     if( state == libvlc_Playing || state == libvlc_Buffering )
667     {
668         if( libvlc_media_player_can_pause( p_mi, p_e ) )
669             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
670         else
671             libvlc_media_player_stop( p_mi, p_e );
672     }
673     else
674         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
675
676     vlc_object_release( p_input_thread );
677 }
678
679 /**************************************************************************
680  * Tells whether the media player is currently playing.
681  *
682  * Enter with lock held.
683  **************************************************************************/
684 int libvlc_media_player_is_playing( 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     return (libvlc_Playing == state) || (libvlc_Buffering == state);
689 }
690
691 /**************************************************************************
692  * Stop playing.
693  **************************************************************************/
694 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
695                                  libvlc_exception_t *p_e )
696 {
697     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
698
699     if( state == libvlc_Playing ||
700         state == libvlc_Paused ||
701         state == libvlc_Buffering )
702     {
703         /* Send a stop notification event only if we are in playing,
704          * buffering or paused states */
705         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
706
707         /* Construct and send the event */
708         libvlc_event_t event;
709         event.type = libvlc_MediaPlayerStopped;
710         libvlc_event_send( p_mi->p_event_manager, &event );
711     }
712
713     if( p_mi->b_own_its_input_thread )
714     {
715         vlc_mutex_lock( &p_mi->object_lock );
716         release_input_thread( p_mi, true ); /* This will stop the input thread */
717         vlc_mutex_unlock( &p_mi->object_lock );
718     }
719     else
720     {
721         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
722         if( !p_input_thread )
723             return;
724
725         input_Stop( p_input_thread, true );
726         vlc_object_release( p_input_thread );
727         p_mi->p_input_thread = NULL;
728     }
729 }
730
731 /**************************************************************************
732  * set_nsobject
733  **************************************************************************/
734 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
735                                         void * drawable,
736                                         libvlc_exception_t *p_e )
737 {
738     (void) p_e;
739     p_mi->drawable.nsobject = drawable;
740 }
741
742 /**************************************************************************
743  * get_nsobject
744  **************************************************************************/
745 uint32_t libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
746 {
747     return p_mi->drawable.nsobject;
748 }
749
750 /**************************************************************************
751  * set_agl
752  **************************************************************************/
753 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
754                                       uint32_t drawable,
755                                       libvlc_exception_t *p_e )
756 {
757     (void) p_e;
758     p_mi->drawable.agl = drawable;
759 }
760
761 /**************************************************************************
762  * get_agl
763  **************************************************************************/
764 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
765 {
766     return p_mi->drawable.agl;
767 }
768
769 /**************************************************************************
770  * set_xwindow
771  **************************************************************************/
772 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
773                                       uint32_t drawable,
774                                       libvlc_exception_t *p_e )
775 {
776     (void) p_e;
777     p_mi->drawable.xid = drawable;
778 }
779
780 /**************************************************************************
781  * get_xwindow
782  **************************************************************************/
783 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
784 {
785     return p_mi->drawable.xid;
786 }
787
788 /**************************************************************************
789  * set_hwnd
790  **************************************************************************/
791 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
792                                    void *drawable,
793                                    libvlc_exception_t *p_e )
794 {
795     (void) p_e;
796     p_mi->drawable.hwnd = drawable;
797 }
798
799 /**************************************************************************
800  * get_hwnd
801  **************************************************************************/
802 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
803 {
804     return p_mi->drawable.hwnd;
805 }
806
807 /**************************************************************************
808  * Set Drawable
809  **************************************************************************/
810 void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
811                                        libvlc_drawable_t drawable,
812                                        libvlc_exception_t *p_e )
813 {
814 #ifdef WIN32
815     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
816         p_mi->drawable.hwnd = (HWND)drawable;
817     else
818         libvlc_exception_raise(p_e, "Operation not supported");
819 #elif defined(__APPLE__)
820     p_mi->drawable.agl = drawable;
821     (void) p_e;
822 #else
823     p_mi->drawable.xid = drawable;
824     (void) p_e;
825 #endif
826 }
827
828 /**************************************************************************
829  * Get Drawable
830  **************************************************************************/
831 libvlc_drawable_t
832 libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi,
833                                    libvlc_exception_t *p_e )
834 {
835     VLC_UNUSED(p_e);
836
837 #ifdef WIN32
838     if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
839         return (libvlc_drawable_t)p_mi->drawable.hwnd;
840     else
841         return 0;
842 #elif defined(__APPLE__)
843     return p_mi->drawable.agl;
844 #else
845     return p_mi->drawable.xid;
846 #endif
847 }
848
849 /**************************************************************************
850  * Getters for stream information
851  **************************************************************************/
852 libvlc_time_t libvlc_media_player_get_length(
853                              libvlc_media_player_t *p_mi,
854                              libvlc_exception_t *p_e )
855 {
856     input_thread_t *p_input_thread;
857     vlc_value_t val;
858
859     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
860     if( !p_input_thread )
861         return -1;
862
863     var_Get( p_input_thread, "length", &val );
864     vlc_object_release( p_input_thread );
865
866     return (val.i_time+500LL)/1000LL;
867 }
868
869 libvlc_time_t libvlc_media_player_get_time(
870                                    libvlc_media_player_t *p_mi,
871                                    libvlc_exception_t *p_e )
872 {
873     input_thread_t *p_input_thread;
874     vlc_value_t val;
875
876     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
877     if( !p_input_thread )
878         return -1;
879
880     var_Get( p_input_thread , "time", &val );
881     vlc_object_release( p_input_thread );
882     return (val.i_time+500LL)/1000LL;
883 }
884
885 void libvlc_media_player_set_time(
886                                  libvlc_media_player_t *p_mi,
887                                  libvlc_time_t time,
888                                  libvlc_exception_t *p_e )
889 {
890     input_thread_t *p_input_thread;
891
892     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
893     if( !p_input_thread )
894         return;
895
896     var_SetTime( p_input_thread, "time", time*1000LL );
897     vlc_object_release( p_input_thread );
898 }
899
900 void libvlc_media_player_set_position(
901                                 libvlc_media_player_t *p_mi,
902                                 float position,
903                                 libvlc_exception_t *p_e )
904 {
905     input_thread_t *p_input_thread;
906
907     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
908     if( !p_input_thread )
909         return;
910
911     var_SetFloat( p_input_thread, "position", position );
912     vlc_object_release( p_input_thread );
913 }
914
915 float libvlc_media_player_get_position(
916                                  libvlc_media_player_t *p_mi,
917                                  libvlc_exception_t *p_e )
918 {
919     input_thread_t *p_input_thread;
920     vlc_value_t val;
921
922     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
923     if( !p_input_thread )
924         return -1.0;
925
926     var_Get( p_input_thread, "position", &val );
927     vlc_object_release( p_input_thread );
928
929     return val.f_float;
930 }
931
932 void libvlc_media_player_set_chapter(
933                                  libvlc_media_player_t *p_mi,
934                                  int chapter,
935                                  libvlc_exception_t *p_e )
936 {
937     input_thread_t *p_input_thread;
938
939     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
940     if( !p_input_thread )
941         return;
942
943     var_SetInteger( p_input_thread, "chapter", chapter );
944     vlc_object_release( p_input_thread );
945 }
946
947 int libvlc_media_player_get_chapter(
948                                  libvlc_media_player_t *p_mi,
949                                  libvlc_exception_t *p_e )
950 {
951     input_thread_t *p_input_thread;
952     vlc_value_t val;
953
954     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
955     if( !p_input_thread )
956         return -1;
957
958     var_Get( p_input_thread, "chapter", &val );
959     vlc_object_release( p_input_thread );
960
961     return val.i_int;
962 }
963
964 int libvlc_media_player_get_chapter_count(
965                                  libvlc_media_player_t *p_mi,
966                                  libvlc_exception_t *p_e )
967 {
968     input_thread_t *p_input_thread;
969     vlc_value_t val;
970
971     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
972     if( !p_input_thread )
973         return -1;
974
975     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
976     vlc_object_release( p_input_thread );
977
978     return val.i_int;
979 }
980
981 int libvlc_media_player_get_chapter_count_for_title(
982                                  libvlc_media_player_t *p_mi,
983                                  int i_title,
984                                  libvlc_exception_t *p_e )
985 {
986     input_thread_t *p_input_thread;
987     vlc_value_t val;
988
989     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
990     if( !p_input_thread )
991         return -1;
992
993     char *psz_name;
994     if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
995     {
996         vlc_object_release( p_input_thread );
997         return -1;
998     }
999     var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1000     vlc_object_release( p_input_thread );
1001     free( psz_name );
1002
1003     return val.i_int;
1004 }
1005
1006 void libvlc_media_player_set_title(
1007                                  libvlc_media_player_t *p_mi,
1008                                  int i_title,
1009                                  libvlc_exception_t *p_e )
1010 {
1011     input_thread_t *p_input_thread;
1012
1013     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
1014     if( !p_input_thread )
1015         return;
1016
1017     var_SetInteger( p_input_thread, "title", i_title );
1018     vlc_object_release( p_input_thread );
1019
1020     //send event
1021     libvlc_event_t event;
1022     event.type = libvlc_MediaPlayerTitleChanged;
1023     event.u.media_player_title_changed.new_title = i_title;
1024     libvlc_event_send( p_mi->p_event_manager, &event );
1025 }
1026
1027 int libvlc_media_player_get_title(
1028                                  libvlc_media_player_t *p_mi,
1029                                  libvlc_exception_t *p_e )
1030 {
1031     input_thread_t *p_input_thread;
1032     vlc_value_t val;
1033
1034     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1035     if( !p_input_thread )
1036         return -1;
1037
1038     var_Get( p_input_thread, "title", &val );
1039     vlc_object_release( p_input_thread );
1040
1041     return val.i_int;
1042 }
1043
1044 int libvlc_media_player_get_title_count(
1045                                  libvlc_media_player_t *p_mi,
1046                                  libvlc_exception_t *p_e )
1047 {
1048     input_thread_t *p_input_thread;
1049     vlc_value_t val;
1050
1051     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1052     if( !p_input_thread )
1053         return -1;
1054
1055     var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1056     vlc_object_release( p_input_thread );
1057
1058     return val.i_int;
1059 }
1060
1061 void libvlc_media_player_next_chapter(
1062                                  libvlc_media_player_t *p_mi,
1063                                  libvlc_exception_t *p_e )
1064 {
1065     input_thread_t *p_input_thread;
1066
1067     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
1068     if( !p_input_thread )
1069         return;
1070
1071     int i_type = var_Type( p_input_thread, "next-chapter" );
1072     var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1073                             "next-chapter":"next-title", true );
1074
1075     vlc_object_release( p_input_thread );
1076 }
1077
1078 void libvlc_media_player_previous_chapter(
1079                                  libvlc_media_player_t *p_mi,
1080                                  libvlc_exception_t *p_e )
1081 {
1082     input_thread_t *p_input_thread;
1083
1084     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
1085     if( !p_input_thread )
1086         return;
1087
1088     int i_type = var_Type( p_input_thread, "next-chapter" );
1089     var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1090                             "prev-chapter":"prev-title", true );
1091
1092     vlc_object_release( p_input_thread );
1093 }
1094
1095 float libvlc_media_player_get_fps(
1096                                  libvlc_media_player_t *p_mi,
1097                                  libvlc_exception_t *p_e)
1098 {
1099     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1100     double f_fps = 0.0;
1101
1102     if( p_input_thread )
1103     {
1104         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
1105             f_fps = 0.0;
1106         vlc_object_release( p_input_thread );
1107     }
1108     return f_fps;
1109 }
1110
1111 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
1112                                      libvlc_exception_t *p_e)
1113 {
1114     input_thread_t *p_input_thread =
1115                             libvlc_get_input_thread ( p_mi, p_e);
1116     if ( !p_input_thread )
1117         return false;
1118
1119     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
1120     {
1121         vlc_object_release( p_input_thread );
1122         return true;
1123     }
1124     vlc_object_release( p_input_thread );
1125     return false;
1126 }
1127
1128 void libvlc_media_player_set_rate(
1129                                  libvlc_media_player_t *p_mi,
1130                                  float rate,
1131                                  libvlc_exception_t *p_e )
1132 {
1133     input_thread_t *p_input_thread;
1134     bool b_can_rewind;
1135
1136     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1137     if( !p_input_thread )
1138         return;
1139
1140     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
1141     if( (rate < 0.0) && !b_can_rewind )
1142     {
1143         vlc_object_release( p_input_thread );
1144         libvlc_exception_raise( p_e, "Rate value is invalid" );
1145         return;
1146     }
1147
1148     var_SetInteger( p_input_thread, "rate", 1000.0f/rate );
1149     vlc_object_release( p_input_thread );
1150 }
1151
1152 float libvlc_media_player_get_rate(
1153                                  libvlc_media_player_t *p_mi,
1154                                  libvlc_exception_t *p_e )
1155 {
1156     input_thread_t *p_input_thread;
1157     vlc_value_t val;
1158     bool b_can_rewind;
1159
1160     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1161     if( !p_input_thread )
1162         return 0.0;  /* rate < 0 indicates rewind */
1163
1164     var_Get( p_input_thread, "rate", &val );
1165     b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
1166     if( (val.i_int < 0) && !b_can_rewind )
1167     {
1168         libvlc_exception_raise( p_e, "invalid rate" );
1169         return 0.0;
1170     }
1171     vlc_object_release( p_input_thread );
1172
1173     return (float)1000.0f/val.i_int;
1174 }
1175
1176 libvlc_state_t libvlc_media_player_get_state(
1177                                  libvlc_media_player_t *p_mi,
1178                                  libvlc_exception_t *p_e )
1179 {
1180     input_thread_t *p_input_thread;
1181     libvlc_state_t state = libvlc_Ended;
1182     vlc_value_t val;
1183
1184     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1185     if( !p_input_thread )
1186     {
1187         /* We do return the right value, no need to throw an exception */
1188         if( libvlc_exception_raised( p_e ) )
1189             libvlc_exception_clear( p_e );
1190         return state;
1191     }
1192
1193     var_Get( p_input_thread, "state", &val );
1194     state = vlc_to_libvlc_state(val.i_int);
1195
1196     if( state == libvlc_Playing )
1197     {
1198         float caching;
1199         caching = var_GetFloat( p_input_thread, "cache" );
1200         if( caching > 0.0 && caching < 1.0 )
1201             state = libvlc_Buffering;
1202     }
1203     vlc_object_release( p_input_thread );
1204     return state;
1205 }
1206
1207 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
1208                                        libvlc_exception_t *p_e )
1209 {
1210     input_thread_t *p_input_thread;
1211     vlc_value_t val;
1212
1213     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1214     if ( !p_input_thread )
1215     {
1216         /* We do return the right value, no need to throw an exception */
1217         if( libvlc_exception_raised( p_e ) )
1218             libvlc_exception_clear( p_e );
1219         return false;
1220     }
1221     var_Get( p_input_thread, "can-seek", &val );
1222     vlc_object_release( p_input_thread );
1223
1224     return val.b_bool;
1225 }
1226
1227 /* internal function, used by audio, video */
1228 libvlc_track_description_t *
1229         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1230                                       const char *psz_variable,
1231                                       libvlc_exception_t *p_e )
1232 {
1233     input_thread_t *p_input = libvlc_get_input_thread( p_mi, p_e );
1234
1235     if( !p_input )
1236         return NULL;
1237
1238     vlc_value_t val_list, text_list;
1239     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
1240
1241     if( val_list.p_list->i_count <= 0 ) /* no tracks */
1242         return NULL;
1243
1244     libvlc_track_description_t *p_track_description, *p_actual, *p_previous;
1245     p_track_description = ( libvlc_track_description_t * )
1246         malloc( sizeof( libvlc_track_description_t ) );
1247     if ( !p_track_description )
1248     {
1249         var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
1250                     &val_list, &text_list);
1251         vlc_object_release( p_input );
1252         libvlc_exception_raise( p_e, "no enough memory" );
1253         return NULL;
1254     }
1255     p_actual = p_track_description;
1256     p_previous = NULL;
1257     for( int i = 0; i < val_list.p_list->i_count; i++ )
1258     {
1259         if( !p_actual )
1260         {
1261             p_actual = ( libvlc_track_description_t * )
1262                 malloc( sizeof( libvlc_track_description_t ) );
1263             if ( !p_actual )
1264             {
1265                 libvlc_track_description_release( p_track_description );
1266                 var_Change( p_input, psz_variable, VLC_VAR_FREELIST,
1267                             &val_list, &text_list);
1268                 vlc_object_release( p_input );
1269                 libvlc_exception_raise( p_e, "no enough memory" );
1270                 return NULL;
1271             }
1272         }
1273         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1274         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1275         p_actual->p_next = NULL;
1276         if( p_previous )
1277             p_previous->p_next = p_actual;
1278         p_previous = p_actual;
1279         p_actual =  NULL;
1280     }
1281     var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
1282     vlc_object_release( p_input );
1283
1284     return p_track_description;
1285 }
1286
1287 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1288 {
1289     libvlc_track_description_t *p_actual, *p_before;
1290     p_actual = p_td;
1291
1292     while ( p_actual )
1293     {
1294         free( p_actual->psz_name );
1295         p_before = p_actual;
1296         p_actual = p_before->p_next;
1297         free( p_before );
1298     }
1299 }
1300
1301 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
1302                                      libvlc_exception_t *p_e )
1303 {
1304     input_thread_t *p_input_thread;
1305     vlc_value_t val;
1306
1307     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
1308     if ( !p_input_thread )
1309     {
1310         /* We do return the right value, no need to throw an exception */
1311         if( libvlc_exception_raised( p_e ) )
1312             libvlc_exception_clear( p_e );
1313         return false;
1314     }
1315     var_Get( p_input_thread, "can-pause", &val );
1316     vlc_object_release( p_input_thread );
1317
1318     return val.b_bool;
1319 }