diff mbox series

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

Message ID 20210318103140.14968-1-fnouwt2@gmail.com
State New
Headers show
Series [FFmpeg-devel,v3] avcodec: add Actimagine VX video decoder | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Florian Nouwt March 18, 2021, 10:31 a.m. UTC
Signed-off-by: Florian Nouwt <fnouwt2@gmail.com>
---
 Changelog                       |    1 +
 configure                       |    1 +
 doc/general_contents.texi       |    2 +
 libavcodec/Makefile             |    3 +-
 libavcodec/actimagine_vx.c      | 1150 +++++++++++++++++++++++++++++++
 libavcodec/actimagine_vx_data.c |   45 ++
 libavcodec/actimagine_vx_data.h |   28 +
 libavcodec/allcodecs.c          |    1 +
 libavcodec/codec_desc.c         |    7 +
 libavcodec/codec_id.h           |    1 +
 libavcodec/h264_cavlc.c         |  205 +-----
 libavcodec/h264_cavlc_data.c    |  220 ++++++
 libavcodec/h264_cavlc_data.h    |   50 ++
 libavcodec/version.h            |    2 +-
 libavformat/riff.c              |    2 +
 15 files changed, 1524 insertions(+), 194 deletions(-)
 create mode 100644 libavcodec/actimagine_vx.c
 create mode 100644 libavcodec/actimagine_vx_data.c
 create mode 100644 libavcodec/actimagine_vx_data.h
 create mode 100644 libavcodec/h264_cavlc_data.c
 create mode 100644 libavcodec/h264_cavlc_data.h

Comments

