- Added support for embeded cover. Demuxer just need to fill psz_arturl meta
authorLaurent Aimar <fenrir@videolan.org>
Sun, 3 Jun 2007 22:40:17 +0000 (22:40 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sun, 3 Jun 2007 22:40:17 +0000 (22:40 +0000)
field to "attachment://NAME" where NAME is an attachment filename
(returned by DEMUX_GET_ATTACHMENTS)
- Lock input_item_t every time we access p_meta fields (there is still a problem
as playlist code does not always do so...).
- Do not preparse item we have already played.
- Wait that the current playing item is meta parsed before fetching its cover.

src/input/es_out.c
src/input/input.c
src/input/input_internal.h
src/input/meta.c
src/misc/stats.c
src/playlist/control.c
src/playlist/engine.c

index 504fff8..ce3f6fe 100644 (file)
@@ -478,10 +478,12 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
     }
 
     /* Update now playing */
+    vlc_mutex_lock( &p_input->p->input.p_item->lock );
     vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta,
                             p_pgrm->psz_now_playing );
     vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta,
                            p_pgrm->psz_publisher );
+    vlc_mutex_unlock( &p_input->p->input.p_item->lock );
 
     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
 }
@@ -658,7 +660,11 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
     if( psz_provider )
     {
         if( p_sys->p_pgrm == p_pgrm )
+        {
+            vlc_mutex_lock( &p_input->p->input.p_item->lock );
             vlc_meta_SetPublisher( p_input->p->input.p_item->p_meta, psz_provider );
+            vlc_mutex_unlock( &p_input->p->input.p_item->lock );
+        }
         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_PUBLISHER), psz_provider );
     }
     for( i = 0; i < p_meta->i_extra; i++ )
@@ -666,20 +672,6 @@ static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
 
     free( psz_cat );
 }
-#define TAB_INSERT_CAST( cast, count, tab, p, index ) do { \
-    if( (count) > 0 )                                                     \
-        (tab) = cast realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
-    else                                                \
-        (tab) = cast malloc( sizeof( void ** ) );       \
-    if( (count) - (index) > 0 )                         \
-        memmove( (void**)(tab) + (index) + 1,           \
-                 (void**)(tab) + (index),               \
-                 ((count) - (index)) * sizeof(*(tab)) );\
-    (tab)[(index)] = (p);                               \
-    (count)++;                                          \
-} while(0)
-
-#define TAB_INSERT( count, tab, p, index ) TAB_INSERT_CAST( , count, tab, p, index )
 
 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
 {
@@ -785,20 +777,19 @@ static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
     if( p_pgrm->psz_now_playing )
         free( p_pgrm->psz_now_playing );
     p_pgrm->psz_now_playing = NULL;
-
     if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
-    {
         p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
-        if( p_pgrm == p_sys->p_pgrm )
-            vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, p_pgrm->psz_now_playing );
+
+    vlc_mutex_lock( &p_input->p->input.p_item->lock );
+    if( p_pgrm == p_sys->p_pgrm )
+        vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, p_pgrm->psz_now_playing );
+    vlc_mutex_unlock( &p_input->p->input.p_item->lock );
+
+    if( p_pgrm->psz_now_playing )
         input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(VLC_META_NOW_PLAYING), p_pgrm->psz_now_playing );
-    }
     else
-    {
-        if( p_pgrm == p_sys->p_pgrm )
-            vlc_meta_SetNowPlaying( p_input->p->input.p_item->p_meta, NULL );
         input_Control( p_input, INPUT_DEL_INFO, psz_cat, _(VLC_META_NOW_PLAYING) );
-    }
+
     free( psz_cat );
 }
 
index cbc5e1e..1213bdc 100644 (file)
@@ -65,7 +65,6 @@ static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
 
 static int  UpdateFromAccess( input_thread_t * );
 static int  UpdateFromDemux( input_thread_t * );
-static int  UpdateMeta( input_thread_t * );
 
 static void UpdateItemLength( input_thread_t *, int64_t i_length );
 
@@ -75,11 +74,14 @@ static input_source_t *InputSourceNew( input_thread_t *);
 static int  InputSourceInit( input_thread_t *, input_source_t *,
                              const char *, const char *psz_forced_demux );
 static void InputSourceClean( input_source_t * );
