You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
lavf/id3v2dec: support multiple values and TIPL frames
Fixes https://trac.ffmpeg.org/ticket/6949 Ordinary text frames in ID3v2 are allowed to have multiple (null-separated) values. This technically isn't allowed in TXXX, but it's used in practice by Picard, and supporting it is harmless. TIPL/IPL (Involved People List) and TMCL (Musician Credits List) work similarly to TXXX, but alternate key-value-key-value. Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
committed by
Michael Niedermayer
parent
172e7ca668
commit
80b77e8e8d
@ -327,8 +327,12 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
|
||||
AVDictionary **metadata, const char *key)
|
||||
{
|
||||
uint8_t *dst;
|
||||
int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
|
||||
uint8_t *dst_key = NULL;
|
||||
int encoding, dict_flags = AV_DICT_MULTIKEY | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DEDUP;
|
||||
unsigned genre;
|
||||
int count = 0;
|
||||
int is_tipl = !(strcmp(key, "TIPL") && strcmp(key, "TMCL") &&
|
||||
strcmp(key, "IPL"));
|
||||
|
||||
if (taglen < 1)
|
||||
return;
|
||||
@ -336,30 +340,33 @@ static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
|
||||
encoding = avio_r8(pb);
|
||||
taglen--; /* account for encoding type byte */
|
||||
|
||||
while (taglen > 1) {
|
||||
if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
|
||||
(sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) &&
|
||||
genre <= ID3v1_GENRE_MAX) {
|
||||
av_freep(&dst);
|
||||
dst = av_strdup(ff_id3v1_genre_str[genre]);
|
||||
} else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
|
||||
} else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX")) ||
|
||||
(is_tipl && (count & 1))) {
|
||||
/* dst now contains the key, need to get value */
|
||||
key = dst;
|
||||
if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
|
||||
av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
|
||||
av_freep(&key);
|
||||
return;
|
||||
}
|
||||
dict_flags |= AV_DICT_DONT_STRDUP_KEY;
|
||||
av_free(dst_key);
|
||||
key = dst_key = dst;
|
||||
continue;
|
||||
} else if (!*dst)
|
||||
av_freep(&dst);
|
||||
|
||||
if (dst)
|
||||
av_dict_set(metadata, key, dst, dict_flags);
|
||||
}
|
||||
|
||||
av_free(dst_key);
|
||||
}
|
||||
|
||||
static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
|
||||
@ -1044,7 +1051,7 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
|
||||
pbx = &pb_local.pub; // read from sync buffer
|
||||
}
|
||||
#endif
|
||||
if (tag[0] == 'T')
|
||||
if (tag[0] == 'T' || !strcmp(tag, "IPL"))
|
||||
/* parse text tag */
|
||||
read_ttag(s, pbx, tlen, metadata, tag);
|
||||
else if (!memcmp(tag, "USLT", 4))
|
||||
|
Reference in New Issue
Block a user