Andreas Rheinhardt March 18, 2021, 2:04 p.m. UTC | #1
Florian Nouwt:
> Signed-off-by: Florian Nouwt <fnouwt2@gmail.com>
> ---
>  Changelog                       |    1 +
>  configure                       |    1 +
>  doc/general_contents.texi       |    2 +
>  libavcodec/Makefile             |    3 +-
>  libavcodec/actimagine_vx.c      | 1150 +++++++++++++++++++++++++++++++
>  libavcodec/actimagine_vx_data.c |   45 ++
>  libavcodec/actimagine_vx_data.h |   28 +
>  libavcodec/allcodecs.c          |    1 +
>  libavcodec/codec_desc.c         |    7 +
>  libavcodec/codec_id.h           |    1 +
>  libavcodec/h264_cavlc.c         |  205 +-----
>  libavcodec/h264_cavlc_data.c    |  220 ++++++
>  libavcodec/h264_cavlc_data.h    |   50 ++
>  libavcodec/version.h            |    2 +-
>  libavformat/riff.c              |    2 +
>  15 files changed, 1524 insertions(+), 194 deletions(-)
>  create mode 100644 libavcodec/actimagine_vx.c
>  create mode 100644 libavcodec/actimagine_vx_data.c
>  create mode 100644 libavcodec/actimagine_vx_data.h
>  create mode 100644 libavcodec/h264_cavlc_data.c
>  create mode 100644 libavcodec/h264_cavlc_data.h
> 
> 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..c38066bc1c 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_vx_decoder_select="bswapdsp golomb h264dsp h264pred"
>  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).
> +@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..0bdeb9fc26 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_VX_DECODER)   += actimagine_vx.o actimagine_vx_data.o h264_cavlc_data.o
>  OBJS-$(CONFIG_AGM_DECODER)             += agm.o
>  OBJS-$(CONFIG_AIC_DECODER)             += aic.o
>  OBJS-$(CONFIG_ALAC_DECODER)            += alac.o alac_data.o alacdsp.o
> @@ -367,7 +368,7 @@ OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
>                                            h264_direct.o h264_loopfilter.o  \
>                                            h264_mb.o h264_picture.o \
>                                            h264_refs.o h264_sei.o \
> -                                          h264_slice.o h264data.o
> +                                          h264_slice.o h264data.o h264_cavlc_data.o
>  OBJS-$(CONFIG_H264_AMF_ENCODER)        += amfenc_h264.o
>  OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuviddec.o
>  OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
> diff --git a/libavcodec/actimagine_vx.c b/libavcodec/actimagine_vx.c
> new file mode 100644
> index 0000000000..84871a1008
> --- /dev/null
> +++ b/libavcodec/actimagine_vx.c
> @@ -0,0 +1,1150 @@
> +/*
> + * 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 "avcodec.h"
> +#include "bytestream.h"
> +#include "bswapdsp.h"
> +#include "get_bits.h"
> +#include "golomb.h"
> +#include "internal.h"
> +#include "libavutil/mem_internal.h"
> +#include "h264_cavlc_data.h"
> +#include "h264dsp.h"
> +#include "h264pred.h"
> +#include "actimagine_vx_data.h"
> +
> +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 }
> +};
> +
> +typedef struct MVec {
> +    int x, y;
> +} MVec;
> +
> +typedef struct VxContext {
> +    AVFrame *out_frame;
> +    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;
> +
> +    uint8_t zigzag_scan[16];
> +
> +    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;
> +    H264DSPContext  h264dsp;
> +    H264PredContext h264pred;
> +} VxContext;
> +
> +#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 VX_VERSION_INVALID  -1
> +#define VX_VERSION_OLD       0
> +#define VX_VERSION_NEW       1
> +
> +static int setup_qtables(AVCodecContext *avctx, int quantizer)
> +{
> +    int qx, qy;
> +    VxContext *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 vx_init(AVCodecContext *avctx)
> +{
> +    int vectors_size;
> +    int total_coeff_y_size;
> +    int total_coeff_uv_size;
> +    VxContext *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);
> +    ff_h264dsp_init(&s->h264dsp, 8, 1);
> +    ff_h264_pred_init(&s->h264pred, AV_CODEC_ID_ACTIMAGINE_VX, 8, 1);
> +
> +    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
> +    avctx->color_range = AVCOL_RANGE_JPEG;
> +    avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
> +    avctx->colorspace = AVCOL_SPC_SMPTE170M;
> +
> +    // zigzag_scan is a transposed version of ff_zigzag_scan, like in h264
> +    for (int i = 0; i < 16; i++)
> +        s->zigzag_scan[i] = (ff_zigzag_scan[i] >> 2) | ((ff_zigzag_scan[i] << 2) & 0xF);
> +
> +    // 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);
> +
> +    // 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_mallocz(total_coeff_y_size);
> +    if (!s->total_coeff_y)
> +        return AVERROR(ENOMEM);
> +
> +    // 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_mallocz(total_coeff_uv_size);
> +    if (!s->total_coeff_uv)
> +        return AVERROR(ENOMEM);
> +
> +    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->out_frame = av_frame_alloc();
> +    if (!s->out_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_h264_cavlc_data_init_vlc();
> +
> +    return 0;
> +}
> +
> +static void clear_total_coeff(AVCodecContext *avctx, int x, int y, int w, int h)
> +{
> +    VxContext *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)
> +{
> +    VxContext *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)
> +{
> +    VxContext *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)
> +{
> +    VxContext *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)
> +{
> +    VxContext *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)
> +{
> +    VxContext *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)
> +{
> +    static const uint8_t shift_tab[] = { 1, 2, 3, 0, 4 };
> +    uint8_t dc;
> +    VxContext *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 >>= 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 >>= 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 >> 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 >> 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)
> +{
> +    VxContext *s = avctx->priv_data;
> +    GetBitContext *gb = &s->gb;
> +    switch (get_ue_golomb_31(gb)) {
> +    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)
> +{
> +    VxContext *s = avctx->priv_data;
> +    GetBitContext *gb = &s->gb;
> +    switch (get_ue_golomb_31(gb)) {
> +    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);
> +}
> +
> +static int predict4(AVCodecContext *avctx, int x, int y, int w, int h)
> +{
> +    VxContext *s = avctx->priv_data;
> +    GetBitContext *gb = &s->gb;
> +    int stride = s->cur_frame->linesize[0];
> +    for (int y2 = 0; y2 < h >> 2; y2++) {
> +        for (int x2 = 0; x2 < w >> 2; x2++) {
> +            uint8_t *dst, *top_right;
> +            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);
> +                mode = val + (val >= mode);
> +            }
> +
> +            s->pred4_cache[1 + y2][1 + x2] = mode;
> +
> +            dst = &PIXEL_CUR(s, 0, x + x2 * 4, y + y2 * 4);
> +            top_right = &PIXEL_CUR(s, 0, x + x2 * 4 + 4, y + y2 * 4 - 1);
> +
> +            switch (mode) {
> +            case 0:// vertical
> +                s->h264pred.pred4x4[VERT_PRED](dst, NULL, stride);
> +                break;
> +            case 1:// horizontal
> +                s->h264pred.pred4x4[HOR_PRED](dst, NULL, stride);
> +                break;
> +            case 2:// dc
> +                if (x + x2 * 4 == 0 && y + y2 * 4 == 0)
> +                    s->h264pred.pred4x4[DC_128_PRED](dst, NULL, stride);
> +                else if (x + x2 * 4 == 0 && y + y2 * 4 != 0)
> +                    s->h264pred.pred4x4[TOP_DC_PRED](dst, NULL, stride);
> +                else if (x + x2 * 4 != 0 && y + y2 * 4 == 0)
> +                    s->h264pred.pred4x4[LEFT_DC_PRED](dst, NULL, stride);
> +                else
> +                    s->h264pred.pred4x4[DC_PRED](dst, NULL, stride);
> +                break;
> +            case 3:// diagonal-down-left
> +                s->h264pred.pred4x4[DIAG_DOWN_LEFT_PRED](dst, top_right, stride);
> +                break;
> +            case 4:// diagonal-down-right
> +                s->h264pred.pred4x4[DIAG_DOWN_RIGHT_PRED](dst, NULL, stride);
> +                break;
> +            case 5:// vertical-right
> +                s->h264pred.pred4x4[VERT_RIGHT_PRED](dst, NULL, stride);
> +                break;
> +            case 6:// horizontal-down
> +                s->h264pred.pred4x4[HOR_DOWN_PRED](dst, NULL, stride);
> +                break;
> +            case 7:// vertical-left
> +                s->h264pred.pred4x4[VERT_LEFT_PRED](dst, top_right, stride);
> +                break;
> +            case 8:// horizontal-up
> +                s->h264pred.pred4x4[HOR_UP_PRED](dst, NULL, stride);
> +                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)
> +{
> +    LOCAL_ALIGNED_16(int16_t, dct, [16]);
> +    VxContext *s = avctx->priv_data;
> +
> +    // dezigzag
> +    for (int i = 0; i < 16; i++)
> +        dct[s->zigzag_scan[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];
> +        }
> +    }
> +
> +    s->h264dsp.h264_idct_add(&PIXEL_CUR(s, plane, x, y), dct,
> +                             s->cur_frame->linesize[plane]);
> +}
> +
> +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;
> +    VxContext *s = avctx->priv_data;
> +    GetBitContext *gb = &s->gb;
> +
> +    coeff_token = get_vlc2(gb, ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[nc]].table,
> +                           FF_H264_CAVLC_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, ff_h264_cavlc_total_zeros_vlc[total_coeff].table,
> +                              FF_H264_CAVLC_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) + 1;
> +
> +            suffix_length += level_code > ff_h264_cavlc_suffix_limit[suffix_length + 1];
> +
> +            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, ff_h264_cavlc_run_vlc[zeros_left].table,
> +                                  FF_H264_CAVLC_RUN_VLC_BITS, 1);
> +        else
> +            run_before = get_vlc2(gb, ff_h264_cavlc_run7_vlc.table,
> +                                  FF_H264_CAVLC_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)
> +{
> +    VxContext *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;
> +            unsigned 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 = ff_actimagine_vx_residu_mask_old_tab[code];
> +            else
> +                residu_mask = ff_actimagine_vx_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)
> +{
> +    VxContext *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;
> +    VxContext *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++) {
> +            // u
> +            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);
> +            // v
> +            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)
> +{
> +    VxContext *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 = ff_actimagine_vx_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
> +    VxContext *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 convert_colorspace(AVCodecContext *avctx)
> +{
> +    int ret;
> +    VxContext *s = avctx->priv_data;
> +    if ((ret = ff_reget_buffer(avctx, s->out_frame, 0)) < 0)
> +        return ret;
> +    
> +    // the color space is not supported by ffmpeg
> +    // r = y + 2v
> +    // g = y - 0.5u - v
> +    // b = y + 2u
> +    // convert to the SMPTE170M format
> +
> +    for (int y = 0; y < avctx->height; y++) {
> +        for (int x = 0; x < avctx->width; x++) {
> +            s->out_frame->data[0][y * s->out_frame->linesize[0] + x]
> +                = av_clip_uint8(PIXEL_CUR(s, 0, x, y) + ((
> +                    (PIXEL_CUR(s, 1, x >> 1, y >> 1) - 128) * -68682 +
> +                    (PIXEL_CUR(s, 2, x >> 1, y >> 1) - 128) * 11534 +                    
> +                    (1 << 19)) >> 20));
> +        }
> +    }
> +
> +    for (int y = 0; y < avctx->height >> 1; y++) {
> +        for (int x = 0; x < avctx->width >> 1; x++) {
> +            s->out_frame->data[1][y * s->out_frame->linesize[1] + x]
> +                = av_clip_uint8(128 + ((
> +                    (PIXEL_CUR(s, 1, x, y) - 128) * 1222325 +
> +                    (PIXEL_CUR(s, 2, x, y) - 128) * -4928) >> 20));
> +            s->out_frame->data[2][y * s->out_frame->linesize[2] + x]
> +                = av_clip_uint8(128 + ((
> +                    (PIXEL_CUR(s, 1, x, y) - 128) * 49073 +
> +                    (PIXEL_CUR(s, 2, x, y) - 128) * 1487615) >> 20));
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int vx_decode(AVCodecContext *avctx, void *data, int *got_frame,
> +                     AVPacket *pkt)
> +{
> +    MVec *vectors;
> +    int ret;
> +    VxContext *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;
> +
> +    // initially we assume this is an i frame
> +    // this is corrected when a p block is found
> +    frame->pict_type = AV_PICTURE_TYPE_I;
> +    frame->key_frame = 1;
> +
> +    if (s->quantizer == -1) {
> +        av_log(avctx, AV_LOG_ERROR, "no quantizer configured\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 ((ret = convert_colorspace(avctx)) < 0)
> +        return ret;
> +
> +    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, s->out_frame)) < 0)
> +        return ret;
> +
> +    *got_frame = 1;
> +
> +    return 0;
> +}
> +
> +static void vx_flush(AVCodecContext *avctx)
> +{
> +    VxContext *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 vx_close(AVCodecContext *avctx)
> +{
> +    VxContext *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);
> +    av_frame_free(&s->out_frame);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_actimagine_vx_decoder = {
> +    .name           = "actimagine_vx",
> +    .long_name      = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_ACTIMAGINE_VX,
> +    .priv_data_size = sizeof(VxContext),
> +    .init           = vx_init,
> +    .decode         = vx_decode,
> +    .flush          = vx_flush,
> +    .close          = vx_close,
> +    .capabilities   = AV_CODEC_CAP_DR1,
> +    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
> +};
> diff --git a/libavcodec/actimagine_vx_data.c b/libavcodec/actimagine_vx_data.c
> new file mode 100644
> index 0000000000..b557dd35a5
> --- /dev/null
> +++ b/libavcodec/actimagine_vx_data.c
> @@ -0,0 +1,45 @@
> +/*
> + * Actimagine VX Video tables
> + * 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 "actimagine_vx_data.h"
> +
> +const uint8_t ff_actimagine_vx_old_mb_mode_remap_tab[24] =
> +{
> +     1,  2,  0,  4,  7,  3, 11, 15,  9,  5, 14,  6,
> +    12, 13,  8, 16, 23, 10, 22, 19, 20, 17, 21, 18
> +};
> +
> +const uint8_t ff_actimagine_vx_residu_mask_old_tab[32] =
> +{
> +    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
> +};
> +
> +const uint8_t ff_actimagine_vx_residu_mask_new_tab[32] =
> +{
> +    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
> +};
> diff --git a/libavcodec/actimagine_vx_data.h b/libavcodec/actimagine_vx_data.h
> new file mode 100644
> index 0000000000..46a715ca71
> --- /dev/null
> +++ b/libavcodec/actimagine_vx_data.h
> @@ -0,0 +1,28 @@
> +/*
> + * 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
> + */
> +
> +#ifndef AVCODEC_ACTIMAGINE_VX_DATA_H
> +#define AVCODEC_ACTIMAGINE_VX_DATA_H
> +
> +#include <stdint.h>
> +
> +extern const uint8_t ff_actimagine_vx_old_mb_mode_remap_tab[24];
> +extern const uint8_t ff_actimagine_vx_residu_mask_old_tab[32];
> +extern const uint8_t ff_actimagine_vx_residu_mask_new_tab[32];

