Florian Nouwt: > Signed-off-by: Florian Nouwt <fnou...@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 <michae...@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 } > }; > > _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".