+/* TODO */
+//static void InputGetAttachments( input_thread_t *, input_source_t * );
 
 static void SlaveDemux( input_thread_t *p_input );
 static void SlaveSeek( input_thread_t *p_input );
 
-static void InputMetaUser( input_thread_t *p_input );
+static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
+static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta );
 
 static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t * );
 static void SoutKeep( sout_instance_t * );
@@ -152,7 +154,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->i_rate  = INPUT_RATE_DEFAULT;
     TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
     TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
-    p_input->p->p_meta  = NULL;
     p_input->p->p_es_out = NULL;
     p_input->p->p_sout  = NULL;
     p_input->p->b_sout_keep  = VLC_FALSE;
@@ -172,15 +173,13 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->input.b_eof = VLC_FALSE;
     p_input->p->input.i_cr_average = 0;
 
+    vlc_mutex_lock( &p_item->lock );
     if( !p_input->p->input.p_item->p_meta )
         p_input->p->input.p_item->p_meta = vlc_meta_New();
 
     if( !p_item->p_stats )
-    {
-        p_item->p_stats = (input_stats_t*)malloc( sizeof( input_stats_t ) );
-        vlc_mutex_init( p_input, &p_item->p_stats->lock );
-        stats_ReinitInputStats( p_item->p_stats );
-    }
+        p_item->p_stats = stats_NewInputStats( p_input );
+    vlc_mutex_unlock( &p_item->lock );
 
     /* No slave */
     p_input->p->i_slave = 0;
@@ -254,7 +253,9 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
 
     /* Remove 'Now playing' info as it is probably outdated */
     input_Control( p_input, INPUT_DEL_INFO, _(VLC_META_INFO_CAT), VLC_META_NOW_PLAYING );
+    vlc_mutex_lock( &p_item->lock );
     vlc_meta_SetNowPlaying( p_item->p_meta, NULL );
+    vlc_mutex_unlock( &p_item->lock );
 
     /* */
     if( p_input->b_preparsing )
@@ -898,7 +899,6 @@ static int Init( input_thread_t * p_input )
     {
         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
         UpdateItemLength( p_input, val.i_time );
-        p_input->p->input.p_item->i_duration = val.i_time;
     }
 
     /* Start title/chapter */
@@ -1120,9 +1120,10 @@ static int Init( input_thread_t * p_input )
         }
     }
 
-    p_meta = p_input->p->input.p_item->p_meta;
+    p_meta = vlc_meta_New();
     /* Get meta data from users */
-    InputMetaUser( p_input );
+    InputMetaUser( p_input, p_meta );
+
     /* Get meta data from master input */
     demux2_Control( p_input->p->input.p_demux, DEMUX_GET_META, p_meta );
 
@@ -1146,7 +1147,7 @@ static int Init( input_thread_t * p_input )
         }
     }
 
-    UpdateMeta( p_input );
+    InputUpdateMeta( p_input, p_meta );
 
     if( !p_input->b_preparsing )
     {
@@ -1846,7 +1847,7 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
 
                 if( !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
                 {
-                    vlc_meta_t *p_meta = p_input->p->input.p_item->p_meta;
+                    vlc_meta_t *p_meta;
                     int64_t i_time;
 
                     /* Add the slave */
@@ -1872,10 +1873,11 @@ static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                     }
 
                     /* Get meta (access and demux) */
+                    p_meta = vlc_meta_New();
                     access2_Control( slave->p_access, ACCESS_GET_META,
                                      p_meta );
                     demux2_Control( slave->p_demux, DEMUX_GET_META, p_meta );
-                    UpdateMeta( p_input );
+                    InputUpdateMeta( p_input, p_meta );
 
                     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave );
                 }
@@ -1980,9 +1982,9 @@ static int UpdateFromAccess( input_thread_t *p_input )
     if( p_access->info.i_update & INPUT_UPDATE_META )
     {
         /* TODO maybe multi - access ? */
-        vlc_meta_t *p_meta = p_input->p->input.p_item->p_meta;
+        vlc_meta_t *p_meta = vlc_meta_New();
         access2_Control( p_input->p->input.p_access,ACCESS_GET_META, p_meta );
-        UpdateMeta( p_input );
+        InputUpdateMeta( p_input, p_meta );
         var_SetBool( p_input, "item-change", p_input->p->input.p_item->i_id );
         p_access->info.i_update &= ~INPUT_UPDATE_META;
     }
