[FFmpeg-devel] [PATCH v2] [RFC] lavc, lavfmt: add FLIF decoding support
Anamitra Ghorui
aghorui at teknik.io
Thu Jul 30 16:41:36 EEST 2020
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 at teknik.io>
Co-authored-by: Kartik K Khullar <kartikkhullar840 at gmail.com>
Signed-off-by: Anamitra Ghorui <aghorui at teknik.io>
---
Changelog | 3 +-
configure | 2 +
doc/general.texi | 2 +
libavcodec/Makefile | 2 +
libavcodec/allcodecs.c | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/flif16.c | 198 +++
libavcodec/flif16.h | 278 +++
libavcodec/flif16_parser.c | 189 ++
libavcodec/flif16_rangecoder.c | 464 +++++
libavcodec/flif16_rangecoder.h | 824 +++++++++
libavcodec/flif16_transform.c | 2964 ++++++++++++++++++++++++++++++++
libavcodec/flif16_transform.h | 123 ++
libavcodec/flif16dec.c | 1146 ++++++++++++
libavcodec/parsers.c | 1 +
libavformat/Makefile | 1 +
libavformat/allformats.c | 1 +
libavformat/flifdec.c | 377 ++++
19 files changed, 6583 insertions(+), 1 deletion(-)
create mode 100644 libavcodec/flif16.c
create mode 100644 libavcodec/flif16.h
create mode 100644 libavcodec/flif16_parser.c
create mode 100644 libavcodec/flif16_rangecoder.c
create mode 100644 libavcodec/flif16_rangecoder.h
create mode 100644 libavcodec/flif16_transform.c
create mode 100644 libavcodec/flif16_transform.h
create mode 100644 libavcodec/flif16dec.c
create mode 100644 libavformat/flifdec.c
diff --git a/Changelog b/Changelog
index 6f648bff2b..ac5a21b1a9 100644
--- a/Changelog
+++ b/Changelog
@@ -10,7 +10,8 @@ version <next>:
- ADPCM IMA Ubisoft APM encoder
- Rayman 2 APM muxer
- AV1 encoding support SVT-AV1
-
+- FLIF16 decoder
+- FLIF16 demuxer
version 4.3:
- v360 filter
diff --git a/configure b/configure
index 169f23e17f..50936fef4a 100755
--- a/configure
+++ b/configure
@@ -2718,6 +2718,8 @@ ffvhuff_encoder_select="huffyuv_encoder"
fic_decoder_select="golomb"
flac_decoder_select="flacdsp"
flac_encoder_select="bswapdsp flacdsp lpc"
+flif16_decoder_select="flif16dec"
+flif16_encoder_select="flif16enc"
flashsv2_decoder_deps="zlib"
flashsv2_encoder_deps="zlib"
flashsv_decoder_deps="zlib"
diff --git a/doc/general.texi b/doc/general.texi
index dfcfd394e6..71b61100e3 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -903,6 +903,8 @@ following image formats are supported:
@item Flash Screen Video v2 @tab X @tab X
@item Flash Video (FLV) @tab X @tab X
@tab Sorenson H.263 used in Flash
+ at item FLIF (Free Lossless Image Format @tab @tab X
+ @tab Precursor to JPEG XL and FUIF
@item FM Screen Capture Codec @tab @tab X
@item Forward Uncompressed @tab @tab X
@item Fraps @tab @tab X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 9d4d52d048..96d06d2479 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -328,6 +328,7 @@ OBJS-$(CONFIG_FLASHSV_ENCODER) += flashsvenc.o
OBJS-$(CONFIG_FLASHSV2_ENCODER) += flashsv2enc.o
OBJS-$(CONFIG_FLASHSV2_DECODER) += flashsv.o
OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o
+OBJS-$(CONFIG_FLIF16_DECODER) += flif16dec.o flif16_rangecoder.o flif16.o flif16_transform.o
OBJS-$(CONFIG_FMVC_DECODER) += fmvc.o
OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o
OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o
@@ -1069,6 +1070,7 @@ OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o
OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o
OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o \
vorbis_data.o
+OBJS-$(CONFIG_FLIF16_PARSER) += flif16_parser.o
OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o
OBJS-$(CONFIG_G729_PARSER) += g729_parser.o
OBJS-$(CONFIG_GIF_PARSER) += gif_parser.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 80142899fe..032ff422f8 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -119,6 +119,7 @@ extern AVCodec ff_flashsv_decoder;
extern AVCodec ff_flashsv2_encoder;
extern AVCodec ff_flashsv2_decoder;
extern AVCodec ff_flic_decoder;
+extern AVCodec ff_flif16_decoder;
extern AVCodec ff_flv_encoder;
extern AVCodec ff_flv_decoder;
extern AVCodec ff_fmvc_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index ced00bd34c..4ca0d1f514 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1784,6 +1784,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("PFM (Portable FloatMap) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
},
+ {
+ .id = AV_CODEC_ID_FLIF16,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "flif16",
+ .long_name = NULL_IF_CONFIG_SMALL("FLIF16 (Free Lossless Image Format)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
/* various PCM "codecs" */
{
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 896ecb0ce0..5c4f2dd7d0 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -296,6 +296,7 @@ enum AVCodecID {
AV_CODEC_ID_MV30,
AV_CODEC_ID_NOTCHLC,
AV_CODEC_ID_PFM,
+ AV_CODEC_ID_FLIF16,
/* various PCM "codecs" */
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/flif16.c b/libavcodec/flif16.c
new file mode 100644
index 0000000000..d8ffb31c34
--- /dev/null
+++ b/libavcodec/flif16.c
@@ -0,0 +1,198 @@
+/*
+ * FLIF16 Image Format Definitions
+ * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * FLIF16 format definitions and functions.
+ */
+
+#include "flif16.h"
+#include "flif16_transform.h"
+
+/**
+ * Initialise property ranges for non interlaced images.
+ * @param[out] prop_ranges resultant ranges
+ * @param[in] color ranges of each channel
+ * @param[in] channels number of channels
+ */
+int32_t (*ff_flif16_maniac_ni_prop_ranges_init(unsigned int *prop_ranges_size,
+ FLIF16RangesContext *ranges,
+ uint8_t plane,
+ uint8_t channels))[2]
+{
+ 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 at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * FLIF16 format definitions and functions.
+ */
+
+#ifndef AVCODEC_FLIF16_H
+#define AVCODEC_FLIF16_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "avcodec.h"
+#include "libavutil/pixfmt.h"
+#include "flif16_rangecoder.h"
+
+#define MAX_PLANES 5
+#define MAX_PREDICTORS 2
+
+#define VARINT_APPEND(a,x) (a) = ((a) << 7) | (uint32_t) ((x) & 127)
+#define ZOOM_ROWPIXELSIZE(zoomlevel) (1 << (((zoomlevel) + 1) / 2))
+#define ZOOM_COLPIXELSIZE(zoomlevel) (1 << (((zoomlevel)) / 2))
+#define ZOOM_HEIGHT(r, z) ((!z) ? 0 : (1 + ((r) - 1) / ZOOM_ROWPIXELSIZE(z)))
+#define ZOOM_WIDTH(w, z) ((!z) ? 0 : (1 + ((w) - 1) / ZOOM_COLPIXELSIZE(z)))
+#define MEDIAN3(a, b, c) (((a) < (b)) ? (((b) < (c)) ? (b) : ((a) < (c) ? (c) : (a))) : (((a) < (c)) ? (a) : ((b) < (c) ? (c) : (b))))
+
+static const uint8_t flif16_header[4] = "FLIF";
+
+// Pixeldata types
+static const enum AVPixelFormat flif16_out_frame_type[][2] = {
+ { -1, -1 }, // Padding
+ { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16 },
+ { -1 , -1 }, // Padding
+ { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGB48 },
+ { AV_PIX_FMT_RGB32, AV_PIX_FMT_RGBA64 }
+};
+
+typedef enum FLIF16Plane {
+ FLIF16_PLANE_Y = 0,
+ FLIF16_PLANE_CO,
+ FLIF16_PLANE_CG,
+ FLIF16_PLANE_ALPHA,
+ FLIF16_PLANE_LOOKBACK, // Frame lookback
+ FLIF16_PLANE_GRAY = 0, // Is this needed?
+} FLIF16Plane;
+
+typedef enum FLIF16PlaneMode {
+ FLIF16_PLANEMODE_CONSTANT = 0, ///< A true constant plane
+ FLIF16_PLANEMODE_NORMAL, ///< A normal pixel matrix
+ FLIF16_PLANEMODE_FILL /**< A constant plane that is later manipulated
+ by transforms, making it nonconstant and
+ allocating a plane for it */
+
+} FLIF16PlaneMode;
+
+typedef struct FLIF16PixelData {
+ int8_t seen_before; // Required by FrameDup
+ uint32_t *col_begin; // Required by FrameShape
+ uint32_t *col_end; // Required by FrameShape
+ int s_r[MAX_PLANES];
+ int s_c[MAX_PLANES];
+ void **data;
+} 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 at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ /**
+ * @file
+ * FLIF16 parser
+ */
+
+#include "flif16.h"
+#include "parser.h"
+#include "libavutil/avassert.h"
+#include "libavutil/bswap.h"
+
+#include <stdio.h> //remove
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef enum FLIF16ParseStates {
+ FLIF16_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 at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+ /**
+ * @file
+ * Range coder for FLIF16
+ */
+
+#include "avcodec.h"
+#include "libavutil/common.h"
+#include "flif16_rangecoder.h"
+#include "flif16.h"
+
+// TODO write separate function for RAC encoder
+
+// The coder requires a certain number of bytes for initiialization. buf
+// provides it. gb is used by the coder functions for actual coding.
+void ff_flif16_rac_init(FLIF16RangeCoder *rc, GetByteContext *gb, uint8_t *buf,
+ uint8_t buf_size)
+{
+ GetByteContext gbi;
+ if(!rc)
+ return;
+
+ if(buf_size < FLIF16_RAC_MAX_RANGE_BYTES)
+ return;
+
+ bytestream2_init(&gbi, buf, buf_size);
+
+ rc->range = FLIF16_RAC_MAX_RANGE;
+ rc->gb = gb;
+
+ for (uint32_t r = FLIF16_RAC_MAX_RANGE; r > 1; r >>= 8) {
+ rc->low <<= 8;
+ rc->low |= bytestream2_get_byte(&gbi);
+ }
+}
+
+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 at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Range coder for FLIF16.
+ */
+
+#ifndef FLIF16_RANGECODER_H
+#define FLIF16_RANGECODER_H
+
+#include "libavutil/mem.h"
+#include "libavutil/intmath.h"
+#include "bytestream.h"
+#include "rangecoder.h"
+
+#include <stdint.h>
+
+
+#define FLIF16_RAC_MAX_RANGE_BITS 24
+#define FLIF16_RAC_MAX_RANGE_BYTES (FLIF16_RAC_MAX_RANGE_BITS / 8)
+#define FLIF16_RAC_MIN_RANGE_BITS 16
+#define FLIF16_RAC_MAX_RANGE (uint32_t) 1 << FLIF16_RAC_MAX_RANGE_BITS
+#define FLIF16_RAC_MIN_RANGE (uint32_t) 1 << FLIF16_RAC_MIN_RANGE_BITS
+
+#define CHANCETABLE_DEFAULT_ALPHA (0xFFFFFFFF / 19)
+#define CHANCETABLE_DEFAULT_CUT 2
+
+// #define MULTISCALE_CHANCES_ENABLED
+
+#define MULTISCALE_CHANCETABLE_DEFAULT_SIZE 6
+#define MULTISCALE_CHANCETABLE_DEFAULT_CUT 8
+
+#define MANIAC_TREE_BASE_SIZE 1600
+#define MANIAC_TREE_MIN_COUNT 1
+#define MANIAC_TREE_MAX_COUNT 512
+
+typedef enum FLIF16RACReader {
+ FLIF16_RAC_BIT = 0,
+ FLIF16_RAC_UNI_INT8,
+ FLIF16_RAC_UNI_INT16,
+ FLIF16_RAC_UNI_INT32,
+ FLIF16_RAC_CHANCE,
+ FLIF16_RAC_NZ_INT,
+ FLIF16_RAC_GNZ_INT,
+#ifdef MULTISCALE_CHANCES_ENABLED
+ FLIF16_RAC_NZ_MULTISCALE_INT,
+ FLIF16_RAC_GNZ_MULTISCALE_INT
+#endif
+} FLIF16RACReader;
+
+typedef struct FLIF16ChanceTable {
+ uint16_t zero_state[4096];
+ uint16_t one_state[4096];
+} FLIF16ChanceTable;
+
+typedef struct FLIF16MultiscaleChanceTable {
+ FLIF16ChanceTable sub_table[MULTISCALE_CHANCETABLE_DEFAULT_SIZE];
+} FLIF16MultiscaleChanceTable;
+
+
+typedef struct FLIF16Log4kTable {
+ uint16_t table[4097];
+ int scale;
+} FLIF16Log4kTable;
+
+static const uint32_t flif16_multiscale_alphas[] = {
+ 21590903, 66728412, 214748365, 7413105, 106514140, 10478104
+};
+
+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 at gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Transforms for FLIF16.
+ */
+
+#include "flif16_transform.h"
+#include "flif16_rangecoder.h"
+#include "libavutil/common.h"
+
+
+// Transform private structs and internal functions
+
+typedef struct transform_priv_ycocg {
+ int origmax4;
+ FLIF16RangesContext *r_ctx;
+} transform_priv_ycocg;
+
+typedef struct transform_priv_permuteplanes {
+ uint8_t subtract;
+ uint8_t permutation[5];
+ FLIF16RangesContext *r_ctx;
+
+ uint8_t from[4], to[4];
+ FLIF16ChanceContext ctx_a;
+} transform_priv_permuteplanes;
+
+typedef struct transform_priv_channelcompact {
+ FLIF16ColorVal *CPalette[4];
+ unsigned int CPalette_size[4];
+ FLIF16ColorVal *CPalette_inv[4];
+ unsigned int CPalette_inv_size[4];
+
+ 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 at gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Transforms for FLIF16.
+ */
+
+#ifndef FLIF16_TRANSFORM_H
+#define FLIF16_TRANSFORM_H
+
+#include "avcodec.h"
+#include "libavutil/common.h"
+#include "flif16.h"
+
+typedef enum FLIF16RangesTypes{
+ FLIF16_RANGES_CHANNELCOMPACT,
+ FLIF16_RANGES_YCOCG,
+ FLIF16_RANGES_PERMUTEPLANES,
+ FLIF16_RANGES_PERMUTEPLANESSUBTRACT,
+ FLIF16_RANGES_BOUNDS,
+ FLIF16_RANGES_STATIC,
+ FLIF16_RANGES_PALETTEALPHA,
+ FLIF16_RANGES_PALETTE,
+ FLIF16_RANGES_COLORBUCKETS,
+ FLIF16_RANGES_FRAMELOOKBACK
+} FLIF16RangesTypes;
+
+typedef enum FLIF16TransformsTypes {
+ FLIF16_TRANSFORM_CHANNELCOMPACT,
+ FLIF16_TRANSFORM_YCOCG,
+ FLIF16_TRANSFORM_RESERVED1,
+ FLIF16_TRANSFORM_PERMUTEPLANES,
+ FLIF16_TRANSFORM_BOUNDS,
+ FLIF16_TRANSFORM_PALETTEALPHA,
+ FLIF16_TRANSFORM_PALETTE,
+ FLIF16_TRANSFORM_COLORBUCKETS,
+ FLIF16_TRANSFORM_RESERVED2,
+ FLIF16_TRANSFORM_RESERVED3,
+ FLIF16_TRANSFORM_DUPLICATEFRAME,
+ FLIF16_TRANSFORM_FRAMESHAPE,
+ FLIF16_TRANSFORM_FRAMELOOKBACK,
+} FLIF16TransformsTypes;
+
+extern FLIF16Ranges *flif16_ranges[14];
+extern FLIF16Transform *flif16_transforms[13];
+
+FLIF16RangesContext *ff_flif16_ranges_static_init(unsigned int channels,
+ unsigned int bpc);
+
+void ff_flif16_ranges_close(FLIF16RangesContext* r_ctx);
+
+static inline FLIF16ColorVal ff_flif16_ranges_min(FLIF16RangesContext *r_ctx, int p)
+{
+ FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no];
+ if(ranges->min)
+ return ranges->min(r_ctx, p);
+ else
+ return 0;
+}
+
+static inline FLIF16ColorVal ff_flif16_ranges_max(FLIF16RangesContext *r_ctx, int p)
+{
+ FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no];
+ if(ranges->max)
+ return ranges->max(r_ctx, p);
+ else
+ return 0;
+}
+
+static inline void ff_flif16_ranges_minmax(FLIF16RangesContext *r_ctx, int p,
+ FLIF16ColorVal *prev_planes,
+ FLIF16ColorVal *minv, FLIF16ColorVal *maxv)
+{
+ flif16_ranges[r_ctx->r_no]->minmax(r_ctx, p, prev_planes, minv, maxv);
+}
+
+static inline void ff_flif16_ranges_snap(FLIF16RangesContext *r_ctx, int p,
+ FLIF16ColorVal *prev_planes, FLIF16ColorVal *minv,
+ FLIF16ColorVal *maxv, FLIF16ColorVal *v)
+{
+ flif16_ranges[r_ctx->r_no]->snap(r_ctx, p, prev_planes, minv, maxv, v);
+}
+
+FLIF16TransformContext *ff_flif16_transform_init(int, FLIF16RangesContext *);
+
+void ff_flif16_transform_configure(FLIF16TransformContext *, const int);
+
+
+// Maybe put FLIF16Context at first in list
+int ff_flif16_transform_read(FLIF16TransformContext *, FLIF16Context *,
+ FLIF16RangesContext *);
+
+FLIF16RangesContext* ff_flif16_transform_meta(FLIF16Context *,
+ FLIF16PixelData *,
+ uint32_t,
+ FLIF16TransformContext *,
+ FLIF16RangesContext *);
+
+int ff_flif16_transform_reverse(FLIF16Context *, FLIF16TransformContext*, FLIF16PixelData*,
+ uint8_t, uint8_t);
+
+void ff_flif16_transforms_close(FLIF16TransformContext *);
+
+#endif /* FLIF16_TRANSFORM_H */
diff --git a/libavcodec/flif16dec.c b/libavcodec/flif16dec.c
new file mode 100644
index 0000000000..18216f5991
--- /dev/null
+++ b/libavcodec/flif16dec.c
@@ -0,0 +1,1146 @@
+/*
+ * FLIF16 Decoder
+ * Copyright (c) 2020 Anamitra Ghorui <aghorui at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * FLIF16 Decoder
+*/
+
+#include <stdio.h> // Remove
+
+#include "flif16.h"
+#include "flif16_rangecoder.h"
+#include "flif16_transform.h"
+
+#include "avcodec.h"
+#include "libavutil/common.h"
+#include "bytestream.h"
+#include "avcodec.h"
+#include "internal.h"
+
+/*
+ * Due to the nature of the format, the decoder has to take the entirety of the
+ * data before it can generate any frames. The decoder has to return
+ * AVERROR(EAGAIN) as long as the bitstream is incomplete.
+ */
+
+
+// TODO make variable size UNI_INT readers
+typedef struct FLIF16DecoderContext {
+
+ /* Inheritance from FLIF16Context */
+
+ GetByteContext gb;
+ FLIF16MANIACContext maniac_ctx;
+ FLIF16RangeCoder rc;
+
+ // Dimensions and other things.
+ uint32_t width;
+ uint32_t height;
+ uint32_t num_frames;
+ uint32_t meta; ///< Size of a meta chunk
+
+ // Primary Header
+ uint8_t ia; ///< Is image interlaced or/and animated or not
+ uint32_t bpc; ///< 2 ^ Bytes per channel
+ uint8_t num_planes; ///< Number of planes
+
+ // change to uint8_t
+ uint32_t loops; ///< Number of times animation loops
+ // change to uint32_t
+ uint32_t *framedelay; ///< Frame delay for each frame
+
+ uint8_t plane_mode[MAX_PLANES];
+
+ // Transform flags
+ uint8_t framedup;
+ uint8_t frameshape;
+ uint8_t framelookback;
+ /* End Inheritance from FLIF16Context */
+
+ FLIF16PixelData *frames;
+ uint32_t out_frames_count;
+ AVFrame *out_frame;
+ int64_t pts;
+
+ uint8_t buf[FLIF16_RAC_MAX_RANGE_BYTES]; ///< Storage for initial RAC buffer
+ uint8_t buf_count; ///< Count for initial RAC buffer
+ int state; ///< The section of the file the parser is in currently.
+ unsigned int segment; ///< The "segment" the code is supposed to jump to
+ unsigned int segment2;///< The "segment" the code is supposed to jump to
+ int i; ///< A generic iterator used to save states between for loops.
+ int i2;
+ int i3;
+
+ // Secondary Header
+ uint8_t alphazero; ///< Alphazero Flag
+ uint8_t custombc; ///< Custom Bitchance Flag
+ uint8_t customalpha; ///< Custom alphadiv & cutoff flag
+
+ uint8_t cut; ///< Chancetable custom cutoff
+ uint32_t alpha; ///< Chancetable custom alphadivisor
+ uint8_t ipp; ///< Invisible pixel predictor
+
+ // Transforms
+ // Size dynamically maybe
+ FLIF16TransformContext *transforms[13];
+ uint8_t transform_top;
+ FLIF16RangesContext *range; ///< The minimum and maximum values a
+ /// channel's pixels can take. Changes
+ /// depending on transformations applied
+ FLIF16RangesContext *prev_range;
+
+ // MANIAC Trees
+ int32_t (*prop_ranges)[2]; ///< Property Ranges
+ uint32_t prop_ranges_size;
+
+ // Pixeldata
+ uint8_t curr_plane; ///< State variable. Current plane under processing
+ FLIF16ColorVal *grays;
+ FLIF16ColorVal *properties;
+ FLIF16ColorVal guess; ///< State variable. Stores guess
+ FLIF16ColorVal min, max;
+ uint32_t c; ///< State variable for current column
+
+ // Interlaced Pixeldata
+ int *zoomlevels;
+ int zooms;
+ int rough_zl;
+ int quality;
+ int scale;
+ int *predictors;
+ int breakpoints;
+} FLIF16DecoderContext;
+
+// Cast values to FLIF16Context for some functions.
+#define CTX_CAST(x) ((FLIF16Context *) (x))
+
+// TODO Remove PIXEL and PIXELY. Concerned with interlaced decoding
+#define PIXEL(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame, p, z, r, c)
+#define PIXELY(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame, FLIF16_PLANE_Y, z, r, c)
+
+#define PIXEL_SET(ctx, fr, p, r, c, val) ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val)
+#define PIXEL_GET(ctx, fr, p, r, c) ff_flif16_pixel_get(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c)
+#define PIXEL_SETZ(ctx, fr, p, z, r, c, val) ff_flif16_pixel_setz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c, val)
+#define PIXEL_GETZ(ctx, fr, p, z, r, c) ff_flif16_pixel_getz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c)
+#define PIXEL_GETFAST(ctx, fr, p, r, c) ff_flif16_pixel_get(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c)
+#define PIXEL_SETFAST(ctx, fr, p, r, c, val) ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val)
+
+// If frame_dup exists, figure out what the previous frame actually is
+#define PREV_FRAME(frames, f_no) (((frames)[(f_no) - 1].seen_before >= 0) ? &(frames)[(frames)[(f_no) - 1].seen_before] : &(frames)[(f_no) - 1])
+#define PREV_FRAMENUM(frames, f_no) (((frames)[(f_no) - 1].seen_before >= 0) ? (frames)[(f_no) - 1].seen_before : (f_no) - 1)
+
+// Static property values
+static const int properties_ni_rgb_size[] = {7, 8, 9, 7, 7};
+static const int properties_ni_rgba_size[] = {8, 9, 10, 7, 7};
+static const int properties_rgb_size[] = {8, 10, 9, 8, 8};
+static const int properties_rgba_size[] = {9, 11, 10, 8, 8};
+
+// From reference decoder:
+//
+// The order in which the planes are encoded.
+// lookback (Lookback) (animations-only, value refers to a previous frame) has
+// to be first, because all other planes are not encoded if lookback != 0
+// Alpha has to be next, because for fully transparent A=0 pixels, the other
+// planes are not encoded
+// Y (luma) is next (the first channel for still opaque images), because it is
+// perceptually most important
+// Co and Cg are in that order because Co is perceptually slightly more
+// important than Cg [citation needed]
+static const int plane_ordering[] = {4,3,0,1,2}; // lookback (lookback), A, Y, Co, Cg
+
+enum FLIF16States {
+ FLIF16_HEADER = 0,
+ FLIF16_SECONDHEADER,
+ FLIF16_TRANSFORM,
+ FLIF16_ROUGH_PIXELDATA,
+ FLIF16_MANIAC,
+ FLIF16_PIXELDATA,
+ FLIF16_OUTPUT,
+ FLIF16_CHECKSUM,
+ FLIF16_EOS
+};
+
+static int flif16_read_header(AVCodecContext *avctx)
+{
+ uint8_t temp, count = 4;
+ FLIF16DecoderContext *s = avctx->priv_data;
+ // TODO Make do without this array
+ uint32_t *vlist[] = { &s->width, &s->height, &s->num_frames };
+
+ s->cut = CHANCETABLE_DEFAULT_CUT;
+ s->alpha = CHANCETABLE_DEFAULT_ALPHA;
+
+ // Minimum size has been empirically found to be 8 bytes.
+ if (bytestream2_size(&s->gb) < 8) {
+ av_log(avctx, AV_LOG_ERROR, "buf size too small (%d)\n",
+ bytestream2_size(&s->gb));
+ return AVERROR(EINVAL);
+ }
+
+ 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 at teknik.io>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * FLIF demuxer.
+ */
+
+#include "avformat.h"
+#include "libavutil/bprint.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "internal.h"
+#include "libavcodec/flif16.h"
+#include "libavcodec/flif16_rangecoder.h"
+
+#include "config.h"
+
+// Remove later
+#include <stdio.h>
+
+
+// Uncomment to disable metadata reading
+// #undef CONFIG_ZLIB
+
+#if CONFIG_ZLIB
+#include <zlib.h>
+#endif
+
+#define BUF_SIZE 4096
+
+typedef struct FLIFDemuxContext {
+ const AVClass *class;
+#if CONFIG_ZLIB
+ z_stream stream;
+ uint8_t active;
+#endif
+ int64_t duration;
+} FLIFDemuxContext;
+
+
+#if CONFIG_ZLIB
+static int flif_inflate(FLIFDemuxContext *s, uint8_t *buf, int buf_size,
+ uint8_t **out_buf, int *out_buf_size)
+{
+ int ret;
+ z_stream *stream = &s->stream;
+
+ if (!s->active) {
+ s->active = 1;
+ stream->zalloc = Z_NULL;
+ stream->zfree = Z_NULL;
+ stream->opaque = Z_NULL;
+ stream->avail_in = 0;
+ stream->next_in = Z_NULL;
+ ret = inflateInit(stream);
+
+ if (ret != Z_OK)
+ return ret;
+
+ *out_buf_size = buf_size;
+ *out_buf = av_realloc(*out_buf, *out_buf_size);
+ if (!*out_buf)
+ return AVERROR(ENOMEM);
+ }
+
+ stream->next_in = buf;
+ stream->avail_in = buf_size;
+ while (stream->total_out >= *out_buf_size) {
+ *out_buf = av_realloc(*out_buf, (*out_buf_size) * 2);
+ if (!out_buf)
+ return AVERROR(ENOMEM);
+ *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,
+};
--
2.17.1
More information about the ffmpeg-devel
mailing list