diff mbox series

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

Message ID c2958cf17cbe8b613e4ca87615715555@teknik.io
State Superseded
Headers show
Series [FFmpeg-devel,v2,RFC] lavc, lavfmt: add FLIF decoding support | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate fail Make fate failed

Commit Message

Anamitra Ghorui July 30, 2020, 1:41 p.m. UTC
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.

Other test files: https://0x0.st/ixSs.7z

Co-authored-by: Anamitra Ghorui <aghorui@teknik.io>
Co-authored-by: Kartik K Khullar <kartikkhullar840@gmail.com>

Signed-off-by: Anamitra Ghorui <aghorui@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

Comments

Nicolas George Aug. 2, 2020, 12:27 p.m. UTC | #1
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@teknik.io>
> Co-authored-by: Kartik K Khullar <kartikkhullar840@gmail.com>
> 
> Signed-off-by: Anamitra Ghorui <aghorui@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
> +@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@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@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@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@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@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@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.

> +
> +    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.

> +    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.

> +    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?

> +
> +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.

> +        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.

> +{
> +    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.

> +    .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.

> +    &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.

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().

> +    if (!data->bounds)
> +        return -1;

AVERROR(ENOMEM)

> +    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.

> +        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.

> +            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.

> +    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.

> +{
> +    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.

> +{
> +    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.

> +        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.

> +    (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.

> +            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?

> +    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@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@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@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,
Anamitra Ghorui Aug. 2, 2020, 2:14 p.m. UTC | #2
Hello,
Thanks a lot for the code review. We will make sure to correct all of
these mistakes after we are done with all of the features in about a
week, before we post our (supposed) final patch for the decoder.

For some reason my mail client has truncated the indentation (and any
series of multiple spaces) in the blockquotes. I apologise for that.

August 2, 2020 5:58 PM, "Nicolas George" <george@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.
> 

[...]

>> 
>> +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.

Will do.

>> +{
>> + 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];

Will do. Seems more efficient.

>> + *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.

Will do.

>> + 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.

No. It is at maximum of size 5. Will remove.

>> +
>> + 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.
> 

Will do.

>> + 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.

No. Initialisation to 0 was done for testing purposes. Ideally, only
initialisation in the "fill" mode should involve preliminiary setting.

>> + 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.

Will do.

>> + 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()

Will do.

>> + if (!frames)
>> + return NULL;
>> +

[...]

>> +
>> +} 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.

Will do.

>> +} 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".

Will do

>> +} 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.

Will do.

>> + uint8_t t_no;
>> + unsigned int segment; ///< Segment the code is executing in.
>> + int i; ///< Variable to store iteration number.
>> + uint8_t done;

[...]

>> + 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.

Will do.

>> + }
>> +}
>> +
>> +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@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.

Will do.

>> + 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;

Will do.

>> + 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)?
>

Will do. I hadn't touched this code since I wrote it so it was mostly
overlooked.

>> + 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
>

Will do.

>> +
>> + switch (f->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.
>

Please see:
* https://github.com/FLIF-hub/FLIF/blob/master/src/maniac/chance.cpp ,
  function `build_table()`
* libavcodec/rangecoder.c, function ff_build_rac_states()
* and function below, build_table()

You will see that these two functions are about 1:1, and the code in
FLIF's reference decoder has been adapted for a more generic case.
The credits were added out of suspicion over who is the original author
of the function. I don't know whether this is the only way to write the
function. A few more functions were more or less copied over from the 
reference decoder (such as log4kf below) but I don't think they are 
useful anymore. Please see below (Multiscale Bitchances).

[...]

>> +
>> +// 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.
> 

True. Will fix.

>> +}
>> +
>> +void ff_flif16_rac_free(FLIF16RangeCoder *rc)
>> +{
>> + if (!rc)
>> + return;
>> 
>> + av_freep(rc);
> 
> Was this tested? av_freep() wants a pointer to pointer.
>

Will fix. I have put the rangecoder struct in the decoder context itself
because of which this error was not caught.

[...]

>> + 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.
>

This may not be requred anymore. Please see below.

>> + 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.

Oh, whoops. Will fix.

>> + 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.
> 

Will do.

>> + 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().
> 

Will do.

>> + 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.
> 

Will do.

>> +
>> + 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.
> 

Will do. 

[...]

>> + --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
> 

Will do.

[...]

>> + 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().
> 

Will do.

>> + m->stack_size *= 2;
>> + }
>> +
>> + temp = m->forest[channel]->data[m->stack[m->stack_top - 1].id].property;
>> +

