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