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