Why are these tables not internal to actimagine_vx.c?

> +
> +#endif /* AVCODEC_ACTIMAGINE_VX_DATA_H */
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index 2e9a3581de..9762521b11 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_vx_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..281da17942 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_VX,
> +        .type      = AVMEDIA_TYPE_VIDEO,
> +        .name      = "actimagine_vx",
> +        .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..172b96ef27 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_VX,
>  
>      /* various PCM "codecs" */
>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
> diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c
> index 9f5f692331..571190bd40 100644
> --- a/libavcodec/h264_cavlc.c
> +++ b/libavcodec/h264_cavlc.c
> @@ -36,6 +36,7 @@
>  #include "golomb.h"
>  #include "mpegutils.h"
>  #include "libavutil/avassert.h"
> +#include "h264_cavlc_data.h"
>  
>  
>  static const uint8_t golomb_to_inter_cbp_gray[16]={
> @@ -86,104 +87,6 @@ static const uint8_t chroma422_dc_coeff_token_bits[4*9]={
>    7,   5,  4, 4,
>  };
>  
> -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 chroma_dc_total_zeros_len[3][4]= {
>      { 1, 2, 3, 3,},
>      { 1, 2, 2, 0,},
> @@ -216,30 +119,6 @@ static const uint8_t chroma422_dc_total_zeros_bits[7][8]= {
>      { 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},
> -};
> -
> -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 chroma_dc_coeff_token_vlc;
>  static VLC_TYPE chroma_dc_coeff_token_vlc_table[256][2];
>  static const int chroma_dc_coeff_token_vlc_table_size = 256;
> @@ -248,10 +127,6 @@ static VLC chroma422_dc_coeff_token_vlc;
>  static VLC_TYPE chroma422_dc_coeff_token_vlc_table[8192][2];
>  static const int chroma422_dc_coeff_token_vlc_table_size = 8192;
>  
> -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 chroma_dc_total_zeros_vlc[3+1];
>  static VLC_TYPE chroma_dc_total_zeros_vlc_tables[3][8][2];
>  static const int chroma_dc_total_zeros_vlc_tables_size = 8;
> @@ -260,25 +135,13 @@ static VLC chroma422_dc_total_zeros_vlc[7+1];
>  static VLC_TYPE chroma422_dc_total_zeros_vlc_tables[7][32][2];
>  static const int chroma422_dc_total_zeros_vlc_tables_size = 32;
>  
> -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 LEVEL_TAB_BITS 8
>  static int8_t cavlc_level_tab[7][1<<LEVEL_TAB_BITS][2];
>  
>  #define CHROMA_DC_COEFF_TOKEN_VLC_BITS 8
>  #define CHROMA422_DC_COEFF_TOKEN_VLC_BITS 13
> -#define COEFF_TOKEN_VLC_BITS           8
> -#define TOTAL_ZEROS_VLC_BITS           9
>  #define CHROMA_DC_TOTAL_ZEROS_VLC_BITS 3
>  #define CHROMA422_DC_TOTAL_ZEROS_VLC_BITS 5
> -#define RUN_VLC_BITS                   3
> -#define RUN7_VLC_BITS                  6
>  
>  /**
>   * Get the predicted number of non-zero coefficients.
> @@ -326,7 +189,7 @@ static av_cold void init_cavlc_level_tab(void){
>  
>  av_cold void ff_h264_decode_init_vlc(void)
>  {
> -    int offset;
> +    ff_h264_cavlc_data_init_vlc();
>  
>      chroma_dc_coeff_token_vlc.table = chroma_dc_coeff_token_vlc_table;
>      chroma_dc_coeff_token_vlc.table_allocated = chroma_dc_coeff_token_vlc_table_size;
> @@ -342,23 +205,6 @@ av_cold void ff_h264_decode_init_vlc(void)
>               &chroma422_dc_coeff_token_bits[0], 1, 1,
>               INIT_VLC_USE_NEW_STATIC);
>  
> -    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 < 3; i++) {
>          chroma_dc_total_zeros_vlc[i + 1].table = chroma_dc_total_zeros_vlc_tables[i];
>          chroma_dc_total_zeros_vlc[i + 1].table_allocated = chroma_dc_total_zeros_vlc_tables_size;
> @@ -379,32 +225,6 @@ av_cold void ff_h264_decode_init_vlc(void)
>                   INIT_VLC_USE_NEW_STATIC);
>      }
>  
> -    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);
> -
>      init_cavlc_level_tab();
>  }
>  
> @@ -436,7 +256,6 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>                             const uint8_t *scantable, const uint32_t *qmul,
>                             int max_coeff)
>  {
> -    static const int coeff_token_table_index[17]= {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3};
>      int level[16];
>      int zeros_left, coeff_token, total_coeff, i, trailing_ones, run_before;
>  
> @@ -451,11 +270,13 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>      }else{
>          if(n >= LUMA_DC_BLOCK_INDEX){
>              total_coeff= pred_non_zero_count(h, sl, (n - LUMA_DC_BLOCK_INDEX)*16);
> -            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);
> +            coeff_token= get_vlc2(gb, 

You wasted an opportunity to add a space before '=' (this code is old
and does not match the currently preferred style).

ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[total_coeff]].table,
> +                                  FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 2);
>              total_coeff= coeff_token>>2;
>          }else{
>              total_coeff= pred_non_zero_count(h, sl, n);
> -            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);
> +            coeff_token= get_vlc2(gb, ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[total_coeff]].table,
> +                                  FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 2);
>              total_coeff= coeff_token>>2;
>          }
>      }
> @@ -529,7 +350,6 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>  
>          //remaining coefficients have suffix_length > 0
>          for(i=trailing_ones+1;i<total_coeff;i++) {
> -            static const unsigned int suffix_limit[7] = {0,3,6,12,24,48,INT_MAX };
>              int bitsi= show_bits(gb, LEVEL_TAB_BITS);
>              level_code= cavlc_level_tab[suffix_length][bitsi][0];
>  
> @@ -556,7 +376,7 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>                  level_code= (((2+level_code)>>1) ^ mask) - mask;
>              }
>              level[i]= level_code;
> -            suffix_length+= suffix_limit[suffix_length] + level_code > 2U*suffix_limit[suffix_length];
> +            suffix_length+= ff_h264_cavlc_suffix_limit[suffix_length] + level_code > 2U*ff_h264_cavlc_suffix_limit[suffix_length];
>          }
>      }
>  
> @@ -571,7 +391,8 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>                  zeros_left = get_vlc2(gb, chroma422_dc_total_zeros_vlc[total_coeff].table,
>                                        CHROMA422_DC_TOTAL_ZEROS_VLC_BITS, 1);
>          } else {
> -            zeros_left= get_vlc2(gb, total_zeros_vlc[ total_coeff ].table, TOTAL_ZEROS_VLC_BITS, 1);
> +            zeros_left= get_vlc2(gb, ff_h264_cavlc_total_zeros_vlc[total_coeff].table,
> +                                 FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS, 1);
>          }
>      }
>  
> @@ -581,9 +402,9 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>          ((type*)block)[*scantable] = level[0]; \
>          for(i=1;i<total_coeff && zeros_left > 0;i++) { \
>              if(zeros_left < 7) \
> -                run_before= get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1); \
> +                run_before= get_vlc2(gb, ff_h264_cavlc_run_vlc[zeros_left].table, FF_H264_CAVLC_RUN_VLC_BITS, 1); \
>              else \
> -                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
> +                run_before= get_vlc2(gb, ff_h264_cavlc_run7_vlc.table, FF_H264_CAVLC_RUN7_VLC_BITS, 2); \
>              zeros_left -= run_before; \
>              scantable -= 1 + run_before; \
>              ((type*)block)[*scantable]= level[i]; \
> @@ -596,9 +417,9 @@ static int decode_residual(const H264Context *h, H264SliceContext *sl,
>          ((type*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32))>>6; \
>          for(i=1;i<total_coeff && zeros_left > 0;i++) { \
>              if(zeros_left < 7) \
> -                run_before= get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1); \
> +                run_before= get_vlc2(gb, ff_h264_cavlc_run_vlc[zeros_left].table, FF_H264_CAVLC_RUN_VLC_BITS, 1); \
>              else \
> -                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
> +                run_before= get_vlc2(gb, ff_h264_cavlc_run7_vlc.table, FF_H264_CAVLC_RUN7_VLC_BITS, 2); \
>              zeros_left -= run_before; \
>              scantable -= 1 + run_before; \
>              ((type*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6; \
> diff --git a/libavcodec/h264_cavlc_data.c b/libavcodec/h264_cavlc_data.c
> new file mode 100644
> index 0000000000..0ab8d917e2
> --- /dev/null
> +++ b/libavcodec/h264_cavlc_data.c
> @@ -0,0 +1,220 @@
> +/*
> + * H.264 cavlc tables
> + * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
> + *
> + * 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 "internal.h"
> +#include "libavutil/thread.h"
> +#include "libavutil/avassert.h"
> +#include "h264_cavlc_data.h"
> +
> +const uint8_t ff_h264_cavlc_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,
> +}
> +};
> +
> +const uint8_t ff_h264_cavlc_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,
> +}
> +};
> +
> +const uint8_t ff_h264_cavlc_coeff_token_table_index[17] = {
> +    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3
> +};
> +
> +const uint8_t ff_h264_cavlc_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},
> +};
> +
> +const uint8_t ff_h264_cavlc_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},
> +};
> +
> +const uint8_t ff_h264_cavlc_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},
> +};
> +
> +const uint8_t ff_h264_cavlc_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},
> +};
> +
> +const unsigned int ff_h264_cavlc_suffix_limit[7] = {
> +    0, 3, 6, 12, 24, 48, INT_MAX
> +};
> +
> +VLC ff_h264_cavlc_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};
> +
> +VLC ff_h264_cavlc_total_zeros_vlc[15+1];
> +static VLC_TYPE total_zeros_vlc_tables[15][512][2];
> +static const int total_zeros_vlc_tables_size = 512;
> +
> +VLC ff_h264_cavlc_run_vlc[6+1];
> +static VLC_TYPE run_vlc_tables[6][8][2];
> +static const int run_vlc_tables_size = 8;
> +
> +VLC ff_h264_cavlc_run7_vlc;
> +static VLC_TYPE run7_vlc_table[96][2];
> +static const int run7_vlc_table_size = 96;
> +
> +static av_cold void cavlc_init_vlc(void)
> +{
> +    int offset = 0;
> +    for (int i = 0; i < 4; i++) {
> +        ff_h264_cavlc_coeff_token_vlc[i].table = coeff_token_vlc_tables + offset;
> +        ff_h264_cavlc_coeff_token_vlc[i].table_allocated = coeff_token_vlc_tables_size[i];
> +        init_vlc(&ff_h264_cavlc_coeff_token_vlc[i], FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 4 * 17,
> +                 &ff_h264_cavlc_coeff_token_len [i][0], 1, 1,
> +                 &ff_h264_cavlc_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++) {
> +        ff_h264_cavlc_total_zeros_vlc[i + 1].table = total_zeros_vlc_tables[i];
> +        ff_h264_cavlc_total_zeros_vlc[i + 1].table_allocated = total_zeros_vlc_tables_size;
> +        init_vlc(&ff_h264_cavlc_total_zeros_vlc[i + 1],
> +                 FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS, 16,
> +                 &ff_h264_cavlc_total_zeros_len [i][0], 1, 1,
> +                 &ff_h264_cavlc_total_zeros_bits[i][0], 1, 1,
> +                 INIT_VLC_USE_NEW_STATIC);
> +    }
> +
> +    for (int i = 0; i < 6; i++) {
> +        ff_h264_cavlc_run_vlc[i + 1].table = run_vlc_tables[i];
> +        ff_h264_cavlc_run_vlc[i + 1].table_allocated = run_vlc_tables_size;
> +        init_vlc(&ff_h264_cavlc_run_vlc[i + 1],
> +                 FF_H264_CAVLC_RUN_VLC_BITS, 7,
> +                 &ff_h264_cavlc_run_len [i][0], 1, 1,
> +                 &ff_h264_cavlc_run_bits[i][0], 1, 1,
> +                 INIT_VLC_USE_NEW_STATIC);
> +    }
> +
> +    ff_h264_cavlc_run7_vlc.table = run7_vlc_table,
> +    ff_h264_cavlc_run7_vlc.table_allocated = run7_vlc_table_size;
> +    init_vlc(&ff_h264_cavlc_run7_vlc, FF_H264_CAVLC_RUN7_VLC_BITS, 16,
> +             &ff_h264_cavlc_run_len [6][0], 1, 1,
> +             &ff_h264_cavlc_run_bits[6][0], 1, 1,
> +             INIT_VLC_USE_NEW_STATIC);
> +}
> +
> +int ff_h264_cavlc_data_init_vlc(void)
> +{
> +    static AVOnce vlc_init = AV_ONCE_INIT;
> +    return ff_thread_once(&vlc_init, cavlc_init_vlc);

In case the actimagine_vx decoder is disabled and only the H.264 decoder
is enabled (I expect this to happen for lots of slim builds), one does
not need to use an ff_thread_once() here at all, because
ff_h264_decode_init_vlc is already guarded this way. Can you add
compile-time checks for this?

> +}
> \ No newline at end of file
> diff --git a/libavcodec/h264_cavlc_data.h b/libavcodec/h264_cavlc_data.h
> new file mode 100644
> index 0000000000..9e8555a1e6
> --- /dev/null
> +++ b/libavcodec/h264_cavlc_data.h
> @@ -0,0 +1,50 @@
> +/*
> + * 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
> + */
> +
> +#ifndef AVCODEC_H264_CAVLC_DATA_H
> +#define AVCODEC_H264_CAVLC_DATA_H
> +
> +#include <stdint.h>
> +#include "vlc.h"
> +
> +#define FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS    8
> +#define FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS    9
> +#define FF_H264_CAVLC_RUN_VLC_BITS            3
> +#define FF_H264_CAVLC_RUN7_VLC_BITS           6
> +
> +extern const uint8_t ff_h264_cavlc_coeff_token_len[4][4*17];
> +extern const uint8_t ff_h264_cavlc_coeff_token_bits[4][4*17];
> +
> +extern const uint8_t ff_h264_cavlc_coeff_token_table_index[17];
> +
> +extern const uint8_t ff_h264_cavlc_total_zeros_len[16][16];
> +extern const uint8_t ff_h264_cavlc_total_zeros_bits[16][16];
> +
> +extern const uint8_t ff_h264_cavlc_run_len[7][16];
> +extern const uint8_t ff_h264_cavlc_run_bits[7][16];
> +

Several of these tables are only used to initialize the VLCs and can
therefore be made internal to h264_cavlc_data.c.

> +extern const unsigned int ff_h264_cavlc_suffix_limit[7];
> +
> +extern VLC ff_h264_cavlc_coeff_token_vlc[4];
> +extern VLC ff_h264_cavlc_total_zeros_vlc[15+1];
> +extern VLC ff_h264_cavlc_run_vlc[6+1];
> +extern VLC ff_h264_cavlc_run7_vlc;
> +
> +int ff_h264_cavlc_data_init_vlc(void);
> +
> +#endif /* AVCODEC_H264_CAVLC_DATA_H */
> diff --git a/libavcodec/version.h b/libavcodec/version.h
> index 662caebc49..cfdde46960 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 133
> +#define LIBAVCODEC_VERSION_MINOR 134
>  #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..848b1d6cfd 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_VX,MKTAG('V', 'X', 'S', '1') },
> +    { AV_CODEC_ID_ACTIMAGINE_VX,MKTAG('v', 'x', 's', '1') },
>      { AV_CODEC_ID_NONE,         0 }
>  };
>  
>
Zane van Iperen March 18, 2021, 2:10 p.m. UTC | #2
On 18/3/21 8:31 pm, Florian Nouwt wrote:
> diff --git a/libavformat/riff.c b/libavformat/riff.c
> index 270ff7c024..848b1d6cfd 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_VX,MKTAG('V', 'X', 'S', '1') },
> +    { AV_CODEC_ID_ACTIMAGINE_VX,MKTAG('v', 'x', 's', '1') },
>       { AV_CODEC_ID_NONE,         0 }
>   };
>   
> 

