[FFmpeg-devel] [PATCH] avcodec: add Actimagine VX video decoder

Florian Nouwt fnouwt2 at gmail.com
Mon Mar 15 16:10:36 EET 2021


I have uploaded an example video here:
https://mega.nz/file/PVwGAbbB#9tL6p3uE-Ej1DP7ngovAPqYghkQckTpW26XlrpAop9w
There's both an .avi file which can be read by ffmpeg and a vx file
containing the exact same video data, for which I will write a demuxer
soon (note that the vx is smaller because it contains compressed
audio). I assumed it would be appropriate to have the demuxer as a
separate patch after this one was accepted.

If I make changes to my patch, do I have to amend the changes to my
commit and then regenerate the patch and send it to this thread? This
patch and mailing list stuff is kinda new to me.

Op ma 15 mrt. 2021 om 14:47 schreef Andreas Rheinhardt
<andreas.rheinhardt at gmail.com>:
>
> Florian Nouwt:
> > This video format is mainly used in older Nintendo DS games in a .vx container. It is the predecessor of the Mobiclip format.
> >
> > Signed-off-by: Florian Nouwt <fnouwt2 at gmail.com>
> > ---
> >  Changelog                 |    1 +
> >  configure                 |    1 +
> >  doc/general_contents.texi |    2 +
> >  libavcodec/Makefile       |    1 +
> >  libavcodec/actimagine.c   | 1644 +++++++++++++++++++++++++++++++++++++
> >  libavcodec/allcodecs.c    |    1 +
> >  libavcodec/codec_desc.c   |    7 +
> >  libavcodec/codec_id.h     |    1 +
> >  libavcodec/version.h      |    2 +-
> >  libavformat/riff.c        |    2 +
> >  10 files changed, 1661 insertions(+), 1 deletion(-)
> >  create mode 100644 libavcodec/actimagine.c
> >
> > diff --git a/Changelog b/Changelog
> > index a96e350e09..8807f3dcb3 100644
> > --- a/Changelog
> > +++ b/Changelog
> > @@ -83,6 +83,7 @@ version <next>:
> >  - msad video filter
> >  - gophers protocol
> >  - RIST protocol via librist
> > +- Actimagine VX video decoder
> >
> >
> >  version 4.3:
> > diff --git a/configure b/configure
> > index f0ac719d2d..10a07da95f 100755
> > --- a/configure
> > +++ b/configure
> > @@ -2662,6 +2662,7 @@ ac3_fixed_decoder_select="ac3_parser ac3dsp bswapdsp mdct"
> >  ac3_encoder_select="ac3dsp audiodsp mdct me_cmp"
> >  ac3_fixed_encoder_select="ac3dsp audiodsp mdct me_cmp"
> >  acelp_kelvin_decoder_select="audiodsp"
> > +actimagine_decoder_select="bswapdsp golomb"
> >  adpcm_g722_decoder_select="g722dsp"
> >  adpcm_g722_encoder_select="g722dsp"
> >  aic_decoder_select="golomb idctdsp"
> > diff --git a/doc/general_contents.texi b/doc/general_contents.texi
> > index 33ece6e884..d4261386fc 100644
> > --- a/doc/general_contents.texi
> > +++ b/doc/general_contents.texi
> > @@ -807,6 +807,8 @@ following image formats are supported:
> >  @item 8088flex TMV           @tab     @tab  X
> >  @item A64 multicolor         @tab  X  @tab
> >      @tab Creates video suitable to be played on a commodore 64 (multicolor mode).
> > + at item Actimagine VX Video    @tab     @tab  X
> > +    @tab fourcc: vxs1, VXS1
> >  @item Amazing Studio PAF Video @tab     @tab  X
> >  @item American Laser Games MM  @tab    @tab X
> >      @tab Used in games like Mad Dog McCree.
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index 81cc16471b..39b3bc968d 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> > @@ -182,6 +182,7 @@ OBJS-$(CONFIG_AC3_ENCODER)             += ac3enc_float.o ac3enc.o ac3tab.o \
> >  OBJS-$(CONFIG_AC3_FIXED_ENCODER)       += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o kbdwin.o
> >  OBJS-$(CONFIG_AC3_MF_ENCODER)          += mfenc.o mf_utils.o
> >  OBJS-$(CONFIG_ACELP_KELVIN_DECODER)    += g729dec.o lsp.o celp_math.o celp_filters.o acelp_filters.o acelp_pitch_delay.o acelp_vectors.o g729postfilter.o
> > +OBJS-$(CONFIG_ACTIMAGINE_DECODER)      += actimagine.o
> >  OBJS-$(CONFIG_AGM_DECODER)             += agm.o
> >  OBJS-$(CONFIG_AIC_DECODER)             += aic.o
> >  OBJS-$(CONFIG_ALAC_DECODER)            += alac.o alac_data.o alacdsp.o
> > diff --git a/libavcodec/actimagine.c b/libavcodec/actimagine.c
> > new file mode 100644
> > index 0000000000..6bb5126b05
> > --- /dev/null
> > +++ b/libavcodec/actimagine.c
> > @@ -0,0 +1,1644 @@
> > +/*
> > + * Actimagine VX Video decoder
> > + * Copyright (c) 2021 Florian Nouwt
> > + *
> > + * 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
> > + */
> > +
> > +#include <inttypes.h>
> > +
> > +#include "libavutil/avassert.h"
> > +#include "libavutil/thread.h"
> > +
> > +#include "avcodec.h"
> > +#include "bytestream.h"
> > +#include "bswapdsp.h"
> > +#include "get_bits.h"
> > +#include "golomb.h"
> > +#include "internal.h"
> > +
> > +static const uint8_t predict_dc_shift_tab[] = {1, 2, 3, 0, 4};
> > +
> > +static const uint8_t zigzag4x4_tab[] =
> > +{
> > +    0x00, 0x04, 0x01, 0x02, 0x05, 0x08, 0x0C, 0x09,
> > +    0x06, 0x03, 0x07, 0x0A, 0x0D, 0x0E, 0x0B, 0x0F
> > +};
> > +
> > +static const uint8_t quant4x4_tab[][8] =
> > +{
> > +    { 0x0A, 0x0D, 0x0A, 0x0D, 0x0D, 0x10, 0x0D, 0x10 },
> > +    { 0x0B, 0x0E, 0x0B, 0x0E, 0x0E, 0x12, 0x0E, 0x12 },
> > +    { 0x0D, 0x10, 0x0D, 0x10, 0x10, 0x14, 0x10, 0x14 },
> > +    { 0x0E, 0x12, 0x0E, 0x12, 0x12, 0x17, 0x12, 0x17 },
> > +    { 0x10, 0x14, 0x10, 0x14, 0x14, 0x19, 0x14, 0x19 },
> > +    { 0x12, 0x17, 0x12, 0x17, 0x17, 0x1D, 0x17, 0x1D }
> > +};
> > +
> > +static const uint8_t old_mb_mode_remap_tab[] =
> > +{
> > +     1,  2,  0,  4,  7,  3, 11, 15,  9,  5, 14,  6,
> > +    12, 13,  8, 16, 23, 10, 22, 19, 20, 17, 21, 18
> > +};
> > +
> > +static const uint8_t residu_mask_old_tab[] =
> > +{
> > +    0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x03, 0x05,
> > +    0x0A, 0x0C, 0x0F, 0x1F, 0x07, 0x0B, 0x0D, 0x0E,
> > +    0x06, 0x09, 0x13, 0x15, 0x1A, 0x1C, 0x11, 0x12,
> > +    0x14, 0x18, 0x17, 0x1B, 0x1D, 0x1E, 0x16, 0x19
> > +};
> > +
> > +static const uint8_t residu_mask_new_tab[] =
> > +{
> > +    0x00, 0x08, 0x04, 0x02, 0x01, 0x1F, 0x0F, 0x0A,
> > +    0x05, 0x0C, 0x03, 0x10, 0x0E, 0x0D, 0x0B, 0x07,
> > +    0x09, 0x06, 0x1E, 0x1B, 0x1A, 0x1D, 0x17, 0x15,
> > +    0x18, 0x12, 0x11, 0x1C, 0x14, 0x13, 0x16, 0x19
> > +};
> > +
> > +static const int cavlc_suffix_len_update_tab[] =
> > +{
> > +    2, 5, 11, 23, 47, 32768
> > +};
> > +
> > +// same tables as h264 cavlc
> > +static const uint8_t coeff_token_table_index[17] =
> > +{
> > +    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3
> > +};
> > +
> > +static const uint8_t coeff_token_len[4][4 * 17] = {
> > +{
> > +     1, 0, 0, 0,
> > +     6, 2, 0, 0,     8, 6, 3, 0,     9, 8, 7, 5,    10, 9, 8, 6,
> > +    11,10, 9, 7,    13,11,10, 8,    13,13,11, 9,    13,13,13,10,
> > +    14,14,13,11,    14,14,14,13,    15,15,14,14,    15,15,15,14,
> > +    16,15,15,15,    16,16,16,15,    16,16,16,16,    16,16,16,16,
> > +},
> > +{
> > +     2, 0, 0, 0,
> > +     6, 2, 0, 0,     6, 5, 3, 0,     7, 6, 6, 4,     8, 6, 6, 4,
> > +     8, 7, 7, 5,     9, 8, 8, 6,    11, 9, 9, 6,    11,11,11, 7,
> > +    12,11,11, 9,    12,12,12,11,    12,12,12,11,    13,13,13,12,
> > +    13,13,13,13,    13,14,13,13,    14,14,14,13,    14,14,14,14,
> > +},
> > +{
> > +     4, 0, 0, 0,
> > +     6, 4, 0, 0,     6, 5, 4, 0,     6, 5, 5, 4,     7, 5, 5, 4,
> > +     7, 5, 5, 4,     7, 6, 6, 4,     7, 6, 6, 4,     8, 7, 7, 5,
> > +     8, 8, 7, 6,     9, 8, 8, 7,     9, 9, 8, 8,     9, 9, 9, 8,
> > +    10, 9, 9, 9,    10,10,10,10,    10,10,10,10,    10,10,10,10,
> > +},
> > +{
> > +     6, 0, 0, 0,
> > +     6, 6, 0, 0,     6, 6, 6, 0,     6, 6, 6, 6,     6, 6, 6, 6,
> > +     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,
> > +     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,
> > +     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,     6, 6, 6, 6,
> > +}
> > +};
> > +
> > +static const uint8_t coeff_token_bits[4][4 * 17] = {
> > +{
> > +     1, 0, 0, 0,
> > +     5, 1, 0, 0,     7, 4, 1, 0,     7, 6, 5, 3,     7, 6, 5, 3,
> > +     7, 6, 5, 4,    15, 6, 5, 4,    11,14, 5, 4,     8,10,13, 4,
> > +    15,14, 9, 4,    11,10,13,12,    15,14, 9,12,    11,10,13, 8,
> > +    15, 1, 9,12,    11,14,13, 8,     7,10, 9,12,     4, 6, 5, 8,
> > +},
> > +{
> > +     3, 0, 0, 0,
> > +    11, 2, 0, 0,     7, 7, 3, 0,     7,10, 9, 5,     7, 6, 5, 4,
> > +     4, 6, 5, 6,     7, 6, 5, 8,    15, 6, 5, 4,    11,14,13, 4,
> > +    15,10, 9, 4,    11,14,13,12,     8,10, 9, 8,    15,14,13,12,
> > +    11,10, 9,12,     7,11, 6, 8,     9, 8,10, 1,     7, 6, 5, 4,
> > +},
> > +{
> > +    15, 0, 0, 0,
> > +    15,14, 0, 0,    11,15,13, 0,     8,12,14,12,    15,10,11,11,
> > +    11, 8, 9,10,     9,14,13, 9,     8,10, 9, 8,    15,14,13,13,
> > +    11,14,10,12,    15,10,13,12,    11,14, 9,12,     8,10,13, 8,
> > +    13, 7, 9,12,     9,12,11,10,     5, 8, 7, 6,     1, 4, 3, 2,
> > +},
> > +{
> > +     3, 0, 0, 0,
> > +     0, 1, 0, 0,     4, 5, 6, 0,     8, 9,10,11,    12,13,14,15,
> > +    16,17,18,19,    20,21,22,23,    24,25,26,27,    28,29,30,31,
> > +    32,33,34,35,    36,37,38,39,    40,41,42,43,    44,45,46,47,
> > +    48,49,50,51,    52,53,54,55,    56,57,58,59,    60,61,62,63,
> > +}
> > +};
> > +
> > +static const uint8_t total_zeros_len[16][16] = {
> > +    {1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},
> > +    {3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},
> > +    {4,3,3,3,4,4,3,3,4,5,5,6,5,6},
> > +    {5,3,4,4,3,3,3,4,3,4,5,5,5},
> > +    {4,4,4,3,3,3,3,3,4,5,4,5},
> > +    {6,5,3,3,3,3,3,3,4,3,6},
> > +    {6,5,3,3,3,2,3,4,3,6},
> > +    {6,4,5,3,2,2,3,3,6},
> > +    {6,6,4,2,2,3,2,5},
> > +    {5,5,3,2,2,2,4},
> > +    {4,4,3,3,1,3},
> > +    {4,4,2,1,3},
> > +    {3,3,1,2},
> > +    {2,2,1},
> > +    {1,1},
> > +};
> > +
> > +static const uint8_t total_zeros_bits[16][16] = {
> > +    {1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1},
> > +    {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0},
> > +    {5,7,6,5,4,3,4,3,2,3,2,1,1,0},
> > +    {3,7,5,4,6,5,4,3,3,2,2,1,0},
> > +    {5,4,3,7,6,5,4,3,2,1,1,0},
> > +    {1,1,7,6,5,4,3,2,1,1,0},
> > +    {1,1,5,4,3,3,2,1,1,0},
> > +    {1,1,1,3,3,2,2,1,0},
> > +    {1,0,1,3,2,1,1,1},
> > +    {1,0,1,3,2,1,1},
> > +    {0,1,1,2,1,3},
> > +    {0,1,1,1,1},
> > +    {0,1,1,1},
> > +    {0,1,1},
> > +    {0,1},
> > +};
> > +
> > +static const uint8_t run_len[7][16] = {
> > +    {1,1},
> > +    {1,2,2},
> > +    {2,2,2,2},
> > +    {2,2,2,3,3},
> > +    {2,2,3,3,3,3},
> > +    {2,3,3,3,3,3,3},
> > +    {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11},
> > +};
> > +
> > +static const uint8_t run_bits[7][16] = {
> > +    {1,0},
> > +    {1,1,0},
> > +    {3,2,1,0},
> > +    {3,2,1,1,0},
> > +    {3,2,3,2,1,0},
> > +    {3,0,1,3,2,5,4},
> > +    {7,6,5,4,3,2,1,1,1,1,1,1,1,1,1},
> > +};
> > +
> > +typedef struct MVec {
> > +    int x, y;
> > +} MVec;
> > +
> > +typedef struct ActimagineContext {
> > +    AVFrame *cur_frame;
> > +    AVFrame *ref_frames[3];
> > +    int      ref_frame_count;
> > +
> > +    int version;
> > +    int quantizer;
> > +    int avi;
> > +
> > +    GetBitContext gb;
> > +
> > +    uint8_t *bitstream;
> > +    int bitstream_size;
> > +
> > +    int qtab[2][4];
> > +
> > +    uint8_t pred4_cache[5][5];
> > +
> > +    MVec *vectors;
> > +    int   vectors_stride;
> > +
> > +    uint8_t *total_coeff_y;
> > +    int      total_coeff_y_stride;
> > +
> > +    uint8_t *total_coeff_uv;
> > +    int      total_coeff_uv_stride;
> > +
> > +    BswapDSPContext bdsp;
> > +} ActimagineContext;
> > +
> > +static VLC coeff_token_vlc[4];
> > +static VLC_TYPE coeff_token_vlc_tables[520+332+280+256][2];
> > +static const int coeff_token_vlc_tables_size[4]={520,332,280,256};
> > +
> > +static VLC total_zeros_vlc[15+1];
> > +static VLC_TYPE total_zeros_vlc_tables[15][512][2];
> > +static const int total_zeros_vlc_tables_size = 512;
> > +
> > +static VLC run_vlc[6+1];
> > +static VLC_TYPE run_vlc_tables[6][8][2];
> > +static const int run_vlc_tables_size = 8;
> > +
> > +static VLC run7_vlc;
> > +static VLC_TYPE run7_vlc_table[96][2];
> > +static const int run7_vlc_table_size = 96;
> > +
> > +#define COEFF_TOKEN_VLC_BITS    8
> > +#define TOTAL_ZEROS_VLC_BITS    9
> > +#define RUN_VLC_BITS            3
> > +#define RUN7_VLC_BITS           6
> > +
> > +#define PIXEL_REF(s, ref, plane, x, y)\
> > +    ((s)->ref_frames[(ref)]->data[(plane)]\
> > +        [(y) * (s)->ref_frames[(ref)]->linesize[(plane)] + (x)])
> > +
> > +#define PIXEL_CUR(s, plane, x, y)\
> > +    ((s)->cur_frame->data[(plane)]\
> > +        [(y) * (s)->cur_frame->linesize[(plane)] + (x)])
> > +
> > +#define PREDICT2(a,b)       (((a) + (b) + 1) >> 1)
> > +#define PREDICT3(a,b,c)     (((a) + 2 * (b) + (c) + 2) >> 2)
> > +
> > +#define VX_VERSION_INVALID  -1
> > +#define VX_VERSION_OLD       0
> > +#define VX_VERSION_NEW       1
> > +
> > +static av_cold void actimagine_init_static(void)
> > +{
> > +    // all these tables are equal to the ones used for h264 cavlc
>
> Then please share them.
>
> > +    int offset = 0;
> > +    for (int i = 0; i < 4; i++) {
> > +        coeff_token_vlc[i].table = coeff_token_vlc_tables + offset;
> > +        coeff_token_vlc[i].table_allocated = coeff_token_vlc_tables_size[i];
> > +        init_vlc(&coeff_token_vlc[i], COEFF_TOKEN_VLC_BITS, 4 * 17,
> > +                 &coeff_token_len [i][0], 1, 1,
> > +                 &coeff_token_bits[i][0], 1, 1,
> > +                 INIT_VLC_USE_NEW_STATIC);
> > +        offset += coeff_token_vlc_tables_size[i];
> > +    }
> > +    /*
> > +     * This is a one time safety check to make sure that
> > +     * the packed static coeff_token_vlc table sizes
> > +     * were initialized correctly.
> > +     */
> > +    av_assert0(offset == FF_ARRAY_ELEMS(coeff_token_vlc_tables));
> > +
> > +    for (int i = 0; i < 15; i++) {
> > +        total_zeros_vlc[i + 1].table = total_zeros_vlc_tables[i];
> > +        total_zeros_vlc[i + 1].table_allocated = total_zeros_vlc_tables_size;
> > +        init_vlc(&total_zeros_vlc[i + 1],
> > +                 TOTAL_ZEROS_VLC_BITS, 16,
> > +                 &total_zeros_len [i][0], 1, 1,
> > +                 &total_zeros_bits[i][0], 1, 1,
> > +                 INIT_VLC_USE_NEW_STATIC);
> > +    }
> > +
> > +    for (int i = 0; i < 6; i++) {
> > +        run_vlc[i + 1].table = run_vlc_tables[i];
> > +        run_vlc[i + 1].table_allocated = run_vlc_tables_size;
> > +        init_vlc(&run_vlc[i + 1],
> > +                 RUN_VLC_BITS, 7,
> > +                 &run_len [i][0], 1, 1,
> > +                 &run_bits[i][0], 1, 1,
> > +                 INIT_VLC_USE_NEW_STATIC);
> > +    }
> > +
> > +    run7_vlc.table = run7_vlc_table,
> > +    run7_vlc.table_allocated = run7_vlc_table_size;
> > +    init_vlc(&run7_vlc, RUN7_VLC_BITS, 16,
> > +             &run_len [6][0], 1, 1,
> > +             &run_bits[6][0], 1, 1,
> > +             INIT_VLC_USE_NEW_STATIC);
> > +}
> > +
> > +static int setup_qtables(AVCodecContext *avctx, int quantizer)
> > +{
> > +    int qx, qy;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    if (quantizer < 12 || quantizer > 161)
> > +        return AVERROR_INVALIDDATA;
> > +
> > +    s->quantizer = quantizer;
> > +
> > +    qx = quantizer % 6;
> > +    qy = quantizer / 6;
> > +
> > +    for (int i = 0; i < 2; i++)
> > +        for (int j = 0; j < 4; j++)
> > +            s->qtab[i][j] = quant4x4_tab[qx][4 * i + j] << qy;
> > +
> > +    return 0;
> > +}
> > +
> > +static av_cold int actimagine_init(AVCodecContext *avctx)
> > +{
> > +    int vectors_size;
> > +    int total_coeff_y_size;
> > +    int total_coeff_uv_size;
> > +    static AVOnce init_static_once = AV_ONCE_INIT;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    if (avctx->width & 15 || avctx->height & 15) {
> > +        av_log(avctx, AV_LOG_ERROR, "width/height not multiple of 16\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    ff_bswapdsp_init(&s->bdsp);
> > +
> > +    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> > +    avctx->color_range = AVCOL_RANGE_JPEG;
> > +    avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
> > +    // the color space of this video format is not supported currently
> > +    // it is a yuv approximation that can be converted back to rgb using bitshifts
> > +    // r = y + (v << 1)
> > +    // g = y - (u >> 1) - v
> > +    // b = y + (u << 1)
> > +    avctx->colorspace = AVCOL_SPC_NB;
> > +
> > +    // predict4 cache
> > +    for (int i = 0; i < 5; i++)
> > +        for (int j = 0; j < 5; j++)
> > +            s->pred4_cache[i][j] = 9;
> > +
> > +    // motion vector cache
> > +    s->vectors_stride = (avctx->width >> 4) + 2;
> > +    vectors_size = ((avctx->height >> 4) + 1) * s->vectors_stride;
> > +    s->vectors = av_calloc(vectors_size, sizeof(MVec));
> > +    if (!s->vectors)
> > +        return AVERROR(ENOMEM);
> > +    memset(s->vectors, 0, vectors_size * sizeof(MVec));
>
> Unnecessary. av_calloc already zeroes it.
>
> > +
> > +    // total dct coefficient cache for luma
> > +    s->total_coeff_y_stride = (avctx->width >> 2) + 1;
> > +    total_coeff_y_size = ((avctx->height >> 2) + 1) * s->total_coeff_y_stride;
> > +    s->total_coeff_y = av_malloc(total_coeff_y_size);
> > +    if (!s->total_coeff_y)
> > +        return AVERROR(ENOMEM);
> > +    memset(s->total_coeff_y, 0, total_coeff_y_size);
>
> Unnecessary: Use av_mallocz.
>
> > +
> > +    // total dct coefficient cache for chroma
> > +    s->total_coeff_uv_stride = (avctx->width >> 3) + 1;
> > +    total_coeff_uv_size = ((avctx->height >> 3) + 1) * s->total_coeff_uv_stride;
> > +    s->total_coeff_uv = av_malloc(total_coeff_uv_size);
> > +    if (!s->total_coeff_uv)
> > +        return AVERROR(ENOMEM);
> > +    memset(s->total_coeff_uv, 0, total_coeff_uv_size);
>
> Same as above.
>
> > +
> > +    s->ref_frame_count = 0;
> > +    for (int i = 0; i < 3; i++) {
> > +        s->ref_frames[i] = av_frame_alloc();
> > +        if (!s->ref_frames[i])
> > +            return AVERROR(ENOMEM);
> > +    }
> > +    s->cur_frame = av_frame_alloc();
> > +    if (!s->cur_frame)
> > +        return AVERROR(ENOMEM);
> > +
> > +    s->version = VX_VERSION_INVALID;
> > +    s->quantizer = -1;
> > +    s->avi = 0;
> > +
> > +    // when the source is an avi file, the quantizer is stored in the extradata
> > +    if (avctx->extradata_size == 4)
> > +        if (!setup_qtables(avctx, AV_RL32(avctx->extradata)))
> > +            s->avi = 1;
> > +
> > +    ff_thread_once(&init_static_once, actimagine_init_static);
> > +
> > +    return 0;
> > +}
> > +
> > +static void clear_total_coeff(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    // luma
> > +    uint8_t *total_coeff = &s->total_coeff_y[
> > +        ((y >> 2) + 1) * s->total_coeff_y_stride + (x >> 2) + 1];
> > +
> > +    for (int y2 = 0; y2 < (h >> 2); y2++)
> > +        for (int x2 = 0; x2 < (w >> 2); x2++)
> > +            total_coeff[y2 * s->total_coeff_y_stride + x2] = 0;
> > +
> > +    // chroma
> > +    total_coeff = &s->total_coeff_uv[
> > +        ((y >> 3) + 1) * s->total_coeff_uv_stride + (x >> 3) + 1];
> > +
> > +    for (int y2 = 0; y2 < (h >> 3); y2++)
> > +        for (int x2 = 0; x2 < (w >> 3); x2++)
> > +            total_coeff[y2 * s->total_coeff_uv_stride + x2] = 0;
> > +}
> > +
> > +static void predict_plane_intern(AVCodecContext *avctx, int x, int y,
> > +                                 int w, int h, int plane)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    if (w == 1 && h == 1)
> > +        return;
> > +    if (w == 1 && h != 1) {
> > +        uint8_t top    = PIXEL_CUR(s, plane, x, y - 1);
> > +        uint8_t bottom = PIXEL_CUR(s, plane, x, y + h - 1);
> > +        PIXEL_CUR(s, plane, x, y + (h >> 1) - 1) = (top + bottom) >> 1;
> > +        predict_plane_intern(avctx, x, y, 1, h >> 1, plane);
> > +        predict_plane_intern(avctx, x, y + (h >> 1), 1, h >> 1, plane);
> > +    } else if (w != 1 && h == 1) {
> > +        uint8_t left  = PIXEL_CUR(s, plane, x - 1, y);
> > +        uint8_t right = PIXEL_CUR(s, plane, x + w - 1, y);
> > +        PIXEL_CUR(s, plane, x + (w >> 1) - 1, y) = (left + right) >> 1;
> > +        predict_plane_intern(avctx, x, y, w >> 1, 1, plane);
> > +        predict_plane_intern(avctx, x + (w >> 1), y, w >> 1, 1, plane);
> > +    } else {
> > +        uint8_t bottom_left  = PIXEL_CUR(s, plane, x - 1, y + h - 1);
> > +        uint8_t top_right    = PIXEL_CUR(s, plane, x + w - 1, y - 1);
> > +        uint8_t bottom_right = PIXEL_CUR(s, plane, x + w - 1, y + h - 1);
> > +        uint8_t bottom_center = (bottom_left + bottom_right) >> 1;
> > +        uint8_t center_right = (top_right + bottom_right) >> 1;
> > +        PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + h - 1) = bottom_center;
> > +        PIXEL_CUR(s, plane, x + w - 1, y + (h >> 1) - 1) = center_right;
> > +        if ((w == 4 || w == 16) ^ (h == 4 || h == 16)) {
> > +            uint8_t center_left = PIXEL_CUR(s, plane, x - 1, y + (h >> 1) - 1);
> > +            PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + (h >> 1) - 1)
> > +                = (center_left + center_right) >> 1;
> > +        } else {
> > +            uint8_t top_center = PIXEL_CUR(s, plane, x + (w >> 1) - 1, y - 1);
> > +            PIXEL_CUR(s, plane, x + (w >> 1) - 1, y + (h >> 1) - 1)
> > +                = (top_center + bottom_center) >> 1;
> > +        }
> > +        predict_plane_intern(avctx, x, y, w >> 1, h >> 1, plane);
> > +        predict_plane_intern(avctx, x + (w >> 1), y, w >> 1, h >> 1, plane);
> > +        predict_plane_intern(avctx, x, y + (h >> 1), w >> 1, h >> 1, plane);
> > +        predict_plane_intern(avctx, x + (w >> 1), y + (h >> 1), w >> 1, h >> 1,
> > +                             plane);
> > +    }
> > +}
> > +
> > +static void predict_plane(AVCodecContext *avctx, int x, int y, int w, int h,
> > +                          int plane, int param)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    uint8_t bottom_left = PIXEL_CUR(s, plane, x - 1, y + h - 1);
> > +    uint8_t top_right   = PIXEL_CUR(s, plane, x + w - 1, y - 1);
> > +    PIXEL_CUR(s, plane, x + w - 1, y + h - 1)
> > +        = ((bottom_left + top_right + 1) >> 1) + param;
> > +    predict_plane_intern(avctx, x, y, w, h, plane);
> > +}
> > +
> > +static int predict_mb_plane(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    // y
> > +    int param = get_se_golomb(gb);
> > +    if (param < -(1 << 16) || param >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    predict_plane(avctx, x, y, w, h, 0, param << 1);
> > +
> > +    // u
> > +    param = get_se_golomb(gb);
> > +    if (param < -(1 << 16) || param >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1, param << 1);
> > +
> > +    // v
> > +    param = get_se_golomb(gb);
> > +    if (param < -(1 << 16) || param >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid plane param\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2, param << 1);
> > +
> > +    return 0;
> > +}
> > +
> > +static void predict_horizontal(AVCodecContext *avctx, int x, int y,
> > +                               int w, int h, int plane)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    for (int y2 = 0; y2 < h; y2++) {
> > +        uint8_t pixel = PIXEL_CUR(s, plane, x - 1, y + y2);
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            PIXEL_CUR(s, plane, x + x2, y + y2) = pixel;
> > +    }
> > +}
> > +
> > +static void predict_vertical(AVCodecContext *avctx, int x, int y,
> > +                             int w, int h, int plane)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    for (int y2 = 0; y2 < h; y2++)
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            PIXEL_CUR(s, plane, x + x2, y + y2)
> > +                = PIXEL_CUR(s, plane, x + x2, y - 1);
> > +}
> > +
> > +static void predict_dc(AVCodecContext *avctx, int x, int y, int w, int h,
> > +                       int plane)
> > +{
> > +    uint8_t dc;
> > +    ActimagineContext *s = avctx->priv_data;
> > +    if (x != 0 && y != 0) {
> > +        int sum_h, sum_v;
> > +        sum_h = w >> 1;
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            sum_h += PIXEL_CUR(s, plane, x + x2, y - 1);
> > +        sum_h >>= predict_dc_shift_tab[w >> 2];
> > +
> > +        sum_v = h >> 1;
> > +        for (int y2 = 0; y2 < h; y2++)
> > +            sum_v += PIXEL_CUR(s, plane, x - 1, y + y2);
> > +        sum_v >>= predict_dc_shift_tab[h >> 2];
> > +
> > +        dc = (sum_h + sum_v + 1) >> 1;
> > +    } else if (x == 0 && y != 0) {
> > +        int sum = w >> 1;
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            sum += PIXEL_CUR(s, plane, x + x2, y - 1);
> > +        dc = sum >> predict_dc_shift_tab[w >> 2];
> > +    } else if (x != 0 && y == 0) {
> > +        int sum = h >> 1;
> > +        for (int y2 = 0; y2 < h; y2++)
> > +            sum += PIXEL_CUR(s, plane, x - 1, y + y2);
> > +        dc = sum >> predict_dc_shift_tab[h >> 2];
> > +    } else
> > +        dc = 128;
> > +
> > +    for (int y2 = 0; y2 < h; y2++)
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            PIXEL_CUR(s, plane, x + x2, y + y2) = dc;
> > +}
> > +
> > +static int predict_notile_uv(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    int mode_uv = get_ue_golomb_31(gb);
> > +    switch (mode_uv) {
> > +    case 0:// dc
> > +        predict_dc(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
> > +        predict_dc(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
> > +        break;
> > +    case 1:// horizontal
> > +        predict_horizontal(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
> > +        predict_horizontal(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
> > +        break;
> > +    case 2:// vertical
> > +        predict_vertical(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1);
> > +        predict_vertical(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2);
> > +        break;
> > +    case 3:// plane
> > +        predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 1, 0);
> > +        predict_plane(avctx, x >> 1, y >> 1, w >> 1, h >> 1, 2, 0);
> > +        break;
> > +    default:
> > +        av_log(avctx, AV_LOG_ERROR, "invalid predict notile uv mode\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int predict_notile(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    int mode_y = get_ue_golomb_31(gb);
> > +    switch (mode_y) {
> > +    case 0:// vertical
> > +        predict_vertical(avctx, x, y, w, h, 0);
> > +        break;
> > +    case 1:// horizontal
> > +        predict_horizontal(avctx, x, y, w, h, 0);
> > +        break;
> > +    case 2:// dc
> > +        predict_dc(avctx, x, y, w, h, 0);
> > +        break;
> > +    case 3:// plane
> > +        predict_plane(avctx, x, y, w, h, 0, 0);
> > +        break;
> > +    default:
> > +        av_log(avctx, AV_LOG_ERROR, "invalid predict notile y mode\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    return predict_notile_uv(avctx, x, y, w, h);
> > +}
> > +
> > +// slightly different from the common dc prediction method
> > +static void predict4_dc(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t dc;
> > +    ActimagineContext *s = avctx->priv_data;
> > +    if (x == 0 && y == 0)
> > +        dc = 128;
> > +    else {
> > +        int sum   = 0;
> > +        int shift = 1;
> > +
> > +        if (x != 0) {
> > +            shift++;
> > +            for (int y2 = 0; y2 < 4; y2++)
> > +                sum += PIXEL_CUR(s, 0, x - 1, y + y2);
> > +            sum += 2;
> > +        }
> > +
> > +        if (y != 0) {
> > +            shift++;
> > +            for (int x2 = 0; x2 < 4; x2++)
> > +                sum += PIXEL_CUR(s, 0, x + x2, y - 1);
> > +            sum += 2;
> > +        }
> > +
> > +        dc = sum >> shift;
> > +    }
> > +
> > +    for (int y2 = 0; y2 < 4; y2++)
> > +        for (int x2 = 0; x2 < 4; x2++)
> > +            PIXEL_CUR(s, 0, x + x2, y + y2) = dc;
> > +}
> > +
> > +static void predict4_diagonal_down_left(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t val;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
> > +    uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
> > +    uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
> > +    uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
> > +    uint8_t e = PIXEL_CUR(s, 0, x + 4, y - 1);
> > +    uint8_t f = PIXEL_CUR(s, 0, x + 5, y - 1);
> > +    uint8_t g = PIXEL_CUR(s, 0, x + 6, y - 1);
> > +    uint8_t h = PIXEL_CUR(s, 0, x + 7, y - 1);
> > +
> > +    PIXEL_CUR(s, 0, x, y) = PREDICT3(a, b, c);
> > +
> > +    val = PREDICT3(b, c, d);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = val;
> > +
> > +    val = PREDICT3(c, d, e);
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = val;
> > +
> > +    val = PREDICT3(d, e, f);
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = val;
> > +
> > +    val = PREDICT3(e, f, g);
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = val;
> > +
> > +    val = PREDICT3(f, g, h);
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = val;
> > +
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = PREDICT3(g, h, h);
> > +}
> > +
> > +static void predict4_diagonal_down_right(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t val;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
> > +    uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
> > +    uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
> > +    uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
> > +
> > +    uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
> > +    uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
> > +    uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
> > +    uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
> > +
> > +    uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT3(j, k, l);
> > +
> > +    val = PREDICT3(i, j, k);
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = val;
> > +
> > +    val = PREDICT3(m, i, j);
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = val;
> > +
> > +    val = PREDICT3(i, m, a);
> > +    PIXEL_CUR(s, 0, x + 0, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = val;
> > +
> > +    val = PREDICT3(m, a, b);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = val;
> > +
> > +    val = PREDICT3(a, b, c);
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = val;
> > +
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(b, c, d);
> > +}
> > +
> > +static void predict4_vertical_right(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t val;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
> > +    uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
> > +    uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
> > +    uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
> > +
> > +    uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
> > +    uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
> > +    uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
> > +
> > +    uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT3(i, j, k);
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = PREDICT3(m, i, j);
> > +
> > +    val = PREDICT3(a, m, i);
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = val;
> > +
> > +    val = PREDICT2(a, m);
> > +    PIXEL_CUR(s, 0, x + 0, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = val;
> > +
> > +    val = PREDICT3(b, a, m);
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = val;
> > +
> > +    val = PREDICT2(b, a);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = val;
> > +
> > +    val = PREDICT3(c, b, a);
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = val;
> > +
> > +    val = PREDICT2(c, b);
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = val;
> > +
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = PREDICT3(d, c, b);
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT2(d, c);
> > +}
> > +
> > +static void predict4_horizontal_down(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t val;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
> > +    uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
> > +    uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
> > +
> > +    uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
> > +    uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
> > +    uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
> > +    uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
> > +
> > +    uint8_t m = PIXEL_CUR(s, 0, x - 1, y - 1);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = PREDICT2(k, l);
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = PREDICT3(j, k, l);
> > +
> > +    val = PREDICT2(j, k);
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = val;
> > +
> > +    val = PREDICT3(i, j, k);
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = val;
> > +
> > +    val = PREDICT2(i, j);
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = val;
> > +
> > +    val = PREDICT3(m, i, j);
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = val;
> > +
> > +    val = PREDICT2(i, m);
> > +    PIXEL_CUR(s, 0, x + 0, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = val;
> > +
> > +    val = PREDICT3(i, m, a);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = val;
> > +
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = PREDICT3(m, a, b);
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(a, b, c);
> > +}
> > +
> > +static void predict4_vertical_left(AVCodecContext *avctx, int x, int y)
> > +{
> > +    uint8_t val;
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t a = PIXEL_CUR(s, 0, x + 0, y - 1);
> > +    uint8_t b = PIXEL_CUR(s, 0, x + 1, y - 1);
> > +    uint8_t c = PIXEL_CUR(s, 0, x + 2, y - 1);
> > +    uint8_t d = PIXEL_CUR(s, 0, x + 3, y - 1);
> > +    uint8_t e = PIXEL_CUR(s, 0, x + 4, y - 1);
> > +    uint8_t f = PIXEL_CUR(s, 0, x + 5, y - 1);
> > +    uint8_t g = PIXEL_CUR(s, 0, x + 6, y - 1);
> > +
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = PREDICT3(e, f, g);
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = PREDICT2(e, f);
> > +
> > +    val = PREDICT3(d, e, f);
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = val;
> > +
> > +    val = PREDICT2(d, e);
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = val;
> > +
> > +    val = PREDICT3(c, d, e);
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = val;
> > +
> > +    val = PREDICT2(c, d);
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = val;
> > +
> > +    val = PREDICT3(b, c, d);
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = val;
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = val;
> > +
> > +    val = PREDICT2(b, c);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = val;
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = val;
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = PREDICT3(a, b, c);
> > +    PIXEL_CUR(s, 0, x + 0, y + 0) = PREDICT2(a, b);
> > +}
> > +
> > +static void predict4_horizontal_up(AVCodecContext *avctx, int x, int y)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    uint8_t i = PIXEL_CUR(s, 0, x - 1, y + 0);
> > +    uint8_t j = PIXEL_CUR(s, 0, x - 1, y + 1);
> > +    uint8_t k = PIXEL_CUR(s, 0, x - 1, y + 2);
> > +    uint8_t l = PIXEL_CUR(s, 0, x - 1, y + 3);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 0) = PREDICT2(i, j);
> > +    PIXEL_CUR(s, 0, x + 1, y + 0) = PREDICT3(i, j, k);
> > +    PIXEL_CUR(s, 0, x + 2, y + 0) = PREDICT2(j, k);
> > +    PIXEL_CUR(s, 0, x + 3, y + 0) = PREDICT3(j, k, l);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 1) = PREDICT2(j, k);
> > +    PIXEL_CUR(s, 0, x + 1, y + 1) = PREDICT3(j, k, l);
> > +    PIXEL_CUR(s, 0, x + 2, y + 1) = PREDICT2(k, l);
> > +    PIXEL_CUR(s, 0, x + 3, y + 1) = PREDICT3(k, l, l);
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 2) = PREDICT2(k, l);
> > +    PIXEL_CUR(s, 0, x + 1, y + 2) = PREDICT3(k, l, l);
> > +    PIXEL_CUR(s, 0, x + 2, y + 2) = l;
> > +    PIXEL_CUR(s, 0, x + 3, y + 2) = l;
> > +
> > +    PIXEL_CUR(s, 0, x + 0, y + 3) = l;
> > +    PIXEL_CUR(s, 0, x + 1, y + 3) = l;
> > +    PIXEL_CUR(s, 0, x + 2, y + 3) = l;
> > +    PIXEL_CUR(s, 0, x + 3, y + 3) = l;
> > +}
> > +
> > +static int predict4(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    for (int y2 = 0; y2 < h >> 2; y2++) {
> > +        for (int x2 = 0; x2 < w >> 2; x2++) {
> > +            uint8_t mode = FFMIN(s->pred4_cache[1 + y2 - 1][1 + x2],
> > +                                 s->pred4_cache[1 + y2][1 + x2 - 1]);
> > +            if (mode == 9)// if invalid predict dc
> > +                mode = 2;
> > +
> > +            if (!get_bits1(gb)) {
> > +                uint8_t val = get_bits(gb, 3);
> > +                if (val >= mode)
> > +                    val++;
> > +                mode = val;
> > +            }
> > +
> > +            s->pred4_cache[1 + y2][1 + x2] = mode;
> > +
> > +            switch (mode) {
> > +            case 0:// vertical
> > +                predict_vertical(avctx, x + x2 * 4, y + y2 * 4, 4, 4, 0);
> > +                break;
> > +            case 1:// horizontal
> > +                predict_horizontal(avctx, x + x2 * 4, y + y2 * 4, 4, 4, 0);
> > +                break;
> > +            case 2:// dc
> > +                predict4_dc(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 3:// diagonal-down-left
> > +                predict4_diagonal_down_left(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 4:// diagonal-down-right
> > +                predict4_diagonal_down_right(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 5:// vertical-right
> > +                predict4_vertical_right(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 6:// horizontal-down
> > +                predict4_horizontal_down(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 7:// vertical-left
> > +                predict4_vertical_left(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            case 8:// horizontal-up
> > +                predict4_horizontal_up(avctx, x + x2 * 4, y + y2 * 4);
> > +                break;
> > +            default:
> > +                av_log(avctx, AV_LOG_ERROR, "invalid predict4 mode\n");
> > +                return AVERROR_INVALIDDATA;
> > +            }
> > +        }
> > +    }
> > +    return predict_notile_uv(avctx, x, y, w, h);
> > +}
> > +
> > +static void decode_dct(AVCodecContext *avctx, int x, int y, int plane,
> > +                       const int* level)
> > +{
> > +    int a, b, c, d, e, f;
> > +    int dct[16];
> > +    int tmp[16];
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    // dezigzag
> > +    for (int i = 0; i < 16; i++)
> > +        dct[zigzag4x4_tab[i]] = level[i];
> > +
> > +    // dequantize
> > +    for (int i = 0; i < 2; i++) {
> > +        for (int j = 0; j < 4; j++) {
> > +            dct[4 * j + i]     *= s->qtab[i][j];
> > +            dct[4 * j + i + 2] *= s->qtab[i][j];
> > +        }
> > +    }
> > +
> > +    dct[0] += 32;// rounding
> > +
> > +    for (int i = 0; i < 4; i++) {
> > +        a = dct[i * 4 + 0];
> > +        b = dct[i * 4 + 1];
> > +        c = dct[i * 4 + 2];
> > +        d = dct[i * 4 + 3];
> > +        a += c;
> > +        c = a - c * 2;
> > +        e = (b >> 1) - d;
> > +        f = b + (d >> 1);
> > +        tmp[ 0 + i] = a + f;
> > +        tmp[ 4 + i] = c + e;
> > +        tmp[ 8 + i] = c - e;
> > +        tmp[12 + i] = a - f;
> > +    }
> > +
> > +    for (int i = 0; i < 4; i++) {
> > +        a = tmp[i * 4 + 0];
> > +        b = tmp[i * 4 + 1];
> > +        c = tmp[i * 4 + 2];
> > +        d = tmp[i * 4 + 3];
> > +        a += c;
> > +        c =  a - c * 2;
> > +        e  = (b >> 1) - d;
> > +        f = b + (d >> 1);
> > +        PIXEL_CUR(s, plane, x + 0, y + i)
> > +            = av_clip_uint8(PIXEL_CUR(s, plane, x + 0, y + i) + ((a + f) >> 6));
> > +        PIXEL_CUR(s, plane, x + 1, y + i)
> > +            = av_clip_uint8(PIXEL_CUR(s, plane, x + 1, y + i) + ((c + e) >> 6));
> > +        PIXEL_CUR(s, plane, x + 2, y + i)
> > +            = av_clip_uint8(PIXEL_CUR(s, plane, x + 2, y + i) + ((c - e) >> 6));
> > +        PIXEL_CUR(s, plane, x + 3, y + i)
> > +            = av_clip_uint8(PIXEL_CUR(s, plane, x + 3, y + i) + ((a - f) >> 6));
> > +    }
> > +}
> > +
> > +static void decode_residu_cavlc(AVCodecContext *avctx, int x, int y, int plane,
> > +                                int nc, uint8_t *out_total_coeff)
> > +{
> > +    int level[16];
> > +    int coeff_token, total_coeff, trailing_ones, i, zeros_left, suffix_length;
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +
> > +    coeff_token = get_vlc2(gb, coeff_token_vlc[coeff_token_table_index[nc]].table,
> > +                           COEFF_TOKEN_VLC_BITS, 2);
> > +    trailing_ones = coeff_token & 3;
> > +    total_coeff   = coeff_token >> 2;
> > +
> > +    *out_total_coeff = total_coeff;
> > +    if (total_coeff == 0)
> > +        return;
> > +
> > +    av_assert2(total_coeff <= 16);
> > +
> > +    i = 15;
> > +    if (total_coeff != 16) {
> > +        int trailing_zeros;
> > +        zeros_left = get_vlc2(gb, total_zeros_vlc[total_coeff].table,
> > +                              TOTAL_ZEROS_VLC_BITS, 1);
> > +        trailing_zeros = 16 - (total_coeff + zeros_left);
> > +        while(trailing_zeros-- > 0)
> > +            level[i--] = 0;
> > +    } else
> > +        zeros_left = 0;
> > +
> > +    suffix_length = 0;
> > +    while (1) {
> > +        int level_suffix, level_code, run_before;
> > +        if (trailing_ones > 0) {
> > +            trailing_ones--;
> > +            level[i--] = get_bits1(gb) ? -1 : 1;
> > +        } else {
> > +            int level_prefix = 0;
> > +            while (!get_bits1(gb))
> > +                level_prefix++;
> > +
> > +            if (level_prefix == 15)
> > +                level_suffix = get_bits(gb, 11);
> > +            else
> > +                level_suffix = suffix_length == 0 ? 0 : get_bits(gb, suffix_length);
> > +
> > +            level_code = level_suffix + (level_prefix << suffix_length);
> > +
> > +            if (level_code > cavlc_suffix_len_update_tab[suffix_length])
> > +                suffix_length++;
> > +
> > +            level_code++;
> > +            if (get_bits1(gb))
> > +                level_code = -level_code;
> > +            level[i--] = level_code;
> > +        }
> > +
> > +        if (--total_coeff == 0)
> > +            break;
> > +
> > +        if (zeros_left == 0)
> > +            continue;
> > +
> > +        if(zeros_left < 7)
> > +            run_before = get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1);
> > +        else
> > +            run_before = get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2);
> > +        zeros_left -= run_before;
> > +        while(run_before-- > 0)
> > +            level[i--] = 0;
> > +    }
> > +
> > +    while(zeros_left-- > 0)
> > +        level[i--] = 0;
> > +
> > +    decode_dct(avctx, x, y, plane, level);
> > +}
> > +
> > +static int decode_residu_blocks(AVCodecContext *avctx, int x, int y,
> > +                                int w, int h)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    uint8_t *total_coeff_y = &s->total_coeff_y[
> > +        ((y >> 2) + 1) * s->total_coeff_y_stride + (x >> 2) + 1];
> > +    uint8_t *total_coeff_uv = &s->total_coeff_uv[
> > +        ((y >> 3) + 1) * s->total_coeff_uv_stride + (x >> 3) + 1];
> > +    for (int y2 = 0; y2 < h >> 3; y2++) {
> > +        for (int x2 = 0; x2 < w >> 3; x2++) {
> > +            uint8_t residu_mask;
> > +            int code = get_ue_golomb_31(gb);
> > +            if (code > 0x1F) {
> > +                av_log(avctx, AV_LOG_ERROR, "invalid residu mask code\n");
> > +                return AVERROR_INVALIDDATA;
> > +            }
> > +            if (s->version == VX_VERSION_OLD)
> > +                residu_mask = residu_mask_old_tab[code];
> > +            else
> > +                residu_mask = residu_mask_new_tab[code];
> > +
> > +            if (residu_mask & 1) {
> > +                int nc = (total_coeff_y[-1] +
> > +                          total_coeff_y[-s->total_coeff_y_stride] + 1) >> 1;
> > +                decode_residu_cavlc(avctx, x + x2 * 8, y + y2 * 8, 0, nc,
> > +                                    &total_coeff_y[0]);
> > +            } else
> > +                total_coeff_y[0] = 0;
> > +
> > +            if (residu_mask & 2) {
> > +                int nc = (total_coeff_y[0] +
> > +                          total_coeff_y[-s->total_coeff_y_stride + 1] + 1) >> 1;
> > +                decode_residu_cavlc(avctx, x + x2 * 8 + 4, y + y2 * 8, 0, nc,
> > +                                    &total_coeff_y[1]);
> > +            } else
> > +                total_coeff_y[1] = 0;
> > +
> > +            if (residu_mask & 4) {
> > +                int nc = (total_coeff_y[s->total_coeff_y_stride - 1] +
> > +                          total_coeff_y[0] + 1) >> 1;
> > +                decode_residu_cavlc(avctx, x + x2 * 8, y + y2 * 8 + 4, 0, nc,
> > +                                    &total_coeff_y[s->total_coeff_y_stride]);
> > +            } else
> > +                total_coeff_y[s->total_coeff_y_stride] = 0;
> > +
> > +            if (residu_mask & 8) {
> > +                int nc = (total_coeff_y[s->total_coeff_y_stride] +
> > +                          total_coeff_y[1] + 1) >> 1;
> > +                decode_residu_cavlc(
> > +                    avctx, x + x2 * 8 + 4, y + y2 * 8 + 4, 0, nc,
> > +                    &total_coeff_y[s->total_coeff_y_stride + 1]);
> > +            } else
> > +                total_coeff_y[s->total_coeff_y_stride + 1] = 0;
> > +
> > +            if (residu_mask & 16) {
> > +                uint8_t total_coeff_u, total_coeff_v;
> > +                int nc = (total_coeff_uv[-1] +
> > +                          total_coeff_uv[-s->total_coeff_uv_stride] + 1) >> 1;
> > +                decode_residu_cavlc(avctx, (x + x2 * 8) >> 1, (y + y2 * 8) >> 1,
> > +                                    1, nc, &total_coeff_u);
> > +                decode_residu_cavlc(avctx, (x + x2 * 8) >> 1, (y + y2 * 8) >> 1,
> > +                                    2, nc, &total_coeff_v);
> > +                total_coeff_uv[0] = (total_coeff_u + total_coeff_v + 1) >> 1;
> > +            } else
> > +                total_coeff_uv[0] = 0;
> > +
> > +            total_coeff_y += 2;
> > +            total_coeff_uv++;
> > +        }
> > +        total_coeff_y  += (s->total_coeff_y_stride << 1) - (w >> 2);
> > +        total_coeff_uv += s->total_coeff_uv_stride - (w >> 3);
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int predict_inter(AVCodecContext *avctx, int x, int y, int w, int h,
> > +                          const MVec *predVec, int has_delta, int ref_frame)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    MVec vec = *predVec;
> > +
> > +    if (ref_frame >= s->ref_frame_count) {
> > +        av_log(avctx, AV_LOG_ERROR, "reference to unavailable frame\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    s->cur_frame->pict_type = AV_PICTURE_TYPE_P;
> > +    s->cur_frame->key_frame = 0;
> > +
> > +    if (has_delta) {
> > +        vec.x += (unsigned)get_se_golomb(gb);
> > +        vec.y += (unsigned)get_se_golomb(gb);
> > +    }
> > +
> > +    if (vec.x >= INT_MAX || vec.y >= INT_MAX)
> > +        return AVERROR_INVALIDDATA;
> > +
> > +    s->vectors[(1 + (y >> 4)) * s->vectors_stride + 1 + (x >> 4)] = vec;
> > +
> > +    if (x + vec.x < 0 || x + vec.x + w > avctx->width ||
> > +        y + vec.y < 0 || y + vec.y + h > avctx->height) {
> > +        av_log(avctx, AV_LOG_ERROR, "motion vector out of bounds\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    // luma
> > +    for (int y2 = 0; y2 < h; y2++)
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            PIXEL_CUR(s, 0, x + x2, y + y2)
> > +                = PIXEL_REF(s, ref_frame, 0, x + x2 + vec.x, y + y2 + vec.y);
> > +
> > +    // chroma
> > +    for (int y2 = 0; y2 < (h >> 1); y2++) {
> > +        for (int x2 = 0; x2 < (w >> 1); x2++) {
> > +            // u
> > +            PIXEL_CUR(s, 1, (x >> 1) + x2, (y >> 1) + y2)
> > +                = PIXEL_REF(s, ref_frame, 1, (x >> 1) + x2 + (vec.x >> 1),
> > +                            (y >> 1) + y2 + (vec.y >> 1));
> > +            // v
> > +            PIXEL_CUR(s, 2, (x >> 1) + x2, (y >> 1) + y2)
> > +                = PIXEL_REF(s, ref_frame, 2, (x >> 1) + x2 + (vec.x >> 1),
> > +                            (y >> 1) + y2 + (vec.y >> 1));
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int predict_inter_dc(AVCodecContext *avctx, int x, int y, int w, int h)
> > +{
> > +    int dx, dy, dc_y, dc_u, dc_v;
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +
> > +    if (s->ref_frame_count == 0) {
> > +        av_log(avctx, AV_LOG_ERROR, "reference to unavailable frame\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    dx   = get_se_golomb(gb);
> > +    dy   = get_se_golomb(gb);
> > +
> > +    if (x + dx < 0 || x + dx + w > avctx->width ||
> > +        y + dy < 0 || y + dy + h > avctx->height) {
> > +        av_log(avctx, AV_LOG_ERROR, "motion vector out of bounds\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    dc_y = get_se_golomb(gb);
> > +    if (dc_y < -(1<<16) || dc_y >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    dc_y <<= 1;
> > +
> > +    dc_u = get_se_golomb(gb);
> > +    if (dc_u < -(1<<16) || dc_u >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    dc_u <<= 1;
> > +
> > +    dc_v = get_se_golomb(gb);
> > +    if (dc_v < -(1<<16) || dc_v >= (1 << 16)) {
> > +        av_log(avctx, AV_LOG_ERROR, "invalid dc offset\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    dc_v <<= 1;
> > +
> > +    s->cur_frame->pict_type = AV_PICTURE_TYPE_P;
> > +    s->cur_frame->key_frame = 0;
> > +
> > +    // luma
> > +    for (int y2 = 0; y2 < h; y2++)
> > +        for (int x2 = 0; x2 < w; x2++)
> > +            PIXEL_CUR(s, 0, x + x2, y + y2) = av_clip_uint8(
> > +                PIXEL_REF(s, 0, 0, x + x2 + dx, y + y2 + dy) + dc_y);
> > +
> > +    // chroma
> > +    for (int y2 = 0; y2 < (h >> 1); y2++) {
> > +        for (int x2 = 0; x2 < (w >> 1); x2++) {
> > +            PIXEL_CUR(s, 1, (x >> 1) + x2, (y >> 1) + y2) = av_clip_uint8(
> > +                PIXEL_REF(s, 0, 1, (x >> 1) + x2 + (dx >> 1),
> > +                          (y >> 1) + y2 + (dy >> 1)) + dc_u);
> > +            PIXEL_CUR(s, 2, (x >> 1) + x2, (y >> 1) + y2) = av_clip_uint8(
> > +                PIXEL_REF(s, 0, 2, (x >> 1) + x2 + (dx >> 1),
> > +                          (y >> 1) + y2 + (dy >> 1)) + dc_v);
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int decode_mb(AVCodecContext *avctx, int x, int y, int w, int h,
> > +                     const MVec *predVec)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    int ret = 0;
> > +
> > +    int mode = get_ue_golomb_31(gb);
> > +    if (s->version == VX_VERSION_OLD)
> > +        mode = old_mb_mode_remap_tab[mode];
> > +
> > +    switch (mode) {
> > +    case 0:// v-split, no residu
> > +        if (w == 2) {
> > +            av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        if ((ret = decode_mb(avctx, x, y, w >> 1, h, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_mb(avctx, x + (w >> 1), y, w >> 1, h, predVec)) < 0)
> > +            return ret;
> > +        if (w == 8 && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 1:// no delta, no residu, ref 0
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 0)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 2:// h-split, no residu
> > +        if (h == 2) {
> > +            av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        if ((ret = decode_mb(avctx, x, y, w, h >> 1, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_mb(avctx, x, y + (h >> 1), w, h >> 1, predVec)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && h == 8)
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 3:// unpredicted delta ref0 + dc offset, no residu
> > +        if ((ret = predict_inter_dc(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 4:// delta, no residu, ref 0
> > +    case 5:// delta, no residu, ref 1
> > +    case 6:// delta, no residu, ref 2
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 1, mode - 4)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 7:// plane, no residu
> > +        if ((ret = predict_mb_plane(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 8:// v-split, residu
> > +        if (w == 2) {
> > +            av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        if ((ret = decode_mb(avctx, x, y, w >> 1, h, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_mb(avctx, x + (w >> 1), y, w >> 1, h, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 9:// no delta, no residu, ref 1
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 1)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 10:// unpredicted delta ref0 + dc offset, residu
> > +        if ((ret = predict_inter_dc(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 11:// predict notile, no residu
> > +        if ((ret = predict_notile(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 12:// no delta, residu, ref 0
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 0)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 13:// h-split, residu
> > +        if (h == 2) {
> > +            av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        if ((ret = decode_mb(avctx, x, y, w, h >> 1, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_mb(avctx, x, y + (h >> 1), w, h >> 1, predVec)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 14:// no delta, no residu, ref 2
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, 2)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 15:// predict4, no residu
> > +        if ((ret = predict4(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((w == 8 || w == 16) && (h == 8 || h == 16))
> > +            clear_total_coeff(avctx, x, y, w, h);
> > +        break;
> > +    case 16:// delta, residu, ref 0
> > +    case 17:// delta, residu, ref 1
> > +    case 18:// delta, residu, ref 2
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 1, mode - 16)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 19:// predict4, residu
> > +        if ((ret = predict4(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 20:// no delta, residu, ref 1
> > +    case 21:// no delta, residu, ref 2
> > +        if ((ret = predict_inter(avctx, x, y, w, h, predVec, 0, mode - 20 + 1)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 22:// predict notile, residu
> > +        if ((ret = predict_notile(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    case 23:// plane, residu
> > +        if ((ret = predict_mb_plane(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        if ((ret = decode_residu_blocks(avctx, x, y, w, h)) < 0)
> > +            return ret;
> > +        break;
> > +    default:
> > +        av_log(avctx, AV_LOG_ERROR, "invalid macroblock mode\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int detect_format(AVCodecContext *avctx)
> > +{
> > +    // assume the new format, if any incorrect decisions are made for the
> > +    // first macroblock of a keyframe (ref, non-dc prediction) then it must be
> > +    // the old format
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    int w = 16;
> > +    int h = 16;
> > +    while (1) {
> > +        int mode = get_ue_golomb_31(gb);
> > +        if (mode == 0 || mode == 8) { // v-split
> > +            if (w == 2) // too many splits
> > +                return VX_VERSION_OLD;
> > +            w >>= 1;
> > +            continue;
> > +        } else if (mode == 2 || mode == 13) { // h-split
> > +            if (h == 2) // too many splits
> > +                return VX_VERSION_OLD;
> > +            h >>= 1;
> > +            continue;
> > +        } else if (mode == 11 || mode == 22) { // predict notile
> > +            if (get_ue_golomb_31(gb) != 2) // mode_y != dc
> > +                return VX_VERSION_OLD;
> > +            if (get_ue_golomb_31(gb) != 0) // mode_uv != dc
> > +                return VX_VERSION_OLD;
> > +            break; //we should have enough evidence now
> > +        } else if (mode == 15 || mode == 19) { // predict4
> > +            // initial prediction is always dc
> > +            // we don't expect that prediction to be wrong
> > +            if (!get_bits1(gb))
> > +                return VX_VERSION_OLD;
> > +            break; //we should have enough evidence now
> > +        } else // inter prediction, plane or any other value
> > +            return VX_VERSION_OLD;
> > +    }
> > +    return VX_VERSION_NEW;
> > +}
> > +
> > +static int actimagine_decode(AVCodecContext *avctx, void *data,
> > +                            int *got_frame, AVPacket *pkt)
> > +{
> > +    MVec *vectors;
> > +    int ret;
> > +    ActimagineContext *s = avctx->priv_data;
> > +    GetBitContext *gb = &s->gb;
> > +    AVFrame *frame = s->cur_frame;
> > +
> > +    // in avi files the frames start with a 32 bit number that seems to
> > +    // indicate the total number of bits
> > +    int offset = s->avi ? 4 : 0;
> > +
> > +    av_fast_padded_malloc(&s->bitstream, &s->bitstream_size,
> > +                          pkt->size);
> > +
> > +    if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
> > +        return ret;
> > +
> > +    s->bdsp.bswap16_buf((uint16_t *)s->bitstream, (uint16_t *)pkt->data,
> > +                        (pkt->size + 1) >> 1);
> > +
> > +    ret = init_get_bits8(gb, s->bitstream + offset,
> > +                         FFALIGN(pkt->size - offset, 2));
> > +    if (ret < 0)
> > +        return ret;
> > +
> > +    // determine the bitstream version if this was not done yet
> > +    if (s->version == VX_VERSION_INVALID) {
> > +        if (s->ref_frame_count != 0) {
> > +            av_log(avctx, AV_LOG_ERROR, "can't determine version on p frame\n");
> > +            return AVERROR_INVALIDDATA;
> > +        }
> > +        s->version = detect_format(avctx);
> > +
> > +        // reinit bitreader
> > +        ret = init_get_bits8(gb, s->bitstream + offset,
> > +                             FFALIGN(pkt->size - offset, 2));
> > +        if (ret < 0)
> > +            return ret;
> > +    }
> > +
> > +    vectors = s->vectors + s->vectors_stride + 1;
> > +
> > +    frame->pict_type = AV_PICTURE_TYPE_I;
> > +    frame->key_frame = 1;
> > +
> > +    if (s->quantizer == -1) {
> > +        av_log(avctx, AV_LOG_ERROR, "no quantizer setup\n");
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    for (int y = 0; y < avctx->height; y += 16) {
> > +        MVec *vec_cur = vectors;
> > +        for (int x = 0; x < avctx->width; x += 16) {
> > +            MVec predVec;
> > +            vec_cur[0].x = 0;
> > +            vec_cur[0].y = 0;
> > +            predVec.x = mid_pred(vec_cur[-1].x, vec_cur[-s->vectors_stride].x,
> > +                                 vec_cur[-s->vectors_stride + 1].x);
> > +            predVec.y = mid_pred(vec_cur[-1].y, vec_cur[-s->vectors_stride].y,
> > +                                 vec_cur[-s->vectors_stride + 1].y);
> > +            if ((ret = decode_mb(avctx, x, y, 16, 16, &predVec)) < 0)
> > +                return ret;
> > +            vec_cur++;
> > +        }
> > +        vectors += s->vectors_stride;
> > +    }
> > +
> > +    if (s->ref_frame_count == 3)
> > +        av_frame_unref(s->ref_frames[2]);
> > +
> > +    s->cur_frame = s->ref_frames[2];
> > +    s->ref_frames[2] = s->ref_frames[1];
> > +    s->ref_frames[1] = s->ref_frames[0];
> > +    s->ref_frames[0] = frame;
> > +
> > +    if (s->ref_frame_count < 3)
> > +        s->ref_frame_count++;
> > +
> > +    if ((ret = av_frame_ref(data, frame)) < 0)
> > +        return ret;
> > +    *got_frame = 1;
> > +
> > +    return 0;
> > +}
> > +
> > +static void actimagine_flush(AVCodecContext *avctx)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    for (int i = 0; i < 3; i++)
> > +        av_frame_unref(s->ref_frames[i]);
> > +
> > +    s->ref_frame_count = 0;
> > +}
> > +
> > +static av_cold int actimagine_close(AVCodecContext *avctx)
> > +{
> > +    ActimagineContext *s = avctx->priv_data;
> > +
> > +    av_freep(&s->vectors);
> > +    s->vectors_stride = 0;
> > +    av_freep(&s->total_coeff_y);
> > +    s->total_coeff_y_stride = 0;
> > +    av_freep(&s->total_coeff_uv);
> > +    s->total_coeff_uv_stride = 0;
> > +
> > +    av_freep(&s->bitstream);
> > +    s->bitstream_size = 0;
> > +
> > +    for (int i = 0; i < 3; i++)
> > +        av_frame_free(&s->ref_frames[i]);
> > +    av_frame_free(&s->cur_frame);
> > +
> > +    return 0;
> > +}
> > +
> > +AVCodec ff_actimagine_decoder = {
> > +    .name           = "actimagine",
> > +    .long_name      = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
> > +    .type           = AVMEDIA_TYPE_VIDEO,
> > +    .id             = AV_CODEC_ID_ACTIMAGINE,
> > +    .priv_data_size = sizeof(ActimagineContext),
> > +    .init           = actimagine_init,
> > +    .decode         = actimagine_decode,
> > +    .flush          = actimagine_flush,
> > +    .close          = actimagine_close,
> > +    .capabilities   = AV_CODEC_CAP_DR1,
> > +    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
> > +};
> > diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> > index 2e9a3581de..10809f3492 100644
> > --- a/libavcodec/allcodecs.c
> > +++ b/libavcodec/allcodecs.c
> > @@ -32,6 +32,7 @@
> >  extern AVCodec ff_a64multi_encoder;
> >  extern AVCodec ff_a64multi5_encoder;
> >  extern AVCodec ff_aasc_decoder;
> > +extern AVCodec ff_actimagine_decoder;
> >  extern AVCodec ff_aic_decoder;
> >  extern AVCodec ff_alias_pix_encoder;
> >  extern AVCodec ff_alias_pix_decoder;
> > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
> > index 17f8a14044..65d96c21af 100644
> > --- a/libavcodec/codec_desc.c
> > +++ b/libavcodec/codec_desc.c
> > @@ -1856,6 +1856,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
> >          .long_name = NULL_IF_CONFIG_SMALL("Digital Pictures SGA Video"),
> >          .props     = AV_CODEC_PROP_LOSSY,
> >      },
> > +    {
> > +        .id        = AV_CODEC_ID_ACTIMAGINE,
> > +        .type      = AVMEDIA_TYPE_VIDEO,
> > +        .name      = "actimagine",
> > +        .long_name = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
> > +        .props     = AV_CODEC_PROP_LOSSY,
> > +    },
> >
> >      /* various PCM "codecs" */
> >      {
> > diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
> > index ab7bc68ee2..a4b3f3955d 100644
> > --- a/libavcodec/codec_id.h
> > +++ b/libavcodec/codec_id.h
> > @@ -307,6 +307,7 @@ enum AVCodecID {
> >      AV_CODEC_ID_CRI,
> >      AV_CODEC_ID_SIMBIOSIS_IMX,
> >      AV_CODEC_ID_SGA_VIDEO,
> > +    AV_CODEC_ID_ACTIMAGINE,
> >
> >      /* various PCM "codecs" */
> >      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
> > diff --git a/libavcodec/version.h b/libavcodec/version.h
> > index 4299ad4239..f992e1b36e 100644
> > --- a/libavcodec/version.h
> > +++ b/libavcodec/version.h
> > @@ -28,7 +28,7 @@
> >  #include "libavutil/version.h"
> >
> >  #define LIBAVCODEC_VERSION_MAJOR  58
> > -#define LIBAVCODEC_VERSION_MINOR 131
> > +#define LIBAVCODEC_VERSION_MINOR 132
> >  #define LIBAVCODEC_VERSION_MICRO 100
> >
> >  #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
> > diff --git a/libavformat/riff.c b/libavformat/riff.c
> > index 270ff7c024..5d5cfe16b0 100644
> > --- a/libavformat/riff.c
> > +++ b/libavformat/riff.c
> > @@ -496,6 +496,8 @@ const AVCodecTag ff_codec_bmp_tags[] = {
> >      { AV_CODEC_ID_MVHA,         MKTAG('M', 'V', 'H', 'A') },
> >      { AV_CODEC_ID_MV30,         MKTAG('M', 'V', '3', '0') },
> >      { AV_CODEC_ID_NOTCHLC,      MKTAG('n', 'l', 'c', '1') },
> > +    { AV_CODEC_ID_ACTIMAGINE,   MKTAG('V', 'X', 'S', '1') },
> > +    { AV_CODEC_ID_ACTIMAGINE,   MKTAG('v', 'x', 's', '1') },
> >      { AV_CODEC_ID_NONE,         0 }
> >  };
> >
> >
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list