@@ -2016,23 +2018,6 @@ static int UpdateFromAccess( input_thread_t *p_input )
     return 1;
 }
 
-/*****************************************************************************
- * UpdateMeta:
- *****************************************************************************/
-static int  UpdateMeta( input_thread_t *p_input )
-{
-    vlc_meta_t *p_meta = p_input->p->input.p_item->p_meta;
-    if( !p_meta )
-        return VLC_SUCCESS;
-
-    if( p_meta->psz_title && !p_input->p->input.p_item->b_fixed_name )
-        input_Control( p_input, INPUT_SET_NAME, p_meta->psz_title );
-
-    /** \todo handle sout meta */
-
-    return VLC_SUCCESS;
-}
-
 /*****************************************************************************
  * UpdateItemLength:
  *****************************************************************************/
@@ -2327,8 +2312,9 @@ static int InputSourceInit( input_thread_t *p_input,
                 in->b_title_demux = VLC_TRUE;
             }
         }
-        /* get attachment */
-        if( !p_input->b_preparsing )
+        /* get attachment
+         * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
+        if( 1 || !p_input->b_preparsing )
         {
             int i_attachment;
             input_attachment_t **attachment;
@@ -2472,9 +2458,8 @@ static void SlaveSeek( input_thread_t *p_input )
 /*****************************************************************************
  * InputMetaUser:
  *****************************************************************************/
-static void InputMetaUser( input_thread_t *p_input )
+static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta )
 {
-    vlc_meta_t *p_meta = p_input->p->input.p_item->p_meta;
     vlc_value_t val;
 
     if( !p_meta ) return;
@@ -2498,6 +2483,60 @@ static void InputMetaUser( input_thread_t *p_input )
 #undef GET_META
 }
 
+/*****************************************************************************
+ * InputUpdateMeta: merge p_item meta data with p_meta taking care of
+ * arturl and locking issue.
+ *****************************************************************************/
+static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta )
+{
+    input_item_t *p_item = p_input->p->input.p_item;
+    char *psz_title = NULL;
+
+    if( !p_meta )
+        return;
+
+    vlc_mutex_lock( &p_item->lock );
+    if( p_meta->psz_title && !p_item->b_fixed_name )
+        psz_title = strdup( p_meta->psz_title );
+
+    if( p_item->p_meta )
+    {
+        char *psz_arturl = p_item->p_meta->psz_arturl;
+        p_item->p_meta->psz_arturl = NULL;
+
+        vlc_meta_Merge( p_item->p_meta, p_meta );
+
+        if( psz_arturl && *psz_arturl )
+            vlc_meta_SetArtURL( p_item->p_meta, psz_arturl );
+
+        vlc_meta_Delete( p_meta );
+    }
+    else
+    {
+        p_item->p_meta = p_meta;
+    }
+    if( p_item->p_meta->psz_arturl && !strncmp( p_item->p_meta->psz_arturl, "attachment://", strlen("attachment") ) )
+    {
+        /* Don't look for art cover if sout
+         * XXX It can change when sout has meta data support */
+        if( p_input->p->p_sout && !p_input->b_preparsing )
+            vlc_meta_SetArtURL( p_item->p_meta, "" );
+        else
+            input_ExtractAttachmentAndCacheArt( p_input );
+    }
+
+    p_item->p_meta->i_status |= ITEM_PREPARSED;
+    vlc_mutex_unlock( &p_item->lock );
+
+    if( psz_title )
+    {
+        input_Control( p_input, INPUT_SET_NAME, psz_title );
+        free( psz_title );
+    }
+
+    /** \todo handle sout meta */
+}
+
 /*****************************************************************************
  * MRLSplit: parse the access, demux and url part of the
  *           Media Resource Locator.
@@ -2524,8 +2563,6 @@ void MRLSplit( vlc_object_t *p_input, char *psz_dup,
         psz_path = psz_dup;
     }
     else
-#else
-    (void)p_input;
 #endif
 
     if( psz )
index e17df13..d84ffce 100644 (file)
@@ -91,9 +91,6 @@ struct input_thread_private_t
     int i_attachment;
     input_attachment_t **attachment;
 
-    /* Global meta datas FIXME move to input_item_t ? */
-    vlc_meta_t  *p_meta;
-
     /* Output */
     es_out_t    *p_es_out;
     sout_instance_t *p_sout;            /* XXX Move it to es_out ? */