Minor nit: Since this touches libavformat as well, it should probably be in a separate commit.
Florian Nouwt March 18, 2021, 2:22 p.m. UTC | #3
Andreas Rheinhardt:

- Why are these tables not internal to actimagine_vx.c?

I separated the data because for parsing the vx container files I will
need a parser, which will be in a separate file from the decoder and
requires those tables.

- You wasted an opportunity to add a space before '=' (this code is
old and does not match the currently preferred style).

Just to have it clear, when it comes to the tables, is the preferred
style with the brace on the next line or on the same line? And am I
supposed to fix all style errors in that file?

- In case the actimagine_vx decoder is disabled and only the H.264
decoder is enabled (I expect this to happen for lots of slim builds),
one does not need to use an ff_thread_once() here at all, because
ff_h264_decode_init_vlc is already guarded this way. Can you add
compile-time checks for this?

It would remove some safety ofc. But I guess I can put a comment in
the header file that tells any potential future people that might use
it to not forget to change it.

Zane van Iperen:
Should I submit that as a separate patch then after the current one
minus that change has been accepted? Without that change it's
impossible to test the decoder.
Andreas Rheinhardt March 18, 2021, 2:34 p.m. UTC | #4
Florian Nouwt:
> Andreas Rheinhardt:
> 
> - Why are these tables not internal to actimagine_vx.c?
> 
> I separated the data because for parsing the vx container files I will
> need a parser, which will be in a separate file from the decoder and
> requires those tables.
> 
> - You wasted an opportunity to add a space before '=' (this code is
> old and does not match the currently preferred style).
> 
> Just to have it clear, when it comes to the tables, is the preferred
> style with the brace on the next line or on the same line? And am I
> supposed to fix all style errors in that file?

