static int LoopInput( playlist_t *p_playlist ) { playlist_private_t *p_sys = pl_priv(p_playlist); input_thread_t *p_input = p_sys->p_input; if( !p_input ) return VLC_EGENERIC; if( ( p_sys->request.b_request || !vlc_object_alive( p_playlist ) ) && !p_input->b_die ) { PL_DEBUG( "incoming request - stopping current input" ); input_Stop( p_input, true ); } /* This input is dead. Remove it ! */ if( p_input->b_dead ) { PL_DEBUG( "dead input" ); PL_UNLOCK; /* We can unlock as we return VLC_EGENERIC (no event will be lost) */ /* input_resource_t must be manipulated without playlist lock */ if( !var_CreateGetBool( p_input, "sout-keep" ) ) input_resource_TerminateSout( p_sys->p_input_resource ); /* The DelCallback must be issued without playlist lock */ var_DelCallback( p_input, "intf-event", InputEvent, p_playlist ); PL_LOCK; p_sys->p_input = NULL; input_Close( p_input ); UpdateActivity( p_playlist, -DEFAULT_INPUT_ACTIVITY ); return VLC_EGENERIC; } /* This input is dying, let it do */ else if( p_input->b_die ) { PL_DEBUG( "dying input" ); } /* This input has finished, ask it to die ! */ else if( p_input->b_error || p_input->b_eof ) { PL_DEBUG( "finished input" ); input_Stop( p_input, false ); } return VLC_SUCCESS; }
/* Enqueue an item for preparsing, and play it, if needed */ static void GoAndPreparse( playlist_t *p_playlist, int i_mode, playlist_item_t *p_item ) { playlist_private_t *sys = pl_priv(p_playlist); PL_ASSERT_LOCKED; if( (i_mode & PLAYLIST_GO ) ) { sys->request.b_request = true; sys->request.i_skip = 0; sys->request.p_item = p_item; if( sys->p_input != NULL ) input_Stop( sys->p_input ); vlc_cond_signal( &sys->signal ); } /* Preparse if no artist/album info, and hasn't been preparsed already and if user has some preparsing option (auto-preparse variable) enabled*/ char *psz_artist = input_item_GetArtist( p_item->p_input ); char *psz_album = input_item_GetAlbum( p_item->p_input ); if( sys->b_preparse && !input_item_IsPreparsed( p_item->p_input ) && (EMPTY_STR(psz_artist) || EMPTY_STR(psz_album)) ) libvlc_MetadataRequest( p_playlist->obj.libvlc, p_item->p_input, 0, -1, NULL ); free( psz_artist ); free( psz_album ); }
/* * Release the associated input thread. * * Object lock is NOT held. * Input lock is held or instance is being destroyed. */ static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort ) { assert( p_mi ); input_thread_t *p_input_thread = p_mi->input.p_thread; if( !p_input_thread ) return; var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi ); var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi ); var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi ); /* We owned this one */ input_Stop( p_input_thread, b_input_abort ); vlc_thread_join( p_input_thread ); assert( p_input_thread->b_dead ); p_mi->input.p_thread = NULL; vlc_object_release( p_input_thread ); }
void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused ) { input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi ); if( !p_input_thread ) return; libvlc_state_t state = libvlc_media_player_get_state( p_mi ); if( state == libvlc_Playing || state == libvlc_Buffering ) { if( paused ) { if( libvlc_media_player_can_pause( p_mi ) ) input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S ); else input_Stop( p_input_thread, true ); } } else { if( !paused ) input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S ); } vlc_object_release( p_input_thread ); }
/***************************************************************************** * Close: *****************************************************************************/ static void Close( vlc_object_t *p_this ) { services_discovery_t *p_sd = ( services_discovery_t* )p_this; services_discovery_sys_t *p_sys = p_sd->p_sys; int i; vlc_cancel (p_sys->thread); vlc_join (p_sys->thread, NULL); var_DelCallback( p_sd, "podcast-urls", UrlsChange, p_sys ); var_DelCallback( p_sd, "podcast-request", Request, p_sys ); vlc_cond_destroy( &p_sys->wait ); vlc_mutex_destroy( &p_sys->lock ); for( i = 0; i < p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; if( !p_input ) continue; input_Stop( p_input, true ); vlc_thread_join( p_input ); vlc_object_release( p_input ); p_sd->p_sys->pp_input[i] = NULL; } free( p_sd->p_sys->pp_input ); for( i = 0; i < p_sys->i_urls; i++ ) free( p_sys->ppsz_urls[i] ); free( p_sys->ppsz_urls ); for( i = 0; i < p_sys->i_items; i++ ) vlc_gc_decref( p_sys->pp_items[i] ); free( p_sys->pp_items ); free( p_sys->psz_request ); free( p_sys ); }
/* Enqueue an item for preparsing, and play it, if needed */ static void GoAndPreparse( playlist_t *p_playlist, int i_mode, playlist_item_t *p_item ) { PL_ASSERT_LOCKED; if( (i_mode & PLAYLIST_GO ) ) { pl_priv(p_playlist)->request.b_request = true; pl_priv(p_playlist)->request.i_skip = 0; pl_priv(p_playlist)->request.p_item = p_item; if( pl_priv(p_playlist)->p_input ) input_Stop( pl_priv(p_playlist)->p_input, true ); pl_priv(p_playlist)->request.i_status = PLAYLIST_RUNNING; vlc_cond_signal( &pl_priv(p_playlist)->signal ); } /* Preparse if no artist/album info, and hasn't been preparsed allready and if user has some preparsing option (auto-preparse variable) enabled*/ char *psz_artist = input_item_GetArtist( p_item->p_input ); char *psz_album = input_item_GetAlbum( p_item->p_input ); if( pl_priv(p_playlist)->b_auto_preparse && input_item_IsPreparsed( p_item->p_input ) == false && ( EMPTY_STR( psz_artist ) || ( EMPTY_STR( psz_album ) ) ) ) libvlc_MetaRequest( p_playlist->p_libvlc, p_item->p_input ); free( psz_artist ); free( psz_album ); }
static void LoopInput( playlist_t *p_playlist ) { playlist_private_t *p_sys = pl_priv(p_playlist); input_thread_t *p_input = p_sys->p_input; assert( p_input != NULL ); if( p_sys->request.b_request || p_sys->killed ) { PL_DEBUG( "incoming request - stopping current input" ); input_Stop( p_input, true ); } #warning Unsynchronized access to *p_input flags... /* This input is dead. Remove it ! */ if( p_input->b_dead ) { p_sys->p_input = NULL; PL_DEBUG( "dead input" ); PL_UNLOCK; var_SetAddress( p_playlist, "input-current", NULL ); /* WARNING: Input resource manipulation and callback deletion are * incompatible with the playlist lock. */ if( !var_InheritBool( p_input, "sout-keep" ) ) input_resource_TerminateSout( p_sys->p_input_resource ); var_DelCallback( p_input, "intf-event", InputEvent, p_playlist ); input_Close( p_input ); var_TriggerCallback( p_playlist, "activity" ); PL_LOCK; return; } /* This input has finished, ask it to die ! */ else if( p_input->b_error || p_input->b_eof ) { PL_DEBUG( "finished input" ); input_Stop( p_input, false ); } vlc_cond_wait( &p_sys->signal, &p_sys->lock ); }
static void cancelDoFingerprint( void *p_arg ) { fingerprinter_sys_t *p_sys = ( fingerprinter_sys_t * ) p_arg; if ( p_sys->p_input ) { input_Stop( p_sys->p_input, true ); input_Close( p_sys->p_input ); } /* cleanup temporary result */ if ( p_sys->chroma_fingerprint.psz_fingerprint ) FREENULL( p_sys->chroma_fingerprint.psz_fingerprint ); if ( p_sys->p_item ) input_item_Release( p_sys->p_item ); }
/***************************************************************************** * Run: main thread *****************************************************************************/ static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char* psz_urls = var_GetNonEmptyString( p_sd, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) { ParseRequest( p_sd ); } p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; if( p_input->b_eof || p_input->b_error ) { input_Stop( p_input, false ); vlc_thread_join( p_input ); vlc_object_release( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); assert(0); /* dead code */ }
/***************************************************************************** * Run: main thread *****************************************************************************/ VLC_NORETURN static void *Run( void *data ) { services_discovery_t *p_sd = data; services_discovery_sys_t *p_sys = p_sd->p_sys; vlc_mutex_lock( &p_sys->lock ); mutex_cleanup_push( &p_sys->lock ); for( ;; ) { while( !p_sys->b_update ) vlc_cond_wait( &p_sys->wait, &p_sys->lock ); int canc = vlc_savecancel (); msg_Dbg( p_sd, "Update required" ); if( p_sys->update_type == UPDATE_URLS ) { char *psz_urls = var_GetNonEmptyString( p_sd->p_parent, "podcast-urls" ); ParseUrls( p_sd, psz_urls ); free( psz_urls ); } else if( p_sys->update_type == UPDATE_REQUEST ) ParseRequest( p_sd ); p_sys->b_update = false; for( int i = 0; i < p_sd->p_sys->i_input; i++ ) { input_thread_t *p_input = p_sd->p_sys->pp_input[i]; int state = var_GetInteger( p_input, "state" ); if( state == END_S || state == ERROR_S ) { input_Stop( p_input ); input_Close( p_input ); p_sd->p_sys->pp_input[i] = NULL; REMOVE_ELEM( p_sys->pp_input, p_sys->i_input, i ); i--; } } vlc_restorecancel (canc); } vlc_cleanup_pop(); vlc_assert_unreachable(); /* dead code */ }
/** * 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 void PreparserCloseInput( void* preparser_, void* task_ ) { input_preparser_task_t* task = task_; input_preparser_req_t *req = task->req; input_preparser_t* preparser = preparser_; input_thread_t* input = task->input; input_item_t* item = input_priv(task->input)->p_item; int status; switch( atomic_load( &task->state ) ) { case END_S: status = ITEM_PREPARSE_DONE; break; case ERROR_S: status = ITEM_PREPARSE_FAILED; break; default: status = ITEM_PREPARSE_TIMEOUT; } input_Stop( input ); input_Close( input ); if( preparser->fetcher ) { task->preparse_status = status; if (!input_fetcher_Push(preparser->fetcher, item, 0, &input_fetcher_callbacks, task)) { ReqHold(task->req); return; } } free(task); input_item_SetPreparsed( item, true ); if (req->cbs && req->cbs->on_preparse_ended) req->cbs->on_preparse_ended(req->item, status, req->userdata); }
static void LoopInput( playlist_t *p_playlist ) { playlist_private_t *p_sys = pl_priv(p_playlist); input_thread_t *p_input = p_sys->p_input; assert( p_input != NULL ); if( p_sys->request.b_request || p_sys->killed ) { PL_DEBUG( "incoming request - stopping current input" ); input_Stop( p_input ); } switch( var_GetInteger( p_input, "state" ) ) { case END_S: case ERROR_S: /* This input is dead. Remove it ! */ p_sys->p_input = NULL; PL_DEBUG( "dead input" ); PL_UNLOCK; var_SetAddress( p_playlist, "input-current", NULL ); /* WARNING: Input resource manipulation and callback deletion are * incompatible with the playlist lock. */ if( !var_InheritBool( p_input, "sout-keep" ) ) input_resource_TerminateSout( p_sys->p_input_resource ); var_DelCallback( p_input, "intf-event", InputEvent, p_playlist ); input_Close( p_input ); PL_LOCK; break; default: vlc_cond_wait( &p_sys->signal, &p_sys->lock ); } }
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( ); }