@@ -131,7 +128,8 @@ struct input_thread_private_t
     int i_control;
     struct
     {
-        /* XXX: val isn't duplicated so it won't works with string */
+        /* XXX for string value you have to allocate it before calling
+         * input_ControlPush */
         int         i_type;
         vlc_value_t val;
     } control[INPUT_CONTROL_FIFO_SIZE];
@@ -225,10 +223,16 @@ vlc_bool_t  input_MetaSatisfied ( playlist_t*, input_item_t*,
                                   uint32_t*, uint32_t* );
 int         input_DownloadAndCacheArt ( playlist_t *, input_item_t * );
 
+/* Becarefull; p_item lock HAS to be taken */
+void input_ExtractAttachmentAndCacheArt( input_thread_t *p_input );
+
 /***************************************************************************
  * Internal prototypes
  ***************************************************************************/
 
+/* misc/stats.c */
+input_stats_t *stats_NewInputStats( input_thread_t *p_input );
+
 /* input.c */
 #define input_CreateThreadExtended(a,b,c,d) __input_CreateThreadExtended(VLC_OBJECT(a),b,c,d)
 input_thread_t *__input_CreateThreadExtended ( vlc_object_t *, input_item_t *, const char *, sout_instance_t * );
index fbac00c..6631fe0 100644 (file)
 #   include <sys/stat.h>
 #endif
 
-int input_FindArtInCache( playlist_t *p_playlist, input_item_t *p_item );
+// FIXME be sure to not touch p_meta without lock on p_item
+
+#define input_FindArtInCache(a,b) __input_FindArtInCache(VLC_OBJECT(a),b)
+static int __input_FindArtInCache( vlc_object_t *, input_item_t *p_item );
 
 vlc_bool_t input_MetaSatisfied( playlist_t *p_playlist, input_item_t *p_item,
                                 uint32_t *pi_mandatory, uint32_t *pi_optional )
@@ -100,6 +103,7 @@ int input_ArtFind( playlist_t *p_playlist, input_item_t *p_item )
         {
             msg_Dbg( p_playlist, " %s - %s has already been searched",
                      p_item->p_meta->psz_artist,  p_item->p_meta->psz_album );
+    /* TODO-fenrir if we cache art filename too, we can go faster */
             if( album.b_found )
             {
                 /* Actually get URL from cache */
@@ -107,7 +111,9 @@ int input_ArtFind( playlist_t *p_playlist, input_item_t *p_item )
                 return 0;
             }
             else
+            {
                 return VLC_EGENERIC;
+            }
         }
     FOREACH_END();
 
@@ -144,7 +150,56 @@ int input_ArtFind( playlist_t *p_playlist, input_item_t *p_item )
 #ifndef MAX_PATH
 #   define MAX_PATH 250
 #endif
