From patchwork Wed Jul 29 19:05:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anamitra Ghorui X-Patchwork-Id: 21372 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 88C1344AFFE for ; Wed, 29 Jul 2020 22:06:31 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5C2D868BA53; Wed, 29 Jul 2020 22:06:31 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail.teknik.io (mail.teknik.io [5.79.72.163]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 26FA268BA26 for ; Wed, 29 Jul 2020 22:06:25 +0300 (EEST) dkim-signature: v=1; a=rsa-sha256; d=teknik.io; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From:Subject:Date:Message-ID:To:CC; bh=G6n8WVwZMX+ivqiF6fDedsqub+bazd/gvVtWOFeDXDA=; b=KWm4fC8PC3iAvPsvzrQgnSIVCq5ijjec3rR4XzyI9/lVF1D/1FEcexLM7vSbuW5mhEjfBcUgPvTJnZctQWFY5IwPwnhR0kmDzsy6NLqLKdWFc2uzpsxYA29W8cOX3Z+a3wthbgruEz/Al8VzLtRRcaMbj76CfQvQooyLZXposH4zpt09EzmhsEg2OQDKGhGbTG0LbM1FmaNiXIv+LpcWOVejw6Cs5LO33jehiSxwLwWr86voxyU+a0cqZx I8mhsZMK1/fOaYjmSMUveQsLpqag0rKgmaQgA2ELS4bVC6EMH/2JzbMDUiDOjsiOHOo0MRVfr28ActxLKWUHO36dUtFw== Received: from localhost.localdomain (Unknown [103.82.156.1]) by mail.teknik.io with ESMTPSA (version=TLSv1.2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128) ; Wed, 29 Jul 2020 12:06:22 -0700 From: Anamitra Ghorui To: ffmpeg-devel@ffmpeg.org Date: Thu, 30 Jul 2020 00:35:55 +0530 Message-Id: <20200729190555.1772-1-aghorui@teknik.io> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] [RFC] lavc, lavfmt: add FLIF decoding support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Anamitra Ghorui MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This patch implements non interlaced decoding of FLIF16 images with all transforms except for one, FrameLookback which is being tested. Several test files have been attached. The above mentioned transform and interlaced decoding is being tested and will be implemented shortly. The main reason of posting this patch now is to ask advice on deflate decompression (or inflate) on the metadata segments of the format. The reference decoder of the format [1] uses lodepng, and by extension, deflate for generating the metadata segments. Therefore these segments should be able to be decoded by zlib's deflate routines. However it does not work and returns saying that the data is invalid. I have tried isolating the metadata using a hex editor, and then using zlib's example program [2] to decode it. However it also says that it's invalid data. Can you please tell me what I am doing wrong in libavformat/flifdec.c? [1]: https://github.com/FLIF-hub/FLIF [2]: https://zlib.net/zpipe.c Co-authored-by: Anamitra Ghorui Co-authored-by: Karhtik K. Khullar Signed-off-by: Anamitra Ghorui --- Changelog | 2 + configure | 2 + doc/general.texi | 2 + libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 + libavcodec/flif16.c | 198 +++ libavcodec/flif16.h | 278 +++ libavcodec/flif16_parser.c | 185 ++ libavcodec/flif16_rangecoder.c | 463 +++++ libavcodec/flif16_rangecoder.h | 824 +++++++++ libavcodec/flif16_transform.c | 2963 ++++++++++++++++++++++++++++++++ libavcodec/flif16_transform.h | 123 ++ libavcodec/flif16dec.c | 1129 ++++++++++++ libavcodec/gifdec.c | 2 +- libavcodec/parsers.c | 1 + libavcodec/version.h | 4 +- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/flifdec.c | 367 ++++ libavformat/gifdec.c | 1 - libavformat/version.h | 4 +- 23 files changed, 6555 insertions(+), 6 deletions(-) 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 cb310a3abc..2316c6128b 100644 --- a/Changelog +++ b/Changelog @@ -43,6 +43,8 @@ version : - Rayman 2 ADPCM decoder - Rayman 2 APM demuxer - cas video filter +- FLIF16 decoder +- FLIF16 demuxer version 4.2: diff --git a/configure b/configure index 06e3a7b2a8..872ee750e0 100755 --- a/configure +++ b/configure @@ -2709,6 +2709,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 dbdc348598..09f2d883ac 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -885,6 +885,8 @@ following image formats are supported: @item Flash Screen Video v2 @tab X @tab X @item Flash Video (FLV) @tab X @tab X @tab Sorenson H.263 used in Flash +@item FLIF (Free Lossless Image Format @tab @tab X + @tab Precursor to JPEG XL and FUIF @item FM Screen Capture Codec @tab @tab X @item Forward Uncompressed @tab @tab X @item Fraps @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index f1c032b456..88be94acae 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -319,6 +319,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 @@ -1046,6 +1047,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 674995df72..732bbe938d 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/avcodec.h b/libavcodec/avcodec.h index 894a9e5565..4e2af45dd0 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -461,6 +461,7 @@ enum AVCodecID { AV_CODEC_ID_MVDV, AV_CODEC_ID_MVHA, AV_CODEC_ID_CDTOONS, + 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/codec_desc.c b/libavcodec/codec_desc.c index 52178e7afe..993ec450c1 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1754,6 +1754,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("CDToons video"), .props = 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/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 + * + * 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 + * + * 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 +#include + +#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..7321047fba --- /dev/null +++ b/libavcodec/flif16_parser.c @@ -0,0 +1,185 @@ +/* + * FLIF16 parser + * Copyright (c) 2020 Anamitra Ghorui + * + * 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 +#include + +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. + */ + return buf_size; + } + } + 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; + } + + *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..b4e3f76749 --- /dev/null +++ b/libavcodec/flif16_rangecoder.c @@ -0,0 +1,463 @@ +/* + * Range coder for FLIF16 + * Copyright (c) 2004, Michael Niedermayer, + * 2010-2016, Jon Sneyers & Pieter Wuille, + * 2020, Anamitra Ghorui + * + * 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) { + 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 + * + * 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 + + +#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..f71aa22ebb --- /dev/null +++ b/libavcodec/flif16_transform.c @@ -0,0 +1,2963 @@ +/* + * Transforms for FLIF16. + * Copyright (c) 2020 Kartik K. Khullar + * + * 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(&r_ctx, p, prev_planes, minv, maxv, v); + else + ff_flif16_ranges_snap(data->ranges, p, prev_planes, 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>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>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; pr_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; + 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 + * + * 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..52116bfa58 --- /dev/null +++ b/libavcodec/flif16dec.c @@ -0,0 +1,1129 @@ +/* + * FLIF16 Decoder + * Copyright (c) 2020 Anamitra Ghorui + * + * 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 "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); + ++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: + 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 + * ============================================================================ + */ + +// TODO rework parameters + +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); + } + if (ranges_ctx->num_planes > 3) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, 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); + } else { + properties[index++] = 0; + } + + if (nobordercases || r > 1) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-2, c) - top; + } else { + properties[index++] = 0; + } + + if (nobordercases || c > 1) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r, c-2) - 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 (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++) { + 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) { + 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; + + switch (s->segment) { + case 0: + s->grays = compute_grays(s->range); + 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 + + 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 used 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; + printf("rgb24\n"); + + 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 not supported\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/gifdec.c b/libavcodec/gifdec.c index 1906a4c738..38315414aa 100644 --- a/libavcodec/gifdec.c +++ b/libavcodec/gifdec.c @@ -468,7 +468,7 @@ static int gif_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, A { GifState *s = avctx->priv_data; int ret; - + printf("[%s]\n", __func__); bytestream2_init(&s->gb, avpkt->data, avpkt->size); s->frame->pts = avpkt->pts; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 33a71de8a0..8b6eb954b3 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/libavcodec/version.h b/libavcodec/version.h index 36536c3725..c051ac0754 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,8 +28,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 73 -#define LIBAVCODEC_VERSION_MICRO 102 +#define LIBAVCODEC_VERSION_MINOR 74 +#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \ diff --git a/libavformat/Makefile b/libavformat/Makefile index e0681058a2..663d4d7031 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -188,6 +188,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 0209bf0e30..627629d201 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -146,6 +146,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..48bfec9d24 --- /dev/null +++ b/libavformat/flifdec.c @@ -0,0 +1,367 @@ +/* + * FLIF16 demuxer + * Copyright (c) 2020 Anamitra Ghorui + * + * 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 +#if CONFIG_ZLIB +#include +#endif + +#define BUF_SIZE 4096 + +typedef struct FLIFDemuxContext { + const AVClass *class; +#if 0 +// CONFIG_ZLIB + z_stream stream; + uint8_t active; +#endif + int64_t duration; +} FLIFDemuxContext; + + +#if 0 +// CONFIG_ZLIB +static int flif_inflate(FLIFDemuxContext *s, unsigned char *buf, int buf_size, + unsigned char *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, buf_size); + if (!out_buf) + return AVERROR(ENOMEM); + } + + stream->next_in = buf; + stream->avail_in = buf_size; + if(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 + + ret = inflate(stream, Z_PARTIAL_FLUSH); + + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + (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 - 1] = '\0'; + (void) inflateEnd(stream); + } else + ret = AVERROR(EAGAIN); + + return ret; // Return Z_BUF_ERROR/EAGAN 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 0 + 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 0 + // CONFIG_ZLIB + // TODO see why this does not work. + // Decompression Routines + while (metadata_size > 0) { + ret = avio_read(pb, metadata_buf, FFMIN(METADATA_BUF_SIZE, metadata_size)); + metadata_size -= ret; + if((ret = flif_inflate(dc, metadata_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 0 + // 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); + } + loops = (!loops) ? 1 : loops; + ++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; + } + goto end; + } + + need_more_data: + avio_read_partial(pb, buf, BUF_SIZE); + bytestream2_init(&gb, buf, BUF_SIZE); + } + + end: + + if (bpc > 65535) { + av_log(s, AV_LOG_ERROR, "depth per channel greater than 16 bits not supported\n"); + return AVERROR_PATCHWELCOME; + } + + format = flif16_out_frame_type[FFMIN(num_planes, 4)][bpc > 255]; + + // The minimum possible delay in a FLIF16 image is 1 millisecond. + // Therefore time base is 10^-3, i.e. 1/1000 + 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); + 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, +}; diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index a31644c2a8..58e2d368ca 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -268,7 +268,6 @@ static int gif_read_packet(AVFormatContext *s, AVPacket *pkt) keyframe, frame_parsed = 0, ret; int64_t frame_start = avio_tell(pb), frame_end; unsigned char buf[6]; - if ((ret = avio_read(pb, buf, 6)) == 6) { keyframe = memcmp(buf, gif87a_sig, 6) == 0 || memcmp(buf, gif89a_sig, 6) == 0; diff --git a/libavformat/version.h b/libavformat/version.h index 4724269b3c..a233b67351 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,8 +32,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 58 -#define LIBAVFORMAT_VERSION_MINOR 39 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 40 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \