On 19/03/16 22:48, Vittorio Giovara wrote:
> From: Vitaliy E Sugrobov <vsug...@hotmail.com>
> 
> This demuxer is capable of extracting multiple frames from gif file.
> In conjunction with gif decoder it implements support for reading
> animated gifs.
> 
> Signed-off-by: Vitaliy E Sugrobov <vsug...@hotmail.com>
> Signed-off-by: Vittorio Giovara <vittorio.giov...@gmail.com>
> ---
>  Changelog                |   1 +
>  doc/general.texi         |   2 +-
>  libavformat/Makefile     |   1 +
>  libavformat/allformats.c |   2 +-
>  libavformat/gifdec.c     | 318 
> +++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 322 insertions(+), 2 deletions(-)
>  create mode 100644 libavformat/gifdec.c
> 
> diff --git a/Changelog b/Changelog
> index ca9c9b4..71fe9e2 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -52,6 +52,7 @@ version <next>:
>  - G.723.1 muxer and encoder
>  - compressed SWF
>  - G.729 raw demuxer
> +- GIF demuxer
>  
>  
>  version 11:
> diff --git a/doc/general.texi b/doc/general.texi
> index 15e4a66..5f01c50 100644
> --- a/doc/general.texi
> +++ b/doc/general.texi
> @@ -282,7 +282,7 @@ library:
>  @item framecrc testing format   @tab X @tab
>  @item FunCom ISS                @tab   @tab X
>      @tab Audio format used in various games from FunCom like The Longest 
> Journey.
> -@item GIF Animation             @tab X @tab
> +@item GIF Animation             @tab X @tab X
>  @item GXF                       @tab X @tab X
>      @tab General eXchange Format SMPTE 360M, used by Thomson Grass Valley
>           playout servers.
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 891a20f..5cd8f8f 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -135,6 +135,7 @@ OBJS-$(CONFIG_FOURXM_DEMUXER)            += 4xm.o
>  OBJS-$(CONFIG_FRAMECRC_MUXER)            += framecrcenc.o framehash.o
>  OBJS-$(CONFIG_FRAMEMD5_MUXER)            += md5enc.o framehash.o
>  OBJS-$(CONFIG_GIF_MUXER)                 += gif.o
> +OBJS-$(CONFIG_GIF_DEMUXER)               += gifdec.o
>  OBJS-$(CONFIG_GSM_DEMUXER)               += gsmdec.o
>  OBJS-$(CONFIG_GXF_DEMUXER)               += gxf.o
>  OBJS-$(CONFIG_GXF_MUXER)                 += gxfenc.o audiointerleave.o
> diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> index 0f49756..1056d7b 100644
> --- a/libavformat/allformats.c
> +++ b/libavformat/allformats.c
> @@ -106,7 +106,7 @@ void av_register_all(void)
>      REGISTER_MUXDEMUX(G722,             g722);
>      REGISTER_MUXDEMUX(G723_1,           g723_1);
>      REGISTER_DEMUXER (G729,             g729);
> -    REGISTER_MUXER   (GIF,              gif);
> +    REGISTER_MUXDEMUX(GIF,              gif);
>      REGISTER_DEMUXER (GSM,              gsm);
>      REGISTER_MUXDEMUX(GXF,              gxf);
>      REGISTER_MUXDEMUX(H261,             h261);
> diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c
> new file mode 100644
> index 0000000..cc46716
> --- /dev/null
> +++ b/libavformat/gifdec.c
> @@ -0,0 +1,318 @@
> +/*
> + * GIF demuxer
> + * Copyright (c) 2012 Vitaliy E Sugrobov
> + *
> + * This file is part of Libav.
> + *
> + * Libav is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * Libav is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +/**
> + * @file
> + * GIF demuxer.
> + *
> + * There are two options available to user: default_delay and min_delay.
> + *
> + * These options are for protection from too rapid gif animations.
> + * In practice it is standard approach to slow down rendering of this
> + * kind of gifs. If you try to play gif with delay between frames of one
> + * hundredth of second (100fps) using one of major web browsers, you get
> + * significantly slower playback, around 10 fps. This is because browser
> + * detects that delay value is less than some threshold (usually 2 hundredths
> + * of second) and reset it to default value (usually 10 hundredths of second,
> + * which corresponds to 10fps). Manipulating these options, user can achieve
> + * the same effect during conversion to some video format. Otherwise user
> + * can set them to not protect from rapid animations at all.
> + *
> + * The other case when these options necessary is for gif images encoded
> + * according to gif87a standard since prior to gif89a there was no delay
> + * information included in file.
> + */
> +
> +#include "libavutil/intreadwrite.h"
> +#include "libavutil/opt.h"
> +
> +#include "avformat.h"
> +#include "internal.h"
> +
> +#define GIF_SIG_87A "GIF87a"
> +#define GIF_SIG_89A "GIF89a"
> +
> +#define GIF_TRAILER                 0x3b
> +#define GIF_EXTENSION_INTRODUCER    0x21
> +#define GIF_IMAGE_SEPARATOR         0x2c
> +#define GIF_GCE_EXT_LABEL           0xf9
> +
> +typedef struct GIFDemuxContext {
> +    const AVClass *class;
> +    uint32_t width;
> +    uint32_t height;
> +
> +    /**
> +     * Time span in hundredths of second before
> +     * the next frame should be drawn on screen.
> +     */
> +    int delay;
> +
> +    /**
> +     * Minimum allowed delay between frames in hundredths of
> +     * second. Values below this threshold considered to be
> +     * invalid and set to value of default_delay.
> +     */
> +    int min_delay;
> +    int default_delay;
> +    int total_duration; ///< In hundredths of second.
> +} GIFDemuxContext;
> +
> +/**
> + * Major web browsers display gifs at ~10-15fps when rate is not explicitly
> + * set or have too low values. We assume default rate to be 10.
> + * Default delay = 100hundredths of second / 10fps = 10hos per frame.
> + */
> +#define GIF_DEFAULT_DELAY   10
> +
> +/**
> + * By default delay values less than this threshold considered to be invalid.
> + */
> +#define GIF_MIN_DELAY       2
> +
> +static int gif_probe(AVProbeData *p)
> +{

Check that the buf is at least 8 bytes here.

> +    /* check magick */
> +    if (memcmp(p->buf, GIF_SIG_87A, 6) && memcmp(p->buf, GIF_SIG_89A, 6))
> +        return 0;
> +
> +    /* width or height contains zero? */
> +    if (!AV_RL16(&p->buf[6]) || !AV_RL16(&p->buf[8]))
> +        return 0;
> +
> +    return AVPROBE_SCORE_MAX;
> +}
> +
> +static int gif_read_header(AVFormatContext *s)
> +{
> +    GIFDemuxContext *gdc = s->priv_data;
> +    AVIOContext     *pb  = s->pb;
> +    AVStream        *st;
> +    int ret;
> +
> +    /* skip 6-byte magick */
> +    if ((ret = avio_skip(pb, 6)) < 0)
> +        return ret;
> +
> +    gdc->delay  = gdc->default_delay;
> +    gdc->width  = avio_rl16(pb);
> +    gdc->height = avio_rl16(pb);
> +
> +    if (gdc->width == 0 || gdc->height == 0)
> +        return AVERROR_INVALIDDATA;
> +
> +    st = avformat_new_stream(s, NULL);
> +    if (!st)
> +        return AVERROR(ENOMEM);
> +
> +    /* GIF format operates with time in "hundredths of second",
> +     * therefore timebase is 1/100 */
> +    avpriv_set_pts_info(st, 64, 1, 100);
> +    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
> +    st->codecpar->codec_id   = AV_CODEC_ID_GIF;
> +    st->codecpar->width      = gdc->width;
> +    st->codecpar->height     = gdc->height;


check dimensions maybe?

> +
> +    /* jump to start because gif decoder needs header data too */
> +    return avio_seek(pb, 0, SEEK_SET);
> +}
> +
> +static int gif_skip_subblocks(AVIOContext *pb)
> +{
> +    int sb_size, ret = 0;
> +
> +    while ((sb_size = avio_r8(pb)) > 0) {
> +        if ((ret = avio_skip(pb, sb_size)) < 0)
> +            return ret;
> +    }
> +
> +    return ret;
> +}
> +
> +static int gif_read_ext(AVFormatContext *s)
> +{
> +    GIFDemuxContext *gdc = s->priv_data;
> +    AVIOContext *pb = s->pb;
> +    int sb_size, ext_label = avio_r8(pb);
> +    int ret;
> +
> +    if (ext_label != GIF_GCE_EXT_LABEL)
> +        return gif_skip_subblocks(pb);
> +
> +    if ((sb_size = avio_r8(pb)) < 4) {
> +        av_log(s, AV_LOG_FATAL,

AV_LOG_ERROR

> +               "Graphic Control Extension block's size less than 4.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +

The rest seems good.

lu

_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to