]> git.sesse.net Git - vlc/blob - lib/media_player.c
playlist: convert "volume" to float
[vlc] / lib / media_player.c
1 /*****************************************************************************
2  * media_player.c: Libvlc API Media Instance management functions
3  *****************************************************************************
4  * Copyright (C) 2005-2011 VLC authors and VideoLAN
5  *
6  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <assert.h>
28
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_events.h>
32
33 #include <vlc_demux.h>
34 #include <vlc_input.h>
35 #include <vlc_vout.h>
36 #include <vlc_keys.h>
37
38 #include "libvlc_internal.h"
39 #include "media_internal.h" // libvlc_media_set_state()
40 #include "media_player_internal.h"
41
42 /*
43  * mapping of libvlc_navigate_mode_t to vlc_action_t
44  */
45 static const vlc_action_t libvlc_navigate_to_action[] =
46 {
47     ACTIONID_NAV_ACTIVATE,
48     ACTIONID_NAV_UP,
49     ACTIONID_NAV_DOWN,
50     ACTIONID_NAV_LEFT,
51     ACTIONID_NAV_RIGHT
52 };
53
54 static const uint32_t libvlc_navigate_to_action_size =                        \
55   sizeof( libvlc_navigate_to_action ) / sizeof( libvlc_navigate_to_action[0] );
56
57
58 static int
59 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
60                         vlc_value_t oldval, vlc_value_t newval,
61                         void * p_userdata );
62 static int
63 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
64                         vlc_value_t oldval, vlc_value_t newval,
65                         void * p_userdata );
66 static int
67 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
68                      vlc_value_t oldval, vlc_value_t newval,
69                      void * p_userdata );
70
71 static int
72 snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
73                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
74
75 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
76
77 /*
78  * Shortcuts
79  */
80
81 #define register_event(a, b) __register_event(a, libvlc_MediaPlayer ## b)
82 static inline void __register_event(libvlc_media_player_t *mp, libvlc_event_type_t type)
83 {
84     libvlc_event_manager_register_event_type(mp->p_event_manager, type);
85 }
86
87 /*
88  * The input lock protects the input and input resource pointer.
89  * It MUST NOT be used from callbacks.
90  *
91  * The object lock protects the reset, namely the media and the player state.
92  * It can, and usually needs to be taken from callbacks.
93  * The object lock can be acquired under the input lock... and consequently
94  * the opposite order is STRICTLY PROHIBITED.
95  */
96 static inline void lock(libvlc_media_player_t *mp)
97 {
98     vlc_mutex_lock(&mp->object_lock);
99 }
100
101 static inline void unlock(libvlc_media_player_t *mp)
102 {
103     vlc_mutex_unlock(&mp->object_lock);
104 }
105
106 static inline void lock_input(libvlc_media_player_t *mp)
107 {
108     vlc_mutex_lock(&mp->input.lock);
109 }
110
111 static inline void unlock_input(libvlc_media_player_t *mp)
112 {
113     vlc_mutex_unlock(&mp->input.lock);
114 }
115
116 /*
117  * Release the associated input thread.
118  *
119  * Object lock is NOT held.
120  * Input lock is held or instance is being destroyed.
121  */
122 static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
123 {
124     assert( p_mi );
125
126     input_thread_t *p_input_thread = p_mi->input.p_thread;
127     if( !p_input_thread )
128         return;
129     p_mi->input.p_thread = NULL;
130
131     var_DelCallback( p_input_thread, "can-seek",
132                      input_seekable_changed, p_mi );
133     var_DelCallback( p_input_thread, "can-pause",
134                     input_pausable_changed, p_mi );
135     var_DelCallback( p_input_thread, "intf-event",
136                      input_event_changed, p_mi );
137
138     /* We owned this one */
139     input_Stop( p_input_thread, b_input_abort );
140     input_Close( p_input_thread );
141 }
142
143 /*
144  * Retrieve the input thread. Be sure to release the object
145  * once you are done with it. (libvlc Internal)
146  */
147 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi )
148 {
149     input_thread_t *p_input_thread;
150
151     assert( p_mi );
152
153     lock_input(p_mi);
154     p_input_thread = p_mi->input.p_thread;
155     if( p_input_thread )
156         vlc_object_hold( p_input_thread );
157     else
158         libvlc_printerr( "No active input" );
159     unlock_input(p_mi);
160
161     return p_input_thread;
162 }
163
164 /*
165  * Set the internal state of the media_player. (media player Internal)
166  *
167  * Function will lock the media_player.
168  */
169 static void set_state( libvlc_media_player_t *p_mi, libvlc_state_t state,
170     bool b_locked )
171 {
172     if(!b_locked)
173         lock(p_mi);
174     p_mi->state = state;
175
176     libvlc_media_t *media = p_mi->p_md;
177     if (media)
178         libvlc_media_retain(media);
179
180     if(!b_locked)
181         unlock(p_mi);
182
183     if (media)
184     {
185         // Also set the state of the corresponding media
186         // This is strictly for convenience.
187         libvlc_media_set_state(media, state);
188
189         libvlc_media_release(media);
190     }
191 }
192
193 static int
194 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
195                         vlc_value_t oldval, vlc_value_t newval,
196                         void * p_userdata )
197 {
198     VLC_UNUSED(oldval);
199     VLC_UNUSED(p_this);
200     VLC_UNUSED(psz_cmd);
201     libvlc_media_player_t * p_mi = p_userdata;
202     libvlc_event_t event;
203
204     event.type = libvlc_MediaPlayerSeekableChanged;
205     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
206
207     libvlc_event_send( p_mi->p_event_manager, &event );
208     return VLC_SUCCESS;
209 }
210
211 static int
212 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
213                         vlc_value_t oldval, vlc_value_t newval,
214                         void * p_userdata )
215 {
216     VLC_UNUSED(oldval);
217     VLC_UNUSED(p_this);
218     VLC_UNUSED(psz_cmd);
219     libvlc_media_player_t * p_mi = p_userdata;
220     libvlc_event_t event;
221
222     event.type = libvlc_MediaPlayerPausableChanged;
223     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
224
225     libvlc_event_send( p_mi->p_event_manager, &event );
226     return VLC_SUCCESS;
227 }
228
229 static int
230 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
231                      vlc_value_t oldval, vlc_value_t newval,
232                      void * p_userdata )
233 {
234     VLC_UNUSED(oldval);
235     input_thread_t * p_input = (input_thread_t *)p_this;
236     libvlc_media_player_t * p_mi = p_userdata;
237     libvlc_event_t event;
238
239     assert( !strcmp( psz_cmd, "intf-event" ) );
240
241     if( newval.i_int == INPUT_EVENT_STATE )
242     {
243         libvlc_state_t libvlc_state;
244
245         switch ( var_GetInteger( p_input, "state" ) )
246         {
247             case INIT_S:
248                 libvlc_state = libvlc_NothingSpecial;
249                 event.type = libvlc_MediaPlayerNothingSpecial;
250                 break;
251             case OPENING_S:
252                 libvlc_state = libvlc_Opening;
253                 event.type = libvlc_MediaPlayerOpening;
254                 break;
255             case PLAYING_S:
256                 libvlc_state = libvlc_Playing;
257                 event.type = libvlc_MediaPlayerPlaying;
258                 break;
259             case PAUSE_S:
260                 libvlc_state = libvlc_Paused;
261                 event.type = libvlc_MediaPlayerPaused;
262                 break;
263             case END_S:
264                 libvlc_state = libvlc_Ended;
265                 event.type = libvlc_MediaPlayerEndReached;
266                 break;
267             case ERROR_S:
268                 libvlc_state = libvlc_Error;
269                 event.type = libvlc_MediaPlayerEncounteredError;
270                 break;
271
272             default:
273                 return VLC_SUCCESS;
274         }
275
276         set_state( p_mi, libvlc_state, false );
277         libvlc_event_send( p_mi->p_event_manager, &event );
278     }
279     else if( newval.i_int == INPUT_EVENT_ABORT )
280     {
281         libvlc_state_t libvlc_state = libvlc_Stopped;
282         event.type = libvlc_MediaPlayerStopped;
283
284         set_state( p_mi, libvlc_state, false );
285         libvlc_event_send( p_mi->p_event_manager, &event );
286     }
287     else if( newval.i_int == INPUT_EVENT_POSITION )
288     {
289         if( var_GetInteger( p_input, "state" ) != PLAYING_S )
290             return VLC_SUCCESS; /* Don't send the position while stopped */
291
292         /* */
293         event.type = libvlc_MediaPlayerPositionChanged;
294         event.u.media_player_position_changed.new_position =
295                                           var_GetFloat( p_input, "position" );
296         libvlc_event_send( p_mi->p_event_manager, &event );
297
298         /* */
299         event.type = libvlc_MediaPlayerTimeChanged;
300         event.u.media_player_time_changed.new_time =
301            from_mtime(var_GetTime( p_input, "time" ));
302         libvlc_event_send( p_mi->p_event_manager, &event );
303     }
304     else if( newval.i_int == INPUT_EVENT_LENGTH )
305     {
306         event.type = libvlc_MediaPlayerLengthChanged;
307         event.u.media_player_length_changed.new_length =
308            from_mtime(var_GetTime( p_input, "length" ));
309         libvlc_event_send( p_mi->p_event_manager, &event );
310     }
311     else if( newval.i_int == INPUT_EVENT_CACHE )
312     {
313         event.type = libvlc_MediaPlayerBuffering;
314         event.u.media_player_buffering.new_cache = (int)(100 *
315             var_GetFloat( p_input, "cache" ));
316         libvlc_event_send( p_mi->p_event_manager, &event );
317     }
318     else if( newval.i_int == INPUT_EVENT_VOUT )
319     {
320         vout_thread_t **pp_vout;
321         size_t i_vout;
322         if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
323         {
324             i_vout  = 0;
325         }
326         else
327         {
328             for( size_t i = 0; i < i_vout; i++ )
329                 vlc_object_release( pp_vout[i] );
330             free( pp_vout );
331         }
332
333         event.type = libvlc_MediaPlayerVout;
334         event.u.media_player_vout.new_count = i_vout;
335         libvlc_event_send( p_mi->p_event_manager, &event );
336     }
337
338     return VLC_SUCCESS;
339 }
340
341 /**************************************************************************
342  * Snapshot Taken Event.
343  *
344  * FIXME: This snapshot API interface makes no sense in media_player.
345  *************************************************************************/
346 static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
347                               vlc_value_t oldval, vlc_value_t newval, void *p_data )
348 {
349     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);
350
351     libvlc_media_player_t *mp = p_data;
352     libvlc_event_t event;
353     event.type = libvlc_MediaPlayerSnapshotTaken;
354     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
355     libvlc_event_send(mp->p_event_manager, &event);
356
357     return VLC_SUCCESS;
358 }
359
360 static input_thread_t *find_input (vlc_object_t *obj)
361 {
362     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
363
364     return libvlc_get_input_thread (mp);
365 }
366
367 /* */
368 static void libvlc_media_player_destroy( libvlc_media_player_t * );
369
370
371 /**************************************************************************
372  * Create a Media Instance object.
373  *
374  * Refcount strategy:
375  * - All items created by _new start with a refcount set to 1.
376  * - Accessor _release decrease the refcount by 1, if after that
377  *   operation the refcount is 0, the object is destroyed.
378  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
379  *
380  * Object locking strategy:
381  * - No lock held while in constructor.
382  * - When accessing any member variable this lock is held. (XXX who locks?)
383  * - When attempting to destroy the object the lock is also held.
384  **************************************************************************/
385 libvlc_media_player_t *
386 libvlc_media_player_new( libvlc_instance_t *instance )
387 {
388     libvlc_media_player_t * mp;
389
390     assert(instance);
391
392     mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
393     if (unlikely(mp == NULL))
394     {
395         libvlc_printerr("Not enough memory");
396         return NULL;
397     }
398
399     /* Input */
400     var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
401
402     /* Video */
403     var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
404     var_Create (mp, "window", VLC_VAR_STRING);
405     var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
406     var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
407     var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
408     var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
409     var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
410     var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
411     var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
412     var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
413     var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
414     var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
415     var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
416 #if defined (WIN32) || defined (__OS2__)
417     var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
418 #endif
419 #ifdef __APPLE__
420     var_Create (mp, "drawable-agl", VLC_VAR_INTEGER);
421     var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
422 #endif
423
424     var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
425     var_SetBool (mp, "keyboard-events", true);
426     var_Create (mp, "mouse-events", VLC_VAR_BOOL);
427     var_SetBool (mp, "mouse-events", true);
428
429     var_Create (mp, "fullscreen", VLC_VAR_BOOL);
430     var_Create (mp, "autoscale", VLC_VAR_BOOL);
431     var_SetBool (mp, "autoscale", true);
432     var_Create (mp, "scale", VLC_VAR_FLOAT);
433     var_SetFloat (mp, "scale", 1.);
434     var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
435     var_Create (mp, "crop", VLC_VAR_STRING);
436     var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
437     var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
438
439     var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
440
441     var_Create (mp, "marq-marquee", VLC_VAR_STRING);
442     var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
443     var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
444     var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
445     var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
446     var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
447     var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
448     var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
449     var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
450
451     var_Create (mp, "logo-file", VLC_VAR_STRING);
452     var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
453     var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
454     var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
455     var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
456     var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
457     var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
458
459     var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
460     var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
461     var_Create (mp, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
462     var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
463     var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
464
465      /* Audio */
466     var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
467     var_Create (mp, "mute", VLC_VAR_BOOL);
468     var_Create (mp, "volume", VLC_VAR_FLOAT);
469     var_Create (mp, "find-input-callback", VLC_VAR_ADDRESS);
470     var_SetAddress (mp, "find-input-callback", find_input);
471     var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
472     var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
473     var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
474     var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
475     var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
476     var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
477     var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
478     var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
479     var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
480     var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
481     var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
482     var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
483
484     mp->p_md = NULL;
485     mp->state = libvlc_NothingSpecial;
486     mp->p_libvlc_instance = instance;
487     mp->input.p_thread = NULL;
488     mp->input.p_resource = NULL;
489     vlc_mutex_init (&mp->input.lock);
490     mp->i_refcount = 1;
491     mp->p_event_manager = libvlc_event_manager_new(mp, instance);
492     if (unlikely(mp->p_event_manager == NULL))
493     {
494         vlc_object_release(mp);
495         return NULL;
496     }
497     vlc_mutex_init(&mp->object_lock);
498
499     register_event(mp, NothingSpecial);
500     register_event(mp, Opening);
501     register_event(mp, Buffering);
502     register_event(mp, Playing);
503     register_event(mp, Paused);
504     register_event(mp, Stopped);
505     register_event(mp, Forward);
506     register_event(mp, Backward);
507     register_event(mp, EndReached);
508     register_event(mp, EncounteredError);
509     register_event(mp, SeekableChanged);
510
511     register_event(mp, PositionChanged);
512     register_event(mp, TimeChanged);
513     register_event(mp, LengthChanged);
514     register_event(mp, TitleChanged);
515     register_event(mp, PausableChanged);
516
517     register_event(mp, Vout);
518
519     /* Snapshot initialization */
520     register_event(mp, SnapshotTaken);
521
522     register_event(mp, MediaChanged);
523
524     /* Attach a var callback to the global object to provide the glue between
525      * vout_thread that generates the event and media_player that re-emits it
526      * with its own event manager
527      *
528      * FIXME: It's unclear why we want to put this in public API, and why we
529      * want to expose it in such a limiting and ugly way.
530      */
531     var_AddCallback(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp);
532
533     libvlc_retain(instance);
534     return mp;
535 }
536
537 /**************************************************************************
538  * Create a Media Instance object with a media descriptor.
539  **************************************************************************/
540 libvlc_media_player_t *
541 libvlc_media_player_new_from_media( libvlc_media_t * p_md )
542 {
543     libvlc_media_player_t * p_mi;
544
545     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
546     if( !p_mi )
547         return NULL;
548
549     libvlc_media_retain( p_md );
550     p_mi->p_md = p_md;
551
552     return p_mi;
553 }
554
555 /**************************************************************************
556  * Destroy a Media Instance object (libvlc internal)
557  *
558  * Warning: No lock held here, but hey, this is internal. Caller must lock.
559  **************************************************************************/
560 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
561 {
562     assert( p_mi );
563
564     /* Detach Callback from the main libvlc object */
565     var_DelCallback( p_mi->p_libvlc,
566                      "snapshot-file", snapshot_was_taken, p_mi );
567
568     /* No need for lock_input() because no other threads knows us anymore */
569     if( p_mi->input.p_thread )
570         release_input_thread(p_mi, true);
571     if( p_mi->input.p_resource )
572     {
573         input_resource_Terminate( p_mi->input.p_resource );
574         input_resource_Release( p_mi->input.p_resource );
575         p_mi->input.p_resource = NULL;
576     }
577     vlc_mutex_destroy( &p_mi->input.lock );
578
579     libvlc_event_manager_release( p_mi->p_event_manager );
580     libvlc_media_release( p_mi->p_md );
581     vlc_mutex_destroy( &p_mi->object_lock );
582
583     libvlc_instance_t *instance = p_mi->p_libvlc_instance;
584     vlc_object_release( p_mi );
585     libvlc_release(instance);
586 }
587
588 /**************************************************************************
589  * Release a Media Instance object.
590  *
591  * Function does the locking.
592  **************************************************************************/
593 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
594 {
595     bool destroy;
596
597     assert( p_mi );
598     lock(p_mi);
599     destroy = !--p_mi->i_refcount;
600     unlock(p_mi);
601
602     if( destroy )
603         libvlc_media_player_destroy( p_mi );
604 }
605
606 /**************************************************************************
607  * Retain a Media Instance object.
608  *
609  * Caller must hold the lock.
610  **************************************************************************/
611 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
612 {
613     assert( p_mi );
614
615     lock(p_mi);
616     p_mi->i_refcount++;
617     unlock(p_mi);
618 }
619
620 /**************************************************************************
621  * Set the Media descriptor associated with the instance.
622  *
623  * Enter without lock -- function will lock the object.
624  **************************************************************************/
625 void libvlc_media_player_set_media(
626                             libvlc_media_player_t *p_mi,
627                             libvlc_media_t *p_md )
628 {
629     lock_input(p_mi);
630
631     /* FIXME I am not sure if it is a user request or on die(eof/error)
632      * request here */
633     release_input_thread( p_mi,
634                           p_mi->input.p_thread &&
635                           !p_mi->input.p_thread->b_eof &&
636                           !p_mi->input.p_thread->b_error );
637
638     lock( p_mi );
639     set_state( p_mi, libvlc_NothingSpecial, true );
640     unlock_input( p_mi );
641
642     libvlc_media_release( p_mi->p_md );
643
644     if( !p_md )
645     {
646         p_mi->p_md = NULL;
647         unlock(p_mi);
648         return; /* It is ok to pass a NULL md */
649     }
650
651     libvlc_media_retain( p_md );
652     p_mi->p_md = p_md;
653
654     /* The policy here is to ignore that we were created using a different
655      * libvlc_instance, because we don't really care */
656     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
657
658     unlock(p_mi);
659
660     /* Send an event for the newly available media */
661     libvlc_event_t event;
662     event.type = libvlc_MediaPlayerMediaChanged;
663     event.u.media_player_media_changed.new_media = p_md;
664     libvlc_event_send( p_mi->p_event_manager, &event );
665
666 }
667
668 /**************************************************************************
669  * Get the Media descriptor associated with the instance.
670  **************************************************************************/
671 libvlc_media_t *
672 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
673 {
674     libvlc_media_t *p_m;
675
676     lock(p_mi);
677     p_m = p_mi->p_md;
678     if( p_m )
679         libvlc_media_retain( p_mi->p_md );
680     unlock(p_mi);
681     return p_mi->p_md;
682 }
683
684 /**************************************************************************
685  * Get the event Manager.
686  **************************************************************************/
687 libvlc_event_manager_t *
688 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
689 {
690     return p_mi->p_event_manager;
691 }
692
693 /**************************************************************************
694  * Tell media player to start playing.
695  **************************************************************************/
696 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
697 {
698     lock_input( p_mi );
699
700     input_thread_t *p_input_thread = p_mi->input.p_thread;
701     if( p_input_thread )
702     {
703         /* A thread already exists, send it a play message */
704         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
705         unlock_input( p_mi );
706         return 0;
707     }
708
709     /* Ignore previous exception */
710     lock(p_mi);
711
712     if( !p_mi->p_md )
713     {
714         unlock(p_mi);
715         unlock_input( p_mi );
716         libvlc_printerr( "No associated media descriptor" );
717         return -1;
718     }
719
720     if( !p_mi->input.p_resource )
721         p_mi->input.p_resource = input_resource_New( VLC_OBJECT( p_mi ) );
722     p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
723                                    p_mi->input.p_resource );
724     unlock(p_mi);
725     if( !p_input_thread )
726     {
727         unlock_input(p_mi);
728         libvlc_printerr( "Not enough memory" );
729         return -1;
730     }
731
732     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
733     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
734     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
735
736     if( input_Start( p_input_thread ) )
737     {
738         unlock_input(p_mi);
739         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
740         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
741         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
742         vlc_object_release( p_input_thread );
743         libvlc_printerr( "Input initialization failure" );
744         return -1;
745     }
746     p_mi->input.p_thread = p_input_thread;
747     unlock_input(p_mi);
748     return 0;
749 }
750
751 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
752 {
753     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
754     if( !p_input_thread )
755         return;
756
757     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
758     if( state == libvlc_Playing || state == libvlc_Buffering )
759     {
760         if( paused )
761         {
762             if( libvlc_media_player_can_pause( p_mi ) )
763                 input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
764             else
765                 libvlc_media_player_stop( p_mi );
766         }
767     }
768     else
769     {
770         if( !paused )
771             input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
772     }
773
774     vlc_object_release( p_input_thread );
775 }
776
777 /**************************************************************************
778  * Toggle pause.
779  **************************************************************************/
780 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
781 {
782     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
783     bool playing = (state == libvlc_Playing || state == libvlc_Buffering);
784
785     libvlc_media_player_set_pause( p_mi, playing );
786 }
787
788 /**************************************************************************
789  * Tells whether the media player is currently playing.
790  *
791  * Enter with lock held.
792  **************************************************************************/
793 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
794 {
795     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
796     return (libvlc_Playing == state) || (libvlc_Buffering == state);
797 }
798
799 /**************************************************************************
800  * Stop playing.
801  **************************************************************************/
802 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
803 {
804     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
805
806     lock_input(p_mi);
807     release_input_thread( p_mi, true ); /* This will stop the input thread */
808
809     /* Force to go to stopped state, in case we were in Ended, or Error
810      * state. */
811     if( state != libvlc_Stopped )
812     {
813         set_state( p_mi, libvlc_Stopped, false );
814
815         /* Construct and send the event */
816         libvlc_event_t event;
817         event.type = libvlc_MediaPlayerStopped;
818         libvlc_event_send( p_mi->p_event_manager, &event );
819     }
820
821     if( p_mi->input.p_resource != NULL )
822         input_resource_Terminate( p_mi->input.p_resource );
823     unlock_input(p_mi);
824 }
825
826
827 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
828     void *(*lock_cb) (void *, void **),
829     void (*unlock_cb) (void *, void *, void *const *),
830     void (*display_cb) (void *, void *),
831     void *opaque )
832 {
833     var_SetAddress( mp, "vmem-lock", lock_cb );
834     var_SetAddress( mp, "vmem-unlock", unlock_cb );
835     var_SetAddress( mp, "vmem-display", display_cb );
836     var_SetAddress( mp, "vmem-data", opaque );
837     var_SetString( mp, "vout", "vmem" );
838 }
839
840 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
841                                         libvlc_video_format_cb setup,
842                                         libvlc_video_cleanup_cb cleanup )
843 {
844     var_SetAddress( mp, "vmem-setup", setup );
845     var_SetAddress( mp, "vmem-cleanup", cleanup );
846 }
847
848 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
849                               unsigned width, unsigned height, unsigned pitch )
850 {
851     var_SetString( mp, "vmem-chroma", chroma );
852     var_SetInteger( mp, "vmem-width", width );
853     var_SetInteger( mp, "vmem-height", height );
854     var_SetInteger( mp, "vmem-pitch", pitch );
855 }
856
857 /**************************************************************************
858  * set_nsobject
859  **************************************************************************/
860 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
861                                         void * drawable )
862 {
863     assert (p_mi != NULL);
864 #ifdef __APPLE__
865     var_SetAddress (p_mi, "drawable-nsobject", drawable);
866 #else
867     (void) p_mi; (void)drawable;
868 #endif
869 }
870
871 /**************************************************************************
872  * get_nsobject
873  **************************************************************************/
874 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
875 {
876     assert (p_mi != NULL);
877 #ifdef __APPLE__
878     return var_GetAddress (p_mi, "drawable-nsobject");
879 #else
880     return NULL;
881 #endif
882 }
883
884 /**************************************************************************
885  * set_agl
886  **************************************************************************/
887 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
888                                   uint32_t drawable )
889 {
890 #ifdef __APPLE__
891     var_SetInteger (p_mi, "drawable-agl", drawable);
892 #else
893     (void) p_mi; (void)drawable;
894 #endif
895 }
896
897 /**************************************************************************
898  * get_agl
899  **************************************************************************/
900 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
901 {
902     assert (p_mi != NULL);
903 #ifdef __APPLE__
904     return var_GetInteger (p_mi, "drawable-agl");
905 #else
906     return 0;
907 #endif
908 }
909
910 /**************************************************************************
911  * set_xwindow
912  **************************************************************************/
913 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
914                                       uint32_t drawable )
915 {
916     assert (p_mi != NULL);
917
918     var_SetString (p_mi, "vout", drawable ? "xid" : "any");
919     var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "any");
920     var_SetInteger (p_mi, "drawable-xid", drawable);
921 }
922
923 /**************************************************************************
924  * get_xwindow
925  **************************************************************************/
926 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
927 {
928     return var_GetInteger (p_mi, "drawable-xid");
929 }
930
931 /**************************************************************************
932  * set_hwnd
933  **************************************************************************/
934 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
935                                    void *drawable )
936 {
937     assert (p_mi != NULL);
938 #if defined (WIN32) || defined (__OS2__)
939     var_SetString (p_mi, "window",
940                    (drawable != NULL) ? "embed-hwnd,any" : "");
941     var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
942 #else
943     (void) p_mi; (void) drawable;
944 #endif
945 }
946
947 /**************************************************************************
948  * get_hwnd
949  **************************************************************************/
950 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
951 {
952     assert (p_mi != NULL);
953 #if defined (WIN32) || defined (__OS2__)
954     return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
955 #else
956     return NULL;
957 #endif
958 }
959
960 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
961                                  libvlc_audio_play_cb play_cb,
962                                  libvlc_audio_pause_cb pause_cb,
963                                  libvlc_audio_resume_cb resume_cb,
964                                  libvlc_audio_flush_cb flush_cb,
965                                  libvlc_audio_drain_cb drain_cb,
966                                  void *opaque )
967 {
968     var_SetAddress( mp, "amem-play", play_cb );
969     var_SetAddress( mp, "amem-pause", pause_cb );
970     var_SetAddress( mp, "amem-resume", resume_cb );
971     var_SetAddress( mp, "amem-flush", flush_cb );
972     var_SetAddress( mp, "amem-drain", drain_cb );
973     var_SetAddress( mp, "amem-data", opaque );
974     var_SetString( mp, "aout", "amem,none" );
975 }
976
977 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
978                                        libvlc_audio_set_volume_cb cb )
979 {
980     var_SetAddress( mp, "amem-set-volume", cb );
981 }
982
983 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
984                                         libvlc_audio_setup_cb setup,
985                                         libvlc_audio_cleanup_cb cleanup )
986 {
987     var_SetAddress( mp, "amem-setup", setup );
988     var_SetAddress( mp, "amem-cleanup", cleanup );
989 }
990
991 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
992                               unsigned rate, unsigned channels )
993 {
994     var_SetString( mp, "amem-format", format );
995     var_SetInteger( mp, "amem-rate", rate );
996     var_SetInteger( mp, "amem-channels", channels );
997 }
998
999
1000 /**************************************************************************
1001  * Getters for stream information
1002  **************************************************************************/
1003 libvlc_time_t libvlc_media_player_get_length(
1004                              libvlc_media_player_t *p_mi )
1005 {
1006     input_thread_t *p_input_thread;
1007     libvlc_time_t i_time;
1008
1009     p_input_thread = libvlc_get_input_thread ( p_mi );
1010     if( !p_input_thread )
1011         return -1;
1012
1013     i_time = from_mtime(var_GetTime( p_input_thread, "length" ));
1014     vlc_object_release( p_input_thread );
1015
1016     return i_time;
1017 }
1018
1019 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1020 {
1021     input_thread_t *p_input_thread;
1022     libvlc_time_t i_time;
1023
1024     p_input_thread = libvlc_get_input_thread ( p_mi );
1025     if( !p_input_thread )
1026         return -1;
1027
1028     i_time = from_mtime(var_GetTime( p_input_thread , "time" ));
1029     vlc_object_release( p_input_thread );
1030     return i_time;
1031 }
1032
1033 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1034                                    libvlc_time_t i_time )
1035 {
1036     input_thread_t *p_input_thread;
1037
1038     p_input_thread = libvlc_get_input_thread ( p_mi );
1039     if( !p_input_thread )
1040         return;
1041
1042     var_SetTime( p_input_thread, "time", to_mtime(i_time) );
1043     vlc_object_release( p_input_thread );
1044 }
1045
1046 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1047                                        float position )
1048 {
1049     input_thread_t *p_input_thread;
1050
1051     p_input_thread = libvlc_get_input_thread ( p_mi );
1052     if( !p_input_thread )
1053         return;
1054
1055     var_SetFloat( p_input_thread, "position", position );
1056     vlc_object_release( p_input_thread );
1057 }
1058
1059 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1060 {
1061     input_thread_t *p_input_thread;
1062     float f_position;
1063
1064     p_input_thread = libvlc_get_input_thread ( p_mi );
1065     if( !p_input_thread )
1066         return -1.0;
1067
1068     f_position = var_GetFloat( p_input_thread, "position" );
1069     vlc_object_release( p_input_thread );
1070
1071     return f_position;
1072 }
1073
1074 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1075                                       int chapter )
1076 {
1077     input_thread_t *p_input_thread;
1078
1079     p_input_thread = libvlc_get_input_thread ( p_mi );
1080     if( !p_input_thread )
1081         return;
1082
1083     var_SetInteger( p_input_thread, "chapter", chapter );
1084     vlc_object_release( p_input_thread );
1085 }
1086
1087 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1088 {
1089     input_thread_t *p_input_thread;
1090     int i_chapter;
1091
1092     p_input_thread = libvlc_get_input_thread ( p_mi );
1093     if( !p_input_thread )
1094         return -1;
1095
1096     i_chapter = var_GetInteger( p_input_thread, "chapter" );
1097     vlc_object_release( p_input_thread );
1098
1099     return i_chapter;
1100 }
1101
1102 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1103 {
1104     input_thread_t *p_input_thread;
1105     vlc_value_t val;
1106
1107     p_input_thread = libvlc_get_input_thread ( p_mi );
1108     if( !p_input_thread )
1109         return -1;
1110
1111     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1112     vlc_object_release( p_input_thread );
1113
1114     return val.i_int;
1115 }
1116
1117 int libvlc_media_player_get_chapter_count_for_title(
1118                                  libvlc_media_player_t *p_mi,
1119                                  int i_title )
1120 {
1121     input_thread_t *p_input_thread;
1122     vlc_value_t val;
1123
1124     p_input_thread = libvlc_get_input_thread ( p_mi );
1125     if( !p_input_thread )
1126         return -1;
1127
1128     char *psz_name;
1129     if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
1130     {
1131         vlc_object_release( p_input_thread );
1132         return -1;
1133     }
1134     var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1135     vlc_object_release( p_input_thread );
1136     free( psz_name );
1137
1138     return val.i_int;
1139 }
1140
1141 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1142                                     int i_title )
1143 {
1144     input_thread_t *p_input_thread;
1145
1146     p_input_thread = libvlc_get_input_thread ( p_mi );
1147     if( !p_input_thread )
1148         return;
1149
1150     var_SetInteger( p_input_thread, "title", i_title );
1151     vlc_object_release( p_input_thread );
1152
1153     //send event
1154     libvlc_event_t event;
1155     event.type = libvlc_MediaPlayerTitleChanged;
1156     event.u.media_player_title_changed.new_title = i_title;
1157     libvlc_event_send( p_mi->p_event_manager, &event );
1158 }
1159
1160 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1161 {
1162     input_thread_t *p_input_thread;
1163     int i_title;
1164
1165     p_input_thread = libvlc_get_input_thread ( p_mi );
1166     if( !p_input_thread )
1167         return -1;
1168
1169     i_title = var_GetInteger( p_input_thread, "title" );
1170     vlc_object_release( p_input_thread );
1171
1172     return i_title;
1173 }
1174
1175 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1176 {
1177     input_thread_t *p_input_thread;
1178     vlc_value_t val;
1179
1180     p_input_thread = libvlc_get_input_thread ( p_mi );
1181     if( !p_input_thread )
1182         return -1;
1183
1184     var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1185     vlc_object_release( p_input_thread );
1186
1187     return val.i_int;
1188 }
1189
1190 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1191 {
1192     input_thread_t *p_input_thread;
1193
1194     p_input_thread = libvlc_get_input_thread ( p_mi );
1195     if( !p_input_thread )
1196         return;
1197
1198     int i_type = var_Type( p_input_thread, "next-chapter" );
1199     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1200                             "next-chapter":"next-title" );
1201
1202     vlc_object_release( p_input_thread );
1203 }
1204
1205 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1206 {
1207     input_thread_t *p_input_thread;
1208
1209     p_input_thread = libvlc_get_input_thread ( p_mi );
1210     if( !p_input_thread )
1211         return;
1212
1213     int i_type = var_Type( p_input_thread, "next-chapter" );
1214     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1215                             "prev-chapter":"prev-title" );
1216
1217     vlc_object_release( p_input_thread );
1218 }
1219
1220 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1221 {
1222     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1223     double f_fps = 0.0;
1224
1225     if( p_input_thread )
1226     {
1227         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
1228             f_fps = 0.0;
1229         vlc_object_release( p_input_thread );
1230     }
1231     return f_fps;
1232 }
1233
1234 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1235 {
1236     bool b_will_play;
1237     input_thread_t *p_input_thread =
1238                             libvlc_get_input_thread ( p_mi );
1239     if ( !p_input_thread )
1240         return false;
1241
1242     b_will_play = !p_input_thread->b_die && !p_input_thread->b_dead;
1243     vlc_object_release( p_input_thread );
1244
1245     return b_will_play;
1246 }
1247
1248 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1249 {
1250     if (rate < 0.)
1251     {
1252         libvlc_printerr ("Playing backward not supported");
1253         return -1;
1254     }
1255
1256     var_SetFloat (p_mi, "rate", rate);
1257
1258     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1259     if( !p_input_thread )
1260         return 0;
1261     var_SetFloat( p_input_thread, "rate", rate );
1262     vlc_object_release( p_input_thread );
1263     return 0;
1264 }
1265
1266 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1267 {
1268     return var_GetFloat (p_mi, "rate");
1269 }
1270
1271 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1272 {
1273     lock(p_mi);
1274     libvlc_state_t state = p_mi->state;
1275     unlock(p_mi);
1276     return state;
1277 }
1278
1279 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1280 {
1281     input_thread_t *p_input_thread;
1282     bool b_seekable;
1283
1284     p_input_thread = libvlc_get_input_thread ( p_mi );
1285     if ( !p_input_thread )
1286         return false;
1287     b_seekable = var_GetBool( p_input_thread, "can-seek" );
1288     vlc_object_release( p_input_thread );
1289
1290     return b_seekable;
1291 }
1292
1293 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1294                                    unsigned navigate )
1295 {
1296     input_thread_t *p_input_thread;
1297
1298     if ( navigate >= libvlc_navigate_to_action_size)
1299       return;
1300
1301     p_input_thread = libvlc_get_input_thread ( p_mi );
1302     if ( !p_input_thread )
1303       return;
1304
1305     var_SetInteger( p_mi->p_libvlc_instance->p_libvlc_int,
1306                     "key-action", libvlc_navigate_to_action[navigate] );
1307
1308     vlc_object_release( p_input_thread );
1309 }
1310
1311 /* internal function, used by audio, video */
1312 libvlc_track_description_t *
1313         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1314                                       const char *psz_variable )
1315 {
1316     input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1317     libvlc_track_description_t *p_track_description = NULL,
1318                                *p_actual, *p_previous;
1319
1320     if( !p_input )
1321         return NULL;
1322
1323     vlc_value_t val_list, text_list;
1324     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
1325
1326     /* no tracks */
1327     if( val_list.p_list->i_count <= 0 )
1328         goto end;
1329
1330     p_track_description = ( libvlc_track_description_t * )
1331         malloc( sizeof( libvlc_track_description_t ) );
1332     if ( !p_track_description )
1333     {
1334         libvlc_printerr( "Not enough memory" );
1335         goto end;
1336     }
1337     p_actual = p_track_description;
1338     p_previous = NULL;
1339     for( int i = 0; i < val_list.p_list->i_count; i++ )
1340     {
1341         if( !p_actual )
1342         {
1343             p_actual = ( libvlc_track_description_t * )
1344                 malloc( sizeof( libvlc_track_description_t ) );
1345             if ( !p_actual )
1346             {
1347                 libvlc_track_description_list_release( p_track_description );
1348                 libvlc_printerr( "Not enough memory" );
1349                 goto end;
1350             }
1351         }
1352         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1353         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1354         p_actual->p_next = NULL;
1355         if( p_previous )
1356             p_previous->p_next = p_actual;
1357         p_previous = p_actual;
1358         p_actual =  NULL;
1359     }
1360
1361 end:
1362     var_FreeList( &val_list, &text_list );
1363     vlc_object_release( p_input );
1364
1365     return p_track_description;
1366 }
1367
1368 // Deprecated alias for libvlc_track_description_list_release
1369 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1370 {
1371     libvlc_track_description_list_release( p_td );
1372 }
1373
1374 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1375 {
1376     libvlc_track_description_t *p_actual, *p_before;
1377     p_actual = p_td;
1378
1379     while ( p_actual )
1380     {
1381         free( p_actual->psz_name );
1382         p_before = p_actual;
1383         p_actual = p_before->p_next;
1384         free( p_before );
1385     }
1386 }
1387
1388 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1389 {
1390     input_thread_t *p_input_thread;
1391     bool b_can_pause;
1392
1393     p_input_thread = libvlc_get_input_thread ( p_mi );
1394     if ( !p_input_thread )
1395         return false;
1396     b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1397     vlc_object_release( p_input_thread );
1398
1399     return b_can_pause;
1400 }
1401
1402 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1403 {
1404     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1405     if( p_input_thread != NULL )
1406     {
1407         var_TriggerCallback( p_input_thread, "frame-next" );
1408         vlc_object_release( p_input_thread );
1409     }
1410 }