[FFmpeg-devel] [PATCH v2] [RFC] lavc, lavfmt: add FLIF decoding support

Kartik K. Khullar kartikkhullar840 at gmail.com
Sun Aug 2 22:09:14 EEST 2020


On Sun, Aug 2, 2020 at 5:57 PM Nicolas George <george at nsup.org> wrote:

> Anamitra Ghorui (12020-07-30):
> > Visible errors have been fixed in libavformat/flifdec.c, however the
> > problem regarding metadata decoding still exists. The function does work
> > with dummy data from zlib's example program (see https://0x0.st/ix_E.zip
> for
> > an example with "1234" as the encoded sequence), so the problem may be
> > in providing the appropriate parameters.
>
> Thanks for the patch. See a few comments below. This is so long, I was
> not as careful at the end as in the beginning.
>
> >
> > Other test files: https://0x0.st/ixSs.7z
> >
> > Co-authored-by: Anamitra Ghorui <aghorui at teknik.io>
> > Co-authored-by: Kartik K Khullar <kartikkhullar840 at gmail.com>
> >
> > Signed-off-by: Anamitra Ghorui <aghorui at teknik.io>
> > ---
> >  Changelog                      |    3 +-
> >  configure                      |    2 +
> >  doc/general.texi               |    2 +
> >  libavcodec/Makefile            |    2 +
> >  libavcodec/allcodecs.c         |    1 +
> >  libavcodec/codec_desc.c        |    7 +
> >  libavcodec/codec_id.h          |    1 +
> >  libavcodec/flif16.c            |  198 +++
> >  libavcodec/flif16.h            |  278 +++
> >  libavcodec/flif16_parser.c     |  189 ++
> >  libavcodec/flif16_rangecoder.c |  464 +++++
> >  libavcodec/flif16_rangecoder.h |  824 +++++++++
> >  libavcodec/flif16_transform.c  | 2964 ++++++++++++++++++++++++++++++++
> >  libavcodec/flif16_transform.h  |  123 ++
> >  libavcodec/flif16dec.c         | 1146 ++++++++++++
> >  libavcodec/parsers.c           |    1 +
> >  libavformat/Makefile           |    1 +
> >  libavformat/allformats.c       |    1 +
> >  libavformat/flifdec.c          |  377 ++++
> >  19 files changed, 6583 insertions(+), 1 deletion(-)
> >  create mode 100644 libavcodec/flif16.c
> >  create mode 100644 libavcodec/flif16.h
> >  create mode 100644 libavcodec/flif16_parser.c
> >  create mode 100644 libavcodec/flif16_rangecoder.c
> >  create mode 100644 libavcodec/flif16_rangecoder.h
> >  create mode 100644 libavcodec/flif16_transform.c
> >  create mode 100644 libavcodec/flif16_transform.h
> >  create mode 100644 libavcodec/flif16dec.c
> >  create mode 100644 libavformat/flifdec.c
> >
> > diff --git a/Changelog b/Changelog
> > index 6f648bff2b..ac5a21b1a9 100644
> > --- a/Changelog
> > +++ b/Changelog
> > @@ -10,7 +10,8 @@ version <next>:
> >  - ADPCM IMA Ubisoft APM encoder
> >  - Rayman 2 APM muxer
> >  - AV1 encoding support SVT-AV1
> > -
> > +- FLIF16 decoder
> > +- FLIF16 demuxer
> >
> >  version 4.3:
> >  - v360 filter
> > diff --git a/configure b/configure
> > index 169f23e17f..50936fef4a 100755
> > --- a/configure
> > +++ b/configure
> > @@ -2718,6 +2718,8 @@ ffvhuff_encoder_select="huffyuv_encoder"
> >  fic_decoder_select="golomb"
> >  flac_decoder_select="flacdsp"
> >  flac_encoder_select="bswapdsp flacdsp lpc"
> > +flif16_decoder_select="flif16dec"
> > +flif16_encoder_select="flif16enc"
> >  flashsv2_decoder_deps="zlib"
> >  flashsv2_encoder_deps="zlib"
> >  flashsv_decoder_deps="zlib"
> > diff --git a/doc/general.texi b/doc/general.texi
> > index dfcfd394e6..71b61100e3 100644
> > --- a/doc/general.texi
> > +++ b/doc/general.texi
> > @@ -903,6 +903,8 @@ following image formats are supported:
> >  @item Flash Screen Video v2  @tab  X  @tab  X
> >  @item Flash Video (FLV)      @tab  X  @tab  X
> >      @tab Sorenson H.263 used in Flash
> > + at item FLIF (Free Lossless Image Format @tab     @tab  X
> > +    @tab Precursor to JPEG XL and FUIF
> >  @item FM Screen Capture Codec  @tab     @tab  X
> >  @item Forward Uncompressed   @tab     @tab  X
> >  @item Fraps                  @tab     @tab  X
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index 9d4d52d048..96d06d2479 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> > @@ -328,6 +328,7 @@ OBJS-$(CONFIG_FLASHSV_ENCODER)         +=
> flashsvenc.o
> >  OBJS-$(CONFIG_FLASHSV2_ENCODER)        += flashsv2enc.o
> >  OBJS-$(CONFIG_FLASHSV2_DECODER)        += flashsv.o
> >  OBJS-$(CONFIG_FLIC_DECODER)            += flicvideo.o
> > +OBJS-$(CONFIG_FLIF16_DECODER)          += flif16dec.o
> flif16_rangecoder.o flif16.o flif16_transform.o
> >  OBJS-$(CONFIG_FMVC_DECODER)            += fmvc.o
> >  OBJS-$(CONFIG_FOURXM_DECODER)          += 4xm.o
> >  OBJS-$(CONFIG_FRAPS_DECODER)           += fraps.o
> > @@ -1069,6 +1070,7 @@ OBJS-$(CONFIG_DVD_NAV_PARSER)          +=
> dvd_nav_parser.o
> >  OBJS-$(CONFIG_DVDSUB_PARSER)           += dvdsub_parser.o
> >  OBJS-$(CONFIG_FLAC_PARSER)             += flac_parser.o flacdata.o
> flac.o \
> >                                            vorbis_data.o
> > +OBJS-$(CONFIG_FLIF16_PARSER)           += flif16_parser.o
> >  OBJS-$(CONFIG_G723_1_PARSER)           += g723_1_parser.o
> >  OBJS-$(CONFIG_G729_PARSER)             += g729_parser.o
> >  OBJS-$(CONFIG_GIF_PARSER)              += gif_parser.o
> > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> > index 80142899fe..032ff422f8 100644
> > --- a/libavcodec/allcodecs.c
> > +++ b/libavcodec/allcodecs.c
> > @@ -119,6 +119,7 @@ extern AVCodec ff_flashsv_decoder;
> >  extern AVCodec ff_flashsv2_encoder;
> >  extern AVCodec ff_flashsv2_decoder;
> >  extern AVCodec ff_flic_decoder;
> > +extern AVCodec ff_flif16_decoder;
> >  extern AVCodec ff_flv_encoder;
> >  extern AVCodec ff_flv_decoder;
> >  extern AVCodec ff_fmvc_decoder;
> > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> > index ced00bd34c..4ca0d1f514 100644
> > --- a/libavcodec/codec_desc.c
> > +++ b/libavcodec/codec_desc.c
> > @@ -1784,6 +1784,13 @@ static const AVCodecDescriptor
> codec_descriptors[] = {
> >          .long_name = NULL_IF_CONFIG_SMALL("PFM (Portable FloatMap)
> image"),
> >          .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
> >      },
> > +    {
> > +        .id        = AV_CODEC_ID_FLIF16,
> > +        .type      = AVMEDIA_TYPE_VIDEO,
> > +        .name      = "flif16",
> > +        .long_name = NULL_IF_CONFIG_SMALL("FLIF16 (Free Lossless Image
> Format)"),
> > +        .props     = AV_CODEC_PROP_LOSSLESS,
> > +    },
> >
> >      /* various PCM "codecs" */
> >      {
> > diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
> > index 896ecb0ce0..5c4f2dd7d0 100644
> > --- a/libavcodec/codec_id.h
> > +++ b/libavcodec/codec_id.h
> > @@ -296,6 +296,7 @@ enum AVCodecID {
> >      AV_CODEC_ID_MV30,
> >      AV_CODEC_ID_NOTCHLC,
> >      AV_CODEC_ID_PFM,
> > +    AV_CODEC_ID_FLIF16,
> >
> >      /* various PCM "codecs" */
> >      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at
> the start of audio codecs
> > diff --git a/libavcodec/flif16.c b/libavcodec/flif16.c
> > new file mode 100644
> > index 0000000000..d8ffb31c34
> > --- /dev/null
> > +++ b/libavcodec/flif16.c
> > @@ -0,0 +1,198 @@
> > +/*
> > + * FLIF16 Image Format Definitions
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * FLIF16 format definitions and functions.
> > + */
> > +
> > +#include "flif16.h"
> > +#include "flif16_transform.h"
> > +
> > +/**
> > + * Initialise property ranges for non interlaced images.
> > + * @param[out] prop_ranges resultant ranges
> > + * @param[in]  color ranges of each channel
> > + * @param[in]  channels number of channels
> > + */
>
> > +int32_t  (*ff_flif16_maniac_ni_prop_ranges_init(unsigned int
> *prop_ranges_size,
> > +                                                FLIF16RangesContext
> *ranges,
> > +                                                uint8_t plane,
> > +                                                uint8_t channels))[2]
>
> I would prefer avoiding pointers to arrays of arrays, they are tricky to
> use and the syntax is awful, as clearly visible here.
>
> I suggest to define "struct FLIFMinMax { int32_t min, max; }" and to use
> it instead.
>
> > +{
> > +    int min = ff_flif16_ranges_min(ranges, plane);
> > +    int max = ff_flif16_ranges_max(ranges, plane);
> > +    int mind = min - max, maxd = max - min;
> > +    int32_t (*prop_ranges)[2];
> > +    unsigned int top = 0;
>
> > +    unsigned int size = (((plane < 3) ? plane : 0) + 2 + 5) + ((plane <
> 3) && (ranges->num_planes > 3));
>
> Am I wrong, or is it always at most 10 here and 12 in the other function?
>
> If so, then let us get rid of this dynamic allocation and just have:
>
> #define FLIF_MAX_RANGES 12
>
>     FLIFMinMax prop_ranges[FLIF_MAX_RANGES];
>
> > +    *prop_ranges_size = size;
>
> > +    prop_ranges = av_mallocz(sizeof(*prop_ranges) * size);
>
> av_mallocz_array(), but moot if we avoid the dynamic alloc.
>
> > +    if (!prop_ranges)
> > +        return NULL;
> > +    if (plane < 3) {
> > +        for (int i = 0; i < plane; i++) {
> > +            prop_ranges[top][0]   = ff_flif16_ranges_min(ranges, i);
> > +            prop_ranges[top++][1] = ff_flif16_ranges_max(ranges, i);
> // pixels on previous planes
> > +        }
> > +        if (ranges->num_planes > 3)  {
> > +            prop_ranges[top][0]   = ff_flif16_ranges_min(ranges, 3);
> > +            prop_ranges[top++][1] = ff_flif16_ranges_max(ranges, 3);
> // pixel on alpha plane
> > +        }
> > +    }
> > +    prop_ranges[top][0]   = min;
> > +    prop_ranges[top++][1] = max;  // guess (median of 3)
> > +    prop_ranges[top][0]   = 0;
> > +    prop_ranges[top++][1] = 2;      // which predictor was it
>
> > +    for (int i = 0; i < 5; ++i) {
>
> Nit: We usually write i++. At least be consistent.
>
> > +        prop_ranges[top][0] = mind;
> > +        prop_ranges[top++][1] = maxd;
> > +    }
> > +    return prop_ranges;
> > +}
> > +
> > +int32_t (*ff_flif16_maniac_prop_ranges_init(unsigned int
> *prop_ranges_size,
> > +                                            FLIF16RangesContext *ranges,
> > +                                            uint8_t property,
> > +                                            uint8_t channels))[2]
> > +{
> > +    int min = ff_flif16_ranges_min(ranges, property);
> > +    int max = ff_flif16_ranges_max(ranges, property);
> > +    unsigned int top = 0, pp;
> > +    int mind = min - max, maxd = max - min;
> > +    int32_t (*prop_ranges)[2];
>
> > +    unsigned int size =   (((property < 3) ? ((ranges->num_planes > 3)
> ? property + 1 : property) : 0) \
> > +                        + ((property == 1 || property == 2) ? 1 : 0) \
> > +                        + ((property != 2) ? 2 : 0) + 1 + 5);
> > +    prop_ranges = av_mallocz(sizeof(*prop_ranges) * size);
> > +    if (!prop_ranges)
> > +        return NULL;
> > +    *prop_ranges_size = size;
> > +
> > +    if (property < 3) {
> > +      for (pp = 0; pp < property; pp++) {
> > +        prop_ranges[top][0] = ff_flif16_ranges_min(ranges, pp);
> > +        prop_ranges[top++][1] = ff_flif16_ranges_max(ranges, pp);
> > +      }
> > +      if (ranges->num_planes > 3) {
> > +          prop_ranges[top][0] = ff_flif16_ranges_min(ranges, 3);
> > +          prop_ranges[top++][1] = ff_flif16_ranges_max(ranges, 3);;
> > +      }
> > +    }
> > +
> > +    prop_ranges[top][0] = 0;
> > +    prop_ranges[top++][0] = 2;
> > +
> > +    if (property == 1 || property == 2){
> > +        prop_ranges[top][0] = ff_flif16_ranges_min(ranges, 0) -
> ff_flif16_ranges_max(ranges, 0);
> > +        prop_ranges[top++][1] = ff_flif16_ranges_max(ranges, 0) -
> ff_flif16_ranges_min(ranges, 0); // luma prediction miss
> > +    }
> > +    for (int i = 0; i < 4; ++i) {
> > +        prop_ranges[top][0] = mind;
> > +        prop_ranges[top++][1] = maxd;
> > +    }
> > +    prop_ranges[top][0] = min;
> > +    prop_ranges[top++][0] = max;
> > +
> > +    if (property != 2) {
> > +      prop_ranges[top][0] = mind;
> > +      prop_ranges[top++][1] = maxd;
> > +    }
> > +    return prop_ranges;
> > +}
> > +
> > +
> > +int ff_flif16_planes_init(FLIF16Context *s, FLIF16PixelData *frames,
> > +                          uint8_t *plane_mode, uint8_t
> *const_plane_value,
> > +                          uint8_t lookback)
> > +{
> > +    for (int j = 0; j < s->num_frames; ++j) {
> > +        if (frames[j].seen_before >= 0)
> > +            continue;
> > +
>
> > +        frames[j].data = av_mallocz(sizeof(*frames->data) *
> s->num_planes);
>
> Can num_planes be greater than 5? If yes, then av_mallocz_array(). If
> no, then let us get rid of this dynamic allocation too.
>
> > +
> > +        if (!frames[j].data) {
> > +            return AVERROR(ENOMEM);
> > +        }
> > +
> > +        for (int i = 0; i < (s->num_planes + lookback); ++i) {
>
> > +            printf("Plane: %d ", i);
>
> Remember to get rid of all printf() for the final version.
>
> > +            switch (plane_mode[i]) {
> > +                case FLIF16_PLANEMODE_NORMAL:
>
> > +                    frames[j].data[i] = av_mallocz(sizeof(int32_t) *
> s->width * s->height);
>
> av_malloc_array() and missing error check.
>
> Are width and height validated against multiplication overflow? IIRC,
> ff_set_dimensions() checks against avctx->max_pixels, which can be set
> to more than INT_MAX.
>
> Is the initialization to 0 necessary? It is expensive.
>
> > +                    break;
> > +
> > +                case FLIF16_PLANEMODE_CONSTANT:
>
> > +                    frames[j].data[i] = av_mallocz(sizeof(int32_t));
>
> Missing error check. And the initialization to 0 is not necessary.
>
> > +                    ((int32_t *) frames[j].data[i])[0] =
> const_plane_value[i];
> > +                    break;
> > +
> > +                case FLIF16_PLANEMODE_FILL:
>
> > +                    frames[j].data[i] = av_mallocz(sizeof(int32_t) *
> s->width * s->height);;
>
> Same as above.
>
> > +                    if (!frames[j].data[i])
> > +                        return AVERROR(ENOMEM);
> > +                    for (int k = 0; k < s->height * s->width; ++k)
> > +                            ((int32_t *) frames[j].data[i])[k] =
> const_plane_value[i];
> > +                    break;
> > +            }
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +
> > +static void ff_flif16_planes_free(FLIF16PixelData *frame, uint8_t
> num_planes,
> > +                                uint8_t lookback)
> > +{
>
> > +    for(uint8_t i = 0; i < (num_planes + lookback); ++i) {
>
> int i, to avoid confusing the compiler about your intent.
>
> > +        av_free(frame->data[i]);
> > +    }
> > +    av_free(frame->data);
> > +}
> > +
> > +FLIF16PixelData *ff_flif16_frames_init(FLIF16Context *s)
> > +{
> > +    FLIF16PixelData *frames = av_mallocz(sizeof(*frames) *
> s->num_frames);
>
> av_malloc_array()
>
> > +    if (!frames)
> > +        return NULL;
> > +
> > +    for (int i = 0; i < s->num_frames; ++i)
> > +        frames[i].seen_before = -1;
> > +    return frames;
> > +}
> > +
> > +void ff_flif16_frames_free(FLIF16PixelData **frames, uint32_t
> num_frames,
> > +                           uint32_t num_planes, uint8_t lookback)
> > +{
> > +    for (int i = 0; i < num_frames; ++i) {
> > +        if ((*frames)[i].seen_before >= 0)
> > +            continue;
> > +        ff_flif16_planes_free(&(*frames)[i], num_planes, lookback);
> > +        if ((*frames)[i].col_begin)
> > +            av_freep(&(*frames)[i].col_begin);
> > +        if ((*frames)[i].col_end)
> > +            av_freep(&(*frames)[i].col_end);
> > +    }
> > +
> > +    av_freep(frames);
> > +}
> > diff --git a/libavcodec/flif16.h b/libavcodec/flif16.h
> > new file mode 100644
> > index 0000000000..d21cfd79a4
> > --- /dev/null
> > +++ b/libavcodec/flif16.h
> > @@ -0,0 +1,278 @@
> > +/*
> > + * FLIF16 Image Format Definitions
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * FLIF16 format definitions and functions.
> > + */
> > +
> > +#ifndef AVCODEC_FLIF16_H
> > +#define AVCODEC_FLIF16_H
> > +
> > +#include <stdint.h>
> > +#include <stdlib.h>
> > +
> > +#include "avcodec.h"
> > +#include "libavutil/pixfmt.h"
> > +#include "flif16_rangecoder.h"
> > +
> > +#define MAX_PLANES 5
> > +#define MAX_PREDICTORS 2
> > +
> > +#define VARINT_APPEND(a,x) (a) = ((a) << 7) | (uint32_t) ((x) & 127)
> > +#define ZOOM_ROWPIXELSIZE(zoomlevel) (1 << (((zoomlevel) + 1) / 2))
> > +#define ZOOM_COLPIXELSIZE(zoomlevel) (1 << (((zoomlevel)) / 2))
> > +#define ZOOM_HEIGHT(r, z) ((!z) ? 0 : (1 + ((r) - 1) /
> ZOOM_ROWPIXELSIZE(z)))
> > +#define ZOOM_WIDTH(w, z) ((!z) ? 0 : (1 + ((w) - 1) /
> ZOOM_COLPIXELSIZE(z)))
> > +#define MEDIAN3(a, b, c) (((a) < (b)) ? (((b) < (c)) ? (b) : ((a) < (c)
> ? (c) : (a))) : (((a) < (c)) ? (a) : ((b) < (c) ? (c) : (b))))
> > +
> > +static const uint8_t flif16_header[4] = "FLIF";
> > +
> > +// Pixeldata types
> > +static const enum AVPixelFormat flif16_out_frame_type[][2] = {
> > +    { -1,  -1 },  // Padding
> > +    { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16 },
> > +    { -1 , -1 }, // Padding
> > +    { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48  },
> > +    { AV_PIX_FMT_RGB32, AV_PIX_FMT_RGBA64 }
> > +};
> > +
> > +typedef enum FLIF16Plane {
> > +    FLIF16_PLANE_Y = 0,
> > +    FLIF16_PLANE_CO,
> > +    FLIF16_PLANE_CG,
> > +    FLIF16_PLANE_ALPHA,
> > +    FLIF16_PLANE_LOOKBACK, // Frame lookback
> > +    FLIF16_PLANE_GRAY = 0, // Is this needed?
> > +} FLIF16Plane;
> > +
> > +typedef enum FLIF16PlaneMode {
> > +    FLIF16_PLANEMODE_CONSTANT = 0,  ///< A true constant plane
> > +    FLIF16_PLANEMODE_NORMAL,        ///< A normal pixel matrix
> > +    FLIF16_PLANEMODE_FILL           /**< A constant plane that is later
> manipulated
> > +                                         by transforms, making it
> nonconstant and
> > +                                         allocating a plane for it */
> > +
> > +} FLIF16PlaneMode;
> > +
> > +typedef struct FLIF16PixelData {
>
> > +    int8_t seen_before;  // Required by FrameDup
> > +    uint32_t *col_begin; // Required by FrameShape
> > +    uint32_t *col_end;   // Required by FrameShape
> > +    int s_r[MAX_PLANES];
> > +    int s_c[MAX_PLANES];
> > +    void **data;
>
> Nit: Larger fields first, smaller fields last, to avoid padding. Same at
> other places.
>
> > +} FLIF16PixelData;
> > +
> > +typedef int32_t FLIF16ColorVal;
> > +
> > +typedef struct FLIF16Context {
> > +    GetByteContext gb;
> > +    FLIF16MANIACContext maniac_ctx;
> > +    FLIF16RangeCoder rc;
> > +
>
> > +    // Dimensions and other things.
> > +    uint32_t width;
> > +    uint32_t height;
> > +    uint32_t num_frames;
> > +    uint32_t meta;        ///< Size of a meta chunk
> > +
> > +    // Primary Header
> > +    uint8_t  ia;          ///< Is image interlaced or/and animated or
> not
> > +    uint32_t bpc;         ///< 2 ^ Bytes per channel
> > +    uint8_t  num_planes;  ///< Number of planes
> > +    uint8_t loops;        ///< Number of times animation loops
> > +    uint16_t *framedelay; ///< Frame delay for each frame
> > +    uint8_t plane_mode[MAX_PLANES];
> > +
> > +    // Transform flags
> > +    uint8_t framedup;
> > +    uint8_t frameshape;
> > +    uint8_t framelookback;
> > +} FLIF16Context;
> > +
> > +typedef struct FLIF16RangesContext {
> > +    uint8_t r_no;
> > +    uint8_t num_planes;
>
> > +    void* priv_data;
>
> Nit: "void *priv_data".
>
> > +} FLIF16RangesContext;
> > +
> > +typedef struct FLIF16Ranges {
> > +    uint8_t priv_data_size;
> > +
> > +    FLIF16ColorVal (*min)(FLIF16RangesContext *ranges, int plane);
> > +    FLIF16ColorVal (*max)(FLIF16RangesContext *ranges, int plane);
> > +    void (*minmax)(FLIF16RangesContext *ranges, const int plane,
> > +                   FLIF16ColorVal *prev_planes, FLIF16ColorVal *minv,
> > +                   FLIF16ColorVal *maxv);
> > +    void (*snap)(FLIF16RangesContext*, const int, FLIF16ColorVal*,
> > +                 FLIF16ColorVal*, FLIF16ColorVal*, FLIF16ColorVal*);
> > +    uint8_t is_static;
> > +    void (*close)(FLIF16RangesContext*);
> > +    void (*previous)(FLIF16RangesContext*);  //TODO : Maybe remove it
> later
> > +} FLIF16Ranges;
> > +
>
> > +typedef struct FLIF16TransformContext{
>
> Nit: space.
>
> > +    uint8_t t_no;
> > +    unsigned int segment;     ///< Segment the code is executing in.
> > +    int i;                    ///< Variable to store iteration number.
> > +    uint8_t done;
> > +    void *priv_data;
> > +} FLIF16TransformContext;
> > +
> > +typedef struct FLIF16Transform {
> > +    int16_t priv_data_size;
> > +    //Functions
> > +    int (*init) (FLIF16TransformContext *t_ctx, FLIF16RangesContext
> *r_ctx);
> > +    int (*read) (FLIF16TransformContext *t_ctx, FLIF16Context *ctx,
> > +                    FLIF16RangesContext *r_ctx);
> > +    FLIF16RangesContext *(*meta) (FLIF16Context *ctx,
> > +                                  FLIF16PixelData *frame, uint32_t
> frame_count,
> > +                                  FLIF16TransformContext *t_ctx,
> > +                                  FLIF16RangesContext *r_ctx);
> > +    int (*forward) (FLIF16Context *ctx, FLIF16TransformContext *t_ctx,
> FLIF16PixelData *frame);
> > +    int (*reverse) (FLIF16Context *ctx, FLIF16TransformContext *t_ctx,
> FLIF16PixelData *frame,
> > +                    uint32_t stride_row, uint32_t stride_col);
> > +    void (*configure) (FLIF16TransformContext *, const int);
> > +    void (*close) (FLIF16TransformContext *t_ctx);
> > +} FLIF16Transform;
> > +
> > +int32_t (*ff_flif16_maniac_ni_prop_ranges_init(unsigned int
> *prop_ranges_size,
> > +                                               FLIF16RangesContext
> *ranges,
> > +                                               uint8_t property,
> > +                                               uint8_t channels))[2];
> > +
> > +int32_t (*ff_flif16_maniac_prop_ranges_init(unsigned int
> *prop_ranges_size,
> > +                                            FLIF16RangesContext *ranges,
> > +                                            uint8_t property,
> > +                                            uint8_t channels))[2];
> > +
> > +int ff_flif16_planes_init(FLIF16Context *s, FLIF16PixelData *frames,
> > +                          uint8_t *is_const, uint8_t *const_plane_value,
> > +                          uint8_t lookback);
> > +
> > +FLIF16PixelData *ff_flif16_frames_init(FLIF16Context *s);
> > +
> > +void ff_flif16_frames_free(FLIF16PixelData **frames, uint32_t
> num_frames,
> > +                           uint32_t num_planes, uint8_t lookback);
> > +
> > +
> > +
> > +/*
> > + * All constant plane pixel setting should be illegal in theory.
> > + */
> > +
> > +static inline void ff_flif16_pixel_set(FLIF16Context *s,
> FLIF16PixelData *frame,
> > +                                       uint8_t plane, uint32_t row,
> uint32_t col,
> > +                                       FLIF16ColorVal value)
> > +{
> > +    if (s->plane_mode[plane])
> > +        ((FLIF16ColorVal *) frame->data[plane])[s->width * row + col] =
> value;
> > +    else
> > +        ((FLIF16ColorVal *) frame->data[plane])[0] = value;
> > +}
> > +
> > +static inline FLIF16ColorVal ff_flif16_pixel_get(FLIF16Context *s,
> > +                                                 FLIF16PixelData *frame,
> > +                                                 uint8_t plane,
> uint32_t row,
> > +                                                 uint32_t col)
> > +{
> > +    if (s->plane_mode[plane])
> > +        return ((FLIF16ColorVal *) frame->data[plane])[s->width * row +
> col];
> > +    else
> > +        return ((FLIF16ColorVal *) frame->data[plane])[0];
> > +}
> > +
> > +
> > +static inline void ff_flif16_pixel_setz(FLIF16Context *s,
> > +                                        FLIF16PixelData *frame,
> > +                                        uint8_t plane, int z, uint32_t
> row,
> > +                                        uint32_t col, FLIF16ColorVal
> value)
> > +{
> > +    if (s->plane_mode[plane])
> > +        ((FLIF16ColorVal *) frame->data[plane])[(row *
> ZOOM_ROWPIXELSIZE(z)) * s->width +
> > +                                                (col *
> ZOOM_COLPIXELSIZE(z))] = value;
> > +    else
> > +        ((FLIF16ColorVal *) frame->data[plane])[0] = value;
> > +}
> > +
> > +static inline FLIF16ColorVal ff_flif16_pixel_getz(FLIF16Context *s,
> > +                                                  FLIF16PixelData
> *frame,
> > +                                                  uint8_t plane, int z,
> > +                                                  size_t row, size_t
> col)
> > +{
> > +    if (s->plane_mode[plane])
> > +        return ((FLIF16ColorVal *) frame->data[plane])[(row *
> ZOOM_ROWPIXELSIZE(z)) *
> > +                                                       s->width + (col
> * ZOOM_COLPIXELSIZE(z))];
> > +    else
> > +        return ((FLIF16ColorVal *) frame->data[plane])[0];
> > +}
> > +
> > +static inline void ff_flif16_prepare_zoomlevel(FLIF16Context *s,
> > +                                               FLIF16PixelData *frame,
> > +                                               uint8_t plane, int z)
> > +{
> > +    frame->s_r[plane] = ZOOM_ROWPIXELSIZE(z) * s->width;
> > +    frame->s_c[plane] = ZOOM_COLPIXELSIZE(z);
> > +}
> > +
> > +static inline FLIF16ColorVal ff_flif16_pixel_get_fast(FLIF16Context *s,
> > +                                                      FLIF16PixelData
> *frame,
> > +                                                      uint8_t plane,
> uint32_t row,
> > +                                                      uint32_t col)
> > +{
> > +    if (s->plane_mode[plane])
> > +        return ((FLIF16ColorVal *) frame->data[plane])[row *
> frame->s_r[plane] + col * frame->s_c[plane]];
> > +
> > +    return 0;
> > +}
> > +
> > +static inline void ff_flif16_pixel_set_fast(FLIF16Context *s,
> > +                                            FLIF16PixelData *frame,
> > +                                            uint8_t plane, uint32_t row,
> > +                                            uint32_t col,
> FLIF16ColorVal value)
> > +{
> > +    if (s->plane_mode[plane])
> > +        ((FLIF16ColorVal *) frame->data[plane])[row * frame->s_r[plane]
> + col * frame->s_c[plane]] = value;
> > +}
> > +
> > +static inline void ff_flif16_copy_rows(FLIF16Context *s,
> > +                                       FLIF16PixelData *dest,
> > +                                       FLIF16PixelData *src, uint8_t
> plane,
> > +                                       uint32_t row, uint32_t col_start,
> > +                                       uint32_t col_end)
> > +{
> > +    for(uint32_t col = col_start; col < col_end; ++col) {
>
> > +        ff_flif16_pixel_set(s, dest, plane, row, col,
> ff_flif16_pixel_get(s, src, plane, row, col));
>
> ff_flif16_pixel_get() and ff_flif16_pixel_set() hide some arithmetic,
> re-computed for each pixel. I do not trust compilers to optimize them.
>
> Better take a pointer to the source, a pointer to the destination, and
> increment them by the right amount.
>
> > +    }
> > +}
> > +
> > +static inline void ff_flif16_copy_rows_stride(FLIF16Context *s,
> > +                                              FLIF16PixelData *dest,
> > +                                              FLIF16PixelData *src,
> uint8_t plane,
> > +                                              uint32_t row, uint32_t
> col_start,
> > +                                              uint32_t col_end,
> uint32_t stride)
> > +{
> > +    for(uint32_t col = col_start; col < col_end; col += stride) {
> > +        ff_flif16_pixel_set(s, dest, plane, row, col,
> ff_flif16_pixel_get(s, src, plane, row, col));
> > +    }
>
> Same.
>
> > +}
> > +#endif /* AVCODEC_FLIF16_H */
> > diff --git a/libavcodec/flif16_parser.c b/libavcodec/flif16_parser.c
> > new file mode 100644
> > index 0000000000..c795b44b4d
> > --- /dev/null
> > +++ b/libavcodec/flif16_parser.c
> > @@ -0,0 +1,189 @@
> > +/*
> > + * FLIF16 parser
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > + /**
> > +  * @file
> > +  * FLIF16 parser
> > +  */
> > +
> > +#include "flif16.h"
> > +#include "parser.h"
> > +#include "libavutil/avassert.h"
> > +#include "libavutil/bswap.h"
> > +
> > +#include <stdio.h> //remove
> > +#include <stdint.h>
> > +#include <stdlib.h>
> > +
> > +typedef enum FLIF16ParseStates {
>
> FLIF16_INIT_STATE = 0,
>
> It is not elegant to use an enum and a value that is not part of the
> enum.
>
> > +    FLIF16_HEADER = 1,
> > +    FLIF16_METADATA,
> > +    FLIF16_BITSTREAM
> > +} FLIF16ParseStates;
> > +
> > +typedef struct FLIF16ParseContext {
> > +    ParseContext pc;
>
> > +    int state;          ///< The section of the file the parser is in
> currently.
>
> FLIF16ParseStates state;
>
> > +    unsigned int index; ///< An index based on the current state.
> > +    uint8_t animated;   ///< Is image animated or not
> > +    uint8_t varint;     ///< Number of varints to process in sequence
> > +    uint32_t width;
> > +    uint32_t height;
> > +    uint32_t frames;
> > +    uint32_t meta;      ///< Size of a meta chunk
> > +    uint32_t count;
> > +} FLIF16ParseContext;
> > +
> > +
> > +// TODO revamp this function
> > +static int flif16_find_frame(FLIF16ParseContext *f, const uint8_t *buf,
> > +                             int buf_size)
> > +{
> > +    int next = END_NOT_FOUND;
> > +    int index;
> > +
> > +    for (index = 0; index < buf_size; index++) {
> > +        if (!f->state) {
> > +            if (!memcmp(flif16_header, buf + index, 4))
> > +                f->state = FLIF16_HEADER;
> > +            ++f->index;
>
> > +        } else if (f->state == FLIF16_HEADER) {
>
> switch (f->state)?
>
> > +            if (f->index == 3 + 1) {
> > +                // See whether image is animated or not
> > +                f->animated = (((buf[index] >> 4) > 4)?1:0);
> > +            } else if (f->index == (3 + 1 + 1)) {
> > +                // Start - 1 of the first varint
> > +                f->varint = 1;
> > +            } else if (f->varint) {
> > +                // Count varint
> > +                if (f->count == 5)
>
> > +                        return AVERROR(ENOMEM);
>
> AVERROR_INVALIDDATA
>
> > +
> > +                switch (f->varint) {
> > +                    case 1:
> > +                        VARINT_APPEND(f->width, buf[index]);
> > +                        break;
> > +
> > +                    case 2:
> > +                        VARINT_APPEND(f->height, buf[index]);
> > +                        break;
> > +
> > +                    case 3:
> > +                        VARINT_APPEND(f->frames, buf[index]);
> > +                        break;
> > +                }
> > +                if (buf[index] < 128) {
> > +                    if (f->varint < (2 + f->animated)) {
> > +                        switch (f->varint) {
> > +                            case 1: f->width++;  break;
> > +                            case 2: f->height++; break;
> > +                        }
> > +                        f->varint++;
> > +                        f->count = 0;
> > +                    } else {
> > +                        if (f->varint == 2)
> > +                            f->height++;
> > +                        if (f->animated)
> > +                            f->frames += 2;
> > +                        else
> > +                            f->frames = 1;
> > +                        f->state = FLIF16_METADATA;
> > +                        f->varint = 0;
> > +                        f->index = 0;
> > +                        f->count = 0;
> > +                        continue;
> > +                    }
> > +                } else {
> > +                    f->count++;
> > +                }
> > +            }
> > +            f->index++;
> > +        } else if (f->state == FLIF16_METADATA) {
> > +            if (f->index == 0) {
> > +                // Identifier for the bitstream chunk is a null byte.
> > +                if (buf[index] == 0) {
> > +                    f->state = FLIF16_BITSTREAM;
> > +                    return buf_size;
> > +                }
> > +            } else if (f->index < 3) {
> > +                // nop
> > +            } else if (f->index == 3) {
> > +                // Handle the size varint
> > +                f->varint = 1;
> > +            } else if (f->varint) {
> > +                if (f->count == 9)
>
> > +                    return AVERROR(ENOMEM);
>
> AVERROR_INVALIDDATA
>
> > +                if (buf[index] < 128) {
> > +                    f->varint = 0;
> > +                    f->count = 0;
> > +                }
> > +                VARINT_APPEND(f->meta, buf[index]);
> > +                f->count++;
> > +            } else if (f->meta > 1) {
> > +                // increment varint until equal to size
> > +                f->meta--;
> > +            } else {
> > +                f->meta = 0;
> > +                f->index = 0;
> > +                continue;
> > +            }
> > +            f->index++;
> > +        } else if (f->state == FLIF16_BITSTREAM) {
> > +            /* Since we cannot find the end of the bitstream without any
> > +             * processing, we will simply return each read chunk as a
> packet
> > +             * to the decoder.
> > +             */
> > +            printf("<Bitstream chunk size %dd>\n", buf_size);
> > +            return buf_size;
> > +        }
> > +    }
> > +    printf("End not found\n");
> > +    return next;
> > +}
> > +
> > +static int flif16_parse(AVCodecParserContext *s, AVCodecContext *avctx,
> > +                        const uint8_t **poutbuf, int *poutbuf_size,
> > +                        const uint8_t *buf, int buf_size)
> > +{
> > +    FLIF16ParseContext *fpc = s->priv_data;
> > +    int next;
> > +
> > +    next = flif16_find_frame(fpc, buf, buf_size);
> > +
> > +    if (ff_combine_frame(&fpc->pc, next, &buf, &buf_size) < 0) {
> > +        *poutbuf      = NULL;
> > +        *poutbuf_size = 0;
> > +        return buf_size;
> > +    }
> > +    printf("Width:%u\nHeight:%u\nFrames:%u\nEnd:%d\n",
> > +           fpc->width, fpc->height, fpc->frames, buf_size);
> > +    *poutbuf      = buf;
> > +    *poutbuf_size = buf_size;
> > +    return next;
> > +}
> > +
> > +AVCodecParser ff_flif16_parser = {
> > +    .codec_ids      = { AV_CODEC_ID_FLIF16 },
> > +    .priv_data_size = sizeof(FLIF16ParseContext),
> > +    .parser_parse   = flif16_parse,
> > +    .parser_close   = ff_parse_close,
> > +};
> > +
> > diff --git a/libavcodec/flif16_rangecoder.c
> b/libavcodec/flif16_rangecoder.c
> > new file mode 100644
> > index 0000000000..c8f1b7bbb0
> > --- /dev/null
> > +++ b/libavcodec/flif16_rangecoder.c
> > @@ -0,0 +1,464 @@
> > +/*
> > + * Range coder for FLIF16
>
> > + * Copyright (c) 2004, Michael Niedermayer,
>
> This looks like new code. Can you explain where Michael's copyright
> comes from?
>
> > + *               2010-2016, Jon Sneyers & Pieter Wuille,
>
> Same here.
>
> > + *               2020, Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > + /**
> > +  * @file
> > +  * Range coder for FLIF16
> > +  */
> > +
> > +#include "avcodec.h"
> > +#include "libavutil/common.h"
> > +#include "flif16_rangecoder.h"
> > +#include "flif16.h"
> > +
> > +// TODO write separate function for RAC encoder
> > +
> > +// The coder requires a certain number of bytes for initiialization. buf
> > +// provides it. gb is used by the coder functions for actual coding.
> > +void ff_flif16_rac_init(FLIF16RangeCoder *rc, GetByteContext *gb,
> uint8_t *buf,
> > +                        uint8_t buf_size)
> > +{
> > +    GetByteContext gbi;
> > +    if(!rc)
> > +        return;
> > +
> > +    if(buf_size < FLIF16_RAC_MAX_RANGE_BYTES)
> > +        return;
> > +
> > +    bytestream2_init(&gbi, buf, buf_size);
> > +
> > +    rc->range  = FLIF16_RAC_MAX_RANGE;
> > +    rc->gb     = gb;
> > +
>
> > +    for (uint32_t r = FLIF16_RAC_MAX_RANGE; r > 1; r >>= 8) {
> > +        rc->low <<= 8;
> > +        rc->low |= bytestream2_get_byte(&gbi);
> > +    }
>
> Do you need bytestream2_get_byte() for that? Testing that buf_size is
> large enough at the beginning and directly accessing buf seems simpler
> and more efficient.
>
> > +}
> > +
> > +void ff_flif16_rac_free(FLIF16RangeCoder *rc)
> > +{
> > +    if (!rc)
> > +        return;
>
> > +    av_freep(rc);
>
> Was this tested? av_freep() wants a pointer to pointer.
>
> > +}
> > +
> > +// TODO Maybe restructure rangecoder.c/h to fit a more generic case
> > +static void build_table(uint16_t *zero_state, uint16_t *one_state,
> size_t size,
> > +                        uint32_t factor, unsigned int max_p)
> > +{
> > +    const int64_t one = 1LL << 32;
> > +    int64_t p = one / 2;
> > +    unsigned int last_p8 = 0, p8;
> > +    unsigned int i;
> > +
> > +    for (i = 0; i < size / 2; i++) {
> > +        p8 = (size * p + one / 2) >> 32;
> > +        if (p8 <= last_p8)
> > +            p8 = last_p8 + 1;
> > +        if (last_p8 && last_p8 < size && p8 <= max_p)
> > +            one_state[last_p8] = p8;
> > +        p += ((one - p) * factor + one / 2) >> 32;
> > +        last_p8 = p8;
> > +    }
> > +
> > +    for (i = size - max_p; i <= max_p; i++) {
> > +        if (one_state[i])
> > +            continue;
> > +        p = (i * one + size / 2) / size;
> > +        p += ((one - p) * factor + one / 2) >> 32;
> > +        p8 = (size * p + one / 2) >> 32; //FIXME try without the one
> > +        if (p8 <= i)
> > +            p8 = i + 1;
> > +        if (p8 > max_p)
> > +            p8 = max_p;
> > +        one_state[i] = p8;
> > +    }
> > +
> > +    for (i = 1; i < size; i++)
> > +        zero_state[i] = size - one_state[size - i];
> > +}
> > +
> > +static inline uint32_t log4kf(int x, uint32_t base)
> > +{
>
> > +    int bits     = 8 * sizeof(int) - ff_clz(x);
>
> Code relying on sizeof(int) for anything but allocating memory is very
> suspicious.
>
> > +    uint64_t y   = ((uint64_t)x) << (32 - bits);
> > +    uint32_t res = base * (13 - bits);
> > +    uint32_t add = base;
> > +    while ((add > 1) && ((y & 0x7FFFFFFF) != 0)) {
> > +        y = (((uint64_t)y) * y + 0x40000000) >> 31;
> > +        add >>= 1;
> > +        if ((y >> 32) != 0) {
> > +            res -= add;
> > +            y >>= 1;
> > +        }
> > +    }
> > +    return res;
> > +}
> > +
> > +void ff_flif16_build_log4k_table(FLIF16Log4kTable *log4k)
> > +{
> > +    log4k->table[0] = 0;
> > +    for (int i = 1; i < 4096; i++)
> > +        log4k->table[i] = (log4kf(i, (65535UL << 16) / 12) +
> > +                          (1 << 15)) >> 16;
> > +    log4k->scale = 65535 / 12;
> > +}
> > +
> > +void ff_flif16_chancetable_init(FLIF16ChanceTable *ct, int alpha, int
> cut)
> > +{
> > +    build_table(ct->zero_state, ct->one_state, 4096, alpha, 4096 - cut);
> > +}
> > +
> > +void ff_flif16_chancecontext_init(FLIF16ChanceContext *ctx)
> > +{
>
> > +    if(!ctx)
> > +        return;
>
> You never call this except with &something as argument: remove this
> useless check, and let your code crash if you get something wrong when
> debugging.
>
> > +    memcpy(&ctx->data, &flif16_nz_int_chances,
> sizeof(flif16_nz_int_chances));
> > +}
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +FLIF16MultiscaleChanceTable *ff_flif16_multiscale_chancetable_init(void)
> > +{
> > +    unsigned int len = MULTISCALE_CHANCETABLE_DEFAULT_SIZE;
> > +    FLIF16MultiscaleChanceTable *ct = av_malloc(sizeof(*ct));
> > +    if (!ct)
> > +        return null
> > +    for (int i = 0; i < len; ++i) {
> > +        ff_flif16_chancetable_init(&ct->sub_table[i],
> > +                                   flif16_multiscale_alphas[i],
> > +                                   MULTISCALE_CHANCETABLE_DEFAULT_CUT);
> > +    }
> > +    return ct;
> > +}
> > +
> > +/**
> > + * Allocate and set all chances according to flif16_nz_int_chances
> > + */
> > +void
> ff_flif16_multiscale_chancecontext_init(FLIF16MultiscaleChanceContext *ctx)
> > +{
>
> > +    for (int i = 0; i < sizeof(flif16_nz_int_chances) /
> > +                        sizeof(flif16_nz_int_chances[0]); ++i)
>
> FF_ARRAY_ELEMS(); possibly same in other places.
>
> > +        ff_flif16_multiscale_chance_set(&ctx->data[i],
> flif16_nz_int_chances[i]);
> > +    return ctx;
> > +}
> > +
> > +#endif
> > +
> > +int ff_flif16_read_maniac_tree(FLIF16RangeCoder *rc,
> > +                               FLIF16MANIACContext *m,
> > +                               int32_t (*prop_ranges)[2],
> > +                               unsigned int prop_ranges_size,
> > +                               unsigned int channel)
> > +{
> > +    int oldp = 0, p = 0, split_val = 0, temp;
> > +
> > +    switch (rc->segment2) {
>
> > +        default: case 0:
>
> Nit: do not indent cases more than switch().
>
> > +            rc->segment2 = 0;
> > +            if (!(m->forest[channel])) {
> > +                m->forest[channel] =
> av_mallocz(sizeof(*(m->forest[channel])));
> > +                if (!(m->forest[channel]))
> > +                    return AVERROR(ENOMEM);
> > +                m->forest[channel]->data  =
> av_mallocz(MANIAC_TREE_BASE_SIZE *
> > +
>  sizeof(*(m->forest[channel]->data)));
>
> av_mallocz_array().
>
> > +                if (!m->forest[channel]->data)
> > +                    return AVERROR(ENOMEM);
> > +
> > +                m->stack = av_mallocz(MANIAC_TREE_BASE_SIZE *
> sizeof(*(m->stack)));
>
> Same.
>
> > +
> > +                if (!(m->stack))
>
> Nit: parentheses not necessary.
>
> > +                    return AVERROR(ENOMEM);
> > +
> > +                for (int i = 0; i < 3; ++i) {
> > +                    #ifdef MULTISCALE_CHANCES_ENABLED
> > +                    ff_flif16_multiscale_chancecontext_init(&m->ctx[i]);
> > +                    #else
> > +                    ff_flif16_chancecontext_init(&m->ctx[i]);
> > +                    #endif
> > +                }
> > +                m->stack_top = m->tree_top = 0;
>
> > +                m->forest[channel]->size    = MANIAC_TREE_BASE_SIZE;
>
> Strange spacing.
>
> > +                m->stack_size = MANIAC_TREE_BASE_SIZE;
> > +                m->stack[m->stack_top].id   = m->tree_top;
> > +                m->stack[m->stack_top].mode = 0;
> > +                ++m->stack_top;
> > +                ++m->tree_top;
> > +            }
> > +            ++rc->segment2;
> > +
> > +        case 1:
>
> > +            start:
> > +            if(!m->stack_top)
> > +                goto end;
> > +
>
> Looks like precisely the kind of code for which the rule "don't use
> goto" was coined. Better make it a proper loop.
>
> > +            oldp = m->stack[m->stack_top - 1].p;
> > +            if (!m->stack[m->stack_top - 1].visited) {
> > +                switch (m->stack[m->stack_top - 1].mode) {
> > +                    case 1:
> > +                        prop_ranges[oldp][0] = m->stack[m->stack_top -
> 1].min;
> > +                        prop_ranges[oldp][1] = m->stack[m->stack_top -
> 1].max;
> > +                        break;
> > +
> > +                    case 2:
> > +                        prop_ranges[oldp][0] = m->stack[m->stack_top -
> 1].min;
> > +                        break;
> > +                }
> > +            } else {
> > +                prop_ranges[oldp][1] = m->stack[m->stack_top - 1].max2;
> > +                --m->stack_top;
> > +                rc->segment2 = 1;
> > +                goto start;
> > +            }
> > +            m->stack[m->stack_top - 1].visited = 1;
> > +            ++rc->segment2;
> > +
> > +        case 2:
> > +            #ifdef MULTISCALE_CHANCES_ENABLED
> > +            RAC_GET(rc, &m->ctx[0], 0, prop_ranges_size,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].property,
> > +                    FLIF16_RAC_GNZ_MULTISCALE_INT);
> > +            #else
> > +            RAC_GET(rc, &m->ctx[0], 0, prop_ranges_size,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].property,
> > +                    FLIF16_RAC_GNZ_INT);
> > +            #endif
> > +            p = --(m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].property);
> > +            if (p == -1) {
> > +                --m->stack_top;
> > +                rc->segment2 = 1;
> > +                goto start;
> > +            }
> > +
> > +            m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].child_id = m->tree_top;
> > +            rc->oldmin = prop_ranges[p][0];
> > +            rc->oldmax = prop_ranges[p][1];
> > +            if (rc->oldmin >= rc->oldmax) {
> > +                printf("!!! rc->oldmin >= rc->oldmax\n");
>
> > +                return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +            }
> > +            ++rc->segment2;
> > +
> > +        case 3:
> > +            #ifdef MULTISCALE_CHANCES_ENABLED
> > +            RAC_GET(rc, &m->ctx[1], MANIAC_TREE_MIN_COUNT,
> MANIAC_TREE_MAX_COUNT,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].count,
> > +                    FLIF16_RAC_GNZ_MULTISCALE_INT);
> > +            #else
> > +            RAC_GET(rc, &m->ctx[1], MANIAC_TREE_MIN_COUNT,
> MANIAC_TREE_MAX_COUNT,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].count,
> > +                    FLIF16_RAC_GNZ_INT);
> > +            #endif
> > +            ++rc->segment2;
> > +
> > +        case 4:
> > +            #ifdef MULTISCALE_CHANCES_ENABLED
> > +            RAC_GET(rc, &m->ctx[2], rc->oldmin, rc->oldmax - 1,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].split_val,
> > +                    FLIF16_RAC_GNZ_MULTISCALE_INT);
> > +            #else
> > +            RAC_GET(rc, &m->ctx[2], rc->oldmin, rc->oldmax - 1,
> > +                    &m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].split_val,
> > +                    FLIF16_RAC_GNZ_INT);
> > +            #endif
> > +            split_val = m->forest[channel]->data[m->stack[m->stack_top
> - 1].id].split_val;
> > +            ++rc->segment2;
> > +
> > +        case 5:
> > +            if ((m->tree_top + 2) >= m->forest[channel]->size) {
> > +                m->forest[channel]->data =
> av_realloc(m->forest[channel]->data,
> > +                (m->forest[channel]->size) * 2 *
> sizeof(*(m->forest[channel]->data)));
> > +                if(!(m->forest[channel]->data))
> > +                    return AVERROR(ENOMEM);
> > +                m->forest[channel]->size *= 2;
> > +            }
> > +
> > +            if ((m->stack_top + 2) >= m->stack_size) {
>
> > +                m->stack = av_realloc(m->stack, (m->stack_size) * 2 *
> sizeof(*(m->stack)));
>
> av_realloc_array()
>
> > +                if(!(m->stack))
> > +                    return AVERROR(ENOMEM);
>
> This leaks the old m->stack. See av_realloc_f().
>
> > +                m->stack_size *= 2;
> > +            }
> > +
> > +            temp = m->forest[channel]->data[m->stack[m->stack_top -
> 1].id].property;
> > +
> > +            // Parent
> > +            m->stack[m->stack_top - 1].p    = temp;
> > +            m->stack[m->stack_top - 1].max2 = rc->oldmax;
> > +
> > +            // Right child
> > +            m->stack[m->stack_top].id      = m->tree_top + 1;
> > +            m->stack[m->stack_top].p       = temp;
> > +            m->stack[m->stack_top].min     = rc->oldmin;
> > +            m->stack[m->stack_top].max     = split_val;
> > +            m->stack[m->stack_top].mode    = 1;
> > +            m->stack[m->stack_top].visited = 0;
> > +            ++m->stack_top;
> > +
> > +            // Left Child
> > +            m->stack[m->stack_top].id      = m->tree_top;
> > +            m->stack[m->stack_top].p       = temp;
> > +            m->stack[m->stack_top].min     = split_val + 1;
> > +            m->stack[m->stack_top].mode    = 2;
> > +            m->stack[m->stack_top].visited = 0;
> > +            ++m->stack_top;
> > +
> > +            m->tree_top += 2;
> > +            rc->segment2 = 1;
> > +            goto start;
> > +    }
> > +
> > +    end:
> > +    m->forest[channel]->data = av_realloc(m->forest[channel]->data,
> > +                                          m->tree_top *
> sizeof(*m->forest[channel]->data)); // Maybe replace by fast realloc
> > +    if (!m->forest[channel]->data)
> > +        return AVERROR(ENOMEM);
> > +    m->forest[channel]->size = m->tree_top;
> > +    av_freep(&m->stack);
> > +    m->stack_top = 0;
> > +    rc->segment2 = 0;
> > +    return 0;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +void ff_flif16_maniac_close(FLIF16MANIACContext *m, uint8_t num_planes)
> > +{
> > +    for (int i = 0; i < num_planes; ++i) {
> > +        if (!m->forest[i])
> > +            continue;
> > +        if (m->forest[i]->data)
> > +            av_freep(&m->forest[i]->data);
> > +        if (m->forest[i]->leaves)
> > +            av_freep(&m->forest[i]->leaves);
> > +        av_freep(&m->forest[i]);
> > +    }
> > +
> > +    av_freep(&m->forest);
> > +    // Should be already freed in maniac reading, but checking anyway.
> > +    if(m->stack)
> > +        av_freep(&m->stack);
> > +}
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +FLIF16MultiscaleChanceContext
> *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m,
> > +                                                         uint8_t
> channel,
> > +                                                         int32_t
> *properties)
> > +#else
> > +FLIF16ChanceContext *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m,
> > +                                               uint8_t channel,
> > +                                               int32_t *properties)
> > +#endif
> > +{
> > +    unsigned int pos = 0;
> > +    uint32_t old_leaf;
> > +    uint32_t new_leaf;
> > +    FLIF16MANIACTree *tree = m->forest[channel];
> > +    FLIF16MANIACNode *nodes = tree->data;
> > +
> > +    if (!m->forest[channel]->leaves) {
> > +        m->forest[channel]->leaves = av_mallocz(MANIAC_TREE_BASE_SIZE *
> > +
> sizeof(*m->forest[channel]->leaves));
>
> av_mallocz_array();
>
> > +        m->forest[channel]->leaves_size = MANIAC_TREE_BASE_SIZE;
> > +        if(!m->forest[channel]->leaves)
> > +            return NULL;
> > +        ff_flif16_chancecontext_init(&m->forest[channel]->leaves[0]);
> > +        tree->leaves_top = 1;
> > +    }
> > +
> > +    while (nodes[pos].property != -1) {
> > +        if (nodes[pos].count < 0) {
> > +            if (properties[nodes[pos].property] > nodes[pos].split_val)
> > +                pos = nodes[pos].child_id;
> > +            else
> > +                pos = nodes[pos].child_id + 1;
> > +        } else if (nodes[pos].count > 0) {
> > +            --nodes[pos].count;
> > +            break;
> > +        } else {
> > +            --nodes[pos].count;
> > +            if ((tree->leaves_top) >= tree->leaves_size) {
> > +                m->forest[channel]->leaves =
> av_realloc(m->forest[channel]->leaves,
> > +
> sizeof(*m->forest[channel]->leaves) *
> > +
> m->forest[channel]->leaves_size * 2);
>
> > +                if (!m->forest[channel]->leaves)
> > +                    return NULL;
>
> This leaks old leaves.
>
> > +                m->forest[channel]->leaves_size *= 2;
> > +            }
> > +            old_leaf = nodes[pos].leaf_id;
> > +            new_leaf = tree->leaves_top;
> > +            memcpy(&m->forest[channel]->leaves[tree->leaves_top],
> > +                   &m->forest[channel]->leaves[nodes[pos].leaf_id],
> > +                   sizeof(*m->forest[channel]->leaves));
> > +            ++tree->leaves_top;
> > +            nodes[nodes[pos].child_id].leaf_id = old_leaf;
> > +            nodes[nodes[pos].child_id + 1].leaf_id = new_leaf;
> > +
> > +            if (properties[nodes[pos].property] > nodes[pos].split_val)
> > +                return &m->forest[channel]->leaves[old_leaf];
> > +            else
> > +                return &m->forest[channel]->leaves[new_leaf];
> > +        }
> > +    }
> > +    return
> &m->forest[channel]->leaves[m->forest[channel]->data[pos].leaf_id];
> > +}
> > +
> > +int ff_flif16_maniac_read_int(FLIF16RangeCoder *rc,
> > +                              FLIF16MANIACContext *m,
> > +                              int32_t *properties,
> > +                              uint8_t channel,
> > +                              int min, int max, int *target)
> > +{
> > +    if (!rc->maniac_ctx)
> > +        rc->segment2 = 0;
> > +
> > +    switch(rc->segment2) {
> > +        case 0:
> > +            if (min == max) {
> > +                *target = min;
> > +                goto end;
> > +            }
> > +            rc->maniac_ctx = ff_flif16_maniac_findleaf(m, channel,
> properties);
> > +            if(!rc->maniac_ctx) {
> > +                return AVERROR(ENOMEM);
> > +            }
> > +            ++rc->segment2;
> > +
> > +        case 1:
> > +            #ifdef MULTISCALE_CHANCES_ENABLED
> > +            RAC_GET(rc, rc->maniac_ctx, min, max, target,
> FLIF16_RAC_NZ_MULTISCALE_INT);
> > +            #else
> > +            RAC_GET(rc, rc->maniac_ctx, min, max, target,
> FLIF16_RAC_NZ_INT);
> > +            #endif
> > +
> > +    }
> > +
> > +    end:
> > +    rc->maniac_ctx = NULL;
> > +    rc->segment2 = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return 0;
> > +}
> > diff --git a/libavcodec/flif16_rangecoder.h
> b/libavcodec/flif16_rangecoder.h
> > new file mode 100644
> > index 0000000000..9cd2d5ee22
> > --- /dev/null
> > +++ b/libavcodec/flif16_rangecoder.h
> > @@ -0,0 +1,824 @@
> > +/*
> > + * Range coder for FLIF16
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * Range coder for FLIF16.
> > + */
> > +
> > +#ifndef FLIF16_RANGECODER_H
> > +#define FLIF16_RANGECODER_H
> > +
> > +#include "libavutil/mem.h"
> > +#include "libavutil/intmath.h"
> > +#include "bytestream.h"
> > +#include "rangecoder.h"
> > +
> > +#include <stdint.h>
> > +
> > +
> > +#define FLIF16_RAC_MAX_RANGE_BITS 24
> > +#define FLIF16_RAC_MAX_RANGE_BYTES (FLIF16_RAC_MAX_RANGE_BITS / 8)
> > +#define FLIF16_RAC_MIN_RANGE_BITS 16
> > +#define FLIF16_RAC_MAX_RANGE (uint32_t) 1 << FLIF16_RAC_MAX_RANGE_BITS
> > +#define FLIF16_RAC_MIN_RANGE (uint32_t) 1 << FLIF16_RAC_MIN_RANGE_BITS
> > +
> > +#define CHANCETABLE_DEFAULT_ALPHA (0xFFFFFFFF / 19)
> > +#define CHANCETABLE_DEFAULT_CUT 2
> > +
> > +// #define MULTISCALE_CHANCES_ENABLED
> > +
> > +#define MULTISCALE_CHANCETABLE_DEFAULT_SIZE 6
> > +#define MULTISCALE_CHANCETABLE_DEFAULT_CUT  8
> > +
> > +#define MANIAC_TREE_BASE_SIZE 1600
> > +#define MANIAC_TREE_MIN_COUNT 1
> > +#define MANIAC_TREE_MAX_COUNT 512
> > +
> > +typedef enum FLIF16RACReader {
> > +    FLIF16_RAC_BIT = 0,
> > +    FLIF16_RAC_UNI_INT8,
> > +    FLIF16_RAC_UNI_INT16,
> > +    FLIF16_RAC_UNI_INT32,
> > +    FLIF16_RAC_CHANCE,
> > +    FLIF16_RAC_NZ_INT,
> > +    FLIF16_RAC_GNZ_INT,
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +    FLIF16_RAC_NZ_MULTISCALE_INT,
> > +    FLIF16_RAC_GNZ_MULTISCALE_INT
> > +#endif
> > +} FLIF16RACReader;
> > +
> > +typedef struct FLIF16ChanceTable {
> > +    uint16_t zero_state[4096];
> > +    uint16_t one_state[4096];
> > +} FLIF16ChanceTable;
> > +
> > +typedef struct FLIF16MultiscaleChanceTable {
> > +    FLIF16ChanceTable sub_table[MULTISCALE_CHANCETABLE_DEFAULT_SIZE];
> > +} FLIF16MultiscaleChanceTable;
> > +
> > +
> > +typedef struct FLIF16Log4kTable {
> > +    uint16_t table[4097];
> > +    int scale;
> > +} FLIF16Log4kTable;
> > +
>
> > +static const uint32_t flif16_multiscale_alphas[] = {
> > +    21590903, 66728412, 214748365, 7413105, 106514140, 10478104
> > +};
>
> Please add a short comment to explain.
>
> > +
> > +typedef struct FLIF16MultiscaleChance {
> > +    uint16_t chances[MULTISCALE_CHANCETABLE_DEFAULT_SIZE];
> > +    uint32_t quality[MULTISCALE_CHANCETABLE_DEFAULT_SIZE];
> > +    uint8_t best;
> > +} FLIF16MultiscaleChance;
> > +
> > +static uint16_t flif16_nz_int_chances[] = {
> > +    1000,        // ZERO
> > +    2048,        // SIGN (0)  (1)
> > +    1000, 1000,  // EXP:  0,   1
> > +    1200, 1200,  // EXP:  2,   3
> > +    1500, 1500,  // EXP:  4,   5
> > +    1750, 1750,  // EXP:  6,   7
> > +    2000, 2000,  // EXP:  8,   9
> > +    2300, 2300,  // EXP:  10,  11
> > +    2800, 2800,  // EXP:  12,  13
> > +    2400, 2400,  // EXP:  14,  15
> > +    2300, 2300,  // EXP:  16,  17
> > +    2048, 2048,  // EXP:  18,  19
> > +    2048, 2048,  // EXP:  20,  21
> > +    2048, 2048,  // EXP:  22,  23
> > +    2048, 2048,  // EXP:  24,  25
> > +    2048, 2048,  // EXP:  26,  27
> > +    2048, 2048,  // EXP:  28,  29
> > +    2048, 2048,  // EXP:  30,  31
> > +    2048, 2048,  // EXP:  32,  33
> > +    1900,        // MANT: 0
> > +    1850,        // MANT: 1
> > +    1800,        // MANT: 2
> > +    1750,        // MANT: 3
> > +    1650,        // MANT: 4
> > +    1600,        // MANT: 5
> > +    1600,        // MANT: 6
> > +    2048,        // MANT: 7
> > +    2048,        // MANT: 8
> > +    2048,        // MANT: 9
> > +    2048,        // MANT: 10
> > +    2048,        // MANT: 11
> > +    2048,        // MANT: 12
> > +    2048,        // MANT: 13
> > +    2048,        // MANT: 14
> > +    2048,        // MANT: 15
> > +    2048,        // MANT: 16
> > +    2048         // MANT: 17
> > +};
> > +
> > +#define NZ_INT_ZERO (0)
> > +#define NZ_INT_SIGN (1)
> > +#define NZ_INT_EXP(k) ((2 + (k)))
> > +#define NZ_INT_MANT(k) ((36 + (k)))
> > +
> > +
> > +typedef struct FLIF16MultiscaleChanceContext {
> > +    FLIF16MultiscaleChance data[sizeof(flif16_nz_int_chances) /
> sizeof(flif16_nz_int_chances[0])];
> > +} FLIF16MultiscaleChanceContext;
> > +
> > +// Maybe rename to symbol context
> > +typedef struct FLIF16ChanceContext {
>
> > +    uint16_t data[sizeof(flif16_nz_int_chances) /
> sizeof(flif16_nz_int_chances[0])];
>
> FF_ARRAY_ELEMS()
>
> > +} FLIF16ChanceContext;
> > +
> > +typedef struct FLIF16RangeCoder {
> > +    uint_fast32_t range;
> > +    uint_fast32_t low;
> > +    uint16_t chance;
> > +    uint8_t active;   ///< Is an integer reader currently active (to
> save/
> > +                      ///  transfer state)
> > +
> > +    // uni_int state management
> > +    uint32_t min;
> > +    uint32_t len;
> > +
> > +    // nz_int state management
> > +    uint8_t segment; ///< The "segment" the function currently is in
> > +    uint8_t sign;
> > +    int amin, amax, emax, e, have, left, minabs1, maxabs0, pos;
> > +
> > +    // maniac_int state management
> > +    uint8_t segment2;
> > +    int oldmin, oldmax;
> > +
> > +    #ifdef MULTISCALE_CHANCES_ENABLED
> > +    FLIF16MultiscaleChanceContext *maniac_ctx;
> > +    #else
> > +    FLIF16ChanceContext *maniac_ctx;
> > +    #endif
> > +
> > +    FLIF16ChanceTable ct;
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +    FLIF16MultiscaleChanceTable *mct;
> > +    FLIF16Log4kTable log4k;
> > +#endif
> > +    GetByteContext *gb;
> > +} FLIF16RangeCoder;
> > +
> > +/**
> > + * The Stack used to construct the MANIAC tree
> > + */
> > +typedef struct FLIF16MANIACStack {
> > +    unsigned int id;
> > +    int p;
> > +    int min;
> > +    int max;
> > +    int max2;
> > +    uint8_t mode;
> > +    uint8_t visited;
> > +} FLIF16MANIACStack;
> > +
> > +typedef struct FLIF16MANIACNode {
> > +    int32_t property;
> > +    int32_t count;
> > +    int32_t split_val;
> > +    int32_t child_id;
> > +    int32_t leaf_id;
> > +} FLIF16MANIACNode;
> > +
> > +typedef struct FLIF16MANIACTree {
> > +    FLIF16MANIACNode *data;
>
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +    FLIF16MultiscaleChanceContext *leaves;
> > +#else
> > +    FLIF16ChanceContext *leaves;
> > +#endif
>
> You could avoid these multiple ifdef with a single conditional typedef.
>
> > +    unsigned int size;
> > +    unsigned int leaves_size;
> > +    unsigned int leaves_top;
> > +} FLIF16MANIACTree;
> > +
> > +typedef struct FLIF16MANIACContext {
> > +    FLIF16MANIACTree **forest;
> > +    FLIF16MANIACStack *stack;
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +    FLIF16MultiscaleChanceContext ctx[3];
> > +#else
> > +    FLIF16ChanceContext ctx[3];
> > +#endif
> > +    unsigned int tree_top;
> > +    unsigned int stack_top;
> > +    unsigned int stack_size;
> > +} FLIF16MANIACContext;
> > +
> > +void ff_flif16_rac_init(FLIF16RangeCoder *rc, GetByteContext *gb,
> uint8_t *buf,
> > +                        uint8_t buf_size);
> > +
> > +void ff_flif16_rac_free(FLIF16RangeCoder *rc);
> > +
> > +void ff_flif16_chancecontext_init(FLIF16ChanceContext *ctx);
> > +
> > +void ff_flif16_chancetable_init(FLIF16ChanceTable *ct, int alpha, int
> cut);
> > +
> > +void ff_flif16_build_log4k_table(FLIF16Log4kTable *log4k);
> > +
> > +int ff_flif16_read_maniac_tree(FLIF16RangeCoder *rc,
> > +                               FLIF16MANIACContext *m,
> > +                               int32_t (*prop_ranges)[2],
> > +                               unsigned int prop_ranges_size,
> > +                               unsigned int channel);
> > +
> > +void ff_flif16_maniac_close(FLIF16MANIACContext *m, uint8_t num_planes);
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +
> > +void
> ff_flif16_multiscale_chancecontext_init(FLIF16MultiscaleChanceContext *ctx);
> > +
> > +FLIF16MultiscaleChanceTable
> *ff_flif16_multiscale_chancetable_init(void);
> > +
> > +FLIF16MultiscaleChanceContext
> *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m,
> > +                                                         uint8_t
> channel,
> > +                                                         int32_t
> *properties);
> > +#else
> > +FLIF16ChanceContext *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m,
> > +                                               uint8_t channel,
> > +                                               int32_t *properties);
> > +#endif
> > +
> > +int ff_flif16_maniac_read_int(FLIF16RangeCoder *rc,
> > +                              FLIF16MANIACContext *m,
> > +                              int32_t *properties,
> > +                              uint8_t channel,
> > +                              int min, int max, int *target);
> > +
> > +#define MANIAC_GET(rc, m, prop, channel, min, max, target) \
> > +    if (!ff_flif16_maniac_read_int((rc), (m), (prop), (channel), (min),
> (max), (target))) {\
> > +        goto need_more_data; \
> > +    }
> > +
> > +// Functions
> > +
> > +static inline int ff_flif16_rac_renorm(FLIF16RangeCoder *rc)
> > +{
> > +    uint32_t left;
> > +    while (rc->range <= FLIF16_RAC_MIN_RANGE) {
> > +        left = bytestream2_get_bytes_left(rc->gb);
> > +        if (!left) {
> > +            return 0;
> > +        }
> > +        rc->low <<= 8;
> > +        rc->range <<= 8;
> > +        rc->low |= bytestream2_get_byte(rc->gb);
> > +        if(!left) {
> > +            return 0;
> > +        } else {
> > +            --left;
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +static inline uint8_t ff_flif16_rac_get(FLIF16RangeCoder *rc, uint32_t
> chance,
> > +                                        uint8_t *target)
> > +{
> > +    if (rc->low >= rc->range - chance) {
> > +        rc->low -= rc->range - chance;
> > +        rc->range = chance;
> > +        *target = 1;
> > +    } else {
> > +        rc->range -= chance;
> > +        *target = 0;
> > +    }
> > +
> > +    return 1;
> > +}
> > +
> > +static inline uint8_t ff_flif16_rac_read_bit(FLIF16RangeCoder *rc,
> > +                                             uint8_t *target)
> > +{
> > +    return ff_flif16_rac_get(rc, rc->range >> 1, target);
> > +}
> > +
> > +static inline uint32_t ff_flif16_rac_read_chance(FLIF16RangeCoder *rc,
> > +                                                 uint16_t b12, uint8_t
> *target)
> > +{
> > +    uint32_t ret;
> > +
>
> > +    if (sizeof(rc->range) > 4)
> > +        ret = ((rc->range) * b12 + 0x800) >> 12;
> > +    else
> > +        ret = (((((rc->range) & 0xFFF) * b12 + 0x800) >> 12) +
> > +              (((rc->range) >> 12) * b12));
>
> Cast b12 to uint64_t and let the compiler optimize this.
>
> > +
> > +    return ff_flif16_rac_get(rc, ret, target);
> > +}
> > +
> > +/**
> > + * Reads a Uniform Symbol Coded Integer.
> > + */
> > +static inline int ff_flif16_rac_read_uni_int(FLIF16RangeCoder *rc,
> > +                                             uint32_t min, uint32_t len,
> > +                                             int type,
> > +                                             void *target)
> > +{
> > +    int med;
> > +    uint8_t bit;
> > +
> > +    if (!rc->active) {
> > +        rc->min = min;
> > +        rc->len = len;
> > +        rc->active = 1;
> > +    }
> > +
> > +    if ((rc->len) > 0) {
> > +        ff_flif16_rac_read_bit(rc, &bit);
> > +        med = (rc->len) / 2;
> > +        if (bit) {
> > +            rc->min += med + 1;
> > +            rc->len -= med + 1;
> > +        } else {
> > +            rc->len = med;
> > +        }
> > +        return 0;
> > +    } else {
> > +        switch (type) {
> > +            case FLIF16_RAC_UNI_INT8:
> > +                *((uint8_t *) target) = rc->min;
> > +                break;
> > +
> > +            case FLIF16_RAC_UNI_INT16:
> > +                *((uint16_t *) target) = rc->min;
> > +                break;
> > +
> > +            case FLIF16_RAC_UNI_INT32:
> > +                *((uint32_t *) target) = rc->min;
> > +                break;
> > +        }
> > +        rc->active = 0;
> > +        return 1;
> > +    }
> > +}
> > +
> > +// Nearzero integer definitions
> > +
> > +static inline void ff_flif16_chancetable_put(FLIF16RangeCoder *rc,
> > +                                             FLIF16ChanceContext *ctx,
> > +                                             uint16_t type, uint8_t bit)
> > +{
> > +    ctx->data[type] = (!bit) ? rc->ct.zero_state[ctx->data[type]]
> > +                             : rc->ct.one_state[ctx->data[type]];
> > +}
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +static inline void ff_flif16_chance_estim(FLIF16RangeCoder *rc,
> > +                                          uint16_t chance, uint8_t bit,
> > +                                          uint64_t *total)
> > +{
> > +    *total += rc->log4k.table[bit ? chance : 4096 - chance];
> > +}
> > +#endif
> > +
> > +/**
> > + * Reads a near-zero encoded symbol into the RAC probability
> model/chance table
> > + * @param type The symbol chance specified by the NZ_INT_* macros
> > + */
> > +// TODO remove return value
> > +static inline uint8_t ff_flif16_rac_read_symbol(FLIF16RangeCoder *rc,
> > +                                                FLIF16ChanceContext
> *ctx,
> > +                                                uint16_t type,
> > +                                                uint8_t *target)
> > +{
> > +    ff_flif16_rac_read_chance(rc, ctx->data[type], target);
> > +    ff_flif16_chancetable_put(rc, ctx, type, *target);
> > +    return 1;
> > +}
> > +
> > +// NearZero Integer Coder
> > +
> > +static inline int ff_flif16_rac_nz_read_internal(FLIF16RangeCoder *rc,
> > +                                                 FLIF16ChanceContext
> *ctx,
> > +                                                 uint16_t type, uint8_t
> *target)
> > +{
> > +    int flag = 0;
> > +    while (!flag) {
> > +        if(!ff_flif16_rac_renorm(rc))
> > +            return 0; // EAGAIN condition
> > +        flag = ff_flif16_rac_read_symbol(rc, ctx, type, target);
> > +    }
> > +    return 1;
> > +}
> > +
> > +#define RAC_NZ_GET(rc, ctx, chance, target)
>         \
> > +    if (!ff_flif16_rac_nz_read_internal((rc), (ctx), (chance),
>        \
> > +                                        (uint8_t *) (target))) {
>        \
> > +        goto need_more_data;
>        \
> > +    }
> > +
>
> > +static inline int ff_flif16_rac_read_nz_int(FLIF16RangeCoder *rc,
> > +                                            FLIF16ChanceContext *ctx,
> > +                                            int min, int max, int
> *target)
>
> I am worried about the size of all these inline functions that call each
> other multiple times, growing exponentially. Bigger code will stress the
> cache more and make everything slower. Better make them normal
> functions.
>
> > +{
> > +    uint8_t temp = 0;
> > +    if (min == max) {
> > +        *target = min;
> > +        rc->active = 0;
> > +        return 1;
> > +    }
> > +
> > +    if (!rc->active) {
> > +        rc->segment = 0;
> > +        rc->amin    = 1;
> > +        rc->active  = 1;
> > +        rc->sign    = 0;
> > +        rc->have    = 0;
> > +    }
> > +
>
> > +    switch (rc->segment) {
> > +        case 0:
>
> Nit: indentation.
>
> > +            RAC_NZ_GET(rc, ctx, NZ_INT_ZERO, &(temp));
> > +            if (temp) {
> > +                *target = 0;
> > +                rc->active = 0;
> > +                return 1;
> > +            }
> > +            ++rc->segment;
> > +
> > +        case 1:
> > +            if (min < 0) {
> > +                if (max > 0) {
> > +                    RAC_NZ_GET(rc, ctx, NZ_INT_SIGN, &(rc->sign));
> > +                } else {
> > +                    rc->sign = 0;
> > +                }
> > +            } else {
> > +                rc->sign = 1;
> > +            }
> > +            rc->amax = (rc->sign ? max : -min);
> > +            rc->emax = ff_log2(rc->amax);
> > +            rc->e    = ff_log2(rc->amin);
> > +            ++rc->segment;
> > +
> > +        case 2:
> > +            for (; (rc->e) < (rc->emax); (rc->e++)) {
> > +                RAC_NZ_GET(rc, ctx, NZ_INT_EXP((((rc->e) << 1) +
> rc->sign)),
> > +                           &(temp));
> > +                if (temp)
> > +                    break;
> > +                temp = 0;
> > +            }
> > +            rc->have = (1 << (rc->e));
> > +            rc->left = rc->have - 1;
> > +            rc->pos  = rc->e;
> > +            ++rc->segment;
> > +
> > +         /*
> > +          case 3 and case 4 mimic a for loop.
> > +          This is done to separate the RAC read statement.
> > +          for(pos = e; pos > 0; --pos) ...
> > +          TODO replace entirely with an actual for loop.
> > +         */
> > +        case 3:
>
> > +            loop: /* start for */
>
> Avoid goto, make it a real loop.
>
> > +            if ((rc->pos) <= 0)
> > +                goto end;
> > +            --(rc->pos);
> > +            rc->left >>= 1;
> > +            rc->minabs1 = (rc->have) | (1 << (rc->pos));
> > +            rc->maxabs0 = (rc->have) | (rc->left);
> > +            ++rc->segment;
> > +
> > +        case 4:
> > +            if ((rc->minabs1) > (rc->amax)) {
> > +                --rc->segment;
> > +                goto loop; /* continue; */
> > +            } else if ((rc->maxabs0) >= (rc->amin)) {
> > +                RAC_NZ_GET(rc, ctx, NZ_INT_MANT(rc->pos), &temp);
> > +                if (temp)
> > +                    rc->have = rc->minabs1;
> > +                temp = 0;
> > +            } else
> > +                rc->have = rc->minabs1;
> > +            --rc->segment;
> > +            goto loop; /* end for */
> > +    }
> > +
> > +    end:
> > +    *target = ((rc->sign) ? (rc->have) : -(rc->have));
> > +    rc->active = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return 0;
> > +}
> > +
> > +static inline int ff_flif16_rac_read_gnz_int(FLIF16RangeCoder *rc,
> > +                                             FLIF16ChanceContext *ctx,
> > +                                             int min, int max, int
> *target)
> > +{
> > +    int ret;
> > +    if (min > 0) {
> > +        ret = ff_flif16_rac_read_nz_int(rc, ctx, 0, max - min, target);
> > +        if (ret)
> > +            *target += min;
> > +    } else if (max < 0) {
> > +        ret =  ff_flif16_rac_read_nz_int(rc, ctx, min - max, 0, target);
> > +        if (ret)
> > +            *target += max;
> > +    } else
> > +        ret = ff_flif16_rac_read_nz_int(rc, ctx, min, max, target);
> > +    return ret;
> > +
> > +}
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +// Multiscale chance definitions
> > +
> > +static inline void
> ff_flif16_multiscale_chance_set(FLIF16MultiscaleChance *c,
> > +                                                   uint16_t chance)
> > +{
> > +    for (int i = 0; i < MULTISCALE_CHANCETABLE_DEFAULT_SIZE; i++) {
> > +        c->chances[i] = chance;
> > +        c->quality[i] = 0;
> > +    }
> > +    c->best = 0;
> > +}
> > +
>
> > +static inline uint16_t
> ff_flif16_multiscale_chance_get(FLIF16MultiscaleChance c)
> > +{
> > +    return c.chances[c.best];
> > +}
>
> This does not look very useful.
>
> > +
> > +static inline void
> ff_flif16_multiscale_chancetable_put(FLIF16RangeCoder *rc,
> > +
> FLIF16MultiscaleChanceContext *ctx,
> > +                                                        uint16_t type,
> uint8_t bit)
> > +{
> > +    FLIF16MultiscaleChance *c = &ctx->data[type];
> > +    uint64_t sbits, oqual;
> > +    for (int i = 0; i < MULTISCALE_CHANCETABLE_DEFAULT_SIZE; ++i) {
> > +        sbits = 0;
> > +        ff_flif16_chance_estim(rc, c->chances[i], bit, &sbits);
> > +        oqual = c->quality[i];
> > +        c->quality[i] = (oqual * 255 + sbits * 4097 + 128) >> 8;
> > +        c->chances[i] = (bit) ?
> rc->mct->sub_table[i].one_state[c->chances[i]]
> > +                              :
> rc->mct->sub_table[i].zero_state[c->chances[i]];
> > +    }
> > +    for (int i = 0; i < MULTISCALE_CHANCETABLE_DEFAULT_SIZE; ++i)
> > +        if (c->quality[i] < c->quality[c->best])
> > +            c->best = i;
> > +}
> > +
> > +static inline int ff_flif16_rac_read_multiscale_symbol(FLIF16RangeCoder
> *rc,
> > +
>  FLIF16MultiscaleChanceContext *ctx,
> > +                                                       uint16_t type,
> uint8_t *target)
> > +{
> > +    ff_flif16_rac_read_chance(rc,
> ff_flif16_multiscale_chance_get(ctx->data[type]), target);
> > +    ff_flif16_multiscale_chancetable_put(rc, ctx, type, *target);
> > +    return 1;
> > +}
> > +
> > +static inline int
> ff_flif16_rac_nz_read_multiscale_internal(FLIF16RangeCoder *rc,
> > +
> FLIF16MultiscaleChanceContext *ctx,
> > +                                                            uint16_t
> type, uint8_t *target)
> > +{
> > +    int flag = 0;
> > +    // Maybe remove the while loop
> > +    while (!flag) {
> > +        if(!ff_flif16_rac_renorm(rc))
> > +            return 0; // EAGAIN condition
> > +        flag = ff_flif16_rac_read_multiscale_symbol(rc, ctx, type,
> target);
> > +    }
> > +    return 1;
> > +}
> > +
> > +#define RAC_NZ_MULTISCALE_GET(rc, ctx, chance, target)
>        \
> > +    if (!ff_flif16_rac_nz_read_multiscale_internal((rc), (ctx),
> (chance),      \
> > +                                                   (uint8_t *)
> (target))) {    \
> > +        goto need_more_data;
>        \
> > +    }
> > +
> > +static inline int ff_flif16_rac_read_nz_multiscale_int(FLIF16RangeCoder
> *rc,
> > +
>  FLIF16MultiscaleChanceContext *ctx,
> > +                                                      int min, int max,
> int *target)
> > +{
> > +    int temp = 0;
> > +
> > +    if (min == max) {
> > +        *target = min;
> > +        goto end;
> > +    }
> > +
> > +    if (!rc->active) {
> > +        rc->segment = 0;
> > +        rc->amin    = 1;
> > +        rc->active  = 1;
> > +        rc->sign    = 0;
> > +        rc->have    = 0;
> > +    }
> > +
>
> > +    switch (rc->segment) {
> > +        case 0:
>
> Nit: indentation.
>
> > +            RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_ZERO, &(temp));
> > +            if (temp) {
> > +                *target = 0;
> > +                goto end;
> > +            }
>
> > +            ++rc->segment;__PLN__
>
> What is this __PLN__?
>
> > +
> > +        case 1:
> > +            if (min < 0) {
> > +                if (max > 0) {
> > +                    RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_SIGN,
> &(rc->sign));
> > +                } else {
> > +                    rc->sign = 0;
> > +                }
> > +            } else {
> > +                rc->sign = 1;
> > +            }
> > +            rc->amax = (rc->sign ? max : -min);
> > +            rc->emax = ff_log2(rc->amax);
> > +            rc->e    = ff_log2(rc->amin);
> > +            ++rc->segment;__PLN__
> > +
> > +        case 2:
> > +            for (; (rc->e) < (rc->emax); (rc->e++)) {
> > +                RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_EXP((((rc->e) <<
> 1) + rc->sign)),
> > +                                      &(temp));
> > +                if (temp)
> > +                    break;
> > +                temp = 0;
> > +            }
> > +            rc->have = (1 << (rc->e));
> > +            rc->left = rc->have - 1;
> > +            rc->pos  = rc->e;
> > +            ++rc->segment;__PLN__
> > +
> > +        /*
> > +         * case 3 and case 4 mimic a for loop.
> > +         * This is done to separate the RAC read statement.
> > +         * for(pos = e; pos > 0; --pos) ...
> > +         * TODO replace with actual for loop.
> > +         */
> > +        case 3:
>
> > +            loop: /* start for */
>
> Make it a real loop.
>
> > +            if ((rc->pos) <= 0)
> > +                goto end;
> > +            --(rc->pos);
> > +            rc->left >>= 1;
> > +            rc->minabs1 = (rc->have) | (1 << (rc->pos));
> > +            rc->maxabs0 = (rc->have) | (rc->left);
> > +            ++rc->segment;__PLN__
> > +
> > +        case 4:
> > +            if ((rc->minabs1) > (rc->amax)) {
> > +                --rc->segment;
> > +                goto loop; /* continue; */
> > +            } else if ((rc->maxabs0) >= (rc->amin)) {
> > +                RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_MANT(rc->pos),
> &temp);
> > +                if (temp)
> > +                    rc->have = rc->minabs1;
> > +                temp = 0;
> > +            }
> > +            else
> > +                rc->have = rc->minabs1;
> > +            --rc->segment;
> > +            goto loop; /* end for */
> > +    }
> > +
> > +    end:
> > +    *target = ((rc->sign) ? (rc->have) : -(rc->have));
> > +    rc->active = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return 0;
> > +}
> > +
> > +static inline int
> ff_flif16_rac_read_gnz_multiscale_int(FLIF16RangeCoder *rc,
> > +
> FLIF16MultiscaleChanceContext *ctx,
> > +                                                        int min, int
> max, int *target)
> > +{
> > +    int ret;
> > +    if (min > 0) {
> > +        ret = ff_flif16_rac_read_nz_multiscale_int(rc, ctx, 0, max -
> min, target);
> > +        if (ret)
> > +            *target += min;
> > +    } else if (max < 0) {
> > +        ret =  ff_flif16_rac_read_nz_multiscale_int(rc, ctx, min - max,
> 0, target);
> > +        if (ret)
> > +            *target += max;
> > +    } else
> > +        ret = ff_flif16_rac_read_nz_multiscale_int(rc, ctx, min, max,
> target);
> > +    return ret;
> > +
> > +}
> > +#endif
> > +
> > +/*
> > +RAC_NZ_DEFINE(, FLIF16ChanceContext)
> > +RAC_GNZ_DEFINE(, FLIF16ChanceContext)
> > +
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +
> > +#undef RAC_NZ_GET
> > +
> > +#define RAC_NZ_GET(rc, ctx, chance, target)
>         \
> > +    if (!ff_flif16_rac_nz_read_multiscale_internal((rc), (ctx),
> (chance),      \
> > +                                            (uint8_t *) (target))) {
>        \
> > +        goto need_more_data;
>        \
> > +    }
> > +
> > +RAC_NZ_DEFINE(_multiscale, FLIF16MultiscaleChanceContext)
> > +RAC_GNZ_DEFINE(_multiscale, FLIF16MultiscaleChanceContext)
> > +
> > +#endif
> > +*/
> > +
> > +/**
> > + * Reads an integer encoded by FLIF's RAC.
> > + * @param[in]  val1 A generic value, chosen according to the required
> type
> > + * @param[in]  val2 Same as val1
> > + * @param[out] target The place where the resultant value should be
> written to
> > + * @param[in]  type The type of the integer to be decoded specified by
> > + *             FLIF16RACTypes
> > + * @return 0 on bytestream empty, 1 on successful decoding.
> > + */
> > +static inline int ff_flif16_rac_process(FLIF16RangeCoder *rc,
> > +                                        void *ctx,
> > +                                        int val1, int val2, void
> *target,
> > +                                        int type)
> > +{
> > +    int flag = 0;
> > +    while (!flag) {
> > +        if(!ff_flif16_rac_renorm(rc)) {
> > +            return 0; // EAGAIN condition
> > +        }
> > +
>
> > +        switch (type) {
> > +            case FLIF16_RAC_BIT:
>
> Nit: indentation.
>
> > +                flag = ff_flif16_rac_read_bit(rc, (uint8_t *) target);
> > +                break;
> > +
> > +            case FLIF16_RAC_UNI_INT8:
> > +            case FLIF16_RAC_UNI_INT16:
> > +            case FLIF16_RAC_UNI_INT32:
> > +                flag = ff_flif16_rac_read_uni_int(rc, val1, val2, type,
> target);
> > +                break;
> > +
> > +            case FLIF16_RAC_CHANCE:
> > +                flag = ff_flif16_rac_read_chance(rc, val1, (uint8_t *)
> target);
> > +                break;
> > +
> > +            case FLIF16_RAC_NZ_INT:
> > +                // handle nz_ints
> > +                flag = ff_flif16_rac_read_nz_int(rc,
> (FLIF16ChanceContext *) ctx,
> > +                                                 val1, val2, (int *)
> target);
> > +                break;
> > +
> > +            case FLIF16_RAC_GNZ_INT:
> > +                // handle gnz_ints
> > +                flag = ff_flif16_rac_read_gnz_int(rc,
> (FLIF16ChanceContext *) ctx,
> > +                                                  val1, val2, (int *)
> target);
> > +                break;
> > +#ifdef MULTISCALE_CHANCES_ENABLED
> > +            case FLIF16_RAC_NZ_MULTISCALE_INT:
> > +                // handle nz_ints
> > +                flag = ff_flif16_rac_read_nz_multiscale_int(rc,
> (FLIF16MultiscaleChanceContext *) ctx,
> > +                                                            val1, val2,
> (int *) target);
> > +                break;
> > +
> > +            case FLIF16_RAC_GNZ_MULTISCALE_INT:
> > +                // handle multiscale nz_ints
> > +                flag = ff_flif16_rac_read_gnz_multiscale_int(rc,
> (FLIF16MultiscaleChanceContext *) ctx,
> > +                                                             val1,
> val2, (int *) target);
> > +                break;
> > +#endif
> > +            default:
> > +                // MSG("unknown rac reader\n");
> > +                break;
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +#define RAC_GET(rc, ctx, val1, val2, target, type) \
> > +    if (!ff_flif16_rac_process((rc), (ctx), (val1), (val2), (target),
> (type))) {\
> > +        goto need_more_data; \
> > +    }
> > +
> > +#endif /* FLIF16_RANGECODER_H */
> > diff --git a/libavcodec/flif16_transform.c
> b/libavcodec/flif16_transform.c
> > new file mode 100644
> > index 0000000000..7b6cdef070
> > --- /dev/null
> > +++ b/libavcodec/flif16_transform.c
> > @@ -0,0 +1,2964 @@
> > +/*
> > + * Transforms for FLIF16.
> > + * Copyright (c) 2020 Kartik K. Khullar <kartikkhullar840 at gmail.com>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * Transforms for FLIF16.
> > + */
> > +
> > +#include "flif16_transform.h"
> > +#include "flif16_rangecoder.h"
> > +#include "libavutil/common.h"
> > +
> > +
> > +// Transform private structs and internal functions
> > +
> > +typedef struct transform_priv_ycocg {
> > +    int origmax4;
> > +    FLIF16RangesContext *r_ctx;
> > +} transform_priv_ycocg;
> > +
> > +typedef struct transform_priv_permuteplanes {
> > +    uint8_t subtract;
> > +    uint8_t permutation[5];
> > +    FLIF16RangesContext *r_ctx;
> > +
> > +    uint8_t from[4], to[4];
> > +    FLIF16ChanceContext ctx_a;
> > +} transform_priv_permuteplanes;
> > +
> > +typedef struct transform_priv_channelcompact {
>
> > +    FLIF16ColorVal *CPalette[4];
> > +    unsigned int CPalette_size[4];
> > +    FLIF16ColorVal *CPalette_inv[4];
> > +    unsigned int CPalette_inv_size[4];
>
> Fields should not have capitals.


Okay, will change that.

>
>
> +
> > +    FLIF16ColorVal min;
> > +    int remaining;
> > +    unsigned int i;                   //Iterator for nested loop.
> > +    FLIF16ChanceContext ctx_a;
> > +} transform_priv_channelcompact;
> > +
> > +typedef struct transform_priv_bounds {
> > +    FLIF16ColorVal (*bounds)[2];
> > +    int min;
> > +    FLIF16ChanceContext ctx_a;
> > +} transform_priv_bounds;
> > +
> > +typedef struct transform_priv_palette {
> > +    uint8_t has_alpha;
> > +    uint8_t ordered_palette;
> > +    uint32_t max_palette_size;
> > +    FLIF16ColorVal (*Palette)[3];
> > +    FLIF16ColorVal min[3], max[3];
> > +    FLIF16ColorVal *prev;
> > +    FLIF16ColorVal pp[2];
> > +    FLIF16ColorVal Y, I, Q;
> > +    FLIF16ChanceContext ctx;
> > +    FLIF16ChanceContext ctxY;
> > +    FLIF16ChanceContext ctxI;
> > +    FLIF16ChanceContext ctxQ;
> > +    long unsigned size;
> > +    uint8_t sorted;
> > +    unsigned int p;       //Iterator
> > +} transform_priv_palette;
> > +
> > +typedef struct transform_priv_palettealpha {
> > +    FLIF16ColorVal (*Palette)[4];
> > +    unsigned int max_palette_size;
> > +    uint8_t alpha_zero_special;
> > +    uint8_t ordered_palette;
> > +    uint8_t already_has_palette;
> > +    FLIF16ColorVal min[4], max[4];
> > +    FLIF16ColorVal *prev;
> > +    FLIF16ColorVal pp[2];
> > +    FLIF16ColorVal Y, I, Q, A;
> > +    FLIF16ChanceContext ctx;
> > +    FLIF16ChanceContext ctxY;
> > +    FLIF16ChanceContext ctxI;
> > +    FLIF16ChanceContext ctxQ;
> > +    FLIF16ChanceContext ctxA;
> > +    unsigned int p;
> > +    uint8_t sorted;
> > +    long unsigned int size;
> > +} transform_priv_palettealpha;
> > +
> > +typedef int16_t ColorValCB;
> > +typedef struct ColorValCB_list ColorValCB_list ;
> > +
> > +typedef struct ColorValCB_list {
> > +    ColorValCB data;
> > +    ColorValCB_list *next;
> > +} ColorValCB_list;
> > +
> > +typedef struct ColorBucket {
> > +    ColorValCB *snapvalues;
> > +    unsigned int snapvalues_size;
> > +    ColorValCB_list *values;
> > +    unsigned int values_size;
> > +    ColorValCB min, max;
> > +    uint8_t discrete;
> > +} ColorBucket;
> > +
> > +typedef struct ColorBuckets {
> > +    ColorBucket bucket0;
> > +    int min0, min1;
> > +    ColorBucket *bucket1;
> > +    unsigned int bucket1_size;
> > +    ColorBucket **bucket2;    // list of a list
> > +    unsigned int bucket2_size, bucket2_list_size;
> > +    ColorBucket bucket3;
> > +    ColorBucket empty_bucket;
> > +    FLIF16RangesContext *ranges;
> > +
> > +    /*
> > +     *  Data members used while reading buckets
> > +     */
> > +    unsigned int i, i2;    // Iterator
> > +    FLIF16ColorVal smin, smax;
> > +    FLIF16ColorVal v;
> > +    int nb;
> > +} ColorBuckets;
> > +
>
> > +typedef struct transform_priv_colorbuckets {
>
> Struct names in CamelCase is our convention.
>

Will correct all of these.

>
> > +    ColorBuckets *cb;
> > +    uint8_t really_used;
> > +    FLIF16ChanceContext ctx[6];
> > +
> > +    int i, j, k;    // Iterators
> > +    FLIF16ColorVal pixelL[2], pixelU[2];
> > +} transform_priv_colorbuckets;
> > +
> > +typedef struct transform_priv_framedup {
> > +    int *seen_before;
> > +    uint32_t nb;
> > +    FLIF16ChanceContext chancectx;
> > +    unsigned int i;
> > +} transform_priv_framedup;
> > +
> > +typedef struct transform_priv_frameshape {
> > +    int *b, *e;    // begin and end
> > +    uint32_t cols;
> > +    uint32_t nb;
> > +    FLIF16ChanceContext chancectx;
> > +    unsigned int i;
> > +} transform_priv_frameshape;
> > +
> > +typedef struct transform_priv_framecombine {
> > +    uint8_t was_flat;
> > +    uint8_t was_greyscale;
> > +    int max_lookback;
> > +    int user_max_lookback;
> > +    int nb_frames;
> > +
> > +    FLIF16ChanceContext chancectx;
> > +} transform_priv_framecombine;
> > +
> > +typedef struct ranges_priv_channelcompact {
> > +    int nb_colors[4];
> > +} ranges_priv_channelcompact;
> > +
> > +typedef struct ranges_priv_ycocg {
> > +    int origmax4;
> > +    FLIF16RangesContext *r_ctx;
> > +} ranges_priv_ycocg;
> > +
> > +typedef struct ranges_priv_permuteplanes {
> > +    uint8_t permutation[5];
> > +    FLIF16RangesContext *r_ctx;
> > +} ranges_priv_permuteplanes;
> > +
> > +typedef struct ranges_priv_bounds {
> > +    FLIF16ColorVal (*bounds)[2];
> > +    FLIF16RangesContext *r_ctx;
> > +} ranges_priv_bounds;
> > +
> > +typedef struct ranges_priv_palette {
> > +    int nb_colors;
> > +    FLIF16RangesContext *r_ctx;
> > +} ranges_priv_palette;
> > +
> > +typedef struct ranges_priv_colorbuckets {
> > +    FLIF16RangesContext *r_ctx;
> > +    ColorBuckets *buckets;
> > +} ranges_priv_colorbuckets;
> > +
> > +typedef struct ranges_priv_framecombine {
> > +    FLIF16ColorVal numPrevFrames;
> > +    FLIF16ColorVal alpha_min;
> > +    FLIF16ColorVal alpha_max;
> > +    FLIF16RangesContext *ranges;
> > +} ranges_priv_framecombine;
> > +
> > +typedef struct ranges_priv_static {
> > +    FLIF16ColorVal (*bounds)[2];
> > +} ranges_priv_static;
> > +
> > +
> > +/*
> > + *
> =============================================================================
> > + * Ranges
> > + *
> =============================================================================
> > + */
> > +
> > +/*
> > + * Static
> > + */
> > +
> > +static FLIF16ColorVal ff_static_min(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_static *data = r_ctx->priv_data;
>
> > +    if (p >= r_ctx->num_planes)
> > +        return 0;
> > +    av_assert0(p < r_ctx->num_planes);
>
> Get rid of the test before the assert. Otherwise you are silently
> silencing possible future bugs.
>
> Ya, right.

> > +    return data->bounds[p][0];
> > +}
> > +
> > +static FLIF16ColorVal ff_static_max(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_static *data = r_ctx->priv_data;
> > +    if (p >= r_ctx->num_planes)
> > +        return 0;
> > +    av_assert0(p < r_ctx->num_planes);
>
> Same.
>
> > +    return data->bounds[p][1];
> > +}
> > +
> > +static void ff_static_minmax(FLIF16RangesContext *src_ctx ,const int p,
> > +                             FLIF16ColorVal *prev_planes,
> > +                             FLIF16ColorVal *minv, FLIF16ColorVal *maxv)
> > +{
> > +    FLIF16Ranges *ranges = flif16_ranges[src_ctx->r_no];
> > +    *minv = ranges->min(src_ctx, p);
> > +    *maxv = ranges->max(src_ctx, p);
> > +}
> > +
> > +static void ff_static_snap(FLIF16RangesContext *src_ctx , const int p,
> > +                           FLIF16ColorVal *prev_planes,
> > +                           FLIF16ColorVal *minv, FLIF16ColorVal *maxv,
> > +                           FLIF16ColorVal *v)
> > +{
> > +    ff_flif16_ranges_minmax(src_ctx, p, prev_planes, minv, maxv);
> > +    if (*minv > *maxv)
> > +        *maxv = *minv;
> > +    *v = av_clip(*v, *minv, *maxv);
> > +}
> > +
> > +static void ff_static_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_static *data = r_ctx->priv_data;
> > +    av_free(data->bounds);
> > +}
> > +
> > +/*
> > + * ChannelCompact
> > + */
> > +
> > +static FLIF16ColorVal ff_channelcompact_min(FLIF16RangesContext
> *ranges, int p)
> > +{
> > +    return 0;
> > +}
> > +
> > +static FLIF16ColorVal ff_channelcompact_max(FLIF16RangesContext
> *src_ctx, int p)
> > +{
> > +    ranges_priv_channelcompact *data = src_ctx->priv_data;
> > +    return data->nb_colors[p];
> > +}
> > +
> > +static void ff_channelcompact_minmax(FLIF16RangesContext *r_ctx, int p,
> > +                                     FLIF16ColorVal *prev_planes,
> > +                                     FLIF16ColorVal *minv,
> FLIF16ColorVal *maxv)
> > +{
> > +    ranges_priv_channelcompact *data = r_ctx->priv_data;
> > +    *minv = 0;
> > +    *maxv = data->nb_colors[p];
> > +}
> > +
> > +/*
> > + * YCoCg
> > + */
> > +
> > +static inline FLIF16ColorVal ff_get_max_y(int origmax4)
> > +{
> > +    return 4 * origmax4 - 1;
> > +}
> > +
> > +static inline int ff_get_min_co(int origmax4, int yval)
> > +{
> > +    if (yval < origmax4 - 1)
> > +        return -3 - 4*yval;
> > +    else if (yval >= 3*origmax4)
>
> > +        return 4*(1 + yval - 4*origmax4);
>
> Nit: spacing. Same below.
>
> > +    else
> > +        return -4*origmax4 + 1;
> > +}
> > +
> > +static inline int ff_get_max_co(int origmax4, int yval)
> > +{
> > +    if (yval < origmax4-1)
> > +        return 3 + 4 * yval;
> > +    else if (yval >= 3 * origmax4)
> > +        return 4*origmax4 - 4*(1 + yval - 3*origmax4);
> > +    else
> > +        return 4 * origmax4 - 1;
> > +}
> > +
> > +static inline int ff_get_min_cg(int origmax4, int yval, int coval)
> > +{
> > +    if (yval < origmax4 - 1)
> > +        return -(2*yval+1);
> > +    else if (yval >= 3*origmax4)
> > +        return -(2*(4*origmax4 - 1 - yval) - ((1 + abs(coval))/2)*2);
> > +    else {
> > +        return -FFMIN(2*origmax4 - 1 + (yval -origmax4 + 1)*2,
>
> > +                     2*origmax4 + (3*origmax4 - 1 - yval)*2 - ((1 +
> abs(coval))/2)*2);
>
> Nit: indentation.
>
> > +    }
> > +}
> > +
> > +static inline int ff_get_max_cg(int origmax4, int yval, int coval)
> > +{
> > +    if (yval < origmax4 - 1)
> > +        return 1 + 2 * yval - 2 * (abs(coval) / 2);
> > +    else if (yval >= 3 * origmax4)
> > +        return 2 * (4*origmax4 - 1 - yval);
> > +    else
> > +        return -FFMAX(-4*origmax4 + (1 + yval - 2*origmax4)*2,
> > +                      -2*origmax4 - (yval - origmax4)*2 - 1 +
> (abs(coval)/2)*2);
> > +}
> > +
> > +static FLIF16ColorVal ff_ycocg_min(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_ycocg *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    switch (p) {
> > +        case FLIF16_PLANE_Y:
> > +            return 0;
> > +        case FLIF16_PLANE_CO:
> > +        case FLIF16_PLANE_CG:
> > +            return -4 * data->origmax4 + 1;
> > +        default:
> > +            return ranges->min(data->r_ctx, p);
> > +    }
> > +}
> > +
> > +static FLIF16ColorVal ff_ycocg_max(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_ycocg *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    switch (p) {
> > +        case FLIF16_PLANE_Y:
> > +        case FLIF16_PLANE_CO:
> > +        case FLIF16_PLANE_CG:
> > +            return 4 * data->origmax4 - 1;
> > +        default:
> > +            return ranges->max(data->r_ctx, p);
> > +    }
> > +}
> > +
> > +static void ff_ycocg_minmax(FLIF16RangesContext *r_ctx ,const int p,
> > +                            FLIF16ColorVal *prev_planes,
> > +                            FLIF16ColorVal *minv, FLIF16ColorVal *maxv)
> > +{
> > +    ranges_priv_ycocg *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    switch (p) {
> > +        case FLIF16_PLANE_Y:
> > +            *minv = 0;
> > +            *maxv = ff_get_max_y(data->origmax4);
> > +            break;
> > +        case FLIF16_PLANE_CO:
> > +            *minv = ff_get_min_co(data->origmax4, prev_planes[0]);
> > +            *maxv = ff_get_max_co(data->origmax4, prev_planes[0]);
> > +            break;
> > +        case FLIF16_PLANE_CG:
> > +            *minv = ff_get_min_cg(data->origmax4, prev_planes[0],
> prev_planes[1]);
> > +            *maxv = ff_get_max_cg(data->origmax4, prev_planes[0],
> prev_planes[1]);
> > +            break;
> > +        default:
> > +            ranges->minmax(data->r_ctx, p, prev_planes, minv, maxv);
> > +    }
> > +}
> > +
> > +static void ff_ycocg_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_ycocg *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->r_ctx->r_no];
> > +    if (range->close)
> > +        range->close(data->r_ctx);
> > +    av_free(data->r_ctx);
> > +}
> > +
> > +/*
> > + * PermutePlanesSubtract
> > + */
> > +
> > +static FLIF16ColorVal ff_permuteplanessubtract_min(FLIF16RangesContext
> *r_ctx, int p)
> > +{
> > +    ranges_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    if (p == 0 || p > 2)
> > +        return ranges->min(data->r_ctx, data->permutation[p]);
> > +    return ranges->min(data->r_ctx, data->permutation[p]) -
> > +           ranges->max(data->r_ctx, data->permutation[0]);
> > +}
> > +
> > +static FLIF16ColorVal ff_permuteplanessubtract_max(FLIF16RangesContext
> *r_ctx, int p)
> > +{
> > +    ranges_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    if (p == 0 || p > 2)
> > +        return ranges->max(data->r_ctx, data->permutation[p]);
> > +    return ranges->max(data->r_ctx, data->permutation[p]) -
> > +           ranges->min(data->r_ctx, data->permutation[0]);
> > +}
> > +
> > +static void ff_permuteplanessubtract_minmax(FLIF16RangesContext *r_ctx,
> int p,
> > +                                            FLIF16ColorVal
> *prev_planes,
> > +                                            FLIF16ColorVal *minv,
> > +                                            FLIF16ColorVal *maxv)
> > +{
> > +    ranges_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    if (p == 0 || p > 2) {
> > +        *minv = ranges->min(data->r_ctx, p);
> > +        *maxv = ranges->max(data->r_ctx, p);
> > +    }
> > +    else {
> > +        *minv = ranges->min(data->r_ctx, data->permutation[p]) -
> prev_planes[0];
> > +        *maxv = ranges->max(data->r_ctx, data->permutation[p]) -
> prev_planes[0];
> > +    }
> > +}
> > +
> > +/*
> > + * PermutePlanes
> > + */
> > +
> > +static FLIF16ColorVal ff_permuteplanes_min(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    transform_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    return ranges->min(data->r_ctx, data->permutation[p]);
> > +}
> > +
> > +static FLIF16ColorVal ff_permuteplanes_max(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    transform_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    return ranges->max(data->r_ctx, data->permutation[p]);
> > +}
> > +
> > +static void ff_permuteplanes_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_permuteplanes *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->r_ctx->r_no];
> > +    if (range->close)
> > +        range->close(data->r_ctx);
> > +    av_free(data->r_ctx);
> > +}
> > +
> > +/*
> > + * Bounds
> > + */
> > +
> > +static FLIF16ColorVal ff_bounds_min(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_bounds *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    av_assert0(p < r_ctx->num_planes);
> > +    return FFMAX(ranges->min(data->r_ctx, p), data->bounds[p][0]);
> > +}
> > +
> > +static FLIF16ColorVal ff_bounds_max(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_bounds *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    av_assert0(p < r_ctx->num_planes);
> > +    return FFMIN(ranges->max(data->r_ctx, p), data->bounds[p][1]);
> > +}
> > +
> > +static void ff_bounds_minmax(FLIF16RangesContext *r_ctx, int p,
> > +                             FLIF16ColorVal *prev_planes,
> > +                             FLIF16ColorVal *minv, FLIF16ColorVal *maxv)
> > +{
> > +    ranges_priv_bounds *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    av_assert0(p < r_ctx->num_planes);
> > +    if (p == 0 || p == 3) {
> > +        *minv = data->bounds[p][0];
> > +        *maxv = data->bounds[p][1];
> > +        return;
> > +    }
> > +    ranges->minmax(data->r_ctx, p, prev_planes, minv, maxv);
> > +    if (*minv < data->bounds[p][0])
> > +        *minv = data->bounds[p][0];
> > +    if (*maxv > data->bounds[p][1])
> > +        *maxv = data->bounds[p][1];
> > +    if (*minv > *maxv) {
> > +        *minv = data->bounds[p][0];
> > +        *maxv = data->bounds[p][1];
> > +    }
> > +    av_assert0(*minv <= *maxv);
> > +}
> > +
> > +static void ff_bounds_snap(FLIF16RangesContext *r_ctx, int p,
> > +                           FLIF16ColorVal *prev_planes, FLIF16ColorVal
> *minv,
> > +                           FLIF16ColorVal *maxv, FLIF16ColorVal *v)
> > +{
> > +    ranges_priv_bounds *data = r_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    if (p == 0 || p == 3) {
> > +        *minv = data->bounds[p][0];
> > +        *maxv = data->bounds[p][1];
> > +    }
> > +    else {
> > +        ranges->snap(data->r_ctx, p, prev_planes, minv, maxv, v);
> > +        if (*minv < data->bounds[p][0])
> > +            *minv = data->bounds[p][0];
> > +        if (*maxv > data->bounds[p][1])
> > +            *maxv = data->bounds[p][1];
> > +        if (*minv > *maxv) {
> > +            *minv = data->bounds[p][0];
> > +            *maxv = data->bounds[p][1];
> > +        }
> > +    }
> > +    if (*v > *maxv)
> > +        *v = *maxv;
> > +    if (*v < *minv)
> > +        *v = *minv;
> > +}
> > +
> > +static void ff_bounds_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_bounds *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->r_ctx->r_no];
> > +    if (range->close)
> > +        range->close(data->r_ctx);
> > +    av_free(data->bounds);
> > +    av_free(data->r_ctx);
> > +}
> > +
> > +/*
> > + * Palette
> > + */
> > +
> > +static FLIF16ColorVal ff_palette_min(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
>
> > +    if (p < 3)
> > +        return 0;
> > +    else
> > +        return ff_flif16_ranges_min(data->r_ctx, p);
> > +}
> > +
> > +static FLIF16ColorVal ff_palette_max(FLIF16RangesContext *r_ctx, int p)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    if (p == 1)
> > +        return data->nb_colors-1;
> > +    else if (p < 3)
> > +        return 0;
> > +    else
> > +        return ff_flif16_ranges_max(data->r_ctx, p);
> > +}
> > +
> > +static void ff_palette_minmax(FLIF16RangesContext *r_ctx, int p,
> > +                              FLIF16ColorVal *prev_planes,
> > +                              FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    if (p == FLIF16_PLANE_CO) {
> > +        *minv = 0;
> > +        *maxv = data->nb_colors-1;
> > +    }
> > +    else if (p < FLIF16_PLANE_ALPHA) {
> > +        *minv = 0;
> > +        *maxv = 0;
> > +    }
> > +    else
> > +        ff_flif16_ranges_minmax(data->r_ctx, p, prev_planes, minv,
> maxv);
> > +}
> > +
> > +static void ff_palette_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->r_ctx->r_no];
> > +    if (range->close)
> > +        range->close(data->r_ctx);
> > +    av_free(data->r_ctx);
> > +}
> > +
> > +/*
> > + * Palette Alpha
> > + */
> > +
> > +static FLIF16ColorVal ff_palettealpha_min(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    if (p < FLIF16_PLANE_ALPHA)
> > +        return 0;
> > +    else if (p == FLIF16_PLANE_ALPHA)
> > +        return 1;
> > +    else
> > +        return ff_flif16_ranges_min(data->r_ctx, p);
> > +}
> > +
> > +static FLIF16ColorVal ff_palettealpha_max(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    switch (p) {
> > +        case FLIF16_PLANE_Y:
> > +            return 0;
> > +        case FLIF16_PLANE_CO:
> > +            return data->nb_colors-1;
> > +        case FLIF16_PLANE_CG:
> > +            return 0;
> > +        case FLIF16_PLANE_ALPHA:
> > +            return 1;
> > +        default:
> > +            return ff_flif16_ranges_max(data->r_ctx, p);
> > +    }
> > +}
> > +
> > +static void ff_palettealpha_minmax(FLIF16RangesContext *r_ctx, int p,
> > +                                   FLIF16ColorVal *prev_planes,
> > +                                   FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv)
> > +{
> > +    ranges_priv_palette *data = r_ctx->priv_data;
> > +    if (p == FLIF16_PLANE_CO) {
> > +        *minv = 0;
> > +        *maxv = data->nb_colors-1;
> > +    }
> > +    else if (p < FLIF16_PLANE_ALPHA) {
> > +        *minv = 0;
> > +        *maxv = 0;
> > +    }
> > +    else if (p == FLIF16_PLANE_ALPHA) {
> > +        *minv = 1;
> > +        *maxv = 1;
> > +    }
> > +    else
> > +        ff_flif16_ranges_minmax(data->r_ctx, p, prev_planes, minv,
> maxv);
> > +}
> > +
> > +/*
> > + * ColorBuckets
> > + */
> > +
>
> > +// quantization constants
> > +#define CB0a 1
> > +#define CB0b 1
> > +#define CB1 4
>
> Do these really make the code clearer?
>

