]> git.sesse.net Git - vlc/blob - lib/media_player.c
aout: remove old aout_(Volume|Mute)(Get|Set)() functions
[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 /* */
361 static void libvlc_media_player_destroy( libvlc_media_player_t * );
362
363
364 /**************************************************************************
365  * Create a Media Instance object.
366  *
367  * Refcount strategy:
368  * - All items created by _new start with a refcount set to 1.
369  * - Accessor _release decrease the refcount by 1, if after that
370  *   operation the refcount is 0, the object is destroyed.
371  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
372  *
373  * Object locking strategy:
374  * - No lock held while in constructor.
375  * - When accessing any member variable this lock is held. (XXX who locks?)
376  * - When attempting to destroy the object the lock is also held.
377  **************************************************************************/
378 libvlc_media_player_t *
379 libvlc_media_player_new( libvlc_instance_t *instance )
380 {
381     libvlc_media_player_t * mp;
382
383     assert(instance);
384
385     mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
386     if (unlikely(mp == NULL))
387     {
388         libvlc_printerr("Not enough memory");
389         return NULL;
390     }
391
392     /* Input */
393     var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
394
395     /* Video */
396     var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
397     var_Create (mp, "window", VLC_VAR_STRING);
398     var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
399     var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
400     var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
401     var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
402     var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
403     var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
404     var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
405     var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
406     var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
407     var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
408     var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
409 #if defined (WIN32) || defined (__OS2__)
410     var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
411 #endif
412 #ifdef __APPLE__
413     var_Create (mp, "drawable-agl", VLC_VAR_INTEGER);
414     var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
415 #endif
416
417     var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
418     var_SetBool (mp, "keyboard-events", true);
419     var_Create (mp, "mouse-events", VLC_VAR_BOOL);
420     var_SetBool (mp, "mouse-events", true);
421
422     var_Create (mp, "fullscreen", VLC_VAR_BOOL);
423     var_Create (mp, "autoscale", VLC_VAR_BOOL);
424     var_SetBool (mp, "autoscale", true);
425     var_Create (mp, "scale", VLC_VAR_FLOAT);
426     var_SetFloat (mp, "scale", 1.);
427     var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
428     var_Create (mp, "crop", VLC_VAR_STRING);
429     var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
430     var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
431
432     var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
433
434     var_Create (mp, "marq-marquee", VLC_VAR_STRING);
435     var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
436     var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
437     var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
438     var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
439     var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
440     var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
441     var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
442     var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
443
444     var_Create (mp, "logo-file", VLC_VAR_STRING);
445     var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
446     var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
447     var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
448     var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
449     var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
450     var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
451
452     var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
453     var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
454     var_Create (mp, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
455     var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
456     var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
457
458      /* Audio */
459     var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
460     var_Create (mp, "mute", VLC_VAR_BOOL);
461     var_Create (mp, "volume", VLC_VAR_FLOAT);
462     var_Create (mp, "corks", VLC_VAR_INTEGER);
463     var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
464     var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
465     var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
466     var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
467     var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
468     var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
469     var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
470     var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
471     var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
472     var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
473     var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
474     var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
475
476     mp->p_md = NULL;
477     mp->state = libvlc_NothingSpecial;
478     mp->p_libvlc_instance = instance;
479     mp->input.p_thread = NULL;
480     mp->input.p_resource = input_resource_New(VLC_OBJECT(mp));
481     if (unlikely(mp->input.p_resource == NULL))
482     {
483         vlc_object_release(mp);
484         return NULL;
485     }
486     vlc_mutex_init (&mp->input.lock);
487     mp->i_refcount = 1;
488     mp->p_event_manager = libvlc_event_manager_new(mp, instance);
489     if (unlikely(mp->p_event_manager == NULL))
490     {
491         input_resource_Release(mp->input.p_resource);
492         vlc_object_release(mp);
493         return NULL;
494     }
495     vlc_mutex_init(&mp->object_lock);
496
497     register_event(mp, NothingSpecial);
498     register_event(mp, Opening);
499     register_event(mp, Buffering);
500     register_event(mp, Playing);
501     register_event(mp, Paused);
502     register_event(mp, Stopped);
503     register_event(mp, Forward);
504     register_event(mp, Backward);
505     register_event(mp, EndReached);
506     register_event(mp, EncounteredError);
507     register_event(mp, SeekableChanged);
508
509     register_event(mp, PositionChanged);
510     register_event(mp, TimeChanged);
511     register_event(mp, LengthChanged);
512     register_event(mp, TitleChanged);
513     register_event(mp, PausableChanged);
514
515     register_event(mp, Vout);
516
517     /* Snapshot initialization */
518     register_event(mp, SnapshotTaken);
519
520     register_event(mp, MediaChanged);
521
522     /* Attach a var callback to the global object to provide the glue between
523      * vout_thread that generates the event and media_player that re-emits it
524      * with its own event manager
525      *
526      * FIXME: It's unclear why we want to put this in public API, and why we
527      * want to expose it in such a limiting and ugly way.
528      */
529     var_AddCallback(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp);
530
531     libvlc_retain(instance);
532     return mp;
533 }
534
535 /**************************************************************************
536  * Create a Media Instance object with a media descriptor.
537  **************************************************************************/
538 libvlc_media_player_t *
539 libvlc_media_player_new_from_media( libvlc_media_t * p_md )
540 {
541     libvlc_media_player_t * p_mi;
542
543     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
544     if( !p_mi )
545         return NULL;
546
547     libvlc_media_retain( p_md );
548     p_mi->p_md = p_md;
549
550     return p_mi;
551 }
552
553 /**************************************************************************
554  * Destroy a Media Instance object (libvlc internal)
555  *
556  * Warning: No lock held here, but hey, this is internal. Caller must lock.
557  **************************************************************************/
558 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
559 {
560     assert( p_mi );
561
562     /* Detach Callback from the main libvlc object */
563     var_DelCallback( p_mi->p_libvlc,
564                      "snapshot-file", snapshot_was_taken, p_mi );
565
566     /* No need for lock_input() because no other threads knows us anymore */
567     if( p_mi->input.p_thread )
568         release_input_thread(p_mi, true);
569     input_resource_Terminate( p_mi->input.p_resource );
570     input_resource_Release( p_mi->input.p_resource );
571     vlc_mutex_destroy( &p_mi->input.lock );
572
573     libvlc_event_manager_release( p_mi->p_event_manager );
574     libvlc_media_release( p_mi->p_md );
575     vlc_mutex_destroy( &p_mi->object_lock );
576
577     libvlc_instance_t *instance = p_mi->p_libvlc_instance;
578     vlc_object_release( p_mi );
579     libvlc_release(instance);
580 }
581
582 /**************************************************************************
583  * Release a Media Instance object.
584  *
585  * Function does the locking.
586  **************************************************************************/
587 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
588 {
589     bool destroy;
590
591     assert( p_mi );
592     lock(p_mi);
593     destroy = !--p_mi->i_refcount;
594     unlock(p_mi);
595
596     if( destroy )
597         libvlc_media_player_destroy( p_mi );
598 }
599
600 /**************************************************************************
601  * Retain a Media Instance object.
602  *
603  * Caller must hold the lock.
604  **************************************************************************/
605 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
606 {
607     assert( p_mi );
608
609     lock(p_mi);
610     p_mi->i_refcount++;
611     unlock(p_mi);
612 }
613
614 /**************************************************************************
615  * Set the Media descriptor associated with the instance.
616  *
617  * Enter without lock -- function will lock the object.
618  **************************************************************************/
619 void libvlc_media_player_set_media(
620                             libvlc_media_player_t *p_mi,
621                             libvlc_media_t *p_md )
622 {
623     lock_input(p_mi);
624
625     /* FIXME I am not sure if it is a user request or on die(eof/error)
626      * request here */
627     release_input_thread( p_mi,
628                           p_mi->input.p_thread &&
629                           !p_mi->input.p_thread->b_eof &&
630                           !p_mi->input.p_thread->b_error );
631
632     lock( p_mi );
633     set_state( p_mi, libvlc_NothingSpecial, true );
634     unlock_input( p_mi );
635
636     libvlc_media_release( p_mi->p_md );
637
638     if( !p_md )
639     {
640         p_mi->p_md = NULL;
641         unlock(p_mi);
642         return; /* It is ok to pass a NULL md */
643     }
644
645     libvlc_media_retain( p_md );
646     p_mi->p_md = p_md;
647
648     /* The policy here is to ignore that we were created using a different
649      * libvlc_instance, because we don't really care */
650     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
651
652     unlock(p_mi);
653
654     /* Send an event for the newly available media */
655     libvlc_event_t event;
656     event.type = libvlc_MediaPlayerMediaChanged;
657     event.u.media_player_media_changed.new_media = p_md;
658     libvlc_event_send( p_mi->p_event_manager, &event );
659
660 }
661
662 /**************************************************************************
663  * Get the Media descriptor associated with the instance.
664  **************************************************************************/
665 libvlc_media_t *
666 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
667 {
668     libvlc_media_t *p_m;
669
670     lock(p_mi);
671     p_m = p_mi->p_md;
672     if( p_m )
673         libvlc_media_retain( p_mi->p_md );
674     unlock(p_mi);
675     return p_mi->p_md;
676 }
677
678 /**************************************************************************
679  * Get the event Manager.
680  **************************************************************************/
681 libvlc_event_manager_t *
682 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
683 {
684     return p_mi->p_event_manager;
685 }
686
687 /**************************************************************************
688  * Tell media player to start playing.
689  **************************************************************************/
690 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
691 {
692     lock_input( p_mi );
693
694     input_thread_t *p_input_thread = p_mi->input.p_thread;
695     if( p_input_thread )
696     {
697         /* A thread already exists, send it a play message */
698         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
699         unlock_input( p_mi );
700         return 0;
701     }
702
703     /* Ignore previous exception */
704     lock(p_mi);
705
706     if( !p_mi->p_md )
707     {
708         unlock(p_mi);
709         unlock_input( p_mi );
710         libvlc_printerr( "No associated media descriptor" );
711         return -1;
712     }
713
714     p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
715                                    p_mi->input.p_resource );
716     unlock(p_mi);
717     if( !p_input_thread )
718     {
719         unlock_input(p_mi);
720         libvlc_printerr( "Not enough memory" );
721         return -1;
722     }
723
724     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
725     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
726     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
727
728     if( input_Start( p_input_thread ) )
729     {
730         unlock_input(p_mi);
731         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
732         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
733         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
734         vlc_object_release( p_input_thread );
735         libvlc_printerr( "Input initialization failure" );
736         return -1;
737     }
738     p_mi->input.p_thread = p_input_thread;
739     unlock_input(p_mi);
740     return 0;
741 }
742
743 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
744 {
745     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
746     if( !p_input_thread )
747         return;
748
749     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
750     if( state == libvlc_Playing || state == libvlc_Buffering )
751     {
752         if( paused )
753         {
754             if( libvlc_media_player_can_pause( p_mi ) )
755                 input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
756             else
757                 libvlc_media_player_stop( p_mi );
758         }
759     }
760     else
761     {
762         if( !paused )
763             input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
764     }
765
766     vlc_object_release( p_input_thread );
767 }
768
769 /**************************************************************************
770  * Toggle pause.
771  **************************************************************************/
772 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
773 {
774     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
775     bool playing = (state == libvlc_Playing || state == libvlc_Buffering);
776
777     libvlc_media_player_set_pause( p_mi, playing );
778 }
779
780 /**************************************************************************
781  * Tells whether the media player is currently playing.
782  *
783  * Enter with lock held.
784  **************************************************************************/
785 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
786 {
787     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
788     return (libvlc_Playing == state) || (libvlc_Buffering == state);
789 }
790
791 /**************************************************************************
792  * Stop playing.
793  **************************************************************************/
794 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
795 {
796     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
797
798     lock_input(p_mi);
799     release_input_thread( p_mi, true ); /* This will stop the input thread */
800
801     /* Force to go to stopped state, in case we were in Ended, or Error
802      * state. */
803     if( state != libvlc_Stopped )
804     {
805         set_state( p_mi, libvlc_Stopped, false );
806
807         /* Construct and send the event */
808         libvlc_event_t event;
809         event.type = libvlc_MediaPlayerStopped;
810         libvlc_event_send( p_mi->p_event_manager, &event );
811     }
812
813     input_resource_Terminate( p_mi->input.p_resource );
814     unlock_input(p_mi);
815 }
816
817
818 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
819     void *(*lock_cb) (void *, void **),
820     void (*unlock_cb) (void *, void *, void *const *),
821     void (*display_cb) (void *, void *),
822     void *opaque )
823 {
824     var_SetAddress( mp, "vmem-lock", lock_cb );
825     var_SetAddress( mp, "vmem-unlock", unlock_cb );
826     var_SetAddress( mp, "vmem-display", display_cb );
827     var_SetAddress( mp, "vmem-data", opaque );
828     var_SetString( mp, "vout", "vmem" );
829 }
830
831 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
832                                         libvlc_video_format_cb setup,
833                                         libvlc_video_cleanup_cb cleanup )
834 {
835     var_SetAddress( mp, "vmem-setup", setup );
836     var_SetAddress( mp, "vmem-cleanup", cleanup );
837 }
838
839 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
840                               unsigned width, unsigned height, unsigned pitch )
841 {
842     var_SetString( mp, "vmem-chroma", chroma );
843     var_SetInteger( mp, "vmem-width", width );
844     var_SetInteger( mp, "vmem-height", height );
845     var_SetInteger( mp, "vmem-pitch", pitch );
846 }
847
848 /**************************************************************************
849  * set_nsobject
850  **************************************************************************/
851 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
852                                         void * drawable )
853 {
854     assert (p_mi != NULL);
855 #ifdef __APPLE__
856     var_SetAddress (p_mi, "drawable-nsobject", drawable);
857 #else
858     (void) p_mi; (void)drawable;
859 #endif
860 }
861
862 /**************************************************************************
863  * get_nsobject
864  **************************************************************************/
865 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
866 {
867     assert (p_mi != NULL);
868 #ifdef __APPLE__
869     return var_GetAddress (p_mi, "drawable-nsobject");
870 #else
871     return NULL;
872 #endif
873 }
874
875 /**************************************************************************
876  * set_agl
877  **************************************************************************/
878 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
879                                   uint32_t drawable )
880 {
881 #ifdef __APPLE__
882     var_SetInteger (p_mi, "drawable-agl", drawable);
883 #else
884     (void) p_mi; (void)drawable;
885 #endif
886 }
887
888 /**************************************************************************
889  * get_agl
890  **************************************************************************/
891 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
892 {
893     assert (p_mi != NULL);
894 #ifdef __APPLE__
895     return var_GetInteger (p_mi, "drawable-agl");
896 #else
897     return 0;
898 #endif
899 }
900
901 /**************************************************************************
902  * set_xwindow
903  **************************************************************************/
904 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
905                                       uint32_t drawable )
906 {
907     assert (p_mi != NULL);
908
909     var_SetString (p_mi, "vout", drawable ? "xid" : "any");
910     var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "any");
911     var_SetInteger (p_mi, "drawable-xid", drawable);
912 }
913
914 /**************************************************************************
915  * get_xwindow
916  **************************************************************************/
917 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
918 {
919     return var_GetInteger (p_mi, "drawable-xid");
920 }
921
922 /**************************************************************************
923  * set_hwnd
924  **************************************************************************/
925 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
926                                    void *drawable )
927 {
928     assert (p_mi != NULL);
929 #if defined (WIN32) || defined (__OS2__)
930     var_SetString (p_mi, "window",
931                    (drawable != NULL) ? "embed-hwnd,any" : "");
932     var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
933 #else
934     (void) p_mi; (void) drawable;
935 #endif
936 }
937
938 /**************************************************************************
939  * get_hwnd
940  **************************************************************************/
941 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
942 {
943     assert (p_mi != NULL);
944 #if defined (WIN32) || defined (__OS2__)
945     return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
946 #else
947     return NULL;
948 #endif
949 }
950
951 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
952                                  libvlc_audio_play_cb play_cb,
953                                  libvlc_audio_pause_cb pause_cb,
954                                  libvlc_audio_resume_cb resume_cb,
955                                  libvlc_audio_flush_cb flush_cb,
956                                  libvlc_audio_drain_cb drain_cb,
957                                  void *opaque )
958 {
959     var_SetAddress( mp, "amem-play", play_cb );
960     var_SetAddress( mp, "amem-pause", pause_cb );
961     var_SetAddress( mp, "amem-resume", resume_cb );
962     var_SetAddress( mp, "amem-flush", flush_cb );
963     var_SetAddress( mp, "amem-drain", drain_cb );
964     var_SetAddress( mp, "amem-data", opaque );
965     var_SetString( mp, "aout", "amem,none" );
966 }
967
968 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
969                                        libvlc_audio_set_volume_cb cb )
970 {
971     var_SetAddress( mp, "amem-set-volume", cb );
972 }
973
974 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
975                                         libvlc_audio_setup_cb setup,
976                                         libvlc_audio_cleanup_cb cleanup )
977 {
978     var_SetAddress( mp, "amem-setup", setup );
979     var_SetAddress( mp, "amem-cleanup", cleanup );
980 }
981
982 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
983                               unsigned rate, unsigned channels )
984 {
985     var_SetString( mp, "amem-format", format );
986     var_SetInteger( mp, "amem-rate", rate );
987     var_SetInteger( mp, "amem-channels", channels );
988 }
989
990
991 /**************************************************************************
992  * Getters for stream information
993  **************************************************************************/
994 libvlc_time_t libvlc_media_player_get_length(
995                              libvlc_media_player_t *p_mi )
996 {
997     input_thread_t *p_input_thread;
998     libvlc_time_t i_time;
999
1000     p_input_thread = libvlc_get_input_thread ( p_mi );
1001     if( !p_input_thread )
1002         return -1;
1003
1004     i_time = from_mtime(var_GetTime( p_input_thread, "length" ));
1005     vlc_object_release( p_input_thread );
1006
1007     return i_time;
1008 }
1009
1010 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1011 {
1012     input_thread_t *p_input_thread;
1013     libvlc_time_t i_time;
1014
1015     p_input_thread = libvlc_get_input_thread ( p_mi );
1016     if( !p_input_thread )
1017         return -1;
1018
1019     i_time = from_mtime(var_GetTime( p_input_thread , "time" ));
1020     vlc_object_release( p_input_thread );
1021     return i_time;
1022 }
1023
1024 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1025                                    libvlc_time_t i_time )
1026 {
1027     input_thread_t *p_input_thread;
1028
1029     p_input_thread = libvlc_get_input_thread ( p_mi );
1030     if( !p_input_thread )
1031         return;
1032
1033     var_SetTime( p_input_thread, "time", to_mtime(i_time) );
1034     vlc_object_release( p_input_thread );
1035 }
1036
1037 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1038                                        float position )
1039 {
1040     input_thread_t *p_input_thread;
1041
1042     p_input_thread = libvlc_get_input_thread ( p_mi );
1043     if( !p_input_thread )
1044         return;
1045
1046     var_SetFloat( p_input_thread, "position", position );
1047     vlc_object_release( p_input_thread );
1048 }
1049
1050 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1051 {
1052     input_thread_t *p_input_thread;
1053     float f_position;
1054
1055     p_input_thread = libvlc_get_input_thread ( p_mi );
1056     if( !p_input_thread )
1057         return -1.0;
1058
1059     f_position = var_GetFloat( p_input_thread, "position" );
1060     vlc_object_release( p_input_thread );
1061
1062     return f_position;
1063 }
1064
1065 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1066                                       int chapter )
1067 {
1068     input_thread_t *p_input_thread;
1069
1070     p_input_thread = libvlc_get_input_thread ( p_mi );
1071     if( !p_input_thread )
1072         return;
1073
1074     var_SetInteger( p_input_thread, "chapter", chapter );
1075     vlc_object_release( p_input_thread );
1076 }
1077
1078 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1079 {
1080     input_thread_t *p_input_thread;
1081     int i_chapter;
1082
1083     p_input_thread = libvlc_get_input_thread ( p_mi );
1084     if( !p_input_thread )
1085         return -1;
1086
1087     i_chapter = var_GetInteger( p_input_thread, "chapter" );
1088     vlc_object_release( p_input_thread );
1089
1090     return i_chapter;
1091 }
1092
1093 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1094 {
1095     input_thread_t *p_input_thread;
1096     vlc_value_t val;
1097
1098     p_input_thread = libvlc_get_input_thread ( p_mi );
1099     if( !p_input_thread )
1100         return -1;
1101
1102     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1103     vlc_object_release( p_input_thread );
1104
1105     return val.i_int;
1106 }
1107
1108 int libvlc_media_player_get_chapter_count_for_title(
1109                                  libvlc_media_player_t *p_mi,
1110                                  int i_title )
1111 {
1112     input_thread_t *p_input_thread;
1113     vlc_value_t val;
1114
1115     p_input_thread = libvlc_get_input_thread ( p_mi );
1116     if( !p_input_thread )
1117         return -1;
1118
1119     char *psz_name;
1120     if( asprintf( &psz_name,  "title %2i", i_title ) == -1 )
1121     {
1122         vlc_object_release( p_input_thread );
1123         return -1;
1124     }
1125     var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1126     vlc_object_release( p_input_thread );
1127     free( psz_name );
1128
1129     return val.i_int;
1130 }
1131
1132 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1133                                     int i_title )
1134 {
1135     input_thread_t *p_input_thread;
1136
1137     p_input_thread = libvlc_get_input_thread ( p_mi );
1138     if( !p_input_thread )
1139         return;
1140
1141     var_SetInteger( p_input_thread, "title", i_title );
1142     vlc_object_release( p_input_thread );
1143
1144     //send event
1145     libvlc_event_t event;
1146     event.type = libvlc_MediaPlayerTitleChanged;
1147     event.u.media_player_title_changed.new_title = i_title;
1148     libvlc_event_send( p_mi->p_event_manager, &event );
1149 }
1150
1151 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1152 {
1153     input_thread_t *p_input_thread;
1154     int i_title;
1155
1156     p_input_thread = libvlc_get_input_thread ( p_mi );
1157     if( !p_input_thread )
1158         return -1;
1159
1160     i_title = var_GetInteger( p_input_thread, "title" );
1161     vlc_object_release( p_input_thread );
1162
1163     return i_title;
1164 }
1165
1166 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1167 {
1168     input_thread_t *p_input_thread;
1169     vlc_value_t val;
1170
1171     p_input_thread = libvlc_get_input_thread ( p_mi );
1172     if( !p_input_thread )
1173         return -1;
1174
1175     var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1176     vlc_object_release( p_input_thread );
1177
1178     return val.i_int;
1179 }
1180
1181 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1182 {
1183     input_thread_t *p_input_thread;
1184
1185     p_input_thread = libvlc_get_input_thread ( p_mi );
1186     if( !p_input_thread )
1187         return;
1188
1189     int i_type = var_Type( p_input_thread, "next-chapter" );
1190     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1191                             "next-chapter":"next-title" );
1192
1193     vlc_object_release( p_input_thread );
1194 }
1195
1196 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1197 {
1198     input_thread_t *p_input_thread;
1199
1200     p_input_thread = libvlc_get_input_thread ( p_mi );
1201     if( !p_input_thread )
1202         return;
1203
1204     int i_type = var_Type( p_input_thread, "next-chapter" );
1205     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1206                             "prev-chapter":"prev-title" );
1207
1208     vlc_object_release( p_input_thread );
1209 }
1210
1211 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1212 {
1213     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1214     double f_fps = 0.0;
1215
1216     if( p_input_thread )
1217     {
1218         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
1219             f_fps = 0.0;
1220         vlc_object_release( p_input_thread );
1221     }
1222     return f_fps;
1223 }
1224
1225 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1226 {
1227     bool b_will_play;
1228     input_thread_t *p_input_thread =
1229                             libvlc_get_input_thread ( p_mi );
1230     if ( !p_input_thread )
1231         return false;
1232
1233     b_will_play = !p_input_thread->b_die && !p_input_thread->b_dead;
1234     vlc_object_release( p_input_thread );
1235
1236     return b_will_play;
1237 }
1238
1239 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1240 {
1241     if (rate < 0.)
1242     {
1243         libvlc_printerr ("Playing backward not supported");
1244         return -1;
1245     }
1246
1247     var_SetFloat (p_mi, "rate", rate);
1248
1249     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1250     if( !p_input_thread )
1251         return 0;
1252     var_SetFloat( p_input_thread, "rate", rate );
1253     vlc_object_release( p_input_thread );
1254     return 0;
1255 }
1256
1257 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1258 {
1259     return var_GetFloat (p_mi, "rate");
1260 }
1261
1262 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1263 {
1264     lock(p_mi);
1265     libvlc_state_t state = p_mi->state;
1266     unlock(p_mi);
1267     return state;
1268 }
1269
1270 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1271 {
1272     input_thread_t *p_input_thread;
1273     bool b_seekable;
1274
1275     p_input_thread = libvlc_get_input_thread ( p_mi );
1276     if ( !p_input_thread )
1277         return false;
1278     b_seekable = var_GetBool( p_input_thread, "can-seek" );
1279     vlc_object_release( p_input_thread );
1280
1281     return b_seekable;
1282 }
1283
1284 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1285                                    unsigned navigate )
1286 {
1287     input_thread_t *p_input_thread;
1288
1289     if ( navigate >= libvlc_navigate_to_action_size)
1290       return;
1291
1292     p_input_thread = libvlc_get_input_thread ( p_mi );
1293     if ( !p_input_thread )
1294       return;
1295
1296     var_SetInteger( p_mi->p_libvlc_instance->p_libvlc_int,
1297                     "key-action", libvlc_navigate_to_action[navigate] );
1298
1299     vlc_object_release( p_input_thread );
1300 }
1301
1302 /* internal function, used by audio, video */
1303 libvlc_track_description_t *
1304         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1305                                       const char *psz_variable )
1306 {
1307     input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1308     libvlc_track_description_t *p_track_description = NULL,
1309                                *p_actual, *p_previous;
1310
1311     if( !p_input )
1312         return NULL;
1313
1314     vlc_value_t val_list, text_list;
1315     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
1316
1317     /* no tracks */
1318     if( val_list.p_list->i_count <= 0 )
1319         goto end;
1320
1321     p_track_description = ( libvlc_track_description_t * )
1322         malloc( sizeof( libvlc_track_description_t ) );
1323     if ( !p_track_description )
1324     {
1325         libvlc_printerr( "Not enough memory" );
1326         goto end;
1327     }
1328     p_actual = p_track_description;
1329     p_previous = NULL;
1330     for( int i = 0; i < val_list.p_list->i_count; i++ )
1331     {
1332         if( !p_actual )
1333         {
1334             p_actual = ( libvlc_track_description_t * )
1335                 malloc( sizeof( libvlc_track_description_t ) );
1336             if ( !p_actual )
1337             {
1338                 libvlc_track_description_list_release( p_track_description );
1339                 libvlc_printerr( "Not enough memory" );
1340                 goto end;
1341             }
1342         }
1343         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1344         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1345         p_actual->p_next = NULL;
1346         if( p_previous )
1347             p_previous->p_next = p_actual;
1348         p_previous = p_actual;
1349         p_actual =  NULL;
1350     }
1351
1352 end:
1353     var_FreeList( &val_list, &text_list );
1354     vlc_object_release( p_input );
1355
1356     return p_track_description;
1357 }
1358
1359 // Deprecated alias for libvlc_track_description_list_release
1360 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1361 {
1362     libvlc_track_description_list_release( p_td );
1363 }
1364
1365 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1366 {
1367     libvlc_track_description_t *p_actual, *p_before;
1368     p_actual = p_td;
1369
1370     while ( p_actual )
1371     {
1372         free( p_actual->psz_name );
1373         p_before = p_actual;
1374         p_actual = p_before->p_next;
1375         free( p_before );
1376     }
1377 }
1378
1379 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1380 {
1381     input_thread_t *p_input_thread;
1382     bool b_can_pause;
1383
1384     p_input_thread = libvlc_get_input_thread ( p_mi );
1385     if ( !p_input_thread )
1386         return false;
1387     b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1388     vlc_object_release( p_input_thread );
1389
1390     return b_can_pause;
1391 }
1392
1393 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1394 {
1395     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1396     if( p_input_thread != NULL )
1397     {
1398         var_TriggerCallback( p_input_thread, "frame-next" );
1399         vlc_object_release( p_input_thread );
1400     }
1401 }