[...]

>> + 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();
> 

Will do.

[...]

>> +} FLIF16Log4kTable;
>> +
>> 
>> +static const uint32_t flif16_multiscale_alphas[] = {
>> + 21590903, 66728412, 214748365, 7413105, 106514140, 10478104
>> +};
> 
> Please add a short comment to explain.
> 

FLIF's reference sourcecode has 2 probability models (or chances) which
are non interchangeable. This is the multiscale version of the
probability model (as opposed to the simple one). However, FLIF's
upstream sourcecode does not have this enabled by default (This is a 
compile tine option). This means that all FLIF encoded files in
circulation do not use the multiscale chances/probability table for
their encoded data, and since FLIF development is dead, this is not
going to change. Should I remove this?

[...]

>> 
>> + uint16_t data[sizeof(flif16_nz_int_chances) / sizeof(flif16_nz_int_chances[0])];
> 
> FF_ARRAY_ELEMS()
> 

Will do.


>> +#ifdef MULTISCALE_CHANCES_ENABLED
>> + FLIF16MultiscaleChanceContext *leaves;
>> +#else
>> + FLIF16ChanceContext *leaves;
>> +#endif
> 
> You could avoid these multiple ifdef with a single conditional typedef.
> 

Will do if I decide to keep it. Please see above (Multiscale Bitchances)

>> + 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.
> 

Will do.

>> +
>> + 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.
> 

Will do.

>> +{
>> + 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.
> 

Will do.

>> + 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.
> 

Will do.

>> + 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.
> 

Will remove if I decide to keep it. Please see above. (Multiscale
Bitchances)

>> +
>> +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.
> 

Will do.

>> + RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_ZERO, &(temp));
>> + if (temp) {
>> + *target = 0;
>> + goto end;
>> + }
>> 
>> + ++rc->segment;__PLN__
> 
> What is this __PLN__?
> 

"Print Line Number". Will remove it. Was there for debugging purposes.

>> +
>> + 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.
> 

Will do.

>> + 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.
> 

Will do.

>> + 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@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
>> + */

This part is for Kartik to respond. In hindsight I should have gone
through this sourcecode more and suggest more changes.

[...]

