/************************************************************************** * 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; } 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, "program-scrambled", input_scrambled_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, "program-scrambled", input_scrambled_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; }
/** * Start the input for an item * * \param p_playlist the playlist object * \param p_item the item to play * \return nothing */ static void 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_item->i_nb_played++; set_current_status_item( p_playlist, p_item ); p_sys->status.i_status = PLAYLIST_RUNNING; assert( p_sys->p_input == NULL ); PL_UNLOCK; input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL, p_sys->p_input_resource ); if( likely(p_input_thread != NULL) ) { var_AddCallback( p_input_thread, "intf-event", InputEvent, p_playlist ); if( input_Start( p_input_thread ) ) { var_DelCallback( p_input_thread, "intf-event", InputEvent, p_playlist ); vlc_object_release( p_input_thread ); p_input_thread = NULL; } } var_SetAddress( p_playlist, "input-current", p_input_thread ); /* TODO store art policy in playlist private data */ char *psz_arturl = input_item_GetArtURL( p_input ); /* p_input->p_meta should not be null after a successful CreateThread */ bool b_has_art = !EMPTY_STR( psz_arturl ); if( !b_has_art || strncmp( psz_arturl, "attachment://", 13 ) ) { PL_DEBUG( "requesting art for new input thread" ); libvlc_ArtRequest( p_playlist->p_libvlc, p_input, META_REQUEST_OPTION_NONE ); } free( psz_arturl ); var_TriggerCallback( p_playlist, "activity" ); PL_LOCK; p_sys->p_input = p_input_thread; }
/** * This function preparses an item when needed. */ static void Preparse( playlist_preparser_t *preparser, input_item_t *p_item, input_item_meta_request_option_t i_options ) { vlc_mutex_lock( &p_item->lock ); int i_type = p_item->i_type; bool b_net = p_item->b_net; vlc_mutex_unlock( &p_item->lock ); bool b_preparse = false; switch (i_type) { case ITEM_TYPE_FILE: case ITEM_TYPE_DIRECTORY: case ITEM_TYPE_PLAYLIST: case ITEM_TYPE_NODE: if (!b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK) b_preparse = true; break; } /* Do not preparse if it is already done (like by playing it) */ if( b_preparse && !input_item_IsPreparsed( p_item ) ) { input_thread_t *input = input_CreatePreparser( preparser->object, p_item ); if( input == NULL ) return; var_AddCallback( input, "intf-event", InputEvent, &preparser->item_done ); if( input_Start( input ) == VLC_SUCCESS ) vlc_sem_wait( &preparser->item_done ); var_DelCallback( input, "intf-event", InputEvent, &preparser->item_done ); /* Normally, the input is already stopped since we waited for it. But * if the playlist preparser is being deleted, then the input might * still be running. Force it to stop. */ input_Stop( input ); input_Close( input ); var_SetAddress( preparser->object, "item-change", p_item ); } input_item_SetPreparsed( p_item, true ); input_item_SignalPreparseEnded( p_item ); }
static int PreparserOpenInput( void* preparser_, void* req_, void** out ) { input_preparser_t* preparser = preparser_; input_preparser_req_t *req = req_; input_preparser_task_t* task = malloc( sizeof *task ); if( unlikely( !task ) ) goto error; atomic_init( &task->state, INIT_S ); atomic_init( &task->done, false ); task->preparser = preparser_; task->input = input_CreatePreparser( preparser->owner, InputEvent, task, req->item ); if( !task->input ) goto error; task->req = req; task->preparse_status = -1; if( input_Start( task->input ) ) { input_Close( task->input ); goto error; } *out = task; return VLC_SUCCESS; error: free( task ); if (req->cbs && req->cbs->on_preparse_ended) req->cbs->on_preparse_ended(req->item, ITEM_PREPARSE_FAILED, req->userdata); return VLC_EGENERIC; }
/** * 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; }
/** * 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; assert( p_sys->p_input == NULL ); 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; } } bool b_find_art = var_GetInteger( p_playlist, "album-art" ) == ALBUM_ART_WHEN_PLAYED; if( b_find_art ) { char *psz_uri = input_item_GetURI( p_item->p_input ); if( psz_uri != NULL && (!strncmp( psz_uri, "directory:", 10 ) || !strncmp( psz_uri, "vlc:", 4 )) ) b_find_art = false; free( psz_uri ); } /* TODO store art policy in playlist private data */ if( b_find_art ) { char *psz_arturl = input_item_GetArtURL( p_input ); char *psz_name = input_item_GetName( p_input ); /* p_input->p_meta should not be null after a successful CreateThread */ bool b_has_art = !EMPTY_STR( psz_arturl ); if( !b_has_art || strncmp( psz_arturl, "attachment://", 13 ) ) { PL_DEBUG( "requesting art for %s", psz_name ); libvlc_ArtRequest( p_playlist->p_libvlc, p_input ); } free( psz_arturl ); free( psz_name ); } PL_UNLOCK; var_TriggerCallback( p_playlist, "activity" ); PL_LOCK; return VLC_SUCCESS; }
static void DoFingerprint( fingerprinter_thread_t *p_fingerprinter, acoustid_fingerprint_t *fp, const char *psz_uri ) { input_item_t *p_item = input_item_New( NULL, NULL ); if ( unlikely(p_item == NULL) ) return; char *psz_sout_option; /* Note: need at -max- 2 channels, but we can't guess it before playing */ /* the stereo upmix could make the mono tracks fingerprint to differ :/ */ if ( asprintf( &psz_sout_option, "sout=#transcode{acodec=%s,channels=2}:chromaprint", ( VLC_CODEC_S16L == VLC_CODEC_S16N ) ? "s16l" : "s16b" ) == -1 ) { input_item_Release( p_item ); return; } input_item_AddOption( p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); input_item_AddOption( p_item, "vout=dummy", VLC_INPUT_OPTION_TRUSTED ); input_item_AddOption( p_item, "aout=dummy", VLC_INPUT_OPTION_TRUSTED ); if ( fp->i_duration ) { if ( asprintf( &psz_sout_option, "stop-time=%u", fp->i_duration ) == -1 ) { input_item_Release( p_item ); return; } input_item_AddOption( p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); } input_item_SetURI( p_item, psz_uri ) ; input_thread_t *p_input = input_Create( p_fingerprinter, p_item, "fingerprinter", NULL, NULL ); input_item_Release( p_item ); if( p_input == NULL ) return; chromaprint_fingerprint_t chroma_fingerprint; chroma_fingerprint.psz_fingerprint = NULL; chroma_fingerprint.i_duration = fp->i_duration; var_Create( p_input, "fingerprint-data", VLC_VAR_ADDRESS ); var_SetAddress( p_input, "fingerprint-data", &chroma_fingerprint ); var_AddCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys ); if( input_Start( p_input ) != VLC_SUCCESS ) { var_DelCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys ); input_Close( p_input ); } else { p_fingerprinter->p_sys->processing.b_working = true; while( p_fingerprinter->p_sys->processing.b_working ) { vlc_cond_wait( &p_fingerprinter->p_sys->processing.cond, &p_fingerprinter->p_sys->processing.lock ); } var_DelCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys ); input_Stop( p_input ); input_Close( p_input ); fp->psz_fingerprint = chroma_fingerprint.psz_fingerprint; if( !fp->i_duration ) /* had not given hint */ fp->i_duration = chroma_fingerprint.i_duration; } }
static void DoFingerprint( vlc_object_t *p_this, fingerprinter_sys_t *p_sys, acoustid_fingerprint_t *fp ) { p_sys->p_input = NULL; p_sys->p_item = NULL; p_sys->chroma_fingerprint.psz_fingerprint = NULL; vlc_cleanup_push( cancelDoFingerprint, p_sys ); p_sys->p_item = input_item_New( NULL, NULL ); if ( ! p_sys->p_item ) goto end; char *psz_sout_option; /* Note: need at -max- 2 channels, but we can't guess it before playing */ /* the stereo upmix could make the mono tracks fingerprint to differ :/ */ if ( asprintf( &psz_sout_option, "sout=#transcode{acodec=%s,channels=2}:chromaprint", ( VLC_CODEC_S16L == VLC_CODEC_S16N ) ? "s16l" : "s16b" ) == -1 ) goto end; input_item_AddOption( p_sys->p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); input_item_AddOption( p_sys->p_item, "vout=dummy", VLC_INPUT_OPTION_TRUSTED ); input_item_AddOption( p_sys->p_item, "aout=dummy", VLC_INPUT_OPTION_TRUSTED ); if ( fp->i_duration ) { if ( asprintf( &psz_sout_option, "stop-time=%u", fp->i_duration ) == -1 ) goto end; input_item_AddOption( p_sys->p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); } input_item_SetURI( p_sys->p_item, p_sys->psz_uri ) ; p_sys->p_input = input_Create( p_this, p_sys->p_item, "fingerprinter", NULL ); if ( p_sys->p_input ) { p_sys->chroma_fingerprint.i_duration = fp->i_duration; var_Create( p_sys->p_input, "fingerprint-data", VLC_VAR_ADDRESS ); var_SetAddress( p_sys->p_input, "fingerprint-data", & p_sys->chroma_fingerprint ); input_Start( p_sys->p_input ); /* Wait for input to start && end */ p_sys->condwait.i_input_state = var_GetInteger( p_sys->p_input, "state" ); if ( likely( var_AddCallback( p_sys->p_input, "intf-event", inputStateCallback, p_sys ) == VLC_SUCCESS ) ) { while( p_sys->condwait.i_input_state <= PAUSE_S ) { vlc_mutex_lock( &p_sys->condwait.lock ); mutex_cleanup_push( &p_sys->condwait.lock ); vlc_cond_wait( &p_sys->condwait.wait, &p_sys->condwait.lock ); vlc_cleanup_run(); } var_DelCallback( p_sys->p_input, "intf-event", inputStateCallback, p_sys ); } input_Stop( p_sys->p_input, true ); input_Close( p_sys->p_input ); p_sys->p_input = NULL; if ( p_sys->chroma_fingerprint.psz_fingerprint ) { fp->psz_fingerprint = strdup( p_sys->chroma_fingerprint.psz_fingerprint ); if ( ! fp->i_duration ) /* had not given hint */ fp->i_duration = p_sys->chroma_fingerprint.i_duration; } } end: vlc_cleanup_run( ); }