[FFmpeg-devel] [PATCH] Process compressed id3v2 tags.

Adrian Drzewiecki adrian.drzewiecki at gmail.com
Sun Dec 4 02:42:31 CET 2011


Please ignore this version, as it has an extra av_free() that I didn't catch.

-Adrian

On Dec 3, 2011, at 5:38 PM, Adrian Drzewiecki wrote:

> ID3v2.4 allows for zlib compressed tags, but libavformat skips them.
> Implement code to inflate compressed tags.
> ---
> libavformat/id3v2.c |   86 +++++++++++++++++++++++++++++++++++++++++++++-----
> 1 files changed, 77 insertions(+), 9 deletions(-)
> 
> diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c
> index f0a2197..e6f8d14 100644
> --- a/libavformat/id3v2.c
> +++ b/libavformat/id3v2.c
> @@ -26,6 +26,12 @@
>  * http://id3.org/Developer_Information
>  */
> 
> +#include "config.h"
> +
> +#if CONFIG_ZLIB
> +#include <zlib.h>
> +#endif
> +
> #include "id3v2.h"
> #include "id3v1.h"
> #include "libavutil/avstring.h"
> @@ -419,6 +425,18 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
>     return NULL;
> }
> 
> +#if CONFIG_ZLIB
> +static void *id3v2_zalloc(void *opaque, unsigned int items, unsigned int size)
> +{
> +    return av_calloc(items, size);
> +}
> +
> +static void id3v2_zfree(void *opaque, void *ptr)
> +{
> +    av_free(ptr);
> +}
> +#endif
> +
> static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags, ID3v2ExtraMeta **extra_meta)
> {
>     int isv34, unsync;
> @@ -432,6 +450,8 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
>     unsigned char *buffer = NULL;
>     int buffer_size = 0;
>     const ID3v2EMFunc *extra_func;
> +    unsigned char *compressed_buffer = NULL;
> +    int compressed_buffer_size = 0;
> 
>     switch (version) {
>     case 2:
> @@ -476,6 +496,9 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
>     while (len >= taghdrlen) {
>         unsigned int tflags = 0;
>         int tunsync = 0;
> +        int tcomp = 0;
> +        int tencr = 0;
> +        int dlen;
> 
>         if (isv34) {
>             avio_read(s->pb, tag, 4);
> @@ -509,24 +532,68 @@ static void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t
>         if (tflags & ID3v2_FLAG_DATALEN) {
>             if (tlen < 4)
>                 break;
> -            avio_rb32(s->pb);
> +            dlen = avio_rb32(s->pb);
>             tlen -= 4;
> -        }
> +        } else
> +            dlen = tlen;
> +
> +        tcomp = tflags & ID3v2_FLAG_COMPRESSION;
> +        tencr = tflags & ID3v2_FLAG_ENCRYPTION;
> +
> +        /* skip encrypted tags and, if no zlib, compressed tags */
> +        if (tencr || (!CONFIG_ZLIB && tcomp)) {
> +            const char *type;
> +            if (!tcomp)
> +                type = "encrypted";
> +            else if (!tencr)
> +                type = "compressed";
> +            else
> +                type = "encrypted and compressed";
> 
> -        if (tflags & (ID3v2_FLAG_ENCRYPTION | ID3v2_FLAG_COMPRESSION)) {
> -            av_log(s, AV_LOG_WARNING, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag);
> +            av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
>             avio_skip(s->pb, tlen);
>         /* check for text tag or supported special meta tag */
>         } else if (tag[0] == 'T' || (extra_meta && (extra_func = get_extra_meta_func(tag, isv34)))) {
> -            if (unsync || tunsync) {
> +            if (unsync || tunsync || tcomp) {
>                 int i, j;
> -                av_fast_malloc(&buffer, &buffer_size, tlen);
> +                av_fast_malloc(&buffer, &buffer_size, dlen);
>                 if (!buffer) {
> -                    av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
> +                    av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", dlen);
>                     goto seek;
>                 }
> -                for (i = 0, j = 0; i < tlen; i++, j++) {
> -                    buffer[j] = avio_r8(s->pb);
> +#if CONFIG_ZLIB
> +                if (tcomp) {
> +                    char *compressed_buffer;
> +                    int n, err;
> +
> +                    av_log(s, AV_LOG_DEBUG, "Compresssed frame %s tlen=%d dlen=%d\n", tag, tlen, dlen);
> +
> +                    av_fast_malloc(&compressed_buffer, &compressed_buffer_size, tlen);
> +                    if (!compressed_buffer) {
> +                        av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
> +                        goto seek;
> +                    }
> +
> +                    n = avio_read(s->pb, compressed_buffer, tlen);
> +                    if (n < 0) {
> +                        av_free(compressed_buffer);
> +                        av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
> +                        goto seek;
> +                    }
> +
> +                    err = uncompress(buffer, &dlen, compressed_buffer, n);
> +                    av_free(compressed_buffer);
> +
> +                    if (err != Z_OK) {
> +                        av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
> +                        goto seek;
> +                    }
> +                }
> +#endif
> +
> +                for (i = 0, j = 0; i < dlen; i++, j++) {
> +                    if (!tcomp)
> +                        buffer[j] = avio_r8(s->pb);
>                     if (j > 0 && !buffer[j] && buffer[j - 1] == 0xff) {
>                         /* Unsynchronised byte, skip it */
>                         j--;
> @@ -564,6 +631,7 @@ seek:
>         av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
>     avio_seek(s->pb, end, SEEK_SET);
>     av_free(buffer);
> +    av_free(compressed_buffer);
>     return;
> }
> 
> -- 
> 1.7.8
> 



More information about the ffmpeg-devel mailing list