>> @@ -0,0 +1,1146 @@
>> +/*
>> + * FLIF16 Decoder
>> + * Copyright (c) 2020 Anamitra Ghorui <aghorui@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
>> + */
>> +
>> +/**

[...]

>> + 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
> 

Will do.

>> + }
>> +
>> 
>> + if (bytestream2_get_le32(&s->gb) != (*((uint32_t *) flif16_header))) {
> 
> You can't do that. Was it tested on big endian?
> 

I thought I would be able to get away from using strcmp, but I haven't
tested on big endian machines. I thought the byte order would be the
same if I used bytestream2_get_le32. Will see.

>> + av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
>> 
>> + return AVERROR(EINVAL);
> 
> AVERROR_INVALIDDATA
> 

Will do.

[...]

>> 
>> + return AVERROR(ENOMEM);
> 
> AVERROR_INVALIDDATA
> 

Will do.

[...]

>> 
>> + 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.
> 

Will do.


>> + case FLIF16_TRANSFORM_DUPLICATEFRAME:
>> + s->framedup = 1;
>> + if(s->num_frames < 2)
>> + return AVERROR(EINVAL);
> 
> AVERROR_INVALIDDATA
> 

Will do.

>> + 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
> 

Will do.

>> + 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
> 

Will do.

>> + 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
> 

Will do.

>> + }
>> +
>> + 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.
> 

Will do.

>> + }
>> +
>> + // 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.
> 

Will do.

>> + 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.
> 

Yes. The function parameters are not needed at all. Had put this on hold
for other components. Will fix.

>> 
>> + 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.
> 

Will fix.

>> + 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?

This is a decoder.

>> + ff_set_dimensions(avctx, s->width, s->height);
> 
> Missing error check.
> 

Will fix.

[...]

>> + // 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;
>> +

[...]

>> --- /dev/null
>> +++ b/libavformat/flifdec.c
>> @@ -0,0 +1,377 @@
>> +/*
>> + * FLIF16 demuxer
>> + * Copyright (c) 2020 Anamitra Ghorui <aghorui@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

[...]

>> + 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.
> 

How so?

>> + *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.
> 

Will check.

[...]

>> 
>> + st = avformat_new_stream(s, NULL);
> 
> Missing error check.
> 

Will fix

>> + 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.
> 

Should the dictionary be populated with empty values then?

>> +
>> + // 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.
> 

Will do.

>> + if (out_buf)
> 
> Unnecessary, av_freep() accepts NULL.
> 

Will do.

[...]

> 
> Regards,
> 
> --
> Nicolas George
> 

Thanks,
Anamitra
Nicolas George Aug. 2, 2020, 3:13 p.m. UTC | #3
Anamitra Ghorui (12020-08-02):
> Thanks a lot for the code review. We will make sure to correct all of
> these mistakes after we are done with all of the features in about a
> week, before we post our (supposed) final patch for the decoder.

Thanks.

> For some reason my mail client has truncated the indentation (and any
> series of multiple spaces) in the blockquotes. I apologise for that.

This is a good reason to consider going for a better mail client ;-)

> No. Initialisation to 0 was done for testing purposes. Ideally, only
> initialisation in the "fill" mode should involve preliminiary setting.

You can consider using --enable-memory-poisoning instead.

> Please see:
> * https://github.com/FLIF-hub/FLIF/blob/master/src/maniac/chance.cpp ,
>   function `build_table()`
> * libavcodec/rangecoder.c, function ff_build_rac_states()
> * and function below, build_table()
> 
> You will see that these two functions are about 1:1, and the code in
> FLIF's reference decoder has been adapted for a more generic case.
> The credits were added out of suspicion over who is the original author
> of the function. I don't know whether this is the only way to write the
> function. A few more functions were more or less copied over from the 
> reference decoder (such as log4kf below) but I don't think they are 
> useful anymore. Please see below (Multiscale Bitchances).

I think you should add a comment near the functions that were taken
there.

/*
 * Ported from code by ...
 * https://github.com/FLIF-hub/FLIF/blob/master/src/maniac/chance.cpp
 */

