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