diff --git a/Changelog b/Changelog
index cb310a3abc..4f88dbaadb 100644
--- a/Changelog
+++ b/Changelog
@@ -43,6 +43,7 @@ version <next>:
 - Rayman 2 ADPCM decoder
 - Rayman 2 APM demuxer
 - cas video filter
+- FLIF16 decoder
 
 
 version 4.2:
diff --git a/configure b/configure
index 06e3a7b2a8..872ee750e0 100755
--- a/configure
+++ b/configure
@@ -2709,6 +2709,8 @@ ffvhuff_encoder_select="huffyuv_encoder"
 fic_decoder_select="golomb"
 flac_decoder_select="flacdsp"
 flac_encoder_select="bswapdsp flacdsp lpc"
+flif16_decoder_select="flif16dec"
+flif16_encoder_select="flif16enc"
 flashsv2_decoder_deps="zlib"
 flashsv2_encoder_deps="zlib"
 flashsv_decoder_deps="zlib"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f1c032b456..2b86341a75 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -76,6 +76,7 @@ OBJS-$(CONFIG_EXIF)                    += exif.o tiff_common.o
 OBJS-$(CONFIG_FAANDCT)                 += faandct.o
 OBJS-$(CONFIG_FAANIDCT)                += faanidct.o
 OBJS-$(CONFIG_FDCTDSP)                 += fdctdsp.o jfdctfst.o jfdctint.o
+OBJS-$(CONFIG_FLIF16_RANGECODER)       += flif16_rangecoder.o
 FFT-OBJS-$(CONFIG_HARDCODED_TABLES)    += cos_tables.o cos_fixed_tables.o
 OBJS-$(CONFIG_FFT)                     += avfft.o fft_fixed.o fft_float.o \
                                           fft_fixed_32.o fft_init_table.o \
@@ -314,11 +315,15 @@ OBJS-$(CONFIG_FITS_DECODER)            += fitsdec.o fits.o
 OBJS-$(CONFIG_FITS_ENCODER)            += fitsenc.o
 OBJS-$(CONFIG_FLAC_DECODER)            += flacdec.o flacdata.o flac.o
 OBJS-$(CONFIG_FLAC_ENCODER)            += flacenc.o flacdata.o flac.o vorbis_data.o
+OBJS-$(CONFIG_FLIF16_DECODER)          += flif16dec.o flif16_rangecoder.o
+OBJS-$(CONFIG_FLIF16_ENCODER)          += flif16enc.o flif16_rangecoder.o
 OBJS-$(CONFIG_FLASHSV_DECODER)         += flashsv.o
 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
+OBJS-$(CONFIG_FLIF16_ENCODER)          += flif16enc.o
 OBJS-$(CONFIG_FMVC_DECODER)            += fmvc.o
 OBJS-$(CONFIG_FOURXM_DECODER)          += 4xm.o
 OBJS-$(CONFIG_FRAPS_DECODER)           += fraps.o
@@ -1046,6 +1051,7 @@ OBJS-$(CONFIG_DVD_NAV_PARSER)          += dvd_nav_parser.o
 OBJS-$(CONFIG_DVDSUB_PARSER)           += dvdsub_parser.o
 OBJS-$(CONFIG_FLAC_PARSER)             += flac_parser.o flacdata.o flac.o \
                                           vorbis_data.o