But beware. This is Apache 2.0, and therefore incompatible with GPL 2
(according to https://www.gnu.org/licenses/license-list.en.html), and
probably not LGPL 2 either. Since these are the default for FFmpeg, it
will require configure checks.

Another possibility is to rewrite it from scratch, using a different
enough style.

> >> +static const uint32_t flif16_multiscale_alphas[] = {
> >> + 21590903, 66728412, 214748365, 7413105, 106514140, 10478104
> >> +};
> > 
> > Please add a short comment to explain.
> > 
> 
> FLIF's reference sourcecode has 2 probability models (or chances) which
> are non interchangeable. This is the multiscale version of the
> probability model (as opposed to the simple one). However, FLIF's
> upstream sourcecode does not have this enabled by default (This is a 
> compile tine option). This means that all FLIF encoded files in
> circulation do not use the multiscale chances/probability table for
> their encoded data, and since FLIF development is dead, this is not
> going to change. Should I remove this?

I'm just saying saying it would be a good thing to know where these
magic-looking numbers come from.

/* Copied from the reference implementation, but I have no clue why they
   use precisely these numbers. */

for example. (Numbers do not warrant copyright, no license problem
here.)

> > What is this __PLN__?
> "Print Line Number". Will remove it. Was there for debugging purposes.

Is it a feature of your compiler? If not, I suggest you avoid using
__-prefix for macros, as they are strictly reserved for the compiler and
libc.

> >> + if (bytestream2_get_le32(&s->gb) != (*((uint32_t *) flif16_header))) {
> > You can't do that. Was it tested on big endian?
> I thought I would be able to get away from using strcmp, but I haven't
> tested on big endian machines. I thought the byte order would be the
> same if I used bytestream2_get_le32. Will see.

strcmp() should be inlined here. But you can avoid it by using either
MKTAG or AV_RL32.

> >> +static int flif16_write_frame(AVCodecContext *avctx, AVFrame *data)

> > Why a decoder context for an encoder?
> This is a decoder.

My bad, I saw write_frame().

> >> + *out_buf = av_realloc(*out_buf, (*out_buf_size) * 2);
> >> + if (!out_buf)
> >> + return AVERROR(ENOMEM);
> > Leaks original out_buf.
> How so?

With:

	b = realloc(a, size);

if the allocation fails, the original buffer is preserved, and still
accessible through variable a. Most (correct) programs will either exit
immediately, letting a be freed by the system, or free it and return an
error.

But some programs could continue without the extra memory (if it's a
cache, it will just continue slower), or want to save the contents of a
in emergency. This is why a is not freed if the reallocation fails.

If you write

	a = realloc(a, size);

and the reallocation fails, a is not freed, but the pointer to it is
immediately overwritten with the NULL return value. It leaks.

BSD has reallocf(), that does like realloc() but frees the memory in
case of failure. FFmpeg has av_realloc_f() for the same task, with the
extra bonus that it has the two parameters form to avoid multiplication
overflows.

> >> + tag[i] = avio_r8(pb);
> >> 
> >> + #else
> >> + avio_skip(pb, 3);
> >> + #endif
> > Unnecessary: you can fill tag even if zlib is not available.
> Should the dictionary be populated with empty values then?

No, the other hunk is fine. I mean just this hunk: you can read the 3
chars into tag and then do nothing with it, that's completely equivalent
to discarding them.

Although, if zlib is missing, printing a warning to notify the user that
some data was lost due to a missing library would probably be a good
idea.

Regards,
Kartik K. Khullar Aug. 2, 2020, 7:09 p.m. UTC | #4
On Sun, Aug 2, 2020 at 5:57 PM Nicolas George <george@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@teknik.io>
> > Co-authored-by: Kartik K Khullar <kartikkhullar840@gmail.com>
> >
> > Signed-off-by: Anamitra Ghorui <aghorui@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
> > +@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@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@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@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@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@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@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@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@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@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@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@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
Kartik K. Khullar Aug. 2, 2020, 8:47 p.m. UTC | #5
My apologies, I should have removed other parts of the quoted code which I
was not replying to.
The reply is unnecesarily long now.

On Mon, 3 Aug, 2020, 12:39 am Kartik K. Khullar, <kartikkhullar840@gmail.com>
wrote:

>
>
> On Sun, Aug 2, 2020 at 5:57 PM Nicolas George <george@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@teknik.io>
>> > Co-authored-by: Kartik K Khullar <kartikkhullar840@gmail.com>
>> >
>> > Signed-off-by: Anamitra Ghorui <aghorui@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
>> > +@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@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@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@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@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@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) {
>> > +
>
>
Kartik K. Khullar Aug. 3, 2020, 6:10 p.m. UTC | #6
Wow,
That is such an awesome idea.
Did not know about that offsetof() thing earlier. Definitely going to use
this idea.


> IIRC, the Linux kernel makes heavy use of this structure.
>

That's really cool.

Actually I implemented linked lists and not dynamic arrays because some
elements from somewhere in the middle of the list were to be removed while
processing the transform, and dynamic arrays would just not be suitable for
such
usage because then there will be empty blocks lying around in the array all
over.
So that's why I thought of going with a linked list so that I will keep
deleting nodes
from anywhere I want and no problem would arise.

I will try and implement this structure making the list doubly and then add
a
sentinel node and then process it the same way you just suggested.
It will make deletion of nodes much much simpler since I will just have to
pass the
address of the node of list which has to be deleted and offsetof()
arithmetic will help us
find the whole Object and then we will remove it.
Before I was passing position of the node to be deleted and then the list
was traversed
all over till that node and then it was deleted. Definitely was a very
inefficient way.

Thank You so much.
Kartik.
diff mbox series

Patch

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
+@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@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]
+{
+    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));
+    *prop_ranges_size = size;
+    prop_ranges = av_mallocz(sizeof(*prop_ranges) * size);
+    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) {
+        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);
+
+        if (!frames[j].data) {
+            return AVERROR(ENOMEM);
+        }
+
+        for (int i = 0; i < (s->num_planes + lookback); ++i) {
+            printf("Plane: %d ", i);
+            switch (plane_mode[i]) {
+                case FLIF16_PLANEMODE_NORMAL:
+                    frames[j].data[i] = av_mallocz(sizeof(int32_t) * s->width * s->height);
+                    break;
+
+                case FLIF16_PLANEMODE_CONSTANT:
+                    frames[j].data[i] = av_mallocz(sizeof(int32_t));
+                    ((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);;
+                    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) {
+        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);
+    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@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;
+} 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;
+} 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{
+    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));
+    }
+}
+
+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));
+    }
+}
+#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@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_HEADER = 1,
+    FLIF16_METADATA,
+    FLIF16_BITSTREAM
+} FLIF16ParseStates;
+
+typedef struct FLIF16ParseContext {
+    ParseContext pc;
+    int state;          ///< The section of the file the parser is in currently.
+    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) {
+            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);
+
+                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);
+                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,
+ *               2010-2016, Jon Sneyers & Pieter Wuille,
+ *               2020, Anamitra Ghorui <aghorui@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);
+    }
+}
+
+void ff_flif16_rac_free(FLIF16RangeCoder *rc)
+{
+    if (!rc)
+        return;
+    av_freep(rc);
+}
+
+// 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);
+    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;
+    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_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:
+            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)));
+                if (!m->forest[channel]->data)
+                    return AVERROR(ENOMEM);
+
+                m->stack = av_mallocz(MANIAC_TREE_BASE_SIZE * sizeof(*(m->stack)));
+            
+                if (!(m->stack))
+                    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;
+                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;
+
+            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);
+            }
+            ++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)));
+                if(!(m->stack))
+                    return AVERROR(ENOMEM);
+                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));
+        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;
+                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@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
+};
+
+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])];
+} 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
+    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));
+
+    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)
+{
+    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:
+            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 */
+            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];
+}
+
+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:
+            RAC_NZ_MULTISCALE_GET(rc, ctx, NZ_INT_ZERO, &(temp));
+            if (temp) {
+                *target = 0;
+                goto end;
+            }
+            ++rc->segment;__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 */
+            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:
+                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@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];
+
+    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 {
+    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);
+    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);
+    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);
+    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);
+    }
+}
+
+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
+
+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) {
+        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);
+        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;
+        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)
+{
+    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 = {
+    .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_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:
+            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;
+    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]]);
+            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:
+            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;
+            }
+            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;
+    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)
+            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));
+    if (!data->bounds)
+        return -1;
+    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:
+    if (ctx->i < dec_ctx->num_planes) {
+        switch (ctx->segment) {
+            case 0:
+                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 {
+        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;
+        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;
+        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;
+            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:
+        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;
+    // 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);
+            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]);
+        }
+        //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:
+            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:
+        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;
+    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;
+    }
+    av_assert0(temp);
+    elem->next = temp->next;
+    temp->next = elem;
+
+    return list;
+}
+
+static ColorValCB_list *ff_remove_colorvalCB(ColorValCB_list *list,
+                                             unsigned int pos)
+{
+    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)
+{
+    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 {
+        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);
+        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)
+     ||
+    (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;
+    
+    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;
+    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;
+    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;
+    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:
+            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,
+                            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,
+                                     &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;
+            data->e = av_mallocz(data->nb * sizeof(*data->e));
+            if (!data->e)
+                return -1;
+            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) {
+                       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);
+            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;
+    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];
+    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;
+    }
+    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@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@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);
+    }
+
+    if (bytestream2_get_le32(&s->gb) != (*((uint32_t *) flif16_header))) {
+        av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
+        return AVERROR(EINVAL);
+    }
+
+    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);
+            }
+        }
+        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);
+            }
+            
+            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);
+                    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);
+                    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);
+                    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);
+                    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);
+    }
+
+    // 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:
+            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)
+{
+    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
+                        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;
+    ff_set_dimensions(avctx, s->width, s->height);
+    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) {
+            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@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);
+        *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);
+    }
+
+    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);
+    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
+    
+        // 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
+    if (out_buf)
+        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,
+};