These constants were copied from the reference decoder, I think I will
remove them or make them available in private structs of this transform and
give a clean name to them instead.


> > +
> > +static void ff_init_bucket_default(ColorBucket *b)
> > +{
> > +    b->min = 10000;
> > +    b->max = -10000;
> > +    b->discrete = 1;
> > +    b->values_size = 0;
> > +    b->snapvalues_size = 0;
> > +}
> > +
> > +static ColorBucket *ff_bucket_buckets2(ColorBuckets *buckets, const int
> p,
> > +                                       const FLIF16ColorVal
> *prev_planes)
> > +{
> > +    av_assert0(p >= FLIF16_PLANE_Y);
> > +    av_assert0(p < FLIF16_PLANE_LOOKBACK);
> > +    if (p == FLIF16_PLANE_Y)
> > +        return &buckets->bucket0;
> > +    if (p == FLIF16_PLANE_CO) {
>
> unsigned diff = (prev_planes[0] - buckets->min0)/CB0a;
>
> and then use it. Using unsigned makes the >= 0 test unnecessary.
>

Will do.


>
> > +        av_assert0((prev_planes[0] - buckets->min0)/CB0a >= 0
> > +                && (prev_planes[0] - buckets->min0)/CB0a <
> buckets->bucket1_size);
> > +        return &buckets->bucket1[(prev_planes[0] - buckets->min0)/CB0a];
> > +    }
>
> > +    if (p == FLIF16_PLANE_CG) {
> > +        av_assert0((prev_planes[0] - buckets->min0)/CB0b >= 0
> > +                && (prev_planes[0] - buckets->min0)/CB0b <
> buckets->bucket2_size);
> > +        av_assert0((prev_planes[1] - buckets->min1)/CB1 >= 0
> > +                && (prev_planes[1] - buckets->min1)/CB1 <
> buckets->bucket2_list_size);
>
> Same.
>
> > +        return &buckets->bucket2[(prev_planes[0] -
> buckets->min0)/CB0b][(prev_planes[1] - buckets->min1)/CB1];
> > +    }
> > +
> > +    return &buckets->bucket3;
> > +}
> > +
> > +static ColorBucket *ff_bucket_buckets(ColorBuckets *buckets, const int
> p,
> > +                                      const FLIF16ColorVal *prev_planes)
> > +{
> > +    av_assert0(p >= 0);
> > +    av_assert0(p < 4);
> > +    if (p == FLIF16_PLANE_Y)
> > +        return &buckets->bucket0;
> > +    if (p == FLIF16_PLANE_CO) {
>
> > +        int i = (prev_planes[0] - buckets->min0)/CB0a;
>
> Make i unsigned to avoid the >= 0 test and problems with overflows.
>
> > +        if (i >= 0 && i < (int)buckets->bucket1_size)
> > +            return &buckets->bucket1[i];
> > +        else
> > +            return &buckets->empty_bucket;
> > +    }
> > +    if (p == FLIF16_PLANE_CG) {
> > +        int i = (prev_planes[0] - buckets->min0)/CB0b;
> > +        int j = (prev_planes[1] - buckets->min1)/CB1;
> > +        if (i >= 0 && i < (int)buckets->bucket1_size &&
> > +            j >= 0 && j < (int) buckets->bucket2_list_size)
> > +            return &buckets->bucket2[i][j];
> > +        else
> > +            return &buckets->empty_bucket;
> > +    }
> > +
> > +    return &buckets->bucket3;
> > +}
> > +
>
> > +static FLIF16ColorVal ff_snap_color_bucket(ColorBucket *bucket,
> FLIF16ColorVal *c)
>
> No need to pass c by pointer.
>

