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;
/* */
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-- )
{
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... */
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 )
*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;
}
}
}
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 )