/***************************************************************************** * 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 ); input_Close( 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 ); }
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; }
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 *****************************************************************************/ 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, "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 ); 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(); assert(0); /* 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 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 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); }
/* * 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; p_mi->input.p_thread = NULL; 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 ); input_Close( p_input_thread ); }
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; }
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( ); }