From patchwork Thu Jul 30 13:41:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anamitra Ghorui X-Patchwork-Id: 21380 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 E5E3344AACC for ; Thu, 30 Jul 2020 16:41:44 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id BFA4A68BAB6; Thu, 30 Jul 2020 16:41:44 +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 7194068B942 for ; Thu, 30 Jul 2020 16:41:37 +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:MIME-Version:Content-Type:Content-Transfer-Encoding:In-Reply-To:References; bh=s9ukYrFymBKonQQIeWMsNqy07JuYQa3OHRjxloqL+bk=; b=diHIL7lJQ0IOALE2mxiCOdZgKb1obMsadwKhGMazdwMVRal6ALmAPB+rwxlqcQhjiUTceOZ7QsmccBfSj7M9JB27jYDDi3cxz3Efi4XVALVg1OHPazb/YupCC++qeWNy6D8w+lR73HoRCmObxXbY/Q8J06LLzuvzO01reVI1qxGqM1bdQ4UxLehNb0iif0As0JnsLy2rx5KBJxPJecwabQ3rkYaF2WTO4b8fwSUYEAe87FvdF6fUUAF0zc DIKt7Pakltw6bdtFriwnY112Q4uOn4nz8eoHlXewCp0RxR/nJcyUE256pwuyISnVmwjfJv4Dwc8t3VfjdCHAWcDumfcg== Received: from mail.teknik.io (TEKNIK-SERVER [5.79.72.163]) by mail.teknik.io with ESMTPSA (version=TLSv1.2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128) ; Thu, 30 Jul 2020 06:41:36 -0700 Mime-Version: 1.0 Date: Thu, 30 Jul 2020 13:41:36 +0000 X-Mailer: RainLoop/1.11.3 From: "Anamitra Ghorui" Message-ID: To: "FFmpeg development discussions and patches" In-Reply-To: <20200729190555.1772-1-aghorui@teknik.io> References: <20200729190555.1772-1-aghorui@teknik.io> Subject: [FFmpeg-devel] [PATCH v2] [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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Visible errors have been fixed in libavformat/flifdec.c, however the problem regarding metadata decoding still exists. The function does work with dummy data from zlib's example program (see https://0x0.st/ix_E.zip for an example with "1234" as the encoded sequence), so the problem may be in providing the appropriate parameters. Other test files: https://0x0.st/ixSs.7z Co-authored-by: Anamitra Ghorui Co-authored-by: Kartik K Khullar Signed-off-by: Anamitra Ghorui --- Changelog | 3 +- configure | 2 + doc/general.texi | 2 + libavcodec/Makefile | 2 + libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 + libavcodec/codec_id.h | 1 + libavcodec/flif16.c | 198 +++ libavcodec/flif16.h | 278 +++ libavcodec/flif16_parser.c | 189 ++ libavcodec/flif16_rangecoder.c | 464 +++++ libavcodec/flif16_rangecoder.h | 824 +++++++++ libavcodec/flif16_transform.c | 2964 ++++++++++++++++++++++++++++++++ libavcodec/flif16_transform.h | 123 ++ libavcodec/flif16dec.c | 1146 ++++++++++++ libavcodec/parsers.c | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/flifdec.c | 377 ++++ 19 files changed, 6583 insertions(+), 1 deletion(-) create mode 100644 libavcodec/flif16.c create mode 100644 libavcodec/flif16.h create mode 100644 libavcodec/flif16_parser.c create mode 100644 libavcodec/flif16_rangecoder.c create mode 100644 libavcodec/flif16_rangecoder.h create mode 100644 libavcodec/flif16_transform.c create mode 100644 libavcodec/flif16_transform.h create mode 100644 libavcodec/flif16dec.c create mode 100644 libavformat/flifdec.c diff --git a/Changelog b/Changelog index 6f648bff2b..ac5a21b1a9 100644 --- a/Changelog +++ b/Changelog @@ -10,7 +10,8 @@ version : - ADPCM IMA Ubisoft APM encoder - Rayman 2 APM muxer - AV1 encoding support SVT-AV1 - +- FLIF16 decoder +- FLIF16 demuxer version 4.3: - v360 filter diff --git a/configure b/configure index 169f23e17f..50936fef4a 100755 --- a/configure +++ b/configure @@ -2718,6 +2718,8 @@ ffvhuff_encoder_select="huffyuv_encoder" fic_decoder_select="golomb" flac_decoder_select="flacdsp" flac_encoder_select="bswapdsp flacdsp lpc" +flif16_decoder_select="flif16dec" +flif16_encoder_select="flif16enc" flashsv2_decoder_deps="zlib" flashsv2_encoder_deps="zlib" flashsv_decoder_deps="zlib" diff --git a/doc/general.texi b/doc/general.texi index dfcfd394e6..71b61100e3 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -903,6 +903,8 @@ following image formats are supported: @item Flash Screen Video v2 @tab X @tab X @item Flash Video (FLV) @tab X @tab X @tab Sorenson H.263 used in Flash +@item FLIF (Free Lossless Image Format @tab @tab X + @tab Precursor to JPEG XL and FUIF @item FM Screen Capture Codec @tab @tab X @item Forward Uncompressed @tab @tab X @item Fraps @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 9d4d52d048..96d06d2479 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -328,6 +328,7 @@ OBJS-$(CONFIG_FLASHSV_ENCODER) += flashsvenc.o OBJS-$(CONFIG_FLASHSV2_ENCODER) += flashsv2enc.o OBJS-$(CONFIG_FLASHSV2_DECODER) += flashsv.o OBJS-$(CONFIG_FLIC_DECODER) += flicvideo.o +OBJS-$(CONFIG_FLIF16_DECODER) += flif16dec.o flif16_rangecoder.o flif16.o flif16_transform.o OBJS-$(CONFIG_FMVC_DECODER) += fmvc.o OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o @@ -1069,6 +1070,7 @@ OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o \ vorbis_data.o +OBJS-$(CONFIG_FLIF16_PARSER) += flif16_parser.o OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o OBJS-$(CONFIG_G729_PARSER) += g729_parser.o OBJS-$(CONFIG_GIF_PARSER) += gif_parser.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 80142899fe..032ff422f8 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -119,6 +119,7 @@ extern AVCodec ff_flashsv_decoder; extern AVCodec ff_flashsv2_encoder; extern AVCodec ff_flashsv2_decoder; extern AVCodec ff_flic_decoder; +extern AVCodec ff_flif16_decoder; extern AVCodec ff_flv_encoder; extern AVCodec ff_flv_decoder; extern AVCodec ff_fmvc_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index ced00bd34c..4ca0d1f514 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1784,6 +1784,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PFM (Portable FloatMap) image"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_FLIF16, + .type = AVMEDIA_TYPE_VIDEO, + .name = "flif16", + .long_name = NULL_IF_CONFIG_SMALL("FLIF16 (Free Lossless Image Format)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 896ecb0ce0..5c4f2dd7d0 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -296,6 +296,7 @@ enum AVCodecID { AV_CODEC_ID_MV30, AV_CODEC_ID_NOTCHLC, AV_CODEC_ID_PFM, + AV_CODEC_ID_FLIF16, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavcodec/flif16.c b/libavcodec/flif16.c new file mode 100644 index 0000000000..d8ffb31c34 --- /dev/null +++ b/libavcodec/flif16.c @@ -0,0 +1,198 @@ +/* + * FLIF16 Image Format Definitions + * Copyright (c) 2020 Anamitra Ghorui + * + * 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..c795b44b4d --- /dev/null +++ b/libavcodec/flif16_parser.c @@ -0,0 +1,189 @@ +/* + * 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 //remove +#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. + */ + printf("\n", buf_size); + return buf_size; + } + } + printf("End not found\n"); + return next; +} + +static int flif16_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + FLIF16ParseContext *fpc = s->priv_data; + int next; + + next = flif16_find_frame(fpc, buf, buf_size); + + if (ff_combine_frame(&fpc->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + printf("Width:%u\nHeight:%u\nFrames:%u\nEnd:%d\n", + fpc->width, fpc->height, fpc->frames, buf_size); + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_flif16_parser = { + .codec_ids = { AV_CODEC_ID_FLIF16 }, + .priv_data_size = sizeof(FLIF16ParseContext), + .parser_parse = flif16_parse, + .parser_close = ff_parse_close, +}; + diff --git a/libavcodec/flif16_rangecoder.c b/libavcodec/flif16_rangecoder.c new file mode 100644 index 0000000000..c8f1b7bbb0 --- /dev/null +++ b/libavcodec/flif16_rangecoder.c @@ -0,0 +1,464 @@ +/* + * Range coder for FLIF16 + * Copyright (c) 2004, Michael Niedermayer, + * 2010-2016, Jon Sneyers & Pieter Wuille, + * 2020, Anamitra Ghorui + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + /** + * @file + * Range coder for FLIF16 + */ + +#include "avcodec.h" +#include "libavutil/common.h" +#include "flif16_rangecoder.h" +#include "flif16.h" + +// TODO write separate function for RAC encoder + +// The coder requires a certain number of bytes for initiialization. buf +// provides it. gb is used by the coder functions for actual coding. +void ff_flif16_rac_init(FLIF16RangeCoder *rc, GetByteContext *gb, uint8_t *buf, + uint8_t buf_size) +{ + GetByteContext gbi; + if(!rc) + return; + + if(buf_size < FLIF16_RAC_MAX_RANGE_BYTES) + return; + + bytestream2_init(&gbi, buf, buf_size); + + rc->range = FLIF16_RAC_MAX_RANGE; + rc->gb = gb; + + for (uint32_t r = FLIF16_RAC_MAX_RANGE; r > 1; r >>= 8) { + rc->low <<= 8; + rc->low |= bytestream2_get_byte(&gbi); + } +} + +void ff_flif16_rac_free(FLIF16RangeCoder *rc) +{ + if (!rc) + return; + av_freep(rc); +} + +// TODO Maybe restructure rangecoder.c/h to fit a more generic case +static void build_table(uint16_t *zero_state, uint16_t *one_state, size_t size, + uint32_t factor, unsigned int max_p) +{ + const int64_t one = 1LL << 32; + int64_t p = one / 2; + unsigned int last_p8 = 0, p8; + unsigned int i; + + for (i = 0; i < size / 2; i++) { + p8 = (size * p + one / 2) >> 32; + if (p8 <= last_p8) + p8 = last_p8 + 1; + if (last_p8 && last_p8 < size && p8 <= max_p) + one_state[last_p8] = p8; + p += ((one - p) * factor + one / 2) >> 32; + last_p8 = p8; + } + + for (i = size - max_p; i <= max_p; i++) { + if (one_state[i]) + continue; + p = (i * one + size / 2) / size; + p += ((one - p) * factor + one / 2) >> 32; + p8 = (size * p + one / 2) >> 32; //FIXME try without the one + if (p8 <= i) + p8 = i + 1; + if (p8 > max_p) + p8 = max_p; + one_state[i] = p8; + } + + for (i = 1; i < size; i++) + zero_state[i] = size - one_state[size - i]; +} + +static inline uint32_t log4kf(int x, uint32_t base) +{ + int bits = 8 * sizeof(int) - ff_clz(x); + uint64_t y = ((uint64_t)x) << (32 - bits); + uint32_t res = base * (13 - bits); + uint32_t add = base; + while ((add > 1) && ((y & 0x7FFFFFFF) != 0)) { + y = (((uint64_t)y) * y + 0x40000000) >> 31; + add >>= 1; + if ((y >> 32) != 0) { + res -= add; + y >>= 1; + } + } + return res; +} + +void ff_flif16_build_log4k_table(FLIF16Log4kTable *log4k) +{ + log4k->table[0] = 0; + for (int i = 1; i < 4096; i++) + log4k->table[i] = (log4kf(i, (65535UL << 16) / 12) + + (1 << 15)) >> 16; + log4k->scale = 65535 / 12; +} + +void ff_flif16_chancetable_init(FLIF16ChanceTable *ct, int alpha, int cut) +{ + build_table(ct->zero_state, ct->one_state, 4096, alpha, 4096 - cut); +} + +void ff_flif16_chancecontext_init(FLIF16ChanceContext *ctx) +{ + if(!ctx) + return; + memcpy(&ctx->data, &flif16_nz_int_chances, sizeof(flif16_nz_int_chances)); +} + +#ifdef MULTISCALE_CHANCES_ENABLED +FLIF16MultiscaleChanceTable *ff_flif16_multiscale_chancetable_init(void) +{ + unsigned int len = MULTISCALE_CHANCETABLE_DEFAULT_SIZE; + FLIF16MultiscaleChanceTable *ct = av_malloc(sizeof(*ct)); + if (!ct) + return null + for (int i = 0; i < len; ++i) { + ff_flif16_chancetable_init(&ct->sub_table[i], + flif16_multiscale_alphas[i], + MULTISCALE_CHANCETABLE_DEFAULT_CUT); + } + return ct; +} + +/** + * Allocate and set all chances according to flif16_nz_int_chances + */ +void ff_flif16_multiscale_chancecontext_init(FLIF16MultiscaleChanceContext *ctx) +{ + for (int i = 0; i < sizeof(flif16_nz_int_chances) / + sizeof(flif16_nz_int_chances[0]); ++i) + ff_flif16_multiscale_chance_set(&ctx->data[i], flif16_nz_int_chances[i]); + return ctx; +} + +#endif + +int ff_flif16_read_maniac_tree(FLIF16RangeCoder *rc, + FLIF16MANIACContext *m, + int32_t (*prop_ranges)[2], + unsigned int prop_ranges_size, + unsigned int channel) +{ + int oldp = 0, p = 0, split_val = 0, temp; + + switch (rc->segment2) { + default: case 0: + rc->segment2 = 0; + if (!(m->forest[channel])) { + m->forest[channel] = av_mallocz(sizeof(*(m->forest[channel]))); + if (!(m->forest[channel])) + return AVERROR(ENOMEM); + m->forest[channel]->data = av_mallocz(MANIAC_TREE_BASE_SIZE * + sizeof(*(m->forest[channel]->data))); + if (!m->forest[channel]->data) + return AVERROR(ENOMEM); + + m->stack = av_mallocz(MANIAC_TREE_BASE_SIZE * sizeof(*(m->stack))); + + if (!(m->stack)) + return AVERROR(ENOMEM); + + for (int i = 0; i < 3; ++i) { + #ifdef MULTISCALE_CHANCES_ENABLED + ff_flif16_multiscale_chancecontext_init(&m->ctx[i]); + #else + ff_flif16_chancecontext_init(&m->ctx[i]); + #endif + } + m->stack_top = m->tree_top = 0; + m->forest[channel]->size = MANIAC_TREE_BASE_SIZE; + m->stack_size = MANIAC_TREE_BASE_SIZE; + m->stack[m->stack_top].id = m->tree_top; + m->stack[m->stack_top].mode = 0; + ++m->stack_top; + ++m->tree_top; + } + ++rc->segment2; + + case 1: + start: + if(!m->stack_top) + goto end; + + oldp = m->stack[m->stack_top - 1].p; + if (!m->stack[m->stack_top - 1].visited) { + switch (m->stack[m->stack_top - 1].mode) { + case 1: + prop_ranges[oldp][0] = m->stack[m->stack_top - 1].min; + prop_ranges[oldp][1] = m->stack[m->stack_top - 1].max; + break; + + case 2: + prop_ranges[oldp][0] = m->stack[m->stack_top - 1].min; + break; + } + } else { + prop_ranges[oldp][1] = m->stack[m->stack_top - 1].max2; + --m->stack_top; + rc->segment2 = 1; + goto start; + } + m->stack[m->stack_top - 1].visited = 1; + ++rc->segment2; + + case 2: + #ifdef MULTISCALE_CHANCES_ENABLED + RAC_GET(rc, &m->ctx[0], 0, prop_ranges_size, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].property, + FLIF16_RAC_GNZ_MULTISCALE_INT); + #else + RAC_GET(rc, &m->ctx[0], 0, prop_ranges_size, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].property, + FLIF16_RAC_GNZ_INT); + #endif + p = --(m->forest[channel]->data[m->stack[m->stack_top - 1].id].property); + if (p == -1) { + --m->stack_top; + rc->segment2 = 1; + goto start; + } + + m->forest[channel]->data[m->stack[m->stack_top - 1].id].child_id = m->tree_top; + rc->oldmin = prop_ranges[p][0]; + rc->oldmax = prop_ranges[p][1]; + if (rc->oldmin >= rc->oldmax) { + printf("!!! rc->oldmin >= rc->oldmax\n"); + return AVERROR(EINVAL); + } + ++rc->segment2; + + case 3: + #ifdef MULTISCALE_CHANCES_ENABLED + RAC_GET(rc, &m->ctx[1], MANIAC_TREE_MIN_COUNT, MANIAC_TREE_MAX_COUNT, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].count, + FLIF16_RAC_GNZ_MULTISCALE_INT); + #else + RAC_GET(rc, &m->ctx[1], MANIAC_TREE_MIN_COUNT, MANIAC_TREE_MAX_COUNT, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].count, + FLIF16_RAC_GNZ_INT); + #endif + ++rc->segment2; + + case 4: + #ifdef MULTISCALE_CHANCES_ENABLED + RAC_GET(rc, &m->ctx[2], rc->oldmin, rc->oldmax - 1, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].split_val, + FLIF16_RAC_GNZ_MULTISCALE_INT); + #else + RAC_GET(rc, &m->ctx[2], rc->oldmin, rc->oldmax - 1, + &m->forest[channel]->data[m->stack[m->stack_top - 1].id].split_val, + FLIF16_RAC_GNZ_INT); + #endif + split_val = m->forest[channel]->data[m->stack[m->stack_top - 1].id].split_val; + ++rc->segment2; + + case 5: + if ((m->tree_top + 2) >= m->forest[channel]->size) { + m->forest[channel]->data = av_realloc(m->forest[channel]->data, + (m->forest[channel]->size) * 2 * sizeof(*(m->forest[channel]->data))); + if(!(m->forest[channel]->data)) + return AVERROR(ENOMEM); + m->forest[channel]->size *= 2; + } + + if ((m->stack_top + 2) >= m->stack_size) { + m->stack = av_realloc(m->stack, (m->stack_size) * 2 * sizeof(*(m->stack))); + if(!(m->stack)) + return AVERROR(ENOMEM); + m->stack_size *= 2; + } + + temp = m->forest[channel]->data[m->stack[m->stack_top - 1].id].property; + + // Parent + m->stack[m->stack_top - 1].p = temp; + m->stack[m->stack_top - 1].max2 = rc->oldmax; + + // Right child + m->stack[m->stack_top].id = m->tree_top + 1; + m->stack[m->stack_top].p = temp; + m->stack[m->stack_top].min = rc->oldmin; + m->stack[m->stack_top].max = split_val; + m->stack[m->stack_top].mode = 1; + m->stack[m->stack_top].visited = 0; + ++m->stack_top; + + // Left Child + m->stack[m->stack_top].id = m->tree_top; + m->stack[m->stack_top].p = temp; + m->stack[m->stack_top].min = split_val + 1; + m->stack[m->stack_top].mode = 2; + m->stack[m->stack_top].visited = 0; + ++m->stack_top; + + m->tree_top += 2; + rc->segment2 = 1; + goto start; + } + + end: + m->forest[channel]->data = av_realloc(m->forest[channel]->data, + m->tree_top * sizeof(*m->forest[channel]->data)); // Maybe replace by fast realloc + if (!m->forest[channel]->data) + return AVERROR(ENOMEM); + m->forest[channel]->size = m->tree_top; + av_freep(&m->stack); + m->stack_top = 0; + rc->segment2 = 0; + return 0; + + need_more_data: + return AVERROR(EAGAIN); +} + +void ff_flif16_maniac_close(FLIF16MANIACContext *m, uint8_t num_planes) +{ + for (int i = 0; i < num_planes; ++i) { + if (!m->forest[i]) + continue; + if (m->forest[i]->data) + av_freep(&m->forest[i]->data); + if (m->forest[i]->leaves) + av_freep(&m->forest[i]->leaves); + av_freep(&m->forest[i]); + } + + av_freep(&m->forest); + // Should be already freed in maniac reading, but checking anyway. + if(m->stack) + av_freep(&m->stack); +} + +#ifdef MULTISCALE_CHANCES_ENABLED +FLIF16MultiscaleChanceContext *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m, + uint8_t channel, + int32_t *properties) +#else +FLIF16ChanceContext *ff_flif16_maniac_findleaf(FLIF16MANIACContext *m, + uint8_t channel, + int32_t *properties) +#endif +{ + unsigned int pos = 0; + uint32_t old_leaf; + uint32_t new_leaf; + FLIF16MANIACTree *tree = m->forest[channel]; + FLIF16MANIACNode *nodes = tree->data; + + if (!m->forest[channel]->leaves) { + m->forest[channel]->leaves = av_mallocz(MANIAC_TREE_BASE_SIZE * + sizeof(*m->forest[channel]->leaves)); + m->forest[channel]->leaves_size = MANIAC_TREE_BASE_SIZE; + if(!m->forest[channel]->leaves) + return NULL; + ff_flif16_chancecontext_init(&m->forest[channel]->leaves[0]); + tree->leaves_top = 1; + } + + while (nodes[pos].property != -1) { + if (nodes[pos].count < 0) { + if (properties[nodes[pos].property] > nodes[pos].split_val) + pos = nodes[pos].child_id; + else + pos = nodes[pos].child_id + 1; + } else if (nodes[pos].count > 0) { + --nodes[pos].count; + break; + } else { + --nodes[pos].count; + if ((tree->leaves_top) >= tree->leaves_size) { + m->forest[channel]->leaves = av_realloc(m->forest[channel]->leaves, + sizeof(*m->forest[channel]->leaves) * + m->forest[channel]->leaves_size * 2); + if (!m->forest[channel]->leaves) + return NULL; + m->forest[channel]->leaves_size *= 2; + } + old_leaf = nodes[pos].leaf_id; + new_leaf = tree->leaves_top; + memcpy(&m->forest[channel]->leaves[tree->leaves_top], + &m->forest[channel]->leaves[nodes[pos].leaf_id], + sizeof(*m->forest[channel]->leaves)); + ++tree->leaves_top; + nodes[nodes[pos].child_id].leaf_id = old_leaf; + nodes[nodes[pos].child_id + 1].leaf_id = new_leaf; + + if (properties[nodes[pos].property] > nodes[pos].split_val) + return &m->forest[channel]->leaves[old_leaf]; + else + return &m->forest[channel]->leaves[new_leaf]; + } + } + return &m->forest[channel]->leaves[m->forest[channel]->data[pos].leaf_id]; +} + +int ff_flif16_maniac_read_int(FLIF16RangeCoder *rc, + FLIF16MANIACContext *m, + int32_t *properties, + uint8_t channel, + int min, int max, int *target) +{ + if (!rc->maniac_ctx) + rc->segment2 = 0; + + switch(rc->segment2) { + case 0: + if (min == max) { + *target = min; + goto end; + } + rc->maniac_ctx = ff_flif16_maniac_findleaf(m, channel, properties); + if(!rc->maniac_ctx) { + return AVERROR(ENOMEM); + } + ++rc->segment2; + + case 1: + #ifdef MULTISCALE_CHANCES_ENABLED + RAC_GET(rc, rc->maniac_ctx, min, max, target, FLIF16_RAC_NZ_MULTISCALE_INT); + #else + RAC_GET(rc, rc->maniac_ctx, min, max, target, FLIF16_RAC_NZ_INT); + #endif + + } + + end: + rc->maniac_ctx = NULL; + rc->segment2 = 0; + return 1; + + need_more_data: + return 0; +} diff --git a/libavcodec/flif16_rangecoder.h b/libavcodec/flif16_rangecoder.h new file mode 100644 index 0000000000..9cd2d5ee22 --- /dev/null +++ b/libavcodec/flif16_rangecoder.h @@ -0,0 +1,824 @@ +/* + * Range coder for FLIF16 + * Copyright (c) 2020 Anamitra Ghorui + * + * 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..7b6cdef070 --- /dev/null +++ b/libavcodec/flif16_transform.c @@ -0,0 +1,2964 @@ +/* + * 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(src_ctx, p, prev_planes, minv, maxv, v); + else + ff_flif16_ranges_snap(data->ranges, p, prev_planes, minv, maxv, v); + // printf("min : %d max : %d v : %d\n", *minv, *maxv, *v); +} + +static void ff_framecombine_close(FLIF16RangesContext *r_ctx) +{ + ranges_priv_framecombine *data = r_ctx->priv_data; + FLIF16Ranges *range = flif16_ranges[data->ranges->r_no]; + if (range->close) + range->close(data->ranges); + av_free(data->ranges); +} + +FLIF16Ranges flif16_ranges_static = { + .priv_data_size = sizeof(ranges_priv_static), + .min = &ff_static_min, + .max = &ff_static_max, + .minmax = &ff_static_minmax, + .snap = &ff_static_snap, + .is_static = 1, + .close = &ff_static_close +}; + +FLIF16Ranges flif16_ranges_channelcompact = { + .priv_data_size = sizeof(ranges_priv_channelcompact), + .min = &ff_channelcompact_min, + .max = &ff_channelcompact_max, + .minmax = &ff_channelcompact_minmax, + .snap = &ff_static_snap, + .is_static = 1, + .close = NULL +}; + +FLIF16Ranges flif16_ranges_ycocg = { + .priv_data_size = sizeof(ranges_priv_ycocg), + .min = &ff_ycocg_min, + .max = &ff_ycocg_max, + .minmax = &ff_ycocg_minmax, + .snap = &ff_static_snap, + .is_static = 0, + .close = &ff_ycocg_close +}; + +FLIF16Ranges flif16_ranges_permuteplanessubtract = { + .priv_data_size = sizeof(ranges_priv_permuteplanes), + .min = &ff_permuteplanessubtract_min, + .max = &ff_permuteplanessubtract_max, + .minmax = &ff_permuteplanessubtract_minmax, + .snap = &ff_static_snap, + .is_static = 0, + .close = &ff_permuteplanes_close +}; + +FLIF16Ranges flif16_ranges_permuteplanes = { + .priv_data_size = sizeof(ranges_priv_permuteplanes), + .min = &ff_permuteplanes_min, + .max = &ff_permuteplanes_max, + .minmax = &ff_static_minmax, + .snap = &ff_static_snap, + .is_static = 0, + .close = &ff_permuteplanes_close +}; + +FLIF16Ranges flif16_ranges_bounds = { + .priv_data_size = sizeof(ranges_priv_bounds), + .min = &ff_bounds_min, + .max = &ff_bounds_max, + .minmax = &ff_bounds_minmax, + .snap = &ff_bounds_snap, + .is_static = 0, + .close = &ff_bounds_close +}; + +FLIF16Ranges flif16_ranges_palette = { + .priv_data_size = sizeof(ranges_priv_palette), + .min = &ff_palette_min, + .max = &ff_palette_max, + .minmax = &ff_palette_minmax, + .snap = &ff_static_snap, + .is_static = 0, + .close = &ff_palette_close +}; + +FLIF16Ranges flif16_ranges_palettealpha = { + .priv_data_size = sizeof(ranges_priv_palette), + .min = &ff_palettealpha_min, + .max = &ff_palettealpha_max, + .minmax = &ff_palettealpha_minmax, + .snap = &ff_static_snap, + .is_static = 0, + .close = &ff_palette_close +}; + +FLIF16Ranges flif16_ranges_colorbuckets = { + .priv_data_size = sizeof(ranges_priv_colorbuckets), + .min = &ff_colorbuckets_min, + .max = &ff_colorbuckets_max, + .minmax = &ff_colorbuckets_minmax, + .snap = &ff_colorbuckets_snap, + .is_static = 0, + .close = &ff_colorbuckets_close +}; + +FLIF16Ranges flif16_ranges_framecombine = { + .priv_data_size = sizeof(ranges_priv_framecombine), + .min = &ff_framecombine_min, + .max = &ff_framecombine_max, + .minmax = &ff_framecombine_minmax, + .snap = &ff_framecombine_snap, + .is_static = 0, + .close = &ff_framecombine_close +}; + +FLIF16Ranges *flif16_ranges[] = { + &flif16_ranges_channelcompact, // FLIF16_RANGES_CHANNELCOMPACT, + &flif16_ranges_ycocg, // FLIF16_RANGES_YCOCG, + &flif16_ranges_permuteplanes, // FLIF16_RANGES_PERMUTEPLANES, + &flif16_ranges_permuteplanessubtract, // FLIF16_RANGES_PERMUTEPLANESSUBTRACT, + &flif16_ranges_bounds, // FLIF16_RANGES_BOUNDS, + &flif16_ranges_static, // FLIF16_RANGES_STATIC, + &flif16_ranges_palettealpha, // FLIF16_RANGES_PALETTEALPHA, + &flif16_ranges_palette, // FLIF16_RANGES_PALETTE, + &flif16_ranges_colorbuckets, // FLIF16_RANGES_COLORBUCKETS, + &flif16_ranges_framecombine // FLIF16_RANGES_FRAMELOOKBACK +}; + +FLIF16RangesContext *ff_flif16_ranges_static_init(unsigned int channels, + unsigned int bpc) +{ + FLIF16Ranges *r = flif16_ranges[FLIF16_RANGES_STATIC]; + FLIF16RangesContext *ctx; + ranges_priv_static *data; + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + ctx->r_no = FLIF16_RANGES_STATIC; + ctx->num_planes = channels; + ctx->priv_data = av_mallocz(r->priv_data_size); + if (!ctx->priv_data) + return NULL; + data = ctx->priv_data; + data->bounds = av_mallocz(sizeof(*data->bounds) * channels); + if (!data->bounds) + return NULL; + for (unsigned int i = 0; i < channels; ++i) { + data->bounds[i][0] = 0; + data->bounds[i][1] = bpc; + } + return ctx; +} + +void ff_flif16_ranges_close(FLIF16RangesContext* r_ctx){ + FLIF16Ranges* ranges = flif16_ranges[r_ctx->r_no]; + if(ranges->close) + ranges->close(r_ctx); + if(ranges->priv_data_size) + av_free(r_ctx->priv_data); + av_freep(&r_ctx); +} + +static void ff_flif16_planes_get(FLIF16Context *ctx, FLIF16PixelData *frame, + FLIF16ColorVal *values, uint32_t row, uint32_t col) +{ + for (int i = 0; i < 3; i++) + values[i] = ff_flif16_pixel_get(ctx, frame, i, row, col); +} + +static void ff_flif16_planes_set(FLIF16Context *ctx, FLIF16PixelData *frame, + FLIF16ColorVal *values, uint32_t row, uint32_t col) +{ + for (int i = 0; i < 3; i++) + ff_flif16_pixel_set(ctx, frame, i, row, col, values[i]); +} + +/* + * ============================================================================= + * Transforms + * ============================================================================= + */ + +/* + * YCoCg + */ +static int transform_ycocg_init(FLIF16TransformContext *ctx, FLIF16RangesContext *r_ctx) +{ + transform_priv_ycocg *data = ctx->priv_data; + FLIF16Ranges *src_ranges = flif16_ranges[r_ctx->r_no]; + + av_assert0(data); + + if ( r_ctx->num_planes < 3 + || src_ranges->min(r_ctx, 0) == src_ranges->max(r_ctx, 0) + || src_ranges->min(r_ctx, 1) == src_ranges->max(r_ctx, 1) + || src_ranges->min(r_ctx, 2) == src_ranges->max(r_ctx, 2) + || src_ranges->min(r_ctx, 0) < 0 + || src_ranges->min(r_ctx, 1) < 0 + || src_ranges->min(r_ctx, 2) < 0) + return 0; + + data->origmax4 = FFMAX3(src_ranges->max(r_ctx, 0), + src_ranges->max(r_ctx, 1), + src_ranges->max(r_ctx, 2))/4 + 1; + data->r_ctx = r_ctx; + return 1; +} + +static FLIF16RangesContext *transform_ycocg_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + FLIF16RangesContext *r_ctx; + ranges_priv_ycocg *data; + transform_priv_ycocg *trans_data = t_ctx->priv_data; + r_ctx = av_mallocz(sizeof(FLIF16RangesContext)); + if (!r_ctx) + return NULL; + r_ctx->r_no = FLIF16_RANGES_YCOCG; + r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_ycocg)); + if (!r_ctx->priv_data) + return NULL; + data = r_ctx->priv_data; + + data->origmax4 = trans_data->origmax4; + data->r_ctx = trans_data->r_ctx; + r_ctx->num_planes = src_ctx->num_planes; + return r_ctx; +} + +static int transform_ycocg_forward(FLIF16Context *ctx, + FLIF16TransformContext *t_ctx, + FLIF16PixelData *pixel_data) +{ + int r, c; + FLIF16ColorVal RGB[3], YCOCG[3]; + + int height = ctx->height; + int width = ctx->width; + + for (r = 0; r>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; + printf("bounds[%d].min : %d bounds[%d].max : %d\n", ctx->i, data->bounds[ctx->i][0], ctx->i, data->bounds[ctx->i][1]); + ctx->i++; + ctx->segment--; + goto start; + } + } + else { + ctx->i = 0; + ctx->segment = 0; + } + + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static FLIF16RangesContext *transform_bounds_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + FLIF16RangesContext *r_ctx; + transform_priv_bounds *trans_data = t_ctx->priv_data; + ranges_priv_static *data; + ranges_priv_bounds *dataB; + + r_ctx = av_mallocz(sizeof(FLIF16RangesContext)); + if (!r_ctx) + return NULL; + r_ctx->num_planes = src_ctx->num_planes; + + if (flif16_ranges[src_ctx->r_no]->is_static) { + r_ctx->r_no = FLIF16_RANGES_STATIC; + r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_static)); + if (!r_ctx->priv_data) + return NULL; + data = r_ctx->priv_data; + data->bounds = trans_data->bounds; + } + else { + r_ctx->r_no = FLIF16_RANGES_BOUNDS; + r_ctx->priv_data = av_mallocz(sizeof(ranges_priv_bounds)); + if (!r_ctx->priv_data) + return NULL; + dataB = r_ctx->priv_data; + dataB->bounds = trans_data->bounds; + dataB->r_ctx = src_ctx; + } + return r_ctx; +} + +/* + * Palette + */ + +#define MAX_PALETTE_SIZE 30000 + +static int transform_palette_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_palette *data = ctx->priv_data; + + if ( (src_ctx->num_planes < 3) || + (ff_flif16_ranges_max(src_ctx, 0) == 0 + && ff_flif16_ranges_max(src_ctx, 2) == 0 + && src_ctx->num_planes > 3 + && ff_flif16_ranges_min(src_ctx, 3) == 1 + && ff_flif16_ranges_max(src_ctx, 3) == 1) || + (ff_flif16_ranges_min(src_ctx, 1) == ff_flif16_ranges_max(src_ctx, 1) + && ff_flif16_ranges_min(src_ctx, 2) == ff_flif16_ranges_max(src_ctx, 2))) + return 0; + + if (src_ctx->num_planes > 3) + data->has_alpha = 1; + else + data->has_alpha = 0; + + ff_flif16_chancecontext_init(&data->ctx); + ff_flif16_chancecontext_init(&data->ctxY); + ff_flif16_chancecontext_init(&data->ctxI); + ff_flif16_chancecontext_init(&data->ctxQ); + data->p = 0; + + return 1; +} + +static int transform_palette_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_palette *data = ctx->priv_data; + switch (ctx->i) + { + case 0: + RAC_GET(&dec_ctx->rc, &data->ctx, 1, MAX_PALETTE_SIZE, + &data->size, FLIF16_RAC_GNZ_INT); + data->Palette = av_mallocz(data->size * sizeof(*data->Palette)); + if (!data->Palette) + return -1; + ctx->i++; + + case 1: + RAC_GET(&dec_ctx->rc, &data->ctx, 0, 1, + &data->sorted, FLIF16_RAC_GNZ_INT); + if (data->sorted) { + ctx->i = 2; + for (int i = 0; i < 3; i++) { + data->min[i] = ff_flif16_ranges_min(src_ctx, i); + data->max[i] = ff_flif16_ranges_max(src_ctx, i); + data->Palette[0][i] = -1; + } + data->prev = data->Palette[0]; + } + else { + ctx->i = 5; + goto unsorted; + } + + loop: + if (data->p < data->size) { + case 2: + RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0], data->max[0], + &data->Y, FLIF16_RAC_GNZ_INT); + data->pp[0] = data->Y; + ff_flif16_ranges_minmax(src_ctx, 1, data->pp, &data->min[1], &data->max[1]); + ctx->i++; + + case 3: + RAC_GET(&dec_ctx->rc, &data->ctxI, + data->prev[0] == data->Y ? data->prev[1] : data->min[1], + data->max[1], + &data->I, FLIF16_RAC_GNZ_INT); + data->pp[1] = data->I; + ff_flif16_ranges_minmax(src_ctx, 2, data->pp, &data->min[2], &data->max[2]); + ctx->i++; + + case 4: + RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[2], data->max[2], + &data->Q, FLIF16_RAC_GNZ_INT); + data->Palette[data->p][0] = data->Y; + data->Palette[data->p][1] = data->I; + data->Palette[data->p][2] = data->Q; + data->min[0] = data->Y; + data->prev = data->Palette[data->p]; + data->p++; + ctx->i = 2; + goto loop; + } + else { + ctx->i = 0; + data->p = 0; + goto end; + } + + unsorted: + if (data->p < data->size) { + case 5: + ff_flif16_ranges_minmax(src_ctx, 0, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0], data->max[0], + &data->Y, FLIF16_RAC_GNZ_INT); + data->pp[0] = data->Y; + ctx->i++; + + case 6: + ff_flif16_ranges_minmax(src_ctx, 1, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxI, data->min[0], data->max[0], + &data->I, FLIF16_RAC_GNZ_INT); + data->pp[1] = data->I; + ctx->i++; + + case 7: + ff_flif16_ranges_minmax(src_ctx, 2, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[0], data->max[0], + &data->Q, FLIF16_RAC_GNZ_INT); + data->Palette[data->p][0] = data->Y; + data->Palette[data->p][1] = data->I; + data->Palette[data->p][2] = data->Q; + data->p++; + ctx->i = 5; + goto unsorted; + } + else { + data->p = 0; + ctx->i = 0; + goto end; + } + + } + end: + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static FLIF16RangesContext *transform_palette_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + FLIF16RangesContext *r_ctx; + transform_priv_palette *trans_data; + ranges_priv_palette *data; + + r_ctx = av_mallocz(sizeof(*r_ctx)); + if (!r_ctx) + return NULL; + trans_data = t_ctx->priv_data; + data = av_mallocz(sizeof(*data)); + if (!data) + return NULL; + // int i; + // for (i = 0; i < frame_count; i++) + // frame[i].palette = 1; + data->r_ctx = src_ctx; + data->nb_colors = trans_data->size; + r_ctx->r_no = FLIF16_RANGES_PALETTE; + r_ctx->num_planes = src_ctx->num_planes; + r_ctx->priv_data = data; + return r_ctx; +} + +static int transform_palette_reverse(FLIF16Context *ctx, + FLIF16TransformContext *t_ctx, + FLIF16PixelData *frame, + uint32_t stride_row, + uint32_t stride_col) +{ + int r, c; + int P; + transform_priv_palette *data = t_ctx->priv_data; + for (r = 0; r < ctx->height; r += stride_row) { + for (c = 0; c < ctx->width; c += stride_col) { + P = ff_flif16_pixel_get(ctx, frame, 1, r, c); + if (P < 0 || P >= data->size) + P = 0; + av_assert0(P < data->size); + av_assert0(P >= 0); + ff_flif16_pixel_set(ctx, frame, 0, r, c, data->Palette[P][0]); + ff_flif16_pixel_set(ctx, frame, 1, r, c, data->Palette[P][1]); + ff_flif16_pixel_set(ctx, frame, 2, r, c, data->Palette[P][2]); + } + //frame->palette = 0; + } + return 1; +} + +static void transform_palette_close(FLIF16TransformContext *ctx) +{ + transform_priv_palette *data = ctx->priv_data; + av_free(data->Palette); +} + +/* + * Palette Alpha + */ + +static int transform_palettealpha_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_palettealpha *data = ctx->priv_data; + if ( src_ctx->num_planes < 4 + || ff_flif16_ranges_min(src_ctx, 3) == ff_flif16_ranges_max(src_ctx, 3)) + return 0; + + data->already_has_palette = 0; + ff_flif16_chancecontext_init(&data->ctx); + ff_flif16_chancecontext_init(&data->ctxY); + ff_flif16_chancecontext_init(&data->ctxI); + ff_flif16_chancecontext_init(&data->ctxQ); + ff_flif16_chancecontext_init(&data->ctxA); + data->p = 0; + + return 1; +} + +static int transform_palettealpha_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_palettealpha *data = ctx->priv_data; + switch (ctx->i) + { + case 0: + RAC_GET(&dec_ctx->rc, &data->ctx, 1, MAX_PALETTE_SIZE, + &data->size, FLIF16_RAC_GNZ_INT); + data->Palette = av_mallocz(data->size * sizeof(*data->Palette)); + if (!data->Palette) + return 0; + ctx->i++; + + case 1: + RAC_GET(&dec_ctx->rc, &data->ctx, 0, 1, + &data->sorted, FLIF16_RAC_GNZ_INT); + if (data->sorted) { + ctx->i = 2; + data->min[0] = ff_flif16_ranges_min(src_ctx, 3); + data->max[0] = ff_flif16_ranges_max(src_ctx, 3); + for (int i = 1; i < 4; i++) { + data->min[i] = ff_flif16_ranges_min(src_ctx, i-1); + data->max[i] = ff_flif16_ranges_max(src_ctx, i-1); + data->Palette[0][i] = -1; + } + data->prev = data->Palette[0]; + } + else { + ctx->i = 6; + goto unsorted; + } + + loop: + if (data->p < data->size) { + case 2: + RAC_GET(&dec_ctx->rc, &data->ctxA, data->min[0], data->max[0], + &data->A, FLIF16_RAC_GNZ_INT); + if (data->alpha_zero_special && data->A == 0) { + for (int i = 0; i < 4; i++) + data->Palette[data->p][i] = 0; + data->p++; + goto loop; + } + ctx->i++; + + case 3: + RAC_GET(&dec_ctx->rc, &data->ctxY, + data->prev[0] == data->A ? data->prev[1] : data->min[1], + data->max[1], + &data->Y, FLIF16_RAC_GNZ_INT); + data->pp[0] = data->Y; + ff_flif16_ranges_minmax(src_ctx, 1, data->pp, &data->min[2], &data->max[2]); + ctx->i++; + + case 4: + RAC_GET(&dec_ctx->rc, &data->ctxI, + data->min[2], data->max[2], + &data->I, FLIF16_RAC_GNZ_INT); + data->pp[1] = data->I; + ff_flif16_ranges_minmax(src_ctx, 2, data->pp, &data->min[3], &data->max[3]); + ctx->i++; + + case 5: + RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[3], data->max[3], + &data->Q, FLIF16_RAC_GNZ_INT); + data->Palette[data->p][0] = data->A; + data->Palette[data->p][1] = data->Y; + data->Palette[data->p][2] = data->I; + data->Palette[data->p][3] = data->Q; + data->min[0] = data->A; + data->prev = data->Palette[data->p]; + data->p++; + ctx->i = 2; + goto loop; + } + else { + ctx->i = 0; + data->p = 0; + goto end; + } + + unsorted: + if (data->p < data->size) { + case 6: + RAC_GET(&dec_ctx->rc, &data->ctxA, + ff_flif16_ranges_min(src_ctx, 3), ff_flif16_ranges_max(src_ctx, 3), + &data->A, FLIF16_RAC_GNZ_INT); + if (data->alpha_zero_special && data->A == 0) { + for (int i = 0; i < 4; i++) + data->Palette[data->p][i] = 0; + data->p++; + goto loop; + } + ctx->i++; + + case 7: + ff_flif16_ranges_minmax(src_ctx, 0, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxY, data->min[0], data->max[0], + &data->Y, FLIF16_RAC_GNZ_INT); + data->pp[0] = data->Y; + ctx->i++; + + case 8: + ff_flif16_ranges_minmax(src_ctx, 1, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxI, data->min[0], data->max[0], + &data->I, FLIF16_RAC_GNZ_INT); + data->pp[1] = data->I; + ctx->i++; + + case 9: + ff_flif16_ranges_minmax(src_ctx, 2, data->pp, &data->min[0], &data->max[0]); + RAC_GET(&dec_ctx->rc, &data->ctxQ, data->min[0], data->max[0], + &data->Q, FLIF16_RAC_GNZ_INT); + data->Palette[data->p][0] = data->A; + data->Palette[data->p][1] = data->Y; + data->Palette[data->p][2] = data->I; + data->Palette[data->p][3] = data->Q; + data->p++; + ctx->i = 6; + goto unsorted; + } + else { + data->p = 0; + ctx->i = 0; + goto end; + } + + } + end: + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static void transform_palettealpha_configure(FLIF16TransformContext *ctx, + const int setting) +{ + transform_priv_palettealpha *data = ctx->priv_data; + data->alpha_zero_special = setting; + if (setting > 0) { + data->ordered_palette = 1; + data->max_palette_size = setting; + } + else { + data->ordered_palette = 0; + data->max_palette_size = -setting; + } +} + +static FLIF16RangesContext *transform_palettealpha_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + FLIF16RangesContext *r_ctx; + transform_priv_palettealpha *data; + ranges_priv_palette *priv_data; + r_ctx = av_mallocz(sizeof(*r_ctx)); + if (!r_ctx) + return NULL; + data = t_ctx->priv_data; + // ???? + priv_data = av_mallocz(sizeof(ranges_priv_permuteplanes)); + if (!priv_data) + return NULL; + r_ctx->r_no = FLIF16_RANGES_PALETTEALPHA; + r_ctx->num_planes = src_ctx->num_planes; + priv_data->nb_colors = data->size; + priv_data->r_ctx = src_ctx; + r_ctx->priv_data = priv_data; + + // for (int i = 0; i < frame_count; i++) + // frame[i].palette = 1; + + return r_ctx; +} + +static int transform_palettealpha_reverse(FLIF16Context *ctx, + FLIF16TransformContext *t_ctx, + FLIF16PixelData *frame, + uint32_t stride_row, + uint32_t stride_col) +{ + int r, c; + int P; + transform_priv_palettealpha *data = t_ctx->priv_data; + for (r = 0; r < ctx->height; r += stride_row) { + for (c = 0; c < ctx->width; c += stride_col) { + P = ff_flif16_pixel_get(ctx, frame, 1, r, c); + av_assert0(P < data->size); + ff_flif16_pixel_set(ctx, frame, 0, r, c, data->Palette[P][1]); + ff_flif16_pixel_set(ctx, frame, 1, r, c, data->Palette[P][2]); + ff_flif16_pixel_set(ctx, frame, 2, r, c, data->Palette[P][3]); + ff_flif16_pixel_set(ctx, frame, 3, r, c, data->Palette[P][0]); + } + //frame->palette = 0; + } + return 1; +} + +static void transform_palettealpha_close(FLIF16TransformContext *ctx) +{ + transform_priv_palettealpha *data = ctx->priv_data; + av_free(data->Palette); +} + +/* + * ColorBuckets + */ + + +static ColorValCB_list *ff_insert_colorvalCB(ColorValCB_list *list, + unsigned int pos, ColorValCB val) +{ + ColorValCB_list *temp = list; + ColorValCB_list *elem = av_mallocz(sizeof(*elem)); + if (!elem) + return NULL; + elem->data = val; + elem->next = 0; + + if (pos == 0) { + elem->next = temp; + return elem; + } + + for (unsigned int i = 1; i < pos; i++) { + temp = temp->next; + } + av_assert0(temp); + elem->next = temp->next; + temp->next = elem; + + return list; +} + +static ColorValCB_list *ff_remove_colorvalCB(ColorValCB_list *list, + unsigned int pos) +{ + ColorValCB_list *temp = list, *temp1; + if (pos == 0) { + temp = list->next; + av_free(list); + return temp; + } + + for (int i = 1; i < pos; i++) { + temp = temp->next; + } + temp1 = temp->next; + temp->next = temp1->next; + av_free(temp1); + + return list; +} + +static ColorValCB ff_colorvalCB_at(ColorValCB_list *list, unsigned int pos) +{ + ColorValCB_list *temp = list; + for (unsigned int i = 0; i < pos; i++) { + temp = temp->next; + } + return temp->data; +} + +static uint8_t ff_remove_color(ColorBucket *cb, const FLIF16ColorVal c) +{ + if (cb->discrete) { + unsigned int pos = 0; + ColorValCB_list *temp = cb->values; + for (; pos < cb->values_size; pos++, temp = temp->next) { + if (c == temp->data) { + cb->values = ff_remove_colorvalCB(cb->values, pos); + cb->values_size--; + break; + } + } + if (cb->values_size == 0) { + cb->min = 10000; + cb->max = -10000; + return 1; + } + av_assert0(cb->values_size > 0); + if (c == cb->min) + cb->min = ff_colorvalCB_at(cb->values, 0); + if (c == cb->max) + cb->max = ff_colorvalCB_at(cb->values, cb->values_size-1); + } + else { + if (c == cb->min) + cb->min++; + if (c == cb->max) + cb->max--; + if (c > cb->max) + return 1; + if (c < cb->min) + return 1; + cb->discrete = 1; + av_freep(&cb->values); + cb->values_size = 0; + for (FLIF16ColorVal x = cb->min; x <= cb->max; x++) { + if (x != c) { + cb->values = ff_insert_colorvalCB(cb->values, cb->values_size, x); + cb->values_size++; + } + } + } + return 1; +} + +static FLIF16ColorVal ff_snap_color_slow(ColorBucket *cb, const FLIF16ColorVal c) +{ + FLIF16ColorVal diff; + if (c <= cb->min) + return cb->min; + if (c >= cb->max) + return cb->max; + if (cb->discrete) { + FLIF16ColorVal mindiff = abs(c - cb->min); + unsigned int best = 0; + ColorValCB_list *temp = cb->values->next; + for (unsigned int i = 1; i < cb->values_size; i++, temp = temp->next) { + if (c == temp->data) + return c; + diff = abs(c - temp->data); + if (diff < mindiff) { + best = i; + mindiff = diff; + } + if (temp->data > c) + break; + } + return ff_colorvalCB_at(cb->values, best); + } + return c; +} + +static void ff_prepare_snapvalues(ColorBucket *cb) +{ + int i = 0; + if (cb->discrete) { + av_freep(&cb->snapvalues); + cb->snapvalues = av_mallocz((cb->max - cb->min) * sizeof(*cb->snapvalues)); + // av_assert0(cb->snapvalues != NULL); + cb->snapvalues_size = cb->max - cb->min; + for (FLIF16ColorVal c = cb->min; c < cb->max; c++) { + cb->snapvalues[i] = ff_snap_color_slow(cb, c); + i++; + } + } +} + + +static uint8_t ff_colorbuckets_exists2(ColorBuckets *cb, const int p, + FLIF16ColorVal *pp) +{ + FLIF16ColorVal rmin, rmax, v; + ColorBucket *b; + if (p > FLIF16_PLANE_Y + && (pp[0] < cb->min0 || pp[0] > ff_flif16_ranges_max(cb->ranges, 0))) { + return 0; + } + if (p > FLIF16_PLANE_CO + && (pp[1] < cb->min1 || pp[1] > ff_flif16_ranges_max(cb->ranges, 1))) { + return 0; + } + + v = pp[p]; + ff_flif16_ranges_snap(cb->ranges, p, pp, &rmin, &rmax, &v); + if (v != pp[p]) + return 0; + + b = ff_bucket_buckets(cb, p, pp); + if (ff_snap_color_slow(b, pp[p]) != pp[p]) + return 0; + + return 1; +} + +static uint8_t ff_colorbuckets_exists(ColorBuckets *cb, const int p, + FLIF16ColorVal *lower, FLIF16ColorVal *upper) +{ + FLIF16ColorVal pixel[2]; + pixel[0] = lower[0]; + pixel[1] = lower[1]; + if (p == FLIF16_PLANE_Y) { + for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) { + if (ff_colorbuckets_exists2(cb, p, pixel)) + return 1; + } + } + if (p == FLIF16_PLANE_CO) { + for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) { + for (pixel[1] = lower[1]; pixel[1] <= upper[1]; pixel[1]++) { + if (ff_colorbuckets_exists2(cb, p, pixel)) + return 1; + } + } + } + return 0; +} + +static int transform_colorbuckets_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_colorbuckets *data = ctx->priv_data; + int length, temp; + ColorBuckets *cb; + data->cb = NULL; + data->really_used = 0; + if ((src_ctx->num_planes < 3) + || + (ff_flif16_ranges_min(src_ctx, 0) == 0 + && ff_flif16_ranges_max(src_ctx, 0) == 0 + && ff_flif16_ranges_min(src_ctx, 2) == 0 + && ff_flif16_ranges_max(src_ctx, 2) == 0) + || + (ff_flif16_ranges_min(src_ctx, 0) == ff_flif16_ranges_max(src_ctx, 0) + && ff_flif16_ranges_min(src_ctx, 1) == ff_flif16_ranges_max(src_ctx, 1) + && ff_flif16_ranges_min(src_ctx, 2) == ff_flif16_ranges_max(src_ctx, 2)) + || + (ff_flif16_ranges_max(src_ctx, 0) - ff_flif16_ranges_min(src_ctx, 0) > 1023 + ||ff_flif16_ranges_max(src_ctx, 1) - ff_flif16_ranges_min(src_ctx, 1) > 1023 + ||ff_flif16_ranges_max(src_ctx, 2) - ff_flif16_ranges_min(src_ctx, 2) > 1023) + || + (ff_flif16_ranges_min(src_ctx, 1) == ff_flif16_ranges_max(src_ctx, 1))) + return 0; + + cb = av_mallocz(sizeof(*cb)); + if (!cb) + return 0; + + ff_init_bucket_default(&cb->bucket0); + cb->min0 = ff_flif16_ranges_min(src_ctx, 0); + cb->min1 = ff_flif16_ranges_min(src_ctx, 1); + + length = ((ff_flif16_ranges_max(src_ctx, 0) - cb->min0)/CB0b + 1); + temp = ((ff_flif16_ranges_max(src_ctx, 1) - cb->min1)/CB1 + 1); + + cb->bucket1 = av_mallocz(((ff_flif16_ranges_max(src_ctx, 0) + - cb->min0)/CB0a + 1) + * sizeof(*cb->bucket1)); + if (!cb->bucket1) + return 0; + cb->bucket1_size = ((ff_flif16_ranges_max(src_ctx, 0) + - cb->min0)/CB0a + 1); + cb->bucket2 = av_mallocz(length * sizeof(*cb->bucket2)); + if (!cb->bucket2) + return 0; + cb->bucket2_size = length; + for (int i = 0; i < length; i++) { + cb->bucket2_list_size = temp; + cb->bucket2[i] = av_mallocz(temp * sizeof(*cb->bucket2[i])); + if (!cb->bucket2[i]) + return 0; + } + ff_init_bucket_default(&cb->bucket3); + for (uint8_t i = 0; i < 6; i++) + ff_flif16_chancecontext_init(&data->ctx[i]); + + cb->ranges = src_ctx; + data->cb = cb; + data->i = 0; + + return 1; +} + +static FLIF16RangesContext *transform_colorbuckets_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + FLIF16RangesContext *r_ctx; + transform_priv_colorbuckets *trans_data = t_ctx->priv_data; + ranges_priv_colorbuckets *data; + ColorBuckets *cb = trans_data->cb; + FLIF16ColorVal pixelL[2], pixelU[2]; + + r_ctx = av_mallocz(sizeof(*r_ctx)); + if (!r_ctx) + return NULL; + data = av_mallocz(sizeof(ranges_priv_palette)); + if (!data) + return NULL; + if (ff_flif16_ranges_min(src_ctx, 2) < ff_flif16_ranges_max(src_ctx, 2)) { + pixelL[0] = cb->min0; + pixelU[0] = cb->min0 + CB0b -1; + pixelL[1] = cb->min1; + pixelU[1] = cb->min1 + CB1 - 1; + for (int i = 0; i < cb->bucket2_size; i++) { + pixelL[1] = cb->min1; + pixelU[1] = cb->min1 + CB1 -1; + for (int j = 0; j < cb->bucket2_list_size; j++) { + if (cb->bucket2[i][j].min > cb->bucket2[i][j].max) { + for (FLIF16ColorVal c = pixelL[1]; c <= pixelU[1]; c++) { + if (!ff_remove_color(ff_bucket_buckets2(cb, 1, pixelL), c)) + return NULL; + if (!ff_remove_color(ff_bucket_buckets2(cb, 1, pixelU), c)) + return NULL; + } + } + pixelL[1] += CB1; + pixelU[1] += CB1; + } + pixelL[0] += CB0b; + pixelU[0] += CB0b; + } + } + ff_prepare_snapvalues(&cb->bucket0); + ff_prepare_snapvalues(&cb->bucket3); + for (unsigned int i = 0; i < cb->bucket1_size; i++) + ff_prepare_snapvalues(&cb->bucket1[i]); + for (unsigned int i = 0; i < cb->bucket2_size; i++) { + for (unsigned int j = 0; j < cb->bucket2_list_size; j++) + ff_prepare_snapvalues(&cb->bucket2[i][j]); + } + + trans_data->really_used = 1; + + data->r_ctx = src_ctx; + data->buckets = trans_data->cb; + + r_ctx->r_no = FLIF16_RANGES_COLORBUCKETS; + r_ctx->priv_data = data; + r_ctx->num_planes = src_ctx->num_planes; + + return r_ctx; +} + +static void transform_colorbuckets_minmax(FLIF16RangesContext *src_ctx, int p, + FLIF16ColorVal *lower, + FLIF16ColorVal *upper, + FLIF16ColorVal *smin, + FLIF16ColorVal *smax) +{ + FLIF16ColorVal rmin, rmax; + FLIF16ColorVal pixel[2]; + pixel[0] = lower[0]; + pixel[1] = lower[1]; + *smin = 10000; + *smax = -10000; + if (p == FLIF16_PLANE_Y) { + ff_flif16_ranges_minmax(src_ctx, p,pixel,smin,smax); + } + else if (p == FLIF16_PLANE_CO) { + for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) { + ff_flif16_ranges_minmax(src_ctx, p, pixel, &rmin, &rmax); + if (rmin < *smin) + *smin = rmin; + if (rmax > *smax) + *smax = rmax; + } + } + else if (p == FLIF16_PLANE_CG) { + for (pixel[0] = lower[0]; pixel[0] <= upper[0]; pixel[0]++) { + for (pixel[1] = lower[1]; pixel[1] <= upper[1]; pixel[1]++) { + ff_flif16_ranges_minmax(src_ctx, p, pixel, &rmin, &rmax); + if (rmin < *smin) + *smin = rmin; + if (rmax > *smax) + *smax = rmax; + } + } + } + else if (p == FLIF16_PLANE_ALPHA) { + ff_flif16_ranges_minmax(src_ctx, p, pixel, smin, smax); + } +} + +const unsigned int max_per_colorbucket[] = {255, 510, 5, 255}; + +static int ff_load_bucket(FLIF16RangeCoder *rc, FLIF16ChanceContext *chancectx, + ColorBucket *b, ColorBuckets *cb, + FLIF16RangesContext *src_ctx, int plane, + FLIF16ColorVal *pixelL, FLIF16ColorVal *pixelU) +{ + int temp; + int exists; + switch (cb->i) { + case 0: + if (plane < FLIF16_PLANE_ALPHA) + for (int p = 0; p < plane; p++) { + if (!ff_colorbuckets_exists(cb, p, pixelL, pixelU)) { + goto end; + } + } + cb->i = 1; + + case 1: + transform_colorbuckets_minmax(src_ctx, plane, + pixelL, pixelU, + &cb->smin, &cb->smax); + RAC_GET(rc, &chancectx[0], 0, 1, &exists, FLIF16_RAC_GNZ_INT); + if (exists == 0) { + goto end; // empty bucket + } + if (cb->smin == cb->smax) { + b->min = cb->smin; + b->max = cb->smin; + b->discrete = 0; + goto end; + } + cb->i = 2; + + case 2: + RAC_GET(rc, &chancectx[1], cb->smin, cb->smax, &b->min, FLIF16_RAC_GNZ_INT); + cb->i = 3; + + case 3: + RAC_GET(rc, &chancectx[2], b->min, cb->smax, &b->max, FLIF16_RAC_GNZ_INT); + if (b->min == b->max) { + b->discrete = 0; + goto end; + } + if (b->min + 1 == b->max) { + b->discrete = 0; + goto end; + } + cb->i = 4; + + case 4: + RAC_GET(rc, &chancectx[3], 0, 1, &b->discrete, FLIF16_RAC_GNZ_INT); + cb->i = 5; + + case 5: + if (b->discrete) { + RAC_GET(rc, &chancectx[4], 2, + FFMIN(max_per_colorbucket[plane], b->max - b->min), + &cb->nb, FLIF16_RAC_GNZ_INT); + b->values = 0; + b->values = ff_insert_colorvalCB(b->values, 0, b->min); + cb->v = b->min; + cb->i = 6; + cb->i2 = 1; + + for (; cb->i2 < cb->nb - 1; cb->i2++) { + case 6: + RAC_GET(rc, &chancectx[5], cb->v + 1, + b->max + 1 - cb->nb + cb->i2, &temp, + FLIF16_RAC_GNZ_INT); + b->values = ff_insert_colorvalCB(b->values, cb->i2, temp); + cb->v = temp; + } + + if (b->min < b->max) { + b->values = ff_insert_colorvalCB(b->values, cb->nb - 1, b->max); + b->values_size = cb->nb; + goto end; + } + b->values_size = cb->nb - 1; + } + } + + end: + cb->i = 0; + cb->i2 = 0; + cb->nb = 0; + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static int transform_colorbuckets_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_colorbuckets *data = ctx->priv_data; + ColorBuckets *cb = data->cb; + int8_t ret; + + switch (data->i) { + case 0: + ret = ff_load_bucket(&dec_ctx->rc, data->ctx, &cb->bucket0, cb, + src_ctx, 0, data->pixelL, data->pixelU); + if (ret <= 0) + goto need_more_data; + data->pixelL[0] = (cb->min0); + data->pixelU[0] = (cb->min0 + (int)CB0a - 1); + data->i = 1; + + for (; data->j < cb->bucket1_size; data->j++) { + case 1: + ret = ff_load_bucket(&dec_ctx->rc, data->ctx, + &cb->bucket1[data->j], cb, + src_ctx, 1, data->pixelL, data->pixelU); + if (ret <= 0) + goto need_more_data; + data->pixelL[0] += CB0a; + data->pixelU[0] += CB0a; + } + data->j = 0; + + if (ff_flif16_ranges_min(src_ctx, 2) < ff_flif16_ranges_max(src_ctx, 2)) { + data->pixelL[0] = cb->min0; + data->pixelU[0] = cb->min0 + CB0b - 1; + data->pixelL[1] = cb->min1; + data->pixelU[1] = cb->min1 + CB1 - 1; + for (; data->j < cb->bucket2_size; data->j++) { + data->pixelL[1] = cb->min1; + data->pixelU[1] = cb->min1 + CB1 - 1; + data->i = 2; + + for (; data->k < cb->bucket2_list_size; data->k++) { + case 2: + ret = ff_load_bucket(&dec_ctx->rc, data->ctx, + &cb->bucket2[data->j][data->k], cb, + src_ctx, 2, data->pixelL, data->pixelU); + if (ret <= 0) + goto need_more_data; + data->pixelL[1] += CB1; + data->pixelU[1] += CB1; + } + data->k = 0; + data->pixelL[0] += CB0b; + data->pixelU[0] += CB0b; + } + data->j = 0; + } + data->i = 3; + + if (src_ctx->num_planes > 3) { + case 3: + ret = ff_load_bucket(&dec_ctx->rc, data->ctx, &cb->bucket3, cb, + src_ctx, 3, data->pixelL, data->pixelU); + if (ret <= 0) + goto need_more_data; + } + + goto end; + } + + end: + data->i = 0; + data->j = 0; + data->k = 0; + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static int transform_framedup_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framedup *data = ctx->priv_data; + ff_flif16_chancecontext_init(&data->chancectx); + data->i = 0; + + return 1; +} + +static void transform_framedup_configure(FLIF16TransformContext *ctx, + const int setting) +{ + transform_priv_framedup *data = ctx->priv_data; + data->nb = setting; +} + +static int transform_framedup_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framedup *data = ctx->priv_data; + + switch (ctx->i) { + case 0: + data->seen_before = av_mallocz(data->nb * sizeof(*data->seen_before)); + if (!data->seen_before) + return 0; + data->seen_before[0] = -1; + ctx->i = 1; + data->i = 1; + + case 1: + for (; data->i < data->nb; data->i++) { + RAC_GET(&dec_ctx->rc, &data->chancectx, -1, data->i - 1, + &data->seen_before[data->i], FLIF16_RAC_NZ_INT); + } + data->i = 0; + goto end; + } + + end: + ctx->i = 0; + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static FLIF16RangesContext *transform_framedup_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framedup *data = t_ctx->priv_data; + for (unsigned int fr = 0; fr < frame_count; fr++) { + frame[fr].seen_before = data->seen_before[fr]; + } + + return src_ctx; +} + +static void transform_framedup_close(FLIF16TransformContext *ctx) +{ + transform_priv_framedup *data = ctx->priv_data; + av_free(data->seen_before); +} + +static int transform_frameshape_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_frameshape *data = ctx->priv_data; + ff_flif16_chancecontext_init(&data->chancectx); + data->i = 0; + + return 1; +} + +static void transform_frameshape_configure(FLIF16TransformContext *ctx, + const int setting) +{ + transform_priv_frameshape *data = ctx->priv_data; + if (data->nb == 0) { + data->nb = setting; + } + else + data->cols = setting; +} + +static int transform_frameshape_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_frameshape *data = ctx->priv_data; + int temp; + + switch (ctx->i) { + case 0: + data->b = av_mallocz(data->nb * sizeof(*data->b)); + if (!data->b) + return -1; + data->e = av_mallocz(data->nb * sizeof(*data->e)); + if (!data->e) + return -1; + ctx->i = 1; + + case 1: + for (; data->i < data->nb; data->i++) { + RAC_GET(&dec_ctx->rc, &data->chancectx, 0, data->cols, + &data->b[data->i], FLIF16_RAC_NZ_INT); + } + ctx->i = 2; + data->i = 0; + + case 2: + for (; data->i < data->nb; data->i++) { + //RAC_GET(&dec_ctx->rc, &data->chancectx, 0, + // data->cols - data->b[data->i], + // &data->e[data->i], FLIF16_RAC_NZ_INT); + temp = ff_flif16_rac_process(&dec_ctx->rc, &data->chancectx, 0, + data->cols - data->b[data->i], + &data->e[data->i], FLIF16_RAC_NZ_INT); + if (temp == 0) + goto need_more_data; + data->e[data->i] = data->cols - data->e[data->i]; + + if ( data->e[data->i] > data->cols + || data->e[data->i] < data->b[data->i] + || data->e[data->i] <= 0) { + return 0; + } + } + data->i = 0; + } + + ctx->i = 0; + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static FLIF16RangesContext *transform_frameshape_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_frameshape *data = t_ctx->priv_data; + uint32_t pos = 0; + + for (unsigned int fr = 1; fr < frame_count; fr++) { + if (frame[fr].seen_before >= 0) + continue; + frame[fr].col_begin = av_mallocz(ctx->height * sizeof(*frame->col_begin)); + if (!frame[fr].col_begin) { + return NULL; + } + frame[fr].col_end = av_mallocz(ctx->height * sizeof(*frame->col_end)); + if (!frame[fr].col_end) { + return NULL; + } + for (uint32_t r = 0; r < ctx->height; r++) { + av_assert0(pos < data->nb); + frame[fr].col_begin[r] = data->b[pos]; + frame[fr].col_end[r] = data->e[pos]; + pos++; + } + } + + return src_ctx; +} + +static void transform_frameshape_close(FLIF16TransformContext *ctx) +{ + transform_priv_frameshape *data = ctx->priv_data; + av_free(data->b); + av_free(data->e); +} + +static int transform_framecombine_init(FLIF16TransformContext *ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framecombine *data = ctx->priv_data; + ff_flif16_chancecontext_init(&data->chancectx); + + return 1; +} + +static void transform_framecombine_configure(FLIF16TransformContext *ctx, + const int setting) +{ + transform_priv_framecombine *data = ctx->priv_data; + data->user_max_lookback = data->nb_frames = setting; +} + +static int transform_framecombine_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framecombine *data = ctx->priv_data; + + switch (ctx->i) { + case 0: + if (src_ctx->num_planes > 4) + return 0; + ctx->i = 1; + + case 1: + RAC_GET(&dec_ctx->rc, &data->chancectx, 1, data->nb_frames - 1, + &data->max_lookback, FLIF16_RAC_GNZ_INT); + printf("max_lookback : %d", data->max_lookback); + } + + ctx->i = 0; + return 1; + + need_more_data: + return AVERROR(EAGAIN); +} + +static FLIF16RangesContext *transform_framecombine_meta(FLIF16Context *ctx, + FLIF16PixelData *frame, + uint32_t frame_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *src_ctx) +{ + transform_priv_framecombine *data = t_ctx->priv_data; + ranges_priv_framecombine *rdata; + FLIF16RangesContext *ranges; + int lookback; + ranges = av_mallocz(sizeof(*ranges)); + if (!ranges) + return NULL; + rdata = av_mallocz(sizeof(*rdata)); + if (!rdata) + return NULL; + av_assert0(data->max_lookback < frame_count); + data->was_greyscale = (src_ctx->num_planes < 2); + data->was_flat = (src_ctx->num_planes < 4); + + lookback = frame_count - 1; + if (lookback > data->max_lookback) + lookback = data->max_lookback; + + ranges->r_no = FLIF16_RANGES_FRAMELOOKBACK; + ranges->num_planes = 5; + ranges->priv_data = rdata; + + rdata->numPrevFrames = lookback; + rdata->alpha_min = (src_ctx->num_planes == 4 ? ff_flif16_ranges_min(src_ctx, 3) : 1); + rdata->alpha_max = (src_ctx->num_planes == 4 ? ff_flif16_ranges_max(src_ctx, 3) : 1); + rdata->ranges = src_ctx; + + return ranges; +} + +FLIF16Transform flif16_transform_channelcompact = { + .priv_data_size = sizeof(transform_priv_channelcompact), + .init = &transform_channelcompact_init, + .read = &transform_channelcompact_read, + .meta = &transform_channelcompact_meta, + .forward = NULL,//&transform_channelcompact_forward, + .reverse = &transform_channelcompact_reverse, + .close = &transform_channelcompact_close +}; + +FLIF16Transform flif16_transform_ycocg = { + .priv_data_size = sizeof(transform_priv_ycocg), + .init = &transform_ycocg_init, + .read = NULL, + .meta = &transform_ycocg_meta, + .forward = &transform_ycocg_forward, + .reverse = &transform_ycocg_reverse, + .close = NULL +}; + +FLIF16Transform flif16_transform_permuteplanes = { + .priv_data_size = sizeof(transform_priv_permuteplanes), + .init = &transform_permuteplanes_init, + .read = &transform_permuteplanes_read, + .meta = &transform_permuteplanes_meta, + .forward = &transform_permuteplanes_forward, + .reverse = &transform_permuteplanes_reverse, + .close = NULL +}; + +FLIF16Transform flif16_transform_bounds = { + .priv_data_size = sizeof(transform_priv_bounds), + .init = &transform_bounds_init, + .read = &transform_bounds_read, + .meta = &transform_bounds_meta, + .forward = NULL, + .reverse = NULL, + .close = NULL +}; + +FLIF16Transform flif16_transform_palette = { + .priv_data_size = sizeof(transform_priv_palette), + .init = &transform_palette_init, + .read = &transform_palette_read, + .meta = &transform_palette_meta, + //.forward + .reverse = &transform_palette_reverse, + .close = &transform_palette_close +}; + +FLIF16Transform flif16_transform_palettealpha = { + .priv_data_size = sizeof(transform_priv_palettealpha), + .init = &transform_palettealpha_init, + .read = &transform_palettealpha_read, + .meta = &transform_palettealpha_meta, + .configure = &transform_palettealpha_configure, + //.forward + .reverse = &transform_palettealpha_reverse, + .close = &transform_palettealpha_close +}; + +FLIF16Transform flif16_transform_colorbuckets = { + .priv_data_size = sizeof(transform_priv_colorbuckets), + .init = &transform_colorbuckets_init, + .read = &transform_colorbuckets_read, + .meta = &transform_colorbuckets_meta, + .forward = NULL, + .reverse = NULL, + .close = NULL +}; + +FLIF16Transform flif16_transform_framedup = { + .priv_data_size = sizeof(transform_priv_framedup), + .init = &transform_framedup_init, + .read = &transform_framedup_read, + .meta = &transform_framedup_meta, + .configure = &transform_framedup_configure, + .forward = NULL, + .reverse = NULL, + .close = &transform_framedup_close +}; + +FLIF16Transform flif16_transform_frameshape = { + .priv_data_size = sizeof(transform_priv_frameshape), + .init = &transform_frameshape_init, + .read = &transform_frameshape_read, + .meta = &transform_frameshape_meta, + .configure = &transform_frameshape_configure, + .forward = NULL, + .reverse = NULL, + .close = &transform_frameshape_close +}; + +FLIF16Transform flif16_transform_framecombine = { + .priv_data_size = sizeof(transform_priv_framecombine), + .init = &transform_framecombine_init, + .read = &transform_framecombine_read, + .meta = &transform_framecombine_meta, + .configure = &transform_framecombine_configure, + .forward = NULL, + .reverse = NULL, + .close = NULL +}; + +FLIF16Transform *flif16_transforms[13] = { + &flif16_transform_channelcompact, + &flif16_transform_ycocg, + NULL, // RESERVED, + &flif16_transform_permuteplanes, + &flif16_transform_bounds, + &flif16_transform_palettealpha, + &flif16_transform_palette, + &flif16_transform_colorbuckets, + NULL, // RESERVED, + NULL, // RESERVED, + &flif16_transform_framedup, + &flif16_transform_frameshape, + &flif16_transform_framecombine +}; + +FLIF16TransformContext *ff_flif16_transform_init(int t_no, FLIF16RangesContext *r_ctx) +{ + FLIF16Transform *trans; + FLIF16TransformContext *ctx; + void *k = NULL; + + trans = flif16_transforms[t_no]; + if (!trans) + return NULL; + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return NULL; + if (trans->priv_data_size) { + k = av_mallocz(trans->priv_data_size); + if (!k) + return NULL; + } + ctx->t_no = t_no; + ctx->priv_data = k; + ctx->segment = 0; + ctx->i = 0; + + if (trans->init) + if (!trans->init(ctx, r_ctx)) + return NULL; + + return ctx; +} + +int ff_flif16_transform_read(FLIF16TransformContext *ctx, + FLIF16Context *dec_ctx, + FLIF16RangesContext *r_ctx) +{ + FLIF16Transform *trans = flif16_transforms[ctx->t_no]; + if (trans->read) + return trans->read(ctx, dec_ctx, r_ctx); + else + return 1; +} + +FLIF16RangesContext *ff_flif16_transform_meta(FLIF16Context *ctx, + FLIF16PixelData *frames, + uint32_t frames_count, + FLIF16TransformContext *t_ctx, + FLIF16RangesContext *r_ctx) +{ + FLIF16Transform *trans; + trans = flif16_transforms[t_ctx->t_no]; + if (trans->meta) + return trans->meta(ctx, frames, frames_count, t_ctx, r_ctx); + else + return r_ctx; +} + +void ff_flif16_transform_configure(FLIF16TransformContext *ctx, const int setting) +{ + FLIF16Transform *trans = flif16_transforms[ctx->t_no]; + if (trans->configure) + trans->configure(ctx, setting); +} + +int ff_flif16_transform_reverse(FLIF16Context *ctx, + FLIF16TransformContext *t_ctx, + FLIF16PixelData *frame, + uint8_t stride_row, uint8_t stride_col) +{ + FLIF16Transform *trans = flif16_transforms[t_ctx->t_no]; + if (trans->reverse != NULL) + return trans->reverse(ctx, t_ctx, frame, stride_row, stride_col); + else + return 1; +} + +void ff_flif16_transforms_close(FLIF16TransformContext *ctx) +{ + FLIF16Transform *trans = flif16_transforms[ctx->t_no]; + if (trans->close) + trans->close(ctx); + if (trans->priv_data_size) + av_free(ctx->priv_data); + av_freep(&ctx); +} diff --git a/libavcodec/flif16_transform.h b/libavcodec/flif16_transform.h new file mode 100644 index 0000000000..c4bba24fc5 --- /dev/null +++ b/libavcodec/flif16_transform.h @@ -0,0 +1,123 @@ +/* + * Transforms for FLIF16. + * Copyright (c) 2020 Kartik K. Khullar + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Transforms for FLIF16. + */ + +#ifndef FLIF16_TRANSFORM_H +#define FLIF16_TRANSFORM_H + +#include "avcodec.h" +#include "libavutil/common.h" +#include "flif16.h" + +typedef enum FLIF16RangesTypes{ + FLIF16_RANGES_CHANNELCOMPACT, + FLIF16_RANGES_YCOCG, + FLIF16_RANGES_PERMUTEPLANES, + FLIF16_RANGES_PERMUTEPLANESSUBTRACT, + FLIF16_RANGES_BOUNDS, + FLIF16_RANGES_STATIC, + FLIF16_RANGES_PALETTEALPHA, + FLIF16_RANGES_PALETTE, + FLIF16_RANGES_COLORBUCKETS, + FLIF16_RANGES_FRAMELOOKBACK +} FLIF16RangesTypes; + +typedef enum FLIF16TransformsTypes { + FLIF16_TRANSFORM_CHANNELCOMPACT, + FLIF16_TRANSFORM_YCOCG, + FLIF16_TRANSFORM_RESERVED1, + FLIF16_TRANSFORM_PERMUTEPLANES, + FLIF16_TRANSFORM_BOUNDS, + FLIF16_TRANSFORM_PALETTEALPHA, + FLIF16_TRANSFORM_PALETTE, + FLIF16_TRANSFORM_COLORBUCKETS, + FLIF16_TRANSFORM_RESERVED2, + FLIF16_TRANSFORM_RESERVED3, + FLIF16_TRANSFORM_DUPLICATEFRAME, + FLIF16_TRANSFORM_FRAMESHAPE, + FLIF16_TRANSFORM_FRAMELOOKBACK, +} FLIF16TransformsTypes; + +extern FLIF16Ranges *flif16_ranges[14]; +extern FLIF16Transform *flif16_transforms[13]; + +FLIF16RangesContext *ff_flif16_ranges_static_init(unsigned int channels, + unsigned int bpc); + +void ff_flif16_ranges_close(FLIF16RangesContext* r_ctx); + +static inline FLIF16ColorVal ff_flif16_ranges_min(FLIF16RangesContext *r_ctx, int p) +{ + FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no]; + if(ranges->min) + return ranges->min(r_ctx, p); + else + return 0; +} + +static inline FLIF16ColorVal ff_flif16_ranges_max(FLIF16RangesContext *r_ctx, int p) +{ + FLIF16Ranges *ranges = flif16_ranges[r_ctx->r_no]; + if(ranges->max) + return ranges->max(r_ctx, p); + else + return 0; +} + +static inline void ff_flif16_ranges_minmax(FLIF16RangesContext *r_ctx, int p, + FLIF16ColorVal *prev_planes, + FLIF16ColorVal *minv, FLIF16ColorVal *maxv) +{ + flif16_ranges[r_ctx->r_no]->minmax(r_ctx, p, prev_planes, minv, maxv); +} + +static inline void ff_flif16_ranges_snap(FLIF16RangesContext *r_ctx, int p, + FLIF16ColorVal *prev_planes, FLIF16ColorVal *minv, + FLIF16ColorVal *maxv, FLIF16ColorVal *v) +{ + flif16_ranges[r_ctx->r_no]->snap(r_ctx, p, prev_planes, minv, maxv, v); +} + +FLIF16TransformContext *ff_flif16_transform_init(int, FLIF16RangesContext *); + +void ff_flif16_transform_configure(FLIF16TransformContext *, const int); + + +// Maybe put FLIF16Context at first in list +int ff_flif16_transform_read(FLIF16TransformContext *, FLIF16Context *, + FLIF16RangesContext *); + +FLIF16RangesContext* ff_flif16_transform_meta(FLIF16Context *, + FLIF16PixelData *, + uint32_t, + FLIF16TransformContext *, + FLIF16RangesContext *); + +int ff_flif16_transform_reverse(FLIF16Context *, FLIF16TransformContext*, FLIF16PixelData*, + uint8_t, uint8_t); + +void ff_flif16_transforms_close(FLIF16TransformContext *); + +#endif /* FLIF16_TRANSFORM_H */ diff --git a/libavcodec/flif16dec.c b/libavcodec/flif16dec.c new file mode 100644 index 0000000000..18216f5991 --- /dev/null +++ b/libavcodec/flif16dec.c @@ -0,0 +1,1146 @@ +/* + * FLIF16 Decoder + * Copyright (c) 2020 Anamitra Ghorui + * + * 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 // Remove + +#include "flif16.h" +#include "flif16_rangecoder.h" +#include "flif16_transform.h" + +#include "avcodec.h" +#include "libavutil/common.h" +#include "bytestream.h" +#include "avcodec.h" +#include "internal.h" + +/* + * Due to the nature of the format, the decoder has to take the entirety of the + * data before it can generate any frames. The decoder has to return + * AVERROR(EAGAIN) as long as the bitstream is incomplete. + */ + + +// TODO make variable size UNI_INT readers +typedef struct FLIF16DecoderContext { + + /* Inheritance from FLIF16Context */ + + GetByteContext gb; + FLIF16MANIACContext maniac_ctx; + FLIF16RangeCoder rc; + + // Dimensions and other things. + uint32_t width; + uint32_t height; + uint32_t num_frames; + uint32_t meta; ///< Size of a meta chunk + + // Primary Header + uint8_t ia; ///< Is image interlaced or/and animated or not + uint32_t bpc; ///< 2 ^ Bytes per channel + uint8_t num_planes; ///< Number of planes + + // change to uint8_t + uint32_t loops; ///< Number of times animation loops + // change to uint32_t + uint32_t *framedelay; ///< Frame delay for each frame + + uint8_t plane_mode[MAX_PLANES]; + + // Transform flags + uint8_t framedup; + uint8_t frameshape; + uint8_t framelookback; + /* End Inheritance from FLIF16Context */ + + FLIF16PixelData *frames; + uint32_t out_frames_count; + AVFrame *out_frame; + int64_t pts; + + uint8_t buf[FLIF16_RAC_MAX_RANGE_BYTES]; ///< Storage for initial RAC buffer + uint8_t buf_count; ///< Count for initial RAC buffer + int state; ///< The section of the file the parser is in currently. + unsigned int segment; ///< The "segment" the code is supposed to jump to + unsigned int segment2;///< The "segment" the code is supposed to jump to + int i; ///< A generic iterator used to save states between for loops. + int i2; + int i3; + + // Secondary Header + uint8_t alphazero; ///< Alphazero Flag + uint8_t custombc; ///< Custom Bitchance Flag + uint8_t customalpha; ///< Custom alphadiv & cutoff flag + + uint8_t cut; ///< Chancetable custom cutoff + uint32_t alpha; ///< Chancetable custom alphadivisor + uint8_t ipp; ///< Invisible pixel predictor + + // Transforms + // Size dynamically maybe + FLIF16TransformContext *transforms[13]; + uint8_t transform_top; + FLIF16RangesContext *range; ///< The minimum and maximum values a + /// channel's pixels can take. Changes + /// depending on transformations applied + FLIF16RangesContext *prev_range; + + // MANIAC Trees + int32_t (*prop_ranges)[2]; ///< Property Ranges + uint32_t prop_ranges_size; + + // Pixeldata + uint8_t curr_plane; ///< State variable. Current plane under processing + FLIF16ColorVal *grays; + FLIF16ColorVal *properties; + FLIF16ColorVal guess; ///< State variable. Stores guess + FLIF16ColorVal min, max; + uint32_t c; ///< State variable for current column + + // Interlaced Pixeldata + int *zoomlevels; + int zooms; + int rough_zl; + int quality; + int scale; + int *predictors; + int breakpoints; +} FLIF16DecoderContext; + +// Cast values to FLIF16Context for some functions. +#define CTX_CAST(x) ((FLIF16Context *) (x)) + +// TODO Remove PIXEL and PIXELY. Concerned with interlaced decoding +#define PIXEL(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame, p, z, r, c) +#define PIXELY(z,r,c) ff_flif16_pixel_getz(CTX_CAST(s), frame, FLIF16_PLANE_Y, z, r, c) + +#define PIXEL_SET(ctx, fr, p, r, c, val) ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val) +#define PIXEL_GET(ctx, fr, p, r, c) ff_flif16_pixel_get(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c) +#define PIXEL_SETZ(ctx, fr, p, z, r, c, val) ff_flif16_pixel_setz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c, val) +#define PIXEL_GETZ(ctx, fr, p, z, r, c) ff_flif16_pixel_getz(CTX_CAST(ctx), &(ctx)->frames[fr], p, z, r, c) +#define PIXEL_GETFAST(ctx, fr, p, r, c) ff_flif16_pixel_get(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c) +#define PIXEL_SETFAST(ctx, fr, p, r, c, val) ff_flif16_pixel_set(CTX_CAST(ctx), &(ctx)->frames[fr], p, r, c, val) + +// If frame_dup exists, figure out what the previous frame actually is +#define PREV_FRAME(frames, f_no) (((frames)[(f_no) - 1].seen_before >= 0) ? &(frames)[(frames)[(f_no) - 1].seen_before] : &(frames)[(f_no) - 1]) +#define PREV_FRAMENUM(frames, f_no) (((frames)[(f_no) - 1].seen_before >= 0) ? (frames)[(f_no) - 1].seen_before : (f_no) - 1) + +// Static property values +static const int properties_ni_rgb_size[] = {7, 8, 9, 7, 7}; +static const int properties_ni_rgba_size[] = {8, 9, 10, 7, 7}; +static const int properties_rgb_size[] = {8, 10, 9, 8, 8}; +static const int properties_rgba_size[] = {9, 11, 10, 8, 8}; + +// From reference decoder: +// +// The order in which the planes are encoded. +// lookback (Lookback) (animations-only, value refers to a previous frame) has +// to be first, because all other planes are not encoded if lookback != 0 +// Alpha has to be next, because for fully transparent A=0 pixels, the other +// planes are not encoded +// Y (luma) is next (the first channel for still opaque images), because it is +// perceptually most important +// Co and Cg are in that order because Co is perceptually slightly more +// important than Cg [citation needed] +static const int plane_ordering[] = {4,3,0,1,2}; // lookback (lookback), A, Y, Co, Cg + +enum FLIF16States { + FLIF16_HEADER = 0, + FLIF16_SECONDHEADER, + FLIF16_TRANSFORM, + FLIF16_ROUGH_PIXELDATA, + FLIF16_MANIAC, + FLIF16_PIXELDATA, + FLIF16_OUTPUT, + FLIF16_CHECKSUM, + FLIF16_EOS +}; + +static int flif16_read_header(AVCodecContext *avctx) +{ + uint8_t temp, count = 4; + FLIF16DecoderContext *s = avctx->priv_data; + // TODO Make do without this array + uint32_t *vlist[] = { &s->width, &s->height, &s->num_frames }; + + s->cut = CHANCETABLE_DEFAULT_CUT; + s->alpha = CHANCETABLE_DEFAULT_ALPHA; + + // Minimum size has been empirically found to be 8 bytes. + if (bytestream2_size(&s->gb) < 8) { + av_log(avctx, AV_LOG_ERROR, "buf size too small (%d)\n", + bytestream2_size(&s->gb)); + return AVERROR(EINVAL); + } + + if (bytestream2_get_le32(&s->gb) != (*((uint32_t *) flif16_header))) { + av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); + return AVERROR(EINVAL); + } + + s->state = FLIF16_HEADER; + + temp = bytestream2_get_byte(&s->gb); + s->ia = temp >> 4; + s->num_planes = (0x0F & temp); + + if (!(s->ia % 2)) { + av_log(avctx, AV_LOG_ERROR, "interlaced images not supported\n"); + return AVERROR_PATCHWELCOME; + } + + s->bpc = bytestream2_get_byte(&s->gb); + + + + // Handle dimensions and frames + for(int i = 0; i < 2 + ((s->ia > 4) ? 1 : 0); ++i) { + while ((temp = bytestream2_get_byte(&s->gb)) > 127) { + VARINT_APPEND(*vlist[i], temp); + if (!(count--)) { + av_log(avctx, AV_LOG_ERROR, "image dimensions too big\n"); + return AVERROR(ENOMEM); + } + } + VARINT_APPEND(*vlist[i], temp); + count = 4; + } + s->width++; + s->height++; + (s->ia > 4) ? (s->num_frames += 2) : (s->num_frames = 1); + + if (s->num_frames > 1) { + s->framedelay = av_mallocz(sizeof(*(s->framedelay)) * s->num_frames); + if (!s->framedelay) + return AVERROR(ENOMEM); + } + + s->frames = ff_flif16_frames_init(CTX_CAST(s)); + + if (!s->frames) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate frames\n"); + return AVERROR(ENOMEM); + } + + // Handle Metadata Chunk. Currently it discards all data. + + while ((temp = bytestream2_get_byte(&s->gb)) != 0) { + bytestream2_seek(&s->gb, 3, SEEK_CUR); + // Read varint + while ((temp = bytestream2_get_byte(&s->gb)) > 127) { + VARINT_APPEND(s->meta, temp); + if (!(count--)) { + av_log(avctx, AV_LOG_ERROR, "metadata chunk too big \n"); + return AVERROR(ENOMEM); + } + } + VARINT_APPEND(s->meta, temp); + bytestream2_seek(&s->gb, s->meta, SEEK_CUR); + count = 4; + } + + s->state = FLIF16_SECONDHEADER; + return 0; +} + +static int flif16_read_second_header(AVCodecContext *avctx) +{ + uint32_t temp; + FLIF16DecoderContext *s = avctx->priv_data; + + switch (s->segment) { + case 0: + s->buf_count += bytestream2_get_buffer(&s->gb, s->buf + s->buf_count, + FFMIN(bytestream2_get_bytes_left(&s->gb), + (FLIF16_RAC_MAX_RANGE_BYTES - s->buf_count))); + + if (s->buf_count < FLIF16_RAC_MAX_RANGE_BYTES) + return AVERROR(EAGAIN); + + ff_flif16_rac_init(&s->rc, &s->gb, s->buf, s->buf_count); + ++s->segment; + + case 1: + // In original source this is handled in what seems to be a very + // bogus manner. It takes all the bpps of all planes and then + // takes the max, negating any benefit of actually keeping these + // multiple values. + if (s->bpc == '0') { + s->bpc = 0; + for (; s->i < s->num_planes; ++s->i) { + RAC_GET(&s->rc, NULL, 1, 15, &temp, FLIF16_RAC_UNI_INT8); + s->bpc = FFMAX(s->bpc, (1 << temp) - 1); + } + } else + s->bpc = (s->bpc == '1') ? 255 : 65535; + s->i = 0; + s->range = ff_flif16_ranges_static_init(s->num_planes, s->bpc); + // MSG("planes : %d & bpc : %d\n", s->num_planes, s->bpc); + ++s->segment; + + case 2: + if (s->num_planes > 3) { + RAC_GET(&s->rc, NULL, 0, 1, &s->alphazero, + FLIF16_RAC_UNI_INT8); + } + ++s->segment; + + case 3: + if (s->num_frames > 1) { + RAC_GET(&s->rc, NULL, 0, 100, &s->loops, + FLIF16_RAC_UNI_INT8); + } + ++s->segment; + + case 4: + if (s->num_frames > 1) { + for (; (s->i) < (s->num_frames); ++(s->i)) { + RAC_GET(&s->rc, NULL, 0, 60000, &(s->framedelay[s->i]), + FLIF16_RAC_UNI_INT16); + } + s->i = 0; + } + ++s->segment; + + case 5: + // Has custom alpha flag + RAC_GET(&s->rc, NULL, 0, 1, &s->customalpha, FLIF16_RAC_UNI_INT8); + ++s->segment; + + case 6: + if (s->customalpha) { + RAC_GET(&s->rc, NULL, 1, 128, &s->cut, FLIF16_RAC_UNI_INT8); + } + ++s->segment; + + case 7: + if (s->customalpha) { + RAC_GET(&s->rc, NULL, 2, 128, &s->alpha, FLIF16_RAC_UNI_INT8); + s->alpha = 0xFFFFFFFF / s->alpha; + } + ++s->segment; + + case 8: + if (s->customalpha) + RAC_GET(&s->rc, NULL, 0, 1, &s->custombc, FLIF16_RAC_UNI_INT8); + if (s->custombc) { + av_log(avctx, AV_LOG_ERROR, "custom bitchances not implemented\n"); + return AVERROR_PATCHWELCOME; + } + goto end; + } + + end: + s->state = FLIF16_TRANSFORM; + s->segment = 0; + + #ifdef MULTISCALE_CHANCES_ENABLED + s->rc->mct = ff_flif16_multiscale_chancetable_init(); + ff_flif16_build_log4k_table(&s->rc->log4k); + #endif + + ff_flif16_chancetable_init(&s->rc.ct, s->alpha, s->cut); + + return 0; + + need_more_data: + // MSG("Need more data\n"); + return AVERROR(EAGAIN); +} + + +static int flif16_read_transforms(AVCodecContext *avctx) +{ + FLIF16DecoderContext *s = avctx->priv_data; + FLIF16RangesContext *prev_range; + uint8_t const_plane_value[MAX_PLANES]; + uint8_t temp; + int unique_frames; + + loop: + switch (s->segment) { + case 0: + RAC_GET(&s->rc, NULL, 0, 0, &temp, FLIF16_RAC_BIT); + if(!temp) + goto end; + ++s->segment; + + case 1: + RAC_GET(&s->rc, NULL, 0, 13, &temp, FLIF16_RAC_UNI_INT8); + if (!flif16_transforms[temp]) { + av_log(avctx, AV_LOG_ERROR, "transform %u not implemented\n", temp); + return AVERROR_PATCHWELCOME; + } + + s->transforms[s->transform_top] = ff_flif16_transform_init(temp, s->range); + if (!s->transforms[s->transform_top]) { + av_log(avctx, AV_LOG_ERROR, "failed to initialise transform %u\n", temp); + return AVERROR(ENOMEM); + } + + switch (temp) { + case FLIF16_TRANSFORM_PALETTEALPHA: + s->plane_mode[FLIF16_PLANE_ALPHA] = FLIF16_PLANEMODE_CONSTANT; + ff_flif16_transform_configure(s->transforms[s->transform_top], + s->alphazero); + + case FLIF16_TRANSFORM_CHANNELCOMPACT: + if (s->num_planes > 3 && !s->plane_mode[FLIF16_PLANE_ALPHA]) + s->plane_mode[FLIF16_PLANE_ALPHA] = FLIF16_PLANEMODE_FILL; + + case FLIF16_TRANSFORM_YCOCG: + case FLIF16_TRANSFORM_PALETTE: + s->plane_mode[FLIF16_PLANE_Y] = FLIF16_PLANEMODE_NORMAL; + s->plane_mode[FLIF16_PLANE_CO] = FLIF16_PLANEMODE_NORMAL; + s->plane_mode[FLIF16_PLANE_CG] = FLIF16_PLANEMODE_NORMAL; + break; + + case FLIF16_TRANSFORM_DUPLICATEFRAME: + s->framedup = 1; + if(s->num_frames < 2) + return AVERROR(EINVAL); + ff_flif16_transform_configure(s->transforms[s->transform_top], + s->num_frames); + break; + + case FLIF16_TRANSFORM_FRAMESHAPE: + s->frameshape = 1; + if (s->num_frames < 2) + return AVERROR(EINVAL); + unique_frames = s->num_frames - 1; + for (unsigned int i = 0; i < s->num_frames; i++) { + if(s->frames[i].seen_before >= 0) + unique_frames--; + } + if (unique_frames < 1) + return AVERROR(EINVAL); + ff_flif16_transform_configure(s->transforms[s->transform_top], + (unique_frames) * s->height); + ff_flif16_transform_configure(s->transforms[s->transform_top], + s->width); + break; + + case FLIF16_TRANSFORM_FRAMELOOKBACK: + if(s->num_frames < 2) + return AVERROR(EINVAL); + s->framelookback = 1; + ff_flif16_transform_configure(s->transforms[s->transform_top], + s->num_frames); + break; + } + ++s->segment; + + case 2: + if(ff_flif16_transform_read(s->transforms[s->transform_top], + CTX_CAST(s), s->range) <= 0) + goto need_more_data; + prev_range = s->range; + s->range = ff_flif16_transform_meta(CTX_CAST(s), s->frames, s->num_frames, + s->transforms[s->transform_top], + prev_range); + if(!s->range) + return AVERROR(ENOMEM); + s->segment = 0; + ++s->transform_top; + goto loop; + + case 3: + end: + s->segment = 3; + // Read invisible pixel predictor + if ( s->alphazero && s->num_planes > 3 + && ff_flif16_ranges_min(s->range, 3) <= 0 + && !(s->ia % 2)) + RAC_GET(&s->rc, NULL, 0, 2, &s->ipp, FLIF16_RAC_UNI_INT8) + } + + for (int i = 0; i < FFMIN(s->num_planes, 4); ++i) { + if (s->plane_mode[i] != FLIF16_PLANEMODE_NORMAL) { + if (ff_flif16_ranges_min(s->range, i) >= ff_flif16_ranges_max(s->range, i)) + const_plane_value[i] = ff_flif16_ranges_min(s->range, i); + else + s->plane_mode[i] = FLIF16_PLANEMODE_NORMAL; + } + } + + if (ff_flif16_planes_init(CTX_CAST(s), s->frames, s->plane_mode, + const_plane_value, s->framelookback) < 0) { + av_log(avctx, AV_LOG_ERROR, "could not allocate planes\n"); + return AVERROR(ENOMEM); + } + + // if (!(s->ia % 2)) + // s->state = FLIF16_ROUGH_PIXELDATA; + // else + // s->state = FLIF16_MANIAC; + s->state = FLIF16_MANIAC; + s->segment = 0; + return 0; + + need_more_data: + return AVERROR(EAGAIN); +} + +static int flif16_read_maniac_forest(AVCodecContext *avctx) +{ + int ret; + FLIF16DecoderContext *s = avctx->priv_data; + if (!s->maniac_ctx.forest) { + s->maniac_ctx.forest = av_mallocz((s->num_planes) * sizeof(*(s->maniac_ctx.forest))); + if (!s->maniac_ctx.forest) { + return AVERROR(ENOMEM); + } + s->segment = s->i = 0; // Remove later + } + switch (s->segment) { + case 0: + loop: + if (s->i >= s->num_planes) + goto end; + + if (!(s->ia % 2)) + s->prop_ranges = ff_flif16_maniac_prop_ranges_init(&s->prop_ranges_size, s->range, + s->i, s->num_planes); + else + s->prop_ranges = ff_flif16_maniac_ni_prop_ranges_init(&s->prop_ranges_size, s->range, + s->i, s->num_planes); + + if(!s->prop_ranges) + return AVERROR(ENOMEM); + ++s->segment; + + case 1: + if (ff_flif16_ranges_min(s->range, s->i) >= ff_flif16_ranges_max(s->range, s->i)) { + ++s->i; + --s->segment; + goto loop; + } + ret = ff_flif16_read_maniac_tree(&s->rc, &s->maniac_ctx, s->prop_ranges, + s->prop_ranges_size, s->i); + if (ret) { + goto error; + } + av_freep(&s->prop_ranges); + --s->segment; + ++s->i; + goto loop; + } + + end: + s->state = FLIF16_PIXELDATA; + s->segment = 0; + return 0; + + error: + return ret; +} + +/* ============================================================================ + * Non interlaced plane decoding + * ============================================================================ + */ + + +static FLIF16ColorVal flif16_ni_predict_calcprops(FLIF16DecoderContext *s, + FLIF16PixelData *pixel, + FLIF16ColorVal *properties, + FLIF16RangesContext *ranges_ctx, + uint8_t p, uint32_t r, + uint32_t c, FLIF16ColorVal *min, + FLIF16ColorVal *max, + const FLIF16ColorVal fallback, + uint8_t nobordercases) +{ + FLIF16ColorVal guess, left, top, topleft, gradientTL; + int width = s->width; + int which = 0; + int index = 0; + if (p < 3) { + for (int pp = 0; pp < p; pp++) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, pp, r, c); //image(pp,r,c); + } + if (ranges_ctx->num_planes > 3) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, 3, r, c); //image(3,r,c); + } + } + left = (nobordercases || c > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r, c-1) : + (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c) : fallback)); + top = (nobordercases || r > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c) : left); + topleft = (nobordercases || (r>0 && c>0) ? + ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c-1) : (r > 0 ? top : left)); + gradientTL = left + top - topleft; + guess = MEDIAN3(gradientTL, left, top); + ff_flif16_ranges_snap(ranges_ctx, p, properties, min, max, &guess); + + if (guess == gradientTL) + which = 0; + else if (guess == left) + which = 1; + else if (guess == top) + which = 2; + + properties[index++] = guess; + properties[index++] = which; + + if (nobordercases || (c > 0 && r > 0)) { + properties[index++] = left - topleft; + properties[index++] = topleft - top; + } else { + properties[index++] = 0; + properties[index++] = 0; + } + + if (nobordercases || (c+1 < width && r > 0)) { + properties[index++] = top - ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c+1); // top - topright + } else { + properties[index++] = 0; + } + + if (nobordercases || r > 1) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-2, c) - top; // toptop - top + } else { + properties[index++] = 0; + } + + if (nobordercases || c > 1) { + properties[index++] = ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r, c-2) - left; // leftleft - left + } else { + properties[index++] = 0; + } + + return guess; +} + +static inline FLIF16ColorVal flif16_ni_predict(FLIF16DecoderContext *s, + FLIF16PixelData *pixel, + uint32_t p, uint32_t r, uint32_t c, + FLIF16ColorVal gray) { + FLIF16ColorVal left = (c > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r, c-1) : + (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r-1, c) : gray)); + FLIF16ColorVal top = (r > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r - 1, c) : left); + FLIF16ColorVal topleft = (r > 0 && c > 0 ? ff_flif16_pixel_get(CTX_CAST(s), pixel, p, r - 1, c - 1) : top); + FLIF16ColorVal gradientTL = left + top - topleft; + return MEDIAN3(gradientTL, left, top); +} + +static int flif16_read_ni_plane(FLIF16DecoderContext *s, + FLIF16RangesContext *ranges_ctx, + FLIF16ColorVal *properties, uint8_t p, + uint32_t fr, uint32_t r, FLIF16ColorVal gray, + FLIF16ColorVal minP) +{ + FLIF16ColorVal curr; + uint32_t begin = 0, end = s->width; + switch (s->segment2) { + case 0: + // if this is a duplicate frame, copy the row from the frame being duplicated + // TODO add this condition in read_ni_image + if (s->frames[fr].seen_before >= 0) { + return 0; + } + + // if this is not the first or only frame, fill the beginning of the row + // before the actual pixel data + if (fr > 0) { + // if alphazero is on, fill with a predicted value, otherwise + // copy pixels from the previous frame + begin = (!s->frameshape) ? 0 : s->frames[fr].col_begin[r]; + end = (!s->frameshape) ? s->width : s->frames[fr].col_end[r]; + if (s->alphazero && p < 3) { + for (uint32_t c = 0; c < begin; c++) + if (PIXEL_GET(s, fr, 3, r, c) == 0) { + PIXEL_SET(s, fr, p, r, c, flif16_ni_predict(s, &s->frames[fr], p, r, c, gray)); + } else { + PIXEL_SET(s, fr, p, r, c, PIXEL_GET(s, PREV_FRAMENUM(s->frames, fr), p, r, c)); + } + } else if (p != 4) { + ff_flif16_copy_rows(CTX_CAST(s), &s->frames[fr], + PREV_FRAME(s->frames, fr), p, r, 0, begin); + } + } + ++s->segment2; + + if (r > 1 && !s->framelookback && begin == 0 && end > 3) { + //decode actual pixel data + s->c = begin; + + for (; s->c < 2; s->c++) { + if (s->alphazero && p<3 && + PIXEL_GET(s, fr, 3, r, s->c) == 0) { + PIXEL_SET(s, fr, p, r, s->c, + flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray)); + continue; + } + s->guess = flif16_ni_predict_calcprops(s, &s->frames[fr], + properties, ranges_ctx, p, r, s->c, &s->min, &s->max, minP, 0); + case 1: + MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p, + s->min - s->guess, s->max - s->guess, &curr); + curr += s->guess; + ff_flif16_pixel_set(CTX_CAST(s), &s->frames[fr], p, r, s->c, curr); + } + ++s->segment2; + + for (; s->c < end-1; s->c++) { + if (s->alphazero && p < 3 && + ff_flif16_pixel_get(CTX_CAST(s), &s->frames[fr], 3, r, s->c) == 0) { + ff_flif16_pixel_set(CTX_CAST(s),&s->frames[fr], p, r, s->c, + flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray)); + continue; + } + s->guess = flif16_ni_predict_calcprops(s, &s->frames[fr], + properties, ranges_ctx, p, r, s->c, &s->min, &s->max, minP, 1); + case 2: + MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p, + s->min - s->guess, s->max - s->guess, &curr); + curr += s->guess; + PIXEL_SET(s, fr, p, r, s->c, curr); + } + ++s->segment2; + + for (; s->c < end; s->c++) { + if (s->alphazero && p < 3 && + PIXEL_GET(s, fr, 3, r, s->c) == 0) { + PIXEL_SET(s, fr, p, r, s->c, flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray)); + continue; + } + s->guess = flif16_ni_predict_calcprops(s, &s->frames[fr], + properties, ranges_ctx, p, r, s->c, &s->min, &s->max, minP, 0); + case 3: + MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p, + s->min - s->guess, s->max - s->guess, &curr); + curr += s->guess; + PIXEL_SET(s, fr, p, r, s->c, curr); + } + ++s->segment2; + + } else { + s->segment2 = 4; + for (s->c = begin; s->c < end; s->c++) { + //predict pixel for alphazero and get a previous pixel for lookback + if (s->alphazero && p < 3 && + ff_flif16_pixel_get(CTX_CAST(s), &s->frames[fr], 3, r, s->c) == 0) { + PIXEL_SET(s, fr, p, r, s->c, + flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray)); + continue; + } + if (s->framelookback && p < 4 && + PIXEL_GET(s, fr, FLIF16_PLANE_LOOKBACK, r, s->c) > 0) { + // TODO accomodate PRE_FRAME for this + PIXEL_SET(s, fr, p, r, s->c, + PIXEL_GET(s, fr - PIXEL_GET(s, fr, FLIF16_PLANE_LOOKBACK, r, s->c), p, r, s->c)); + continue; + } + //calculate properties and use them to decode the next pixel + s->guess = flif16_ni_predict_calcprops(s, &s->frames[fr], properties, + ranges_ctx, p, r, s->c, &s->min, + &s->max, minP, 0); + if (s->framelookback && p == FLIF16_PLANE_LOOKBACK && s->max > fr) + s->max = fr; + case 4: + MANIAC_GET(&s->rc, &s->maniac_ctx, properties, p, + s->min - s->guess, s->max - s->guess, &curr); + curr += s->guess; + PIXEL_SET(s, fr, p, r, s->c, curr); + } + } /* end if */ + + // If this is not the first or only frame, fill the end of the row after the actual pixel data + if (fr > 0) { + //if alphazero is on, fill with a predicted value, otherwise copy pixels from the previous frame + if (s->alphazero && p < 3) { + for (uint32_t c = end; c < s->width; c++) + if (PIXEL_GET(s, fr, 3, r, s->c) == 0) { + PIXEL_SET(s, fr, p, r, s->c, flif16_ni_predict(s, &s->frames[fr], p, r, s->c, gray)); + } else { + PIXEL_SET(s, fr, p, r, s->c, PIXEL_GET(s, PREV_FRAMENUM(s->frames, fr), p, r, s->c)); + } + } else if(p != 4) { + ff_flif16_copy_rows(CTX_CAST(s), &s->frames[fr], + PREV_FRAME(s->frames, fr), p, r, end, s->width); + } + } + } + + s->segment2 = 0; + return 0; + + need_more_data: + return AVERROR(EAGAIN); +} + + +static FLIF16ColorVal *compute_grays(FLIF16RangesContext *ranges) +{ + FLIF16ColorVal *grays; // a pixel with values in the middle of the bounds + grays = av_malloc(ranges->num_planes * sizeof(*grays)); + if (!grays) + return NULL; + for (int p = 0; p < ranges->num_planes; p++) + grays[p] = (ff_flif16_ranges_min(ranges, p) + ff_flif16_ranges_max(ranges, p)) / 2; + return grays; +} + +static int flif16_read_ni_image(AVCodecContext *avctx) +{ + FLIF16DecoderContext *s = avctx->priv_data; + int ret; + FLIF16ColorVal min_p; + + // Set images to gray + switch (s->segment) { + case 0: + s->grays = compute_grays(s->range); // free later + if (!s->grays) + return AVERROR(ENOMEM); + s->i = s->i2 = s->i3 = 0; + if ( (s->range->num_planes > 3 && ff_flif16_ranges_max(s->range, 3) == 0) + || (s->range->num_planes > 3 && ff_flif16_ranges_min(s->range, 3) > 0)) + s->alphazero = 0; + + ++s->segment; + + for (; s->i < 5; ++s->i) { + s->curr_plane = plane_ordering[s->i]; + if (s->curr_plane >= s->num_planes) { + continue; + } + if (ff_flif16_ranges_min(s->range, s->curr_plane) >= + ff_flif16_ranges_max(s->range, s->curr_plane)) { + continue; + } + s->properties = av_mallocz((s->num_planes > 3 ? properties_ni_rgba_size[s->curr_plane] + : properties_ni_rgb_size[s->curr_plane]) + * sizeof(*s->properties)); + if (!s->properties) + return AVERROR(ENOMEM); + for (; s->i2 < s->height; ++s->i2) { + for (; s->i3 < s->num_frames; ++s->i3) { + case 1: + // TODO maybe put this in dec ctx + min_p = ff_flif16_ranges_min(s->range, s->curr_plane); + ret = flif16_read_ni_plane(s, s->range, s->properties, + s->curr_plane, + s->i3, + s->i2, + s->grays[s->curr_plane], + min_p); + + if (ret) { + goto error; + } + } // End for + s->i3 = 0; + } // End for + if (s->properties) + av_freep(&s->properties); + s->i2 = 0; + } // End for + + } // End switch + + for (int i = 0; i < s->num_frames; i++) { + if (s->frames[i].seen_before >= 0) + continue; + for (int j = s->transform_top - 1; j >= 0; --j) { + ff_flif16_transform_reverse(CTX_CAST(s), s->transforms[j], &s->frames[i], 1, 1); + } + } + + if (s->grays) + av_freep(&s->grays); + + s->state = FLIF16_OUTPUT; + return 0; + + error: + return ret; +} + +/* ============================================================================ + * Interlaced plane decoding + * ============================================================================ + * + * This is how the data is organised here: + * 1. uni_int: rough_zoomlevel + * 2. (repeat num_planes times) values of top left pixels of each channel + * 3. Rough Pixeldata max_zoomlevel to rough_zoomlevel + 1 + * For this case, the MANIAC forest is initialised with a single node per + * channel. This is nused with the maniac integer reader. + * 4. Actual Encoded MANIAC trees + * 5. Rest of the pixeldata rough_zoomlevel to 0 + * + * TODO + */ + +static int flif16_read_pixeldata(AVCodecContext *avctx) +{ + FLIF16DecoderContext *s = avctx->priv_data; + int ret; + if((s->ia % 2)) + ret = flif16_read_ni_image(avctx); + else + return AVERROR(EINVAL); + + if(!ret) + s->state = FLIF16_OUTPUT; + + return ret; +} + +static int flif16_write_frame(AVCodecContext *avctx, AVFrame *data) +{ + uint32_t target_frame; + int ret; + FLIF16DecoderContext *s = avctx->priv_data; + ff_set_dimensions(avctx, s->width, s->height); + s->out_frame->pict_type = AV_PICTURE_TYPE_I; + + if (s->bpc > 65535) { + av_log(avctx, AV_LOG_ERROR, "depth per channel greater than 16 bits not supported\n"); + return AVERROR_PATCHWELCOME; + } + + avctx->pix_fmt = flif16_out_frame_type[FFMIN(s->num_planes, 4)][s->bpc > 255]; + + if ((ret = ff_reget_buffer(avctx, s->out_frame, 0)) < 0) { + return ret; + } + + target_frame = (s->frames[s->out_frames_count].seen_before >= 0) + ? s->frames[s->out_frames_count].seen_before + : s->out_frames_count; + + if (s->num_frames > 1) { + s->out_frame->pts = s->pts; + s->pts += s->framedelay[s->out_frames_count]; + } + + // Clear out transparent pixels + if (s->num_planes > 3) { + for (uint32_t i = 0; i < s->height; ++i) + for (uint32_t j = 0; j < s->width; ++j) + if (!PIXEL_GET(s, s->out_frames_count, FLIF16_PLANE_ALPHA, i, j)) { + PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_Y, i, j, 0); + PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_CO, i, j, 0); + PIXEL_SET(s, s->out_frames_count, FLIF16_PLANE_CG, i, j, 0); + } + } + + switch (avctx->pix_fmt) { + case AV_PIX_FMT_GRAY8: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *(s->out_frame->data[0] + i * s->out_frame->linesize[0] + j) = \ + PIXEL_GET(s, target_frame, 0, i, j); + } + } + break; + + case AV_PIX_FMT_RGB24: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *(s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 3 + 0 ) = \ + PIXEL_GET(s, target_frame, 0, i, j); + *(s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 3 + 1) = \ + PIXEL_GET(s, target_frame, 1, i, j); + *(s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 3 + 2) = \ + PIXEL_GET(s, target_frame, 2, i, j); + } + } + break; + + case AV_PIX_FMT_RGB32: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *((uint32_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 4)) + = (PIXEL_GET(s, target_frame, 3, i, j) << 24) | + (PIXEL_GET(s, target_frame, 0, i, j) << 16) | + (PIXEL_GET(s, target_frame, 1, i, j) << 8) | + PIXEL_GET(s, target_frame, 2, i, j); + } + } + break; + + case AV_PIX_FMT_GRAY16: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *((uint16_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 2)) = \ + PIXEL_GET(s, target_frame, 0, i, j); + } + } + break; + + case AV_PIX_FMT_RGB48: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *((uint16_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 6 + 0)) = \ + PIXEL_GET(s, target_frame, 0, i, j); + *((uint16_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 6 + 1)) = \ + PIXEL_GET(s, target_frame, 1, i, j); + *((uint16_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 6 + 2)) = \ + PIXEL_GET(s, target_frame, 2, i, j); + } + } + + case AV_PIX_FMT_RGBA64: + for (uint32_t i = 0; i < s->height; ++i) { + for (uint32_t j = 0; j < s->width; ++j) { + *((uint64_t *) (s->out_frame->data[0] + i * s->out_frame->linesize[0] + j * 8)) + = (uint64_t) \ + (((uint64_t) PIXEL_GET(s, target_frame, 3, i, j)) << 48) | + (((uint64_t) PIXEL_GET(s, target_frame, 2, i, j)) << 32) | + (((uint64_t) PIXEL_GET(s, target_frame, 1, i, j)) << 16) | + ((uint64_t) PIXEL_GET(s, target_frame, 0, i, j)); + } + } + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Pixel format %d out of bounds?\n", avctx->pix_fmt); + return AVERROR_PATCHWELCOME; + } + + av_frame_ref(data, s->out_frame); + if ((++s->out_frames_count) >= s->num_frames) + s->state = FLIF16_EOS; + + return 0; +} + +static int flif16_read_checksum(AVCodecContext *avctx) +{ + return AVERROR_EOF; +} + +static int flif16_decode_init(AVCodecContext *avctx) +{ + FLIF16DecoderContext *s = avctx->priv_data; + s->out_frame = av_frame_alloc(); + if (!s->out_frame) + return AVERROR(ENOMEM); + return 0; +} + +static int flif16_decode_frame(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + int ret = 0; + FLIF16DecoderContext *s = avctx->priv_data; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + AVFrame *p = data; + + bytestream2_init(&s->gb, buf, buf_size); + + // Looping is done to change states in between functions. + // Function will either exit on AVERROR(EAGAIN) or AVERROR_EOF + do { + switch(s->state) { + case FLIF16_HEADER: + ret = flif16_read_header(avctx); + break; + + case FLIF16_SECONDHEADER: + ret = flif16_read_second_header(avctx); + break; + + case FLIF16_TRANSFORM: + ret = flif16_read_transforms(avctx); + break; + + case FLIF16_ROUGH_PIXELDATA: + av_assert0(0); + ret = flif16_read_pixeldata(avctx); + if (!ret) + s->state = FLIF16_MANIAC; + break; + + case FLIF16_MANIAC: + // TODO manage interlaced condition + ret = flif16_read_maniac_forest(avctx); + break; + + case FLIF16_PIXELDATA: + ret = flif16_read_pixeldata(avctx); + break; + + case FLIF16_CHECKSUM: + ret = flif16_read_checksum(avctx); + break; + + case FLIF16_OUTPUT: + ret = flif16_write_frame(avctx, p); + if (!ret) { + *got_frame = 1; + return buf_size; + } + break; + + case FLIF16_EOS: + return AVERROR_EOF; + } + + } while (!ret); + + return ret; +} + +static av_cold int flif16_decode_end(AVCodecContext *avctx) +{ + FLIF16DecoderContext *s = avctx->priv_data; + if (s->framedelay) + av_freep(&s->framedelay); + if (s->prop_ranges) + av_freep(&s->prop_ranges); + if (s->frames) + ff_flif16_frames_free(&s->frames, s->num_frames, s->num_planes, s->framelookback); + + for (int i = s->transform_top - 1; i >= 0; --i) + ff_flif16_transforms_close(s->transforms[i]); + + ff_flif16_maniac_close(&s->maniac_ctx, s->num_planes); + av_frame_free(&s->out_frame); + + if (s->range) + ff_flif16_ranges_close(s->range); + return 0; +} + +AVCodec ff_flif16_decoder = { + .name = "flif16", + .long_name = NULL_IF_CONFIG_SMALL("FLIF (Free Lossless Image Format)"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_FLIF16, + .init = flif16_decode_init, + .close = flif16_decode_end, + .priv_data_size = sizeof(FLIF16DecoderContext), + .decode = flif16_decode_frame, + .capabilities = AV_CODEC_CAP_DELAY, + //.caps_internal = 0, + .priv_class = NULL, +}; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c index 7d75cea830..e5956d81cd 100644 --- a/libavcodec/parsers.c +++ b/libavcodec/parsers.c @@ -40,6 +40,7 @@ extern AVCodecParser ff_dvbsub_parser; extern AVCodecParser ff_dvdsub_parser; extern AVCodecParser ff_dvd_nav_parser; extern AVCodecParser ff_flac_parser; +extern AVCodecParser ff_flif16_parser; extern AVCodecParser ff_g723_1_parser; extern AVCodecParser ff_g729_parser; extern AVCodecParser ff_gif_parser; diff --git a/libavformat/Makefile b/libavformat/Makefile index 62d8cbb54e..514fb827aa 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -191,6 +191,7 @@ OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o rawdec.o \ OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o flacenc_header.o \ vorbiscomment.o OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o +OBJS-$(CONFIG_FLIF_DEMUXER) += flifdec.o OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o OBJS-$(CONFIG_LIVE_FLV_DEMUXER) += flvdec.o OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index fd9e46e233..7d941cdcfe 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -149,6 +149,7 @@ extern AVOutputFormat ff_fits_muxer; extern AVInputFormat ff_flac_demuxer; extern AVOutputFormat ff_flac_muxer; extern AVInputFormat ff_flic_demuxer; +extern AVInputFormat ff_flif_demuxer; extern AVInputFormat ff_flv_demuxer; extern AVOutputFormat ff_flv_muxer; extern AVInputFormat ff_live_flv_demuxer; diff --git a/libavformat/flifdec.c b/libavformat/flifdec.c new file mode 100644 index 0000000000..a4241aedbb --- /dev/null +++ b/libavformat/flifdec.c @@ -0,0 +1,377 @@ +/* + * FLIF16 demuxer + * Copyright (c) 2020 Anamitra Ghorui + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * FLIF demuxer. + */ + +#include "avformat.h" +#include "libavutil/bprint.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "libavcodec/flif16.h" +#include "libavcodec/flif16_rangecoder.h" + +#include "config.h" + +// Remove later +#include + + +// Uncomment to disable metadata reading +// #undef CONFIG_ZLIB + +#if CONFIG_ZLIB +#include +#endif + +#define BUF_SIZE 4096 + +typedef struct FLIFDemuxContext { + const AVClass *class; +#if CONFIG_ZLIB + z_stream stream; + uint8_t active; +#endif + int64_t duration; +} FLIFDemuxContext; + + +#if CONFIG_ZLIB +static int flif_inflate(FLIFDemuxContext *s, uint8_t *buf, int buf_size, + uint8_t **out_buf, int *out_buf_size) +{ + int ret; + z_stream *stream = &s->stream; + + if (!s->active) { + s->active = 1; + stream->zalloc = Z_NULL; + stream->zfree = Z_NULL; + stream->opaque = Z_NULL; + stream->avail_in = 0; + stream->next_in = Z_NULL; + ret = inflateInit(stream); + + if (ret != Z_OK) + return ret; + + *out_buf_size = buf_size; + *out_buf = av_realloc(*out_buf, *out_buf_size); + if (!*out_buf) + return AVERROR(ENOMEM); + } + + stream->next_in = buf; + stream->avail_in = buf_size; + while (stream->total_out >= *out_buf_size) { + *out_buf = av_realloc(*out_buf, (*out_buf_size) * 2); + if (!out_buf) + return AVERROR(ENOMEM); + *out_buf_size *= 2; + } + + stream->next_out = *out_buf + stream->total_out; + stream->avail_out = *out_buf_size - stream->total_out - 1; // Last byte should be NULL char + printf("First 10 bytes: "); + for (int i = 0; i < FFMIN(10, buf_size); ++i) + printf("%x ", buf[i]); + printf("\n"); + printf("Buf size: %d, Outbuf size: %d\n", buf_size, *out_buf_size); + ret = inflate(stream, Z_NO_FLUSH); + printf("Return: %d Message: %s \nZ_NEED_DICT: %d\nZ_DATA_ERROR: %d\n" + "Z_MEM_ERROR: %d\n", ret, stream->msg, Z_NEED_DICT, Z_DATA_ERROR, + Z_MEM_ERROR); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + ret = inflateSync(stream); + printf("Sync ret: %d\n", ret); + printf("Buf size: %d, Outbuf size: %d\n", buf_size, *out_buf_size); + (void)inflateEnd(stream); + return AVERROR(EINVAL); + case Z_MEM_ERROR: + (void)inflateEnd(stream); + return AVERROR(ENOMEM); + } + + if (ret == Z_STREAM_END) { + ret = 0; + s->active = 0; + (*out_buf)[stream->total_out] = '\0'; + (void) inflateEnd(stream); + } else + ret = AVERROR(EAGAIN); + + return ret; // Return Z_BUF_ERROR/EAGAIN as long as input is incomplete. +} +#endif + +static int flif16_probe(const AVProbeData *p) +{ + uint32_t vlist[3] = {0}; + unsigned int count = 0, pos = 0; + + // Magic Number + if (memcmp(p->buf, flif16_header, 4)) { + return 0; + } + + for(int i = 0; i < 2 + (((p->buf[4] >> 4) > 4) ? 1 : 0); ++i) { + while (p->buf[5 + pos] > 127) { + if (!(count--)) { + return 0; + } + VARINT_APPEND(vlist[i], p->buf[5 + pos]); + ++pos; + } + VARINT_APPEND(vlist[i], p->buf[5 + pos]); + count = 0; + } + + if (!((vlist[0] + 1) && (vlist[1] + 1))) + return 0; + + if (((p->buf[4] >> 4) > 4) && !(vlist[2] + 2)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static int flif16_read_header(AVFormatContext *s) +{ + FLIFDemuxContext *dc = s->priv_data; + GetByteContext gb; + FLIF16RangeCoder rc; + + AVIOContext *pb = s->pb; + AVStream *st; + + uint32_t vlist[3] = {0}; + uint32_t flag, animated, temp; + uint32_t bpc = 0; + uint8_t tag[5] = {0}; + uint8_t buf[BUF_SIZE]; + uint32_t metadata_size = 0; + uint8_t *out_buf = NULL; + int out_buf_size = 0; + + unsigned int count = 4; + int ret; + int format; + int segment = 0, i = 0; + int64_t duration = 0; + uint8_t loops = 0; + uint8_t num_planes; + uint8_t num_frames; + + // Magic Number + if (avio_rl32(pb) != (*((uint32_t *) flif16_header))) { + av_log(s, AV_LOG_ERROR, "bad magic number\n"); + return AVERROR(EINVAL); + } + + st = avformat_new_stream(s, NULL); + flag = avio_r8(pb); + animated = (flag >> 4) > 4; + duration = !animated; + bpc = avio_r8(pb); // Bytes per channel + + num_planes = flag & 0x0F; + + for (int i = 0; i < (2 + animated); ++i) { + while ((temp = avio_r8(pb)) > 127) { + if (!(count--)) + return AVERROR_INVALIDDATA; + VARINT_APPEND(vlist[i], temp); + } + VARINT_APPEND(vlist[i], temp); + count = 4; + } + + + ++vlist[0]; + ++vlist[1]; + if (animated) + vlist[2] += 2; + else + vlist[2] = 1; + + num_frames = vlist[2]; + + while ((temp = avio_r8(pb))) { + // Get metadata identifier + #if CONFIG_ZLIB + tag[0] = temp; + for(int i = 1; i <= 3; ++i) + tag[i] = avio_r8(pb); + #else + avio_skip(pb, 3); + #endif + + // Read varint + while ((temp = avio_r8(pb)) > 127) { + if (!(count--)) + return AVERROR_INVALIDDATA; + VARINT_APPEND(metadata_size, temp); + } + VARINT_APPEND(metadata_size, temp); + count = 4; + + #if CONFIG_ZLIB + // Decompression Routines + while (metadata_size > 0) { + ret = avio_read(pb, buf, FFMIN(BUF_SIZE, metadata_size)); + metadata_size -= ret; + if((ret = flif_inflate(dc, buf, ret, &out_buf, &out_buf_size)) < 0 && + ret != AVERROR(EAGAIN)) { + av_log(s, AV_LOG_ERROR, "could not decode metadata\n"); + return ret; + } + } + av_dict_set(&s->metadata, tag, out_buf, 0); + #else + avio_skip(pb, metadata_size); + #endif + } + + #if CONFIG_ZLIB + if (out_buf) + av_freep(&out_buf); + #endif + + avio_read(pb, buf, FLIF16_RAC_MAX_RANGE_BYTES); + ff_flif16_rac_init(&rc, NULL, buf, FLIF16_RAC_MAX_RANGE_BYTES); + ret = avio_read_partial(pb, buf, BUF_SIZE); + bytestream2_init(&gb, buf, ret); + rc.gb = &gb; + + while (1) { + switch (segment) { + case 0: + if (bpc == '0') { + bpc = 0; + for (; i < num_planes; ++i) { + RAC_GET(&rc, NULL, 1, 15, &temp, FLIF16_RAC_UNI_INT8); + bpc = FFMAX(bpc, (1 << temp) - 1); + } + i = 0; + } else + bpc = (bpc == '1') ? 255 : 65535; + // MSG("planes : %d & bpc : %d\n", num_planes, bpc); + if (num_frames < 2) + goto end; + ++segment; + + case 1: + if (num_planes > 3) { + RAC_GET(&rc, NULL, 0, 1, &temp, FLIF16_RAC_UNI_INT8); + } + ++segment; + + case 2: + if (num_frames > 1) { + RAC_GET(&rc, NULL, 0, 100, &loops, FLIF16_RAC_UNI_INT8); + } else + loops = 1; + ++segment; + + case 3: + if (num_frames > 1) { + for (; i < num_frames; ++i) { + temp = 0; + RAC_GET(&rc, NULL, 0, 60000, &(temp), FLIF16_RAC_UNI_INT16); + duration += temp; + } + i = 0; + } else + duration = 1; + goto end; + } + + need_more_data: + ret = avio_read_partial(pb, buf, BUF_SIZE); + bytestream2_init(&gb, buf, ret); + } + + end: + if (bpc > 65535) { + av_log(s, AV_LOG_ERROR, "depth per channel greater than 16 bits not supported\n"); + return AVERROR_PATCHWELCOME; + } + + // The minimum possible delay in a FLIF16 image is 1 millisecond. + // Therefore time base is 10^-3, i.e. 1/1000 + format = flif16_out_frame_type[FFMIN(num_planes, 4)][bpc > 255]; + avpriv_set_pts_info(st, 64, 1, 1000); + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_FLIF16; + st->codecpar->width = vlist[0]; + st->codecpar->height = vlist[1]; + st->codecpar->format = format; + st->duration = duration * loops; + st->start_time = 0; + st->nb_frames = vlist[2]; + // st->need_parsing = 1; + + // Jump to start because flif16 decoder needs header data too + if (avio_seek(pb, 0, SEEK_SET) != 0) + return AVERROR(EIO); + //printf("At: [%s] %s, %d\n", __func__, __FILE__, __LINE__); + return 0; +} + + +static int flif16_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVIOContext *pb = s->pb; + int ret; + // FFMIN(BUF_SIZE, avio_size(pb)) + ret = av_get_packet(pb, pkt, avio_size(pb)); + return ret; +} + + +static const AVOption options[] = { + { NULL } +}; + +static const AVClass demuxer_class = { + .class_name = "FLIF demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + +AVInputFormat ff_flif_demuxer = { + .name = "flif", + .long_name = NULL_IF_CONFIG_SMALL("Free Lossless Image Format (FLIF)"), + .priv_data_size = sizeof(FLIFDemuxContext), + .extensions = "flif", + .read_probe = flif16_probe, + .read_header = flif16_read_header, + .read_packet = flif16_read_packet, + //.flags = AVFMT_NOTIMESTAMPS, + .priv_class = &demuxer_class, +};