-int input_FindArtInCache( playlist_t *p_playlist, input_item_t *p_item )
+#define ArtCacheCreateName( a,b,c,d,e) __ArtCacheCreateName(VLC_OBJECT(a),b,c,d,e)
+static void __ArtCacheCreateName( vlc_object_t *p_obj,
+                                  char psz_filename[MAX_PATH+1],
+                                  const char *psz_artist, const char *psz_album,
+                                  const char *psz_extension )
+{
+    snprintf( psz_filename, MAX_PATH,
+              "file://%s" DIR_SEP CONFIG_DIR DIR_SEP "art"
+              DIR_SEP "%s" DIR_SEP "%s" DIR_SEP "art%s",
+              p_obj->p_libvlc->psz_homedir,
+              psz_artist, psz_album, psz_extension ? psz_extension : "" );
+}
+#define ArtCacheCreatePath(a,b,c) __ArtCacheCreatePath(VLC_OBJECT(a),b,c)
+static void __ArtCacheCreatePath( vlc_object_t *p_obj,
+                                  const char *psz_artist, const char *psz_album )
+{
+    char psz_dir[MAX_PATH+1];
+    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR,
+              p_obj->p_libvlc->psz_homedir );
+    utf8_mkdir( psz_dir );
+    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP "art",
+              p_obj->p_libvlc->psz_homedir );
+    utf8_mkdir( psz_dir );
+    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP
+              "art" DIR_SEP "%s",
+                 p_obj->p_libvlc->psz_homedir, psz_artist );
+    utf8_mkdir( psz_dir );
+    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP
+              "art" DIR_SEP "%s" DIR_SEP "%s",
+                      p_obj->p_libvlc->psz_homedir,
+                      psz_artist, psz_album );
+    utf8_mkdir( psz_dir );
+}
+static char *ArtCacheCreateString( const char *psz )
+{
+    char *dup = strdup(psz);
+    int i;
+
+    /* Doesn't create a filename with invalid characters
+     * TODO: several filesystems forbid several characters: list them all
+     */
+    for( i = 0; dup[i] != '\0'; i++ )
+    {
+        if( dup[i] == '/' )
+            dup[i] = ' ';
+    }
+    return dup;
+}
+
+static int __input_FindArtInCache( vlc_object_t *p_obj, input_item_t *p_item )
 {
     char *psz_artist;
     char *psz_album;
@@ -160,11 +215,7 @@ int input_FindArtInCache( playlist_t *p_playlist, input_item_t *p_item )
 
     for( i = 0; i < 5; i++ )
     {
-        snprintf( psz_filename, MAX_PATH,
-                  "file://%s" DIR_SEP CONFIG_DIR DIR_SEP "art"
-                  DIR_SEP "%s" DIR_SEP "%s" DIR_SEP "art%s",
-                  p_playlist->p_libvlc->psz_homedir,
-                  psz_artist, psz_album, ppsz_type[i] );
+        ArtCacheCreateName( p_obj, psz_filename, psz_artist, psz_album, ppsz_type[i] );
 
         /* Check if file exists */
         if( utf8_stat( psz_filename+7, &a ) == 0 )
@@ -184,68 +235,41 @@ int input_DownloadAndCacheArt( playlist_t *p_playlist, input_item_t *p_item )
 {
     int i_status = VLC_EGENERIC;
     stream_t *p_stream;
-    char psz_filename[MAX_PATH+1], psz_dir[MAX_PATH+1];
+    char psz_filename[MAX_PATH+1];
     char *psz_artist = NULL;
     char *psz_album = NULL;
     char *psz_type;
-    unsigned int  i;
     if( p_item->p_meta->psz_artist )
-        psz_artist = strdup( p_item->p_meta->psz_artist );
+        psz_artist = ArtCacheCreateString( p_item->p_meta->psz_artist );
     if( p_item->p_meta->psz_album )
-        psz_album = strdup( p_item->p_meta->psz_album );
+        psz_album = ArtCacheCreateString( p_item->p_meta->psz_album );
 
     assert( p_item->p_meta && !EMPTY_STR(p_item->p_meta->psz_arturl) );
 
     /* FIXME: use an alternate saving filename scheme if we don't have
      * the artist or album name */
-    if( !p_item->p_meta->psz_artist || !p_item->p_meta->psz_album )
+    if( !psz_artist || !psz_album )
     {
-        free( psz_artist );
-        free( psz_album );
+        if( psz_artist ) free( psz_artist );
+        if( psz_album ) free( psz_album );
         return VLC_EGENERIC;
     }
 
-    /* Doesn't create a filename with invalid characters
-     * TODO: several filesystems forbid several characters: list them all
-     */
-    for( i = 0 ; i < strlen( psz_artist ) ; i++ )
-        if( psz_artist[i] == '/' )
-            psz_artist[i] = ' ';
-
-    for( i = 0 ; i < strlen( psz_album ) ; i++ )
-        if( psz_album[i] == '/' )
-            psz_album[i] = ' ';
-
     psz_type = strrchr( p_item->p_meta->psz_arturl, '.' );
 
-    /* Todo: get a helper to do this */
-    snprintf( psz_filename, MAX_PATH,
-              "file://%s" DIR_SEP CONFIG_DIR DIR_SEP "art"
-              DIR_SEP "%s" DIR_SEP "%s" DIR_SEP "art%s",
-              p_playlist->p_libvlc->psz_homedir,
-              psz_artist, psz_album, psz_type );
+    /* */
+    ArtCacheCreateName( p_playlist, psz_filename, psz_artist, psz_album, psz_type );
 
-    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR,
-              p_playlist->p_libvlc->psz_homedir );
-    utf8_mkdir( psz_dir );
-    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP "art",
-              p_playlist->p_libvlc->psz_homedir );
-    utf8_mkdir( psz_dir );
-    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP
-              "art" DIR_SEP "%s",
-                 p_playlist->p_libvlc->psz_homedir, psz_artist );
-    utf8_mkdir( psz_dir );
-    snprintf( psz_dir, MAX_PATH, "%s" DIR_SEP CONFIG_DIR DIR_SEP
-              "art" DIR_SEP "%s" DIR_SEP "%s",
-                      p_playlist->p_libvlc->psz_homedir,
-                      psz_artist, psz_album );
-    utf8_mkdir( psz_dir );
+    /* */
+    ArtCacheCreatePath( p_playlist, psz_artist, psz_album );
+
+    /* */
+    free( psz_artist );
+    free( psz_album );
 
     if( !strncmp( p_item->p_meta->psz_arturl , "APIC", 4 ) )
     {
         msg_Warn( p_playlist, "APIC fetch not supported yet" );
-        free( psz_artist );
-        free( psz_album );
         return VLC_EGENERIC;
     }
 
