[FFmpeg-devel] [PATCH v4] avcodec: add Actimagine VX video decoder
Florian Nouwt
fnouwt2 at gmail.com
Fri Mar 19 10:49:47 EET 2021
Signed-off-by: Florian Nouwt <fnouwt2 at gmail.com>
---
* fixed style issues
* ff_h264_cavlc_data_init_vlc now only uses ff_thread_once if the vx decoder is enabled
* made tables static which are not used outside h264_cavlc_data.c
---
Changelog | 1 +
configure | 1 +
doc/general_contents.texi | 2 +
libavcodec/Makefile | 3 +-
libavcodec/actimagine_vx_data.c | 42 ++
libavcodec/actimagine_vx_data.h | 28 +
libavcodec/actimagine_vxdec.c | 1149 +++++++++++++++++++++++++++++++
libavcodec/allcodecs.c | 1 +
libavcodec/codec_desc.c | 7 +
libavcodec/codec_id.h | 1 +
libavcodec/h264_cavlc.c | 205 +-----
libavcodec/h264_cavlc_data.c | 231 +++++++
libavcodec/h264_cavlc_data.h | 43 ++
libavcodec/version.h | 2 +-
libavformat/riff.c | 2 +
15 files changed, 1524 insertions(+), 194 deletions(-)
create mode 100644 libavcodec/actimagine_vx_data.c
create mode 100644 libavcodec/actimagine_vx_data.h
create mode 100644 libavcodec/actimagine_vxdec.c
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).
+ at item Actimagine VX Video @tab @tab X
+ @tab fourcc: vxs1, VXS1
@item Amazing Studio PAF Video @tab @tab X
@item American Laser Games MM @tab @tab X
@tab Used in games like Mad Dog McCree.
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 81cc16471b..1adae43b40 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_vxdec.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_data.c b/libavcodec/actimagine_vx_data.c
new file mode 100644
index 0000000000..64144de4a6
--- /dev/null
+++ b/libavcodec/actimagine_vx_data.c
@@ -0,0 +1,42 @@
+/*
+ * 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/actimagine_vxdec.c b/libavcodec/actimagine_vxdec.c
new file mode 100644
index 0000000000..5a527a66dd
--- /dev/null
+++ b/libavcodec/actimagine_vxdec.c
@@ -0,0 +1,1149 @@
+/*
+ * 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/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..5b74c81379 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..0f2e95ae4c
--- /dev/null
+++ b/libavcodec/h264_cavlc_data.c
@@ -0,0 +1,231 @@
+/*
+ * H.264 cavlc tables
+ * Copyright (c) 2003 Michael Niedermayer <michaelni at 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"
+
+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,
+ }
+};
+
+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
+};
+
+static const uint8_t total_zeros_len[16][16] = {
+ {1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},
+ {3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},
+ {4,3,3,3,4,4,3,3,4,5,5,6,5,6},
+ {5,3,4,4,3,3,3,4,3,4,5,5,5},
+ {4,4,4,3,3,3,3,3,4,5,4,5},
+ {6,5,3,3,3,3,3,3,4,3,6},
+ {6,5,3,3,3,2,3,4,3,6},
+ {6,4,5,3,2,2,3,3,6},
+ {6,6,4,2,2,3,2,5},
+ {5,5,3,2,2,2,4},
+ {4,4,3,3,1,3},
+ {4,4,2,1,3},
+ {3,3,1,2},
+ {2,2,1},
+ {1,1},
+};
+
+static const uint8_t total_zeros_bits[16][16] = {
+ {1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1},
+ {7,6,5,4,3,5,4,3,2,3,2,3,2,1,0},
+ {5,7,6,5,4,3,4,3,2,3,2,1,1,0},
+ {3,7,5,4,6,5,4,3,3,2,2,1,0},
+ {5,4,3,7,6,5,4,3,2,1,1,0},
+ {1,1,7,6,5,4,3,2,1,1,0},
+ {1,1,5,4,3,3,2,1,1,0},
+ {1,1,1,3,3,2,2,1,0},
+ {1,0,1,3,2,1,1,1},
+ {1,0,1,3,2,1,1},
+ {0,1,1,2,1,3},
+ {0,1,1,1,1},
+ {0,1,1,1},
+ {0,1,1},
+ {0,1},
+};
+
+static const uint8_t run_len[7][16] = {
+ {1,1},
+ {1,2,2},
+ {2,2,2,2},
+ {2,2,2,3,3},
+ {2,2,3,3,3,3},
+ {2,3,3,3,3,3,3},
+ {3,3,3,3,3,3,3,4,5,6,7,8,9,10,11},
+};
+
+static const uint8_t run_bits[7][16] = {
+ {1,0},
+ {1,1,0},
+ {3,2,1,0},
+ {3,2,1,1,0},
+ {3,2,3,2,1,0},
+ {3,0,1,3,2,5,4},
+ {7,6,5,4,3,2,1,1,1,1,1,1,1,1,1},
+};
+
+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,
+ &coeff_token_len [i][0], 1, 1,
+ &coeff_token_bits[i][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+ offset += coeff_token_vlc_tables_size[i];
+ }
+ /*
+ * This is a one time safety check to make sure that
+ * the packed static coeff_token_vlc table sizes
+ * were initialized correctly.
+ */
+ av_assert0(offset == FF_ARRAY_ELEMS(coeff_token_vlc_tables));
+
+ for (int i = 0; i < 15; i++) {
+ 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,
+ &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++) {
+ 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,
+ &run_len [i][0], 1, 1,
+ &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,
+ &run_len [6][0], 1, 1,
+ &run_bits[6][0], 1, 1,
+ INIT_VLC_USE_NEW_STATIC);
+}
+
+int ff_h264_cavlc_data_init_vlc(void)
+{
+ // at the current time this function is only called by
+ // - vx_init (actimagine_vxdec.c)
+ // - ff_h264_decode_init_vlc (h264_cavlc.c)
+ // since ff_h264_decode_init_vlc is already called using ff_thread_once
+ // we only need to use ff_thread_once here if the actimagine_vx decoder
+ // is enabled as well
+#if CONFIG_ACTIMAGINE_VX_DECODER
+ static AVOnce vlc_init = AV_ONCE_INIT;
+ return ff_thread_once(&vlc_init, cavlc_init_vlc);
+#else
+ cavlc_init_vlc();
+ return 0;
+#endif
+}
\ 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..170da67360
--- /dev/null
+++ b/libavcodec/h264_cavlc_data.h
@@ -0,0 +1,43 @@
+/*
+ * 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_table_index[17];
+
+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;
+
+// when using this function, make sure to modify the #if statement in the c
+// file to ensure a thread-safe one-time initialization
+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 }
};
--
2.17.1
More information about the ffmpeg-devel
mailing list