1 /*****************************************************************************
2 * media_player.c: Libvlc API Media Instance management functions
3 *****************************************************************************
4 * Copyright (C) 2005-2011 VLC authors and VideoLAN
6 * Authors: Clément Stenac <zorglub@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_events.h>
33 #include <vlc_demux.h>
34 #include <vlc_input.h>
38 #include "libvlc_internal.h"
39 #include "media_internal.h" // libvlc_media_set_state()
40 #include "media_player_internal.h"
43 * mapping of libvlc_navigate_mode_t to vlc_action_t
45 static const vlc_action_t libvlc_navigate_to_action[] =
47 ACTIONID_NAV_ACTIVATE,
54 static const uint32_t libvlc_navigate_to_action_size = \
55 sizeof( libvlc_navigate_to_action ) / sizeof( libvlc_navigate_to_action[0] );
59 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
60 vlc_value_t oldval, vlc_value_t newval,
63 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
64 vlc_value_t oldval, vlc_value_t newval,
67 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
68 vlc_value_t oldval, vlc_value_t newval,
72 snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
73 vlc_value_t oldval, vlc_value_t newval, void *p_data );
75 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
81 #define register_event(a, b) __register_event(a, libvlc_MediaPlayer ## b)
82 static inline void __register_event(libvlc_media_player_t *mp, libvlc_event_type_t type)
84 libvlc_event_manager_register_event_type(mp->p_event_manager, type);
88 * The input lock protects the input and input resource pointer.
89 * It MUST NOT be used from callbacks.
91 * The object lock protects the reset, namely the media and the player state.
92 * It can, and usually needs to be taken from callbacks.
93 * The object lock can be acquired under the input lock... and consequently
94 * the opposite order is STRICTLY PROHIBITED.
96 static inline void lock(libvlc_media_player_t *mp)
98 vlc_mutex_lock(&mp->object_lock);
101 static inline void unlock(libvlc_media_player_t *mp)
103 vlc_mutex_unlock(&mp->object_lock);
106 static inline void lock_input(libvlc_media_player_t *mp)
108 vlc_mutex_lock(&mp->input.lock);
111 static inline void unlock_input(libvlc_media_player_t *mp)
113 vlc_mutex_unlock(&mp->input.lock);
117 * Release the associated input thread.
119 * Object lock is NOT held.
120 * Input lock is held or instance is being destroyed.
122 static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
126 input_thread_t *p_input_thread = p_mi->input.p_thread;
127 if( !p_input_thread )
129 p_mi->input.p_thread = NULL;
131 var_DelCallback( p_input_thread, "can-seek",
132 input_seekable_changed, p_mi );
133 var_DelCallback( p_input_thread, "can-pause",
134 input_pausable_changed, p_mi );
135 var_DelCallback( p_input_thread, "intf-event",
136 input_event_changed, p_mi );
138 /* We owned this one */
139 input_Stop( p_input_thread, b_input_abort );
140 input_Close( p_input_thread );
144 * Retrieve the input thread. Be sure to release the object
145 * once you are done with it. (libvlc Internal)
147 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi )
149 input_thread_t *p_input_thread;
154 p_input_thread = p_mi->input.p_thread;
156 vlc_object_hold( p_input_thread );
158 libvlc_printerr( "No active input" );
161 return p_input_thread;
165 * Set the internal state of the media_player. (media player Internal)
167 * Function will lock the media_player.
169 static void set_state( libvlc_media_player_t *p_mi, libvlc_state_t state,
176 libvlc_media_t *media = p_mi->p_md;
178 libvlc_media_retain(media);
185 // Also set the state of the corresponding media
186 // This is strictly for convenience.
187 libvlc_media_set_state(media, state);
189 libvlc_media_release(media);
194 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
195 vlc_value_t oldval, vlc_value_t newval,
201 libvlc_media_player_t * p_mi = p_userdata;
202 libvlc_event_t event;
204 event.type = libvlc_MediaPlayerSeekableChanged;
205 event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
207 libvlc_event_send( p_mi->p_event_manager, &event );
212 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
213 vlc_value_t oldval, vlc_value_t newval,
219 libvlc_media_player_t * p_mi = p_userdata;
220 libvlc_event_t event;
222 event.type = libvlc_MediaPlayerPausableChanged;
223 event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
225 libvlc_event_send( p_mi->p_event_manager, &event );
230 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
231 vlc_value_t oldval, vlc_value_t newval,
235 input_thread_t * p_input = (input_thread_t *)p_this;
236 libvlc_media_player_t * p_mi = p_userdata;
237 libvlc_event_t event;
239 assert( !strcmp( psz_cmd, "intf-event" ) );
241 if( newval.i_int == INPUT_EVENT_STATE )
243 libvlc_state_t libvlc_state;
245 switch ( var_GetInteger( p_input, "state" ) )
248 libvlc_state = libvlc_NothingSpecial;
249 event.type = libvlc_MediaPlayerNothingSpecial;
252 libvlc_state = libvlc_Opening;
253 event.type = libvlc_MediaPlayerOpening;
256 libvlc_state = libvlc_Playing;
257 event.type = libvlc_MediaPlayerPlaying;
260 libvlc_state = libvlc_Paused;
261 event.type = libvlc_MediaPlayerPaused;
264 libvlc_state = libvlc_Ended;
265 event.type = libvlc_MediaPlayerEndReached;
268 libvlc_state = libvlc_Error;
269 event.type = libvlc_MediaPlayerEncounteredError;
276 set_state( p_mi, libvlc_state, false );
277 libvlc_event_send( p_mi->p_event_manager, &event );
279 else if( newval.i_int == INPUT_EVENT_ABORT )
281 libvlc_state_t libvlc_state = libvlc_Stopped;
282 event.type = libvlc_MediaPlayerStopped;
284 set_state( p_mi, libvlc_state, false );
285 libvlc_event_send( p_mi->p_event_manager, &event );
287 else if( newval.i_int == INPUT_EVENT_POSITION )
289 if( var_GetInteger( p_input, "state" ) != PLAYING_S )
290 return VLC_SUCCESS; /* Don't send the position while stopped */
293 event.type = libvlc_MediaPlayerPositionChanged;
294 event.u.media_player_position_changed.new_position =
295 var_GetFloat( p_input, "position" );
296 libvlc_event_send( p_mi->p_event_manager, &event );
299 event.type = libvlc_MediaPlayerTimeChanged;
300 event.u.media_player_time_changed.new_time =
301 from_mtime(var_GetTime( p_input, "time" ));
302 libvlc_event_send( p_mi->p_event_manager, &event );
304 else if( newval.i_int == INPUT_EVENT_LENGTH )
306 event.type = libvlc_MediaPlayerLengthChanged;
307 event.u.media_player_length_changed.new_length =
308 from_mtime(var_GetTime( p_input, "length" ));
309 libvlc_event_send( p_mi->p_event_manager, &event );
311 else if( newval.i_int == INPUT_EVENT_CACHE )
313 event.type = libvlc_MediaPlayerBuffering;
314 event.u.media_player_buffering.new_cache = (int)(100 *
315 var_GetFloat( p_input, "cache" ));
316 libvlc_event_send( p_mi->p_event_manager, &event );
318 else if( newval.i_int == INPUT_EVENT_VOUT )
320 vout_thread_t **pp_vout;
322 if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
328 for( size_t i = 0; i < i_vout; i++ )
329 vlc_object_release( pp_vout[i] );
333 event.type = libvlc_MediaPlayerVout;
334 event.u.media_player_vout.new_count = i_vout;
335 libvlc_event_send( p_mi->p_event_manager, &event );
341 /**************************************************************************
342 * Snapshot Taken Event.
344 * FIXME: This snapshot API interface makes no sense in media_player.
345 *************************************************************************/
346 static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
347 vlc_value_t oldval, vlc_value_t newval, void *p_data )
349 VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);
351 libvlc_media_player_t *mp = p_data;
352 libvlc_event_t event;
353 event.type = libvlc_MediaPlayerSnapshotTaken;
354 event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
355 libvlc_event_send(mp->p_event_manager, &event);
361 static void libvlc_media_player_destroy( libvlc_media_player_t * );
364 /**************************************************************************
365 * Create a Media Instance object.
368 * - All items created by _new start with a refcount set to 1.
369 * - Accessor _release decrease the refcount by 1, if after that
370 * operation the refcount is 0, the object is destroyed.
371 * - Accessor _retain increase the refcount by 1 (XXX: to implement)
373 * Object locking strategy:
374 * - No lock held while in constructor.
375 * - When accessing any member variable this lock is held. (XXX who locks?)
376 * - When attempting to destroy the object the lock is also held.
377 **************************************************************************/
378 libvlc_media_player_t *
379 libvlc_media_player_new( libvlc_instance_t *instance )
381 libvlc_media_player_t * mp;
385 mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
386 if (unlikely(mp == NULL))
388 libvlc_printerr("Not enough memory");
393 var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
396 var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
397 var_Create (mp, "window", VLC_VAR_STRING);
398 var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
399 var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
400 var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
401 var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
402 var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
403 var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
404 var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
405 var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
406 var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
407 var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
408 var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
409 #if defined (WIN32) || defined (__OS2__)
410 var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
413 var_Create (mp, "drawable-agl", VLC_VAR_INTEGER);
414 var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
417 var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
418 var_SetBool (mp, "keyboard-events", true);
419 var_Create (mp, "mouse-events", VLC_VAR_BOOL);
420 var_SetBool (mp, "mouse-events", true);
422 var_Create (mp, "fullscreen", VLC_VAR_BOOL);
423 var_Create (mp, "autoscale", VLC_VAR_BOOL);
424 var_SetBool (mp, "autoscale", true);
425 var_Create (mp, "scale", VLC_VAR_FLOAT);
426 var_SetFloat (mp, "scale", 1.);
427 var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
428 var_Create (mp, "crop", VLC_VAR_STRING);
429 var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
430 var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
432 var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
434 var_Create (mp, "marq-marquee", VLC_VAR_STRING);
435 var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
436 var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
437 var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
438 var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
439 var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
440 var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
441 var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
442 var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
444 var_Create (mp, "logo-file", VLC_VAR_STRING);
445 var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
446 var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
447 var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
448 var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
449 var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
450 var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
452 var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
453 var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
454 var_Create (mp, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
455 var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
456 var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
459 var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
460 var_Create (mp, "mute", VLC_VAR_BOOL);
461 var_Create (mp, "volume", VLC_VAR_FLOAT);
462 var_Create (mp, "corks", VLC_VAR_INTEGER);
463 var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
464 var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
465 var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
466 var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
467 var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
468 var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
469 var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
470 var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
471 var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
472 var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
473 var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
474 var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
477 mp->state = libvlc_NothingSpecial;
478 mp->p_libvlc_instance = instance;
479 mp->input.p_thread = NULL;
480 mp->input.p_resource = input_resource_New(VLC_OBJECT(mp));
481 if (unlikely(mp->input.p_resource == NULL))
483 vlc_object_release(mp);
486 vlc_mutex_init (&mp->input.lock);
488 mp->p_event_manager = libvlc_event_manager_new(mp, instance);
489 if (unlikely(mp->p_event_manager == NULL))
491 input_resource_Release(mp->input.p_resource);
492 vlc_object_release(mp);
495 vlc_mutex_init(&mp->object_lock);
497 register_event(mp, NothingSpecial);
498 register_event(mp, Opening);
499 register_event(mp, Buffering);
500 register_event(mp, Playing);
501 register_event(mp, Paused);
502 register_event(mp, Stopped);
503 register_event(mp, Forward);
504 register_event(mp, Backward);
505 register_event(mp, EndReached);
506 register_event(mp, EncounteredError);
507 register_event(mp, SeekableChanged);
509 register_event(mp, PositionChanged);
510 register_event(mp, TimeChanged);
511 register_event(mp, LengthChanged);
512 register_event(mp, TitleChanged);
513 register_event(mp, PausableChanged);
515 register_event(mp, Vout);
517 /* Snapshot initialization */
518 register_event(mp, SnapshotTaken);
520 register_event(mp, MediaChanged);
522 /* Attach a var callback to the global object to provide the glue between
523 * vout_thread that generates the event and media_player that re-emits it
524 * with its own event manager
526 * FIXME: It's unclear why we want to put this in public API, and why we
527 * want to expose it in such a limiting and ugly way.
529 var_AddCallback(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp);
531 libvlc_retain(instance);
535 /**************************************************************************
536 * Create a Media Instance object with a media descriptor.
537 **************************************************************************/
538 libvlc_media_player_t *
539 libvlc_media_player_new_from_media( libvlc_media_t * p_md )
541 libvlc_media_player_t * p_mi;
543 p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
547 libvlc_media_retain( p_md );
553 /**************************************************************************
554 * Destroy a Media Instance object (libvlc internal)
556 * Warning: No lock held here, but hey, this is internal. Caller must lock.
557 **************************************************************************/
558 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
562 /* Detach Callback from the main libvlc object */
563 var_DelCallback( p_mi->p_libvlc,
564 "snapshot-file", snapshot_was_taken, p_mi );
566 /* No need for lock_input() because no other threads knows us anymore */
567 if( p_mi->input.p_thread )
568 release_input_thread(p_mi, true);
569 input_resource_Terminate( p_mi->input.p_resource );
570 input_resource_Release( p_mi->input.p_resource );
571 vlc_mutex_destroy( &p_mi->input.lock );
573 libvlc_event_manager_release( p_mi->p_event_manager );
574 libvlc_media_release( p_mi->p_md );
575 vlc_mutex_destroy( &p_mi->object_lock );
577 libvlc_instance_t *instance = p_mi->p_libvlc_instance;
578 vlc_object_release( p_mi );
579 libvlc_release(instance);
582 /**************************************************************************
583 * Release a Media Instance object.
585 * Function does the locking.
586 **************************************************************************/
587 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
593 destroy = !--p_mi->i_refcount;
597 libvlc_media_player_destroy( p_mi );
600 /**************************************************************************
601 * Retain a Media Instance object.
603 * Caller must hold the lock.
604 **************************************************************************/
605 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
614 /**************************************************************************
615 * Set the Media descriptor associated with the instance.
617 * Enter without lock -- function will lock the object.
618 **************************************************************************/
619 void libvlc_media_player_set_media(
620 libvlc_media_player_t *p_mi,
621 libvlc_media_t *p_md )
625 /* FIXME I am not sure if it is a user request or on die(eof/error)
627 release_input_thread( p_mi,
628 p_mi->input.p_thread &&
629 !p_mi->input.p_thread->b_eof &&
630 !p_mi->input.p_thread->b_error );
633 set_state( p_mi, libvlc_NothingSpecial, true );
634 unlock_input( p_mi );
636 libvlc_media_release( p_mi->p_md );
642 return; /* It is ok to pass a NULL md */
645 libvlc_media_retain( p_md );
648 /* The policy here is to ignore that we were created using a different
649 * libvlc_instance, because we don't really care */
650 p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
654 /* Send an event for the newly available media */
655 libvlc_event_t event;
656 event.type = libvlc_MediaPlayerMediaChanged;
657 event.u.media_player_media_changed.new_media = p_md;
658 libvlc_event_send( p_mi->p_event_manager, &event );
662 /**************************************************************************
663 * Get the Media descriptor associated with the instance.
664 **************************************************************************/
666 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
673 libvlc_media_retain( p_mi->p_md );
678 /**************************************************************************
679 * Get the event Manager.
680 **************************************************************************/
681 libvlc_event_manager_t *
682 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
684 return p_mi->p_event_manager;
687 /**************************************************************************
688 * Tell media player to start playing.
689 **************************************************************************/
690 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
694 input_thread_t *p_input_thread = p_mi->input.p_thread;
697 /* A thread already exists, send it a play message */
698 input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
699 unlock_input( p_mi );
703 /* Ignore previous exception */
709 unlock_input( p_mi );
710 libvlc_printerr( "No associated media descriptor" );
714 p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
715 p_mi->input.p_resource );
717 if( !p_input_thread )
720 libvlc_printerr( "Not enough memory" );
724 var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
725 var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
726 var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
728 if( input_Start( p_input_thread ) )
731 var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
732 var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
733 var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
734 vlc_object_release( p_input_thread );
735 libvlc_printerr( "Input initialization failure" );
738 p_mi->input.p_thread = p_input_thread;
743 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
745 input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
746 if( !p_input_thread )
749 libvlc_state_t state = libvlc_media_player_get_state( p_mi );
750 if( state == libvlc_Playing || state == libvlc_Buffering )
754 if( libvlc_media_player_can_pause( p_mi ) )
755 input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
757 libvlc_media_player_stop( p_mi );
763 input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
766 vlc_object_release( p_input_thread );
769 /**************************************************************************
771 **************************************************************************/
772 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
774 libvlc_state_t state = libvlc_media_player_get_state( p_mi );
775 bool playing = (state == libvlc_Playing || state == libvlc_Buffering);
777 libvlc_media_player_set_pause( p_mi, playing );
780 /**************************************************************************
781 * Tells whether the media player is currently playing.
783 * Enter with lock held.
784 **************************************************************************/
785 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
787 libvlc_state_t state = libvlc_media_player_get_state( p_mi );
788 return (libvlc_Playing == state) || (libvlc_Buffering == state);
791 /**************************************************************************
793 **************************************************************************/
794 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
796 libvlc_state_t state = libvlc_media_player_get_state( p_mi );
799 release_input_thread( p_mi, true ); /* This will stop the input thread */
801 /* Force to go to stopped state, in case we were in Ended, or Error
803 if( state != libvlc_Stopped )
805 set_state( p_mi, libvlc_Stopped, false );
807 /* Construct and send the event */
808 libvlc_event_t event;
809 event.type = libvlc_MediaPlayerStopped;
810 libvlc_event_send( p_mi->p_event_manager, &event );
813 input_resource_Terminate( p_mi->input.p_resource );
818 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
819 void *(*lock_cb) (void *, void **),
820 void (*unlock_cb) (void *, void *, void *const *),
821 void (*display_cb) (void *, void *),
824 var_SetAddress( mp, "vmem-lock", lock_cb );
825 var_SetAddress( mp, "vmem-unlock", unlock_cb );
826 var_SetAddress( mp, "vmem-display", display_cb );
827 var_SetAddress( mp, "vmem-data", opaque );
828 var_SetString( mp, "vout", "vmem" );
831 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
832 libvlc_video_format_cb setup,
833 libvlc_video_cleanup_cb cleanup )
835 var_SetAddress( mp, "vmem-setup", setup );
836 var_SetAddress( mp, "vmem-cleanup", cleanup );
839 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
840 unsigned width, unsigned height, unsigned pitch )
842 var_SetString( mp, "vmem-chroma", chroma );
843 var_SetInteger( mp, "vmem-width", width );
844 var_SetInteger( mp, "vmem-height", height );
845 var_SetInteger( mp, "vmem-pitch", pitch );
848 /**************************************************************************
850 **************************************************************************/
851 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
854 assert (p_mi != NULL);
856 var_SetAddress (p_mi, "drawable-nsobject", drawable);
858 (void) p_mi; (void)drawable;
862 /**************************************************************************
864 **************************************************************************/
865 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
867 assert (p_mi != NULL);
869 return var_GetAddress (p_mi, "drawable-nsobject");
875 /**************************************************************************
877 **************************************************************************/
878 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
882 var_SetInteger (p_mi, "drawable-agl", drawable);
884 (void) p_mi; (void)drawable;
888 /**************************************************************************
890 **************************************************************************/
891 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
893 assert (p_mi != NULL);
895 return var_GetInteger (p_mi, "drawable-agl");
901 /**************************************************************************
903 **************************************************************************/
904 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
907 assert (p_mi != NULL);
909 var_SetString (p_mi, "vout", drawable ? "xid" : "any");
910 var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "any");
911 var_SetInteger (p_mi, "drawable-xid", drawable);
914 /**************************************************************************
916 **************************************************************************/
917 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
919 return var_GetInteger (p_mi, "drawable-xid");
922 /**************************************************************************
924 **************************************************************************/
925 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
928 assert (p_mi != NULL);
929 #if defined (WIN32) || defined (__OS2__)
930 var_SetString (p_mi, "window",
931 (drawable != NULL) ? "embed-hwnd,any" : "");
932 var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
934 (void) p_mi; (void) drawable;
938 /**************************************************************************
940 **************************************************************************/
941 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
943 assert (p_mi != NULL);
944 #if defined (WIN32) || defined (__OS2__)
945 return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
951 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
952 libvlc_audio_play_cb play_cb,
953 libvlc_audio_pause_cb pause_cb,
954 libvlc_audio_resume_cb resume_cb,
955 libvlc_audio_flush_cb flush_cb,
956 libvlc_audio_drain_cb drain_cb,
959 var_SetAddress( mp, "amem-play", play_cb );
960 var_SetAddress( mp, "amem-pause", pause_cb );
961 var_SetAddress( mp, "amem-resume", resume_cb );
962 var_SetAddress( mp, "amem-flush", flush_cb );
963 var_SetAddress( mp, "amem-drain", drain_cb );
964 var_SetAddress( mp, "amem-data", opaque );
965 var_SetString( mp, "aout", "amem,none" );
968 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
969 libvlc_audio_set_volume_cb cb )
971 var_SetAddress( mp, "amem-set-volume", cb );
974 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
975 libvlc_audio_setup_cb setup,
976 libvlc_audio_cleanup_cb cleanup )
978 var_SetAddress( mp, "amem-setup", setup );
979 var_SetAddress( mp, "amem-cleanup", cleanup );
982 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
983 unsigned rate, unsigned channels )
985 var_SetString( mp, "amem-format", format );
986 var_SetInteger( mp, "amem-rate", rate );
987 var_SetInteger( mp, "amem-channels", channels );
991 /**************************************************************************
992 * Getters for stream information
993 **************************************************************************/
994 libvlc_time_t libvlc_media_player_get_length(
995 libvlc_media_player_t *p_mi )
997 input_thread_t *p_input_thread;
998 libvlc_time_t i_time;
1000 p_input_thread = libvlc_get_input_thread ( p_mi );
1001 if( !p_input_thread )
1004 i_time = from_mtime(var_GetTime( p_input_thread, "length" ));
1005 vlc_object_release( p_input_thread );
1010 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1012 input_thread_t *p_input_thread;
1013 libvlc_time_t i_time;
1015 p_input_thread = libvlc_get_input_thread ( p_mi );
1016 if( !p_input_thread )
1019 i_time = from_mtime(var_GetTime( p_input_thread , "time" ));
1020 vlc_object_release( p_input_thread );
1024 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1025 libvlc_time_t i_time )
1027 input_thread_t *p_input_thread;
1029 p_input_thread = libvlc_get_input_thread ( p_mi );
1030 if( !p_input_thread )
1033 var_SetTime( p_input_thread, "time", to_mtime(i_time) );
1034 vlc_object_release( p_input_thread );
1037 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1040 input_thread_t *p_input_thread;
1042 p_input_thread = libvlc_get_input_thread ( p_mi );
1043 if( !p_input_thread )
1046 var_SetFloat( p_input_thread, "position", position );
1047 vlc_object_release( p_input_thread );
1050 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1052 input_thread_t *p_input_thread;
1055 p_input_thread = libvlc_get_input_thread ( p_mi );
1056 if( !p_input_thread )
1059 f_position = var_GetFloat( p_input_thread, "position" );
1060 vlc_object_release( p_input_thread );
1065 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1068 input_thread_t *p_input_thread;
1070 p_input_thread = libvlc_get_input_thread ( p_mi );
1071 if( !p_input_thread )
1074 var_SetInteger( p_input_thread, "chapter", chapter );
1075 vlc_object_release( p_input_thread );
1078 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1080 input_thread_t *p_input_thread;
1083 p_input_thread = libvlc_get_input_thread ( p_mi );
1084 if( !p_input_thread )
1087 i_chapter = var_GetInteger( p_input_thread, "chapter" );
1088 vlc_object_release( p_input_thread );
1093 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1095 input_thread_t *p_input_thread;
1098 p_input_thread = libvlc_get_input_thread ( p_mi );
1099 if( !p_input_thread )
1102 var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1103 vlc_object_release( p_input_thread );
1108 int libvlc_media_player_get_chapter_count_for_title(
1109 libvlc_media_player_t *p_mi,
1112 input_thread_t *p_input_thread;
1115 p_input_thread = libvlc_get_input_thread ( p_mi );
1116 if( !p_input_thread )
1120 if( asprintf( &psz_name, "title %2i", i_title ) == -1 )
1122 vlc_object_release( p_input_thread );
1125 var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1126 vlc_object_release( p_input_thread );
1132 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1135 input_thread_t *p_input_thread;
1137 p_input_thread = libvlc_get_input_thread ( p_mi );
1138 if( !p_input_thread )
1141 var_SetInteger( p_input_thread, "title", i_title );
1142 vlc_object_release( p_input_thread );
1145 libvlc_event_t event;
1146 event.type = libvlc_MediaPlayerTitleChanged;
1147 event.u.media_player_title_changed.new_title = i_title;
1148 libvlc_event_send( p_mi->p_event_manager, &event );
1151 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1153 input_thread_t *p_input_thread;
1156 p_input_thread = libvlc_get_input_thread ( p_mi );
1157 if( !p_input_thread )
1160 i_title = var_GetInteger( p_input_thread, "title" );
1161 vlc_object_release( p_input_thread );
1166 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1168 input_thread_t *p_input_thread;
1171 p_input_thread = libvlc_get_input_thread ( p_mi );
1172 if( !p_input_thread )
1175 var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1176 vlc_object_release( p_input_thread );
1181 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1183 input_thread_t *p_input_thread;
1185 p_input_thread = libvlc_get_input_thread ( p_mi );
1186 if( !p_input_thread )
1189 int i_type = var_Type( p_input_thread, "next-chapter" );
1190 var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1191 "next-chapter":"next-title" );
1193 vlc_object_release( p_input_thread );
1196 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1198 input_thread_t *p_input_thread;
1200 p_input_thread = libvlc_get_input_thread ( p_mi );
1201 if( !p_input_thread )
1204 int i_type = var_Type( p_input_thread, "next-chapter" );
1205 var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1206 "prev-chapter":"prev-title" );
1208 vlc_object_release( p_input_thread );
1211 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1213 input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1216 if( p_input_thread )
1218 if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
1220 vlc_object_release( p_input_thread );
1225 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1228 input_thread_t *p_input_thread =
1229 libvlc_get_input_thread ( p_mi );
1230 if ( !p_input_thread )
1233 b_will_play = !p_input_thread->b_dead;
1234 vlc_object_release( p_input_thread );
1239 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1243 libvlc_printerr ("Playing backward not supported");
1247 var_SetFloat (p_mi, "rate", rate);
1249 input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1250 if( !p_input_thread )
1252 var_SetFloat( p_input_thread, "rate", rate );
1253 vlc_object_release( p_input_thread );
1257 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1259 return var_GetFloat (p_mi, "rate");
1262 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1265 libvlc_state_t state = p_mi->state;
1270 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1272 input_thread_t *p_input_thread;
1275 p_input_thread = libvlc_get_input_thread ( p_mi );
1276 if ( !p_input_thread )
1278 b_seekable = var_GetBool( p_input_thread, "can-seek" );
1279 vlc_object_release( p_input_thread );
1284 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1287 input_thread_t *p_input_thread;
1289 if ( navigate >= libvlc_navigate_to_action_size)
1292 p_input_thread = libvlc_get_input_thread ( p_mi );
1293 if ( !p_input_thread )
1296 var_SetInteger( p_mi->p_libvlc_instance->p_libvlc_int,
1297 "key-action", libvlc_navigate_to_action[navigate] );
1299 vlc_object_release( p_input_thread );
1302 /* internal function, used by audio, video */
1303 libvlc_track_description_t *
1304 libvlc_get_track_description( libvlc_media_player_t *p_mi,
1305 const char *psz_variable )
1307 input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1308 libvlc_track_description_t *p_track_description = NULL,
1309 *p_actual, *p_previous;
1314 vlc_value_t val_list, text_list;
1315 var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
1318 if( val_list.p_list->i_count <= 0 )
1321 p_track_description = ( libvlc_track_description_t * )
1322 malloc( sizeof( libvlc_track_description_t ) );
1323 if ( !p_track_description )
1325 libvlc_printerr( "Not enough memory" );
1328 p_actual = p_track_description;
1330 for( int i = 0; i < val_list.p_list->i_count; i++ )
1334 p_actual = ( libvlc_track_description_t * )
1335 malloc( sizeof( libvlc_track_description_t ) );
1338 libvlc_track_description_list_release( p_track_description );
1339 libvlc_printerr( "Not enough memory" );
1343 p_actual->i_id = val_list.p_list->p_values[i].i_int;
1344 p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1345 p_actual->p_next = NULL;
1347 p_previous->p_next = p_actual;
1348 p_previous = p_actual;
1353 var_FreeList( &val_list, &text_list );
1354 vlc_object_release( p_input );
1356 return p_track_description;
1359 // Deprecated alias for libvlc_track_description_list_release
1360 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1362 libvlc_track_description_list_release( p_td );
1365 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1367 libvlc_track_description_t *p_actual, *p_before;
1372 free( p_actual->psz_name );
1373 p_before = p_actual;
1374 p_actual = p_before->p_next;
1379 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1381 input_thread_t *p_input_thread;
1384 p_input_thread = libvlc_get_input_thread ( p_mi );
1385 if ( !p_input_thread )
1387 b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1388 vlc_object_release( p_input_thread );
1393 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1395 input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1396 if( p_input_thread != NULL )
1398 var_TriggerCallback( p_input_thread, "frame-next" );
1399 vlc_object_release( p_input_thread );