/***************************************************************************** * media_player.c: Libvlc API Media Instance management functions ***************************************************************************** * Copyright (C) 2005-2015 VLC authors and VideoLAN * * Authors: Clément Stenac * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "libvlc_internal.h" #include "media_internal.h" // libvlc_media_set_state() #include "media_player_internal.h" #include "renderer_discoverer_internal.h" #define ES_INIT (-2) /* -1 is reserved for ES deselect */ static int snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *p_data ); static void media_attach_preparsed_event(libvlc_media_t *); static void media_detach_preparsed_event(libvlc_media_t *); static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi ); // player callbacks static void on_current_media_changed(vlc_player_t *player, input_item_t *new_media, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_media_t *md = mp->p_md; input_item_t *media = md ? md->p_input_item : NULL; if (new_media == media) /* no changes */ return; if (md) media_detach_preparsed_event(md); if (new_media) { mp->p_md = libvlc_media_new_from_input_item(mp->p_libvlc_instance, new_media); if (!mp->p_md) /* error already printed by the function call */ return; media_attach_preparsed_event(mp->p_md); } else mp->p_md = NULL; libvlc_media_release(md); libvlc_event_t event; event.type = libvlc_MediaPlayerMediaChanged; event.u.media_player_media_changed.new_media = mp->p_md; libvlc_event_send(&mp->event_manager, &event); } static void on_state_changed(vlc_player_t *player, enum vlc_player_state new_state, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; switch (new_state) { case VLC_PLAYER_STATE_STOPPED: event.type = libvlc_MediaPlayerStopped; break; case VLC_PLAYER_STATE_STOPPING: event.type = libvlc_MediaPlayerEndReached; break; case VLC_PLAYER_STATE_STARTED: event.type = libvlc_MediaPlayerOpening; break; case VLC_PLAYER_STATE_PLAYING: event.type = libvlc_MediaPlayerPlaying; break; case VLC_PLAYER_STATE_PAUSED: event.type = libvlc_MediaPlayerPaused; break; default: vlc_assert_unreachable(); } libvlc_event_send(&mp->event_manager, &event); } static void on_error_changed(vlc_player_t *player, enum vlc_player_error error, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; switch (error) { case VLC_PLAYER_ERROR_NONE: event.type = libvlc_MediaPlayerNothingSpecial; break; case VLC_PLAYER_ERROR_GENERIC: event.type = libvlc_MediaPlayerEncounteredError; break; default: vlc_assert_unreachable(); } libvlc_event_send(&mp->event_manager, &event); } static void on_buffering_changed(vlc_player_t *player, float new_buffering, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerBuffering; event.u.media_player_buffering.new_cache = 100 * new_buffering; libvlc_event_send(&mp->event_manager, &event); } static void on_capabilities_changed(vlc_player_t *player, int old_caps, int new_caps, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; bool old_seekable = old_caps & VLC_INPUT_CAPABILITIES_SEEKABLE; bool new_seekable = new_caps & VLC_INPUT_CAPABILITIES_SEEKABLE; if (new_seekable != old_seekable) { event.type = libvlc_MediaPlayerSeekableChanged; event.u.media_player_seekable_changed.new_seekable = new_seekable; libvlc_event_send(&mp->event_manager, &event); } bool old_pauseable = old_caps & VLC_INPUT_CAPABILITIES_PAUSEABLE; bool new_pauseable = new_caps & VLC_INPUT_CAPABILITIES_PAUSEABLE; if (new_pauseable != old_pauseable) { event.type = libvlc_MediaPlayerPausableChanged; event.u.media_player_pausable_changed.new_pausable = new_pauseable; libvlc_event_send(&mp->event_manager, &event); } } static void on_position_changed(vlc_player_t *player, vlc_tick_t new_time, float new_pos, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerPositionChanged; event.u.media_player_position_changed.new_position = new_pos; libvlc_event_send(&mp->event_manager, &event); event.type = libvlc_MediaPlayerTimeChanged; event.u.media_player_time_changed.new_time = MS_FROM_VLC_TICK(new_time); libvlc_event_send(&mp->event_manager, &event); } static void on_length_changed(vlc_player_t *player, vlc_tick_t new_length, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerLengthChanged; event.u.media_player_length_changed.new_length = MS_FROM_VLC_TICK(new_length); libvlc_event_send(&mp->event_manager, &event); } static int track_type_from_cat(enum es_format_category_e cat) { switch (cat) { case VIDEO_ES: return libvlc_track_video; case AUDIO_ES: return libvlc_track_audio; case SPU_ES: return libvlc_track_text; default: return libvlc_track_unknown; } } static void on_track_list_changed(vlc_player_t *player, enum vlc_player_list_action action, const struct vlc_player_track *track, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; if (action == VLC_PLAYER_LIST_ADDED) event.type = libvlc_MediaPlayerESAdded; else if (action == VLC_PLAYER_LIST_REMOVED) event.type = libvlc_MediaPlayerESDeleted; else /* no event to forward */ return; event.u.media_player_es_changed.i_type = track_type_from_cat(track->fmt.i_cat); event.u.media_player_es_changed.i_id = vlc_es_id_GetInputId(track->es_id); libvlc_event_send(&mp->event_manager, &event); } static void on_track_selection_changed(vlc_player_t *player, vlc_es_id_t *unselected_id, vlc_es_id_t *selected_id, void *data) { (void) player; (void) unselected_id; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerESSelected; if (selected_id) { enum es_format_category_e cat = vlc_es_id_GetCat(selected_id); event.u.media_player_es_changed.i_type = track_type_from_cat(cat); event.u.media_player_es_changed.i_id = vlc_es_id_GetInputId(selected_id); libvlc_event_send(&mp->event_manager, &event); } } static void on_program_list_changed(vlc_player_t *player, enum vlc_player_list_action action, const struct vlc_player_program *prgm, void* data) { (void) action; (void) prgm; libvlc_media_player_t *mp = data; const struct vlc_player_program *selected = vlc_player_GetSelectedProgram(player); if (!selected) return; libvlc_event_t event; event.type = libvlc_MediaPlayerScrambledChanged; event.u.media_player_scrambled_changed.new_scrambled = selected->scrambled; libvlc_event_send(&mp->event_manager, &event); } static void on_program_selection_changed(vlc_player_t *player, int unselected_id, int selected_id, void *data) { (void) unselected_id; libvlc_media_player_t *mp = data; if (selected_id == -1) return; const struct vlc_player_program *program = vlc_player_GetSelectedProgram(player); assert(program); libvlc_event_t event; event.type = libvlc_MediaPlayerScrambledChanged; event.u.media_player_scrambled_changed.new_scrambled = program->scrambled; libvlc_event_send(&mp->event_manager, &event); } static void on_title_selection_changed(vlc_player_t *player, const struct vlc_player_title *new_title, size_t new_idx, void *data) { (void) player; (void) new_title; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerTitleChanged; event.u.media_player_title_changed.new_title = new_idx; libvlc_event_send(&mp->event_manager, &event); } static void on_chapter_selection_changed(vlc_player_t *player, const struct vlc_player_title *title, size_t title_idx, const struct vlc_player_chapter *new_chapter, size_t new_chapter_idx, void *data) { (void) player; (void) title; (void) title_idx; (void) new_chapter; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerChapterChanged; event.u.media_player_chapter_changed.new_chapter = new_chapter_idx; libvlc_event_send(&mp->event_manager, &event); } static void on_media_subitems_changed(vlc_player_t *player, input_item_t *media, input_item_node_t *new_subitems, void *data) { (void) player; libvlc_media_player_t *mp = data; input_item_t *current = mp->p_md ? mp->p_md->p_input_item : NULL; if (media == current) libvlc_media_add_subtree(mp->p_md, new_subitems); } static void on_cork_changed(vlc_player_t *player, unsigned cork_count, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = cork_count ? libvlc_MediaPlayerCorked : libvlc_MediaPlayerUncorked; libvlc_event_send(&mp->event_manager, &event); } static void on_vout_changed(vlc_player_t *player, enum vlc_player_vout_action action, vout_thread_t *vout, vlc_es_id_t *es_id, void *data) { (void) action; (void) vout; (void) es_id; libvlc_media_player_t *mp = data; size_t count; vout_thread_t **vouts = vlc_player_vout_HoldAll(player, &count); if (!vouts) return; for (size_t i = 0; i < count; ++i) vout_Release(vouts[i]); free(vouts); libvlc_event_t event; event.type = libvlc_MediaPlayerVout; event.u.media_player_vout.new_count = count; libvlc_event_send(&mp->event_manager, &event); } // player aout callbacks static void on_volume_changed(vlc_player_t *player, float new_volume, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerAudioVolume; event.u.media_player_audio_volume.volume = new_volume; libvlc_event_send(&mp->event_manager, &event); } static void on_mute_changed(vlc_player_t *player, bool new_muted, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = new_muted ? libvlc_MediaPlayerMuted : libvlc_MediaPlayerUnmuted; libvlc_event_send(&mp->event_manager, &event); } static void on_audio_device_changed(vlc_player_t *player, const char *device, void *data) { (void) player; libvlc_media_player_t *mp = data; libvlc_event_t event; event.type = libvlc_MediaPlayerAudioDevice; event.u.media_player_audio_device.device = device; libvlc_event_send(&mp->event_manager, &event); } static const struct vlc_player_cbs vlc_player_cbs = { .on_current_media_changed = on_current_media_changed, .on_state_changed = on_state_changed, .on_error_changed = on_error_changed, .on_buffering_changed = on_buffering_changed, .on_capabilities_changed = on_capabilities_changed, .on_position_changed = on_position_changed, .on_length_changed = on_length_changed, .on_track_list_changed = on_track_list_changed, .on_track_selection_changed = on_track_selection_changed, .on_program_list_changed = on_program_list_changed, .on_program_selection_changed = on_program_selection_changed, .on_title_selection_changed = on_title_selection_changed, .on_chapter_selection_changed = on_chapter_selection_changed, .on_media_subitems_changed = on_media_subitems_changed, .on_cork_changed = on_cork_changed, .on_vout_changed = on_vout_changed, }; static const struct vlc_player_aout_cbs vlc_player_aout_cbs = { .on_volume_changed = on_volume_changed, .on_mute_changed = on_mute_changed, .on_device_changed = on_audio_device_changed, }; /************************************************************************** * Snapshot Taken Event. * * FIXME: This snapshot API interface makes no sense in media_player. *************************************************************************/ static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this); libvlc_media_player_t *mp = p_data; libvlc_event_t event; event.type = libvlc_MediaPlayerSnapshotTaken; event.u.media_player_snapshot_taken.psz_filename = newval.psz_string; libvlc_event_send(&mp->event_manager, &event); return VLC_SUCCESS; } static void input_item_preparsed_changed( const vlc_event_t *p_event, void * user_data ) { libvlc_media_t *p_md = user_data; if( p_event->u.input_item_preparsed_changed.new_status & ITEM_PREPARSED ) { /* Send the event */ libvlc_event_t event; event.type = libvlc_MediaParsedChanged; event.u.media_parsed_changed.new_status = libvlc_media_parsed_status_done; libvlc_event_send( &p_md->event_manager, &event ); } } static void media_attach_preparsed_event( libvlc_media_t *p_md ) { vlc_event_attach( &p_md->p_input_item->event_manager, vlc_InputItemPreparsedChanged, input_item_preparsed_changed, p_md ); } static void media_detach_preparsed_event( libvlc_media_t *p_md ) { vlc_event_detach( &p_md->p_input_item->event_manager, vlc_InputItemPreparsedChanged, input_item_preparsed_changed, p_md ); } /************************************************************************** * Create a Media Instance object. * * Refcount strategy: * - All items created by _new start with a refcount set to 1. * - Accessor _release decrease the refcount by 1, if after that * operation the refcount is 0, the object is destroyed. * - Accessor _retain increase the refcount by 1 (XXX: to implement) * * Object locking strategy: * - No lock held while in constructor. * - When accessing any member variable this lock is held. (XXX who locks?) * - When attempting to destroy the object the lock is also held. **************************************************************************/ libvlc_media_player_t * libvlc_media_player_new( libvlc_instance_t *instance ) { libvlc_media_player_t * mp; assert(instance); mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp)); if (unlikely(mp == NULL)) { libvlc_printerr("Not enough memory"); return NULL; } /* Input */ var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT); var_Create (mp, "sout", VLC_VAR_STRING); var_Create (mp, "demux-filter", VLC_VAR_STRING); /* Video */ var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT); var_Create (mp, "window", VLC_VAR_STRING); var_Create (mp, "gl", VLC_VAR_STRING); var_Create (mp, "gles2", VLC_VAR_STRING); var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS); var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS); var_Create (mp, "vmem-display", VLC_VAR_ADDRESS); var_Create (mp, "vmem-data", VLC_VAR_ADDRESS); var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS); var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS); var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create( mp, "vout-cb-opaque", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-setup", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-cleanup", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-update-output", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-swap", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-get-proc-address", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-make-current", VLC_VAR_ADDRESS ); var_Create( mp, "vout-cb-select-plane", VLC_VAR_ADDRESS ); var_Create (mp, "avcodec-hw", VLC_VAR_STRING); var_Create (mp, "drawable-xid", VLC_VAR_INTEGER); #if defined (_WIN32) || defined (__OS2__) var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER); #endif #ifdef __APPLE__ var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS); #endif #ifdef __ANDROID__ var_Create (mp, "drawable-androidwindow", VLC_VAR_ADDRESS); #endif var_Create (mp, "keyboard-events", VLC_VAR_BOOL); var_SetBool (mp, "keyboard-events", true); var_Create (mp, "mouse-events", VLC_VAR_BOOL); var_SetBool (mp, "mouse-events", true); var_Create (mp, "fullscreen", VLC_VAR_BOOL); var_Create (mp, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT); var_Create (mp, "zoom", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); var_Create (mp, "aspect-ratio", VLC_VAR_STRING); var_Create (mp, "crop", VLC_VAR_STRING); var_Create (mp, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "vbi-page", VLC_VAR_INTEGER); var_SetInteger (mp, "vbi-page", 100); var_Create (mp, "video-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "sub-source", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "marq-marquee", VLC_VAR_STRING); var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-file", VLC_VAR_STRING); var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); var_Create (mp, "hue", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT); /* Audio */ var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "audio-device", VLC_VAR_STRING); var_Create (mp, "mute", VLC_VAR_BOOL); var_Create (mp, "volume", VLC_VAR_FLOAT); var_Create (mp, "corks", VLC_VAR_INTEGER); var_Create (mp, "audio-filter", VLC_VAR_STRING); var_Create (mp, "role", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "amem-data", VLC_VAR_ADDRESS); var_Create (mp, "amem-setup", VLC_VAR_ADDRESS); var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS); var_Create (mp, "amem-play", VLC_VAR_ADDRESS); var_Create (mp, "amem-pause", VLC_VAR_ADDRESS); var_Create (mp, "amem-resume", VLC_VAR_ADDRESS); var_Create (mp, "amem-flush", VLC_VAR_ADDRESS); var_Create (mp, "amem-drain", VLC_VAR_ADDRESS); var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS); var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT); var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); /* Video Title */ var_Create (mp, "video-title-show", VLC_VAR_BOOL); var_Create (mp, "video-title-position", VLC_VAR_INTEGER); var_Create (mp, "video-title-timeout", VLC_VAR_INTEGER); /* Equalizer */ var_Create (mp, "equalizer-preamp", VLC_VAR_FLOAT); var_Create (mp, "equalizer-vlcfreqs", VLC_VAR_BOOL); var_Create (mp, "equalizer-bands", VLC_VAR_STRING); /* Initialize the shared HTTP cookie jar */ vlc_value_t cookies; cookies.p_address = vlc_http_cookies_new(); if ( likely(cookies.p_address) ) { var_Create(mp, "http-cookies", VLC_VAR_ADDRESS); var_SetChecked(mp, "http-cookies", VLC_VAR_ADDRESS, cookies); } mp->p_md = NULL; mp->p_libvlc_instance = instance; /* use a reentrant lock to allow calling libvlc functions from callbacks */ mp->player = vlc_player_New(VLC_OBJECT(mp), VLC_PLAYER_LOCK_REENTRANT, NULL, NULL); if (unlikely(!mp->player)) goto error1; vlc_player_Lock(mp->player); mp->listener = vlc_player_AddListener(mp->player, &vlc_player_cbs, mp); if (unlikely(!mp->listener)) goto error2; mp->aout_listener = vlc_player_aout_AddListener(mp->player, &vlc_player_aout_cbs, mp); if (unlikely(!mp->aout_listener)) goto error3; vlc_player_Unlock(mp->player); mp->i_refcount = 1; libvlc_event_manager_init(&mp->event_manager, mp); /* Snapshot initialization */ /* Attach a var callback to the global object to provide the glue between * vout_thread that generates the event and media_player that re-emits it * with its own event manager * * FIXME: It's unclear why we want to put this in public API, and why we * want to expose it in such a limiting and ugly way. */ var_AddCallback(vlc_object_instance(mp), "snapshot-file", snapshot_was_taken, mp); libvlc_retain(instance); return mp; error3: vlc_player_RemoveListener(mp->player, mp->listener); error2: vlc_player_Unlock(mp->player); vlc_player_Delete(mp->player); error1: vlc_object_delete(mp); return NULL; } /************************************************************************** * Create a Media Instance object with a media descriptor. **************************************************************************/ libvlc_media_player_t * libvlc_media_player_new_from_media( libvlc_media_t * p_md ) { libvlc_media_player_t * p_mi; p_mi = libvlc_media_player_new( p_md->p_libvlc_instance ); if( !p_mi ) return NULL; libvlc_media_retain( p_md ); p_mi->p_md = p_md; media_attach_preparsed_event(p_md); vlc_player_Lock(p_mi->player); int ret = vlc_player_SetCurrentMedia(p_mi->player, p_md->p_input_item); vlc_player_Unlock(p_mi->player); if (ret != VLC_SUCCESS) { media_detach_preparsed_event(p_md); libvlc_media_release(p_md); p_mi->p_md = NULL; return NULL; } return p_mi; } /************************************************************************** * Destroy a Media Instance object (libvlc internal) * * Warning: No lock held here, but hey, this is internal. Caller must lock. **************************************************************************/ static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi ) { assert( p_mi ); /* Detach Callback from the main libvlc object */ var_DelCallback( vlc_object_instance(p_mi), "snapshot-file", snapshot_was_taken, p_mi ); vlc_player_Lock(p_mi->player); vlc_player_aout_RemoveListener(p_mi->player, p_mi->aout_listener); vlc_player_RemoveListener(p_mi->player, p_mi->listener); vlc_player_Unlock(p_mi->player); vlc_player_Delete(p_mi->player); libvlc_event_manager_destroy(&p_mi->event_manager); libvlc_media_release( p_mi->p_md ); vlc_http_cookie_jar_t *cookies = var_GetAddress( p_mi, "http-cookies" ); if ( cookies ) { var_Destroy( p_mi, "http-cookies" ); vlc_http_cookies_destroy( cookies ); } libvlc_instance_t *instance = p_mi->p_libvlc_instance; vlc_object_delete(p_mi); libvlc_release(instance); } /************************************************************************** * Release a Media Instance object. * * Function does the locking. **************************************************************************/ void libvlc_media_player_release( libvlc_media_player_t *p_mi ) { bool destroy; assert( p_mi ); vlc_player_Lock(p_mi->player); destroy = !--p_mi->i_refcount; vlc_player_Unlock(p_mi->player); if( destroy ) libvlc_media_player_destroy( p_mi ); } /************************************************************************** * Retain a Media Instance object. * * Caller must hold the lock. **************************************************************************/ void libvlc_media_player_retain( libvlc_media_player_t *p_mi ) { assert( p_mi ); vlc_player_Lock(p_mi->player); p_mi->i_refcount++; vlc_player_Unlock(p_mi->player); } /************************************************************************** * Set the Media descriptor associated with the instance. * * Enter without lock -- function will lock the object. **************************************************************************/ void libvlc_media_player_set_media( libvlc_media_player_t *p_mi, libvlc_media_t *p_md ) { vlc_player_Lock(p_mi->player); if (p_mi->p_md) media_detach_preparsed_event(p_mi->p_md); libvlc_media_release( p_mi->p_md ); if( p_md ) { libvlc_media_retain( p_md ); media_attach_preparsed_event(p_md); } p_mi->p_md = p_md; vlc_player_SetCurrentMedia(p_mi->player, p_md->p_input_item); /* The policy here is to ignore that we were created using a different * libvlc_instance, because we don't really care */ p_mi->p_libvlc_instance = p_md->p_libvlc_instance; vlc_player_Unlock(p_mi->player); } /************************************************************************** * Get the Media descriptor associated with the instance. **************************************************************************/ libvlc_media_t * libvlc_media_player_get_media( libvlc_media_player_t *p_mi ) { libvlc_media_t *p_m; vlc_player_Lock(p_mi->player); p_m = p_mi->p_md; if( p_m ) libvlc_media_retain( p_m ); vlc_player_Unlock(p_mi->player); return p_m; } /************************************************************************** * Get the event Manager. **************************************************************************/ libvlc_event_manager_t * libvlc_media_player_event_manager( libvlc_media_player_t *p_mi ) { return &p_mi->event_manager; } /************************************************************************** * Tell media player to start playing. **************************************************************************/ int libvlc_media_player_play( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); int ret = vlc_player_Start(player); if (ret == VLC_SUCCESS) { if (vlc_player_IsPaused(player)) vlc_player_Resume(player); } vlc_player_Unlock(player); return ret; } void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); if (paused) { if (vlc_player_CanPause(player)) vlc_player_Pause(player); else vlc_player_Stop(player); } else { vlc_player_Resume(player); } vlc_player_Unlock(player); } /************************************************************************** * Toggle pause. **************************************************************************/ void libvlc_media_player_pause( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_TogglePause(player); vlc_player_Unlock(player); } /************************************************************************** * Tells whether the media player is currently playing. **************************************************************************/ bool libvlc_media_player_is_playing(libvlc_media_player_t *p_mi) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); bool ret = vlc_player_IsStarted(player) && !vlc_player_IsPaused(player); vlc_player_Unlock(player); return ret; } /************************************************************************** * Stop playing. **************************************************************************/ void libvlc_media_player_stop_async( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_Stop(player); vlc_player_Unlock(player); } int libvlc_media_player_set_renderer( libvlc_media_player_t *p_mi, libvlc_renderer_item_t *p_litem ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_renderer_item_t *renderer = libvlc_renderer_item_to_vlc(p_litem); vlc_player_SetRenderer(player, renderer); vlc_player_Unlock(player); return 0; } void libvlc_video_set_callbacks( libvlc_media_player_t *mp, void *(*lock_cb) (void *, void **), void (*unlock_cb) (void *, void *, void *const *), void (*display_cb) (void *, void *), void *opaque ) { var_SetAddress( mp, "vmem-lock", lock_cb ); var_SetAddress( mp, "vmem-unlock", unlock_cb ); var_SetAddress( mp, "vmem-display", display_cb ); var_SetAddress( mp, "vmem-data", opaque ); var_SetString( mp, "avcodec-hw", "none" ); var_SetString( mp, "vout", "vmem" ); var_SetString( mp, "window", "dummy" ); } void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp, libvlc_video_format_cb setup, libvlc_video_cleanup_cb cleanup ) { var_SetAddress( mp, "vmem-setup", setup ); var_SetAddress( mp, "vmem-cleanup", cleanup ); } void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma, unsigned width, unsigned height, unsigned pitch ) { var_SetString( mp, "vmem-chroma", chroma ); var_SetInteger( mp, "vmem-width", width ); var_SetInteger( mp, "vmem-height", height ); var_SetInteger( mp, "vmem-pitch", pitch ); } bool libvlc_video_set_output_callbacks(libvlc_media_player_t *mp, libvlc_video_engine_t engine, libvlc_video_setup_cb setup_cb, libvlc_video_cleanup_cb cleanup_cb, libvlc_video_update_output_cb update_output_cb, libvlc_video_swap_cb swap_cb, libvlc_video_makeCurrent_cb makeCurrent_cb, libvlc_video_getProcAddress_cb getProcAddress_cb, void *opaque) { #ifdef __ANDROID__ //use the default android window var_SetString( mp, "window", ""); #else var_SetString( mp, "window", "wdummy"); #endif if( engine == libvlc_video_engine_gles2 ) { var_SetString ( mp, "vout", "gles2" ); var_SetString ( mp, "gles2", "vgl" ); } else if( engine == libvlc_video_engine_opengl ) { var_SetString ( mp, "vout", "gl" ); var_SetString ( mp, "gl", "vgl"); } else return false; var_SetAddress( mp, "vout-cb-opaque", opaque ); var_SetAddress( mp, "vout-cb-setup", setup_cb ); var_SetAddress( mp, "vout-cb-cleanup", cleanup_cb ); var_SetAddress( mp, "vout-cb-update-output", update_output_cb ); var_SetAddress( mp, "vout-cb-swap", swap_cb ); var_SetAddress( mp, "vout-cb-get-proc-address", getProcAddress_cb ); var_SetAddress( mp, "vout-cb-make-current", makeCurrent_cb ); return true; } bool libvlc_video_direct3d_set_callbacks(libvlc_media_player_t *mp, libvlc_video_direct3d_engine_t engine, libvlc_video_direct3d_device_setup_cb setup_cb, libvlc_video_direct3d_device_cleanup_cb cleanup_cb, libvlc_video_direct3d_update_output_cb update_output_cb, libvlc_video_swap_cb swap_cb, libvlc_video_direct3d_start_end_rendering_cb makeCurrent_cb, libvlc_video_direct3d_select_plane_cb select_plane_cb, void *opaque) { var_SetString( mp, "window", "wdummy"); if ( engine == libvlc_video_direct3d_engine_d3d11 ) { var_SetString ( mp, "vout", "direct3d11" ); var_SetString ( mp, "avcodec-hw", "d3d11va"); } else if ( engine == libvlc_video_direct3d_engine_d3d9 ) { var_SetString ( mp, "vout", "direct3d9" ); var_SetString ( mp, "avcodec-hw", "dxva2"); } else return false; var_SetAddress( mp, "vout-cb-opaque", opaque ); var_SetAddress( mp, "vout-cb-setup", setup_cb ); var_SetAddress( mp, "vout-cb-cleanup", cleanup_cb ); var_SetAddress( mp, "vout-cb-update-output", update_output_cb ); var_SetAddress( mp, "vout-cb-swap", swap_cb ); var_SetAddress( mp, "vout-cb-make-current", makeCurrent_cb ); var_SetAddress( mp, "vout-cb-select-plane", select_plane_cb ); return true; } /************************************************************************** * set_nsobject **************************************************************************/ void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi, void * drawable ) { assert (p_mi != NULL); #ifdef __APPLE__ var_SetString (p_mi, "avcodec-hw", ""); var_SetString (p_mi, "vout", ""); var_SetString (p_mi, "window", ""); var_SetAddress (p_mi, "drawable-nsobject", drawable); #else (void)drawable; libvlc_printerr ("can't set nsobject: APPLE build required"); assert(false); var_SetString (p_mi, "vout", "none"); var_SetString (p_mi, "window", "none"); #endif } /************************************************************************** * get_nsobject **************************************************************************/ void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi ) { assert (p_mi != NULL); #ifdef __APPLE__ return var_GetAddress (p_mi, "drawable-nsobject"); #else (void) p_mi; return NULL; #endif } /************************************************************************** * set_xwindow **************************************************************************/ void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi, uint32_t drawable ) { assert (p_mi != NULL); var_SetString (p_mi, "avcodec-hw", ""); var_SetString (p_mi, "vout", ""); var_SetString (p_mi, "window", drawable ? "embed-xid,any" : ""); var_SetInteger (p_mi, "drawable-xid", drawable); } /************************************************************************** * get_xwindow **************************************************************************/ uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi ) { return var_GetInteger (p_mi, "drawable-xid"); } /************************************************************************** * set_hwnd **************************************************************************/ void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi, void *drawable ) { assert (p_mi != NULL); #if defined (_WIN32) || defined (__OS2__) var_SetString (p_mi, "avcodec-hw", ""); var_SetString (p_mi, "vout", ""); var_SetString (p_mi, "window", (drawable != NULL) ? "embed-hwnd,any" : ""); var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable); #else (void) drawable; libvlc_printerr ("can't set hwnd: WIN32 build required"); assert(false); var_SetString (p_mi, "vout", "none"); var_SetString (p_mi, "window", "none"); #endif } /************************************************************************** * get_hwnd **************************************************************************/ void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi ) { assert (p_mi != NULL); #if defined (_WIN32) || defined (__OS2__) return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd"); #else (void) p_mi; return NULL; #endif } /************************************************************************** * set_android_context **************************************************************************/ void libvlc_media_player_set_android_context( libvlc_media_player_t *p_mi, void *p_awindow_handler ) { assert (p_mi != NULL); #ifdef __ANDROID__ var_SetAddress (p_mi, "drawable-androidwindow", p_awindow_handler); #else (void) p_awindow_handler; libvlc_printerr ("can't set android context: ANDROID build required"); assert(false); var_SetString (p_mi, "vout", "none"); var_SetString (p_mi, "window", "none"); #endif } void libvlc_audio_set_callbacks( libvlc_media_player_t *mp, libvlc_audio_play_cb play_cb, libvlc_audio_pause_cb pause_cb, libvlc_audio_resume_cb resume_cb, libvlc_audio_flush_cb flush_cb, libvlc_audio_drain_cb drain_cb, void *opaque ) { var_SetAddress( mp, "amem-play", play_cb ); var_SetAddress( mp, "amem-pause", pause_cb ); var_SetAddress( mp, "amem-resume", resume_cb ); var_SetAddress( mp, "amem-flush", flush_cb ); var_SetAddress( mp, "amem-drain", drain_cb ); var_SetAddress( mp, "amem-data", opaque ); var_SetString( mp, "aout", "amem,none" ); } void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp, libvlc_audio_set_volume_cb cb ) { var_SetAddress( mp, "amem-set-volume", cb ); } void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp, libvlc_audio_setup_cb setup, libvlc_audio_cleanup_cb cleanup ) { var_SetAddress( mp, "amem-setup", setup ); var_SetAddress( mp, "amem-cleanup", cleanup ); } void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format, unsigned rate, unsigned channels ) { var_SetString( mp, "amem-format", format ); var_SetInteger( mp, "amem-rate", rate ); var_SetInteger( mp, "amem-channels", channels ); } /************************************************************************** * Getters for stream information **************************************************************************/ libvlc_time_t libvlc_media_player_get_length( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_tick_t length = vlc_player_GetLength(player); libvlc_time_t i_time = from_mtime(length); vlc_player_Unlock(player); return i_time; } libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_tick_t tick = vlc_player_GetTime(player); libvlc_time_t i_time = from_mtime(tick); vlc_player_Unlock(player); return i_time; } int libvlc_media_player_set_time( libvlc_media_player_t *p_mi, libvlc_time_t i_time, bool b_fast ) { vlc_tick_t tick = to_mtime(i_time); vlc_player_t *player = p_mi->player; vlc_player_Lock(player); enum vlc_player_seek_speed speed = b_fast ? VLC_PLAYER_SEEK_FAST : VLC_PLAYER_SEEK_PRECISE; vlc_player_SeekByTime(player, tick, speed, VLC_PLAYER_WHENCE_ABSOLUTE); vlc_player_Unlock(player); /* may not fail anymore, keep int not to break the API */ return 0; } int libvlc_media_player_set_position( libvlc_media_player_t *p_mi, float position, bool b_fast ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); enum vlc_player_seek_speed speed = b_fast ? VLC_PLAYER_SEEK_FAST : VLC_PLAYER_SEEK_PRECISE; vlc_player_SeekByPos(player, position, speed, VLC_PLAYER_WHENCE_ABSOLUTE); vlc_player_Unlock(player); /* may not fail anymore, keep int not to break the API */ return 0; } float libvlc_media_player_get_position( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); float f_position = vlc_player_GetPosition(player); vlc_player_Unlock(player); return f_position; } void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi, int chapter ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_SelectChapterIdx(player, chapter); vlc_player_Unlock(player); } int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); ssize_t i_chapter = vlc_player_GetSelectedChapterIdx(player); vlc_player_Unlock(player); return i_chapter; } int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); const struct vlc_player_title *title = vlc_player_GetSelectedTitle(player); int ret = title ? (int) title->chapter_count : -1; vlc_player_Unlock(player); return ret; } int libvlc_media_player_get_chapter_count_for_title( libvlc_media_player_t *p_mi, int i_title ) { assert(i_title >= 0); size_t idx = i_title; int ret = -1; vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_title_list *titles = vlc_player_GetTitleList(player); if (!titles) goto end; size_t titles_count = vlc_player_title_list_GetCount(titles); if (idx < titles_count) goto end; const struct vlc_player_title *title = vlc_player_title_list_GetAt(titles, idx); assert(title); ret = title->chapter_count; end: vlc_player_Unlock(player); return ret; } void libvlc_media_player_set_title( libvlc_media_player_t *p_mi, int i_title ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_SelectTitleIdx(player, i_title); vlc_player_Unlock(player); } int libvlc_media_player_get_title( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); ssize_t i_title = vlc_player_GetSelectedTitleIdx(player); vlc_player_Unlock(player); return i_title; } int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_title_list *titles = vlc_player_GetTitleList(player); int ret = titles ? (int) vlc_player_title_list_GetCount(titles) : -1; vlc_player_Unlock(player); return ret; } int libvlc_media_player_get_full_title_descriptions( libvlc_media_player_t *p_mi, libvlc_title_description_t *** pp_titles ) { assert( p_mi ); int ret = -1; vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_title_list *titles = vlc_player_GetTitleList(player); if (!titles) goto end; size_t count = vlc_player_title_list_GetCount(titles); libvlc_title_description_t **descs = vlc_alloc(count, sizeof(*descs)); if (count > 0 && !descs) goto end; for (size_t i = 0; i < count; i++) { const struct vlc_player_title *title = vlc_player_title_list_GetAt(titles, i); libvlc_title_description_t *desc = malloc(sizeof(*desc)); if (!desc) { libvlc_title_descriptions_release(descs, i); goto end; } descs[i] = desc; /* we want to return milliseconds to match the rest of the API */ desc->i_duration = MS_FROM_VLC_TICK(title->length); desc->i_flags = title->flags; desc->psz_name = title->name ? strdup(title->name) : NULL; } ret = count; *pp_titles = descs; end: vlc_player_Unlock(player); return ret; } void libvlc_title_descriptions_release( libvlc_title_description_t **p_titles, unsigned i_count ) { for (unsigned i = 0; i < i_count; i++ ) { if ( !p_titles[i] ) continue; free( p_titles[i]->psz_name ); free( p_titles[i] ); } free( p_titles ); } int libvlc_media_player_get_full_chapter_descriptions( libvlc_media_player_t *p_mi, int i_chapters_of_title, libvlc_chapter_description_t *** pp_chapters ) { assert( p_mi ); int ret = -1; vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_title_list *titles = vlc_player_GetTitleList(player); if (!titles) goto end; size_t titles_count = vlc_player_title_list_GetCount(titles); if (i_chapters_of_title < (int) titles_count) goto end; const struct vlc_player_title *title = vlc_player_title_list_GetAt(titles, i_chapters_of_title); assert(title); size_t i_chapter_count = title->chapter_count; libvlc_chapter_description_t **descs = vlc_alloc(i_chapter_count, sizeof(*descs)); if (i_chapter_count > 0 && !descs) goto end; for (size_t i = 0; i < i_chapter_count; i++) { const struct vlc_player_chapter *chapter = &title->chapters[i]; libvlc_chapter_description_t *desc = malloc(sizeof(*desc)); if (!desc) { libvlc_chapter_descriptions_release(descs, i); goto end; } descs[i] = desc; vlc_tick_t chapter_end = i < i_chapter_count - 1 ? title->chapters[i + 1].time : title->length; desc->i_time_offset = MS_FROM_VLC_TICK(chapter->time); desc->psz_name = chapter->name ? strdup(chapter->name) : NULL; desc->i_duration = MS_FROM_VLC_TICK(chapter_end) - desc->i_time_offset; } ret = i_chapter_count; *pp_chapters = descs; end: vlc_player_Unlock(player); return ret; } void libvlc_chapter_descriptions_release( libvlc_chapter_description_t **p_chapters, unsigned i_count ) { for (unsigned i = 0; i < i_count; i++ ) { if ( !p_chapters[i] ) continue; free( p_chapters[i]->psz_name ); free( p_chapters[i] ); } free( p_chapters ); } void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_SelectNextChapter(player); vlc_player_Unlock(player); } void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_SelectPrevChapter(player); vlc_player_Unlock(player); } int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_ChangeRate(player, rate); vlc_player_Unlock(player); return 0; } float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); float rate = vlc_player_GetRate(player); vlc_player_Unlock(player); return rate; } libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); enum vlc_player_error error = vlc_player_GetError(player); enum vlc_player_state state = vlc_player_GetState(player); vlc_player_Unlock(player); if (error != VLC_PLAYER_ERROR_NONE) return libvlc_Error; switch (state) { case VLC_PLAYER_STATE_STOPPED: return libvlc_Stopped; case VLC_PLAYER_STATE_STOPPING: return libvlc_Ended; case VLC_PLAYER_STATE_STARTED: return libvlc_Opening; case VLC_PLAYER_STATE_PLAYING: return libvlc_Playing; case VLC_PLAYER_STATE_PAUSED: return libvlc_Paused; default: vlc_assert_unreachable(); } } bool libvlc_media_player_is_seekable(libvlc_media_player_t *p_mi) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); bool b_seekable = vlc_player_CanSeek(player); vlc_player_Unlock(player); return b_seekable; } void libvlc_media_player_navigate( libvlc_media_player_t* p_mi, unsigned navigate ) { static const enum vlc_player_nav map[] = { VLC_PLAYER_NAV_ACTIVATE, VLC_PLAYER_NAV_UP, VLC_PLAYER_NAV_DOWN, VLC_PLAYER_NAV_LEFT, VLC_PLAYER_NAV_RIGHT, VLC_PLAYER_NAV_POPUP, }; if( navigate >= sizeof(map) / sizeof(map[0]) ) return; vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_Navigate(player, map[navigate]); vlc_player_Unlock(player); } /* internal function, used by audio, video */ libvlc_track_description_t * libvlc_get_track_description( libvlc_media_player_t *p_mi, enum es_format_category_e cat ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); libvlc_track_description_t *ret, **pp = &ret; size_t count = vlc_player_GetTrackCount(player, cat); for (size_t i = 0; i < count; i++) { libvlc_track_description_t *tr = malloc(sizeof (*tr)); if (unlikely(tr == NULL)) { libvlc_printerr("Not enough memory"); continue; } const struct vlc_player_track *track = vlc_player_GetTrackAt(player, cat, i); *pp = tr; tr->i_id = vlc_es_id_GetInputId(track->es_id); tr->psz_name = strdup(track->name); if (unlikely(!tr->psz_name)) { free(tr); continue; } pp = &tr->p_next; } *pp = NULL; vlc_player_Unlock(player); return ret; } void libvlc_track_description_list_release( libvlc_track_description_t *p_td ) { libvlc_track_description_t *p_actual, *p_before; p_actual = p_td; while ( p_actual ) { free( p_actual->psz_name ); p_before = p_actual; p_actual = p_before->p_next; free( p_before ); } } bool libvlc_media_player_can_pause(libvlc_media_player_t *p_mi) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); bool b_can_pause = vlc_player_CanPause(player); vlc_player_Unlock(player); return b_can_pause; } bool libvlc_media_player_program_scrambled(libvlc_media_player_t *p_mi) { bool b_program_scrambled = false; vlc_player_t *player = p_mi->player; vlc_player_Lock(player); const struct vlc_player_program *program = vlc_player_GetSelectedProgram(player); if (!program) goto end; b_program_scrambled = program->scrambled; vlc_player_Unlock(player); end: return b_program_scrambled; } void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); vlc_player_NextVideoFrame(player); vlc_player_Unlock(player); } /** * Private lookup table to get subpicture alignment flag values corresponding * to a libvlc_position_t enumerated value. */ static const unsigned char position_subpicture_alignment[] = { [libvlc_position_center] = 0, [libvlc_position_left] = SUBPICTURE_ALIGN_LEFT, [libvlc_position_right] = SUBPICTURE_ALIGN_RIGHT, [libvlc_position_top] = SUBPICTURE_ALIGN_TOP, [libvlc_position_top_left] = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT, [libvlc_position_top_right] = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT, [libvlc_position_bottom] = SUBPICTURE_ALIGN_BOTTOM, [libvlc_position_bottom_left] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT, [libvlc_position_bottom_right] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT }; void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, libvlc_position_t position, unsigned timeout ) { assert( position >= libvlc_position_disable && position <= libvlc_position_bottom_right ); if ( position != libvlc_position_disable ) { var_SetBool( p_mi, "video-title-show", true ); var_SetInteger( p_mi, "video-title-position", position_subpicture_alignment[position] ); var_SetInteger( p_mi, "video-title-timeout", timeout ); } else { var_SetBool( p_mi, "video-title-show", false ); } } int libvlc_media_player_add_slave( libvlc_media_player_t *p_mi, libvlc_media_slave_type_t i_type, const char *psz_uri, bool b_select ) { vlc_player_t *player = p_mi->player; vlc_player_Lock(player); enum es_format_category_e cat = i_type == libvlc_media_slave_type_subtitle ? SPU_ES : AUDIO_ES; int ret = vlc_player_AddAssociatedMedia(player, cat, psz_uri, b_select, false, false); vlc_player_Unlock(player); return ret; } /** * Maximum size of a formatted equalizer amplification band frequency value. * * The allowed value range is supposed to be constrained from -20.0 to 20.0. * * The format string " %.07f" with a minimum value of "-20" gives a maximum * string length of e.g. " -19.1234567", i.e. 12 bytes (not including the null * terminator). */ #define EQZ_BAND_VALUE_SIZE 12 int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer ) { char bands[EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1]; if( p_equalizer != NULL ) { for( unsigned i = 0, c = 0; i < EQZ_BANDS_MAX; i++ ) { c += snprintf( bands + c, sizeof(bands) - c, " %.07f", p_equalizer->f_amp[i] ); if( unlikely(c >= sizeof(bands)) ) return -1; } var_SetFloat( p_mi, "equalizer-preamp", p_equalizer->f_preamp ); var_SetString( p_mi, "equalizer-bands", bands ); } var_SetString( p_mi, "audio-filter", p_equalizer ? "equalizer" : "" ); audio_output_t *p_aout = vlc_player_aout_Hold( p_mi->player ); if( p_aout != NULL ) { if( p_equalizer != NULL ) { var_SetFloat( p_aout, "equalizer-preamp", p_equalizer->f_preamp ); var_SetString( p_aout, "equalizer-bands", bands ); } var_SetString( p_aout, "audio-filter", p_equalizer ? "equalizer" : "" ); aout_Release(p_aout); } return 0; } static const char roles[][16] = { [libvlc_role_Music] = "music", [libvlc_role_Video] = "video", [libvlc_role_Communication] = "communication", [libvlc_role_Game] = "game", [libvlc_role_Notification] = "notification", [libvlc_role_Animation] = "animation", [libvlc_role_Production] = "production", [libvlc_role_Accessibility] = "accessibility", [libvlc_role_Test] = "test", }; int libvlc_media_player_set_role(libvlc_media_player_t *mp, unsigned role) { if (role >= ARRAY_SIZE(roles) || var_SetString(mp, "role", roles[role]) != VLC_SUCCESS) return -1; return 0; } int libvlc_media_player_get_role(libvlc_media_player_t *mp) { int ret = -1; char *str = var_GetString(mp, "role"); if (str == NULL) return 0; for (size_t i = 0; i < ARRAY_SIZE(roles); i++) if (!strcmp(roles[i], str)) { ret = i; break; } free(str); return ret; } #include /* make sure surface structures from libvlc can be passed as such to vlc otherwise we will need wrappers between what libvlc understands and what vlc uses */ #define cast_ libvlc_video_color_space_t static_assert(libvlc_video_colorspace_BT601 == (cast_)COLOR_SPACE_BT601 && libvlc_video_colorspace_BT709 == (cast_)COLOR_SPACE_BT709 && libvlc_video_colorspace_BT2020 == (cast_)COLOR_SPACE_BT2020 , "libvlc video colorspace mismatch"); #undef cast_ #define cast_ libvlc_video_transfer_func_t static_assert(libvlc_video_transfer_func_LINEAR == (cast_)TRANSFER_FUNC_LINEAR && libvlc_video_transfer_func_SRGB == (cast_)TRANSFER_FUNC_SRGB && libvlc_video_transfer_func_BT470_BG == (cast_)TRANSFER_FUNC_BT470_BG && libvlc_video_transfer_func_BT470_M == (cast_)TRANSFER_FUNC_BT470_M && libvlc_video_transfer_func_BT709 == (cast_)TRANSFER_FUNC_BT709 && libvlc_video_transfer_func_PQ == (cast_)TRANSFER_FUNC_SMPTE_ST2084 && libvlc_video_transfer_func_SMPTE_240 == (cast_)TRANSFER_FUNC_SMPTE_240 && libvlc_video_transfer_func_HLG == (cast_)TRANSFER_FUNC_HLG , "libvlc video transfer function mismatch"); #undef cast_ #define cast_ libvlc_video_color_primaries_t static_assert(libvlc_video_primaries_BT601_525 == (cast_)COLOR_PRIMARIES_BT601_525 && libvlc_video_primaries_BT601_625 == (cast_)COLOR_PRIMARIES_BT601_625 && libvlc_video_primaries_BT709 == (cast_)COLOR_PRIMARIES_BT709 && libvlc_video_primaries_BT2020 == (cast_)COLOR_PRIMARIES_BT2020 && libvlc_video_primaries_DCI_P3 == (cast_)COLOR_PRIMARIES_DCI_P3 && libvlc_video_primaries_BT470_M == (cast_)COLOR_PRIMARIES_BT470_M , "libvlc video color primaries mismatch"); #undef cast_