/************************************************************************** * Tell media player to start playing. **************************************************************************/ int libvlc_media_player_play( libvlc_media_player_t *p_mi ) { lock_input( p_mi ); input_thread_t *p_input_thread = p_mi->input.p_thread; if( p_input_thread ) { /* A thread already exists, send it a play message */ input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S ); unlock_input( p_mi ); return 0; } /* Ignore previous exception */ lock(p_mi); if( !p_mi->p_md ) { unlock(p_mi); unlock_input( p_mi ); libvlc_printerr( "No associated media descriptor" ); return -1; } if( !p_mi->input.p_resource ) p_mi->input.p_resource = input_resource_New( VLC_OBJECT( p_mi ) ); p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL, p_mi->input.p_resource ); unlock(p_mi); if( !p_input_thread ) { unlock_input(p_mi); libvlc_printerr( "Not enough memory" ); return -1; } var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi ); var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi ); var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi ); if( input_Start( p_input_thread ) ) { unlock_input(p_mi); var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi ); var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi ); var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi ); vlc_object_release( p_input_thread ); libvlc_printerr( "Input initialization failure" ); return -1; } p_mi->input.p_thread = p_input_thread; unlock_input(p_mi); return 0; }
/** * Create playlist * * Create a playlist structure. * \param p_parent the vlc object that is to be the parent of this playlist * \return a pointer to the created playlist, or NULL on error */ static playlist_t *playlist_Create( vlc_object_t *p_parent ) { playlist_t *p_playlist; playlist_private_t *p; /* Allocate structure */ p = vlc_custom_create( p_parent, sizeof( *p ), "playlist" ); if( !p ) return NULL; assert( offsetof( playlist_private_t, public_data ) == 0 ); p_playlist = &p->public_data; TAB_INIT( pl_priv(p_playlist)->i_sds, pl_priv(p_playlist)->pp_sds ); VariablesInit( p_playlist ); vlc_mutex_init( &p->lock ); vlc_cond_init( &p->signal ); p->killed = false; /* Initialise data structures */ pl_priv(p_playlist)->i_last_playlist_id = 0; pl_priv(p_playlist)->p_input = NULL; ARRAY_INIT( p_playlist->items ); ARRAY_INIT( p_playlist->all_items ); ARRAY_INIT( pl_priv(p_playlist)->items_to_delete ); ARRAY_INIT( p_playlist->current ); p_playlist->i_current_index = 0; pl_priv(p_playlist)->b_reset_currently_playing = true; pl_priv(p_playlist)->b_tree = var_InheritBool( p_parent, "playlist-tree" ); pl_priv(p_playlist)->b_doing_ml = false; pl_priv(p_playlist)->b_auto_preparse = var_InheritBool( p_parent, "auto-preparse" ); /* Preparser (and meta retriever) */ p->p_preparser = playlist_preparser_New( VLC_OBJECT(p_playlist) ); if( unlikely(p->p_preparser == NULL) ) msg_Err( p_playlist, "cannot create preparser" ); /* Create the root node */ PL_LOCK; p_playlist->p_root = playlist_NodeCreate( p_playlist, NULL, NULL, PLAYLIST_END, 0, NULL ); PL_UNLOCK; if( !p_playlist->p_root ) return NULL; /* Create currently playing items node */ PL_LOCK; p_playlist->p_playing = playlist_NodeCreate( p_playlist, _( "Playlist" ), p_playlist->p_root, PLAYLIST_END, PLAYLIST_RO_FLAG, NULL ); PL_UNLOCK; if( !p_playlist->p_playing ) return NULL; /* Create media library node */ const bool b_ml = var_InheritBool( p_parent, "media-library"); if( b_ml ) { PL_LOCK; p_playlist->p_media_library = playlist_NodeCreate( p_playlist, _( "Media Library" ), p_playlist->p_root, PLAYLIST_END, PLAYLIST_RO_FLAG, NULL ); PL_UNLOCK; } else { p_playlist->p_media_library = NULL; } p_playlist->p_root_category = p_playlist->p_root; p_playlist->p_root_onelevel = p_playlist->p_root; p_playlist->p_local_category = p_playlist->p_playing; p_playlist->p_local_onelevel = p_playlist->p_playing; p_playlist->p_ml_category = p_playlist->p_media_library; p_playlist->p_ml_onelevel = p_playlist->p_media_library;; /* Initial status */ pl_priv(p_playlist)->status.p_item = NULL; pl_priv(p_playlist)->status.p_node = p_playlist->p_playing; pl_priv(p_playlist)->request.b_request = false; pl_priv(p_playlist)->status.i_status = PLAYLIST_STOPPED; if(b_ml) { const bool b_auto_preparse = pl_priv(p_playlist)->b_auto_preparse; pl_priv(p_playlist)->b_auto_preparse = false; playlist_MLLoad( p_playlist ); pl_priv(p_playlist)->b_auto_preparse = b_auto_preparse; } /* Input resources */ p->p_input_resource = input_resource_New( VLC_OBJECT( p_playlist ) ); if( unlikely(p->p_input_resource == NULL) ) abort(); /* Audio output (needed for volume and device controls). */ audio_output_t *aout = input_resource_GetAout( p->p_input_resource ); if( aout != NULL ) input_resource_PutAout( p->p_input_resource, aout ); /* Thread */ playlist_Activate (p_playlist); /* Add service discovery modules */ char *mods = var_InheritString( p_playlist, "services-discovery" ); if( mods != NULL ) { char *p = mods, *m; while( (m = strsep( &p, " :," )) != NULL ) playlist_ServicesDiscoveryAdd( p_playlist, m ); free( mods ); } return p_playlist; }
/** * Start the input for an item * * \param p_playlist the playlist object * \param p_item the item to play * \return nothing */ static int PlayItem( playlist_t *p_playlist, playlist_item_t *p_item ) { playlist_private_t *p_sys = pl_priv(p_playlist); input_item_t *p_input = p_item->p_input; PL_ASSERT_LOCKED; msg_Dbg( p_playlist, "creating new input thread" ); p_input->i_nb_played++; set_current_status_item( p_playlist, p_item ); p_sys->status.i_status = PLAYLIST_RUNNING; UpdateActivity( p_playlist, DEFAULT_INPUT_ACTIVITY ); assert( p_sys->p_input == NULL ); if( !p_sys->p_input_resource ) p_sys->p_input_resource = input_resource_New( VLC_OBJECT( p_playlist ) ); input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL, p_sys->p_input_resource ); if( p_input_thread ) { p_sys->p_input = p_input_thread; var_AddCallback( p_input_thread, "intf-event", InputEvent, p_playlist ); var_SetAddress( p_playlist, "input-current", p_input_thread ); if( input_Start( p_sys->p_input ) ) { vlc_object_release( p_input_thread ); p_sys->p_input = p_input_thread = NULL; } } char *psz_uri = input_item_GetURI( p_item->p_input ); if( psz_uri && ( !strncmp( psz_uri, "directory:", 10 ) || !strncmp( psz_uri, "vlc:", 4 ) ) ) { free( psz_uri ); return VLC_SUCCESS; } free( psz_uri ); /* TODO store art policy in playlist private data */ if( var_GetInteger( p_playlist, "album-art" ) == ALBUM_ART_WHEN_PLAYED ) { bool b_has_art; char *psz_arturl, *psz_name; psz_arturl = input_item_GetArtURL( p_input ); psz_name = input_item_GetName( p_input ); /* p_input->p_meta should not be null after a successfull CreateThread */ b_has_art = !EMPTY_STR( psz_arturl ); if( !b_has_art || strncmp( psz_arturl, "attachment://", 13 ) ) { PL_DEBUG( "requesting art for %s", psz_name ); playlist_AskForArtEnqueue( p_playlist, p_input ); } free( psz_arturl ); free( psz_name ); } /* FIXME: this is not safe !!*/ PL_UNLOCK; var_SetAddress( p_playlist, "item-current", p_input ); PL_LOCK; return VLC_SUCCESS; }
/** * Create playlist * * Create a playlist structure. * \param p_parent the vlc object that is to be the parent of this playlist * \return a pointer to the created playlist, or NULL on error */ playlist_t *playlist_Create( vlc_object_t *p_parent ) { playlist_t *p_playlist; playlist_private_t *p; /* Allocate structure */ p = vlc_custom_create( p_parent, sizeof( *p ), "playlist" ); if( !p ) return NULL; assert( offsetof( playlist_private_t, public_data ) == 0 ); p_playlist = &p->public_data; TAB_INIT( pl_priv(p_playlist)->i_sds, pl_priv(p_playlist)->pp_sds ); VariablesInit( p_playlist ); vlc_mutex_init( &p->lock ); vlc_cond_init( &p->signal ); p->killed = false; /* Initialise data structures */ pl_priv(p_playlist)->i_last_playlist_id = 0; pl_priv(p_playlist)->p_input = NULL; ARRAY_INIT( p_playlist->items ); ARRAY_INIT( p_playlist->all_items ); ARRAY_INIT( pl_priv(p_playlist)->items_to_delete ); ARRAY_INIT( p_playlist->current ); p_playlist->i_current_index = 0; pl_priv(p_playlist)->b_reset_currently_playing = true; pl_priv(p_playlist)->b_tree = var_InheritBool( p_parent, "playlist-tree" ); pl_priv(p_playlist)->b_preparse = var_InheritBool( p_parent, "auto-preparse" ); /* Create the root, playing items and meida library nodes */ playlist_item_t *root, *playing, *ml; PL_LOCK; root = playlist_NodeCreate( p_playlist, NULL, NULL, PLAYLIST_END, 0, NULL ); playing = playlist_NodeCreate( p_playlist, _( "Playlist" ), root, PLAYLIST_END, PLAYLIST_RO_FLAG | PLAYLIST_NO_INHERIT_FLAG, NULL ); if( var_InheritBool( p_parent, "media-library") ) ml = playlist_NodeCreate( p_playlist, _( "Media Library" ), root, PLAYLIST_END, PLAYLIST_RO_FLAG | PLAYLIST_NO_INHERIT_FLAG, NULL ); else ml = NULL; PL_UNLOCK; if( unlikely(root == NULL || playing == NULL) ) abort(); p_playlist->p_root = root; p_playlist->p_playing = playing; p_playlist->p_media_library = ml; p_playlist->p_root_category = p_playlist->p_root; p_playlist->p_root_onelevel = p_playlist->p_root; p_playlist->p_local_category = p_playlist->p_playing; p_playlist->p_local_onelevel = p_playlist->p_playing; p_playlist->p_ml_category = p_playlist->p_media_library; p_playlist->p_ml_onelevel = p_playlist->p_media_library;; /* Initial status */ pl_priv(p_playlist)->status.p_item = NULL; pl_priv(p_playlist)->status.p_node = p_playlist->p_playing; pl_priv(p_playlist)->request.b_request = false; if (ml != NULL) playlist_MLLoad( p_playlist ); /* Input resources */ p->p_input_resource = input_resource_New( VLC_OBJECT( p_playlist ) ); if( unlikely(p->p_input_resource == NULL) ) abort(); /* Audio output (needed for volume and device controls). */ audio_output_t *aout = input_resource_GetAout( p->p_input_resource ); if( aout != NULL ) input_resource_PutAout( p->p_input_resource, aout ); /* Initialize the shared HTTP cookie jar */ vlc_value_t cookies; cookies.p_address = vlc_http_cookies_new(); if ( likely(cookies.p_address) ) { var_Create( p_playlist, "http-cookies", VLC_VAR_ADDRESS ); var_SetChecked( p_playlist, "http-cookies", VLC_VAR_ADDRESS, cookies ); } /* Thread */ playlist_Activate (p_playlist); /* Add service discovery modules */ char *mods = var_InheritString( p_playlist, "services-discovery" ); if( mods != NULL ) { char *s = mods, *m; while( (m = strsep( &s, " :," )) != NULL ) playlist_ServicesDiscoveryAdd( p_playlist, m ); free( mods ); } return p_playlist; }
/************************************************************************** * 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); /* Video */ var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT); var_Create (mp, "window", 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, "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-agl", VLC_VAR_INTEGER); var_Create (mp, "drawable-nsobject", 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); var_SetBool (mp, "autoscale", true); var_Create (mp, "scale", VLC_VAR_FLOAT); var_SetFloat (mp, "scale", 1.); var_Create (mp, "aspect-ratio", VLC_VAR_STRING); var_Create (mp, "crop", VLC_VAR_STRING); var_Create (mp, "deinterlace", VLC_VAR_INTEGER); var_Create (mp, "deinterlace-mode", VLC_VAR_STRING); var_Create (mp, "vbi-page", VLC_VAR_INTEGER); 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_INTEGER | 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, "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, "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); mp->p_md = NULL; mp->state = libvlc_NothingSpecial; mp->p_libvlc_instance = instance; mp->input.p_thread = NULL; mp->input.p_resource = input_resource_New(VLC_OBJECT(mp)); if (unlikely(mp->input.p_resource == NULL)) { vlc_object_release(mp); return NULL; } audio_output_t *aout = input_resource_GetAout(mp->input.p_resource); if( aout != NULL ) input_resource_PutAout(mp->input.p_resource, aout); vlc_mutex_init (&mp->input.lock); mp->i_refcount = 1; mp->p_event_manager = libvlc_event_manager_new(mp, instance); if (unlikely(mp->p_event_manager == NULL)) { input_resource_Release(mp->input.p_resource); vlc_object_release(mp); return NULL; } vlc_mutex_init(&mp->object_lock); register_event(mp, NothingSpecial); register_event(mp, Opening); register_event(mp, Buffering); register_event(mp, Playing); register_event(mp, Paused); register_event(mp, Stopped); register_event(mp, Forward); register_event(mp, Backward); register_event(mp, EndReached); register_event(mp, EncounteredError); register_event(mp, SeekableChanged); register_event(mp, PositionChanged); register_event(mp, TimeChanged); register_event(mp, LengthChanged); register_event(mp, TitleChanged); register_event(mp, PausableChanged); register_event(mp, Vout); register_event(mp, ScrambledChanged); /* Snapshot initialization */ register_event(mp, SnapshotTaken); register_event(mp, MediaChanged); /* 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(mp->p_libvlc, "snapshot-file", snapshot_was_taken, mp); libvlc_retain(instance); return mp; }