+OBJS-$(CONFIG_FLIF16_PARSER)           += flif16_parser.o
 OBJS-$(CONFIG_G723_1_PARSER)           += g723_1_parser.o
 OBJS-$(CONFIG_G729_PARSER)             += g729_parser.o
 OBJS-$(CONFIG_GIF_PARSER)              += gif_parser.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 674995df72..79a2d89ee8 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -119,6 +119,8 @@ 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_flif16_encoder;
 extern AVCodec ff_flv_encoder;
 extern AVCodec ff_flv_decoder;
 extern AVCodec ff_fmvc_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 894a9e5565..4e2af45dd0 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -461,6 +461,7 @@ enum AVCodecID {
     AV_CODEC_ID_MVDV,
     AV_CODEC_ID_MVHA,
     AV_CODEC_ID_CDTOONS,
+    AV_CODEC_ID_FLIF16,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 52178e7afe..993ec450c1 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1754,6 +1754,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("CDToons video"),
         .props     = AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_FLIF16,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "flif16",
+        .long_name = NULL_IF_CONFIG_SMALL("FLIF16 (Free Lossless Image Format)"),
+        .props     = AV_CODEC_PROP_LOSSLESS,
+    },
 
     /* various PCM "codecs" */
     {
diff --git a/libavcodec/flif16.h b/libavcodec/flif16.h
new file mode 100644
index 0000000000..8206f82a64
--- /dev/null
+++ b/libavcodec/flif16.h
@@ -0,0 +1,37 @@
+/*
+ * 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 <stdint.h>
+#include <stdlib.h>
+// Remove this
+#define __PLN__ printf("At: [%s] %s, %d\n", __func__, __FILE__, __LINE__);
+static const uint8_t flif16_header[4] = "FLIF";
+#define FF_FLIF16_VARINT_APPEND(a,x) a = (a << 7) | (uint64_t) (x & 127)
+
+#endif /* AVCODEC_FLIF16_H */
diff --git a/libavcodec/flif16_parser.c b/libavcodec/flif16_parser.c
new file mode 100644
index 0000000000..b56c330443
--- /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 <stdio.h> //remove
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef enum FLIF16ParseStates {
+    FLIF16_HEADER = 1,
+    FLIF16_METADATA,
+    FLIF16_BITSTREAM,
+    FLIF16_CHECKSUM,
+    FLIF16_VARINT
+} 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
+    uint64_t width;
+    uint64_t height;
+    uint64_t frames;
+    uint64_t meta;      ///< Size of a meta chunk
+    uint64_t count;
+} FLIF16ParseContext;
+
+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 == 9)
+                        return AVERROR(ENOMEM);
+
+                switch (f->varint) {
+                    case 1:
+                        FF_FLIF16_VARINT_APPEND(f->width, buf[index]);
+                        break;
+                    
+                    case 2:
+                        FF_FLIF16_VARINT_APPEND(f->height, buf[index]);
+                        break;
+                    
+                    case 3:
+                        FF_FLIF16_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;
+                }
+                FF_FLIF16_VARINT_APPEND(f->meta, buf[index]);
+                f->count++;
+            } else if (f->meta > 1) {
+                // increment varint until equal to size
+                f->meta--;
+            } else {
+                f->meta = 0;
+                f->index = 0;
+                continue;
+            }
+            f->index++;
+        } else if (f->state == FLIF16_BITSTREAM) {
+            /* Since we cannot find the end of the bitstream without any
+             * processing, we will simply return each read chunk as a packet
+             * to the decoder.
+             */
+            printf("<Bitstream chunk size %dd>\n", buf_size);
+            return buf_size;
+        }
+    }
+    printf("End not found\n");
+    return next;
+}
+
+static int flif16_parse(AVCodecParserContext *s, AVCodecContext *avctx,
+                        const uint8_t **poutbuf, int *poutbuf_size,
+                        const uint8_t *buf, int buf_size)
+{
+    FLIF16ParseContext *fpc = s->priv_data;
+    int next;
+    
+    next = flif16_find_frame(fpc, buf, buf_size);
+    
+    if (ff_combine_frame(&fpc->pc, next, &buf, &buf_size) < 0) {
+        *poutbuf      = NULL;
+        *poutbuf_size = 0;
+        return buf_size;
+    }
+    printf("Width:%lu\nHeight:%lu\nFrames:%lu\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..4585693146
--- /dev/null
+++ b/libavcodec/flif16_rangecoder.c
@@ -0,0 +1,134 @@
+/*
+ * Range coder for FLIF16
+ * Copyright (c) 2004, 2020 Jon Sneyers, Michael Niedermayer, 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 "flif16_rangecoder.h"
+
+// TODO write separate function for RAC decoder
+
+// The coder requires a certain number of bytes for initiialization. buf
+// provides it. gb is used by the coder functions for actual coding.
+
+FLIF16RangeCoder *ff_flif16_rac_init(GetByteContext *gb, 
+                                     uint8_t *buf,
+                                     uint8_t buf_size)
+{
+    FLIF16RangeCoder *rc = av_mallocz(sizeof(*rc));
+    GetByteContext gbi;
+
+    if (!rc)
+        return NULL;
+    
+    if(buf_size < FLIF16_RAC_MAX_RANGE_BYTES)
+        return NULL;
+    
+    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);
+    }
+    printf("[%s] low = %d\n", __func__, rc->low);
+    return rc;
+}
+
+void ff_flif16_rac_free(FLIF16RangeCoder *rc)
+{
+    free(rc->ct);
+    free(rc->log4k);
+    free(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 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(FLIF16RangeCoder *rc)
+{
+    rc->log4k->table[0] = 0;
+    for (int i = 1; i < 4096; i++)
+        rc->log4k->table[i] = (log4kf(i, (65535UL << 16) / 12) + 
+                               (1 << 15)) >> 16;
+    rc->log4k->scale = 65535 / 12;
+}
+
+void ff_flif16_chancetable_init(FLIF16RangeCoder *rc, int alpha, int cut) {
+    rc->chance = 0x800;
+    rc->ct = av_mallocz(sizeof(*(rc->ct)));
+    build_table(rc->ct->zero_state, rc->ct->one_state, 4096, alpha, 4096 - cut);
+    ff_flif16_build_log4k_table(rc);
+}
diff --git a/libavcodec/flif16_rangecoder.h b/libavcodec/flif16_rangecoder.h
new file mode 100644
index 0000000000..a2bbd6d61e
--- /dev/null
+++ b/libavcodec/flif16_rangecoder.h
@@ -0,0 +1,395 @@
+/*
+ * 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 "rangecoder.h"
+#include "flif16.h"
+
+#include "libavutil/mem.h"
+#include "libavutil/intmath.h"
+#include "bytestream.h"
+
+#include <stdio.h> // Remove
+#include <stdint.h>
+#include <assert.h>
+
+#define FLIF16_RAC_MAX_RANGE_BITS 24
+#define FLIF16_RAC_MAX_RANGE_BYTES (FLIF16_RAC_MAX_RANGE_BITS / 8)
+#define FLIF16_RAC_MIN_RANGE_BITS 16
+#define FLIF16_RAC_MAX_RANGE (uint32_t) 1 << FLIF16_RAC_MAX_RANGE_BITS
+#define FLIF16_RAC_MIN_RANGE (uint32_t) 1 << FLIF16_RAC_MIN_RANGE_BITS
+
+
+typedef enum FLIF16RACTypes {
+    FLIF16_RAC_BIT = 0,
+    FLIF16_RAC_UNI_INT,
+    FLIF16_RAC_CHANCE,
+    FLIF16_RAC_NZ_INT,
+    FLIF16_RAC_GNZ_INT
+} FLIF16RACReaders;
+
+typedef struct FLIF16ChanceTable {
+    uint16_t zero_state[4096];
+    uint16_t one_state[4096];
+} FLIF16ChanceTable;
+
+typedef struct FLIF16Log4kTable {
+    uint16_t table[4096];
+    int scale;
+} FLIF16Log4kTable;
+
+typedef struct FLIF16RangeCoder {
+    unsigned int range;
+    unsigned int low;
+    uint16_t chance;
+    uint8_t empty;    ///< Is bytestream empty
+    uint8_t renorm;   ///< Is a renormalisation required 
+    uint8_t active;   ///< Is an integer reader currently active (to save/
+                      ///  transfer state)
+    
+    // uni_int state management
+    uint32_t min;
+    uint32_t len;
+
+    FLIF16ChanceTable *ct;
+    FLIF16Log4kTable *log4k;
+    GetByteContext *gb;
+} FLIF16RangeCoder;
+
+FLIF16RangeCoder *ff_flif16_rac_init(GetByteContext *gb, uint8_t *buf,
+                                     uint8_t buf_size);
+void ff_flif16_rac_free(FLIF16RangeCoder *rc);
+void ff_flif16_chancetable_init(FLIF16RangeCoder *rc, int alpha, int cut);
+void ff_flif16_build_log4k_table(FLIF16RangeCoder *rc);
+
+// NearZero Integer Definitions:
+// Maybe pad with extra 2048s for faster access like in original code.
+static uint16_t flif16_nz_int_chances[20] = {
+    1000, // Zero
+    2048, // Sign
+    
+    // Exponents
+    1000, 1200, 1500, 1750, 2000, 2300, 2800, 2400, 2300, 
+    2048, // <- exp >= 9
+    
+    // Mantisaa
+    1900, 1850, 1800, 1750, 1650, 1600, 1600, 
+    2048 // <- mant > 7
+};
+
+#define NZ_INT_ZERO (flif16_nz_int_chances[0])
+#define NZ_INT_SIGN (flif16_nz_int_chances[1])
+#define NZ_INT_EXP(k) ((k < 9) ? flif16_nz_int_chances[2 + (k)] : \
+                                 flif16_nz_int_chances[11])
+#define NZ_INT_MANT(k) ((k < 8) ? flif16_nz_int_chances[12 + (k)] : \
+                                  flif16_nz_int_chances[19])
+
+// Functions
+
+static inline int ff_flif16_rac_renorm(FLIF16RangeCoder *rc)
+{
+    uint32_t left = bytestream2_get_bytes_left(rc->gb);
+    printf("[%s] left = %d\n", __func__, left);
+    if (!left)
+        return 0;
+    while (rc->range <= FLIF16_RAC_MIN_RANGE) {
+        rc->low <<= 8;
+        rc->range <<= 8;
+        rc->low |= bytestream2_get_byte(rc->gb);
+        if(!left)
+            return 0;
+        else
+            --left;
+    }
+    rc->renorm = 0;
+    return 1;
+}
+
+static inline uint8_t ff_flif16_rac_get(FLIF16RangeCoder *rc, uint32_t chance,
+                                        uint8_t *target)
+{
+    // assert(rc->chance > 0);
+    // assert(rc->chance < rc->range);
+
+    // printf("[%s] low: %u range: %u chance: %u\n", __func__, rc->low, rc->range, chance);
+    if (rc->renorm) {
+        printf("[%s] Triggered\n", __func__);
+        return 0;
+    }
+
+    if (rc->low >= rc->range - chance) {
+        rc->low -= rc->range - chance;
+        rc->range = chance;
+        *target = 1;
+    } else {
+        rc->range -= chance;
+        *target = 0;
+    }
+    
+    rc->renorm = 1;
+    
+    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 (rc->renorm) {
+        printf("[%s] Triggered\n", __func__);
+        return 0;
+    }
+    // assert((b12 > 0) && (b12 >> 12) == 0);
+    // Optimisation based on CPU bus size (32/64 bit)
+    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,
+                                             uint32_t *target)
+{
+    // assert(len >= 0);
+    int med;
+    uint8_t bit;
+
+    if (rc->renorm) {
+        printf("[%s] Triggered\n", __func__);
+        return 0;
+    }
+
+    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;
+        }
+        //__PLN__
+        printf("[%s] min = %d , len = %d\n", __func__, rc->min, rc->len);
+        return 0;
+    } else {
+        *target = rc->min;
+        printf("[%s] target = %d\n", __func__, rc->min);
+        rc->active = 0;
+        return 1;
+    }
+}
+
+// Overload of above function in original code
+
+static inline int ff_flif16_rac_read_uni_int_bits(FLIF16RangeCoder *rc,
+                                                  int bits, uint32_t *target)
+{
+    return ff_flif16_rac_read_uni_int(rc, 0, (1 << bits) - 1, target);
+}
+
+// Nearzero integer definitions
+
+void inline ff_flif16_chancetable_put(FLIF16RangeCoder *rc, 
+                                      uint8_t bit, uint16_t chance)
+{
+    rc->chance = (!bit) ? rc->ct->zero_state[chance]
+                        : rc->ct->one_state[chance];
+}
+
+/**
+ * Reads a near-zero encoded symbol into the RAC probability model/chance table;
+ * @param chance The symbol chance specified by the NZ_INT_* macros
+ */
+/*
+static inline uint8_t ff_flif16_rac_read_symbol(FLIF16RangeCoder *rc,
+                                                uint16_t chance)
+{
+    uint8_t bit;
+    ff_flif16_rac_read_chance(rc, chance, &bit);
+    ff_flif16_chancetable_put(rc, bit, chance);
+    return bit;
+}
+*/
+/**
+ * Returns an integer encoded by near zero integer encoding.
+ */
+/*
+static inline int ff_flif16_rac_read_nz_int(FLIF16RangeCoder *rc, int min,
+                                            int max, uint32_t *target)
+{
+    uint8_t sign;
+    uint32_t temp;
+    const int amin = 1;
+    const int amax = (sign ? max : -min);
+    
+    const int emax = ff_log2(amax);
+    int e          = ff_log2(amin);
+    int have, left, minabs1, maxabs0;
+
+    if (min == max)
+        return min;
+    
+    switch (rc->segment) {
+        case 0:
+            ff_flif16_rac_read_symbol(rc, NZ_INT_ZERO, &temp);
+
+            if (temp) {
+                *target = 0;
+                return 1;
+            }
+            break;
+        
+        case 1:
+            if (min < 0) {
+                if (max > 0)
+                    sign = ff_flif16_rac_read_symbol(rc, NZ_INT_SIGN);
+                else
+                    sign = 0;
+            } else
+                sign = 1;
+            break;
+
+        case 2:
+            for (; e < emax; e++) {
+                ff_flif16_rac_read_symbol(rc, NZ_INT_EXP((e << 1) + sign),
+                                          target);
+                if (*target)
+                    break;
+            }
+            have = (1 << e);
+            left = have - 1;
+            break;
+
+        case 3:
+            for (int pos = e; pos > 0;) {
+                left >>= 1;
+                pos--;
+                minabs1 = have | (1 << pos);
+                maxabs0 = have | left;
+                if (minabs1 > amax) {
+                    continue;
+                } else if (maxabs0 >= amin) {
+                    if (ff_flif16_rac_read_symbol(rc, NZ_INT_MANT(pos)))
+                        have = minabs1;
+                } 
+                else
+                    have = minabs1;
+            }
+            
+            *target = (sign ? have : -have);
+            break;
+    }
+
+    return 1;
+}
+
+static inline int ff_flif16_rac_read_gnz_int(FLIF16RangeCoder *rc, int min,
+                                             int max)
+{
+    if (min > 0) 
+        return ff_flif16_rac_read_nz_int(rc, 0, max - min) + min;
+    else if (max < 0) 
+        return ff_flif16_rac_read_nz_int(rc, min - max, 0) + max;
+    else 
+        return ff_flif16_rac_read_nz_int(rc, min, max);
+}
+*/
+
+/**
+ * Reads an integer encoded by FLIF's RAC.
+ * @param val1 A generic value, chosen according to the required type
+ * @param val2 Same as val1
+ * @param target The place where the resultant value should be written to
+ * @param type The type of the integer to be decoded specified by FLIF16RACTypes
+ * 
+ * @return -1 on bytestream empty, 0 on successful decoding.
+ */
+static inline int ff_flif16_rac_process(FLIF16RangeCoder *rc, uint32_t val1, 
+                                        uint32_t val2, uint32_t *target, 
+                                        int type)
+{
+    int flag = 0;
+    while (!flag) {
+        printf("[%s] low = %d range = %d renorm = %d\n", __func__, rc->low, 
+               rc->range, rc->renorm);
+        if(rc->renorm) {
+            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_INT:
+                flag = ff_flif16_rac_read_uni_int(rc, val1, val2, 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
+                break;
+            
+            case FLIF16_RAC_GNZ_INT:
+                // handle gnz_ints
+                break;
+            
+            default:
+                printf("[%s] unknown rac reader\n", __func__);
+                break;
+        }
+    }
+
+    return 1;
+}
+
+#endif /* FLIF16_RANGECODER_H */
diff --git a/libavcodec/flif16_transform.c b/libavcodec/flif16_transform.c
new file mode 100644
index 0000000000..3e66a972e9
--- /dev/null
+++ b/libavcodec/flif16_transform.c
@@ -0,0 +1,247 @@
+#include "flif16_transform.h"
+
+int process(Transform transform, AVFrame *frame, int planes, interimPixelData *pixelData){
+	if(!pixelData->initialized){
+		int r, c;
+		int p;
+		int width = frame->width, height = frame->height;
+		pixelData->height = height;
+		pixelData->width = width;
+		pixelData->num_planes = planes;
+		for(p = 0; p < p; p++){
+			pixelData->data[p] = (ColorVal*)malloc(height*width*sizeof(ColorVal));
+			for(r = 0; r < frame->height; r++){
+				for(c = 0; c < frame->width; c++){
+					pixelData->data[p][r*width + c] = frame->data[p][r*width + c];
+				}
+			}
+		}
+		pixelData->initialized = 1;
+	}
+	switch(transform.transform_number){
+        case 1: //Transform number for YCoCg transformation is 1 officially.
+        if(!transform.done){
+			TransformYCoCg transformYCoCg = initYCoCg(pixelData);
+            if(!processYCoCg(pixelData))
+            	transform.done = 1;
+            return 0;
+        }
+		break;
+
+        /*
+        Rest of the cases will be implemented here.
+        */
+
+        default:
+        break;
+    }
+    return 0;
+}
+
+TransformYCoCg initYCoCg(interimPixelData *pixelData){
+	TransformYCoCg transform;
+	transform.ranges = getRanges(pixelData);
+    transform.origmax4 = max(transform.ranges[0].max, transform.ranges[1].max, transform.ranges[2].max)/4 -1;
+    int p;
+	for(p=0; p<pixelData->num_planes; p++){
+    	transform.ranges[p].max = max_range_YCoCg(p, transform.origmax4);
+    	transform.ranges[p].min = min_range_YCoCg(p, transform.origmax4);
+	}
+    return transform;
+}
+
+int processYCoCg(interimPixelData *pixelData){
+    int r, c;
+    ColorVal R,G,B,Y,Co,Cg;
+    
+    //Assuming all the channels will have same width and height
+	int height = pixelData->height;
+    int width = pixelData->width;
+    
+	for (r=0; r<height; r++) {
+        for (c=0; c<width; c++) {
+            R = pixelData->data[0][r*width + c];
+            G = pixelData->data[1][r*width + c];
+            B = pixelData->data[2][r*width + c];
+
+            Y = (((R + B)>>1) + G)>>1;
+            Co = R - B;
+            Cg = G - ((R + B)>>1);
+
+            pixelData->data[0][r*width + c] = Y;
+            pixelData->data[1][r*width + c] = Co;
+            pixelData->data[2][r*width + c] = Cg;
+        }
+    }
+	return 0;
+}
+
+// TODO inversetransform requires more work. 
+/*
+int invProcessYCoCg(AVFrame *frame){
+	int r, c;
+    ColorVal R,G,B,Y,Co,Cg;
+    
+    //Assuming all the channels will have same width and height
+	int height = frame[0].height;
+    int width = frame[0].width;
+    
+	for (r=0; r<height; r++) {
+        for (c=0; c<width; c++) {
+            Y = frame->data[0][r*width + c];
+            Co= frame->data[1][r*width + c];
+            Cg= frame->data[2][r*width + c];
+
+            R = Co + Y + ((1-Cg)>>1) - (Co>>1);
+            G = Y - ((-Cg)>>1);
+            B = Y + ((1-Cg)>>1) - (Co>>1);
+
+            frame->data[0][r*width + c] = R;
+            frame->data[1][r*width + c] = G;
+            frame->data[2][r*width + c] = B;
+        }
+    }
+	return 0;
+}
+*/
+
+ColorRanges* getRanges(interimPixelData *pixelData){
+    int p = pixelData->num_planes;
+	ColorRanges ranges[p];
+    int i, c, r, width, height;
+    ColorVal min, max;
+    
+    for(i=0; i<p; i++){
+        width = pixelData->width;
+        height = pixelData->height;
+        min = pixelData->data[p][0];
+        max = pixelData->data[p][0];
+        for(r=0; r<pixelData->height; r++){
+            for(c=0; c<pixelData->width; r++){
+                if(min > pixelData->data[p][r*width + c])
+                    min = pixelData->data[p][r*width + c];
+                if(max < pixelData->data[p][r*width + c])
+                    max = pixelData->data[p][r*width + c];
+            }
+        }
+        ranges[p].min = min;
+        ranges[p].max = max;
+    }
+    return ranges;
+}
+
+int max(int a, int b, int c){
+	if(a > b){
+		if(a > c)
+			return a;
+		else
+			return c;
+	}
+	else
+		return b;
+}
+
+int min(int a, int b){
+	if(a < b)
+		return a;
+	else
+		return b;
+}
+
+int get_min_y(int origmax4){
+	return 0;
+}
+
+int get_max_y(int origmax4){
+	return 4*origmax4-1;
+}
+
+int get_min_co(int origmax4, int yval){
+	int newmax = 4*origmax4 - 1;
+	if (yval < origmax4-1)
+    	return -3 - 4*yval; 
+	else if (yval >= 3*origmax4)
+      	return 4*(yval - newmax);
+    else
+      	return -newmax;
+}
+
+int get_max_co(int origmax4, int yval){
+	int newmax = 4*origmax4 - 1;
+	if (yval < origmax4-1)
+    	return 3 + 4*yval; 
+	else if (yval >= 3*origmax4)
+      	return 4*(newmax - yval);
+    else
+      	return newmax;
+}
+
+int get_min_cg(int origmax4, int yval, int coval){
+	int newmax = 4*origmax4 - 1;
+	if (yval < origmax4-1)
+    	return -2 - 2*yval; 
+	else if (yval >= 3*origmax4)
+      	return -2*(newmax-yval) + 2*((abs(coval)+1)/2);
+    else{
+      	return min(2*yval + 1, 2*newmax - 2*yval - 2*abs(coval)+1)/2;
+	}
+}
+
+int get_max_cg(int origmax4, int yval, int coval){
+	int newmax = 4*origmax4 - 1;
+	if (yval < origmax4-1)
+    	return 1 + 2*yval - 2*(abs(coval)/2); 
+	else if (yval >= 3*origmax4)
+      	return 2 * (newmax-yval);
+    else
+      	return min(2*(yval- newmax), -2*yval - 1 + 2*(abs(coval)/2));
+}
+
+int min_range_YCoCg(int p, int origmax4){
+	switch(p){
+		case 0:
+			return 0;
+        case 1:
+			return -4*origmax4+1;
+        case 2:
+			return -4*origmax4+1;
+		default:
+			return 0;
+			break;
+	}
+}
+
+int max_range_YCoCg(int p, int origmax4){
+	switch(p){
+		case 0:
+			return 0;
+        case 1:
+			return 4*origmax4+1;
+        case 2:
+			return 4*origmax4+1;
+		default:
+			return 0;
+			break;
+	}
+}
+
+ColorRanges crangeYCoCg(int p, ColorVal* prevPlanes, TransformYCoCg transform){
+	ColorRanges crange;
+	switch(p){
+		case 0:
+			crange.min = get_min_y(transform.origmax4);
+			crange.max = get_max_y(transform.origmax4);
+			break;
+		case 1:
+			crange.min = get_min_co(transform.origmax4, prevPlanes[0]);
+			crange.max = get_max_co(transform.origmax4, prevPlanes[0]);
+			break;	
+		case 2:
+			crange.min = get_min_cg(transform.origmax4, prevPlanes[0], prevPlanes[1]);
+			crange.max = get_max_cg(transform.origmax4, prevPlanes[0], prevPlanes[1]);
+			break;
+		default:
+			break; 
+	}
+	return crange;
+}
diff --git a/libavcodec/flif16_transform.h b/libavcodec/flif16_transform.h
new file mode 100644
index 0000000000..318c5638e2
--- /dev/null
+++ b/libavcodec/flif16_transform.h
@@ -0,0 +1,60 @@
+#include <stdint.h>
+#include "../libavutil/frame.h"
+#define MAX_PLANES 5
+
+typedef int16_t ColorVal;
+
+typedef struct{
+   	ColorVal min, max;
+}ColorRanges;
+
+typedef struct{
+    char* desc;
+    int transform_number;
+    uint8_t done;
+}Transform;
+
+typedef struct{
+    int origmax4;
+    ColorRanges *ranges;
+}TransformYCoCg;
+
+typedef struct{
+    uint8_t initialized;
+    int height, width;
+    int num_planes;
+    ColorVal *data[MAX_PLANES];
+}interimPixelData;
+
+typedef struct TransformPermute{
+	uint8_t subtract;
+	uint8_t permutation[MAX_PLANES];
+    ColorRanges *ranges;
+}TransformPermute; 
+
+ColorRanges* getRanges(interimPixelData* pixelData);
+
+int getmax(ColorRanges* ranges, int p);
+
+int max_range_YCoCg(int p, int origmax4);
+int min_range_YCoCg(int p, int origmax4);
+
+int get_min_y(int);
+int get_max_y(int orgimax4);
+
+int get_min_co(int orgimax4, int yval);
+int get_max_co(int orgimax4, int yval);
+
+int get_min_cg(int orgimax4, int yval, int coval);
+int get_max_cg(int orgimax4, int yval, int coval);
+
+int min(int, int);
+int max(int, int, int);
+
+ColorRanges crangesYCoCg(int p, ColorVal* prevPlanes, TransformYCoCg transform);
+
+int process(Transform transform, AVFrame *frame, int p, interimPixelData *pixelData);
+TransformYCoCg initYCoCg(interimPixelData *pixelData);
+int processYCoCg(interimPixelData *pixelData);
+int invProcessYCoCg(AVFrame *frame);
+
diff --git a/libavcodec/flif16dec.c b/libavcodec/flif16dec.c
new file mode 100644
index 0000000000..37ac1d2175
--- /dev/null
+++ b/libavcodec/flif16dec.c
@@ -0,0 +1,372 @@
+/*
+ * 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 <stdio.h> // Remove
+
+#include "flif16.h"
+#include "flif16_rangecoder.h"
+
+#include "avcodec.h"
+#include "libavutil/common.h"
+#include "bytestream.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 prefix approprate functions with ff_*
+
+enum FLIF16States {
+    FLIF16_HEADER = 1,
+    FLIF16_SECONDHEADER,
+    FLIF16_TRANSFORM,
+    FLIF16_PIXELDATA,
+    FLIF16_CHECKSUM
+};
+
+typedef struct FLIF16RACQueue {
+    uint32_t val1;
+    uint32_t val2;
+    uint32_t *target;
+    int done;
+    int type;
+} FLIF16RACQueue;
+
+typedef struct FLIF16DecoderContext {
+    GetByteContext gb;
+    FLIF16RangeCoder *rc;
+    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
+    int i;               ///< A generic iterator used to save states between
+                         ///  for loops.
+    // Primary Header
+    uint8_t ia;          ///< Is image interlaced or/and animated or not
+    uint8_t bpc;         ///< Bytes per channel
+    uint8_t channels;    ///< Number of channels
+    uint8_t varint;      ///< Number of varints to process in sequence
+    
+    // Secondary Header
+    uint8_t  channelbpc; ///< bpc per channel. Size == 1 if bpc == '0' 
+                         ///  else equal to number of frames
+    
+    // Flags. TODO Merge all these flags
+    uint8_t alphazero;   ///< Alphazero
+    uint8_t custombc;    ///< Custom Bitchance
+
+    uint8_t cutoff; 
+    uint8_t alphadiv;
+
+    uint8_t loops;       ///< Number of times animation loops
+    uint16_t *framedelay;///< Frame delay for each frame
+    
+    // Dimensions and other things.
+    uint32_t width;
+    uint32_t height;
+    uint32_t frames;
+    uint32_t meta;      ///< Size of a meta chunk
+} FLIF16DecoderContext;
+
+
+static int flif16_read_header(AVCodecContext *avctx)
+{
+    uint8_t temp, count = 3;
+    FLIF16DecoderContext *s = avctx->priv_data;
+    // TODO Make do without this array
+    uint32_t *vlist[] = { &s->width, &s->height, &s->frames };
+    // Minimum size has empirically found to be 14 bytes.
+    __PLN__
+    /*
+    if (bytestream2_size(&s->gb) < 14) {
+        av_log(avctx, AV_LOG_ERROR, "buf size too small (%d)\n", 
+               bytestream2_size(&s->gb));
+        return AVERROR(EINVAL);
+    }*/
+    __PLN__
+    if (bytestream2_get_le32(&s->gb) != (*((uint32_t *) flif16_header))) {
+        av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
+        return AVERROR(EINVAL);
+    }
+    __PLN__
+    s->state = FLIF16_HEADER;
+
+    temp = bytestream2_get_byte(&s->gb);
+    s->ia       = temp >> 4;
+    s->channels = (0x0F & temp);
+    s->bpc      = bytestream2_get_byte(&s->gb);
+    __PLN__
+    // Will be later updated by the secondary header step, if bpc = 3
+    s->channelbpc = (s->bpc == '1') ? 8 : 16;
+    
+    // Handle dimensions and frames
+    for(int i = 0; i < 2 + ((s->ia > 4) ? 1 : 0); ++i) {
+        while ((temp = bytestream2_get_byte(&s->gb)) > 127) {
+            FF_FLIF16_VARINT_APPEND(*vlist[i], temp);
+            if (!count) {
+                av_log(avctx, AV_LOG_ERROR, "image dimensions too big\n");
+                return AVERROR(ENOMEM);
+            }
+        }
+        FF_FLIF16_VARINT_APPEND(*vlist[i], temp);
+        count = 3;
+    }
+    __PLN__
+    s->width++;
+    s->height++;
+    (s->ia > 4) ? (s->frames += 2) : (s->frames = 1);
+    
+    // Handle Metadata Chunk. Currently it discards all data.
+    __PLN__
+    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) {
+            FF_FLIF16_VARINT_APPEND(s->meta, temp);
+            if (!count) {
+                av_log(avctx, AV_LOG_ERROR, "metadata chunk too big \n");
+                return AVERROR(ENOMEM);
+            }
+        }
+        FF_FLIF16_VARINT_APPEND(s->meta, temp);
+        bytestream2_seek(&s->gb, s->meta, SEEK_CUR);
+    }
+    
+    printf("[%s] left = %d\n", __func__, bytestream2_get_bytes_left(&s->gb));
+    s->state = FLIF16_SECONDHEADER;
+    return 0;
+}
+
+#define RAC_GET(rc, val1, val2, target, type) \
+    if (!ff_flif16_rac_process((rc), (val1), (val2), \
+        (uint32_t *) (target), (type))) \
+        goto need_more_data;
+        
+static int fli16_read_second_header(AVCodecContext *avctx)
+{
+    uint32_t temp;
+    FLIF16DecoderContext *s = avctx->priv_data;
+    
+    if (!s->rc) {
+        s->buf_count += bytestream2_get_buffer(&s->gb, s->buf, 
+                                       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);
+
+        s->rc = ff_flif16_rac_init(&s->gb, s->buf, s->buf_count);
+    }
+
+    loop:
+    switch (s->segment) {
+        default: case 0:
+            // In original source this is handled in what seems to be a very 
+            // bogus manner. It takes all the bpps of all channels and then 
+            // takes the max.
+            if (s->bpc == '0') {
+                for (; s->i < s->channels; ++s->i) {
+                    RAC_GET(s->rc, 1, 15, &temp, FLIF16_RAC_UNI_INT);
+                    s->channelbpc = FFMAX(s->channelbpc, (1 << temp) - 1);
+                }
+            }
+            s->i = 0;
+            ++s->segment; __PLN__
+            break;
+        
+        case 1:
+            if (s->channels > 3)
+                RAC_GET(s->rc, 0, 1, (uint32_t *) &s->alphazero,
+                        FLIF16_RAC_UNI_INT);
+            ++s->segment; __PLN__
+            break;
+        
+        case 2:
+            if (s->frames > 1) {
+                RAC_GET(s->rc, 0, 100, (uint32_t *) &s->loops, 
+                        FLIF16_RAC_UNI_INT);
+                s->framedelay = av_mallocz(sizeof(*(s->framedelay)) * s->frames);
+            }
+            ++s->segment; __PLN__
+            break;
+        
+        case 3:
+            if (s->frames > 1) {
+                for (; (s->i) < (s->frames); ++(s->i)) {
+                    RAC_GET(s->rc, 0, 60000, &(s->framedelay[(s->i)]), 
+                            FLIF16_RAC_UNI_INT);
+                }
+                s->i = 0;
+            }
+            ++s->segment;
+            break;
+
+        case 4:
+            // Has custom alpha flag
+            RAC_GET(s->rc, 0, 1, &temp, FLIF16_RAC_UNI_INT);
+            printf("[%s] has_custom_cutoff_alpha = %d\n", __func__, temp);
+            ++s->segment;
+            break; 
+        
+        case 5:
+            if (temp)
+                RAC_GET(s->rc, 1, 128, &s->cutoff, FLIF16_RAC_UNI_INT);
+            ++s->segment;
+            break;
+
+        case 6:
+            if (temp)
+                RAC_GET(s->rc, 2, 128, &s->alphadiv, FLIF16_RAC_UNI_INT);
+            ++s->segment;
+            break;
+
+        case 7:
+            if (temp)
+                RAC_GET(s->rc, 0, 1, &s->cutoff, FLIF16_RAC_UNI_INT);
+            if (s->custombc) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "custom bitchances not implemented\n");
+                return AVERROR_PATCHWELCOME;
+            }
+            goto end;
+            break;
+    }
+    
+    goto loop;
+
+    end:
+    s->state = FLIF16_TRANSFORM;
+    return 0;
+    
+    need_more_data:
+    printf("[%s] Need more data\n", __func__);
+    return AVERROR(EAGAIN);
+}
+
+
+static int flif16_read_transforms(AVCodecContext *avctx) {
+    
+    /*
+    while (ff_flif16_rac_read_bit(s->rc)) {
+        temp = ff_flif16_rac_read_uni_int(s->rc, 0, 13); // Transform number
+        // ff_flif16_transform_process(temp, tlist, rc);
+    }
+    */
+    
+    return AVERROR_EOF;
+}
+
+static int flif16_read_pixeldata(AVCodecContext *avctx, AVFrame *p)
+{
+    return AVERROR_EOF;
+}
+
+static int flif16_read_checksum(AVCodecContext *avctx)
+{
+    return AVERROR_EOF;
+}
+
+static int flif16_decode_frame(AVCodecContext *avctx,
+                               void *data, int *got_frame,
+                               AVPacket *avpkt)
+{
+    int ret = AVERROR(EINVAL);
+    FLIF16DecoderContext *s = avctx->priv_data;
+    const uint8_t *buf      = avpkt->data;
+    int buf_size            = avpkt->size;
+    AVFrame *p              = data;
+    printf("[Decode] Packet Size = %d\n", buf_size);
+    bytestream2_init(&s->gb, buf, buf_size);
+    __PLN__
+    // Looping is done to change states in between functions.
+    // Function will either exit on AVERROR(EAGAIN) or AVERROR_EOF
+    do {
+        switch(s->state) {
+            case 0: case FLIF16_HEADER:
+                ret = flif16_read_header(avctx);
+                break;
+            
+            case FLIF16_SECONDHEADER:
+                ret = fli16_read_second_header(avctx);
+                break;
+            
+            case FLIF16_TRANSFORM:
+                ret = flif16_read_transforms(avctx);
+                break;
+
+            case FLIF16_PIXELDATA:
+                __PLN__
+                ret = flif16_read_pixeldata(avctx, p);
+                break;
+
+            case FLIF16_CHECKSUM:
+                ret = flif16_read_checksum(avctx);
+                break;
+        }
+    } while (!ret);
+
+    printf("[Decode Result]\n"                \
+           "Width: %u, Height: %u, Frames: %u\n"\
+           "ia: %x bpc: %c channels: %u\n"    \
+           "channelbpc: %u\n"                 \
+           "alphazero: %u custombc: %u\n"     \
+           "cutoff: %u alphadiv: %u \n"       \
+           "loops: %u\n", s->width, s->height, s->frames, s->ia, s->bpc, 
+           s->channels, s->channelbpc, s->alphazero, s->custombc, s->cutoff,
+           s->alphadiv, s->loops);
+    if (s->framedelay) {
+        printf("Framedelays:\n");
+        for(uint32_t i = 0; i < s->frames; ++i)
+            printf("%u, ", s->framedelay[i]);
+        printf("\n");
+    }
+    return ret;
+}
+
+static av_cold int flif16_decode_end(AVCodecContext *avctx)
+{
+    FLIF16DecoderContext *s = avctx->priv_data;
+    av_free(s->rc);
+    if(s->framedelay)
+        av_free(s->framedelay);
+    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,
+    .close          = flif16_decode_end,
+    .priv_data_size = sizeof(FLIF16DecoderContext),
+    .decode         = flif16_decode_frame,
+    //.capabilities   = 0,
+    //.caps_internal  = 0,
+    .priv_class     = NULL,
+};
diff --git a/libavcodec/flif16enc.c b/libavcodec/flif16enc.c
new file mode 100644
index 0000000000..8cad9973be
--- /dev/null
+++ b/libavcodec/flif16enc.c
@@ -0,0 +1,25 @@
+#include "flif16.h"
+#include "avcodec.h"
+
+#include "bytestream.h"
+
+// TODO Add all Functions
+static int flif16_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+                            const AVFrame *pict, int *got_packet)
+{
+    
+    return AVERROR(EINVAL);
+}
+
+AVCodec ff_flif16_encoder = {
+    .name           = "flif16",
+    .long_name      = NULL_IF_CONFIG_SMALL("FLIF (Free Lossless Image Format)"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_FLIF16,
+    .priv_data_size = 0,
+    //.init           = NULL,
+    .encode2        = flif16_encode_frame,
+    //.close          = NULL,
+    //.pix_fmts       = (const enum AVPixelFormat[]){},
+    .priv_class     = NULL,
+};
diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c
index 33a71de8a0..8b6eb954b3 100644
--- a/libavcodec/parsers.c
+++ b/libavcodec/parsers.c
@@ -40,6 +40,7 @@ extern AVCodecParser ff_dvbsub_parser;
 extern AVCodecParser ff_dvdsub_parser;
 extern AVCodecParser ff_dvd_nav_parser;
 extern AVCodecParser ff_flac_parser;
+extern AVCodecParser ff_flif16_parser;
 extern AVCodecParser ff_g723_1_parser;
 extern AVCodecParser ff_g729_parser;
 extern AVCodecParser ff_gif_parser;
diff --git a/libavformat/img2.c b/libavformat/img2.c
index 16bc9d2abd..14c11d0c82 100644
--- a/libavformat/img2.c
+++ b/libavformat/img2.c
@@ -81,6 +81,7 @@ const IdStrMap ff_img_tags[] = {
     { AV_CODEC_ID_XPM,        "xpm"      },
     { AV_CODEC_ID_XFACE,      "xface"    },
     { AV_CODEC_ID_XWD,        "xwd"      },
+    { AV_CODEC_ID_FLIF16,     "flif16"   },
     { AV_CODEC_ID_NONE,       NULL       }
 };
 
