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