Right. It's the result of some code translation from the reference decoder.


>
> > +{
> > +    if (*c <= bucket->min) {
> > +        return bucket->min;
> > +    }
> > +    if (*c >= bucket->max) {
> > +        return bucket->max;
> > +    }
> > +    if (bucket->discrete) {
> > +        av_assert0((FLIF16ColorVal)bucket->snapvalues_size > (*c -
> bucket->min));
> > +        return bucket->snapvalues[*c - bucket->min];
> > +    }
> > +    return *c;
> > +}
> > +
> > +static FLIF16ColorVal ff_colorbuckets_min(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_colorbuckets *data = r_ctx->priv_data;
> > +    return ff_flif16_ranges_min(data->r_ctx, p);
> > +}
> > +
> > +static FLIF16ColorVal ff_colorbuckets_max(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_colorbuckets *data = r_ctx->priv_data;
> > +    return ff_flif16_ranges_max(data->r_ctx, p);
> > +}
> > +
> > +static void ff_colorbuckets_snap(FLIF16RangesContext *src_ctx, const
> int p,
> > +                                 FLIF16ColorVal *prev_planes,
> > +                                 FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv,
> > +                                 FLIF16ColorVal *v)
> > +{
> > +    ranges_priv_colorbuckets *data = src_ctx->priv_data;
> > +    ColorBucket *b = ff_bucket_buckets(data->buckets, p, prev_planes);
> > +    *minv = b->min;
> > +    *maxv = b->max;
> > +    if (b->min > b->max) {
> > +        *minv = ff_colorbuckets_min(src_ctx, p);
> > +        *v = *minv;
> > +        *maxv = ff_colorbuckets_max(src_ctx, p);
> > +        return;
> > +    }
> > +    *v = ff_snap_color_bucket(b, v);
> > +}
> > +
> > +static void ff_colorbuckets_minmax(FLIF16RangesContext *r_ctx,
> > +                                   int p, FLIF16ColorVal *prev_planes,
> > +                                   FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv)
> > +{
> > +    ranges_priv_colorbuckets *data = r_ctx->priv_data;
> > +    const ColorBucket *b = ff_bucket_buckets(data->buckets, p,
> prev_planes);
> > +    *minv = b->min;
> > +    *maxv = b->max;
> > +    if (b->min > b->max) {
> > +        *minv = ff_colorbuckets_min(r_ctx, p);
> > +        *maxv = ff_colorbuckets_max(r_ctx, p);
> > +    }
> > +}
> > +
> > +static void ff_colorbuckets_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_colorbuckets *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->r_ctx->r_no];
> > +    if (range->close)
> > +        range->close(data->r_ctx);
> > +    av_free(data->buckets);
> > +    av_free(data->r_ctx);
> > +}
> > +
> > +static FLIF16ColorVal ff_framecombine_min(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_framecombine *data = r_ctx->priv_data;
> > +    if (p < FLIF16_PLANE_ALPHA)
> > +        return ff_flif16_ranges_min(data->ranges, p);
> > +    else if (p == FLIF16_PLANE_ALPHA)
> > +        return data->alpha_min;
> > +    else
> > +        return 0;
> > +}
> > +
> > +static FLIF16ColorVal ff_framecombine_max(FLIF16RangesContext *r_ctx,
> int p)
> > +{
> > +    ranges_priv_framecombine *data = r_ctx->priv_data;
> > +    if (p < FLIF16_PLANE_ALPHA)
> > +        return ff_flif16_ranges_max(data->ranges, p);
> > +    else if (p == FLIF16_PLANE_ALPHA)
> > +        return data->alpha_max;
> > +    else
> > +        return data->numPrevFrames;
> > +}
> > +
> > +static void ff_framecombine_minmax(FLIF16RangesContext *r_ctx,
> > +                                   int p, FLIF16ColorVal *prev_planes,
> > +                                   FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv)
> > +{
> > +    ranges_priv_framecombine *data = r_ctx->priv_data;
> > +    if (p >= 3) {
> > +        *minv = ff_framecombine_min(r_ctx, p);
> > +        *maxv = ff_framecombine_max(r_ctx, p);
> > +    }
> > +    else
> > +        ff_flif16_ranges_minmax(data->ranges, p, prev_planes, minv,
> maxv);
> > +}
> > +
> > +static void ff_framecombine_snap(FLIF16RangesContext *src_ctx, const
> int p,
> > +                                 FLIF16ColorVal *prev_planes,
> > +                                 FLIF16ColorVal *minv, FLIF16ColorVal
> *maxv,
> > +                                 FLIF16ColorVal *v)
> > +{
> > +    ranges_priv_framecombine *data = src_ctx->priv_data;
> > +    // FLIF16RangesContext r_ctx;
> > +    // r_ctx.r_no = FLIF16_RANGES_FRAMELOOKBACK;
> > +    // r_ctx.num_planes = 5;
> > +    // r_ctx.priv_data = NULL;
> > +    if (p >= 3)
> > +        ff_static_snap(src_ctx, p, prev_planes, minv, maxv, v);
> > +    else
> > +        ff_flif16_ranges_snap(data->ranges, p, prev_planes, minv, maxv,
> v);
> > +    // printf("min : %d max : %d v : %d\n", *minv, *maxv, *v);
> > +}
> > +
> > +static void ff_framecombine_close(FLIF16RangesContext *r_ctx)
> > +{
> > +    ranges_priv_framecombine *data = r_ctx->priv_data;
> > +    FLIF16Ranges *range = flif16_ranges[data->ranges->r_no];
> > +    if (range->close)
> > +        range->close(data->ranges);
> > +    av_free(data->ranges);
> > +}
> > +
>
> > +FLIF16Ranges flif16_ranges_static = {
>
> static const; same for all below.
>

Will do.


>
> > +    .priv_data_size = sizeof(ranges_priv_static),
> > +    .min            = &ff_static_min,
> > +    .max            = &ff_static_max,
> > +    .minmax         = &ff_static_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 1,
> > +    .close          = &ff_static_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_channelcompact = {
> > +    .priv_data_size = sizeof(ranges_priv_channelcompact),
> > +    .min            = &ff_channelcompact_min,
> > +    .max            = &ff_channelcompact_max,
> > +    .minmax         = &ff_channelcompact_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 1,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_ycocg = {
> > +    .priv_data_size = sizeof(ranges_priv_ycocg),
> > +    .min            = &ff_ycocg_min,
> > +    .max            = &ff_ycocg_max,
> > +    .minmax         = &ff_ycocg_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_ycocg_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_permuteplanessubtract = {
> > +    .priv_data_size = sizeof(ranges_priv_permuteplanes),
> > +    .min            = &ff_permuteplanessubtract_min,
> > +    .max            = &ff_permuteplanessubtract_max,
> > +    .minmax         = &ff_permuteplanessubtract_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_permuteplanes_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_permuteplanes = {
> > +    .priv_data_size = sizeof(ranges_priv_permuteplanes),
> > +    .min            = &ff_permuteplanes_min,
> > +    .max            = &ff_permuteplanes_max,
> > +    .minmax         = &ff_static_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_permuteplanes_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_bounds = {
> > +    .priv_data_size = sizeof(ranges_priv_bounds),
> > +    .min            = &ff_bounds_min,
> > +    .max            = &ff_bounds_max,
> > +    .minmax         = &ff_bounds_minmax,
> > +    .snap           = &ff_bounds_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_bounds_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_palette = {
> > +    .priv_data_size = sizeof(ranges_priv_palette),
> > +    .min            = &ff_palette_min,
> > +    .max            = &ff_palette_max,
> > +    .minmax         = &ff_palette_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_palette_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_palettealpha = {
> > +    .priv_data_size = sizeof(ranges_priv_palette),
> > +    .min            = &ff_palettealpha_min,
> > +    .max            = &ff_palettealpha_max,
> > +    .minmax         = &ff_palettealpha_minmax,
> > +    .snap           = &ff_static_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_palette_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_colorbuckets = {
> > +    .priv_data_size = sizeof(ranges_priv_colorbuckets),
> > +    .min            = &ff_colorbuckets_min,
> > +    .max            = &ff_colorbuckets_max,
> > +    .minmax         = &ff_colorbuckets_minmax,
> > +    .snap           = &ff_colorbuckets_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_colorbuckets_close
> > +};
> > +
> > +FLIF16Ranges flif16_ranges_framecombine = {
> > +    .priv_data_size = sizeof(ranges_priv_framecombine),
> > +    .min            = &ff_framecombine_min,
> > +    .max            = &ff_framecombine_max,
> > +    .minmax         = &ff_framecombine_minmax,
> > +    .snap           = &ff_framecombine_snap,
> > +    .is_static      = 0,
> > +    .close          = &ff_framecombine_close
> > +};
> > +
> > +FLIF16Ranges *flif16_ranges[] = {
>
> > +    &flif16_ranges_channelcompact,        //
> FLIF16_RANGES_CHANNELCOMPACT,
>
> [FLIF16_RANGES_CHANNELCOMPACT] = &flif16_ranges_channelcompact
>
> Same below.
>
Okay.

>
> > +    &flif16_ranges_ycocg,                 // FLIF16_RANGES_YCOCG,
> > +    &flif16_ranges_permuteplanes,         //
> FLIF16_RANGES_PERMUTEPLANES,
> > +    &flif16_ranges_permuteplanessubtract, //
> FLIF16_RANGES_PERMUTEPLANESSUBTRACT,
> > +    &flif16_ranges_bounds,                // FLIF16_RANGES_BOUNDS,
> > +    &flif16_ranges_static,                // FLIF16_RANGES_STATIC,
> > +    &flif16_ranges_palettealpha,          // FLIF16_RANGES_PALETTEALPHA,
> > +    &flif16_ranges_palette,               // FLIF16_RANGES_PALETTE,
> > +    &flif16_ranges_colorbuckets,          // FLIF16_RANGES_COLORBUCKETS,
> > +    &flif16_ranges_framecombine           // FLIF16_RANGES_FRAMELOOKBACK
> > +};
> > +
> > +FLIF16RangesContext *ff_flif16_ranges_static_init(unsigned int channels,
> > +                                                  unsigned int bpc)
> > +{
> > +    FLIF16Ranges *r = flif16_ranges[FLIF16_RANGES_STATIC];
> > +    FLIF16RangesContext *ctx;
> > +    ranges_priv_static *data;
> > +    ctx = av_mallocz(sizeof(*ctx));
> > +    if (!ctx)
> > +        return NULL;
> > +    ctx->r_no       = FLIF16_RANGES_STATIC;
> > +    ctx->num_planes = channels;
> > +    ctx->priv_data  = av_mallocz(r->priv_data_size);
> > +    if (!ctx->priv_data)
> > +        return NULL;
> > +    data = ctx->priv_data;
> > +    data->bounds = av_mallocz(sizeof(*data->bounds) * channels);
> > +    if (!data->bounds)
> > +        return NULL;
> > +    for (unsigned int i = 0; i < channels; ++i) {
> > +        data->bounds[i][0] = 0;
> > +        data->bounds[i][1] = bpc;
> > +    }
> > +    return ctx;
> > +}
> > +
> > +void ff_flif16_ranges_close(FLIF16RangesContext* r_ctx){
> > +    FLIF16Ranges* ranges = flif16_ranges[r_ctx->r_no];
> > +    if(ranges->close)
> > +        ranges->close(r_ctx);
> > +    if(ranges->priv_data_size)
> > +        av_free(r_ctx->priv_data);
> > +    av_freep(&r_ctx);
> > +}
> > +
> > +static void ff_flif16_planes_get(FLIF16Context *ctx, FLIF16PixelData
> *frame,
> > +                                 FLIF16ColorVal *values, uint32_t row,
> uint32_t col)
> > +{
> > +    for (int i = 0; i < 3; i++)
> > +        values[i] = ff_flif16_pixel_get(ctx, frame, i, row, col);
> > +}
> > +
> > +static void ff_flif16_planes_set(FLIF16Context *ctx, FLIF16PixelData
> *frame,
> > +                                 FLIF16ColorVal *values, uint32_t row,
> uint32_t col)
> > +{
> > +    for (int i = 0; i < 3; i++)
> > +        ff_flif16_pixel_set(ctx, frame, i, row, col, values[i]);
> > +}
> > +
> > +/*
> > + *
> =============================================================================
> > + * Transforms
> > + *
> =============================================================================
> > + */
> > +
> > +/*
> > + * YCoCg
> > + */
> > +static int transform_ycocg_init(FLIF16TransformContext *ctx,
> FLIF16RangesContext *r_ctx)
> > +{
> > +    transform_priv_ycocg *data = ctx->priv_data;
> > +    FLIF16Ranges *src_ranges = flif16_ranges[r_ctx->r_no];
> > +
> > +    av_assert0(data);
> > +
> > +    if (  r_ctx->num_planes < 3
> > +       || src_ranges->min(r_ctx, 0) == src_ranges->max(r_ctx, 0)
> > +       || src_ranges->min(r_ctx, 1) == src_ranges->max(r_ctx, 1)
> > +       || src_ranges->min(r_ctx, 2) == src_ranges->max(r_ctx, 2)
> > +       || src_ranges->min(r_ctx, 0) < 0
> > +       || src_ranges->min(r_ctx, 1) < 0
> > +       || src_ranges->min(r_ctx, 2) < 0)
> > +        return 0;
> > +
> > +    data->origmax4 = FFMAX3(src_ranges->max(r_ctx, 0),
> > +                            src_ranges->max(r_ctx, 1),
> > +                            src_ranges->max(r_ctx, 2))/4 + 1;
> > +    data->r_ctx = r_ctx;
> > +    return 1;
> > +}
> > +
> > +static FLIF16RangesContext *transform_ycocg_meta(FLIF16Context *ctx,
> > +                                                 FLIF16PixelData *frame,
> > +                                                 uint32_t frame_count,
> > +                                                 FLIF16TransformContext
> *t_ctx,
> > +                                                 FLIF16RangesContext
> *src_ctx)
> > +{
> > +    FLIF16RangesContext *r_ctx;
> > +    ranges_priv_ycocg *data;
> > +    transform_priv_ycocg *trans_data = t_ctx->priv_data;
> > +    r_ctx = av_mallocz(sizeof(FLIF16RangesContext));
> > +    if (!r_ctx)
> > +        return NULL;
> > +    r_ctx->r_no = FLIF16_RANGES_YCOCG;
> > +    r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_ycocg));
> > +    if (!r_ctx->priv_data)
> > +        return NULL;
> > +    data = r_ctx->priv_data;
> > +
> > +    data->origmax4 = trans_data->origmax4;
> > +    data->r_ctx    = trans_data->r_ctx;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +    return r_ctx;
> > +}
> > +
> > +static int transform_ycocg_forward(FLIF16Context *ctx,
> > +                                      FLIF16TransformContext *t_ctx,
> > +                                      FLIF16PixelData *pixel_data)
> > +{
> > +    int r, c;
> > +    FLIF16ColorVal RGB[3], YCOCG[3];
> > +
> > +    int height = ctx->height;
> > +    int width  = ctx->width;
> > +
> > +    for (r = 0; r<height; r++) {
> > +        for (c = 0; c<width; c++) {
> > +            ff_flif16_planes_get(ctx, pixel_data, RGB, r, c);
> > +
> > +            YCOCG[0] = (((RGB[0] + RGB[2])>>1) + RGB[1])>>1;
> > +            YCOCG[1] = RGB[0] - RGB[2];
> > +            YCOCG[2] = RGB[1] - ((RGB[0] + RGB[2])>>1);
> > +
> > +            ff_flif16_planes_set(ctx, pixel_data, YCOCG, r, c);
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +static int transform_ycocg_reverse(FLIF16Context *ctx,
> > +                                      FLIF16TransformContext *t_ctx,
> > +                                      FLIF16PixelData *pixel_data,
> > +                                      uint32_t stride_row,
> > +                                      uint32_t stride_col)
> > +{
> > +    int r, c;
> > +    FLIF16ColorVal RGB[3], YCOCG[3];
> > +    int height = ctx->height;
> > +    int width  = ctx->width;
> > +    transform_priv_ycocg *data = t_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +
> > +    for (r = 0; r<height; r+=stride_row) {
> > +        for (c = 0; c<width; c+=stride_col) {
> > +            ff_flif16_planes_get(ctx, pixel_data, YCOCG, r, c);
> > +
> > +            RGB[1] = YCOCG[0] - ((-YCOCG[2])>>1);
> > +            RGB[2] = YCOCG[0] + ((1-YCOCG[2])>>1) - (YCOCG[1]>>1);
> > +            RGB[0] = YCOCG[1] + RGB[2];
> > +
> > +            RGB[0] = av_clip(RGB[0], 0, ranges->max(data->r_ctx, 0));
> > +            RGB[1] = av_clip(RGB[1], 0, ranges->max(data->r_ctx, 1));
> > +            RGB[2] = av_clip(RGB[2], 0, ranges->max(data->r_ctx, 2));
> > +
> > +            ff_flif16_planes_set(ctx, pixel_data, RGB, r, c);
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +/*
> > + * PermutePlanes
> > + */
> > +
> > +static int transform_permuteplanes_init(FLIF16TransformContext *ctx,
> > +                                           FLIF16RangesContext *r_ctx)
> > +{
> > +    transform_priv_permuteplanes *data = ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no];
> > +    ff_flif16_chancecontext_init(&data->ctx_a);
> > +
> > +    if ( r_ctx->num_planes     < 3
> > +      || ranges->min(r_ctx, 0) < 0
> > +      || ranges->min(r_ctx, 1) < 0
> > +      || ranges->min(r_ctx, 2) < 0)
> > +        return 0;
> > +
> > +    data->r_ctx = r_ctx;
> > +    return 1;
> > +}
> > +
> > +static int transform_permuteplanes_read(FLIF16TransformContext *ctx,
> > +                                           FLIF16Context *dec_ctx,
> > +                                           FLIF16RangesContext *r_ctx)
> > +{
> > +    int p;
> > +    transform_priv_permuteplanes *data = ctx->priv_data;
> > +
> > +    switch (ctx->segment) {
> > +        case 0:
>
> Nit: indentation.
>
> > +            RAC_GET(&dec_ctx->rc, &data->ctx_a, 0, 1, &data->subtract,
> > +                    FLIF16_RAC_NZ_INT);
> > +
> > +            for (p = 0; p<4; p++) {
> > +                data->from[p] = 0;
> > +                data->to[p] = 0;
> > +            }
> > +        case 1:
> > +            for (; ctx->i < dec_ctx->num_planes; ++ctx->i) {
> > +                RAC_GET(&dec_ctx->rc, &data->ctx_a, 0,
> dec_ctx->num_planes-1,
> > +                        &data->permutation[ctx->i],
> > +                        FLIF16_RAC_NZ_INT);
> > +                data->from[ctx->i] = 1;
> > +                data->to[ctx->i] = 1;
> > +            }
> > +            ctx->i = 0;
> > +
> > +            for (p = 0; p < dec_ctx->num_planes; p++) {
> > +                if (!data->from[p] || !data->to[p])
> > +                return 0;
> > +            }
> > +            ++ctx->segment;
> > +    }
> > +
> > +    ctx->segment = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_permuteplanes_meta(FLIF16Context
> *ctx,
> > +
>  FLIF16PixelData *frame,
> > +                                                         uint32_t
> frame_count,
> > +
>  FLIF16TransformContext *t_ctx,
> > +
>  FLIF16RangesContext *src_ctx)
> > +{
> > +    int i;
> > +    FLIF16RangesContext *r_ctx;
> > +    transform_priv_permuteplanes *data;
> > +    ranges_priv_permuteplanes *priv_data;
> > +
> > +    r_ctx = av_mallocz(sizeof(FLIF16RangesContext));
> > +    if (!r_ctx)
> > +        return NULL;
> > +    data = t_ctx->priv_data;
> > +    priv_data = av_mallocz(sizeof(ranges_priv_permuteplanes));
> > +    if (!priv_data)
> > +        return NULL;
> > +    if (data->subtract)
> > +        r_ctx->r_no = FLIF16_RANGES_PERMUTEPLANESSUBTRACT;
> > +    else
> > +        r_ctx->r_no = FLIF16_RANGES_PERMUTEPLANES;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +    for (i = 0; i < 5; i++) {
> > +        priv_data->permutation[i] = data->permutation[i];
> > +    }
>
> > +    priv_data->r_ctx       = data->r_ctx;
>
> Strange spacing.
>
> > +    r_ctx->priv_data = priv_data;
> > +    return r_ctx;
> > +}
> > +
> > +static int transform_permuteplanes_forward(FLIF16Context *ctx,
> > +                                              FLIF16TransformContext
> *t_ctx,
> > +                                              FLIF16PixelData
> *pixel_data)
> > +{
> > +    FLIF16ColorVal pixel[5];
> > +    int r, c, p;
> > +    int width  = ctx->width;
> > +    int height = ctx->height;
> > +    transform_priv_permuteplanes *data = t_ctx->priv_data;
> > +
> > +    for (r = 0; r < height; r++) {
> > +        for (c = 0; c < width; c++) {
> > +            for (p = 0; p < data->r_ctx->num_planes; p++)
>
> > +                pixel[p] = ff_flif16_pixel_get(ctx, pixel_data, 0, r,
> c);
> > +            ff_flif16_pixel_set(ctx, pixel_data, 0, r, c,
> pixel[data->permutation[0]]);
>
> This looks like critical code, and should probably be done by keeping a
> pointer and incrementing it appropriately.
>
> Ya, will have to change that entirely throughout the decoder. Will do.


> Same below.
>
> > +            if (!data->subtract) {
> > +                for (p = 1; p<data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, pixel_data, p, r, c,
> pixel[data->permutation[p]]);
> > +            }
> > +            else {
> > +                for (p = 1; p < 3 && p < data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, pixel_data, p, r, c,
> > +                    pixel[data->permutation[p]] -
> pixel[data->permutation[0]]);
> > +                for (p = 3; p < data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, pixel_data, p, r, c,
> pixel[data->permutation[p]]);
> > +            }
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +static int transform_permuteplanes_reverse(FLIF16Context *ctx,
> > +                                              FLIF16TransformContext
> *t_ctx,
> > +                                              FLIF16PixelData *frame,
> > +                                              uint32_t stride_row,
> > +                                              uint32_t stride_col)
> > +{
> > +    int p, r, c;
> > +    FLIF16ColorVal pixel[5];
> > +    transform_priv_permuteplanes *data = t_ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[data->r_ctx->r_no];
> > +    int height = ctx->height;
> > +    int width  = ctx->width;
> > +    for (r = 0; r < height; r += stride_row) {
> > +        for (c = 0; c < width; c += stride_col) {
> > +            for (p = 0; p < data->r_ctx->num_planes; p++)
> > +                pixel[p] =  ff_flif16_pixel_get(ctx, frame, p, r, c);
> > +            for (p = 0; p < data->r_ctx->num_planes; p++)
> > +                ff_flif16_pixel_set(ctx, frame, data->permutation[p],
> r, c, pixel[p]);
> > +
> > +            ff_flif16_pixel_set(ctx, frame, data->permutation[0], r, c,
> pixel[0]);
> > +            if (!data->subtract) {
> > +                for (p = 1; p < data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, frame,
> data->permutation[p], r, c, pixel[p]);
> > +            }
> > +            else {
> > +                for (p = 1; p < 3 && p < data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, frame,
> data->permutation[p], r, c,
> > +                    av_clip(pixel[p] + pixel[0],
> > +                         ranges->min(data->r_ctx, data->permutation[p]),
> > +                         ranges->max(data->r_ctx,
> data->permutation[p])));
> > +                for (p = 3; p < data->r_ctx->num_planes; p++)
> > +                    ff_flif16_pixel_set(ctx, frame,
> data->permutation[p], r, c, pixel[p]);
> > +            }
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +/*
> > + * ChannelCompact
> > + */
> > +
> > +static int transform_channelcompact_init(FLIF16TransformContext *ctx,
> > +                                            FLIF16RangesContext
> *src_ctx)
> > +{
> > +    int p;
> > +    transform_priv_channelcompact *data = ctx->priv_data;
> > +    if (src_ctx->num_planes > 4)
> > +        return 0;
> > +
> > +    for (p = 0; p < 4; p++) {
> > +        data->CPalette[p]       = 0;
> > +        data->CPalette_size[p]  = 0;
> > +    }
> > +    ff_flif16_chancecontext_init(&data->ctx_a);
> > +    return 1;
> > +}
> > +
> > +static int transform_channelcompact_read(FLIF16TransformContext *ctx,
> > +                                            FLIF16Context *dec_ctx,
> > +                                            FLIF16RangesContext
> *src_ctx)
> > +{
> > +    unsigned int nb;
> > +    transform_priv_channelcompact *data = ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[src_ctx->r_no];
> > +    start:
>
> > +    switch (ctx->segment) {
> > +        case 0:
>
> Nit: indentation.
>
> > +            if (ctx->i < dec_ctx->num_planes) {
> > +                RAC_GET(&dec_ctx->rc, &data->ctx_a,
> > +                        0, ranges->max(src_ctx, ctx->i) -
> > +                        ranges->min(src_ctx, ctx->i),
> > +                        &nb, FLIF16_RAC_NZ_INT);
> > +                nb += 1;
> > +                data->min = ranges->min(src_ctx, ctx->i);
> > +                data->CPalette[ctx->i] = av_mallocz(nb *
> sizeof(FLIF16ColorVal));
> > +                if (!data->CPalette[ctx->i])
> > +                    return -1;
> > +                data->CPalette_size[ctx->i] = nb;
> > +                data->remaining = nb-1;
> > +                ++ctx->segment;
>
> > +                goto next_case;
>
> Goto again.
>
> > +            }
> > +            ctx->i = 0;
> > +            goto end;
> > +
> > +        next_case:
> > +        case 1:
> > +            for (; data->i < data->CPalette_size[ctx->i]; ++data->i) {
> > +                RAC_GET(&dec_ctx->rc, &data->ctx_a,
> > +                        0, ranges->max(src_ctx,
> ctx->i)-data->min-data->remaining,
> > +                        &data->CPalette[ctx->i][data->i],
> > +                        FLIF16_RAC_NZ_INT);
> > +                data->CPalette[ctx->i][data->i] += data->min;
> > +                data->min = data->CPalette[ctx->i][data->i]+1;
> > +                data->remaining--;
> > +            }
> > +            data->i = 0;
> > +            ctx->segment--;
> > +            ctx->i++;
> > +            goto start;
> > +    }
> > +
> > +    end:
> > +    ctx->segment = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_channelcompact_meta(FLIF16Context
> *ctx,
> > +
> FLIF16PixelData *frame,
> > +                                                          uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +
> FLIF16RangesContext *src_ctx)
> > +{
> > +    int i;
> > +    FLIF16RangesContext *r_ctx;
> > +    ranges_priv_channelcompact *data;
> > +    transform_priv_channelcompact *trans_data;
> > +
> > +    r_ctx = av_mallocz(sizeof(*r_ctx));
> > +    if (!r_ctx)
> > +        return NULL;
>
> > +    data = av_mallocz(sizeof(*data));
> > +    if (!data)
> > +        return NULL;
>
> Leaks r_ctx.
>
> > +    trans_data = t_ctx->priv_data;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +    for (i = 0; i < src_ctx->num_planes; i++) {
> > +        data->nb_colors[i] = trans_data->CPalette_size[i] - 1;
> > +    }
> > +    r_ctx->priv_data = data;
> > +    r_ctx->r_no = FLIF16_RANGES_CHANNELCOMPACT;
> > +    ff_flif16_ranges_close(src_ctx);
> > +    return r_ctx;
> > +}
> > +
> > +static int transform_channelcompact_reverse(FLIF16Context *ctx,
> > +                                               FLIF16TransformContext
> *t_ctx,
> > +                                               FLIF16PixelData *frame,
> > +                                               uint32_t stride_row,
> > +                                               uint32_t stride_col)
> > +{
> > +    int p, P;
> > +    uint32_t r, c;
> > +    FLIF16ColorVal *palette;
> > +    unsigned int palette_size;
> > +    transform_priv_channelcompact *data = t_ctx->priv_data;
> > +
> > +    for (p = 0; p < ctx->num_planes; p++) {
> > +        palette      = data->CPalette[p];
> > +        palette_size = data->CPalette_size[p];
> > +
> > +        for (r = 0; r < ctx->height; r += stride_row) {
> > +            for (c = 0; c < ctx->width; c += stride_col) {
> > +                P = ff_flif16_pixel_get(ctx, frame, p, r, c);
> > +                if (P < 0 || P >= (int) palette_size)
> > +                    P = 0;
> > +                av_assert0(P < (int) palette_size);
> > +                ff_flif16_pixel_set(ctx, frame, p, r, c, palette[P]);
> > +            }
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +static void transform_channelcompact_close(FLIF16TransformContext *ctx)
> > +{
> > +    transform_priv_channelcompact *data = ctx->priv_data;
> > +    for (unsigned int i = 0; i < 4; i++) {
>
> > +         if (data->CPalette_size[i] != 0)
>
> Unnecessary test.
>
> > +            av_free(data->CPalette[i]);
> > +    }
> > +    // av_free(data->CPalette_inv);    //  Only used in transform
> forward
> > +}
> > +
> > +/*
> > + * Bounds
> > + */
> > +
> > +static int transform_bounds_init(FLIF16TransformContext *ctx,
> > +                                    FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_bounds *data = ctx->priv_data;
> > +    if (src_ctx->num_planes > 4)
> > +        return 0;
> > +    ff_flif16_chancecontext_init(&data->ctx_a);
>
> > +    data->bounds =
> av_mallocz(src_ctx->num_planes*sizeof(*data->bounds));
>
> av_mallocz_array().
>
Will correct it.

>
> > +    if (!data->bounds)
> > +        return -1;
>
> AVERROR(ENOMEM)
>
and also change return codes in terms of AVERROR codes.

>
> > +    return 1;
> > +}
> > +
> > +static int transform_bounds_read(FLIF16TransformContext *ctx,
> > +                                    FLIF16Context *dec_ctx,
> > +                                    FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_bounds *data = ctx->priv_data;
> > +    FLIF16Ranges *ranges = flif16_ranges[src_ctx->r_no];
> > +    int max;
>
> > +    start:
>
> Proper loop please.
>
> > +    if (ctx->i < dec_ctx->num_planes) {
> > +        switch (ctx->segment) {
> > +            case 0:
>
> Nit: indent.
>
> > +                ranges->min(src_ctx, ctx->i);
> > +                ranges->max(src_ctx, ctx->i);
> > +                RAC_GET(&dec_ctx->rc, &data->ctx_a,
> > +                        ranges->min(src_ctx, ctx->i),
> > +                        ranges->max(src_ctx, ctx->i),
> > +                        &data->min, FLIF16_RAC_GNZ_INT);
> > +                ctx->segment++;
> > +
> > +            case 1:
> > +                RAC_GET(&dec_ctx->rc, &data->ctx_a,
> > +                        data->min, ranges->max(src_ctx, ctx->i),
> > +                        &max, FLIF16_RAC_GNZ_INT);
> > +                if (data->min > max)
> > +                    return 0;
> > +                if (data->min < ranges->min(src_ctx, ctx->i))
> > +                    return 0;
> > +                if (max > ranges->max(src_ctx, ctx->i))
> > +                    return 0;
> > +                data->bounds[ctx->i][0] = data->min;
> > +                data->bounds[ctx->i][1] = max;
> > +                printf("bounds[%d].min : %d bounds[%d].max : %d\n",
> ctx->i, data->bounds[ctx->i][0], ctx->i, data->bounds[ctx->i][1]);
> > +                ctx->i++;
> > +                ctx->segment--;
> > +                goto start;
> > +        }
>
> > +    }
> > +    else {
>
> Else on the same line. Same below.
>

Will take care of that everywhere in the decoder.

>
> > +        ctx->i = 0;
> > +        ctx->segment = 0;
> > +    }
> > +
> > +    return 1;
> > +
> > +    need_more_data:
> > +        return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_bounds_meta(FLIF16Context *ctx,
> > +                                                  FLIF16PixelData
> *frame,
> > +                                                  uint32_t frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +                                                  FLIF16RangesContext
> *src_ctx)
> > +{
> > +    FLIF16RangesContext *r_ctx;
> > +    transform_priv_bounds *trans_data = t_ctx->priv_data;
> > +    ranges_priv_static *data;
> > +    ranges_priv_bounds *dataB;
> > +
> > +    r_ctx = av_mallocz(sizeof(FLIF16RangesContext));
> > +    if (!r_ctx)
> > +        return NULL;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +
> > +    if (flif16_ranges[src_ctx->r_no]->is_static) {
> > +        r_ctx->r_no = FLIF16_RANGES_STATIC;
> > +        r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_static));
>
> > +        if (!r_ctx->priv_data)
> > +            return NULL;
>
> Leaks r_ctx.
>
> > +        data = r_ctx->priv_data;
> > +        data->bounds = trans_data->bounds;
> > +    }
> > +    else {
> > +        r_ctx->r_no = FLIF16_RANGES_BOUNDS;
> > +        r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_bounds));
>
> > +        if (!r_ctx->priv_data)
> > +            return NULL;
>
> Same.
>
> > +        dataB = r_ctx->priv_data;
> > +        dataB->bounds = trans_data->bounds;
> > +        dataB->r_ctx = src_ctx;
> > +    }
> > +    return r_ctx;
> > +}
> > +
> > +/*
> > + * Palette
> > + */
> > +
> > +#define MAX_PALETTE_SIZE 30000
> > +
> > +static int transform_palette_init(FLIF16TransformContext *ctx,
> > +                                     FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_palette *data = ctx->priv_data;
> > +
> > +    if ( (src_ctx->num_planes < 3)  ||
> > +         (ff_flif16_ranges_max(src_ctx, 0) == 0
> > +       && ff_flif16_ranges_max(src_ctx, 2) == 0
> > +       && src_ctx->num_planes > 3
> > +       && ff_flif16_ranges_min(src_ctx, 3) == 1
> > +       && ff_flif16_ranges_max(src_ctx, 3) == 1)  ||
> > +         (ff_flif16_ranges_min(src_ctx, 1) ==
> ff_flif16_ranges_max(src_ctx, 1)
> > +       && ff_flif16_ranges_min(src_ctx, 2) ==
> ff_flif16_ranges_max(src_ctx, 2)))
> > +        return 0;
> > +
> > +    if (src_ctx->num_planes > 3)
> > +        data->has_alpha = 1;
> > +    else
> > +        data->has_alpha = 0;
> > +
> > +    ff_flif16_chancecontext_init(&data->ctx);
> > +    ff_flif16_chancecontext_init(&data->ctxY);
> > +    ff_flif16_chancecontext_init(&data->ctxI);
> > +    ff_flif16_chancecontext_init(&data->ctxQ);
> > +    data->p = 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static int transform_palette_read(FLIF16TransformContext *ctx,
> > +                                     FLIF16Context *dec_ctx,
> > +                                     FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_palette *data = ctx->priv_data;
> > +    switch (ctx->i)
> > +    {
> > +        case 0:
> > +            RAC_GET(&dec_ctx->rc, &data->ctx, 1, MAX_PALETTE_SIZE,
> > +                    &data->size, FLIF16_RAC_GNZ_INT);
> > +            data->Palette = av_mallocz(data->size *
> sizeof(*data->Palette));
> > +            if (!data->Palette)
>
> > +                return -1;
>
> AVERROR(ENOMEM)
>
> > +            ctx->i++;
> > +
> > +        case 1:
> > +            RAC_GET(&dec_ctx->rc, &data->ctx, 0, 1,
> > +                    &data->sorted, FLIF16_RAC_GNZ_INT);
> > +            if (data->sorted) {
> > +                ctx->i = 2;
> > +                for (int i = 0; i < 3; i++) {
> > +                    data->min[i] = ff_flif16_ranges_min(src_ctx, i);
> > +                    data->max[i] = ff_flif16_ranges_max(src_ctx, i);
> > +                    data->Palette[0][i] = -1;
> > +                }
> > +                data->prev = data->Palette[0];
> > +            }
> > +            else {
> > +                ctx->i = 5;
> > +                goto unsorted;
> > +            }
> > +
>
> > +        loop:
>
> Proper loop please.
>
> > +        if (data->p < data->size) {
> > +        case 2:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0],
> data->max[0],
> > +                    &data->Y, FLIF16_RAC_GNZ_INT);
> > +            data->pp[0] = data->Y;
> > +            ff_flif16_ranges_minmax(src_ctx, 1, data->pp,
> &data->min[1], &data->max[1]);
> > +            ctx->i++;
> > +
> > +        case 3:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxI,
> > +                    data->prev[0] == data->Y ? data->prev[1] :
> data->min[1],
> > +                    data->max[1],
> > +                    &data->I, FLIF16_RAC_GNZ_INT);
> > +            data->pp[1] = data->I;
> > +            ff_flif16_ranges_minmax(src_ctx, 2, data->pp,
> &data->min[2], &data->max[2]);
> > +            ctx->i++;
> > +
> > +        case 4:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[2],
> data->max[2],
> > +                    &data->Q, FLIF16_RAC_GNZ_INT);
> > +            data->Palette[data->p][0] = data->Y;
> > +            data->Palette[data->p][1] = data->I;
> > +            data->Palette[data->p][2] = data->Q;
> > +            data->min[0] = data->Y;
> > +            data->prev = data->Palette[data->p];
> > +            data->p++;
> > +            ctx->i = 2;
> > +            goto loop;
> > +        }
> > +        else {
> > +            ctx->i = 0;
> > +            data->p = 0;
> > +            goto end;
> > +        }
> > +
> > +        unsorted:
> > +        if (data->p < data->size) {
> > +        case 5:
> > +            ff_flif16_ranges_minmax(src_ctx, 0, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0],
> data->max[0],
> > +                    &data->Y, FLIF16_RAC_GNZ_INT);
> > +            data->pp[0] = data->Y;
> > +            ctx->i++;
> > +
> > +        case 6:
> > +            ff_flif16_ranges_minmax(src_ctx, 1, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxI, data->min[0],
> data->max[0],
> > +                    &data->I, FLIF16_RAC_GNZ_INT);
> > +            data->pp[1] = data->I;
> > +            ctx->i++;
> > +
> > +        case 7:
> > +            ff_flif16_ranges_minmax(src_ctx, 2, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[0],
> data->max[0],
> > +                    &data->Q, FLIF16_RAC_GNZ_INT);
> > +            data->Palette[data->p][0] = data->Y;
> > +            data->Palette[data->p][1] = data->I;
> > +            data->Palette[data->p][2] = data->Q;
> > +            data->p++;
> > +            ctx->i = 5;
> > +            goto unsorted;
> > +        }
> > +        else {
> > +            data->p = 0;
> > +            ctx->i = 0;
> > +            goto end;
> > +        }
> > +
> > +    }
> > +    end:
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_palette_meta(FLIF16Context *ctx,
> > +                                                   FLIF16PixelData
> *frame,
> > +                                                   uint32_t frame_count,
> > +
>  FLIF16TransformContext *t_ctx,
> > +                                                   FLIF16RangesContext
> *src_ctx)
> > +{
> > +    FLIF16RangesContext *r_ctx;
> > +    transform_priv_palette *trans_data;
> > +    ranges_priv_palette *data;
> > +
> > +    r_ctx = av_mallocz(sizeof(*r_ctx));
> > +    if (!r_ctx)
> > +        return NULL;
> > +    trans_data = t_ctx->priv_data;
> > +    data = av_mallocz(sizeof(*data));
>
> > +    if (!data)
> > +        return NULL;
>
> Leaks r_ctx.
>
> > +    // int i;
> > +    // for (i = 0; i < frame_count; i++)
> > +    //     frame[i].palette = 1;
> > +    data->r_ctx = src_ctx;
> > +    data->nb_colors = trans_data->size;
> > +    r_ctx->r_no = FLIF16_RANGES_PALETTE;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +    r_ctx->priv_data = data;
> > +    return r_ctx;
> > +}
> > +
> > +static int transform_palette_reverse(FLIF16Context *ctx,
> > +                                        FLIF16TransformContext *t_ctx,
> > +                                        FLIF16PixelData *frame,
> > +                                        uint32_t stride_row,
> > +                                        uint32_t stride_col)
> > +{
> > +    int r, c;
> > +    int P;
> > +    transform_priv_palette *data = t_ctx->priv_data;
> > +    for (r = 0; r < ctx->height; r += stride_row) {
> > +        for (c = 0; c < ctx->width; c += stride_col) {
> > +            P = ff_flif16_pixel_get(ctx, frame, 1, r, c);
>
> > +            if (P < 0 || P >= data->size)
> > +                P = 0;
> > +            av_assert0(P < data->size);
> > +            av_assert0(P >= 0);
>
> Unless you expect data->size to be 0, these asserts are nonsensical.
>
> > +            ff_flif16_pixel_set(ctx, frame, 0, r, c,
> data->Palette[P][0]);
> > +            ff_flif16_pixel_set(ctx, frame, 1, r, c,
> data->Palette[P][1]);
> > +            ff_flif16_pixel_set(ctx, frame, 2, r, c,
> data->Palette[P][2]);
>
> Critical code: better optimize the pointer arithmetic.
>
> > +        }
> > +        //frame->palette = 0;
> > +    }
> > +    return 1;
> > +}
> > +
> > +static void transform_palette_close(FLIF16TransformContext *ctx)
> > +{
> > +    transform_priv_palette *data = ctx->priv_data;
> > +    av_free(data->Palette);
> > +}
> > +
> > +/*
> > + * Palette Alpha
> > + */
> > +
> > +static int transform_palettealpha_init(FLIF16TransformContext *ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_palettealpha *data = ctx->priv_data;
> > +    if ( src_ctx->num_planes < 4
> > +      || ff_flif16_ranges_min(src_ctx, 3) ==
> ff_flif16_ranges_max(src_ctx, 3))
> > +        return 0;
> > +
> > +    data->already_has_palette = 0;
> > +    ff_flif16_chancecontext_init(&data->ctx);
> > +    ff_flif16_chancecontext_init(&data->ctxY);
> > +    ff_flif16_chancecontext_init(&data->ctxI);
> > +    ff_flif16_chancecontext_init(&data->ctxQ);
> > +    ff_flif16_chancecontext_init(&data->ctxA);
> > +    data->p = 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static int transform_palettealpha_read(FLIF16TransformContext *ctx,
> > +                                          FLIF16Context *dec_ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_palettealpha *data = ctx->priv_data;
>
> > +    switch (ctx->i)
> > +    {
> > +        case 0:
>
> Nit: brace on the same line and indentation.
>

Okay.


>
> > +            RAC_GET(&dec_ctx->rc, &data->ctx, 1, MAX_PALETTE_SIZE,
> > +                    &data->size, FLIF16_RAC_GNZ_INT);
> > +            data->Palette = av_mallocz(data->size *
> sizeof(*data->Palette));
> > +            if (!data->Palette)
> > +                return 0;
> > +            ctx->i++;
> > +
> > +        case 1:
> > +            RAC_GET(&dec_ctx->rc, &data->ctx, 0, 1,
> > +                    &data->sorted, FLIF16_RAC_GNZ_INT);
> > +            if (data->sorted) {
> > +                ctx->i = 2;
> > +                data->min[0] = ff_flif16_ranges_min(src_ctx, 3);
> > +                data->max[0] = ff_flif16_ranges_max(src_ctx, 3);
> > +                for (int i = 1; i < 4; i++) {
> > +                    data->min[i] = ff_flif16_ranges_min(src_ctx, i-1);
> > +                    data->max[i] = ff_flif16_ranges_max(src_ctx, i-1);
> > +                    data->Palette[0][i] = -1;
> > +                }
> > +                data->prev = data->Palette[0];
> > +            }
> > +            else {
> > +                ctx->i = 6;
> > +                goto unsorted;
> > +            }
> > +
>
> > +        loop:
>
> Proper loop please.
>
> > +        if (data->p < data->size) {
> > +        case 2:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxA, data->min[0],
> data->max[0],
> > +                    &data->A, FLIF16_RAC_GNZ_INT);
> > +            if (data->alpha_zero_special && data->A == 0) {
> > +                for (int i = 0; i < 4; i++)
> > +                    data->Palette[data->p][i] = 0;
> > +                data->p++;
> > +                goto loop;
> > +            }
> > +            ctx->i++;
> > +
> > +        case 3:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxY,
> > +                    data->prev[0] == data->A ? data->prev[1] :
> data->min[1],
> > +                    data->max[1],
> > +                    &data->Y, FLIF16_RAC_GNZ_INT);
> > +            data->pp[0] = data->Y;
> > +            ff_flif16_ranges_minmax(src_ctx, 1, data->pp,
> &data->min[2], &data->max[2]);
> > +            ctx->i++;
> > +
> > +        case 4:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxI,
> > +                    data->min[2], data->max[2],
> > +                    &data->I, FLIF16_RAC_GNZ_INT);
> > +            data->pp[1] = data->I;
> > +            ff_flif16_ranges_minmax(src_ctx, 2, data->pp,
> &data->min[3], &data->max[3]);
> > +            ctx->i++;
> > +
> > +        case 5:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[3],
> data->max[3],
> > +                    &data->Q, FLIF16_RAC_GNZ_INT);
> > +            data->Palette[data->p][0] = data->A;
> > +            data->Palette[data->p][1] = data->Y;
> > +            data->Palette[data->p][2] = data->I;
> > +            data->Palette[data->p][3] = data->Q;
> > +            data->min[0] = data->A;
> > +            data->prev = data->Palette[data->p];
> > +            data->p++;
> > +            ctx->i = 2;
> > +            goto loop;
> > +        }
> > +        else {
> > +            ctx->i = 0;
> > +            data->p = 0;
> > +            goto end;
> > +        }
> > +
> > +        unsorted:
> > +        if (data->p < data->size) {
> > +        case 6:
> > +            RAC_GET(&dec_ctx->rc, &data->ctxA,
> > +            ff_flif16_ranges_min(src_ctx, 3),
> ff_flif16_ranges_max(src_ctx, 3),
> > +            &data->A, FLIF16_RAC_GNZ_INT);
> > +            if (data->alpha_zero_special && data->A == 0) {
> > +                for (int i = 0; i < 4; i++)
> > +                    data->Palette[data->p][i] = 0;
> > +                data->p++;
> > +                goto loop;
> > +            }
> > +            ctx->i++;
> > +
> > +        case 7:
> > +            ff_flif16_ranges_minmax(src_ctx, 0, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0],
> data->max[0],
> > +                    &data->Y, FLIF16_RAC_GNZ_INT);
> > +            data->pp[0] = data->Y;
> > +            ctx->i++;
> > +
> > +        case 8:
> > +            ff_flif16_ranges_minmax(src_ctx, 1, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxI, data->min[0],
> data->max[0],
> > +                    &data->I, FLIF16_RAC_GNZ_INT);
> > +            data->pp[1] = data->I;
> > +            ctx->i++;
> > +
> > +        case 9:
> > +            ff_flif16_ranges_minmax(src_ctx, 2, data->pp,
> &data->min[0], &data->max[0]);
> > +            RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[0],
> data->max[0],
> > +                    &data->Q, FLIF16_RAC_GNZ_INT);
> > +            data->Palette[data->p][0] = data->A;
> > +            data->Palette[data->p][1] = data->Y;
> > +            data->Palette[data->p][2] = data->I;
> > +            data->Palette[data->p][3] = data->Q;
> > +            data->p++;
> > +            ctx->i = 6;
> > +            goto unsorted;
> > +        }
> > +        else {
> > +            data->p = 0;
> > +            ctx->i = 0;
> > +            goto end;
> > +        }
> > +
> > +    }
> > +    end:
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static void transform_palettealpha_configure(FLIF16TransformContext
> *ctx,
> > +                                             const int setting)
> > +{
> > +    transform_priv_palettealpha *data = ctx->priv_data;
> > +    data->alpha_zero_special = setting;
> > +    if (setting > 0) {
> > +        data->ordered_palette = 1;
> > +        data->max_palette_size = setting;
> > +    }
> > +    else {
> > +        data->ordered_palette = 0;
> > +        data->max_palette_size = -setting;
> > +    }
> > +}
> > +
> > +static FLIF16RangesContext *transform_palettealpha_meta(FLIF16Context
> *ctx,
> > +                                                        FLIF16PixelData
> *frame,
> > +                                                        uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +
> FLIF16RangesContext *src_ctx)
> > +{
> > +    FLIF16RangesContext *r_ctx;
> > +    transform_priv_palettealpha *data;
> > +    ranges_priv_palette *priv_data;
> > +    r_ctx = av_mallocz(sizeof(*r_ctx));
> > +    if (!r_ctx)
> > +        return NULL;
> > +    data = t_ctx->priv_data;
> > +    // ????
>
> > +    priv_data = av_mallocz(sizeof(ranges_priv_permuteplanes));
> > +    if (!priv_data)
> > +        return NULL;
>
> Leaks r_ctx.
>
> > +    r_ctx->r_no = FLIF16_RANGES_PALETTEALPHA;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +    priv_data->nb_colors = data->size;
> > +    priv_data->r_ctx = src_ctx;
> > +    r_ctx->priv_data = priv_data;
> > +
> > +    // for (int i = 0; i < frame_count; i++)
> > +    //     frame[i].palette = 1;
> > +
> > +    return r_ctx;
> > +}
> > +
> > +static int transform_palettealpha_reverse(FLIF16Context *ctx,
> > +                                             FLIF16TransformContext
> *t_ctx,
> > +                                             FLIF16PixelData *frame,
> > +                                             uint32_t stride_row,
> > +                                             uint32_t stride_col)
> > +{
> > +    int r, c;
> > +    int P;
> > +    transform_priv_palettealpha *data = t_ctx->priv_data;
> > +    for (r = 0; r < ctx->height; r += stride_row) {
> > +        for (c = 0; c < ctx->width; c += stride_col) {
> > +            P = ff_flif16_pixel_get(ctx, frame, 1, r, c);
> > +            av_assert0(P < data->size);
> > +            ff_flif16_pixel_set(ctx, frame, 0, r, c,
> data->Palette[P][1]);
> > +            ff_flif16_pixel_set(ctx, frame, 1, r, c,
> data->Palette[P][2]);
> > +            ff_flif16_pixel_set(ctx, frame, 2, r, c,
> data->Palette[P][3]);
> > +            ff_flif16_pixel_set(ctx, frame, 3, r, c,
> data->Palette[P][0]);
> > +        }
> > +        //frame->palette = 0;
> > +    }
> > +    return 1;
> > +}
> > +
> > +static void transform_palettealpha_close(FLIF16TransformContext *ctx)
> > +{
> > +    transform_priv_palettealpha *data = ctx->priv_data;
> > +    av_free(data->Palette);
> > +}
> > +
> > +/*
> > + * ColorBuckets
> > + */
> > +
> > +
> > +static ColorValCB_list *ff_insert_colorvalCB(ColorValCB_list *list,
> > +                                             unsigned int pos,
> ColorValCB val)
> > +{
> > +    ColorValCB_list *temp = list;
> > +    ColorValCB_list *elem = av_mallocz(sizeof(*elem));
> > +    if (!elem)
> > +        return NULL;
> > +    elem->data = val;
> > +    elem->next = 0;
> > +
> > +    if (pos == 0) {
> > +        elem->next = temp;
> > +        return elem;
> > +    }
> > +
>
> > +    for (unsigned int i = 1; i < pos; i++) {
> > +        temp = temp->next;
> > +    }
>
> This is quadratic in total. Keep a pointer to the "next" field of the
> last element, initialized to the pointer to the list, and it becomes
> linear.
>

Okay will do.

>
> > +    av_assert0(temp);
> > +    elem->next = temp->next;
> > +    temp->next = elem;
> > +
> > +    return list;
> > +}
> > +
>
> > +static ColorValCB_list *ff_remove_colorvalCB(ColorValCB_list *list,
> > +                                             unsigned int pos)
>
> Mixing linked lists and indices is usually a sign you are doing
> something wrong.
>
> Here, I believe you would do better with a doubly linked list and
> pointers instead of indices.
>
> Note: there is a trick with doubly linked lists where you put the next
> and prev pointers together alone in a struct, and have them point not to
> the actual elements but to the next/prev struct of the elements. That
> way, you can have the whole list itself as just another such struct, and
> not have to make special cases for the ends of the list.
>
> If you do not know that trick and want to, I can explain.
>

Yes please explain more.

>
> > +{
> > +    ColorValCB_list *temp = list, *temp1;
> > +    if (pos == 0) {
> > +        temp = list->next;
> > +        av_free(list);
> > +        return temp;
> > +    }
> > +
> > +    for (int i = 1; i < pos; i++) {
> > +        temp = temp->next;
> > +    }
> > +    temp1 = temp->next;
> > +    temp->next = temp1->next;
> > +    av_free(temp1);
> > +
> > +    return list;
> > +}
> > +
> > +static ColorValCB ff_colorvalCB_at(ColorValCB_list *list, unsigned int
> pos)
> > +{
> > +    ColorValCB_list *temp = list;
> > +    for (unsigned int i = 0; i < pos; i++) {
> > +        temp = temp->next;
> > +    }
> > +    return temp->data;
> > +}
> > +
>
> > +static uint8_t ff_remove_color(ColorBucket *cb, const FLIF16ColorVal c)
>
> The return value seems unnecessary.
>
Ya will adjust/remove this.

>
> > +{
> > +    if (cb->discrete) {
> > +        unsigned int pos = 0;
> > +        ColorValCB_list *temp = cb->values;
> > +        for (; pos < cb->values_size; pos++, temp = temp->next) {
> > +            if (c == temp->data) {
> > +                cb->values = ff_remove_colorvalCB(cb->values, pos);
> > +                cb->values_size--;
> > +                break;
> > +            }
> > +        }
> > +        if (cb->values_size == 0) {
> > +            cb->min = 10000;
> > +            cb->max = -10000;
> > +            return 1;
> > +        }
> > +        av_assert0(cb->values_size > 0);
> > +        if (c == cb->min)
> > +            cb->min = ff_colorvalCB_at(cb->values, 0);
> > +        if (c == cb->max)
> > +            cb->max = ff_colorvalCB_at(cb->values, cb->values_size-1);
>
> > +    }
> > +    else {
>
> Nit: else on the same line.
>
> > +        if (c == cb->min)
> > +            cb->min++;
> > +        if (c == cb->max)
> > +            cb->max--;
> > +        if (c > cb->max)
> > +            return 1;
> > +        if (c < cb->min)
> > +            return 1;
> > +        cb->discrete = 1;
> > +        av_freep(&cb->values);
> > +        cb->values_size = 0;
> > +        for (FLIF16ColorVal x = cb->min; x <= cb->max; x++) {
> > +            if (x != c) {
> > +                cb->values = ff_insert_colorvalCB(cb->values,
> cb->values_size, x);
> > +                cb->values_size++;
> > +            }
> > +        }
> > +    }
> > +    return 1;
> > +}
> > +
> > +static FLIF16ColorVal ff_snap_color_slow(ColorBucket *cb, const
> FLIF16ColorVal c)
> > +{
> > +    FLIF16ColorVal diff;
> > +    if (c <= cb->min)
> > +        return cb->min;
> > +    if (c >= cb->max)
> > +        return cb->max;
> > +    if (cb->discrete) {
> > +        FLIF16ColorVal mindiff = abs(c - cb->min);
> > +        unsigned int best = 0;
> > +        ColorValCB_list *temp = cb->values->next;
> > +        for (unsigned int i = 1; i < cb->values_size; i++, temp =
> temp->next) {
> > +            if (c == temp->data)
> > +                return c;
> > +            diff = abs(c - temp->data);
> > +            if (diff < mindiff) {
> > +                best = i;
> > +                mindiff = diff;
> > +            }
> > +            if (temp->data > c)
> > +                break;
> > +        }
> > +        return ff_colorvalCB_at(cb->values, best);
> > +    }
> > +    return c;
> > +}
> > +
> > +static void ff_prepare_snapvalues(ColorBucket *cb)
> > +{
> > +    int i = 0;
> > +    if (cb->discrete) {
> > +        av_freep(&cb->snapvalues);
>
> > +        cb->snapvalues = av_mallocz((cb->max - cb->min) *
> sizeof(*cb->snapvalues));
> > +        // av_assert0(cb->snapvalues != NULL);
>
> Proper error check and propagation please.
>

Will do.


>
> > +        cb->snapvalues_size = cb->max - cb->min;
> > +        for (FLIF16ColorVal c = cb->min; c < cb->max; c++) {
> > +            cb->snapvalues[i] = ff_snap_color_slow(cb, c);
> > +            i++;
> > +        }
> > +    }
> > +}
> > +
> > +
> > +static uint8_t ff_colorbuckets_exists2(ColorBuckets *cb, const int p,
> > +                                       FLIF16ColorVal *pp)
> > +{
> > +    FLIF16ColorVal rmin, rmax, v;
> > +    ColorBucket *b;
> > +    if (p > FLIF16_PLANE_Y
> > +    && (pp[0] < cb->min0 || pp[0] > ff_flif16_ranges_max(cb->ranges,
> 0))) {
> > +        return 0;
> > +    }
> > +    if (p > FLIF16_PLANE_CO
> > +    && (pp[1] < cb->min1 || pp[1] > ff_flif16_ranges_max(cb->ranges,
> 1))) {
> > +        return 0;
> > +    }
> > +
> > +    v = pp[p];
> > +    ff_flif16_ranges_snap(cb->ranges, p, pp, &rmin, &rmax, &v);
> > +    if (v != pp[p])
> > +        return 0;
> > +
> > +    b = ff_bucket_buckets(cb, p, pp);
> > +    if (ff_snap_color_slow(b, pp[p]) != pp[p])
> > +        return 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static uint8_t ff_colorbuckets_exists(ColorBuckets *cb, const int p,
> > +                                      FLIF16ColorVal *lower,
> FLIF16ColorVal *upper)
> > +{
> > +    FLIF16ColorVal pixel[2];
> > +    pixel[0] = lower[0];
> > +    pixel[1] = lower[1];
> > +    if (p == FLIF16_PLANE_Y) {
> > +        for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) {
> > +            if (ff_colorbuckets_exists2(cb, p, pixel))
> > +                return 1;
> > +        }
> > +    }
> > +    if (p == FLIF16_PLANE_CO) {
> > +        for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) {
> > +            for (pixel[1] = lower[1]; pixel[1] <= upper[1]; pixel[1]++)
> {
> > +                if (ff_colorbuckets_exists2(cb, p, pixel))
> > +                    return 1;
> > +            }
> > +        }
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int transform_colorbuckets_init(FLIF16TransformContext *ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_colorbuckets *data = ctx->priv_data;
> > +    int length, temp;
> > +    ColorBuckets *cb;
> > +    data->cb = NULL;
> > +    data->really_used = 0;
>
> > +    if ((src_ctx->num_planes < 3)
> > +     ||
> > +      (ff_flif16_ranges_min(src_ctx, 0) == 0
> > +    && ff_flif16_ranges_max(src_ctx, 0) == 0
> > +    && ff_flif16_ranges_min(src_ctx, 2) == 0
> > +    && ff_flif16_ranges_max(src_ctx, 2) == 0)
> > +     ||
> > +      (ff_flif16_ranges_min(src_ctx, 0) ==
> ff_flif16_ranges_max(src_ctx, 0)
> > +    && ff_flif16_ranges_min(src_ctx, 1) ==
> ff_flif16_ranges_max(src_ctx, 1)
> > +    && ff_flif16_ranges_min(src_ctx, 2) ==
> ff_flif16_ranges_max(src_ctx, 2))
> > +     ||
> > +      (ff_flif16_ranges_max(src_ctx, 0) - ff_flif16_ranges_min(src_ctx,
> 0) > 1023
> > +     ||ff_flif16_ranges_max(src_ctx, 1) - ff_flif16_ranges_min(src_ctx,
> 1) > 1023
> > +     ||ff_flif16_ranges_max(src_ctx, 2) - ff_flif16_ranges_min(src_ctx,
> 2) > 1023)
> > +     ||
>
> It would look clearer with the || and && operators at the end.
>

Will do it that way.


>
> > +    (ff_flif16_ranges_min(src_ctx, 1) == ff_flif16_ranges_max(src_ctx,
> 1)))
> > +        return 0;
> > +
>
> > +    cb = av_mallocz(sizeof(*cb));
> > +    if (!cb)
> > +        return 0;
>
> AVERROR(ENOMEM) and error propagation.
>
> > +
> > +    ff_init_bucket_default(&cb->bucket0);
> > +    cb->min0 = ff_flif16_ranges_min(src_ctx, 0);
> > +    cb->min1 = ff_flif16_ranges_min(src_ctx, 1);
> > +
> > +    length = ((ff_flif16_ranges_max(src_ctx, 0) - cb->min0)/CB0b + 1);
> > +    temp = ((ff_flif16_ranges_max(src_ctx, 1) - cb->min1)/CB1 + 1);
> > +
> > +    cb->bucket1 = av_mallocz(((ff_flif16_ranges_max(src_ctx, 0)
> > +                                   - cb->min0)/CB0a + 1)
> > +                                   * sizeof(*cb->bucket1));
>
> > +    if (!cb->bucket1)
> > +        return 0;
>
> Leaks cb.
>
> > +    cb->bucket1_size = ((ff_flif16_ranges_max(src_ctx, 0)
> > +                                   - cb->min0)/CB0a + 1);
>
> > +    cb->bucket2 = av_mallocz(length * sizeof(*cb->bucket2));
>
> > +    if (!cb->bucket2)
> > +        return 0;
>
> Same.
>
> > +    cb->bucket2_size = length;
> > +    for (int i = 0; i < length; i++) {
> > +        cb->bucket2_list_size = temp;
> > +        cb->bucket2[i] = av_mallocz(temp * sizeof(*cb->bucket2[i]));
> > +        if (!cb->bucket2[i])
> > +            return 0;
> > +    }
> > +    ff_init_bucket_default(&cb->bucket3);
> > +    for (uint8_t i = 0; i < 6; i++)
> > +        ff_flif16_chancecontext_init(&data->ctx[i]);
> > +
> > +    cb->ranges = src_ctx;
> > +    data->cb = cb;
> > +    data->i = 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static FLIF16RangesContext *transform_colorbuckets_meta(FLIF16Context
> *ctx,
> > +                                                        FLIF16PixelData
> *frame,
> > +                                                        uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +
> FLIF16RangesContext *src_ctx)
> > +{
> > +    FLIF16RangesContext *r_ctx;
> > +    transform_priv_colorbuckets *trans_data = t_ctx->priv_data;
> > +    ranges_priv_colorbuckets *data;
> > +    ColorBuckets *cb = trans_data->cb;
> > +    FLIF16ColorVal pixelL[2], pixelU[2];
> > +
> > +    r_ctx = av_mallocz(sizeof(*r_ctx));
> > +    if (!r_ctx)
> > +        return NULL;
>
> > +    data = av_mallocz(sizeof(ranges_priv_palette));
> > +    if (!data)
> > +        return NULL;
>
> Leaks r_ctx.
>
> > +    if (ff_flif16_ranges_min(src_ctx, 2) <
> ff_flif16_ranges_max(src_ctx, 2)) {
> > +        pixelL[0] = cb->min0;
> > +        pixelU[0] = cb->min0 + CB0b -1;
> > +        pixelL[1] = cb->min1;
> > +        pixelU[1] = cb->min1 + CB1 - 1;
> > +        for (int i = 0; i < cb->bucket2_size; i++) {
> > +            pixelL[1] = cb->min1;
> > +            pixelU[1] = cb->min1 + CB1 -1;
> > +            for (int j = 0; j < cb->bucket2_list_size; j++) {
> > +                if (cb->bucket2[i][j].min > cb->bucket2[i][j].max) {
> > +                    for (FLIF16ColorVal c = pixelL[1]; c <= pixelU[1];
> c++) {
> > +                        if (!ff_remove_color(ff_bucket_buckets2(cb, 1,
> pixelL), c))
> > +                            return NULL;
> > +                        if (!ff_remove_color(ff_bucket_buckets2(cb, 1,
> pixelU), c))
> > +                            return NULL;
> > +                    }
> > +                }
> > +                pixelL[1] += CB1;
> > +                pixelU[1] += CB1;
> > +            }
> > +            pixelL[0] += CB0b;
> > +            pixelU[0] += CB0b;
> > +        }
> > +    }
> > +    ff_prepare_snapvalues(&cb->bucket0);
> > +    ff_prepare_snapvalues(&cb->bucket3);
> > +    for (unsigned int i = 0; i < cb->bucket1_size; i++)
> > +        ff_prepare_snapvalues(&cb->bucket1[i]);
> > +    for (unsigned int i = 0; i < cb->bucket2_size; i++) {
> > +        for (unsigned int j = 0; j < cb->bucket2_list_size; j++)
> > +            ff_prepare_snapvalues(&cb->bucket2[i][j]);
> > +    }
> > +
> > +    trans_data->really_used = 1;
> > +
> > +    data->r_ctx = src_ctx;
> > +    data->buckets = trans_data->cb;
> > +
> > +    r_ctx->r_no = FLIF16_RANGES_COLORBUCKETS;
> > +    r_ctx->priv_data = data;
> > +    r_ctx->num_planes = src_ctx->num_planes;
> > +
> > +    return r_ctx;
> > +}
> > +
> > +static void transform_colorbuckets_minmax(FLIF16RangesContext *src_ctx,
> int p,
> > +                                          FLIF16ColorVal *lower,
> > +                                          FLIF16ColorVal *upper,
> > +                                          FLIF16ColorVal *smin,
> > +                                          FLIF16ColorVal *smax)
> > +{
> > +    FLIF16ColorVal rmin, rmax;
> > +    FLIF16ColorVal pixel[2];
> > +    pixel[0] = lower[0];
> > +    pixel[1] = lower[1];
> > +    *smin = 10000;
> > +    *smax = -10000;
> > +    if (p == FLIF16_PLANE_Y) {
> > +        ff_flif16_ranges_minmax(src_ctx, p,pixel,smin,smax);
> > +    }
> > +    else if (p == FLIF16_PLANE_CO) {
> > +        for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) {
> > +            ff_flif16_ranges_minmax(src_ctx, p, pixel, &rmin, &rmax);
> > +            if (rmin < *smin)
> > +                *smin = rmin;
> > +            if (rmax > *smax)
> > +                *smax = rmax;
> > +        }
> > +    }
> > +    else if (p == FLIF16_PLANE_CG) {
> > +        for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) {
> > +            for (pixel[1] = lower[1]; pixel[1] <= upper[1]; pixel[1]++)
> {
> > +                ff_flif16_ranges_minmax(src_ctx, p, pixel, &rmin,
> &rmax);
> > +                if (rmin < *smin)
> > +                    *smin = rmin;
> > +                if (rmax > *smax)
> > +                    *smax = rmax;
> > +            }
> > +        }
> > +    }
> > +    else if (p == FLIF16_PLANE_ALPHA) {
> > +        ff_flif16_ranges_minmax(src_ctx, p, pixel, smin, smax);
> > +    }
> > +}
> > +
> > +const unsigned int max_per_colorbucket[] = {255, 510, 5, 255};
> > +
> > +static int ff_load_bucket(FLIF16RangeCoder *rc, FLIF16ChanceContext
> *chancectx,
> > +                             ColorBucket *b, ColorBuckets *cb,
> > +                             FLIF16RangesContext *src_ctx, int plane,
> > +                             FLIF16ColorVal *pixelL, FLIF16ColorVal
> *pixelU)
> > +{
> > +    int temp;
> > +    int exists;
>
> > +    switch (cb->i) {
> > +        case 0:
>
> Nit: indentation.
>
> > +            if (plane < FLIF16_PLANE_ALPHA)
> > +            for (int p = 0; p < plane; p++) {
> > +                if (!ff_colorbuckets_exists(cb, p, pixelL, pixelU)) {
> > +                    goto end;
> > +                }
> > +            }
> > +            cb->i = 1;
> > +
> > +        case 1:
> > +            transform_colorbuckets_minmax(src_ctx, plane,
> > +                                          pixelL, pixelU,
> > +                                          &cb->smin, &cb->smax);
> > +            RAC_GET(rc, &chancectx[0], 0, 1, &exists,
> FLIF16_RAC_GNZ_INT);
> > +            if (exists == 0) {
> > +                goto end; // empty bucket
> > +            }
> > +            if (cb->smin == cb->smax) {
> > +                b->min = cb->smin;
> > +                b->max = cb->smin;
> > +                b->discrete = 0;
> > +                goto end;
> > +            }
> > +            cb->i = 2;
> > +
> > +        case 2:
> > +            RAC_GET(rc, &chancectx[1], cb->smin, cb->smax, &b->min,
> FLIF16_RAC_GNZ_INT);
> > +            cb->i = 3;
> > +
> > +        case 3:
> > +            RAC_GET(rc, &chancectx[2], b->min, cb->smax, &b->max,
> FLIF16_RAC_GNZ_INT);
> > +            if (b->min == b->max) {
> > +                b->discrete = 0;
> > +                goto end;
> > +            }
> > +            if (b->min + 1 == b->max) {
> > +                b->discrete = 0;
> > +                goto end;
> > +            }
> > +            cb->i = 4;
> > +
> > +        case 4:
> > +            RAC_GET(rc, &chancectx[3], 0, 1, &b->discrete,
> FLIF16_RAC_GNZ_INT);
> > +            cb->i = 5;
> > +
> > +        case 5:
> > +            if (b->discrete) {
> > +                RAC_GET(rc, &chancectx[4], 2,
> > +                        FFMIN(max_per_colorbucket[plane], b->max -
> b->min),
> > +                        &cb->nb, FLIF16_RAC_GNZ_INT);
> > +                b->values = 0;
> > +                b->values = ff_insert_colorvalCB(b->values, 0, b->min);
> > +                cb->v = b->min;
> > +                cb->i = 6;
> > +                cb->i2 = 1;
> > +
>
> > +                for (; cb->i2 < cb->nb - 1; cb->i2++) {
> > +        case 6:
> > +                    RAC_GET(rc, &chancectx[5], cb->v + 1,
>
> Urgh.
>
> > +                            b->max + 1 - cb->nb + cb->i2, &temp,
> > +                            FLIF16_RAC_GNZ_INT);
> > +                    b->values = ff_insert_colorvalCB(b->values, cb->i2,
> temp);
> > +                    cb->v = temp;
> > +                }
> > +
> > +                if (b->min < b->max) {
> > +                    b->values = ff_insert_colorvalCB(b->values, cb->nb
> - 1, b->max);
> > +                    b->values_size = cb->nb;
> > +                    goto end;
> > +                }
> > +                b->values_size = cb->nb - 1;
> > +            }
> > +    }
> > +
> > +    end:
> > +    cb->i = 0;
> > +    cb->i2 = 0;
> > +    cb->nb = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static int transform_colorbuckets_read(FLIF16TransformContext *ctx,
> > +                                          FLIF16Context *dec_ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_colorbuckets *data = ctx->priv_data;
> > +    ColorBuckets *cb = data->cb;
> > +    int8_t ret;
> > +
> > +    switch (data->i) {
> > +        case 0:
> > +            ret = ff_load_bucket(&dec_ctx->rc, data->ctx, &cb->bucket0,
> cb,
> > +                                 src_ctx, 0, data->pixelL,
> data->pixelU);
> > +            if (ret <= 0)
> > +                goto need_more_data;
> > +            data->pixelL[0] = (cb->min0);
> > +            data->pixelU[0] = (cb->min0 + (int)CB0a - 1);
> > +            data->i = 1;
> > +
>
> > +            for (; data->j < cb->bucket1_size; data->j++) {
> > +        case 1:
> > +                ret = ff_load_bucket(&dec_ctx->rc, data->ctx,
>
> Urgh.
>
> > +                                     &cb->bucket1[data->j], cb,
> > +                                     src_ctx, 1, data->pixelL,
> data->pixelU);
> > +                if (ret <= 0)
> > +                    goto need_more_data;
> > +                data->pixelL[0] += CB0a;
> > +                data->pixelU[0] += CB0a;
> > +            }
> > +            data->j = 0;
> > +
> > +            if (ff_flif16_ranges_min(src_ctx, 2) <
> ff_flif16_ranges_max(src_ctx, 2)) {
> > +                data->pixelL[0] = cb->min0;
> > +                data->pixelU[0] = cb->min0 + CB0b - 1;
> > +                data->pixelL[1] = cb->min1;
> > +                data->pixelU[1] = cb->min1 + CB1 - 1;
> > +                for (; data->j < cb->bucket2_size; data->j++) {
> > +                    data->pixelL[1] = cb->min1;
> > +                    data->pixelU[1] = cb->min1 + CB1 - 1;
> > +                    data->i = 2;
> > +
> > +                    for (; data->k < cb->bucket2_list_size; data->k++) {
> > +        case 2:
> > +                        ret = ff_load_bucket(&dec_ctx->rc, data->ctx,
> > +
>  &cb->bucket2[data->j][data->k], cb,
> > +                                             src_ctx, 2, data->pixelL,
> data->pixelU);
> > +                        if (ret <= 0)
> > +                            goto need_more_data;
> > +                        data->pixelL[1] += CB1;
> > +                        data->pixelU[1] += CB1;
> > +                    }
> > +                    data->k = 0;
> > +                    data->pixelL[0] += CB0b;
> > +                    data->pixelU[0] += CB0b;
> > +                }
> > +                data->j = 0;
> > +            }
> > +            data->i = 3;
> > +
> > +            if (src_ctx->num_planes > 3) {
> > +        case 3:
> > +                ret = ff_load_bucket(&dec_ctx->rc, data->ctx,
> &cb->bucket3, cb,
> > +                                     src_ctx, 3, data->pixelL,
> data->pixelU);
> > +                if (ret <= 0)
> > +                    goto need_more_data;
> > +            }
> > +
> > +            goto end;
> > +    }
> > +
> > +    end:
> > +    data->i = 0;
> > +    data->j = 0;
> > +    data->k = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static int transform_framedup_init(FLIF16TransformContext *ctx,
> > +                                      FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_framedup *data = ctx->priv_data;
> > +    ff_flif16_chancecontext_init(&data->chancectx);
> > +    data->i = 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static void transform_framedup_configure(FLIF16TransformContext *ctx,
> > +                                         const int setting)
> > +{
> > +    transform_priv_framedup *data = ctx->priv_data;
> > +    data->nb = setting;
> > +}
> > +
> > +static int transform_framedup_read(FLIF16TransformContext  *ctx,
> > +                                      FLIF16Context *dec_ctx,
> > +                                      FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_framedup *data = ctx->priv_data;
> > +
> > +    switch (ctx->i) {
> > +        case 0:
> > +            data->seen_before = av_mallocz(data->nb *
> sizeof(*data->seen_before));
> > +            if (!data->seen_before)
> > +                return 0;
> > +            data->seen_before[0] = -1;
> > +            ctx->i = 1;
> > +            data->i = 1;
> > +
> > +        case 1:
> > +            for (; data->i < data->nb; data->i++) {
> > +                RAC_GET(&dec_ctx->rc, &data->chancectx, -1, data->i - 1,
> > +                        &data->seen_before[data->i], FLIF16_RAC_NZ_INT);
> > +            }
> > +            data->i = 0;
> > +            goto end;
> > +    }
> > +
> > +    end:
> > +    ctx->i = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_framedup_meta(FLIF16Context *ctx,
> > +                                                    FLIF16PixelData
> *frame,
> > +                                                    uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +                                                    FLIF16RangesContext
> *src_ctx)
> > +{
> > +    transform_priv_framedup *data = t_ctx->priv_data;
> > +    for (unsigned int fr = 0; fr < frame_count; fr++) {
> > +        frame[fr].seen_before = data->seen_before[fr];
> > +    }
> > +
> > +    return src_ctx;
> > +}
> > +
> > +static void transform_framedup_close(FLIF16TransformContext *ctx)
> > +{
> > +    transform_priv_framedup *data = ctx->priv_data;
> > +    av_free(data->seen_before);
> > +}
> > +
> > +static int transform_frameshape_init(FLIF16TransformContext *ctx,
> > +                                        FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_frameshape *data = ctx->priv_data;
> > +    ff_flif16_chancecontext_init(&data->chancectx);
> > +    data->i = 0;
> > +
> > +    return 1;
> > +}
> > +
> > +static void transform_frameshape_configure(FLIF16TransformContext *ctx,
> > +                                           const int setting)
> > +{
> > +    transform_priv_frameshape *data = ctx->priv_data;
> > +    if (data->nb == 0) {
> > +        data->nb = setting;
> > +    }
> > +    else
> > +        data->cols = setting;
> > +}
> > +
> > +static int transform_frameshape_read(FLIF16TransformContext  *ctx,
> > +                                        FLIF16Context *dec_ctx,
> > +                                        FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_frameshape *data = ctx->priv_data;
> > +    int temp;
> > +
> > +    switch (ctx->i) {
> > +        case 0:
> > +            data->b = av_mallocz(data->nb * sizeof(*data->b));
> > +            if (!data->b)
>
> > +                return -1;
>
> AVERROR(ENOMEM)
>
> > +            data->e = av_mallocz(data->nb * sizeof(*data->e));
>
> > +            if (!data->e)
> > +                return -1;
>
> Leaks data, and  AVERROR(ENOMEM).
>
> > +            ctx->i = 1;
> > +
> > +        case 1:
> > +            for (; data->i < data->nb; data->i++) {
> > +                RAC_GET(&dec_ctx->rc, &data->chancectx, 0, data->cols,
> > +                        &data->b[data->i], FLIF16_RAC_NZ_INT);
> > +            }
> > +            ctx->i = 2;
> > +            data->i = 0;
> > +
> > +        case 2:
> > +            for (; data->i < data->nb; data->i++) {
> > +                //RAC_GET(&dec_ctx->rc, &data->chancectx, 0,
> > +                //        data->cols - data->b[data->i],
> > +                //        &data->e[data->i], FLIF16_RAC_NZ_INT);
> > +                temp = ff_flif16_rac_process(&dec_ctx->rc,
> &data->chancectx, 0,
> > +                                           data->cols -
> data->b[data->i],
> > +                                           &data->e[data->i],
> FLIF16_RAC_NZ_INT);
> > +                if (temp == 0)
> > +                    goto need_more_data;
> > +                data->e[data->i] = data->cols - data->e[data->i];
> > +
>
> > +                if (   data->e[data->i] > data->cols
> > +                    || data->e[data->i] < data->b[data->i]
> > +                    || data->e[data->i] <= 0) {
>
> Would look better with || at the end.
>
> > +                       return 0;
> > +                }
> > +            }
> > +            data->i = 0;
> > +    }
> > +
> > +    ctx->i = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_frameshape_meta(FLIF16Context
> *ctx,
> > +                                                      FLIF16PixelData
> *frame,
> > +                                                      uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +
> FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_frameshape *data = t_ctx->priv_data;
> > +    uint32_t pos = 0;
> > +
> > +    for (unsigned int fr = 1; fr < frame_count; fr++) {
> > +        if (frame[fr].seen_before >= 0)
> > +            continue;
> > +        frame[fr].col_begin = av_mallocz(ctx->height *
> sizeof(*frame->col_begin));
> > +        if (!frame[fr].col_begin) {
> > +            return NULL;
> > +        }
> > +        frame[fr].col_end   = av_mallocz(ctx->height *
> sizeof(*frame->col_end));
> > +        if (!frame[fr].col_end) {
> > +            return NULL;
> > +        }
> > +        for (uint32_t r = 0; r < ctx->height; r++) {
>
> > +            av_assert0(pos < data->nb);
>
> av_assert1() in a loop like that, and make sure you build with
> --assert-level=2.
>
> Okay sure.


> > +            frame[fr].col_begin[r] = data->b[pos];
> > +            frame[fr].col_end[r] = data->e[pos];
> > +            pos++;
> > +        }
> > +    }
> > +
> > +    return src_ctx;
> > +}
> > +
> > +static void transform_frameshape_close(FLIF16TransformContext *ctx)
> > +{
> > +    transform_priv_frameshape *data = ctx->priv_data;
> > +    av_free(data->b);
> > +    av_free(data->e);
> > +}
> > +
> > +static int transform_framecombine_init(FLIF16TransformContext *ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_framecombine *data = ctx->priv_data;
> > +    ff_flif16_chancecontext_init(&data->chancectx);
> > +
> > +    return 1;
> > +}
> > +
> > +static void transform_framecombine_configure(FLIF16TransformContext
> *ctx,
> > +                                             const int setting)
> > +{
> > +    transform_priv_framecombine *data = ctx->priv_data;
> > +    data->user_max_lookback = data->nb_frames = setting;
> > +}
> > +
> > +static int transform_framecombine_read(FLIF16TransformContext *ctx,
> > +                                          FLIF16Context *dec_ctx,
> > +                                          FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_framecombine *data = ctx->priv_data;
> > +
> > +    switch (ctx->i) {
> > +        case 0:
> > +            if (src_ctx->num_planes > 4)
> > +                return 0;
> > +            ctx->i = 1;
> > +
> > +        case 1:
> > +            RAC_GET(&dec_ctx->rc, &data->chancectx, 1, data->nb_frames
> - 1,
> > +                        &data->max_lookback, FLIF16_RAC_GNZ_INT);
> > +            printf("max_lookback : %d", data->max_lookback);
> > +    }
> > +
> > +    ctx->i = 0;
> > +    return 1;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static FLIF16RangesContext *transform_framecombine_meta(FLIF16Context
> *ctx,
> > +                                                        FLIF16PixelData
> *frame,
> > +                                                        uint32_t
> frame_count,
> > +
> FLIF16TransformContext *t_ctx,
> > +
> FLIF16RangesContext *src_ctx)
> > +{
> > +    transform_priv_framecombine *data = t_ctx->priv_data;
> > +    ranges_priv_framecombine *rdata;
> > +    FLIF16RangesContext *ranges;
> > +    int lookback;
> > +    ranges = av_mallocz(sizeof(*ranges));
> > +    if (!ranges)
> > +        return NULL;
>
> > +    rdata = av_mallocz(sizeof(*rdata));
> > +    if (!rdata)
> > +        return NULL;
>
> Leaks ranges.
>
> > +    av_assert0(data->max_lookback < frame_count);
> > +    data->was_greyscale = (src_ctx->num_planes < 2);
> > +    data->was_flat = (src_ctx->num_planes < 4);
> > +
> > +    lookback = frame_count - 1;
> > +    if (lookback > data->max_lookback)
> > +        lookback = data->max_lookback;
> > +
> > +    ranges->r_no = FLIF16_RANGES_FRAMELOOKBACK;
> > +    ranges->num_planes = 5;
> > +    ranges->priv_data = rdata;
> > +
> > +    rdata->numPrevFrames = lookback;
> > +    rdata->alpha_min = (src_ctx->num_planes == 4 ?
> ff_flif16_ranges_min(src_ctx, 3) : 1);
> > +    rdata->alpha_max = (src_ctx->num_planes == 4 ?
> ff_flif16_ranges_max(src_ctx, 3) : 1);
> > +    rdata->ranges = src_ctx;
> > +
> > +    return ranges;
> > +}
> > +
> > +FLIF16Transform flif16_transform_channelcompact = {
> > +    .priv_data_size = sizeof(transform_priv_channelcompact),
> > +    .init           = &transform_channelcompact_init,
> > +    .read           = &transform_channelcompact_read,
> > +    .meta           = &transform_channelcompact_meta,
> > +    .forward        = NULL,//&transform_channelcompact_forward,
> > +    .reverse        = &transform_channelcompact_reverse,
> > +    .close          = &transform_channelcompact_close
> > +};
> > +
> > +FLIF16Transform flif16_transform_ycocg = {
> > +    .priv_data_size = sizeof(transform_priv_ycocg),
> > +    .init           = &transform_ycocg_init,
> > +    .read           = NULL,
> > +    .meta           = &transform_ycocg_meta,
> > +    .forward        = &transform_ycocg_forward,
> > +    .reverse        = &transform_ycocg_reverse,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Transform flif16_transform_permuteplanes = {
> > +    .priv_data_size = sizeof(transform_priv_permuteplanes),
> > +    .init           = &transform_permuteplanes_init,
> > +    .read           = &transform_permuteplanes_read,
> > +    .meta           = &transform_permuteplanes_meta,
> > +    .forward        = &transform_permuteplanes_forward,
> > +    .reverse        = &transform_permuteplanes_reverse,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Transform flif16_transform_bounds = {
> > +    .priv_data_size = sizeof(transform_priv_bounds),
> > +    .init           = &transform_bounds_init,
> > +    .read           = &transform_bounds_read,
> > +    .meta           = &transform_bounds_meta,
> > +    .forward        = NULL,
> > +    .reverse        = NULL,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Transform flif16_transform_palette = {
> > +    .priv_data_size = sizeof(transform_priv_palette),
> > +    .init           = &transform_palette_init,
> > +    .read           = &transform_palette_read,
> > +    .meta           = &transform_palette_meta,
> > +    //.forward
> > +    .reverse        = &transform_palette_reverse,
> > +    .close          = &transform_palette_close
> > +};
> > +
> > +FLIF16Transform flif16_transform_palettealpha = {
> > +    .priv_data_size = sizeof(transform_priv_palettealpha),
> > +    .init           = &transform_palettealpha_init,
> > +    .read           = &transform_palettealpha_read,
> > +    .meta           = &transform_palettealpha_meta,
> > +    .configure      = &transform_palettealpha_configure,
> > +    //.forward
> > +    .reverse        = &transform_palettealpha_reverse,
> > +    .close          = &transform_palettealpha_close
> > +};
> > +
> > +FLIF16Transform flif16_transform_colorbuckets = {
> > +    .priv_data_size = sizeof(transform_priv_colorbuckets),
> > +    .init           = &transform_colorbuckets_init,
> > +    .read           = &transform_colorbuckets_read,
> > +    .meta           = &transform_colorbuckets_meta,
> > +    .forward        = NULL,
> > +    .reverse        = NULL,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Transform flif16_transform_framedup = {
> > +    .priv_data_size = sizeof(transform_priv_framedup),
> > +    .init           = &transform_framedup_init,
> > +    .read           = &transform_framedup_read,
> > +    .meta           = &transform_framedup_meta,
> > +    .configure      = &transform_framedup_configure,
> > +    .forward        = NULL,
> > +    .reverse        = NULL,
> > +    .close          = &transform_framedup_close
> > +};
> > +
> > +FLIF16Transform flif16_transform_frameshape = {
> > +    .priv_data_size = sizeof(transform_priv_frameshape),
> > +    .init           = &transform_frameshape_init,
> > +    .read           = &transform_frameshape_read,
> > +    .meta           = &transform_frameshape_meta,
> > +    .configure      = &transform_frameshape_configure,
> > +    .forward        = NULL,
> > +    .reverse        = NULL,
> > +    .close          = &transform_frameshape_close
> > +};
> > +
> > +FLIF16Transform flif16_transform_framecombine = {
> > +    .priv_data_size = sizeof(transform_priv_framecombine),
> > +    .init           = &transform_framecombine_init,
> > +    .read           = &transform_framecombine_read,
> > +    .meta           = &transform_framecombine_meta,
> > +    .configure      = &transform_framecombine_configure,
> > +    .forward        = NULL,
> > +    .reverse        = NULL,
> > +    .close          = NULL
> > +};
> > +
> > +FLIF16Transform *flif16_transforms[13] = {
> > +    &flif16_transform_channelcompact,
> > +    &flif16_transform_ycocg,
> > +    NULL, // RESERVED,
> > +    &flif16_transform_permuteplanes,
> > +    &flif16_transform_bounds,
> > +    &flif16_transform_palettealpha,
> > +    &flif16_transform_palette,
> > +    &flif16_transform_colorbuckets,
> > +    NULL, // RESERVED,
> > +    NULL, // RESERVED,
> > +    &flif16_transform_framedup,
> > +    &flif16_transform_frameshape,
> > +    &flif16_transform_framecombine
> > +};
> > +
> > +FLIF16TransformContext *ff_flif16_transform_init(int t_no,
> FLIF16RangesContext *r_ctx)
> > +{
> > +    FLIF16Transform *trans;
> > +    FLIF16TransformContext *ctx;
> > +    void *k = NULL;
> > +
>
> > +    trans = flif16_transforms[t_no];
>
> Are you sure t_no was validated?
>
Will validate t_no.

>
> > +    if (!trans)
> > +        return NULL;
> > +    ctx = av_mallocz(sizeof(*ctx));
> > +    if (!ctx)
> > +        return NULL;
> > +    if (trans->priv_data_size) {
>
> > +        k = av_mallocz(trans->priv_data_size);
> > +        if (!k)
> > +            return NULL;
>
> Leaks ctx.
>
> > +    }
> > +    ctx->t_no      = t_no;
> > +    ctx->priv_data = k;
> > +    ctx->segment   = 0;
> > +    ctx->i         = 0;
> > +
> > +    if (trans->init)
> > +        if (!trans->init(ctx, r_ctx))
> > +            return NULL;
> > +
> > +    return ctx;
> > +}
> > +
> > +int ff_flif16_transform_read(FLIF16TransformContext *ctx,
> > +                             FLIF16Context *dec_ctx,
> > +                             FLIF16RangesContext *r_ctx)
> > +{
> > +    FLIF16Transform *trans = flif16_transforms[ctx->t_no];
> > +    if (trans->read)
> > +        return trans->read(ctx, dec_ctx, r_ctx);
> > +    else
> > +        return 1;
> > +}
> > +
> > +FLIF16RangesContext *ff_flif16_transform_meta(FLIF16Context *ctx,
> > +                                              FLIF16PixelData *frames,
> > +                                              uint32_t frames_count,
> > +                                              FLIF16TransformContext
> *t_ctx,
> > +                                              FLIF16RangesContext
> *r_ctx)
> > +{
> > +    FLIF16Transform *trans;
> > +    trans = flif16_transforms[t_ctx->t_no];
> > +    if (trans->meta)
> > +        return trans->meta(ctx, frames, frames_count, t_ctx, r_ctx);
> > +    else
> > +        return r_ctx;
> > +}
> > +
> > +void ff_flif16_transform_configure(FLIF16TransformContext *ctx, const
> int setting)
> > +{
> > +    FLIF16Transform *trans = flif16_transforms[ctx->t_no];
> > +    if (trans->configure)
> > +        trans->configure(ctx, setting);
> > +}
> > +
> > +int ff_flif16_transform_reverse(FLIF16Context *ctx,
> > +                                FLIF16TransformContext *t_ctx,
> > +                                FLIF16PixelData *frame,
> > +                                uint8_t stride_row, uint8_t stride_col)
> > +{
> > +    FLIF16Transform *trans = flif16_transforms[t_ctx->t_no];
> > +    if (trans->reverse != NULL)
> > +        return trans->reverse(ctx, t_ctx, frame, stride_row,
> stride_col);
> > +    else
> > +        return 1;
> > +}
> > +
> > +void ff_flif16_transforms_close(FLIF16TransformContext *ctx)
> > +{
> > +    FLIF16Transform *trans = flif16_transforms[ctx->t_no];
> > +    if (trans->close)
> > +        trans->close(ctx);
> > +    if (trans->priv_data_size)
> > +        av_free(ctx->priv_data);
> > +    av_freep(&ctx);
> > +}
> > diff --git a/libavcodec/flif16_transform.h
> b/libavcodec/flif16_transform.h
> > new file mode 100644
> > index 0000000000..c4bba24fc5
> > --- /dev/null
> > +++ b/libavcodec/flif16_transform.h
> > @@ -0,0 +1,123 @@
> > +/*
> > + * Transforms for FLIF16.
> > + * Copyright (c) 2020 Kartik K. Khullar <kartikkhullar840 at gmail.com>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * Transforms for FLIF16.
> > + */
> > +
> > +#ifndef FLIF16_TRANSFORM_H
> > +#define FLIF16_TRANSFORM_H
> > +
> > +#include "avcodec.h"
> > +#include "libavutil/common.h"
> > +#include "flif16.h"
> > +
> > +typedef enum FLIF16RangesTypes{
> > +    FLIF16_RANGES_CHANNELCOMPACT,
> > +    FLIF16_RANGES_YCOCG,
> > +    FLIF16_RANGES_PERMUTEPLANES,
> > +    FLIF16_RANGES_PERMUTEPLANESSUBTRACT,
> > +    FLIF16_RANGES_BOUNDS,
> > +    FLIF16_RANGES_STATIC,
> > +    FLIF16_RANGES_PALETTEALPHA,
> > +    FLIF16_RANGES_PALETTE,
> > +    FLIF16_RANGES_COLORBUCKETS,
> > +    FLIF16_RANGES_FRAMELOOKBACK
> > +} FLIF16RangesTypes;
> > +
> > +typedef enum FLIF16TransformsTypes {
> > +    FLIF16_TRANSFORM_CHANNELCOMPACT,
> > +    FLIF16_TRANSFORM_YCOCG,
> > +    FLIF16_TRANSFORM_RESERVED1,
> > +    FLIF16_TRANSFORM_PERMUTEPLANES,
> > +    FLIF16_TRANSFORM_BOUNDS,
> > +    FLIF16_TRANSFORM_PALETTEALPHA,
> > +    FLIF16_TRANSFORM_PALETTE,
> > +    FLIF16_TRANSFORM_COLORBUCKETS,
> > +    FLIF16_TRANSFORM_RESERVED2,
> > +    FLIF16_TRANSFORM_RESERVED3,
> > +    FLIF16_TRANSFORM_DUPLICATEFRAME,
> > +    FLIF16_TRANSFORM_FRAMESHAPE,
> > +    FLIF16_TRANSFORM_FRAMELOOKBACK,
> > +} FLIF16TransformsTypes;
> > +
> > +extern FLIF16Ranges *flif16_ranges[14];
> > +extern FLIF16Transform *flif16_transforms[13];
> > +
> > +FLIF16RangesContext *ff_flif16_ranges_static_init(unsigned int channels,
> > +                                                  unsigned int bpc);
> > +
> > +void ff_flif16_ranges_close(FLIF16RangesContext* r_ctx);
> > +
> > +static inline FLIF16ColorVal ff_flif16_ranges_min(FLIF16RangesContext
> *r_ctx, int p)
> > +{
> > +    FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no];
> > +    if(ranges->min)
> > +        return ranges->min(r_ctx, p);
> > +    else
> > +        return 0;
> > +}
> > +
> > +static inline FLIF16ColorVal ff_flif16_ranges_max(FLIF16RangesContext
> *r_ctx, int p)
> > +{
> > +    FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no];
> > +    if(ranges->max)
> > +        return ranges->max(r_ctx, p);
> > +    else
> > +        return 0;
> > +}
> > +
> > +static inline void ff_flif16_ranges_minmax(FLIF16RangesContext *r_ctx,
> int p,
> > +                                           FLIF16ColorVal *prev_planes,
> > +                                           FLIF16ColorVal *minv,
> FLIF16ColorVal *maxv)
> > +{
> > +    flif16_ranges[r_ctx->r_no]->minmax(r_ctx, p, prev_planes, minv,
> maxv);
> > +}
> > +
> > +static inline void ff_flif16_ranges_snap(FLIF16RangesContext *r_ctx,
> int p,
> > +                                         FLIF16ColorVal *prev_planes,
> FLIF16ColorVal *minv,
> > +                                         FLIF16ColorVal *maxv,
> FLIF16ColorVal *v)
> > +{
> > +    flif16_ranges[r_ctx->r_no]->snap(r_ctx, p, prev_planes, minv, maxv,
> v);
> > +}
> > +
> > +FLIF16TransformContext *ff_flif16_transform_init(int,
> FLIF16RangesContext *);
> > +
> > +void ff_flif16_transform_configure(FLIF16TransformContext *, const int);
> > +
> > +
> > +// Maybe put FLIF16Context at first in list
> > +int ff_flif16_transform_read(FLIF16TransformContext *, FLIF16Context *,
> > +                             FLIF16RangesContext *);
> > +
> > +FLIF16RangesContext* ff_flif16_transform_meta(FLIF16Context *,
> > +                                              FLIF16PixelData *,
> > +                                              uint32_t,
> > +                                              FLIF16TransformContext *,
> > +                                              FLIF16RangesContext *);
> > +
> > +int ff_flif16_transform_reverse(FLIF16Context *,
> FLIF16TransformContext*, FLIF16PixelData*,
> > +                                uint8_t, uint8_t);
> > +
> > +void ff_flif16_transforms_close(FLIF16TransformContext *);
> > +
> > +#endif /* FLIF16_TRANSFORM_H */
> > diff --git a/libavcodec/flif16dec.c b/libavcodec/flif16dec.c
> > new file mode 100644
> > index 0000000000..18216f5991
> > --- /dev/null
> > +++ b/libavcodec/flif16dec.c
> > @@ -0,0 +1,1146 @@
> > +/*
> > + * FLIF16 Decoder
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * FLIF16 Decoder
> > +*/
> > +
> > +#include <stdio.h> // Remove
> > +
> > +#include "flif16.h"
> > +#include "flif16_rangecoder.h"
> > +#include "flif16_transform.h"
> > +
> > +#include "avcodec.h"
> > +#include "libavutil/common.h"
> > +#include "bytestream.h"
> > +#include "avcodec.h"
> > +#include "internal.h"
> > +
> > +/*
> > + * Due to the nature of the format, the decoder has to take the
> entirety of the
> > + * data before it can generate any frames. The decoder has to return
> > + * AVERROR(EAGAIN) as long as the bitstream is incomplete.
> > + */
> > +
> > +
> > +// TODO make variable size UNI_INT readers
> > +typedef struct FLIF16DecoderContext {
> > +
> > +    /* Inheritance from FLIF16Context */
> > +
> > +    GetByteContext gb;
> > +    FLIF16MANIACContext maniac_ctx;
> > +    FLIF16RangeCoder rc;
> > +
> > +    // Dimensions and other things.
> > +    uint32_t width;
> > +    uint32_t height;
> > +    uint32_t num_frames;
> > +    uint32_t meta;       ///< Size of a meta chunk
> > +
> > +    // Primary Header
> > +    uint8_t  ia;         ///< Is image interlaced or/and animated or not
> > +    uint32_t bpc;        ///< 2 ^ Bytes per channel
> > +    uint8_t  num_planes; ///< Number of planes
> > +
> > +    // change to uint8_t
> > +    uint32_t loops;       ///< Number of times animation loops
> > +    // change to uint32_t
> > +    uint32_t *framedelay; ///< Frame delay for each frame
> > +
> > +    uint8_t plane_mode[MAX_PLANES];
> > +
> > +    // Transform flags
> > +    uint8_t framedup;
> > +    uint8_t frameshape;
> > +    uint8_t framelookback;
> > +    /* End Inheritance from FLIF16Context */
> > +
> > +    FLIF16PixelData  *frames;
> > +    uint32_t out_frames_count;
> > +    AVFrame *out_frame;
> > +    int64_t pts;
> > +
> > +    uint8_t buf[FLIF16_RAC_MAX_RANGE_BYTES]; ///< Storage for initial
> RAC buffer
> > +    uint8_t buf_count;    ///< Count for initial RAC buffer
> > +    int state;            ///< The section of the file the parser is in
> currently.
> > +    unsigned int segment; ///< The "segment" the code is supposed to
> jump to
> > +    unsigned int segment2;///< The "segment" the code is supposed to
> jump to
> > +    int i;                ///< A generic iterator used to save states
> between for loops.
> > +    int i2;
> > +    int i3;
> > +
> > +    // Secondary Header
> > +    uint8_t alphazero;    ///< Alphazero Flag
> > +    uint8_t custombc;     ///< Custom Bitchance Flag
> > +    uint8_t customalpha;  ///< Custom alphadiv & cutoff flag
> > +
> > +    uint8_t cut;          ///< Chancetable custom cutoff
> > +    uint32_t alpha;       ///< Chancetable custom alphadivisor
> > +    uint8_t ipp;          ///< Invisible pixel predictor
> > +
> > +    // Transforms
> > +    // Size dynamically maybe
> > +    FLIF16TransformContext *transforms[13];
> > +    uint8_t transform_top;
> > +    FLIF16RangesContext *range; ///< The minimum and maximum values a
> > +                                ///  channel's pixels can take. Changes
> > +                                ///  depending on transformations
> applied
> > +    FLIF16RangesContext *prev_range;
> > +
> > +    // MANIAC Trees
> > +    int32_t (*prop_ranges)[2]; ///< Property Ranges
> > +    uint32_t prop_ranges_size;
> > +
> > +    // Pixeldata
> > +    uint8_t curr_plane;        ///< State variable. Current plane under
> processing
> > +    FLIF16ColorVal *grays;
> > +    FLIF16ColorVal *properties;
> > +    FLIF16ColorVal guess;      ///< State variable. Stores guess
> > +    FLIF16ColorVal min, max;
> > +    uint32_t c;                ///< State variable for current column
> > +
> > +    // Interlaced Pixeldata
> > +    int *zoomlevels;
> > +    int zooms;
> > +    int rough_zl;
> > +    int quality;
> > +    int scale;
> > +    int *predictors;
> > +    int breakpoints;
> > +} FLIF16DecoderContext;
> > +
> > +// Cast values to FLIF16Context for some functions.
> > +#define CTX_CAST(x) ((FLIF16Context *) (x))
> > +
> > +// TODO Remove PIXEL and PIXELY. Concerned with interlaced decoding
> > +#define PIXEL(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame, p, z, r,
> c)
> > +#define PIXELY(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame,
> FLIF16_PLANE_Y, z, r, c)
> > +
> > +#define PIXEL_SET(ctx, fr, p, r, c, val)
> ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val)
> > +#define PIXEL_GET(ctx, fr, p, r, c) ff_flif16_pixel_get(CTX_CAST(ctx),
> &(ctx)->frames[fr], p, r, c)
> > +#define PIXEL_SETZ(ctx, fr, p, z, r, c, val)
> ff_flif16_pixel_setz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c, val)
> > +#define PIXEL_GETZ(ctx, fr, p, z, r, c)
> ff_flif16_pixel_getz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c)
> > +#define PIXEL_GETFAST(ctx, fr, p, r, c)
> ff_flif16_pixel_get(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c)
> > +#define PIXEL_SETFAST(ctx, fr, p, r, c, val)
> ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val)
> > +
> > +// If frame_dup exists, figure out what the previous frame actually is
> > +#define PREV_FRAME(frames, f_no) (((frames)[(f_no) - 1].seen_before >=
> 0) ? &(frames)[(frames)[(f_no) - 1].seen_before] : &(frames)[(f_no) - 1])
> > +#define PREV_FRAMENUM(frames, f_no) (((frames)[(f_no) - 1].seen_before
> >= 0) ? (frames)[(f_no) - 1].seen_before : (f_no) - 1)
> > +
> > +// Static property values
> > +static const int properties_ni_rgb_size[] = {7, 8, 9, 7, 7};
> > +static const int properties_ni_rgba_size[] = {8, 9, 10, 7, 7};
> > +static const int properties_rgb_size[] = {8, 10, 9, 8, 8};
> > +static const int properties_rgba_size[] = {9, 11, 10, 8, 8};
> > +
> > +// From reference decoder:
> > +//
> > +// The order in which the planes are encoded.
> > +// lookback (Lookback) (animations-only, value refers to a previous
> frame) has
> > +// to be first, because all other planes are not encoded if lookback !=
> 0
> > +// Alpha has to be next, because for fully transparent A=0 pixels, the
> other
> > +// planes are not encoded
> > +// Y (luma) is next (the first channel for still opaque images),
> because it is
> > +// perceptually most important
> > +// Co and Cg are in that order because Co is perceptually slightly more
> > +// important than Cg [citation needed]
> > +static const int plane_ordering[] = {4,3,0,1,2}; // lookback
> (lookback), A, Y, Co, Cg
> > +
> > +enum FLIF16States {
> > +    FLIF16_HEADER = 0,
> > +    FLIF16_SECONDHEADER,
> > +    FLIF16_TRANSFORM,
> > +    FLIF16_ROUGH_PIXELDATA,
> > +    FLIF16_MANIAC,
> > +    FLIF16_PIXELDATA,
> > +    FLIF16_OUTPUT,
> > +    FLIF16_CHECKSUM,
> > +    FLIF16_EOS
> > +};
> > +
> > +static int flif16_read_header(AVCodecContext *avctx)
> > +{
> > +    uint8_t temp, count = 4;
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    // TODO Make do without this array
> > +    uint32_t *vlist[] = { &s->width, &s->height, &s->num_frames };
> > +
> > +    s->cut   = CHANCETABLE_DEFAULT_CUT;
> > +    s->alpha = CHANCETABLE_DEFAULT_ALPHA;
> > +
> > +    // Minimum size has been empirically found to be 8 bytes.
> > +    if (bytestream2_size(&s->gb) < 8) {
> > +        av_log(avctx, AV_LOG_ERROR, "buf size too small (%d)\n",
> > +               bytestream2_size(&s->gb));
>
> > +        return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +    }
> > +
>
> > +    if (bytestream2_get_le32(&s->gb) != (*((uint32_t *)
> flif16_header))) {
>
> You can't do that. Was it tested on big endian?
>
> > +        av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
>
> > +        return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +    }
> > +
> > +    s->state = FLIF16_HEADER;
> > +
> > +    temp = bytestream2_get_byte(&s->gb);
> > +    s->ia         = temp >> 4;
> > +    s->num_planes = (0x0F & temp);
> > +
> > +    if (!(s->ia % 2)) {
> > +        av_log(avctx, AV_LOG_ERROR, "interlaced images not
> supported\n");
> > +        return AVERROR_PATCHWELCOME;
> > +    }
> > +
> > +    s->bpc = bytestream2_get_byte(&s->gb);
> > +
> > +
> > +
> > +    // Handle dimensions and frames
> > +    for(int i = 0; i < 2 + ((s->ia > 4) ? 1 : 0); ++i) {
> > +        while ((temp = bytestream2_get_byte(&s->gb)) > 127) {
> > +            VARINT_APPEND(*vlist[i], temp);
> > +            if (!(count--)) {
> > +                av_log(avctx, AV_LOG_ERROR, "image dimensions too
> big\n");
>
> > +                return AVERROR(ENOMEM);
>
> AVERROR_INVALIDDATA
>
> > +            }
> > +        }
> > +        VARINT_APPEND(*vlist[i], temp);
> > +        count = 4;
> > +    }
> > +    s->width++;
> > +    s->height++;
> > +    (s->ia > 4) ? (s->num_frames += 2) : (s->num_frames = 1);
> > +
> > +    if (s->num_frames > 1) {
> > +        s->framedelay = av_mallocz(sizeof(*(s->framedelay)) *
> s->num_frames);
> > +        if (!s->framedelay)
> > +            return AVERROR(ENOMEM);
> > +    }
> > +
> > +    s->frames = ff_flif16_frames_init(CTX_CAST(s));
> > +
> > +    if (!s->frames) {
> > +        av_log(avctx, AV_LOG_ERROR, "Could not allocate frames\n");
> > +        return AVERROR(ENOMEM);
> > +    }
> > +
> > +    // Handle Metadata Chunk. Currently it discards all data.
> > +
> > +    while ((temp = bytestream2_get_byte(&s->gb)) != 0) {
> > +        bytestream2_seek(&s->gb, 3, SEEK_CUR);
> > +        // Read varint
> > +        while ((temp = bytestream2_get_byte(&s->gb)) > 127) {
> > +            VARINT_APPEND(s->meta, temp);
> > +            if (!(count--)) {
> > +                av_log(avctx, AV_LOG_ERROR, "metadata chunk too big
> \n");
> > +                return AVERROR(ENOMEM);
> > +            }
> > +        }
> > +        VARINT_APPEND(s->meta, temp);
> > +        bytestream2_seek(&s->gb, s->meta, SEEK_CUR);
> > +        count = 4;
> > +    }
> > +
> > +    s->state = FLIF16_SECONDHEADER;
> > +    return 0;
> > +}
> > +
> > +static int flif16_read_second_header(AVCodecContext *avctx)
> > +{
> > +    uint32_t temp;
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +
> > +    switch (s->segment) {
> > +        case 0:
> > +            s->buf_count += bytestream2_get_buffer(&s->gb, s->buf +
> s->buf_count,
> > +
>  FFMIN(bytestream2_get_bytes_left(&s->gb),
> > +
>  (FLIF16_RAC_MAX_RANGE_BYTES - s->buf_count)));
> > +
> > +            if (s->buf_count < FLIF16_RAC_MAX_RANGE_BYTES)
> > +                return AVERROR(EAGAIN);
> > +
> > +            ff_flif16_rac_init(&s->rc, &s->gb, s->buf, s->buf_count);
> > +            ++s->segment;
> > +
> > +        case 1:
> > +            // In original source this is handled in what seems to be a
> very
> > +            // bogus manner. It takes all the bpps of all planes and
> then
> > +            // takes the max, negating any benefit of actually keeping
> these
> > +            // multiple values.
> > +            if (s->bpc == '0') {
> > +                s->bpc = 0;
> > +                for (; s->i < s->num_planes; ++s->i) {
> > +                    RAC_GET(&s->rc, NULL, 1, 15, &temp,
> FLIF16_RAC_UNI_INT8);
> > +                    s->bpc = FFMAX(s->bpc, (1 << temp) - 1);
> > +                }
> > +            } else
> > +                s->bpc = (s->bpc == '1') ? 255 : 65535;
> > +            s->i = 0;
> > +            s->range = ff_flif16_ranges_static_init(s->num_planes,
> s->bpc);
> > +            // MSG("planes : %d & bpc : %d\n", s->num_planes, s->bpc);
> > +            ++s->segment;
> > +
> > +        case 2:
> > +            if (s->num_planes > 3) {
> > +                RAC_GET(&s->rc, NULL, 0, 1, &s->alphazero,
> > +                        FLIF16_RAC_UNI_INT8);
> > +            }
> > +            ++s->segment;
> > +
> > +        case 3:
> > +            if (s->num_frames > 1) {
> > +                RAC_GET(&s->rc, NULL, 0, 100, &s->loops,
> > +                        FLIF16_RAC_UNI_INT8);
> > +            }
> > +            ++s->segment;
> > +
> > +        case 4:
> > +            if (s->num_frames > 1) {
> > +                for (; (s->i) < (s->num_frames); ++(s->i)) {
> > +                    RAC_GET(&s->rc, NULL, 0, 60000,
> &(s->framedelay[s->i]),
> > +                            FLIF16_RAC_UNI_INT16);
> > +                }
> > +                s->i = 0;
> > +            }
> > +            ++s->segment;
> > +
> > +        case 5:
> > +            // Has custom alpha flag
> > +            RAC_GET(&s->rc, NULL, 0, 1, &s->customalpha,
> FLIF16_RAC_UNI_INT8);
> > +            ++s->segment;
> > +
> > +        case 6:
> > +            if (s->customalpha) {
> > +                RAC_GET(&s->rc, NULL, 1, 128, &s->cut,
> FLIF16_RAC_UNI_INT8);
> > +            }
> > +            ++s->segment;
> > +
> > +        case 7:
> > +            if (s->customalpha) {
> > +                RAC_GET(&s->rc, NULL, 2, 128, &s->alpha,
> FLIF16_RAC_UNI_INT8);
> > +                s->alpha = 0xFFFFFFFF / s->alpha;
> > +            }
> > +            ++s->segment;
> > +
> > +        case 8:
> > +            if (s->customalpha)
> > +                RAC_GET(&s->rc, NULL, 0, 1, &s->custombc,
> FLIF16_RAC_UNI_INT8);
> > +            if (s->custombc) {
> > +                av_log(avctx, AV_LOG_ERROR, "custom bitchances not
> implemented\n");
> > +                return AVERROR_PATCHWELCOME;
> > +            }
> > +            goto end;
> > +    }
> > +
> > +    end:
> > +    s->state   = FLIF16_TRANSFORM;
> > +    s->segment = 0;
> > +
> > +    #ifdef MULTISCALE_CHANCES_ENABLED
> > +    s->rc->mct = ff_flif16_multiscale_chancetable_init();
> > +    ff_flif16_build_log4k_table(&s->rc->log4k);
> > +    #endif
> > +
> > +    ff_flif16_chancetable_init(&s->rc.ct, s->alpha, s->cut);
> > +
> > +    return 0;
> > +
> > +    need_more_data:
> > +    // MSG("Need more data\n");
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +
> > +static int flif16_read_transforms(AVCodecContext *avctx)
> > +{
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    FLIF16RangesContext *prev_range;
> > +    uint8_t const_plane_value[MAX_PLANES];
> > +    uint8_t temp;
> > +    int unique_frames;
> > +
> > +    loop:
> > +    switch (s->segment) {
> > +        case 0:
> > +            RAC_GET(&s->rc, NULL, 0, 0, &temp, FLIF16_RAC_BIT);
> > +            if(!temp)
> > +                goto end;
> > +            ++s->segment;
> > +
> > +        case 1:
> > +            RAC_GET(&s->rc, NULL, 0, 13, &temp, FLIF16_RAC_UNI_INT8);
> > +            if (!flif16_transforms[temp]) {
> > +                av_log(avctx, AV_LOG_ERROR, "transform %u not
> implemented\n", temp);
> > +                return AVERROR_PATCHWELCOME;
> > +            }
> > +
> > +            s->transforms[s->transform_top] =
> ff_flif16_transform_init(temp, s->range);
> > +            if (!s->transforms[s->transform_top]) {
>
> > +                av_log(avctx, AV_LOG_ERROR, "failed to initialise
> transform %u\n", temp);
> > +                return AVERROR(ENOMEM);
>
> If the reason is ENOMEM, no need for an extra message.
>
> > +            }
> > +
> > +            switch (temp) {
> > +                case FLIF16_TRANSFORM_PALETTEALPHA:
> > +                    s->plane_mode[FLIF16_PLANE_ALPHA] =
> FLIF16_PLANEMODE_CONSTANT;
> > +
> ff_flif16_transform_configure(s->transforms[s->transform_top],
> > +                                                  s->alphazero);
> > +
> > +                case FLIF16_TRANSFORM_CHANNELCOMPACT:
> > +                    if (s->num_planes > 3 &&
> !s->plane_mode[FLIF16_PLANE_ALPHA])
> > +                        s->plane_mode[FLIF16_PLANE_ALPHA] =
> FLIF16_PLANEMODE_FILL;
> > +
> > +                case FLIF16_TRANSFORM_YCOCG:
> > +                case FLIF16_TRANSFORM_PALETTE:
> > +                    s->plane_mode[FLIF16_PLANE_Y] =
> FLIF16_PLANEMODE_NORMAL;
> > +                    s->plane_mode[FLIF16_PLANE_CO] =
> FLIF16_PLANEMODE_NORMAL;
> > +                    s->plane_mode[FLIF16_PLANE_CG] =
> FLIF16_PLANEMODE_NORMAL;
> > +                    break;
> > +
> > +                case FLIF16_TRANSFORM_DUPLICATEFRAME:
> > +                    s->framedup = 1;
> > +                    if(s->num_frames < 2)
> > +                         return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +
> ff_flif16_transform_configure(s->transforms[s->transform_top],
> > +                                                  s->num_frames);
> > +                    break;
> > +
> > +                case FLIF16_TRANSFORM_FRAMESHAPE:
> > +                    s->frameshape = 1;
>
> > +                    if (s->num_frames < 2)
> > +                        return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +                    unique_frames = s->num_frames - 1;
> > +                    for (unsigned int i = 0; i < s->num_frames; i++) {
> > +                        if(s->frames[i].seen_before >= 0)
> > +                            unique_frames--;
> > +                    }
> > +                    if (unique_frames < 1)
> > +                        return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +
> ff_flif16_transform_configure(s->transforms[s->transform_top],
> > +                                                  (unique_frames) *
> s->height);
> > +
> ff_flif16_transform_configure(s->transforms[s->transform_top],
> > +                                                  s->width);
> > +                    break;
> > +
> > +                case FLIF16_TRANSFORM_FRAMELOOKBACK:
> > +                    if(s->num_frames < 2)
> > +                        return AVERROR(EINVAL);
>
> AVERROR_INVALIDDATA
>
> > +                    s->framelookback = 1;
> > +
> ff_flif16_transform_configure(s->transforms[s->transform_top],
> > +                                                  s->num_frames);
> > +                    break;
> > +            }
> > +            ++s->segment;
> > +
> > +        case 2:
> > +            if(ff_flif16_transform_read(s->transforms[s->transform_top],
> > +                                        CTX_CAST(s), s->range) <= 0)
> > +                goto need_more_data;
> > +            prev_range = s->range;
> > +            s->range = ff_flif16_transform_meta(CTX_CAST(s), s->frames,
> s->num_frames,
> > +
> s->transforms[s->transform_top],
> > +                                                prev_range);
> > +            if(!s->range)
> > +                return AVERROR(ENOMEM);
> > +            s->segment = 0;
> > +            ++s->transform_top;
> > +            goto loop;
> > +
> > +        case 3:
> > +            end:
> > +            s->segment = 3;
> > +            // Read invisible pixel predictor
> > +            if (   s->alphazero && s->num_planes > 3
> > +                && ff_flif16_ranges_min(s->range, 3) <= 0
> > +                && !(s->ia % 2))
> > +                RAC_GET(&s->rc, NULL, 0, 2, &s->ipp,
> FLIF16_RAC_UNI_INT8)
> > +    }
> > +
> > +    for (int i = 0; i < FFMIN(s->num_planes, 4); ++i) {
> > +        if (s->plane_mode[i] != FLIF16_PLANEMODE_NORMAL) {
> > +            if (ff_flif16_ranges_min(s->range, i) >=
> ff_flif16_ranges_max(s->range, i))
> > +                const_plane_value[i] = ff_flif16_ranges_min(s->range,
> i);
> > +            else
> > +                s->plane_mode[i] = FLIF16_PLANEMODE_NORMAL;
> > +        }
> > +    }
> > +
> > +    if (ff_flif16_planes_init(CTX_CAST(s), s->frames, s->plane_mode,
> > +                              const_plane_value, s->framelookback) < 0)
> {
>
> > +        av_log(avctx, AV_LOG_ERROR, "could not allocate planes\n");
> > +        return AVERROR(ENOMEM);
>
> Redundant error message.
>
> > +    }
> > +
> > +    // if (!(s->ia % 2))
> > +    //    s->state = FLIF16_ROUGH_PIXELDATA;
> > +    // else
> > +    //    s->state = FLIF16_MANIAC;
> > +    s->state = FLIF16_MANIAC;
> > +    s->segment = 0;
> > +    return 0;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +static int flif16_read_maniac_forest(AVCodecContext *avctx)
> > +{
> > +    int ret;
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    if (!s->maniac_ctx.forest) {
> > +        s->maniac_ctx.forest = av_mallocz((s->num_planes) *
> sizeof(*(s->maniac_ctx.forest)));
> > +        if (!s->maniac_ctx.forest) {
> > +            return AVERROR(ENOMEM);
> > +        }
> > +        s->segment = s->i = 0; // Remove later
> > +    }
> > +    switch (s->segment) {
> > +        case 0:
>
> > +            loop:
>
> Proper loop please.
>
> > +            if (s->i >= s->num_planes)
> > +                goto end;
> > +
> > +            if (!(s->ia % 2))
> > +                s->prop_ranges =
> ff_flif16_maniac_prop_ranges_init(&s->prop_ranges_size, s->range,
> > +
>  s->i, s->num_planes);
> > +            else
> > +                s->prop_ranges =
> ff_flif16_maniac_ni_prop_ranges_init(&s->prop_ranges_size, s->range,
> > +
> s->i, s->num_planes);
> > +
> > +            if(!s->prop_ranges)
> > +                return AVERROR(ENOMEM);
> > +            ++s->segment;
> > +
> > +        case 1:
> > +            if (ff_flif16_ranges_min(s->range, s->i) >=
> ff_flif16_ranges_max(s->range, s->i)) {
> > +                ++s->i;
> > +                --s->segment;
> > +                goto loop;
> > +            }
> > +            ret = ff_flif16_read_maniac_tree(&s->rc, &s->maniac_ctx,
> s->prop_ranges,
> > +                                             s->prop_ranges_size, s->i);
> > +            if (ret) {
> > +                goto error;
> > +            }
> > +            av_freep(&s->prop_ranges);
> > +            --s->segment;
> > +            ++s->i;
> > +            goto loop;
> > +    }
> > +
> > +    end:
> > +    s->state = FLIF16_PIXELDATA;
> > +    s->segment = 0;
> > +    return 0;
> > +
> > +    error:
> > +    return ret;
> > +}
> > +
> > +/*
> ============================================================================
> > + * Non interlaced plane decoding
> > + *
> ============================================================================
> > + */
> > +
> > +
>
> > +static FLIF16ColorVal flif16_ni_predict_calcprops(FLIF16DecoderContext
> *s,
> > +                                                  FLIF16PixelData
> *pixel,
> > +                                                  FLIF16ColorVal
> *properties,
> > +                                                  FLIF16RangesContext
> *ranges_ctx,
> > +                                                  uint8_t p, uint32_t r,
> > +                                                  uint32_t c,
> FLIF16ColorVal *min,
> > +                                                  FLIF16ColorVal *max,
> > +                                                  const FLIF16ColorVal
> fallback,
> > +                                                  uint8_t nobordercases)
>
> Functions with that many parameters would often do better with fewer
> structures.
>
> For example, all the calls below are with "s->c, s->min, s->max", they
> need not be parameters.
>
>
> > +{
> > +    FLIF16ColorVal guess, left, top, topleft, gradientTL;
> > +    int width = s->width;
> > +    int which = 0;
> > +    int index = 0;
> > +    if (p < 3) {
> > +        for (int pp = 0; pp < p; pp++) {
> > +            properties[index++] = ff_flif16_pixel_get(CTX_CAST(s),
> pixel, pp, r, c); //image(pp,r,c);
> > +        }
> > +        if (ranges_ctx->num_planes > 3) {
> > +            properties[index++] = ff_flif16_pixel_get(CTX_CAST(s),
> pixel, 3, r, c); //image(3,r,c);
> > +        }
> > +    }
> > +    left = (nobordercases || c > 0 ? ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r, c-1) :
> > +           (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c)
> : fallback));
> > +    top = (nobordercases || r > 0 ? ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r-1, c) : left);
> > +    topleft = (nobordercases || (r>0 && c>0) ?
> > +              ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c-1) : (r
> > 0 ? top : left));
> > +    gradientTL = left + top - topleft;
> > +    guess = MEDIAN3(gradientTL, left, top);
> > +    ff_flif16_ranges_snap(ranges_ctx, p, properties, min, max, &guess);
> > +
> > +    if (guess == gradientTL)
> > +        which = 0;
> > +    else if (guess == left)
> > +        which = 1;
> > +    else if (guess == top)
> > +        which = 2;
> > +
> > +    properties[index++] = guess;
> > +    properties[index++] = which;
> > +
> > +    if (nobordercases || (c > 0 && r > 0)) {
> > +        properties[index++] = left - topleft;
> > +        properties[index++] = topleft - top;
> > +    } else {
> > +        properties[index++] = 0;
> > +        properties[index++] = 0;
> > +    }
> > +
> > +    if (nobordercases || (c+1 < width && r > 0)) {
> > +        properties[index++] = top - ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r-1, c+1); // top - topright
> > +    } else {
> > +        properties[index++] = 0;
> > +    }
> > +
> > +    if (nobordercases || r > 1) {
> > +        properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel,
> p, r-2, c) - top;  // toptop - top
> > +    } else {
> > +        properties[index++] = 0;
> > +    }
> > +
> > +    if (nobordercases || c > 1) {
> > +        properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel,
> p, r, c-2) - left;  // leftleft - left
> > +    } else {
> > +        properties[index++] = 0;
> > +    }
> > +
> > +    return guess;
> > +}
> > +
> > +static inline FLIF16ColorVal flif16_ni_predict(FLIF16DecoderContext *s,
> > +                                               FLIF16PixelData *pixel,
> > +                                               uint32_t p, uint32_t r,
> uint32_t c,
> > +                                               FLIF16ColorVal gray) {
> > +    FLIF16ColorVal left = (c > 0 ? ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r, c-1) :
> > +                          (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r-1, c) : gray));
> > +    FLIF16ColorVal top = (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s),
> pixel, p, r - 1, c) : left);
> > +    FLIF16ColorVal topleft = (r > 0 && c > 0 ?
> ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r - 1, c - 1) : top);
> > +    FLIF16ColorVal gradientTL = left + top - topleft;
> > +    return MEDIAN3(gradientTL, left, top);
> > +}
> > +
> > +static int flif16_read_ni_plane(FLIF16DecoderContext *s,
> > +                                FLIF16RangesContext *ranges_ctx,
> > +                                FLIF16ColorVal *properties, uint8_t p,
> > +                                uint32_t fr, uint32_t r, FLIF16ColorVal
> gray,
> > +                                FLIF16ColorVal minP)
> > +{
> > +    FLIF16ColorVal curr;
> > +    uint32_t begin = 0, end = s->width;
> > +    switch (s->segment2) {
> > +        case 0:
> > +            // if this is a duplicate frame, copy the row from the
> frame being duplicated
> > +            // TODO add this condition in read_ni_image
> > +            if (s->frames[fr].seen_before >= 0) {
> > +                return 0;
> > +            }
> > +
> > +            // if this is not the first or only frame, fill the
> beginning of the row
> > +            // before the actual pixel data
> > +            if (fr > 0) {
> > +                // if alphazero is on, fill with a predicted value,
> otherwise
> > +                // copy pixels from the previous frame
> > +                begin = (!s->frameshape) ? 0 :
> s->frames[fr].col_begin[r];
> > +                end = (!s->frameshape) ? s->width :
> s->frames[fr].col_end[r];
> > +                if (s->alphazero && p < 3) {
> > +                    for (uint32_t c = 0; c < begin; c++)
> > +                        if (PIXEL_GET(s, fr, 3, r, c) == 0) {
> > +                            PIXEL_SET(s, fr, p, r, c,
> flif16_ni_predict(s, &s->frames[fr], p, r, c, gray));
> > +                        } else {
> > +                            PIXEL_SET(s, fr, p, r, c, PIXEL_GET(s,
> PREV_FRAMENUM(s->frames, fr), p, r, c));
> > +                        }
> > +                } else if (p != 4) {
> > +                    ff_flif16_copy_rows(CTX_CAST(s), &s->frames[fr],
> > +                                        PREV_FRAME(s->frames, fr), p,
> r, 0, begin);
> > +                }
> > +            }
> > +            ++s->segment2;
> > +
> > +            if (r > 1 && !s->framelookback && begin == 0 && end > 3) {
> > +            //decode actual pixel data
> > +            s->c = begin;
> > +
> > +            for (; s->c < 2; s->c++) {
> > +                if (s->alphazero && p<3 &&
> > +                    PIXEL_GET(s, fr, 3, r, s->c) == 0) {
> > +                    PIXEL_SET(s, fr, p, r, s->c,
> > +                    flif16_ni_predict(s, &s->frames[fr], p, r, s->c,
> gray));
> > +                    continue;
> > +                }
> > +                s->guess = flif16_ni_predict_calcprops(s,
> &s->frames[fr],
> > +                           properties, ranges_ctx, p, r, s->c, &s->min,
> &s->max, minP, 0);
> > +        case 1:
> > +                MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p,
> > +                           s->min - s->guess, s->max - s->guess, &curr);
> > +                curr += s->guess;
> > +                ff_flif16_pixel_set(CTX_CAST(s), &s->frames[fr], p, r,
> s->c, curr);
> > +            }
> > +            ++s->segment2;
> > +
> > +            for (; s->c < end-1; s->c++) {
> > +                if (s->alphazero && p < 3 &&
> > +                    ff_flif16_pixel_get(CTX_CAST(s), &s->frames[fr], 3,
> r, s->c) == 0) {
> > +                    ff_flif16_pixel_set(CTX_CAST(s),&s->frames[fr], p,
> r, s->c,
> > +                    flif16_ni_predict(s, &s->frames[fr], p, r, s->c,
> gray));
> > +                    continue;
> > +                }
> > +                s->guess = flif16_ni_predict_calcprops(s,
> &s->frames[fr],
> > +                           properties, ranges_ctx, p, r, s->c, &s->min,
> &s->max, minP, 1);
> > +        case 2:
> > +                MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p,
> > +                           s->min - s->guess, s->max - s->guess, &curr);
> > +                curr += s->guess;
> > +                PIXEL_SET(s, fr, p, r, s->c, curr);
> > +            }
> > +            ++s->segment2;
> > +
> > +            for (; s->c < end; s->c++) {
> > +                if (s->alphazero && p < 3 &&
> > +                    PIXEL_GET(s, fr, 3, r, s->c) == 0) {
> > +                    PIXEL_SET(s, fr, p, r, s->c, flif16_ni_predict(s,
> &s->frames[fr], p, r, s->c, gray));
> > +                    continue;
> > +                }
> > +                s->guess = flif16_ni_predict_calcprops(s,
> &s->frames[fr],
> > +                           properties, ranges_ctx, p, r, s->c, &s->min,
> &s->max, minP, 0);
> > +        case 3:
> > +                MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p,
> > +                           s->min - s->guess, s->max - s->guess, &curr);
> > +                curr += s->guess;
> > +                PIXEL_SET(s, fr, p, r, s->c, curr);
> > +            }
> > +            ++s->segment2;
> > +
> > +            } else {
> > +                s->segment2 = 4;
> > +                for (s->c = begin; s->c < end; s->c++) {
> > +                    //predict pixel for alphazero and get a previous
> pixel for lookback
> > +                    if (s->alphazero && p < 3 &&
> > +                        ff_flif16_pixel_get(CTX_CAST(s),
> &s->frames[fr], 3, r, s->c) == 0) {
> > +                        PIXEL_SET(s, fr, p, r, s->c,
> > +                        flif16_ni_predict(s, &s->frames[fr], p, r,
> s->c, gray));
> > +                        continue;
> > +                    }
> > +                    if (s->framelookback && p < 4 &&
> > +                        PIXEL_GET(s, fr, FLIF16_PLANE_LOOKBACK, r,
> s->c) > 0) {
> > +                        // TODO accomodate PRE_FRAME for this
> > +                        PIXEL_SET(s, fr, p, r, s->c,
> > +                        PIXEL_GET(s, fr - PIXEL_GET(s, fr,
> FLIF16_PLANE_LOOKBACK, r, s->c), p, r, s->c));
> > +                        continue;
> > +                    }
> > +                    //calculate properties and use them to decode the
> next pixel
> > +                    s->guess = flif16_ni_predict_calcprops(s,
> &s->frames[fr], properties,
> > +                                                           ranges_ctx,
> p, r, s->c, &s->min,
> > +                                                           &s->max,
> minP, 0);
> > +                    if (s->framelookback && p == FLIF16_PLANE_LOOKBACK
> && s->max > fr)
> > +                        s->max = fr;
> > +        case 4:
> > +                    MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p,
> > +                               s->min - s->guess, s->max - s->guess,
> &curr);
> > +                    curr += s->guess;
> > +                    PIXEL_SET(s, fr, p, r, s->c, curr);
> > +                }
> > +            } /* end if */
> > +
> > +            // If this is not the first or only frame, fill the end of
> the row after the actual pixel data
> > +            if (fr > 0) {
> > +                //if alphazero is on, fill with a predicted value,
> otherwise copy pixels from the previous frame
> > +                if (s->alphazero && p < 3) {
> > +                    for (uint32_t c = end; c < s->width; c++)
> > +                        if (PIXEL_GET(s, fr, 3, r, s->c) == 0) {
> > +                            PIXEL_SET(s, fr, p, r, s->c,
> flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray));
> > +                        } else {
> > +                            PIXEL_SET(s, fr, p, r, s->c, PIXEL_GET(s,
> PREV_FRAMENUM(s->frames, fr), p, r, s->c));
> > +                        }
> > +                } else if(p != 4) {
> > +                     ff_flif16_copy_rows(CTX_CAST(s), &s->frames[fr],
> > +                     PREV_FRAME(s->frames, fr), p, r, end, s->width);
> > +                }
> > +            }
> > +    }
> > +
> > +    s->segment2 = 0;
> > +    return 0;
> > +
> > +    need_more_data:
> > +    return AVERROR(EAGAIN);
> > +}
> > +
> > +
> > +static FLIF16ColorVal *compute_grays(FLIF16RangesContext *ranges)
> > +{
> > +    FLIF16ColorVal *grays; // a pixel with values in the middle of the
> bounds
> > +    grays = av_malloc(ranges->num_planes * sizeof(*grays));
> > +    if (!grays)
> > +        return NULL;
> > +    for (int p = 0; p < ranges->num_planes; p++)
> > +        grays[p] = (ff_flif16_ranges_min(ranges, p) +
> ff_flif16_ranges_max(ranges, p)) / 2;
> > +    return grays;
> > +}
> > +
> > +static int flif16_read_ni_image(AVCodecContext *avctx)
> > +{
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    int ret;
> > +    FLIF16ColorVal min_p;
> > +
> > +    // Set images to gray
> > +    switch (s->segment) {
> > +        case 0:
> > +            s->grays = compute_grays(s->range); // free later
> > +            if (!s->grays)
> > +                return AVERROR(ENOMEM);
> > +            s->i = s->i2 = s->i3 = 0;
> > +            if (   (s->range->num_planes > 3 &&
> ff_flif16_ranges_max(s->range, 3) == 0)
> > +                || (s->range->num_planes > 3 &&
> ff_flif16_ranges_min(s->range, 3) > 0))
> > +                s->alphazero = 0;
> > +
> > +            ++s->segment;
> > +
> > +            for (; s->i < 5; ++s->i) {
> > +                s->curr_plane = plane_ordering[s->i];
> > +                if (s->curr_plane >= s->num_planes) {
> > +                    continue;
> > +                }
> > +                if (ff_flif16_ranges_min(s->range, s->curr_plane) >=
> > +                    ff_flif16_ranges_max(s->range, s->curr_plane)) {
> > +                    continue;
> > +                }
> > +                s->properties = av_mallocz((s->num_planes > 3 ?
> properties_ni_rgba_size[s->curr_plane]
> > +                                                            :
> properties_ni_rgb_size[s->curr_plane])
> > +                                                            *
> sizeof(*s->properties));
> > +                if (!s->properties)
> > +                    return AVERROR(ENOMEM);
>
> > +                for (; s->i2 < s->height; ++s->i2) {
> > +                    for (; s->i3 < s->num_frames; ++s->i3) {
> > +        case 1:
> > +                        // TODO maybe put this in dec ctx
>
> Urgh.
>
> > +                        min_p = ff_flif16_ranges_min(s->range,
> s->curr_plane);
> > +                        ret = flif16_read_ni_plane(s, s->range,
> s->properties,
> > +                                                   s->curr_plane,
> > +                                                   s->i3,
> > +                                                   s->i2,
> > +
>  s->grays[s->curr_plane],
> > +                                                   min_p);
> > +
> > +                        if (ret) {
> > +                            goto error;
> > +                        }
> > +                    } // End for
> > +                    s->i3 = 0;
> > +                } // End for
> > +                if (s->properties)
> > +                    av_freep(&s->properties);
> > +                s->i2 = 0;
> > +            } // End for
> > +
> > +    } // End switch
> > +
> > +    for (int i = 0; i < s->num_frames; i++) {
> > +        if (s->frames[i].seen_before >= 0)
> > +            continue;
> > +        for (int j = s->transform_top - 1; j >= 0; --j) {
> > +            ff_flif16_transform_reverse(CTX_CAST(s), s->transforms[j],
> &s->frames[i], 1, 1);
> > +        }
> > +    }
> > +
> > +    if (s->grays)
> > +            av_freep(&s->grays);
> > +
> > +    s->state = FLIF16_OUTPUT;
> > +    return 0;
> > +
> > +    error:
> > +    return ret;
> > +}
> > +
> > +/*
> ============================================================================
> > + * Interlaced plane decoding
> > + *
> ============================================================================
> > + *
> > + * This is how the data is organised here:
> > + * 1. uni_int: rough_zoomlevel
> > + * 2. (repeat num_planes times) values of top left pixels of each
> channel
> > + * 3. Rough Pixeldata max_zoomlevel to rough_zoomlevel + 1
> > + *    For this case, the MANIAC forest is initialised with a single
> node per
> > + *    channel. This is nused with the maniac integer reader.
> > + * 4. Actual Encoded MANIAC trees
> > + * 5. Rest of the pixeldata rough_zoomlevel to 0
> > + *
> > + * TODO
> > + */
> > +
> > +static int flif16_read_pixeldata(AVCodecContext *avctx)
> > +{
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    int ret;
> > +    if((s->ia % 2))
> > +        ret = flif16_read_ni_image(avctx);
> > +    else
> > +        return AVERROR(EINVAL);
> > +
> > +    if(!ret)
> > +        s->state = FLIF16_OUTPUT;
> > +
> > +    return ret;
> > +}
> > +
> > +static int flif16_write_frame(AVCodecContext *avctx, AVFrame *data)
> > +{
> > +    uint32_t target_frame;
> > +    int ret;
>
> > +    FLIF16DecoderContext *s = avctx->priv_data;
>
> Why a decoder context for an encoder?
>
> > +    ff_set_dimensions(avctx, s->width, s->height);
>
> Missing error check.
>
> > +    s->out_frame->pict_type = AV_PICTURE_TYPE_I;
> > +
> > +    if (s->bpc > 65535) {
> > +        av_log(avctx, AV_LOG_ERROR, "depth per channel greater than 16
> bits not supported\n");
> > +        return AVERROR_PATCHWELCOME;
> > +    }
> > +
> > +    avctx->pix_fmt = flif16_out_frame_type[FFMIN(s->num_planes,
> 4)][s->bpc > 255];
> > +
> > +    if ((ret = ff_reget_buffer(avctx, s->out_frame, 0)) < 0) {
> > +        return ret;
> > +    }
> > +
> > +    target_frame = (s->frames[s->out_frames_count].seen_before >= 0)
> > +                   ? s->frames[s->out_frames_count].seen_before
> > +                   : s->out_frames_count;
> > +
> > +    if (s->num_frames > 1) {
> > +        s->out_frame->pts = s->pts;
> > +        s->pts += s->framedelay[s->out_frames_count];
> > +    }
> > +
> > +    // Clear out transparent pixels
> > +    if (s->num_planes > 3) {
> > +        for (uint32_t i = 0; i < s->height; ++i)
> > +            for (uint32_t j = 0; j < s->width; ++j)
> > +                if (!PIXEL_GET(s, s->out_frames_count,
> FLIF16_PLANE_ALPHA, i, j)) {
> > +                    PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_Y,
> i, j, 0);
> > +                    PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_CO,
> i, j, 0);
> > +                    PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_CG,
> i, j, 0);
> > +                }
> > +    }
> > +
> > +    switch (avctx->pix_fmt) {
> > +        case AV_PIX_FMT_GRAY8:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *(s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j) = \
> > +                    PIXEL_GET(s, target_frame, 0, i, j);
> > +                }
> > +            }
> > +            break;
> > +
> > +        case AV_PIX_FMT_RGB24:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *(s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 3 + 0 ) = \
> > +                    PIXEL_GET(s, target_frame, 0, i, j);
> > +                    *(s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 3 + 1) = \
> > +                    PIXEL_GET(s, target_frame, 1, i, j);
> > +                    *(s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 3 + 2) = \
> > +                    PIXEL_GET(s, target_frame, 2, i, j);
> > +                }
> > +            }
> > +            break;
> > +
> > +        case AV_PIX_FMT_RGB32:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *((uint32_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 4))
> > +                    = (PIXEL_GET(s, target_frame, 3, i, j) << 24) |
> > +                      (PIXEL_GET(s, target_frame, 0, i, j) << 16) |
> > +                      (PIXEL_GET(s, target_frame, 1, i, j) << 8)  |
> > +                       PIXEL_GET(s, target_frame, 2, i, j);
> > +                }
> > +            }
> > +            break;
> > +
> > +        case AV_PIX_FMT_GRAY16:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *((uint16_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 2)) = \
> > +                    PIXEL_GET(s, target_frame, 0, i, j);
> > +                }
> > +            }
> > +            break;
> > +
> > +        case AV_PIX_FMT_RGB48:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *((uint16_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 6 + 0)) = \
> > +                    PIXEL_GET(s, target_frame, 0, i, j);
> > +                    *((uint16_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 6 + 1)) = \
> > +                    PIXEL_GET(s, target_frame, 1, i, j);
> > +                    *((uint16_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 6 + 2)) = \
> > +                    PIXEL_GET(s, target_frame, 2, i, j);
> > +                }
> > +            }
> > +
> > +        case AV_PIX_FMT_RGBA64:
> > +            for (uint32_t i = 0; i < s->height; ++i) {
> > +                for (uint32_t j = 0; j < s->width; ++j) {
> > +                    *((uint64_t *) (s->out_frame->data[0] + i *
> s->out_frame->linesize[0] + j * 8))
> > +                    = (uint64_t) \
> > +                      (((uint64_t) PIXEL_GET(s, target_frame, 3, i, j))
> << 48) |
> > +                      (((uint64_t) PIXEL_GET(s, target_frame, 2, i, j))
> << 32) |
> > +                      (((uint64_t) PIXEL_GET(s, target_frame, 1, i, j))
> << 16) |
> > +                       ((uint64_t) PIXEL_GET(s, target_frame, 0, i, j));
> > +                }
> > +            }
> > +            break;
> > +
> > +        default:
> > +            av_log(avctx, AV_LOG_ERROR, "Pixel format %d out of
> bounds?\n", avctx->pix_fmt);
> > +            return AVERROR_PATCHWELCOME;
> > +    }
> > +
> > +    av_frame_ref(data, s->out_frame);
> > +    if ((++s->out_frames_count) >= s->num_frames)
> > +        s->state = FLIF16_EOS;
> > +
> > +    return 0;
> > +}
> > +
> > +static int flif16_read_checksum(AVCodecContext *avctx)
> > +{
> > +    return AVERROR_EOF;
> > +}
> > +
> > +static int flif16_decode_init(AVCodecContext *avctx)
> > +{
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    s->out_frame = av_frame_alloc();
> > +    if (!s->out_frame)
> > +        return AVERROR(ENOMEM);
> > +    return 0;
> > +}
> > +
> > +static int flif16_decode_frame(AVCodecContext *avctx,
> > +                               void *data, int *got_frame,
> > +                               AVPacket *avpkt)
> > +{
> > +    int ret = 0;
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    const uint8_t *buf      = avpkt->data;
> > +    int buf_size            = avpkt->size;
> > +    AVFrame *p              = data;
> > +
> > +    bytestream2_init(&s->gb, buf, buf_size);
> > +
> > +    // Looping is done to change states in between functions.
> > +    // Function will either exit on AVERROR(EAGAIN) or AVERROR_EOF
>
> > +    do {
> > +        switch(s->state) {
>
> Now, this is a proper loop with a state machine!
>
> > +            case FLIF16_HEADER:
> > +                ret = flif16_read_header(avctx);
> > +                break;
> > +
> > +            case FLIF16_SECONDHEADER:
> > +                ret = flif16_read_second_header(avctx);
> > +                break;
> > +
> > +            case FLIF16_TRANSFORM:
> > +                ret = flif16_read_transforms(avctx);
> > +                break;
> > +
> > +            case FLIF16_ROUGH_PIXELDATA:
> > +                av_assert0(0);
> > +                ret = flif16_read_pixeldata(avctx);
> > +                if (!ret)
> > +                    s->state = FLIF16_MANIAC;
> > +                break;
> > +
> > +            case FLIF16_MANIAC:
> > +                // TODO manage interlaced condition
> > +                ret = flif16_read_maniac_forest(avctx);
> > +                break;
> > +
> > +            case FLIF16_PIXELDATA:
> > +                ret = flif16_read_pixeldata(avctx);
> > +                break;
> > +
> > +            case FLIF16_CHECKSUM:
> > +                ret = flif16_read_checksum(avctx);
> > +                break;
> > +
> > +            case FLIF16_OUTPUT:
> > +                ret = flif16_write_frame(avctx, p);
> > +                if (!ret) {
> > +                    *got_frame = 1;
> > +                    return buf_size;
> > +                }
> > +                break;
> > +
> > +            case FLIF16_EOS:
> > +                return AVERROR_EOF;
> > +        }
> > +
> > +    } while (!ret);
> > +
> > +    return ret;
> > +}
> > +
> > +static av_cold int flif16_decode_end(AVCodecContext *avctx)
> > +{
> > +    FLIF16DecoderContext *s = avctx->priv_data;
> > +    if (s->framedelay)
> > +        av_freep(&s->framedelay);
> > +    if (s->prop_ranges)
> > +        av_freep(&s->prop_ranges);
> > +    if (s->frames)
> > +        ff_flif16_frames_free(&s->frames, s->num_frames, s->num_planes,
> s->framelookback);
> > +
> > +    for (int i = s->transform_top - 1; i >= 0; --i)
> > +        ff_flif16_transforms_close(s->transforms[i]);
> > +
> > +    ff_flif16_maniac_close(&s->maniac_ctx, s->num_planes);
> > +    av_frame_free(&s->out_frame);
> > +
> > +    if (s->range)
> > +        ff_flif16_ranges_close(s->range);
> > +    return 0;
> > +}
> > +
> > +AVCodec ff_flif16_decoder = {
> > +    .name           = "flif16",
> > +    .long_name      = NULL_IF_CONFIG_SMALL("FLIF (Free Lossless Image
> Format)"),
> > +    .type           = AVMEDIA_TYPE_VIDEO,
> > +    .id             = AV_CODEC_ID_FLIF16,
> > +    .init           = flif16_decode_init,
> > +    .close          = flif16_decode_end,
> > +    .priv_data_size = sizeof(FLIF16DecoderContext),
> > +    .decode         = flif16_decode_frame,
> > +    .capabilities   = AV_CODEC_CAP_DELAY,
> > +    //.caps_internal  = 0,
> > +    .priv_class     = NULL,
> > +};
> > diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
> > index 7d75cea830..e5956d81cd 100644
> > --- a/libavcodec/parsers.c
> > +++ b/libavcodec/parsers.c
> > @@ -40,6 +40,7 @@ extern AVCodecParser ff_dvbsub_parser;
> >  extern AVCodecParser ff_dvdsub_parser;
> >  extern AVCodecParser ff_dvd_nav_parser;
> >  extern AVCodecParser ff_flac_parser;
> > +extern AVCodecParser ff_flif16_parser;
> >  extern AVCodecParser ff_g723_1_parser;
> >  extern AVCodecParser ff_g729_parser;
> >  extern AVCodecParser ff_gif_parser;
> > diff --git a/libavformat/Makefile b/libavformat/Makefile
> > index 62d8cbb54e..514fb827aa 100644
> > --- a/libavformat/Makefile
> > +++ b/libavformat/Makefile
> > @@ -191,6 +191,7 @@ OBJS-$(CONFIG_FLAC_DEMUXER)              +=
> flacdec.o rawdec.o \
> >  OBJS-$(CONFIG_FLAC_MUXER)                += flacenc.o flacenc_header.o \
> >                                              vorbiscomment.o
> >  OBJS-$(CONFIG_FLIC_DEMUXER)              += flic.o
> > +OBJS-$(CONFIG_FLIF_DEMUXER)            += flifdec.o
> >  OBJS-$(CONFIG_FLV_DEMUXER)               += flvdec.o
> >  OBJS-$(CONFIG_LIVE_FLV_DEMUXER)          += flvdec.o
> >  OBJS-$(CONFIG_FLV_MUXER)                 += flvenc.o avc.o
> > diff --git a/libavformat/allformats.c b/libavformat/allformats.c
> > index fd9e46e233..7d941cdcfe 100644
> > --- a/libavformat/allformats.c
> > +++ b/libavformat/allformats.c
> > @@ -149,6 +149,7 @@ extern AVOutputFormat ff_fits_muxer;
> >  extern AVInputFormat  ff_flac_demuxer;
> >  extern AVOutputFormat ff_flac_muxer;
> >  extern AVInputFormat  ff_flic_demuxer;
> > +extern AVInputFormat  ff_flif_demuxer;
> >  extern AVInputFormat  ff_flv_demuxer;
> >  extern AVOutputFormat ff_flv_muxer;
> >  extern AVInputFormat  ff_live_flv_demuxer;
> > diff --git a/libavformat/flifdec.c b/libavformat/flifdec.c
> > new file mode 100644
> > index 0000000000..a4241aedbb
> > --- /dev/null
> > +++ b/libavformat/flifdec.c
> > @@ -0,0 +1,377 @@
> > +/*
> > + * FLIF16 demuxer
> > + * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
> > + *
> > + * This file is part of FFmpeg.
> > + *
> > + * FFmpeg 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.
> > + *
> > + * FFmpeg 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 FFmpeg; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> 02110-1301 USA
> > + */
> > +
> > +/**
> > + * @file
> > + * FLIF demuxer.
> > + */
> > +
> > +#include "avformat.h"
> > +#include "libavutil/bprint.h"
> > +#include "libavutil/intreadwrite.h"
> > +#include "libavutil/opt.h"
> > +#include "internal.h"
> > +#include "libavcodec/flif16.h"
> > +#include "libavcodec/flif16_rangecoder.h"
> > +
> > +#include "config.h"
> > +
> > +// Remove later
> > +#include <stdio.h>
> > +
> > +
> > +// Uncomment to disable metadata reading
> > +// #undef CONFIG_ZLIB
> > +
> > +#if CONFIG_ZLIB
> > +#include <zlib.h>
> > +#endif
> > +
> > +#define BUF_SIZE 4096
> > +
> > +typedef struct FLIFDemuxContext {
> > +    const AVClass *class;
> > +#if CONFIG_ZLIB
> > +    z_stream stream;
> > +    uint8_t active;
> > +#endif
> > +    int64_t duration;
> > +} FLIFDemuxContext;
> > +
> > +
> > +#if CONFIG_ZLIB
> > +static int flif_inflate(FLIFDemuxContext *s, uint8_t *buf, int buf_size,
> > +                        uint8_t **out_buf, int *out_buf_size)
> > +{
> > +    int ret;
> > +    z_stream *stream = &s->stream;
> > +
> > +    if (!s->active) {
> > +        s->active = 1;
> > +        stream->zalloc   = Z_NULL;
> > +        stream->zfree    = Z_NULL;
> > +        stream->opaque   = Z_NULL;
> > +        stream->avail_in = 0;
> > +        stream->next_in  = Z_NULL;
> > +        ret = inflateInit(stream);
> > +
> > +        if (ret != Z_OK)
> > +            return ret;
> > +
> > +        *out_buf_size = buf_size;
> > +        *out_buf = av_realloc(*out_buf, *out_buf_size);
> > +        if (!*out_buf)
> > +            return AVERROR(ENOMEM);
> > +    }
> > +
> > +    stream->next_in  = buf;
> > +    stream->avail_in = buf_size;
> > +    while (stream->total_out >= *out_buf_size) {
>
> > +        *out_buf = av_realloc(*out_buf, (*out_buf_size) * 2);
> > +        if (!out_buf)
> > +            return AVERROR(ENOMEM);
>
> Leaks original out_buf.
>
> > +        *out_buf_size *= 2;
> > +    }
> > +
> > +    stream->next_out  = *out_buf + stream->total_out;
> > +    stream->avail_out = *out_buf_size - stream->total_out - 1; // Last
> byte should be NULL char
> > +    printf("First 10 bytes: ");
> > +    for (int i = 0; i < FFMIN(10, buf_size); ++i)
> > +        printf("%x ", buf[i]);
> > +    printf("\n");
> > +    printf("Buf size: %d, Outbuf size: %d\n", buf_size, *out_buf_size);
> > +    ret = inflate(stream, Z_NO_FLUSH);
> > +    printf("Return: %d Message: %s \nZ_NEED_DICT: %d\nZ_DATA_ERROR:
> %d\n"
> > +           "Z_MEM_ERROR: %d\n", ret, stream->msg, Z_NEED_DICT,
> Z_DATA_ERROR,
> > +           Z_MEM_ERROR);
> > +    switch (ret) {
> > +        case Z_NEED_DICT:
> > +        case Z_DATA_ERROR:
> > +            ret = inflateSync(stream);
> > +            printf("Sync ret: %d\n", ret);
> > +            printf("Buf size: %d, Outbuf size: %d\n", buf_size,
> *out_buf_size);
> > +            (void)inflateEnd(stream);
> > +            return AVERROR(EINVAL);
> > +        case Z_MEM_ERROR:
> > +            (void)inflateEnd(stream);
>
> > +            return AVERROR(ENOMEM);
>
> Looks incorrect.
>
> > +    }
> > +
> > +    if (ret == Z_STREAM_END) {
> > +        ret = 0;
> > +        s->active = 0;
> > +        (*out_buf)[stream->total_out] = '\0';
> > +        (void) inflateEnd(stream);
> > +    } else
> > +        ret = AVERROR(EAGAIN);
> > +
> > +    return ret; // Return Z_BUF_ERROR/EAGAIN as long as input is
> incomplete.
> > +}
> > +#endif
> > +
> > +static int flif16_probe(const AVProbeData *p)
> > +{
> > +    uint32_t vlist[3] = {0};
> > +    unsigned int count = 0, pos = 0;
> > +
> > +    // Magic Number
> > +    if (memcmp(p->buf, flif16_header, 4)) {
> > +        return 0;
> > +    }
> > +
> > +    for(int i = 0; i < 2 + (((p->buf[4] >> 4) > 4) ? 1 : 0); ++i) {
> > +        while (p->buf[5 + pos] > 127) {
> > +            if (!(count--)) {
> > +                return 0;
> > +            }
> > +            VARINT_APPEND(vlist[i], p->buf[5 + pos]);
> > +            ++pos;
> > +        }
> > +        VARINT_APPEND(vlist[i], p->buf[5 + pos]);
> > +        count = 0;
> > +    }
> > +
> > +    if (!((vlist[0] + 1) && (vlist[1] + 1)))
> > +        return 0;
> > +
> > +    if (((p->buf[4] >> 4) > 4) && !(vlist[2] + 2))
> > +        return 0;
> > +
> > +    return AVPROBE_SCORE_MAX;
> > +}
> > +
> > +static int flif16_read_header(AVFormatContext *s)
> > +{
> > +    FLIFDemuxContext *dc = s->priv_data;
> > +    GetByteContext gb;
> > +    FLIF16RangeCoder rc;
> > +
> > +    AVIOContext     *pb  = s->pb;
> > +    AVStream        *st;
> > +
> > +    uint32_t vlist[3] = {0};
> > +    uint32_t flag, animated, temp;
> > +    uint32_t bpc = 0;
> > +    uint8_t tag[5] = {0};
> > +    uint8_t buf[BUF_SIZE];
> > +    uint32_t metadata_size = 0;
> > +    uint8_t *out_buf = NULL;
> > +    int out_buf_size = 0;
> > +
> > +    unsigned int count = 4;
> > +    int ret;
> > +    int format;
> > +    int segment = 0, i = 0;
> > +    int64_t duration = 0;
> > +    uint8_t loops = 0;
> > +    uint8_t num_planes;
> > +    uint8_t num_frames;
> > +
> > +    // Magic Number
> > +    if (avio_rl32(pb) != (*((uint32_t *) flif16_header))) {
> > +        av_log(s, AV_LOG_ERROR, "bad magic number\n");
> > +        return AVERROR(EINVAL);
> > +    }
> > +
>
> > +    st = avformat_new_stream(s, NULL);
>
> Missing error check.
>
> > +    flag = avio_r8(pb);
> > +    animated = (flag >> 4) > 4;
> > +    duration = !animated;
> > +    bpc = avio_r8(pb); // Bytes per channel
> > +
> > +    num_planes = flag & 0x0F;
> > +
> > +    for (int i = 0; i < (2 + animated); ++i) {
> > +        while ((temp = avio_r8(pb)) > 127) {
> > +            if (!(count--))
> > +                return AVERROR_INVALIDDATA;
> > +            VARINT_APPEND(vlist[i], temp);
> > +        }
> > +        VARINT_APPEND(vlist[i], temp);
> > +        count = 4;
> > +    }
> > +
> > +
> > +    ++vlist[0];
> > +    ++vlist[1];
> > +    if (animated)
> > +        vlist[2] += 2;
> > +    else
> > +        vlist[2] = 1;
> > +
> > +    num_frames = vlist[2];
> > +
> > +    while ((temp = avio_r8(pb))) {
> > +        // Get metadata identifier
>
> > +        #if CONFIG_ZLIB
> > +        tag[0] = temp;
> > +        for(int i = 1; i <= 3; ++i)
> > +            tag[i] = avio_r8(pb);
>
> > +        #else
> > +        avio_skip(pb, 3);
> > +        #endif
>
> Unnecessary: you can fill tag even if zlib is not available.
>
> > +
> > +        // Read varint
> > +        while ((temp = avio_r8(pb)) > 127) {
> > +            if (!(count--))
> > +                return AVERROR_INVALIDDATA;
> > +            VARINT_APPEND(metadata_size, temp);
> > +        }
> > +        VARINT_APPEND(metadata_size, temp);
> > +        count = 4;
> > +
> > +        #if CONFIG_ZLIB
> > +        // Decompression Routines
> > +        while (metadata_size > 0) {
> > +            ret = avio_read(pb, buf, FFMIN(BUF_SIZE, metadata_size));
> > +            metadata_size -= ret;
> > +            if((ret = flif_inflate(dc, buf, ret, &out_buf,
> &out_buf_size)) < 0 &&
> > +                ret != AVERROR(EAGAIN)) {
> > +                av_log(s, AV_LOG_ERROR, "could not decode metadata\n");
> > +                return ret;
> > +            }
> > +        }
> > +        av_dict_set(&s->metadata, tag, out_buf, 0);
> > +        #else
> > +        avio_skip(pb, metadata_size);
> > +        #endif
> > +    }
> > +
>
> > +    #if CONFIG_ZLIB
>
> Unnecessary.
>
> > +    if (out_buf)
>
> Unnecessary, av_freep() accepts NULL.
>
> > +        av_freep(&out_buf);
> > +    #endif
> > +
> > +    avio_read(pb, buf, FLIF16_RAC_MAX_RANGE_BYTES);
> > +    ff_flif16_rac_init(&rc, NULL, buf, FLIF16_RAC_MAX_RANGE_BYTES);
> > +    ret = avio_read_partial(pb, buf, BUF_SIZE);
> > +    bytestream2_init(&gb, buf, ret);
> > +    rc.gb = &gb;
> > +
> > +    while (1) {
> > +        switch (segment) {
> > +            case 0:
> > +                if (bpc == '0') {
> > +                    bpc = 0;
> > +                    for (; i < num_planes; ++i) {
> > +                        RAC_GET(&rc, NULL, 1, 15, &temp,
> FLIF16_RAC_UNI_INT8);
> > +                        bpc = FFMAX(bpc, (1 << temp) - 1);
> > +                    }
> > +                    i = 0;
> > +                } else
> > +                    bpc = (bpc == '1') ? 255 : 65535;
> > +                // MSG("planes : %d & bpc : %d\n", num_planes, bpc);
> > +                if (num_frames < 2)
> > +                    goto end;
> > +                ++segment;
> > +
> > +            case 1:
> > +                if (num_planes > 3) {
> > +                    RAC_GET(&rc, NULL, 0, 1, &temp,
> FLIF16_RAC_UNI_INT8);
> > +                }
> > +                ++segment;
> > +
> > +            case 2:
> > +                if (num_frames > 1) {
> > +                    RAC_GET(&rc, NULL, 0, 100, &loops,
> FLIF16_RAC_UNI_INT8);
> > +                } else
> > +                    loops = 1;
> > +                ++segment;
> > +
> > +            case 3:
> > +                if (num_frames > 1) {
> > +                    for (; i < num_frames; ++i) {
> > +                        temp = 0;
> > +                        RAC_GET(&rc, NULL, 0, 60000, &(temp),
> FLIF16_RAC_UNI_INT16);
> > +                        duration += temp;
> > +                    }
> > +                    i = 0;
> > +                } else
> > +                    duration = 1;
> > +                goto end;
> > +        }
> > +
> > +        need_more_data:
> > +            ret = avio_read_partial(pb, buf, BUF_SIZE);
> > +            bytestream2_init(&gb, buf, ret);
> > +    }
> > +
> > +    end:
> > +    if (bpc > 65535) {
> > +        av_log(s, AV_LOG_ERROR, "depth per channel greater than 16 bits
> not supported\n");
> > +        return AVERROR_PATCHWELCOME;
> > +    }
> > +
> > +    // The minimum possible delay in a FLIF16 image is 1 millisecond.
> > +    // Therefore time base is 10^-3, i.e. 1/1000
> > +    format = flif16_out_frame_type[FFMIN(num_planes, 4)][bpc > 255];
> > +    avpriv_set_pts_info(st, 64, 1, 1000);
> > +    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
> > +    st->codecpar->codec_id   = AV_CODEC_ID_FLIF16;
> > +    st->codecpar->width      = vlist[0];
> > +    st->codecpar->height     = vlist[1];
> > +    st->codecpar->format     = format;
> > +    st->duration             = duration * loops;
> > +    st->start_time           = 0;
> > +    st->nb_frames            = vlist[2];
> > +    // st->need_parsing         = 1;
> > +
> > +    // Jump to start because flif16 decoder needs header data too
> > +    if (avio_seek(pb, 0, SEEK_SET) != 0)
> > +        return AVERROR(EIO);
> > +    //printf("At: [%s] %s, %d\n", __func__, __FILE__, __LINE__);
> > +    return 0;
> > +}
> > +
> > +
> > +static int flif16_read_packet(AVFormatContext *s, AVPacket *pkt)
> > +{
> > +    AVIOContext *pb  = s->pb;
> > +    int ret;
> > +    //  FFMIN(BUF_SIZE, avio_size(pb))
> > +    ret = av_get_packet(pb, pkt, avio_size(pb));
> > +    return ret;
> > +}
> > +
> > +
> > +static const AVOption options[] = {
> > +    { NULL }
> > +};
> > +
> > +static const AVClass demuxer_class = {
> > +    .class_name = "FLIF demuxer",
> > +    .item_name  = av_default_item_name,
> > +    .option     = options,
> > +    .version    = LIBAVUTIL_VERSION_INT,
> > +    .category   = AV_CLASS_CATEGORY_DEMUXER,
> > +};
> > +
> > +AVInputFormat ff_flif_demuxer = {
> > +    .name           = "flif",
> > +    .long_name      = NULL_IF_CONFIG_SMALL("Free Lossless Image Format
> (FLIF)"),
> > +    .priv_data_size = sizeof(FLIFDemuxContext),
> > +    .extensions     = "flif",
> > +    .read_probe     = flif16_probe,
> > +    .read_header    = flif16_read_header,
> > +    .read_packet    = flif16_read_packet,
> > +    //.flags          = AVFMT_NOTIMESTAMPS,
> > +    .priv_class     = &demuxer_class,
> > +};
>
> Regards,
>
> --
>   Nicolas George
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


Will correct indentations, leaks pointed out by you. Also will make those
goto into a proper loop everywhere required.
Thank You for taking out your time to review our code.
Definitely helps in improving mindset for error/bug detection while writing
down code.

Regards,
Kartik


More information about the ffmpeg-devel mailing list