@@ -277,11 +301,95 @@ int input_DownloadAndCacheArt( playlist_t *p_playlist, input_item_t *p_item )
         p_item->p_meta->psz_arturl = strdup( psz_filename );
         i_status = VLC_SUCCESS;
     }
-    free( psz_artist );
-    free( psz_album );
     return i_status;
 }
 
+void input_ExtractAttachmentAndCacheArt( input_thread_t *p_input )
+{
+    input_item_t *p_item = p_input->p->input.p_item;
+    char *psz_arturl;
+    char *psz_artist = NULL;
+    char *psz_album = NULL;
+    char *psz_type = NULL;
+    char psz_filename[MAX_PATH+1];
+    FILE *f;
+    input_attachment_t *p_attachment;
+    struct stat s;
+    int i_idx;
+
+    /* TODO-fenrir merge input_ArtFind with download and make it set the flags FETCH
+     * and then set it here to to be faster */
+
+    assert( p_item->p_meta );
+    psz_arturl = p_item->p_meta->psz_arturl;
+    if( !psz_arturl || strncmp( psz_arturl, "attachment://", strlen("attachment://") ) )
+    {
+        msg_Err( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
+        return;
+    }
+    p_item->p_meta->psz_arturl = NULL;
+
+    if( p_item->p_meta->i_status & ITEM_ART_FETCHED )
+    {
+        /* XXX Weird, we should not have end up with attachment:// art url unless there is a race
+         * condition */
+        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
+        input_FindArtInCache( p_input, p_item );
+        free( psz_arturl );
+        return;
+    }
+
+    /* */
+    for( i_idx = 0, p_attachment = NULL; i_idx < p_input->p->i_attachment; i_idx++ )
+    {
+        if( !strcmp( p_input->p->attachment[i_idx]->psz_name,
+                     &psz_arturl[strlen("attachment://")] ) )
+        {
+            p_attachment = p_input->p->attachment[i_idx];
+            break;
+        }
+    }
+    if( !p_attachment || p_attachment->i_data <= 0 )
+    {
+        msg_Warn( p_input, "internal input error with input_ExtractAttachmentAndCacheArt" );
+        goto end;
+    }
+
+    if( p_item->p_meta->psz_artist )
+        psz_artist = ArtCacheCreateString( p_item->p_meta->psz_artist );
+    if( p_item->p_meta->psz_album )
+        psz_album = ArtCacheCreateString( p_item->p_meta->psz_album );
+
+    if( !psz_artist || !psz_album )
+        goto end;
+
+    /* */
+    psz_type = strrchr( psz_arturl, '.' );
+    ArtCacheCreateName( p_input, psz_filename, psz_artist, psz_album, psz_type );
+
+    /* Check if we already dumped it */
+    if( !utf8_stat( psz_filename+7, &s ) )
+        goto end;
+
+    ArtCacheCreatePath( p_input, psz_artist, psz_album );
+
+    f = utf8_fopen( psz_filename+7, "w" );
+    if( f )
+    {
+        if( fwrite( p_attachment->p_data, p_attachment->i_data, 1, f ) != 1 )
+            msg_Err( p_input, "%s: %s", psz_filename, strerror( errno ) );
+        else
+            msg_Dbg( p_input, "album art saved to %s\n", psz_filename );
+        fclose( f );
+    }
+
+end:
+    if( psz_artist ) free( psz_artist );
+    if( psz_album ) free( psz_album );
+    if( psz_arturl ) free( psz_arturl );
+}
+
+
 uint32_t input_CurrentMetaFlags( vlc_meta_t *p_meta )
 {
     uint32_t i_meta = 0;
index b7f9de1..3586bb8 100644 (file)
@@ -135,6 +135,20 @@ int __stats_Get( vlc_object_t *p_this, counter_t *p_counter, vlc_value_t *val )
     return VLC_SUCCESS;;
 }
 
+input_stats_t *stats_NewInputStats( input_thread_t *p_input )
+{
+    input_stats_t *p_stats = malloc( sizeof(input_stats_t) );
+
+    if( !p_stats )
+        return NULL;
+
+    memset( p_stats, 0, sizeof(*p_stats) );
+    vlc_mutex_init( p_input, &p_stats->lock );
+    stats_ReinitInputStats( p_stats );
+
+    return p_stats;
+}
+
 void stats_ComputeInputStats( input_thread_t *p_input, input_stats_t *p_stats )
 {
     if( !p_input->p_libvlc->b_stats ) return;
index a7e2ea2..7b1880a 100644 (file)
@@ -452,15 +452,18 @@ int playlist_PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
 
     if( p_playlist->p_fetcher->i_art_policy == ALBUM_ART_WHEN_PLAYED )
     {
-        if( p_input->p_meta && EMPTY_STR( p_input->p_meta->psz_arturl ) )
+        vlc_bool_t b_has_art;
+
+        vlc_mutex_lock( &p_input->lock );
+        /* p_input->p_meta should not be null after a successfull CreateThread */
+        b_has_art = p_input->p_meta && !EMPTY_STR( p_input->p_meta->psz_arturl );
+        vlc_mutex_unlock( &p_input->lock );
+
+        if( !b_has_art )
         {
             PL_DEBUG( "requesting art for %s", p_input->psz_name );
             playlist_AskForArtEnqueue( p_playlist, p_input );
         }
-        else if( !p_input->p_meta )
-        {
-            PL_DEBUG2( "unable to request art for %s, no meta", p_input->psz_name );
-        }
     }
 
     val.i_int = p_input->i_id;
index 9a259d0..91b3551 100644 (file)
@@ -498,9 +498,13 @@ void playlist_PreparseLoop( playlist_preparse_t *p_obj )
                 b_preparsed = VLC_TRUE;
                 stats_TimerStart( p_playlist, "Preparse run",
                                   STATS_TIMER_PREPARSE );
-                PL_UNLOCK;
-                input_Preparse( p_playlist, p_current );
-                PL_LOCK;
+                /* Do not preparse if it is already done (like by playing it) */
+                if( !p_current->p_meta || !(p_current->p_meta->i_status & ITEM_PREPARSED ) )
+                {
+                    PL_UNLOCK;
+                    input_Preparse( p_playlist, p_current );
+                    PL_LOCK;
+                }
                 stats_TimerStop( p_playlist, STATS_TIMER_PREPARSE );
             }
             PL_UNLOCK;
@@ -621,7 +625,24 @@ void playlist_FetcherLoop( playlist_fetcher_t *p_obj )
             }
             else
             {
-                int i_ret = input_ArtFind( p_playlist, p_item );
+                int i_ret;
+
+                /* Check if it is not yet preparsed and if so wait for it (at most 0.5s)
+                 * (This can happen if we fetch art on play)
+                 * FIXME this doesn't work if we need to fetch meta before art ... */
+                for( i_ret = 0; i_ret < 10 && !(p_item->p_meta->i_status & ITEM_PREPARSED ); i_ret++ )
+                {
+                    vlc_bool_t b_break;
+                    PL_LOCK;
+                    b_break = ( !p_playlist->p_input || input_GetItem(p_playlist->p_input) != p_item  ||
+                                p_playlist->p_input->b_die || p_playlist->p_input->b_eof || p_playlist->p_input->b_error );
+                    PL_UNLOCK;
+                    if( b_break )
+                        break;
+                    msleep( 50000 );
+                }
+                
+                i_ret = input_ArtFind( p_playlist, p_item );
                 if( i_ret == 1 )
                 {
                     PL_DEBUG("downloading art for %s", p_item->psz_name );