I don't have a preference for next line vs same line, but I don't like
something like
}
};
as happens in ff_h264_cavlc_coeff_token_*.
When you change a line, you should fix style issues in said line at the
same time. You are not supposed to touch other lines just to fix style
issues. Such things should be in a separate commit, if at all (after
all, they make using git blame harder).

> 
> - In case the actimagine_vx decoder is disabled and only the H.264
> decoder is enabled (I expect this to happen for lots of slim builds),
> one does not need to use an ff_thread_once() here at all, because
> ff_h264_decode_init_vlc is already guarded this way. Can you add
> compile-time checks for this?
> 
> It would remove some safety ofc. But I guess I can put a comment in
> the header file that tells any potential future people that might use
> it to not forget to change it.
> 

Fine.

- Andreas
diff mbox series

Patch

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..c38066bc1c 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_vx_decoder_select="bswapdsp golomb h264dsp h264pred"
 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).
+@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..0bdeb9fc26 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_VX_DECODER)   += actimagine_vx.o actimagine_vx_data.o h264_cavlc_data.o
 OBJS-$(CONFIG_AGM_DECODER)             += agm.o
 OBJS-$(CONFIG_AIC_DECODER)             += aic.o
 OBJS-$(CONFIG_ALAC_DECODER)            += alac.o alac_data.o alacdsp.o
@@ -367,7 +368,7 @@  OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264_cabac.o h264_cavlc.o \
                                           h264_direct.o h264_loopfilter.o  \
                                           h264_mb.o h264_picture.o \
                                           h264_refs.o h264_sei.o \
-                                          h264_slice.o h264data.o
+                                          h264_slice.o h264data.o h264_cavlc_data.o
 OBJS-$(CONFIG_H264_AMF_ENCODER)        += amfenc_h264.o
 OBJS-$(CONFIG_H264_CUVID_DECODER)      += cuviddec.o
 OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o
