Skip to content

avformat/id3v2: Support null-separated multi-value properties #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

softworkz
Copy link
Collaborator

@softworkz
Copy link
Collaborator Author

/submit

Copy link

ffmpeg-codebot bot commented Mar 1, 2025

Submitted as [email protected]

To fetch this version into FETCH_HEAD:

git fetch https://github.com/ffstaging/FFmpeg pr-ffstaging-54/softworkz/submit_id3v2-v1

To fetch this version to local tag pr-ffstaging-54/softworkz/submit_id3v2-v1:

git fetch --no-tags https://github.com/ffstaging/FFmpeg tag pr-ffstaging-54/softworkz/submit_id3v2-v1

Copy link

On the FFmpeg mailing list, Soft Works wrote (reply to this):



> -----Original Message-----
> From: softworkz <[email protected]>
> Sent: Sonntag, 2. März 2025 00:57
> To: [email protected]
> Cc: softworkz <[email protected]>; softworkz <[email protected]>
> Subject: [PATCH] avformat/id3v2: Support null-separated multi-value
> properties
> 
> From: softworkz <[email protected]>
> 
> Fixes Trac ticket https://trac.ffmpeg.org/ticket/6949
> 
> Signed-off-by: softworkz <[email protected]>
> ---
>     avformat/id3v2: Support null-separated multi-value properties
> 
>     Fixes Trac ticket https://trac.ffmpeg.org/ticket/6949
> 
> Published-As: https://github.com/ffstaging/FFmpeg/releases/tag/pr-
> ffstaging-54%2Fsoftworkz%2Fsubmit_id3v2-v1
> Fetch-It-Via: git fetch https://github.com/ffstaging/FFmpeg pr-
> ffstaging-54/softworkz/submit_id3v2-v1
> Pull-Request: https://github.com/ffstaging/FFmpeg/pull/54
> 
>  libavformat/id3v2.c | 65 ++++++++++++++++++++++++++++-----------------
>  1 file changed, 41 insertions(+), 24 deletions(-)
> 
> diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
> index 29ee59e1f4..cebb4acd75 100644
> --- a/libavformat/id3v2.c
> +++ b/libavformat/id3v2.c
> @@ -327,39 +327,55 @@ 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;
> +    int encoding, nb_values = 0;
>      unsigned genre;
> +    AVDictionaryEntry *tag = NULL;
> 
>      if (taglen < 1)
>          return;
> 
> +    tag = av_dict_get(*metadata, key, NULL, 0);
> +    if (tag)
> +        return;
> +
>      encoding = avio_r8(pb);
>      taglen--; /* account for encoding type byte */
> 
> -    if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
> -        av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n",
> key);
> -        return;
> -    }
> +    /* Read all null-terminated values */
> +    while (taglen > 0) {
> +        int n = 0, dict_flags = AV_DICT_APPEND |
> AV_DICT_DONT_STRDUP_VAL;
> 
> -    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"))) {
> -        /* 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;
> -    } else if (!*dst)
> -        av_freep(&dst);
> 
> -    if (dst)
> -        av_dict_set(metadata, key, dst, dict_flags);
> +        if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
> +            (sscanf(dst, "(%d)", &genre) == 1 || (sscanf(dst, "%d%n",
> &genre, &n) == 1 && n == strlen(dst))) &&
> +            genre <= ID3v1_GENRE_MAX) {
> +            av_freep(&dst);
> +            dst = av_strdup(ff_id3v1_genre_str[genre]);
> +        } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
> +            /* 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;
> +            }
> +        } else if (!*dst) {
> +            av_freep(&dst);
> +            return;
> +        }
> +
> +        if (dst) {
> +            if (nb_values > 0)
> +                av_dict_set(metadata, key, ";", dict_flags &
> ~AV_DICT_DONT_STRDUP_VAL);
> +
> +            av_dict_set(metadata, key, dst, dict_flags);
> +            nb_values++;
> +        }
> +    }
>  }
> 
>  static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
> @@ -372,7 +388,7 @@ static void read_uslt(AVFormatContext *s,
> AVIOContext *pb, int taglen,
>      int encoding;
>      int ok = 0;
> 
> -    if (taglen < 4)
> +    if (taglen < 1)
>          goto error;
> 
>      encoding = avio_r8(pb);
> @@ -383,10 +399,10 @@ static void read_uslt(AVFormatContext *s,
> AVIOContext *pb, int taglen,
>      lang[3] = '\0';
>      taglen -= 3;
> 
> -    if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0 || taglen
> < 0)
> +    if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0)
>          goto error;
> 
> -    if (decode_str(s, pb, encoding, &text, &taglen) < 0 || taglen < 0)
> +    if (decode_str(s, pb, encoding, &text, &taglen) < 0)
>          goto error;
> 
>      // FFmpeg does not support hierarchical metadata, so concatenate
> the keys.
> @@ -1003,7 +1019,8 @@ static void id3v2_parse(AVIOContext *pb,
> AVDictionary **metadata,
>                          t++;
>                  }
> 
> -                ffio_init_read_context(&pb_local, buffer, b - buffer);
> +                ffio_init_context(&pb_local, buffer, b - buffer, 0,
> NULL, NULL, NULL,
> +                                  NULL);
>                  tlen = b - buffer;
>                  pbx  = &pb_local.pub; // read from sync buffer
>              }
> @@ -1039,7 +1056,7 @@ static void id3v2_parse(AVIOContext *pb,
> AVDictionary **metadata,
>                          av_log(s, AV_LOG_ERROR, "Failed to uncompress
> tag: %d\n", err);
>                          goto seek;
>                      }
> -                    ffio_init_read_context(&pb_local,
> uncompressed_buffer, dlen);
> +                    ffio_init_context(&pb_local, uncompressed_buffer,
> dlen, 0, NULL, NULL, NULL, NULL);
>                      tlen = dlen;
>                      pbx = &pb_local.pub; // read from sync buffer
>                  }
> 
> base-commit: 0e7c2a6287f977c30e08e2a211385c6a80614fe8
> --
> ffmpeg-codebot


Is there any maintainer for avformat/id3v2 or somebody who would be able to review this?

Thanks
sw


_______________________________________________
ffmpeg-devel mailing list
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant