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