diff --git a/libavcodec/actimagine_vx.c b/libavcodec/actimagine_vx.c
new file mode 100644
index 0000000000..84871a1008
--- /dev/null
+++ b/libavcodec/actimagine_vx.c
@@ -0,0 +1,1150 @@ 
+/*
+ * 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 "avcodec.h"
+#include "bytestream.h"
+#include "bswapdsp.h"
+#include "get_bits.h"
+#include "golomb.h"
+#include "internal.h"
+#include "libavutil/mem_internal.h"
+#include "h264_cavlc_data.h"
+#include "h264dsp.h"
+#include "h264pred.h"
+#include "actimagine_vx_data.h"
+
+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 }
+};
+
+typedef struct MVec {
+    int x, y;
+} MVec;
+
+typedef struct VxContext {
+    AVFrame *out_frame;
+    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;
+
+    uint8_t zigzag_scan[16];
+
+    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;
+    H264DSPContext  h264dsp;
+    H264PredContext h264pred;
+} VxContext;
+
+#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 VX_VERSION_INVALID  -1
+#define VX_VERSION_OLD       0
+#define VX_VERSION_NEW       1
+
+static int setup_qtables(AVCodecContext *avctx, int quantizer)
+{
+    int qx, qy;
+    VxContext *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 vx_init(AVCodecContext *avctx)
+{
+    int vectors_size;
+    int total_coeff_y_size;
+    int total_coeff_uv_size;
+    VxContext *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);
+    ff_h264dsp_init(&s->h264dsp, 8, 1);
+    ff_h264_pred_init(&s->h264pred, AV_CODEC_ID_ACTIMAGINE_VX, 8, 1);
+
+    avctx->pix_fmt = AV_PIX_FMT_YUV420P;
+    avctx->color_range = AVCOL_RANGE_JPEG;
+    avctx->chroma_sample_location = AVCHROMA_LOC_CENTER;
+    avctx->colorspace = AVCOL_SPC_SMPTE170M;
+
+    // zigzag_scan is a transposed version of ff_zigzag_scan, like in h264
+    for (int i = 0; i < 16; i++)
+        s->zigzag_scan[i] = (ff_zigzag_scan[i] >> 2) | ((ff_zigzag_scan[i] << 2) & 0xF);
+
+    // 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);
+
+    // 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_mallocz(total_coeff_y_size);
+    if (!s->total_coeff_y)
+        return AVERROR(ENOMEM);
+
+    // 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_mallocz(total_coeff_uv_size);
+    if (!s->total_coeff_uv)
+        return AVERROR(ENOMEM);
+
+    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->out_frame = av_frame_alloc();
+    if (!s->out_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_h264_cavlc_data_init_vlc();
+
+    return 0;
+}
+
+static void clear_total_coeff(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+    VxContext *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)
+{
+    VxContext *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)
+{
+    VxContext *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)
+{
+    VxContext *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)
+{
+    VxContext *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)
+{
+    VxContext *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)
+{
+    static const uint8_t shift_tab[] = { 1, 2, 3, 0, 4 };
+    uint8_t dc;
+    VxContext *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 >>= 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 >>= 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 >> 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 >> 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)
+{
+    VxContext *s = avctx->priv_data;
+    GetBitContext *gb = &s->gb;
+    switch (get_ue_golomb_31(gb)) {
+    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)
+{
+    VxContext *s = avctx->priv_data;
+    GetBitContext *gb = &s->gb;
+    switch (get_ue_golomb_31(gb)) {
+    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);
+}
+
+static int predict4(AVCodecContext *avctx, int x, int y, int w, int h)
+{
+    VxContext *s = avctx->priv_data;
+    GetBitContext *gb = &s->gb;
+    int stride = s->cur_frame->linesize[0];
+    for (int y2 = 0; y2 < h >> 2; y2++) {
+        for (int x2 = 0; x2 < w >> 2; x2++) {
+            uint8_t *dst, *top_right;
+            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);
+                mode = val + (val >= mode);
+            }
+
+            s->pred4_cache[1 + y2][1 + x2] = mode;
+
+            dst = &PIXEL_CUR(s, 0, x + x2 * 4, y + y2 * 4);
+            top_right = &PIXEL_CUR(s, 0, x + x2 * 4 + 4, y + y2 * 4 - 1);
+
+            switch (mode) {
+            case 0:// vertical
+                s->h264pred.pred4x4[VERT_PRED](dst, NULL, stride);
+                break;
+            case 1:// horizontal
+                s->h264pred.pred4x4[HOR_PRED](dst, NULL, stride);
+                break;
+            case 2:// dc
+                if (x + x2 * 4 == 0 && y + y2 * 4 == 0)
+                    s->h264pred.pred4x4[DC_128_PRED](dst, NULL, stride);
+                else if (x + x2 * 4 == 0 && y + y2 * 4 != 0)
+                    s->h264pred.pred4x4[TOP_DC_PRED](dst, NULL, stride);
+                else if (x + x2 * 4 != 0 && y + y2 * 4 == 0)
+                    s->h264pred.pred4x4[LEFT_DC_PRED](dst, NULL, stride);
+                else
+                    s->h264pred.pred4x4[DC_PRED](dst, NULL, stride);
+                break;
+            case 3:// diagonal-down-left
+                s->h264pred.pred4x4[DIAG_DOWN_LEFT_PRED](dst, top_right, stride);
+                break;
+            case 4:// diagonal-down-right
+                s->h264pred.pred4x4[DIAG_DOWN_RIGHT_PRED](dst, NULL, stride);
+                break;
+            case 5:// vertical-right
+                s->h264pred.pred4x4[VERT_RIGHT_PRED](dst, NULL, stride);
+                break;
+            case 6:// horizontal-down
+                s->h264pred.pred4x4[HOR_DOWN_PRED](dst, NULL, stride);
+                break;
+            case 7:// vertical-left
+                s->h264pred.pred4x4[VERT_LEFT_PRED](dst, top_right, stride);
+                break;
+            case 8:// horizontal-up
+                s->h264pred.pred4x4[HOR_UP_PRED](dst, NULL, stride);
+                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)
+{
+    LOCAL_ALIGNED_16(int16_t, dct, [16]);
+    VxContext *s = avctx->priv_data;
+
+    // dezigzag
+    for (int i = 0; i < 16; i++)
+        dct[s->zigzag_scan[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];
+        }
+    }
+
+    s->h264dsp.h264_idct_add(&PIXEL_CUR(s, plane, x, y), dct,
+                             s->cur_frame->linesize[plane]);
+}
+
+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;
+    VxContext *s = avctx->priv_data;
+    GetBitContext *gb = &s->gb;
+
+    coeff_token = get_vlc2(gb, ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[nc]].table,
+                           FF_H264_CAVLC_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, ff_h264_cavlc_total_zeros_vlc[total_coeff].table,
+                              FF_H264_CAVLC_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) + 1;
+
+            suffix_length += level_code > ff_h264_cavlc_suffix_limit[suffix_length + 1];
+
+            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, ff_h264_cavlc_run_vlc[zeros_left].table,
+                                  FF_H264_CAVLC_RUN_VLC_BITS, 1);
+        else
+            run_before = get_vlc2(gb, ff_h264_cavlc_run7_vlc.table,
+                                  FF_H264_CAVLC_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)
+{
+    VxContext *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;
+            unsigned 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 = ff_actimagine_vx_residu_mask_old_tab[code];
+            else
+                residu_mask = ff_actimagine_vx_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)
+{
+    VxContext *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;
+    VxContext *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++) {
+            // u
+            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);
+            // v
+            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)
+{
+    VxContext *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 = ff_actimagine_vx_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
+    VxContext *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 convert_colorspace(AVCodecContext *avctx)
+{
+    int ret;
+    VxContext *s = avctx->priv_data;
+    if ((ret = ff_reget_buffer(avctx, s->out_frame, 0)) < 0)
+        return ret;
+    
+    // the color space is not supported by ffmpeg
+    // r = y + 2v
+    // g = y - 0.5u - v
+    // b = y + 2u
+    // convert to the SMPTE170M format
+
+    for (int y = 0; y < avctx->height; y++) {
+        for (int x = 0; x < avctx->width; x++) {
+            s->out_frame->data[0][y * s->out_frame->linesize[0] + x]
+                = av_clip_uint8(PIXEL_CUR(s, 0, x, y) + ((
+                    (PIXEL_CUR(s, 1, x >> 1, y >> 1) - 128) * -68682 +
+                    (PIXEL_CUR(s, 2, x >> 1, y >> 1) - 128) * 11534 +                    
+                    (1 << 19)) >> 20));
+        }
+    }
+
+    for (int y = 0; y < avctx->height >> 1; y++) {
+        for (int x = 0; x < avctx->width >> 1; x++) {
+            s->out_frame->data[1][y * s->out_frame->linesize[1] + x]
+                = av_clip_uint8(128 + ((
+                    (PIXEL_CUR(s, 1, x, y) - 128) * 1222325 +
+                    (PIXEL_CUR(s, 2, x, y) - 128) * -4928) >> 20));
+            s->out_frame->data[2][y * s->out_frame->linesize[2] + x]
+                = av_clip_uint8(128 + ((
+                    (PIXEL_CUR(s, 1, x, y) - 128) * 49073 +
+                    (PIXEL_CUR(s, 2, x, y) - 128) * 1487615) >> 20));
+        }
+    }
+
+    return 0;
+}
+
+static int vx_decode(AVCodecContext *avctx, void *data, int *got_frame,
+                     AVPacket *pkt)
+{
+    MVec *vectors;
+    int ret;
+    VxContext *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;
+
+    // initially we assume this is an i frame
+    // this is corrected when a p block is found
+    frame->pict_type = AV_PICTURE_TYPE_I;
+    frame->key_frame = 1;
+
+    if (s->quantizer == -1) {
+        av_log(avctx, AV_LOG_ERROR, "no quantizer configured\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 ((ret = convert_colorspace(avctx)) < 0)
+        return ret;
+
+    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, s->out_frame)) < 0)
+        return ret;
+
+    *got_frame = 1;
+
+    return 0;
+}
+
+static void vx_flush(AVCodecContext *avctx)
+{
+    VxContext *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 vx_close(AVCodecContext *avctx)
+{
+    VxContext *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);
+    av_frame_free(&s->out_frame);
+
+    return 0;
+}
+
+AVCodec ff_actimagine_vx_decoder = {
+    .name           = "actimagine_vx",
+    .long_name      = NULL_IF_CONFIG_SMALL("Actimagine VX Video"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_ACTIMAGINE_VX,
+    .priv_data_size = sizeof(VxContext),
+    .init           = vx_init,
+    .decode         = vx_decode,
+    .flush          = vx_flush,
+    .close          = vx_close,
+    .capabilities   = AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/actimagine_vx_data.c b/libavcodec/actimagine_vx_data.c
new file mode 100644
index 0000000000..b557dd35a5
--- /dev/null
+++ b/libavcodec/actimagine_vx_data.c
@@ -0,0 +1,45 @@ 
+/*
+ * Actimagine VX Video tables
+ * 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 "actimagine_vx_data.h"
+
+const uint8_t ff_actimagine_vx_old_mb_mode_remap_tab[24] =
+{
+     1,  2,  0,  4,  7,  3, 11, 15,  9,  5, 14,  6,
+    12, 13,  8, 16, 23, 10, 22, 19, 20, 17, 21, 18
+};
+
+const uint8_t ff_actimagine_vx_residu_mask_old_tab[32] =
+{
+    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
+};
+
+const uint8_t ff_actimagine_vx_residu_mask_new_tab[32] =
+{
+    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
+};
diff --git a/libavcodec/actimagine_vx_data.h b/libavcodec/actimagine_vx_data.h
new file mode 100644
index 0000000000..46a715ca71
--- /dev/null
+++ b/libavcodec/actimagine_vx_data.h
@@ -0,0 +1,28 @@ 
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_ACTIMAGINE_VX_DATA_H
+#define AVCODEC_ACTIMAGINE_VX_DATA_H
+
+#include <stdint.h>
+
+extern const uint8_t ff_actimagine_vx_old_mb_mode_remap_tab[24];
+extern const uint8_t ff_actimagine_vx_residu_mask_old_tab[32];
+extern const uint8_t ff_actimagine_vx_residu_mask_new_tab[32];
+
+#endif /* AVCODEC_ACTIMAGINE_VX_DATA_H */
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 2e9a3581de..9762521b11 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_vx_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..281da17942 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_VX,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "actimagine_vx",
+        .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..172b96ef27 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_VX,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c
index 9f5f692331..571190bd40 100644
--- a/libavcodec/h264_cavlc.c
+++ b/libavcodec/h264_cavlc.c
@@ -36,6 +36,7 @@ 
 #include "golomb.h"
 #include "mpegutils.h"
 #include "libavutil/avassert.h"
