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