]> git.sesse.net Git - vlc/blobdiff - modules/demux/xiph_metadata.c
Qt: MIM initialize p_input through constructor parameter
[vlc] / modules / demux / xiph_metadata.c
index f4f324ddceff77f974a56299bbc3c2fd2ab201e2..e4ef7674c2c9c781866a60aaddb15707f892dcd8 100644 (file)
@@ -112,15 +112,49 @@ error:
     return p_attachment;
 }
 
-void vorbis_ParseComment( vlc_meta_t **pp_meta,
+typedef struct chapters_array_t
+{
+    unsigned int i_size;
+    seekpoint_t ** pp_chapters;
+} chapters_array_t;
+
+static seekpoint_t * getChapterEntry( unsigned int i_index, chapters_array_t *p_array )
+{
+    if ( i_index > 4096 ) return NULL;
+    if ( i_index >= p_array->i_size )
+    {
+        unsigned int i_newsize = p_array->i_size;
+        while( i_index >= i_newsize ) i_newsize += 50;
+
+        if ( !p_array->pp_chapters )
+        {
+            p_array->pp_chapters = calloc( i_newsize, sizeof( seekpoint_t * ) );
+            if ( !p_array->pp_chapters ) return NULL;
+            p_array->i_size = i_newsize;
+        } else {
+            seekpoint_t **tmp = calloc( i_newsize, sizeof( seekpoint_t * ) );
+            if ( !tmp ) return NULL;
+            memcpy( tmp, p_array->pp_chapters, p_array->i_size * sizeof( seekpoint_t * ) );
+            free( p_array->pp_chapters );
+            p_array->pp_chapters = tmp;
+            p_array->i_size = i_newsize;
+        }
+    }
+    if ( !p_array->pp_chapters[i_index] )
+        p_array->pp_chapters[i_index] = vlc_seekpoint_New();
+    return p_array->pp_chapters[i_index];
+}
+
+void vorbis_ParseComment( es_format_t *p_fmt, vlc_meta_t **pp_meta,
         const uint8_t *p_data, int i_data,
         int *i_attachments, input_attachment_t ***attachments,
         int *i_cover_score, int *i_cover_idx,
-        int *i_seekpoint, seekpoint_t ***ppp_seekpoint )
+        int *i_seekpoint, seekpoint_t ***ppp_seekpoint,
+        float (* ppf_replay_gain)[AUDIO_REPLAY_GAIN_MAX],
+        float (* ppf_replay_peak)[AUDIO_REPLAY_GAIN_MAX] )
 {
     int n;
     int i_comment;
-    seekpoint_t *sk = NULL;
 
     if( i_data < 8 )
         return;
@@ -154,14 +188,20 @@ void vorbis_ParseComment( vlc_meta_t **pp_meta,
 
     /* */
     bool hasTitle        = false;
-    bool hasAlbum        = false;
-    bool hasTrackTotal   = false;
     bool hasArtist       = false;
+    bool hasGenre        = false;
     bool hasCopyright    = false;
+    bool hasAlbum        = false;
+    bool hasTrackNum     = false;
     bool hasDescription  = false;
-    bool hasGenre        = false;
+    bool hasRating       = false;
     bool hasDate         = false;
+    bool hasLanguage     = false;
     bool hasPublisher    = false;
+    bool hasEncodedBy    = false;
+    bool hasTrackTotal   = false;
+
+    chapters_array_t chapters_array = { 0, NULL };
 
     for( ; i_comment > 0; i_comment-- )
     {
@@ -195,9 +235,28 @@ void vorbis_ParseComment( vlc_meta_t **pp_meta,
             vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \
         has##var = true; \
     }
+
+#define IF_EXTRACT_ONCE(txt,var) \
+    if( !strncasecmp(psz_comment, txt, strlen(txt)) && !has##var ) \
+    { \
+        vlc_meta_Set( p_meta, vlc_meta_ ## var, &psz_comment[strlen(txt)] ); \
+        has##var = true; \
+    }
+
+#define IF_EXTRACT_FMT(txt,var,fmt,target) \
+    IF_EXTRACT(txt,var)\
+    if( fmt && !strncasecmp(psz_comment, txt, strlen(txt)) )\
+        {\
+            if ( fmt->target ) free( fmt->target );\
+            fmt->target = strdup(&psz_comment[strlen(txt)]);\
+        }
+
         IF_EXTRACT("TITLE=", Title )
+        else IF_EXTRACT("ARTIST=", Artist )
+        else IF_EXTRACT("GENRE=", Genre )
+        else IF_EXTRACT("COPYRIGHT=", Copyright )
         else IF_EXTRACT("ALBUM=", Album )
-        else if( !strncasecmp(psz_comment, "TRACKNUMBER=", strlen("TRACKNUMBER=" ) ) )
+        else if( !hasTrackNum && !strncasecmp(psz_comment, "TRACKNUMBER=", strlen("TRACKNUMBER=" ) ) )
         {
             /* Yeah yeah, such a clever idea, let's put xx/xx inside TRACKNUMBER
              * Oh, and let's not use TRACKTOTAL or TOTALTRACKS... */
@@ -205,26 +264,29 @@ void vorbis_ParseComment( vlc_meta_t **pp_meta,
             if( sscanf( &psz_comment[strlen("TRACKNUMBER=")], "%hu/%hu", &u_track, &u_total ) == 2 )
             {
                 char str[6];
-                snprintf(str, 6, "%d", u_track);
+                snprintf(str, 6, "%u", u_track);
                 vlc_meta_Set( p_meta, vlc_meta_TrackNumber, str );
-                snprintf(str, 6, "%d", u_total);
+                hasTrackNum = true;
+                snprintf(str, 6, "%u", u_total);
                 vlc_meta_Set( p_meta, vlc_meta_TrackTotal, str );
+                hasTrackTotal = true;
             }
             else
+            {
                 vlc_meta_Set( p_meta, vlc_meta_TrackNumber, &psz_comment[strlen("TRACKNUMBER=")] );
+                hasTrackNum = true;
+            }
         }
-        else if( !strncasecmp(psz_comment, "TRACKTOTAL=", strlen("TRACKTOTAL=")))
-            vlc_meta_Set( p_meta, vlc_meta_TrackTotal, &psz_comment[strlen("TRACKTOTAL=")] );
-        else if( !strncasecmp(psz_comment, "TOTALTRACKS=", strlen("TOTALTRACKS=")))
-            vlc_meta_Set( p_meta, vlc_meta_TrackTotal, &psz_comment[strlen("TOTALTRACKS=")] );
-        else IF_EXTRACT("TOTALTRACKS=", TrackTotal )
-        else IF_EXTRACT("ARTIST=", Artist )
-        else IF_EXTRACT("COPYRIGHT=", Copyright )
-        else IF_EXTRACT("ORGANIZATION=", Publisher )
+        else IF_EXTRACT_ONCE("TRACKTOTAL=", TrackTotal )
+        else IF_EXTRACT_ONCE("TOTALTRACKS=", TrackTotal )
         else IF_EXTRACT("DESCRIPTION=", Description )
+        else IF_EXTRACT("COMMENT=", Description )
         else IF_EXTRACT("COMMENTS=", Description )
-        else IF_EXTRACT("GENRE=", Genre )
+        else IF_EXTRACT("RATING=", Rating )
         else IF_EXTRACT("DATE=", Date )
+        else IF_EXTRACT_FMT("LANGUAGE=", Language, p_fmt, psz_language )
+        else IF_EXTRACT("ORGANIZATION=", Publisher )
+        else IF_EXTRACT("ENCODER=", EncodedBy )
         else if( !strncasecmp( psz_comment, "METADATA_BLOCK_PICTURE=", strlen("METADATA_BLOCK_PICTURE=")))
         {
             if( attachments == NULL )
@@ -241,29 +303,68 @@ void vorbis_ParseComment( vlc_meta_t **pp_meta,
                     *i_attachments, *attachments, p_attachment );
             }
         }
-        else if( !strncasecmp(psz_comment, "chapter", strlen("chapter")) )
+        else if ( ppf_replay_gain && ppf_replay_peak && !strncmp(psz_comment, "REPLAYGAIN_", 11) )
         {
-            if( ppp_seekpoint == NULL )
-                continue;
+            char *p = strchr( psz_comment, '=' );
+            char *psz_val;
+            if (!p) continue;
+            if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_GAIN=", 22) )
+            {
+                psz_val = malloc( strlen(p+1) + 1 );
+                if (!psz_val) continue;
+                if( sscanf( ++p, "%s dB", psz_val ) == 1 )
+                {
+                    (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( psz_val );
+                    free( psz_val );
+                }
+            }
+            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_GAIN=", 22) )
+            {
+                psz_val = malloc( strlen(p+1) + 1 );
+                if (!psz_val) continue;
+                if( sscanf( ++p, "%s dB", psz_val ) == 1 )
+                {
+                    (*ppf_replay_gain)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( psz_val );
+                    free( psz_val );
+                }
+            }
+            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_ALBUM_PEAK=", 22) )
+            {
+                (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_ALBUM] = us_atof( ++p );
+            }
+            else if ( !strncasecmp(psz_comment, "REPLAYGAIN_TRACK_PEAK=", 22) )
+            {
+                (*ppf_replay_peak)[AUDIO_REPLAY_GAIN_TRACK] = us_atof( ++p );
+            }
+        }
+        else if( !strncasecmp(psz_comment, "CHAPTER", 7) )
+        {
+            unsigned int i_chapt;
+            seekpoint_t *p_seekpoint = NULL;
 
-            int i_chapt;
-            if( strstr( psz_comment, "name") && sscanf( psz_comment, "chapter%i=", &i_chapt ) == 1 )
+            for( int i = 0; psz_comment[i] && psz_comment[i] != '='; i++ )
+                if( psz_comment[i] >= 'a' && psz_comment[i] <= 'z' )
+                    psz_comment[i] -= 'a' - 'A';
+
+            if( strstr( psz_comment, "NAME=" ) &&
+                    sscanf( psz_comment, "CHAPTER%uNAME=", &i_chapt ) == 1 )
             {
                 char *p = strchr( psz_comment, '=' );
-                *p++ = '\0';
-                sk->psz_name = strdup( p );
+                p_seekpoint = getChapterEntry( i_chapt, &chapters_array );
+                if ( !p || ! p_seekpoint ) continue;
+                if ( ! p_seekpoint->psz_name )
+                    p_seekpoint->psz_name = strdup( ++p );
             }
-            else if( sscanf( psz_comment, "chapter %i=", &i_chapt ) == 1 )
+            else if( sscanf( psz_comment, "CHAPTER%u=", &i_chapt ) == 1 )
             {
-                int h, m, s, ms;
+                unsigned int h, m, s, ms;
                 char *p = strchr( psz_comment, '=' );
-                *p++ = '\0';
-
-                if( sscanf( p, "%d:%d:%d.%d", &h, &m, &s, &ms ) == 4 )
+                if( p && sscanf( ++p, "%u:%u:%u.%u", &h, &m, &s, &ms ) == 4 )
                 {
-                    sk = vlc_seekpoint_New();
-                    sk->i_time_offset = ((h * 3600 + m * 60 + s) *1000 + ms) * 1000;
-                    TAB_APPEND_CAST( (seekpoint_t**), *i_seekpoint, *ppp_seekpoint, sk );
+                    p_seekpoint = getChapterEntry( i_chapt, &chapters_array );
+                    if ( ! p_seekpoint ) continue;
+                    p_seekpoint->i_time_offset =
+                      (((int64_t)h * 3600 + (int64_t)m * 60 + (int64_t)s) * 1000 + ms) * 1000;
                 }
             }
         }
@@ -284,6 +385,14 @@ void vorbis_ParseComment( vlc_meta_t **pp_meta,
         free( psz_comment );
     }
 #undef RM
+
+    for ( unsigned int i=0; i<chapters_array.i_size; i++ )
+    {
+        if ( !chapters_array.pp_chapters[i] ) continue;
+        TAB_APPEND_CAST( (seekpoint_t**), *i_seekpoint, *ppp_seekpoint,
+                         chapters_array.pp_chapters[i] );
+    }
+    free( chapters_array.pp_chapters );
 }
 
 const char *FindKateCategoryName( const char *psz_tag )