+#include "h264_cavlc_data.h"
 
 
 static const uint8_t golomb_to_inter_cbp_gray[16]={
@@ -86,104 +87,6 @@  static const uint8_t chroma422_dc_coeff_token_bits[4*9]={
   7,   5,  4, 4,
 };
 
-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 chroma_dc_total_zeros_len[3][4]= {
     { 1, 2, 3, 3,},
     { 1, 2, 2, 0,},
@@ -216,30 +119,6 @@  static const uint8_t chroma422_dc_total_zeros_bits[7][8]= {
     { 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},
-};
-
-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 chroma_dc_coeff_token_vlc;
 static VLC_TYPE chroma_dc_coeff_token_vlc_table[256][2];
 static const int chroma_dc_coeff_token_vlc_table_size = 256;
@@ -248,10 +127,6 @@  static VLC chroma422_dc_coeff_token_vlc;
 static VLC_TYPE chroma422_dc_coeff_token_vlc_table[8192][2];
 static const int chroma422_dc_coeff_token_vlc_table_size = 8192;
 
-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 chroma_dc_total_zeros_vlc[3+1];
 static VLC_TYPE chroma_dc_total_zeros_vlc_tables[3][8][2];
 static const int chroma_dc_total_zeros_vlc_tables_size = 8;
@@ -260,25 +135,13 @@  static VLC chroma422_dc_total_zeros_vlc[7+1];
 static VLC_TYPE chroma422_dc_total_zeros_vlc_tables[7][32][2];
 static const int chroma422_dc_total_zeros_vlc_tables_size = 32;
 
-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 LEVEL_TAB_BITS 8
 static int8_t cavlc_level_tab[7][1<<LEVEL_TAB_BITS][2];
 
 #define CHROMA_DC_COEFF_TOKEN_VLC_BITS 8
 #define CHROMA422_DC_COEFF_TOKEN_VLC_BITS 13
-#define COEFF_TOKEN_VLC_BITS           8
-#define TOTAL_ZEROS_VLC_BITS           9
 #define CHROMA_DC_TOTAL_ZEROS_VLC_BITS 3
 #define CHROMA422_DC_TOTAL_ZEROS_VLC_BITS 5
-#define RUN_VLC_BITS                   3
-#define RUN7_VLC_BITS                  6
 
 /**
  * Get the predicted number of non-zero coefficients.
@@ -326,7 +189,7 @@  static av_cold void init_cavlc_level_tab(void){
 
 av_cold void ff_h264_decode_init_vlc(void)
 {
-    int offset;
+    ff_h264_cavlc_data_init_vlc();
 
     chroma_dc_coeff_token_vlc.table = chroma_dc_coeff_token_vlc_table;
     chroma_dc_coeff_token_vlc.table_allocated = chroma_dc_coeff_token_vlc_table_size;
@@ -342,23 +205,6 @@  av_cold void ff_h264_decode_init_vlc(void)
              &chroma422_dc_coeff_token_bits[0], 1, 1,
              INIT_VLC_USE_NEW_STATIC);
 
-    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 < 3; i++) {
         chroma_dc_total_zeros_vlc[i + 1].table = chroma_dc_total_zeros_vlc_tables[i];
         chroma_dc_total_zeros_vlc[i + 1].table_allocated = chroma_dc_total_zeros_vlc_tables_size;
@@ -379,32 +225,6 @@  av_cold void ff_h264_decode_init_vlc(void)
                  INIT_VLC_USE_NEW_STATIC);
     }
 
-    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);
-
     init_cavlc_level_tab();
 }
 
@@ -436,7 +256,6 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
                            const uint8_t *scantable, const uint32_t *qmul,
                            int max_coeff)
 {
-    static const int coeff_token_table_index[17]= {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3};
     int level[16];
     int zeros_left, coeff_token, total_coeff, i, trailing_ones, run_before;
 
@@ -451,11 +270,13 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
     }else{
         if(n >= LUMA_DC_BLOCK_INDEX){
             total_coeff= pred_non_zero_count(h, sl, (n - LUMA_DC_BLOCK_INDEX)*16);
-            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);
+            coeff_token= get_vlc2(gb, ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[total_coeff]].table,
+                                  FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 2);
             total_coeff= coeff_token>>2;
         }else{
             total_coeff= pred_non_zero_count(h, sl, n);
-            coeff_token= get_vlc2(gb, coeff_token_vlc[ coeff_token_table_index[total_coeff] ].table, COEFF_TOKEN_VLC_BITS, 2);
+            coeff_token= get_vlc2(gb, ff_h264_cavlc_coeff_token_vlc[ff_h264_cavlc_coeff_token_table_index[total_coeff]].table,
+                                  FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 2);
             total_coeff= coeff_token>>2;
         }
     }
@@ -529,7 +350,6 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
 
         //remaining coefficients have suffix_length > 0
         for(i=trailing_ones+1;i<total_coeff;i++) {
-            static const unsigned int suffix_limit[7] = {0,3,6,12,24,48,INT_MAX };
             int bitsi= show_bits(gb, LEVEL_TAB_BITS);
             level_code= cavlc_level_tab[suffix_length][bitsi][0];
 
@@ -556,7 +376,7 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
                 level_code= (((2+level_code)>>1) ^ mask) - mask;
             }
             level[i]= level_code;
-            suffix_length+= suffix_limit[suffix_length] + level_code > 2U*suffix_limit[suffix_length];
+            suffix_length+= ff_h264_cavlc_suffix_limit[suffix_length] + level_code > 2U*ff_h264_cavlc_suffix_limit[suffix_length];
         }
     }
 
@@ -571,7 +391,8 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
                 zeros_left = get_vlc2(gb, chroma422_dc_total_zeros_vlc[total_coeff].table,
                                       CHROMA422_DC_TOTAL_ZEROS_VLC_BITS, 1);
         } else {
-            zeros_left= get_vlc2(gb, total_zeros_vlc[ total_coeff ].table, TOTAL_ZEROS_VLC_BITS, 1);
+            zeros_left= get_vlc2(gb, ff_h264_cavlc_total_zeros_vlc[total_coeff].table,
+                                 FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS, 1);
         }
     }
 
@@ -581,9 +402,9 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
         ((type*)block)[*scantable] = level[0]; \
         for(i=1;i<total_coeff && zeros_left > 0;i++) { \
             if(zeros_left < 7) \
-                run_before= get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1); \
+                run_before= get_vlc2(gb, ff_h264_cavlc_run_vlc[zeros_left].table, FF_H264_CAVLC_RUN_VLC_BITS, 1); \
             else \
-                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
+                run_before= get_vlc2(gb, ff_h264_cavlc_run7_vlc.table, FF_H264_CAVLC_RUN7_VLC_BITS, 2); \
             zeros_left -= run_before; \
             scantable -= 1 + run_before; \
             ((type*)block)[*scantable]= level[i]; \
@@ -596,9 +417,9 @@  static int decode_residual(const H264Context *h, H264SliceContext *sl,
         ((type*)block)[*scantable] = ((int)(level[0] * qmul[*scantable] + 32))>>6; \
         for(i=1;i<total_coeff && zeros_left > 0;i++) { \
             if(zeros_left < 7) \
-                run_before= get_vlc2(gb, run_vlc[zeros_left].table, RUN_VLC_BITS, 1); \
+                run_before= get_vlc2(gb, ff_h264_cavlc_run_vlc[zeros_left].table, FF_H264_CAVLC_RUN_VLC_BITS, 1); \
             else \
-                run_before= get_vlc2(gb, run7_vlc.table, RUN7_VLC_BITS, 2); \
+                run_before= get_vlc2(gb, ff_h264_cavlc_run7_vlc.table, FF_H264_CAVLC_RUN7_VLC_BITS, 2); \
             zeros_left -= run_before; \
             scantable -= 1 + run_before; \
             ((type*)block)[*scantable]= ((int)(level[i] * qmul[*scantable] + 32))>>6; \
diff --git a/libavcodec/h264_cavlc_data.c b/libavcodec/h264_cavlc_data.c
new file mode 100644
index 0000000000..0ab8d917e2
--- /dev/null
+++ b/libavcodec/h264_cavlc_data.c
@@ -0,0 +1,220 @@ 
+/*
+ * H.264 cavlc tables
+ * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
+ *
+ * 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 "internal.h"
+#include "libavutil/thread.h"
+#include "libavutil/avassert.h"
+#include "h264_cavlc_data.h"
+
+const uint8_t ff_h264_cavlc_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,
+}
+};
+
+const uint8_t ff_h264_cavlc_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,
+}
+};
+
+const uint8_t ff_h264_cavlc_coeff_token_table_index[17] = {
+    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3
+};
+
+const uint8_t ff_h264_cavlc_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},
+};
+
+const uint8_t ff_h264_cavlc_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},
+};
+
+const uint8_t ff_h264_cavlc_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},
+};
+
+const uint8_t ff_h264_cavlc_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},
+};
+
+const unsigned int ff_h264_cavlc_suffix_limit[7] = {
+    0, 3, 6, 12, 24, 48, INT_MAX
+};
+
+VLC ff_h264_cavlc_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};
+
+VLC ff_h264_cavlc_total_zeros_vlc[15+1];
+static VLC_TYPE total_zeros_vlc_tables[15][512][2];
+static const int total_zeros_vlc_tables_size = 512;
+
+VLC ff_h264_cavlc_run_vlc[6+1];
+static VLC_TYPE run_vlc_tables[6][8][2];
+static const int run_vlc_tables_size = 8;
+
+VLC ff_h264_cavlc_run7_vlc;
+static VLC_TYPE run7_vlc_table[96][2];
+static const int run7_vlc_table_size = 96;
+
+static av_cold void cavlc_init_vlc(void)
+{
+    int offset = 0;
+    for (int i = 0; i < 4; i++) {
+        ff_h264_cavlc_coeff_token_vlc[i].table = coeff_token_vlc_tables + offset;
+        ff_h264_cavlc_coeff_token_vlc[i].table_allocated = coeff_token_vlc_tables_size[i];
+        init_vlc(&ff_h264_cavlc_coeff_token_vlc[i], FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS, 4 * 17,
+                 &ff_h264_cavlc_coeff_token_len [i][0], 1, 1,
+                 &ff_h264_cavlc_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++) {
+        ff_h264_cavlc_total_zeros_vlc[i + 1].table = total_zeros_vlc_tables[i];
+        ff_h264_cavlc_total_zeros_vlc[i + 1].table_allocated = total_zeros_vlc_tables_size;
+        init_vlc(&ff_h264_cavlc_total_zeros_vlc[i + 1],
+                 FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS, 16,
+                 &ff_h264_cavlc_total_zeros_len [i][0], 1, 1,
+                 &ff_h264_cavlc_total_zeros_bits[i][0], 1, 1,
+                 INIT_VLC_USE_NEW_STATIC);
+    }
+
+    for (int i = 0; i < 6; i++) {
+        ff_h264_cavlc_run_vlc[i + 1].table = run_vlc_tables[i];
+        ff_h264_cavlc_run_vlc[i + 1].table_allocated = run_vlc_tables_size;
+        init_vlc(&ff_h264_cavlc_run_vlc[i + 1],
+                 FF_H264_CAVLC_RUN_VLC_BITS, 7,
+                 &ff_h264_cavlc_run_len [i][0], 1, 1,
+                 &ff_h264_cavlc_run_bits[i][0], 1, 1,
+                 INIT_VLC_USE_NEW_STATIC);
+    }
+
+    ff_h264_cavlc_run7_vlc.table = run7_vlc_table,
+    ff_h264_cavlc_run7_vlc.table_allocated = run7_vlc_table_size;
+    init_vlc(&ff_h264_cavlc_run7_vlc, FF_H264_CAVLC_RUN7_VLC_BITS, 16,
+             &ff_h264_cavlc_run_len [6][0], 1, 1,
+             &ff_h264_cavlc_run_bits[6][0], 1, 1,
+             INIT_VLC_USE_NEW_STATIC);
+}
+
+int ff_h264_cavlc_data_init_vlc(void)
+{
+    static AVOnce vlc_init = AV_ONCE_INIT;
+    return ff_thread_once(&vlc_init, cavlc_init_vlc);
+}
\ No newline at end of file
diff --git a/libavcodec/h264_cavlc_data.h b/libavcodec/h264_cavlc_data.h
new file mode 100644
index 0000000000..9e8555a1e6
--- /dev/null
+++ b/libavcodec/h264_cavlc_data.h
@@ -0,0 +1,50 @@ 
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_H264_CAVLC_DATA_H
+#define AVCODEC_H264_CAVLC_DATA_H
+
+#include <stdint.h>
+#include "vlc.h"
+
+#define FF_H264_CAVLC_COEFF_TOKEN_VLC_BITS    8
+#define FF_H264_CAVLC_TOTAL_ZEROS_VLC_BITS    9
+#define FF_H264_CAVLC_RUN_VLC_BITS            3
+#define FF_H264_CAVLC_RUN7_VLC_BITS           6
+
+extern const uint8_t ff_h264_cavlc_coeff_token_len[4][4*17];
+extern const uint8_t ff_h264_cavlc_coeff_token_bits[4][4*17];
+
+extern const uint8_t ff_h264_cavlc_coeff_token_table_index[17];
+
+extern const uint8_t ff_h264_cavlc_total_zeros_len[16][16];
+extern const uint8_t ff_h264_cavlc_total_zeros_bits[16][16];
+
+extern const uint8_t ff_h264_cavlc_run_len[7][16];
+extern const uint8_t ff_h264_cavlc_run_bits[7][16];
+
+extern const unsigned int ff_h264_cavlc_suffix_limit[7];
+
+extern VLC ff_h264_cavlc_coeff_token_vlc[4];
+extern VLC ff_h264_cavlc_total_zeros_vlc[15+1];
+extern VLC ff_h264_cavlc_run_vlc[6+1];
+extern VLC ff_h264_cavlc_run7_vlc;
+
+int ff_h264_cavlc_data_init_vlc(void);
+
+#endif /* AVCODEC_H264_CAVLC_DATA_H */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 662caebc49..cfdde46960 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 133
+#define LIBAVCODEC_VERSION_MINOR 134
 #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..848b1d6cfd 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_VX,MKTAG('V', 'X', 'S', '1') },
+    { AV_CODEC_ID_ACTIMAGINE_VX,MKTAG('v', 'x', 's', '1') },
     { AV_CODEC_ID_NONE,         0 }
 };