X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fplaylist%2Ffetcher.c;h=1551020960b071765e96530d249424554a3929b7;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=88a289c695b41c2a8ddb2ee7b8ed5ed085e76b3b;hpb=c12edba9d8189b0714197b6e50a38e3d8b6d9351;p=vlc diff --git a/src/playlist/fetcher.c b/src/playlist/fetcher.c index 88a289c695..1551020960 100644 --- a/src/playlist/fetcher.c +++ b/src/playlist/fetcher.c @@ -25,15 +25,21 @@ # include "config.h" #endif +#include + #include #include #include +#include +#include +#include +#include +#include #include "art.h" #include "fetcher.h" #include "playlist_internal.h" - /***************************************************************************** * Structures/definitions *****************************************************************************/ @@ -41,9 +47,9 @@ struct playlist_fetcher_t { playlist_t *p_playlist; - vlc_thread_t thread; vlc_mutex_t lock; vlc_cond_t wait; + bool b_live; int i_art_policy; int i_waiting; input_item_t **pp_waiting; @@ -66,44 +72,53 @@ playlist_fetcher_t *playlist_fetcher_New( playlist_t *p_playlist ) p_fetcher->p_playlist = p_playlist; vlc_mutex_init( &p_fetcher->lock ); vlc_cond_init( &p_fetcher->wait ); + p_fetcher->b_live = false; p_fetcher->i_waiting = 0; p_fetcher->pp_waiting = NULL; p_fetcher->i_art_policy = var_GetInteger( p_playlist, "album-art" ); ARRAY_INIT( p_fetcher->albums ); - if( vlc_clone( &p_fetcher->thread, Thread, p_fetcher, - VLC_THREAD_PRIORITY_LOW ) ) - { - msg_Err( p_playlist, "cannot spawn secondary preparse thread" ); - free( p_fetcher ); - return NULL; - } - return p_fetcher; } -void playlist_fetcher_Push( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) +void playlist_fetcher_Push( playlist_fetcher_t *p_fetcher, + input_item_t *p_item ) { vlc_gc_incref( p_item ); vlc_mutex_lock( &p_fetcher->lock ); INSERT_ELEM( p_fetcher->pp_waiting, p_fetcher->i_waiting, p_fetcher->i_waiting, p_item ); - vlc_cond_signal( &p_fetcher->wait ); + if( !p_fetcher->b_live ) + { + vlc_thread_t th; + + if( vlc_clone( &th, Thread, p_fetcher, VLC_THREAD_PRIORITY_LOW ) ) + msg_Err( p_fetcher->p_playlist, + "cannot spawn secondary preparse thread" ); + else + { + vlc_detach( th ); + p_fetcher->b_live = true; + } + } vlc_mutex_unlock( &p_fetcher->lock ); } void playlist_fetcher_Delete( playlist_fetcher_t *p_fetcher ) { - /* Destroy the item meta-infos fetcher */ - vlc_cancel( p_fetcher->thread ); - vlc_join( p_fetcher->thread, NULL ); - + vlc_mutex_lock( &p_fetcher->lock ); + /* Remove any left-over item, the fetcher will exit */ while( p_fetcher->i_waiting > 0 ) - { /* Any left-over unparsed item? */ + { vlc_gc_decref( p_fetcher->pp_waiting[0] ); REMOVE_ELEM( p_fetcher->pp_waiting, p_fetcher->i_waiting, 0 ); } + + while( p_fetcher->b_live ) + vlc_cond_wait( &p_fetcher->wait, &p_fetcher->lock ); + vlc_mutex_unlock( &p_fetcher->lock ); + vlc_cond_destroy( &p_fetcher->wait ); vlc_mutex_destroy( &p_fetcher->lock ); free( p_fetcher ); @@ -122,14 +137,11 @@ void playlist_fetcher_Delete( playlist_fetcher_t *p_fetcher ) */ static int FindArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) { - playlist_t *p_playlist = p_fetcher->p_playlist; - int i_ret = VLC_EGENERIC; - module_t *p_module; - char *psz_title, *psz_artist, *psz_album; + int i_ret; - psz_artist = input_item_GetArtist( p_item ); - psz_album = input_item_GetAlbum( p_item ); - psz_title = input_item_GetTitle( p_item ); + char *psz_artist = input_item_GetArtist( p_item ); + char *psz_album = input_item_GetAlbum( p_item ); + char *psz_title = input_item_GetTitle( p_item ); if( !psz_title ) psz_title = input_item_GetName( p_item ); @@ -145,7 +157,8 @@ static int FindArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) if( !strcmp( album.psz_artist, psz_artist ) && !strcmp( album.psz_album, psz_album ) ) { - msg_Dbg( p_playlist, " %s - %s has already been searched", + msg_Dbg( p_fetcher->p_playlist, + " %s - %s has already been searched", psz_artist, psz_album ); /* TODO-fenrir if we cache art filename too, we can go faster */ free( psz_artist ); @@ -186,32 +199,50 @@ static int FindArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) return 1; } - PL_LOCK; - p_playlist->p_private = p_item; + /* */ psz_album = input_item_GetAlbum( p_item ); psz_artist = input_item_GetArtist( p_item ); - psz_title = input_item_GetTitle( p_item ); - if( !psz_title ) - psz_title = input_item_GetName( p_item ); - if( psz_album && psz_artist ) { - msg_Dbg( p_playlist, "searching art for %s - %s", + msg_Dbg( p_fetcher->p_playlist, "searching art for %s - %s", psz_artist, psz_album ); } else { - msg_Dbg( p_playlist, "searching art for %s", - psz_title ); + psz_title = input_item_GetTitle( p_item ); + if( !psz_title ) + psz_title = input_item_GetName( p_item ); + + msg_Dbg( p_fetcher->p_playlist, "searching art for %s", psz_title ); + free( psz_title ); } - free( psz_title ); - p_module = module_need( p_playlist, "art finder", NULL, false ); + /* Fetch the art url */ + i_ret = VLC_EGENERIC; - if( p_module ) - i_ret = 1; - else - msg_Dbg( p_playlist, "unable to find art" ); + vlc_object_t *p_parent = VLC_OBJECT(p_fetcher->p_playlist); + art_finder_t *p_finder = + vlc_custom_create( p_parent, sizeof( *p_finder ), VLC_OBJECT_GENERIC, + "art finder" ); + if( p_finder != NULL) + { + module_t *p_module; + + vlc_object_attach( p_finder, p_parent ); + p_finder->p_item = p_item; + + p_module = module_need( p_finder, "art finder", NULL, false ); + if( p_module ) + { + module_unneed( p_finder, p_module ); + /* Try immediately if found in cache by download URL */ + if( !playlist_FindArtInCache( p_item ) ) + i_ret = 0; + else + i_ret = 1; + } + vlc_object_release( p_finder ); + } /* Record this album */ if( psz_artist && psz_album ) @@ -229,11 +260,6 @@ static int FindArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) free( psz_album ); } - if( p_module ) - module_unneed( p_playlist, p_module ); - p_playlist->p_private = NULL; - PL_UNLOCK; - return i_ret; } @@ -241,25 +267,26 @@ static int FindArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) * Download the art using the URL or an art downloaded * This function should be called only if data is not already in cache */ -static int DownloadArt( playlist_t *p_playlist, input_item_t *p_item ) +static int DownloadArt( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) { char *psz_arturl = input_item_GetArtURL( p_item ); assert( *psz_arturl ); if( !strncmp( psz_arturl , "file://", 7 ) ) { - msg_Dbg( p_playlist, "Album art is local file, no need to cache" ); + msg_Dbg( p_fetcher->p_playlist, + "Album art is local file, no need to cache" ); free( psz_arturl ); return VLC_SUCCESS; } if( !strncmp( psz_arturl , "APIC", 4 ) ) { - msg_Warn( p_playlist, "APIC fetch not supported yet" ); + msg_Warn( p_fetcher->p_playlist, "APIC fetch not supported yet" ); goto error; } - stream_t *p_stream = stream_UrlNew( p_playlist, psz_arturl ); + stream_t *p_stream = stream_UrlNew( p_fetcher->p_playlist, psz_arturl ); if( !p_stream ) goto error; @@ -269,10 +296,10 @@ static int DownloadArt( playlist_t *p_playlist, input_item_t *p_item ) { int i_read = 65536; - if( i_data + i_read <= i_data ) /* Protect gainst overflow */ + if( i_data >= INT_MAX - i_read ) break; - p_data = realloc( p_data, i_data + i_read ); + p_data = realloc_or_free( p_data, i_data + i_read ); if( !p_data ) break; @@ -290,7 +317,7 @@ static int DownloadArt( playlist_t *p_playlist, input_item_t *p_item ) if( psz_type && strlen( psz_type ) > 5 ) psz_type = NULL; /* remove extension if it's > to 4 characters */ - playlist_SaveArt( p_playlist, p_item, p_data, i_data, psz_type ); + playlist_SaveArt( p_fetcher->p_playlist, p_item, p_data, i_data, psz_type ); } free( p_data ); @@ -303,15 +330,38 @@ error: return VLC_EGENERIC; } +/** + * FetchMeta, run the "meta fetcher". They are going to do network + * connections, and gather information upon the playing media. + * (even artwork). + */ +static void FetchMeta( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) +{ + demux_meta_t *p_demux_meta = vlc_custom_create(p_fetcher->p_playlist, + sizeof(*p_demux_meta), + VLC_OBJECT_GENERIC, "demux meta" ); + if( !p_demux_meta ) + return; + + vlc_object_attach( p_demux_meta, p_fetcher->p_playlist ); + p_demux_meta->p_demux = NULL; + p_demux_meta->p_item = p_item; + + module_t *p_meta_fetcher = module_need( p_demux_meta, "meta fetcher", NULL, false ); + if( p_meta_fetcher ) + module_unneed( p_demux_meta, p_meta_fetcher ); + vlc_object_release( p_demux_meta ); +} static int InputEvent( vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); - playlist_fetcher_t *p_fetcher = p_data; + vlc_cond_t *p_cond = p_data; - if( newval.i_int == INPUT_EVENT_ITEM_META ) - vlc_cond_signal( &p_fetcher->wait ); + if( newval.i_int == INPUT_EVENT_ITEM_META || + newval.i_int == INPUT_EVENT_DEAD ) + vlc_cond_signal( p_cond ); return VLC_SUCCESS; } @@ -324,34 +374,36 @@ static int InputEvent( vlc_object_t *p_this, char const *psz_cmd, */ static void WaitPreparsed( playlist_fetcher_t *p_fetcher, input_item_t *p_item ) { - playlist_t *p_playlist = p_fetcher->p_playlist; - if( input_item_IsPreparsed( p_item ) ) return; - input_thread_t *p_input = playlist_CurrentInput( p_playlist ); + input_thread_t *p_input = playlist_CurrentInput( p_fetcher->p_playlist ); if( !p_input ) return; if( input_GetItem( p_input ) != p_item ) goto exit; - var_AddCallback( p_input, "intf-event", InputEvent, p_fetcher ); + vlc_cond_t cond; + vlc_cond_init( &cond ); + var_AddCallback( p_input, "intf-event", InputEvent, &cond ); const mtime_t i_deadline = mdate() + 500*1000; + bool b_timeout = false; - while( !p_input->b_eof && !p_input->b_error && !input_item_IsPreparsed( p_item ) ) + while( !p_input->b_eof && !p_input->b_error + && !input_item_IsPreparsed( p_item ) && !b_timeout ) { - /* A bit weird, but input_item_IsPreparsed does held the protected value */ + /* A bit weird, but input_item_IsPreparsed holds the protected value */ + /* FIXME: locking looks wrong here */ vlc_mutex_lock( &p_fetcher->lock ); - vlc_cond_timedwait( &p_fetcher->wait, &p_fetcher->lock, i_deadline ); + if( vlc_cond_timedwait( &cond, &p_fetcher->lock, i_deadline ) ) + b_timeout = true; vlc_mutex_unlock( &p_fetcher->lock ); - - if( i_deadline <= mdate() ) - break; } - var_DelCallback( p_input, "intf-event", InputEvent, p_fetcher ); + var_DelCallback( p_input, "intf-event", InputEvent, &cond ); + vlc_cond_destroy( &cond ); exit: vlc_object_release( p_input ); @@ -364,35 +416,39 @@ static void *Thread( void *p_data ) for( ;; ) { - input_item_t *p_item; + input_item_t *p_item = NULL; - /* Be sure to be cancellable before our queue is empty */ - vlc_testcancel(); - - /* */ vlc_mutex_lock( &p_fetcher->lock ); - mutex_cleanup_push( &p_fetcher->lock ); - - while( p_fetcher->i_waiting == 0 ) - vlc_cond_wait( &p_fetcher->wait, &p_fetcher->lock ); - - p_item = p_fetcher->pp_waiting[0]; - REMOVE_ELEM( p_fetcher->pp_waiting, p_fetcher->i_waiting, 0 ); - vlc_cleanup_run( ); + if( p_fetcher->i_waiting != 0 ) + { + p_item = p_fetcher->pp_waiting[0]; + REMOVE_ELEM( p_fetcher->pp_waiting, p_fetcher->i_waiting, 0 ); + } + else + { + p_fetcher->b_live = false; + vlc_cond_signal( &p_fetcher->wait ); + } + vlc_mutex_unlock( &p_fetcher->lock ); if( !p_item ) - continue; + break; /* */ - int canc = vlc_savecancel(); /* Wait that the input item is preparsed if it is being played */ WaitPreparsed( p_fetcher, p_item ); + /* Triggers "meta fetcher", eventually fetch meta on the network. + * They are identical to "meta reader" expect that may actually + * takes time. That's why they are running here. + * The result of this fetch is not cached. */ + FetchMeta( p_fetcher, p_item ); + /* Find art, and download it if needed */ int i_ret = FindArt( p_fetcher, p_item ); if( i_ret == 1 ) - i_ret = DownloadArt( p_playlist, p_item ); + i_ret = DownloadArt( p_fetcher, p_item ); /* */ char *psz_name = input_item_GetName( p_item ); @@ -400,7 +456,7 @@ static void *Thread( void *p_data ) { PL_DEBUG( "found art for %s in cache", psz_name ); input_item_SetArtFetched( p_item, true ); - var_SetInteger( p_playlist, "item-change", p_item->i_id ); + var_SetAddress( p_playlist, "item-change", p_item ); } else { @@ -409,15 +465,6 @@ static void *Thread( void *p_data ) } free( psz_name ); vlc_gc_decref( p_item ); - - vlc_restorecancel( canc ); - - int i_activity = var_GetInteger( p_playlist, "activity" ); - if( i_activity < 0 ) i_activity = 0; - /* Sleep at least 1ms */ - msleep( (i_activity+1) * 1000 ); } return NULL; } - -