[FFmpeg-devel] [PATCH 2/2] lavc/pngdec: decode textual data (tEXt and zTXt).

Paul B Mahol onemda at gmail.com
Sun Oct 28 15:49:42 CET 2012


On 10/28/12, Nicolas George <nicolas.george at normalesup.org> wrote:
>
> Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
> ---
>  libavcodec/pngdec.c |  126
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 126 insertions(+)
>
> diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
> index a75420b..29e71e6 100644
> --- a/libavcodec/pngdec.c
> +++ b/libavcodec/pngdec.c
> @@ -21,6 +21,7 @@
>
>  //#define DEBUG
>
> +#include "libavutil/bprint.h"
>  #include "libavutil/imgutils.h"
>  #include "avcodec.h"
>  #include "bytestream.h"
> @@ -386,6 +387,117 @@ static int png_decode_idat(PNGDecContext *s, int
> length)
>      return 0;
>  }
>
> +static int decode_zbuf(AVBPrint *bp, const uint8_t *data,
> +                       const uint8_t *data_end)
> +{
> +    z_stream zstream;
> +    unsigned char *buf;
> +    unsigned buf_size;
> +    int ret;
> +
> +    zstream.zalloc = ff_png_zalloc;
> +    zstream.zfree  = ff_png_zfree;
> +    zstream.opaque = NULL;
> +    if (inflateInit(&zstream) != Z_OK)
> +        return AVERROR_EXTERNAL;
> +    zstream.next_in  = (unsigned char *)data;
> +    zstream.avail_in = data_end - data;
> +
> +    while (zstream.avail_in > 0) {
> +        av_bprint_get_buffer(bp, 1, &buf, &buf_size);
> +        if (!buf_size) {
> +            ret = AVERROR(ENOMEM);
> +            goto fail;
> +        }
> +        zstream.next_out  = buf;
> +        zstream.avail_out = buf_size;
> +        ret = inflate(&zstream, Z_PARTIAL_FLUSH);
> +        if (ret != Z_OK && ret != Z_STREAM_END) {
> +            ret = AVERROR_EXTERNAL;
> +            goto fail;
> +        }
> +        bp->len += zstream.next_out - buf;
> +        if (ret == Z_STREAM_END)
> +            break;
> +    }
> +    inflateEnd(&zstream);
> +    bp->str[bp->len] = 0;
> +    return 0;
> +
> +fail:
> +    inflateEnd(&zstream);
> +    av_bprint_finalize(bp, NULL);
> +    return ret;
> +}
> +
> +static uint8_t *iso88591_to_utf8(const uint8_t *in, size_t size_in)
> +{

Why this conversion? APE tags do not have this.
> +    size_t extra = 0, i;
> +    uint8_t *out, *q;
> +
> +    for (i = 0; i < size_in; i++)
> +        extra += in[i] >= 0x80;
> +    if (size_in == SIZE_MAX || extra > SIZE_MAX - size_in - 1)
> +        return NULL;
> +    q = out = av_malloc(size_in + extra + 1);
> +    if (!out)
> +        return NULL;
> +    for (i = 0; i < size_in; i++) {
> +        if (in[i] >= 0x80) {
> +            *(q++) = 0xC0 | (in[i] >> 6);
> +            *(q++) = 0x80 | (in[i] & 0x3F);
> +        } else {
> +            *(q++) = in[i];
> +        }
> +    }
> +    *(q++) = 0;
> +    return out;
> +}
> +
> +static int decode_text_chunk(PNGDecContext *s, uint32_t length, int
> compressed,
> +                             AVDictionary **dict)
> +{
> +    int ret, method;
> +    const uint8_t *data        = s->gb.buffer;
> +    const uint8_t *data_end    = data + length;
> +    const uint8_t *keyword     = data;
> +    const uint8_t *keyword_end = memchr(keyword, 0, data_end - keyword);
> +    uint8_t *text, *utf8;
> +    unsigned text_len;
> +    AVBPrint bp;
> +
> +    if (!keyword_end)
> +        return AVERROR_INVALIDDATA;
> +    data = keyword_end + 1;
> +
> +    av_bprint_init(&bp, 0, -1);
> +    if (compressed) {
> +        if (data == data_end)
> +            return AVERROR_INVALIDDATA;
> +        method = *(data++);
> +        if (method)
> +            return AVERROR_INVALIDDATA;
> +        if ((ret = decode_zbuf(&bp, data, data_end)) < 0)
> +            return ret;
> +        text_len = bp.len;
> +        av_bprint_finalize(&bp, (char **)&text);
> +        if (!text)
> +            return AVERROR(ENOMEM);
> +    } else {
> +        text = (uint8_t *)data;
> +        text_len = data_end - text;
> +    }
> +
> +    utf8 = iso88591_to_utf8(text, text_len);
> +    if (text != data)
> +        av_free(text);
> +    if (!utf8)
> +        return AVERROR(ENOMEM);
> +
> +    av_dict_set(dict, keyword, utf8, AV_DICT_DONT_STRDUP_VAL);
> +    return 0;
> +}
> +
>  static int decode_frame(AVCodecContext *avctx,
>                          void *data, int *data_size,
>                          AVPacket *avpkt)
> @@ -395,6 +507,7 @@ static int decode_frame(AVCodecContext *avctx,
>      PNGDecContext * const s = avctx->priv_data;
>      AVFrame *picture = data;
>      AVFrame *p;
> +    AVDictionary *metadata = NULL;
>      uint8_t *crow_buf_base = NULL;
>      uint32_t tag, length;
>      int64_t sig;
> @@ -617,6 +730,16 @@ static int decode_frame(AVCodecContext *avctx,
>                  bytestream2_skip(&s->gb, 4); /* crc */
>              }
>              break;
> +        case MKTAG('t', 'E', 'X', 't'):
> +            if (decode_text_chunk(s, length, 0, &metadata) < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Broken tEXt chunk\n");
> +            bytestream2_skip(&s->gb, length + 4);
> +            break;
> +        case MKTAG('z', 'T', 'X', 't'):
> +            if (decode_text_chunk(s, length, 1, &metadata) < 0)
> +                av_log(avctx, AV_LOG_WARNING, "Broken zTXt chunk\n");
> +            bytestream2_skip(&s->gb, length + 4);
> +            break;
>          case MKTAG('I', 'E', 'N', 'D'):
>              if (!(s->state & PNG_ALLIMAGE))
>                  av_log(avctx, AV_LOG_ERROR, "IEND without all image\n");
> @@ -712,6 +835,8 @@ static int decode_frame(AVCodecContext *avctx,
>          }
>      }
>
> +    s->current_picture->metadata = metadata;
> +    metadata = NULL;
>      *picture= *s->current_picture;
>      *data_size = sizeof(AVFrame);
>
> @@ -724,6 +849,7 @@ static int decode_frame(AVCodecContext *avctx,
>      av_freep(&s->tmp_row);
>      return ret;
>   fail:
> +    av_dict_free(&metadata);
>      ret = -1;
>      goto the_end;
>  }
> --
> 1.7.10.4
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>


More information about the ffmpeg-devel mailing list