lavc: VP9 decoder
Originally written by Ronald S. Bultje <rsbultje@gmail.com> and Clément Bœsch <u@pkh.me> Further contributions by: Anton Khirnov <anton@khirnov.net> Diego Biurrun <diego@biurrun.de> Luca Barbato <lu_zero@gentoo.org> Martin Storsjö <martin@martin.st> Signed-off-by: Luca Barbato <lu_zero@gentoo.org> Signed-off-by: Anton Khirnov <anton@khirnov.net>
This commit is contained in:
parent
458446acfa
commit
72ca830f51
221 changed files with 10716 additions and 1 deletions
|
|
@ -392,6 +392,8 @@ OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp56dsp.o \
|
|||
OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp56dsp.o \
|
||||
vp6dsp.o vp56rac.o
|
||||
OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp8dsp.o vp56rac.o
|
||||
OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o \
|
||||
vp9block.o vp9prob.o vp9mvs.o vp56rac.o
|
||||
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
|
||||
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o
|
||||
OBJS-$(CONFIG_WEBP_DECODER) += webp.o
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ void avcodec_register_all(void)
|
|||
REGISTER_DECODER(VP6A, vp6a);
|
||||
REGISTER_DECODER(VP6F, vp6f);
|
||||
REGISTER_DECODER(VP8, vp8);
|
||||
REGISTER_DECODER(VP9, vp9);
|
||||
REGISTER_DECODER(VQA, vqa);
|
||||
REGISTER_DECODER(WEBP, webp);
|
||||
REGISTER_ENCDEC (WMV1, wmv1);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
#define LIBAVCODEC_VERSION_MAJOR 55
|
||||
#define LIBAVCODEC_VERSION_MINOR 27
|
||||
#define LIBAVCODEC_VERSION_MINOR 28
|
||||
#define LIBAVCODEC_VERSION_MICRO 0
|
||||
|
||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||
|
|
|
|||
1270
libavcodec/vp9.c
Normal file
1270
libavcodec/vp9.c
Normal file
File diff suppressed because it is too large
Load diff
419
libavcodec/vp9.h
Normal file
419
libavcodec/vp9.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
* VP9 compatible video decoder
|
||||
*
|
||||
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
|
||||
* Copyright (C) 2013 Clément Bœsch <u pkh me>
|
||||
*
|
||||
* This file is part of Libav.
|
||||
*
|
||||
* Libav 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.
|
||||
*
|
||||
* Libav 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 Libav; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VP9_H
|
||||
#define AVCODEC_VP9_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavutil/internal.h"
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "vp56.h"
|
||||
|
||||
enum TxfmMode {
|
||||
TX_4X4,
|
||||
TX_8X8,
|
||||
TX_16X16,
|
||||
TX_32X32,
|
||||
N_TXFM_SIZES,
|
||||
TX_SWITCHABLE = N_TXFM_SIZES,
|
||||
N_TXFM_MODES
|
||||
};
|
||||
|
||||
enum TxfmType {
|
||||
DCT_DCT,
|
||||
DCT_ADST,
|
||||
ADST_DCT,
|
||||
ADST_ADST,
|
||||
N_TXFM_TYPES
|
||||
};
|
||||
|
||||
enum IntraPredMode {
|
||||
VERT_PRED,
|
||||
HOR_PRED,
|
||||
DC_PRED,
|
||||
DIAG_DOWN_LEFT_PRED,
|
||||
DIAG_DOWN_RIGHT_PRED,
|
||||
VERT_RIGHT_PRED,
|
||||
HOR_DOWN_PRED,
|
||||
VERT_LEFT_PRED,
|
||||
HOR_UP_PRED,
|
||||
TM_VP8_PRED,
|
||||
LEFT_DC_PRED,
|
||||
TOP_DC_PRED,
|
||||
DC_128_PRED,
|
||||
DC_127_PRED,
|
||||
DC_129_PRED,
|
||||
N_INTRA_PRED_MODES
|
||||
};
|
||||
|
||||
enum FilterMode {
|
||||
FILTER_8TAP_SMOOTH,
|
||||
FILTER_8TAP_REGULAR,
|
||||
FILTER_8TAP_SHARP,
|
||||
FILTER_BILINEAR,
|
||||
FILTER_SWITCHABLE,
|
||||
};
|
||||
|
||||
enum BlockPartition {
|
||||
PARTITION_NONE, // [ ] <-.
|
||||
PARTITION_H, // [-] |
|
||||
PARTITION_V, // [|] |
|
||||
PARTITION_SPLIT, // [+] --'
|
||||
};
|
||||
|
||||
enum InterPredMode {
|
||||
NEARESTMV = 10,
|
||||
NEARMV = 11,
|
||||
ZEROMV = 12,
|
||||
NEWMV = 13,
|
||||
};
|
||||
|
||||
enum MVJoint {
|
||||
MV_JOINT_ZERO,
|
||||
MV_JOINT_H,
|
||||
MV_JOINT_V,
|
||||
MV_JOINT_HV,
|
||||
};
|
||||
|
||||
typedef struct ProbContext {
|
||||
uint8_t y_mode[4][9];
|
||||
uint8_t uv_mode[10][9];
|
||||
uint8_t filter[4][2];
|
||||
uint8_t mv_mode[7][3];
|
||||
uint8_t intra[4];
|
||||
uint8_t comp[5];
|
||||
uint8_t single_ref[5][2];
|
||||
uint8_t comp_ref[5];
|
||||
uint8_t tx32p[2][3];
|
||||
uint8_t tx16p[2][2];
|
||||
uint8_t tx8p[2];
|
||||
uint8_t skip[3];
|
||||
uint8_t mv_joint[3];
|
||||
struct {
|
||||
uint8_t sign;
|
||||
uint8_t classes[10];
|
||||
uint8_t class0;
|
||||
uint8_t bits[10];
|
||||
uint8_t class0_fp[2][3];
|
||||
uint8_t fp[3];
|
||||
uint8_t class0_hp;
|
||||
uint8_t hp;
|
||||
} mv_comp[2];
|
||||
uint8_t partition[4][4][3];
|
||||
} ProbContext;
|
||||
|
||||
typedef void (*vp9_mc_func)(uint8_t *dst, const uint8_t *ref,
|
||||
ptrdiff_t dst_stride,
|
||||
ptrdiff_t ref_stride,
|
||||
int h, int mx, int my);
|
||||
|
||||
typedef struct VP9DSPContext {
|
||||
/*
|
||||
* dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32
|
||||
* dimension 2: intra prediction modes
|
||||
*
|
||||
* dst/left/top is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
|
||||
* stride is aligned by 16 pixels
|
||||
* top[-1] is top/left; top[4,7] is top-right for 4x4
|
||||
*/
|
||||
// FIXME(rbultje) maybe replace left/top pointers with HAVE_TOP/
|
||||
// HAVE_LEFT/HAVE_TOPRIGHT flags instead, and then handle it in-place?
|
||||
// also needs to fit in with what h264/vp8/etc do
|
||||
void (*intra_pred[N_TXFM_SIZES][N_INTRA_PRED_MODES])(uint8_t *dst,
|
||||
ptrdiff_t stride,
|
||||
const uint8_t *left,
|
||||
const uint8_t *top);
|
||||
|
||||
/*
|
||||
* dimension 1: 0=4x4, 1=8x8, 2=16x16, 3=32x32, 4=lossless (3-4=dct only)
|
||||
* dimension 2: 0=dct/dct, 1=dct/adst, 2=adst/dct, 3=adst/adst
|
||||
*
|
||||
* dst is aligned by transform-size (i.e. 4, 8, 16 or 32 pixels)
|
||||
* stride is aligned by 16 pixels
|
||||
* block is 16-byte aligned
|
||||
* eob indicates the position (+1) of the last non-zero coefficient,
|
||||
* in scan-order. This can be used to write faster versions, e.g. a
|
||||
* dc-only 4x4/8x8/16x16/32x32, or a 4x4-only (eob<10) 8x8/16x16/32x32,
|
||||
* etc.
|
||||
*/
|
||||
// FIXME also write idct_add_block() versions for whole (inter) pred
|
||||
// blocks, so we can do 2 4x4s at once
|
||||
void (*itxfm_add[N_TXFM_SIZES + 1][N_TXFM_TYPES])(uint8_t *dst,
|
||||
ptrdiff_t stride,
|
||||
int16_t *block, int eob);
|
||||
|
||||
/*
|
||||
* dimension 1: width of filter (0=4, 1=8, 2=16)
|
||||
* dimension 2: 0=col-edge filter (h), 1=row-edge filter (v)
|
||||
*
|
||||
* dst/stride are aligned by 8
|
||||
*/
|
||||
void (*loop_filter_8[3][2])(uint8_t *dst, ptrdiff_t stride,
|
||||
int mb_lim, int lim, int hev_thr);
|
||||
|
||||
/*
|
||||
* dimension 1: 0=col-edge filter (h), 1=row-edge filter (v)
|
||||
*
|
||||
* The width of filter is assumed to be 16; dst/stride are aligned by 16
|
||||
*/
|
||||
void (*loop_filter_16[2])(uint8_t *dst, ptrdiff_t stride,
|
||||
int mb_lim, int lim, int hev_thr);
|
||||
|
||||
/*
|
||||
* dimension 1/2: width of filter (0=4, 1=8) for each filter half
|
||||
* dimension 3: 0=col-edge filter (h), 1=row-edge filter (v)
|
||||
*
|
||||
* dst/stride are aligned by operation size
|
||||
* this basically calls loop_filter[d1][d3][0](), followed by
|
||||
* loop_filter[d2][d3][0]() on the next 8 pixels
|
||||
* mb_lim/lim/hev_thr contain two values in the lowest two bytes of the
|
||||
* integer.
|
||||
*/
|
||||
// FIXME perhaps a mix4 that operates on 32px (for AVX2)
|
||||
void (*loop_filter_mix2[2][2][2])(uint8_t *dst, ptrdiff_t stride,
|
||||
int mb_lim, int lim, int hev_thr);
|
||||
|
||||
/*
|
||||
* dimension 1: hsize (0: 64, 1: 32, 2: 16, 3: 8, 4: 4)
|
||||
* dimension 2: filter type (0: smooth, 1: regular, 2: sharp, 3: bilin)
|
||||
* dimension 3: averaging type (0: put, 1: avg)
|
||||
* dimension 4: x subpel interpolation (0: none, 1: 8tap/bilin)
|
||||
* dimension 5: y subpel interpolation (1: none, 1: 8tap/bilin)
|
||||
*
|
||||
* dst/stride are aligned by hsize
|
||||
*/
|
||||
vp9_mc_func mc[5][4][2][2][2];
|
||||
} VP9DSPContext;
|
||||
|
||||
enum CompPredMode {
|
||||
PRED_SINGLEREF,
|
||||
PRED_COMPREF,
|
||||
PRED_SWITCHABLE,
|
||||
};
|
||||
|
||||
typedef struct VP9MVRefPair {
|
||||
VP56mv mv[2];
|
||||
int8_t ref[2];
|
||||
} VP9MVRefPair;
|
||||
|
||||
typedef struct VP9Filter {
|
||||
uint8_t level[8 * 8];
|
||||
uint8_t /* bit=col */ mask[2 /* 0=y, 1=uv */][2 /* 0=col, 1=row */]
|
||||
[8 /* rows */][4 /* 0=16, 1=8, 2=4, 3=inner4 */];
|
||||
} VP9Filter;
|
||||
|
||||
enum BlockLevel {
|
||||
BL_64X64,
|
||||
BL_32X32,
|
||||
BL_16X16,
|
||||
BL_8X8,
|
||||
};
|
||||
|
||||
enum BlockSize {
|
||||
BS_64x64,
|
||||
BS_64x32,
|
||||
BS_32x64,
|
||||
BS_32x32,
|
||||
BS_32x16,
|
||||
BS_16x32,
|
||||
BS_16x16,
|
||||
BS_16x8,
|
||||
BS_8x16,
|
||||
BS_8x8,
|
||||
BS_8x4,
|
||||
BS_4x8,
|
||||
BS_4x4,
|
||||
N_BS_SIZES,
|
||||
};
|
||||
|
||||
typedef struct VP9Block {
|
||||
uint8_t seg_id, intra, comp, ref[2], mode[4], uvmode, skip;
|
||||
enum FilterMode filter;
|
||||
VP56mv mv[4 /* b_idx */][2 /* ref */];
|
||||
enum BlockSize bs;
|
||||
enum TxfmMode tx, uvtx;
|
||||
|
||||
int row, row7, col, col7;
|
||||
uint8_t *dst[3];
|
||||
ptrdiff_t y_stride, uv_stride;
|
||||
} VP9Block;
|
||||
|
||||
typedef struct VP9Context {
|
||||
VP9DSPContext dsp;
|
||||
VideoDSPContext vdsp;
|
||||
GetBitContext gb;
|
||||
VP56RangeCoder c;
|
||||
VP56RangeCoder *c_b;
|
||||
unsigned c_b_size;
|
||||
VP9Block b;
|
||||
|
||||
// bitstream header
|
||||
uint8_t profile;
|
||||
uint8_t keyframe, last_keyframe;
|
||||
uint8_t invisible;
|
||||
uint8_t use_last_frame_mvs;
|
||||
uint8_t errorres;
|
||||
uint8_t colorspace;
|
||||
uint8_t fullrange;
|
||||
uint8_t intraonly;
|
||||
uint8_t resetctx;
|
||||
uint8_t refreshrefmask;
|
||||
uint8_t highprecisionmvs;
|
||||
enum FilterMode filtermode;
|
||||
uint8_t allowcompinter;
|
||||
uint8_t fixcompref;
|
||||
uint8_t refreshctx;
|
||||
uint8_t parallelmode;
|
||||
uint8_t framectxid;
|
||||
uint8_t refidx[3];
|
||||
uint8_t signbias[3];
|
||||
uint8_t varcompref[2];
|
||||
AVFrame *refs[8];
|
||||
AVFrame *cur_frame;
|
||||
|
||||
struct {
|
||||
uint8_t level;
|
||||
int8_t sharpness;
|
||||
uint8_t lim_lut[64];
|
||||
uint8_t mblim_lut[64];
|
||||
} filter;
|
||||
struct {
|
||||
uint8_t enabled;
|
||||
int8_t mode[2];
|
||||
int8_t ref[4];
|
||||
} lf_delta;
|
||||
uint8_t yac_qi;
|
||||
int8_t ydc_qdelta, uvdc_qdelta, uvac_qdelta;
|
||||
uint8_t lossless;
|
||||
struct {
|
||||
uint8_t enabled;
|
||||
uint8_t temporal;
|
||||
uint8_t absolute_vals;
|
||||
uint8_t update_map;
|
||||
struct {
|
||||
uint8_t q_enabled;
|
||||
uint8_t lf_enabled;
|
||||
uint8_t ref_enabled;
|
||||
uint8_t skip_enabled;
|
||||
uint8_t ref_val;
|
||||
int16_t q_val;
|
||||
int8_t lf_val;
|
||||
int16_t qmul[2][2];
|
||||
uint8_t lflvl[4][2];
|
||||
} feat[8];
|
||||
} segmentation;
|
||||
struct {
|
||||
unsigned log2_tile_cols, log2_tile_rows;
|
||||
unsigned tile_cols, tile_rows;
|
||||
unsigned tile_row_start, tile_row_end, tile_col_start, tile_col_end;
|
||||
} tiling;
|
||||
unsigned sb_cols, sb_rows, rows, cols;
|
||||
struct {
|
||||
ProbContext p;
|
||||
uint8_t coef[4][2][2][6][6][3];
|
||||
} prob_ctx[4];
|
||||
struct {
|
||||
ProbContext p;
|
||||
uint8_t coef[4][2][2][6][6][11];
|
||||
uint8_t seg[7];
|
||||
uint8_t segpred[3];
|
||||
} prob;
|
||||
struct {
|
||||
unsigned y_mode[4][10];
|
||||
unsigned uv_mode[10][10];
|
||||
unsigned filter[4][3];
|
||||
unsigned mv_mode[7][4];
|
||||
unsigned intra[4][2];
|
||||
unsigned comp[5][2];
|
||||
unsigned single_ref[5][2][2];
|
||||
unsigned comp_ref[5][2];
|
||||
unsigned tx32p[2][4];
|
||||
unsigned tx16p[2][3];
|
||||
unsigned tx8p[2][2];
|
||||
unsigned skip[3][2];
|
||||
unsigned mv_joint[4];
|
||||
struct {
|
||||
unsigned sign[2];
|
||||
unsigned classes[11];
|
||||
unsigned class0[2];
|
||||
unsigned bits[10][2];
|
||||
unsigned class0_fp[2][4];
|
||||
unsigned fp[4];
|
||||
unsigned class0_hp[2];
|
||||
unsigned hp[2];
|
||||
} mv_comp[2];
|
||||
unsigned partition[4][4][4];
|
||||
unsigned coef[4][2][2][6][6][3];
|
||||
unsigned eob[4][2][2][6][6][2];
|
||||
} counts;
|
||||
enum TxfmMode txfmmode;
|
||||
enum CompPredMode comppredmode;
|
||||
|
||||
// contextual (left/above) cache
|
||||
uint8_t left_partition_ctx[8], *above_partition_ctx;
|
||||
uint8_t left_mode_ctx[16], *above_mode_ctx;
|
||||
// FIXME maybe merge some of the below in a flags field?
|
||||
uint8_t left_y_nnz_ctx[16], *above_y_nnz_ctx;
|
||||
uint8_t left_uv_nnz_ctx[2][8], *above_uv_nnz_ctx[2];
|
||||
uint8_t left_skip_ctx[8], *above_skip_ctx; // 1bit
|
||||
uint8_t left_txfm_ctx[8], *above_txfm_ctx; // 2bit
|
||||
uint8_t left_segpred_ctx[8], *above_segpred_ctx; // 1bit
|
||||
uint8_t left_intra_ctx[8], *above_intra_ctx; // 1bit
|
||||
uint8_t left_comp_ctx[8], *above_comp_ctx; // 1bit
|
||||
uint8_t left_ref_ctx[8], *above_ref_ctx; // 2bit
|
||||
uint8_t left_filter_ctx[8], *above_filter_ctx;
|
||||
VP56mv left_mv_ctx[16][2], (*above_mv_ctx)[2];
|
||||
|
||||
// whole-frame cache
|
||||
uint8_t *intra_pred_data[3];
|
||||
uint8_t *segmentation_map;
|
||||
VP9MVRefPair *mv[2];
|
||||
VP9Filter *lflvl;
|
||||
DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[71 * 80];
|
||||
|
||||
// block reconstruction intermediates
|
||||
DECLARE_ALIGNED(32, int16_t, block)[4096];
|
||||
DECLARE_ALIGNED(32, int16_t, uvblock)[2][1024];
|
||||
uint8_t eob[256];
|
||||
uint8_t uveob[2][64];
|
||||
VP56mv min_mv, max_mv;
|
||||
DECLARE_ALIGNED(32, uint8_t, tmp_y)[64 * 64];
|
||||
DECLARE_ALIGNED(32, uint8_t, tmp_uv)[2][32 * 32];
|
||||
} VP9Context;
|
||||
|
||||
void ff_vp9dsp_init(VP9DSPContext *dsp);
|
||||
|
||||
void ff_vp9dsp_init_x86(VP9DSPContext *dsp);
|
||||
|
||||
void ff_vp9_fill_mv(VP9Context *s, VP56mv *mv, int mode, int sb);
|
||||
|
||||
void ff_vp9_adapt_probs(VP9Context *s);
|
||||
|
||||
int ff_vp9_decode_block(AVCodecContext *avctx, int row, int col,
|
||||
VP9Filter *lflvl, ptrdiff_t yoff, ptrdiff_t uvoff,
|
||||
enum BlockLevel bl, enum BlockPartition bp);
|
||||
|
||||
#endif /* AVCODEC_VP9_H */
|
||||
1684
libavcodec/vp9block.c
Normal file
1684
libavcodec/vp9block.c
Normal file
File diff suppressed because it is too large
Load diff
2133
libavcodec/vp9data.c
Normal file
2133
libavcodec/vp9data.c
Normal file
File diff suppressed because it is too large
Load diff
70
libavcodec/vp9data.h
Normal file
70
libavcodec/vp9data.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
|
||||
* Copyright (C) 2013 Clément Bœsch <u pkh me>
|
||||
*
|
||||
* This file is part of Libav.
|
||||
*
|
||||
* Libav 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.
|
||||
*
|
||||
* Libav 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 Libav; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VP9DATA_H
|
||||
#define AVCODEC_VP9DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "vp9.h"
|
||||
|
||||
extern const int8_t ff_vp9_partition_tree[3][2];
|
||||
extern const uint8_t ff_vp9_default_kf_partition_probs[4][4][3];
|
||||
extern const int8_t ff_vp9_segmentation_tree[7][2];
|
||||
extern const int8_t ff_vp9_intramode_tree[9][2];
|
||||
extern const uint8_t ff_vp9_default_kf_ymode_probs[10][10][9];
|
||||
extern const uint8_t ff_vp9_default_kf_uvmode_probs[10][9];
|
||||
extern const int8_t ff_vp9_inter_mode_tree[3][2];
|
||||
extern const int8_t ff_vp9_filter_tree[2][2];
|
||||
extern const enum FilterMode ff_vp9_filter_lut[3];
|
||||
extern const int16_t ff_vp9_dc_qlookup[256];
|
||||
extern const int16_t ff_vp9_ac_qlookup[256];
|
||||
extern const enum TxfmType ff_vp9_intra_txfm_type[14];
|
||||
extern const int16_t ff_vp9_default_scan_4x4[16];
|
||||
extern const int16_t ff_vp9_col_scan_4x4[16];
|
||||
extern const int16_t ff_vp9_row_scan_4x4[16];
|
||||
extern const int16_t ff_vp9_default_scan_8x8[64];
|
||||
extern const int16_t ff_vp9_col_scan_8x8[64];
|
||||
extern const int16_t ff_vp9_row_scan_8x8[64];
|
||||
extern const int16_t ff_vp9_default_scan_16x16[256];
|
||||
extern const int16_t ff_vp9_col_scan_16x16[256];
|
||||
extern const int16_t ff_vp9_row_scan_16x16[256];
|
||||
extern const int16_t ff_vp9_default_scan_32x32[1024];
|
||||
extern const int16_t *ff_vp9_scans[5][4];
|
||||
extern const int16_t ff_vp9_default_scan_4x4_nb[16][2];
|
||||
extern const int16_t ff_vp9_col_scan_4x4_nb[16][2];
|
||||
extern const int16_t ff_vp9_row_scan_4x4_nb[16][2];
|
||||
extern const int16_t ff_vp9_default_scan_8x8_nb[64][2];
|
||||
extern const int16_t ff_vp9_col_scan_8x8_nb[64][2];
|
||||
extern const int16_t ff_vp9_row_scan_8x8_nb[64][2];
|
||||
extern const int16_t ff_vp9_default_scan_16x16_nb[256][2];
|
||||
extern const int16_t ff_vp9_col_scan_16x16_nb[256][2];
|
||||
extern const int16_t ff_vp9_row_scan_16x16_nb[256][2];
|
||||
extern const int16_t ff_vp9_default_scan_32x32_nb[1024][2];
|
||||
extern const int16_t (*ff_vp9_scans_nb[5][4])[2];
|
||||
extern const uint8_t ff_vp9_model_pareto8[256][8];
|
||||
extern const ProbContext ff_vp9_default_probs;
|
||||
extern const uint8_t ff_vp9_default_coef_probs[4][2][2][6][6][3];
|
||||
extern const int8_t ff_vp9_mv_joint_tree[3][2];
|
||||
extern const int8_t ff_vp9_mv_class_tree[10][2];
|
||||
extern const int8_t ff_vp9_mv_fp_tree[3][2];
|
||||
|
||||
#endif /* AVCODEC_VP9DATA_H */
|
||||
2174
libavcodec/vp9dsp.c
Normal file
2174
libavcodec/vp9dsp.c
Normal file
File diff suppressed because it is too large
Load diff
344
libavcodec/vp9mvs.c
Normal file
344
libavcodec/vp9mvs.c
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* VP9 compatible video decoder
|
||||
*
|
||||
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
|
||||
* Copyright (C) 2013 Clément Bœsch <u pkh me>
|
||||
*
|
||||
* This file is part of Libav.
|
||||
*
|
||||
* Libav 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.
|
||||
*
|
||||
* Libav 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 Libav; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "internal.h"
|
||||
#include "vp56.h"
|
||||
#include "vp9.h"
|
||||
#include "vp9data.h"
|
||||
|
||||
static av_always_inline void clamp_mv(VP56mv *dst, const VP56mv *src,
|
||||
VP9Context *s)
|
||||
{
|
||||
dst->x = av_clip(src->x, s->min_mv.x, s->max_mv.x);
|
||||
dst->y = av_clip(src->y, s->min_mv.y, s->max_mv.y);
|
||||
}
|
||||
|
||||
static void find_ref_mvs(VP9Context *s,
|
||||
VP56mv *pmv, int ref, int z, int idx, int sb)
|
||||
{
|
||||
static const int8_t mv_ref_blk_off[N_BS_SIZES][8][2] = {
|
||||
[BS_64x64] = { { 3, -1 }, { -1, 3 }, { 4, -1 }, { -1, 4 },
|
||||
{ -1, -1 }, { 0, -1 }, { -1, 0 }, { 6, -1 } },
|
||||
[BS_64x32] = { { 0, -1 }, { -1, 0 }, { 4, -1 }, { -1, 2 },
|
||||
{ -1, -1 }, { 0, -3 }, { -3, 0 }, { 2, -1 } },
|
||||
[BS_32x64] = { { -1, 0 }, { 0, -1 }, { -1, 4 }, { 2, -1 },
|
||||
{ -1, -1 }, { -3, 0 }, { 0, -3 }, { -1, 2 } },
|
||||
[BS_32x32] = { { 1, -1 }, { -1, 1 }, { 2, -1 }, { -1, 2 },
|
||||
{ -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
|
||||
[BS_32x16] = { { 0, -1 }, { -1, 0 }, { 2, -1 }, { -1, -1 },
|
||||
{ -1, 1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
|
||||
[BS_16x32] = { { -1, 0 }, { 0, -1 }, { -1, 2 }, { -1, -1 },
|
||||
{ 1, -1 }, { -3, 0 }, { 0, -3 }, { -3, -3 } },
|
||||
[BS_16x16] = { { 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, 1 },
|
||||
{ -1, -1 }, { 0, -3 }, { -3, 0 }, { -3, -3 } },
|
||||
[BS_16x8] = { { 0, -1 }, { -1, 0 }, { 1, -1 }, { -1, -1 },
|
||||
{ 0, -2 }, { -2, 0 }, { -2, -1 }, { -1, -2 } },
|
||||
[BS_8x16] = { { -1, 0 }, { 0, -1 }, { -1, 1 }, { -1, -1 },
|
||||
{ -2, 0 }, { 0, -2 }, { -1, -2 }, { -2, -1 } },
|
||||
[BS_8x8] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
|
||||
{ -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
|
||||
[BS_8x4] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
|
||||
{ -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
|
||||
[BS_4x8] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
|
||||
{ -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
|
||||
[BS_4x4] = { { 0, -1 }, { -1, 0 }, { -1, -1 }, { 0, -2 },
|
||||
{ -2, 0 }, { -1, -2 }, { -2, -1 }, { -2, -2 } },
|
||||
};
|
||||
VP9Block *const b = &s->b;
|
||||
int row = b->row, col = b->col, row7 = b->row7;
|
||||
const int8_t (*p)[2] = mv_ref_blk_off[b->bs];
|
||||
#define INVALID_MV 0x80008000U
|
||||
uint32_t mem = INVALID_MV;
|
||||
int i;
|
||||
|
||||
#define RETURN_DIRECT_MV(mv) \
|
||||
do { \
|
||||
uint32_t m = AV_RN32A(&mv); \
|
||||
if (!idx) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
return; \
|
||||
} else if (mem == INVALID_MV) { \
|
||||
mem = m; \
|
||||
} else if (m != mem) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (sb >= 0) {
|
||||
if (sb == 2 || sb == 1) {
|
||||
RETURN_DIRECT_MV(b->mv[0][z]);
|
||||
} else if (sb == 3) {
|
||||
RETURN_DIRECT_MV(b->mv[2][z]);
|
||||
RETURN_DIRECT_MV(b->mv[1][z]);
|
||||
RETURN_DIRECT_MV(b->mv[0][z]);
|
||||
}
|
||||
|
||||
#define RETURN_MV(mv) \
|
||||
do { \
|
||||
if (sb > 0) { \
|
||||
VP56mv tmp; \
|
||||
uint32_t m; \
|
||||
clamp_mv(&tmp, &mv, s); \
|
||||
m = AV_RN32A(&tmp); \
|
||||
if (!idx) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
return; \
|
||||
} else if (mem == INVALID_MV) { \
|
||||
mem = m; \
|
||||
} else if (m != mem) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
return; \
|
||||
} \
|
||||
} else { \
|
||||
uint32_t m = AV_RN32A(&mv); \
|
||||
if (!idx) { \
|
||||
clamp_mv(pmv, &mv, s); \
|
||||
return; \
|
||||
} else if (mem == INVALID_MV) { \
|
||||
mem = m; \
|
||||
} else if (m != mem) { \
|
||||
clamp_mv(pmv, &mv, s); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
if (row > 0) {
|
||||
VP9MVRefPair *mv = &s->mv[0][(row - 1) * s->sb_cols * 8 + col];
|
||||
|
||||
if (mv->ref[0] == ref)
|
||||
RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][0]);
|
||||
else if (mv->ref[1] == ref)
|
||||
RETURN_MV(s->above_mv_ctx[2 * col + (sb & 1)][1]);
|
||||
}
|
||||
if (col > s->tiling.tile_col_start) {
|
||||
VP9MVRefPair *mv = &s->mv[0][row * s->sb_cols * 8 + col - 1];
|
||||
|
||||
if (mv->ref[0] == ref)
|
||||
RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][0]);
|
||||
else if (mv->ref[1] == ref)
|
||||
RETURN_MV(s->left_mv_ctx[2 * row7 + (sb >> 1)][1]);
|
||||
}
|
||||
i = 2;
|
||||
} else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
// previously coded MVs in the neighborhood, using same reference frame
|
||||
for (; i < 8; i++) {
|
||||
int c = p[i][0] + col, r = p[i][1] + row;
|
||||
|
||||
if (c >= s->tiling.tile_col_start && c < s->cols &&
|
||||
r >= 0 && r < s->rows) {
|
||||
VP9MVRefPair *mv = &s->mv[0][r * s->sb_cols * 8 + c];
|
||||
|
||||
if (mv->ref[0] == ref)
|
||||
RETURN_MV(mv->mv[0]);
|
||||
else if (mv->ref[1] == ref)
|
||||
RETURN_MV(mv->mv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// MV at this position in previous frame, using same reference frame
|
||||
if (s->use_last_frame_mvs) {
|
||||
VP9MVRefPair *mv = &s->mv[1][row * s->sb_cols * 8 + col];
|
||||
|
||||
if (mv->ref[0] == ref)
|
||||
RETURN_MV(mv->mv[0]);
|
||||
else if (mv->ref[1] == ref)
|
||||
RETURN_MV(mv->mv[1]);
|
||||
}
|
||||
|
||||
#define RETURN_SCALE_MV(mv, scale) \
|
||||
do { \
|
||||
if (scale) { \
|
||||
VP56mv mv_temp = { -mv.x, -mv.y }; \
|
||||
RETURN_MV(mv_temp); \
|
||||
} else { \
|
||||
RETURN_MV(mv); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// previously coded MVs in the neighborhood, using different reference frame
|
||||
for (i = 0; i < 8; i++) {
|
||||
int c = p[i][0] + col, r = p[i][1] + row;
|
||||
|
||||
if (c >= s->tiling.tile_col_start && c < s->cols &&
|
||||
r >= 0 && r < s->rows) {
|
||||
VP9MVRefPair *mv = &s->mv[0][r * s->sb_cols * 8 + c];
|
||||
|
||||
if (mv->ref[0] != ref && mv->ref[0] >= 0)
|
||||
RETURN_SCALE_MV(mv->mv[0],
|
||||
s->signbias[mv->ref[0]] != s->signbias[ref]);
|
||||
if (mv->ref[1] != ref && mv->ref[1] >= 0)
|
||||
RETURN_SCALE_MV(mv->mv[1],
|
||||
s->signbias[mv->ref[1]] != s->signbias[ref]);
|
||||
}
|
||||
}
|
||||
|
||||
// MV at this position in previous frame, using different reference frame
|
||||
if (s->use_last_frame_mvs) {
|
||||
VP9MVRefPair *mv = &s->mv[1][row * s->sb_cols * 8 + col];
|
||||
|
||||
if (mv->ref[0] != ref && mv->ref[0] >= 0)
|
||||
RETURN_SCALE_MV(mv->mv[0],
|
||||
s->signbias[mv->ref[0]] != s->signbias[ref]);
|
||||
if (mv->ref[1] != ref && mv->ref[1] >= 0)
|
||||
RETURN_SCALE_MV(mv->mv[1],
|
||||
s->signbias[mv->ref[1]] != s->signbias[ref]);
|
||||
}
|
||||
|
||||
AV_ZERO32(pmv);
|
||||
#undef INVALID_MV
|
||||
#undef RETURN_MV
|
||||
#undef RETURN_SCALE_MV
|
||||
}
|
||||
|
||||
static av_always_inline int read_mv_component(VP9Context *s, int idx, int hp)
|
||||
{
|
||||
int bit, sign = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].sign);
|
||||
int n, c = vp8_rac_get_tree(&s->c, ff_vp9_mv_class_tree,
|
||||
s->prob.p.mv_comp[idx].classes);
|
||||
|
||||
s->counts.mv_comp[idx].sign[sign]++;
|
||||
s->counts.mv_comp[idx].classes[c]++;
|
||||
if (c) {
|
||||
int m;
|
||||
|
||||
for (n = 0, m = 0; m < c; m++) {
|
||||
bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].bits[m]);
|
||||
n |= bit << m;
|
||||
s->counts.mv_comp[idx].bits[m][bit]++;
|
||||
}
|
||||
n <<= 3;
|
||||
bit = vp8_rac_get_tree(&s->c, ff_vp9_mv_fp_tree,
|
||||
s->prob.p.mv_comp[idx].fp);
|
||||
n |= bit << 1;
|
||||
s->counts.mv_comp[idx].fp[bit]++;
|
||||
if (hp) {
|
||||
bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].hp);
|
||||
s->counts.mv_comp[idx].hp[bit]++;
|
||||
n |= bit;
|
||||
} else {
|
||||
n |= 1;
|
||||
// bug in libvpx - we count for bw entropy purposes even if the
|
||||
// bit wasn't coded
|
||||
s->counts.mv_comp[idx].hp[1]++;
|
||||
}
|
||||
n += 8 << c;
|
||||
} else {
|
||||
n = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0);
|
||||
s->counts.mv_comp[idx].class0[n]++;
|
||||
bit = vp8_rac_get_tree(&s->c, ff_vp9_mv_fp_tree,
|
||||
s->prob.p.mv_comp[idx].class0_fp[n]);
|
||||
s->counts.mv_comp[idx].class0_fp[n][bit]++;
|
||||
n = (n << 3) | (bit << 1);
|
||||
if (hp) {
|
||||
bit = vp56_rac_get_prob(&s->c, s->prob.p.mv_comp[idx].class0_hp);
|
||||
s->counts.mv_comp[idx].class0_hp[bit]++;
|
||||
n |= bit;
|
||||
} else {
|
||||
n |= 1;
|
||||
// bug in libvpx - we count for bw entropy purposes even if the
|
||||
// bit wasn't coded
|
||||
s->counts.mv_comp[idx].class0_hp[1]++;
|
||||
}
|
||||
}
|
||||
|
||||
return sign ? -(n + 1) : (n + 1);
|
||||
}
|
||||
|
||||
void ff_vp9_fill_mv(VP9Context *s, VP56mv *mv, int mode, int sb)
|
||||
{
|
||||
VP9Block *const b = &s->b;
|
||||
|
||||
if (mode == ZEROMV) {
|
||||
memset(mv, 0, sizeof(*mv) * 2);
|
||||
} else {
|
||||
int hp;
|
||||
|
||||
// FIXME cache this value and reuse for other subblocks
|
||||
find_ref_mvs(s, &mv[0], b->ref[0], 0, mode == NEARMV,
|
||||
mode == NEWMV ? -1 : sb);
|
||||
// FIXME maybe move this code into find_ref_mvs()
|
||||
if ((mode == NEWMV || sb == -1) &&
|
||||
!(hp = s->highprecisionmvs &&
|
||||
abs(mv[0].x) < 64 && abs(mv[0].y) < 64)) {
|
||||
if (mv[0].y & 1) {
|
||||
if (mv[0].y < 0)
|
||||
mv[0].y++;
|
||||
else
|
||||
mv[0].y--;
|
||||
}
|
||||
if (mv[0].x & 1) {
|
||||
if (mv[0].x < 0)
|
||||
mv[0].x++;
|
||||
else
|
||||
mv[0].x--;
|
||||
}
|
||||
}
|
||||
if (mode == NEWMV) {
|
||||
enum MVJoint j = vp8_rac_get_tree(&s->c, ff_vp9_mv_joint_tree,
|
||||
s->prob.p.mv_joint);
|
||||
|
||||
s->counts.mv_joint[j]++;
|
||||
if (j >= MV_JOINT_V)
|
||||
mv[0].y += read_mv_component(s, 0, hp);
|
||||
if (j & 1)
|
||||
mv[0].x += read_mv_component(s, 1, hp);
|
||||
}
|
||||
|
||||
if (b->comp) {
|
||||
// FIXME cache this value and reuse for other subblocks
|
||||
find_ref_mvs(s, &mv[1], b->ref[1], 1, mode == NEARMV,
|
||||
mode == NEWMV ? -1 : sb);
|
||||
if ((mode == NEWMV || sb == -1) &&
|
||||
!(hp = s->highprecisionmvs &&
|
||||
abs(mv[1].x) < 64 && abs(mv[1].y) < 64)) {
|
||||
if (mv[1].y & 1) {
|
||||
if (mv[1].y < 0)
|
||||
mv[1].y++;
|
||||
else
|
||||
mv[1].y--;
|
||||
}
|
||||
if (mv[1].x & 1) {
|
||||
if (mv[1].x < 0)
|
||||
mv[1].x++;
|
||||
else
|
||||
mv[1].x--;
|
||||
}
|
||||
}
|
||||
if (mode == NEWMV) {
|
||||
enum MVJoint j = vp8_rac_get_tree(&s->c, ff_vp9_mv_joint_tree,
|
||||
s->prob.p.mv_joint);
|
||||
|
||||
s->counts.mv_joint[j]++;
|
||||
if (j >= MV_JOINT_V)
|
||||
mv[1].y += read_mv_component(s, 0, hp);
|
||||
if (j & 1)
|
||||
mv[1].x += read_mv_component(s, 1, hp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
274
libavcodec/vp9prob.c
Normal file
274
libavcodec/vp9prob.c
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* VP9 compatible video decoder
|
||||
*
|
||||
* Copyright (C) 2013 Ronald S. Bultje <rsbultje gmail com>
|
||||
* Copyright (C) 2013 Clément Bœsch <u pkh me>
|
||||
*
|
||||
* This file is part of Libav.
|
||||
*
|
||||
* Libav 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.
|
||||
*
|
||||
* Libav 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 Libav; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "vp56.h"
|
||||
#include "vp9.h"
|
||||
#include "vp9data.h"
|
||||
|
||||
static av_always_inline void adapt_prob(uint8_t *p, unsigned ct0, unsigned ct1,
|
||||
int max_count, int update_factor)
|
||||
{
|
||||
unsigned ct = ct0 + ct1, p2, p1;
|
||||
|
||||
if (!ct)
|
||||
return;
|
||||
|
||||
p1 = *p;
|
||||
p2 = ((ct0 << 8) + (ct >> 1)) / ct;
|
||||
p2 = av_clip(p2, 1, 255);
|
||||
ct = FFMIN(ct, max_count);
|
||||
update_factor = FASTDIV(update_factor * ct, max_count);
|
||||
|
||||
// (p1 * (256 - update_factor) + p2 * update_factor + 128) >> 8
|
||||
*p = p1 + (((p2 - p1) * update_factor + 128) >> 8);
|
||||
}
|
||||
|
||||
void ff_vp9_adapt_probs(VP9Context *s)
|
||||
{
|
||||
int i, j, k, l, m;
|
||||
ProbContext *p = &s->prob_ctx[s->framectxid].p;
|
||||
int uf = (s->keyframe || s->intraonly || !s->last_keyframe) ? 112 : 128;
|
||||
|
||||
// coefficients
|
||||
for (i = 0; i < 4; i++)
|
||||
for (j = 0; j < 2; j++)
|
||||
for (k = 0; k < 2; k++)
|
||||
for (l = 0; l < 6; l++)
|
||||
for (m = 0; m < 6; m++) {
|
||||
uint8_t *pp = s->prob_ctx[s->framectxid].coef[i][j][k][l][m];
|
||||
unsigned *e = s->counts.eob[i][j][k][l][m];
|
||||
unsigned *c = s->counts.coef[i][j][k][l][m];
|
||||
|
||||
if (l == 0 && m >= 3) // dc only has 3 pt
|
||||
break;
|
||||
|
||||
adapt_prob(&pp[0], e[0], e[1], 24, uf);
|
||||
adapt_prob(&pp[1], c[0], c[1] + c[2], 24, uf);
|
||||
adapt_prob(&pp[2], c[1], c[2], 24, uf);
|
||||
}
|
||||
|
||||
if (s->keyframe || s->intraonly) {
|
||||
memcpy(p->skip, s->prob.p.skip, sizeof(p->skip));
|
||||
memcpy(p->tx32p, s->prob.p.tx32p, sizeof(p->tx32p));
|
||||
memcpy(p->tx16p, s->prob.p.tx16p, sizeof(p->tx16p));
|
||||
memcpy(p->tx8p, s->prob.p.tx8p, sizeof(p->tx8p));
|
||||
return;
|
||||
}
|
||||
|
||||
// skip flag
|
||||
for (i = 0; i < 3; i++)
|
||||
adapt_prob(&p->skip[i], s->counts.skip[i][0],
|
||||
s->counts.skip[i][1], 20, 128);
|
||||
|
||||
// intra/inter flag
|
||||
for (i = 0; i < 4; i++)
|
||||
adapt_prob(&p->intra[i], s->counts.intra[i][0],
|
||||
s->counts.intra[i][1], 20, 128);
|
||||
|
||||
// comppred flag
|
||||
if (s->comppredmode == PRED_SWITCHABLE) {
|
||||
for (i = 0; i < 5; i++)
|
||||
adapt_prob(&p->comp[i], s->counts.comp[i][0],
|
||||
s->counts.comp[i][1], 20, 128);
|
||||
}
|
||||
|
||||
// reference frames
|
||||
if (s->comppredmode != PRED_SINGLEREF) {
|
||||
for (i = 0; i < 5; i++)
|
||||
adapt_prob(&p->comp_ref[i], s->counts.comp_ref[i][0],
|
||||
s->counts.comp_ref[i][1], 20, 128);
|
||||
}
|
||||
|
||||
if (s->comppredmode != PRED_COMPREF) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
uint8_t *pp = p->single_ref[i];
|
||||
unsigned (*c)[2] = s->counts.single_ref[i];
|
||||
|
||||
adapt_prob(&pp[0], c[0][0], c[0][1], 20, 128);
|
||||
adapt_prob(&pp[1], c[1][0], c[1][1], 20, 128);
|
||||
}
|
||||
}
|
||||
|
||||
// block partitioning
|
||||
for (i = 0; i < 4; i++)
|
||||
for (j = 0; j < 4; j++) {
|
||||
uint8_t *pp = p->partition[i][j];
|
||||
unsigned *c = s->counts.partition[i][j];
|
||||
|
||||
adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[2], c[2], c[3], 20, 128);
|
||||
}
|
||||
|
||||
// tx size
|
||||
if (s->txfmmode == TX_SWITCHABLE) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned *c16 = s->counts.tx16p[i], *c32 = s->counts.tx32p[i];
|
||||
|
||||
adapt_prob(&p->tx8p[i], s->counts.tx8p[i][0],
|
||||
s->counts.tx8p[i][1], 20, 128);
|
||||
adapt_prob(&p->tx16p[i][0], c16[0], c16[1] + c16[2], 20, 128);
|
||||
adapt_prob(&p->tx16p[i][1], c16[1], c16[2], 20, 128);
|
||||
adapt_prob(&p->tx32p[i][0], c32[0], c32[1] + c32[2] + c32[3], 20, 128);
|
||||
adapt_prob(&p->tx32p[i][1], c32[1], c32[2] + c32[3], 20, 128);
|
||||
adapt_prob(&p->tx32p[i][2], c32[2], c32[3], 20, 128);
|
||||
}
|
||||
}
|
||||
|
||||
// interpolation filter
|
||||
if (s->filtermode == FILTER_SWITCHABLE) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint8_t *pp = p->filter[i];
|
||||
unsigned *c = s->counts.filter[i];
|
||||
|
||||
adapt_prob(&pp[0], c[0], c[1] + c[2], 20, 128);
|
||||
adapt_prob(&pp[1], c[1], c[2], 20, 128);
|
||||
}
|
||||
}
|
||||
|
||||
// inter modes
|
||||
for (i = 0; i < 7; i++) {
|
||||
uint8_t *pp = p->mv_mode[i];
|
||||
unsigned *c = s->counts.mv_mode[i];
|
||||
|
||||
adapt_prob(&pp[0], c[2], c[1] + c[0] + c[3], 20, 128);
|
||||
adapt_prob(&pp[1], c[0], c[1] + c[3], 20, 128);
|
||||
adapt_prob(&pp[2], c[1], c[3], 20, 128);
|
||||
}
|
||||
|
||||
// mv joints
|
||||
{
|
||||
uint8_t *pp = p->mv_joint;
|
||||
unsigned *c = s->counts.mv_joint;
|
||||
|
||||
adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[2], c[2], c[3], 20, 128);
|
||||
}
|
||||
|
||||
// mv components
|
||||
for (i = 0; i < 2; i++) {
|
||||
uint8_t *pp;
|
||||
unsigned *c, (*c2)[2], sum;
|
||||
|
||||
adapt_prob(&p->mv_comp[i].sign, s->counts.mv_comp[i].sign[0],
|
||||
s->counts.mv_comp[i].sign[1], 20, 128);
|
||||
|
||||
pp = p->mv_comp[i].classes;
|
||||
c = s->counts.mv_comp[i].classes;
|
||||
sum = c[1] + c[2] + c[3] + c[4] + c[5] +
|
||||
c[6] + c[7] + c[8] + c[9] + c[10];
|
||||
adapt_prob(&pp[0], c[0], sum, 20, 128);
|
||||
sum -= c[1];
|
||||
adapt_prob(&pp[1], c[1], sum, 20, 128);
|
||||
sum -= c[2] + c[3];
|
||||
adapt_prob(&pp[2], c[2] + c[3], sum, 20, 128);
|
||||
adapt_prob(&pp[3], c[2], c[3], 20, 128);
|
||||
sum -= c[4] + c[5];
|
||||
adapt_prob(&pp[4], c[4] + c[5], sum, 20, 128);
|
||||
adapt_prob(&pp[5], c[4], c[5], 20, 128);
|
||||
sum -= c[6];
|
||||
adapt_prob(&pp[6], c[6], sum, 20, 128);
|
||||
adapt_prob(&pp[7], c[7] + c[8], c[9] + c[10], 20, 128);
|
||||
adapt_prob(&pp[8], c[7], c[8], 20, 128);
|
||||
adapt_prob(&pp[9], c[9], c[10], 20, 128);
|
||||
|
||||
adapt_prob(&p->mv_comp[i].class0, s->counts.mv_comp[i].class0[0],
|
||||
s->counts.mv_comp[i].class0[1], 20, 128);
|
||||
pp = p->mv_comp[i].bits;
|
||||
c2 = s->counts.mv_comp[i].bits;
|
||||
for (j = 0; j < 10; j++)
|
||||
adapt_prob(&pp[j], c2[j][0], c2[j][1], 20, 128);
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
pp = p->mv_comp[i].class0_fp[j];
|
||||
c = s->counts.mv_comp[i].class0_fp[j];
|
||||
adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[2], c[2], c[3], 20, 128);
|
||||
}
|
||||
pp = p->mv_comp[i].fp;
|
||||
c = s->counts.mv_comp[i].fp;
|
||||
adapt_prob(&pp[0], c[0], c[1] + c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[1], c[1], c[2] + c[3], 20, 128);
|
||||
adapt_prob(&pp[2], c[2], c[3], 20, 128);
|
||||
|
||||
if (s->highprecisionmvs) {
|
||||
adapt_prob(&p->mv_comp[i].class0_hp,
|
||||
s->counts.mv_comp[i].class0_hp[0],
|
||||
s->counts.mv_comp[i].class0_hp[1], 20, 128);
|
||||
adapt_prob(&p->mv_comp[i].hp, s->counts.mv_comp[i].hp[0],
|
||||
s->counts.mv_comp[i].hp[1], 20, 128);
|
||||
}
|
||||
}
|
||||
|
||||
// y intra modes
|
||||
for (i = 0; i < 4; i++) {
|
||||
uint8_t *pp = p->y_mode[i];
|
||||
unsigned *c = s->counts.y_mode[i], sum, s2;
|
||||
|
||||
sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
|
||||
adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
|
||||
sum -= c[TM_VP8_PRED];
|
||||
adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
|
||||
sum -= c[VERT_PRED];
|
||||
adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
|
||||
s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
|
||||
sum -= s2;
|
||||
adapt_prob(&pp[3], s2, sum, 20, 128);
|
||||
s2 -= c[HOR_PRED];
|
||||
adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
|
||||
adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED],
|
||||
20, 128);
|
||||
sum -= c[DIAG_DOWN_LEFT_PRED];
|
||||
adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
|
||||
sum -= c[VERT_LEFT_PRED];
|
||||
adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
|
||||
adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
|
||||
}
|
||||
|
||||
// uv intra modes
|
||||
for (i = 0; i < 10; i++) {
|
||||
uint8_t *pp = p->uv_mode[i];
|
||||
unsigned *c = s->counts.uv_mode[i], sum, s2;
|
||||
|
||||
sum = c[0] + c[1] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9];
|
||||
adapt_prob(&pp[0], c[DC_PRED], sum, 20, 128);
|
||||
sum -= c[TM_VP8_PRED];
|
||||
adapt_prob(&pp[1], c[TM_VP8_PRED], sum, 20, 128);
|
||||
sum -= c[VERT_PRED];
|
||||
adapt_prob(&pp[2], c[VERT_PRED], sum, 20, 128);
|
||||
s2 = c[HOR_PRED] + c[DIAG_DOWN_RIGHT_PRED] + c[VERT_RIGHT_PRED];
|
||||
sum -= s2;
|
||||
adapt_prob(&pp[3], s2, sum, 20, 128);
|
||||
s2 -= c[HOR_PRED];
|
||||
adapt_prob(&pp[4], c[HOR_PRED], s2, 20, 128);
|
||||
adapt_prob(&pp[5], c[DIAG_DOWN_RIGHT_PRED], c[VERT_RIGHT_PRED],
|
||||
20, 128);
|
||||
sum -= c[DIAG_DOWN_LEFT_PRED];
|
||||
adapt_prob(&pp[6], c[DIAG_DOWN_LEFT_PRED], sum, 20, 128);
|
||||
sum -= c[VERT_LEFT_PRED];
|
||||
adapt_prob(&pp[7], c[VERT_LEFT_PRED], sum, 20, 128);
|
||||
adapt_prob(&pp[8], c[HOR_DOWN_PRED], c[HOR_UP_PRED], 20, 128);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ OBJS-$(CONFIG_VORBIS_DECODER) += x86/vorbisdsp_init.o
|
|||
OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp_init.o
|
||||
OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp_init.o
|
||||
OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp_init.o
|
||||
OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp_init.o
|
||||
OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o
|
||||
|
||||
MMX-OBJS-$(CONFIG_DSPUTIL) += x86/dsputil_mmx.o \
|
||||
|
|
@ -90,3 +91,4 @@ YASM-OBJS-$(CONFIG_VP3DSP) += x86/vp3dsp.o
|
|||
YASM-OBJS-$(CONFIG_VP6_DECODER) += x86/vp6dsp.o
|
||||
YASM-OBJS-$(CONFIG_VP8_DECODER) += x86/vp8dsp.o \
|
||||
x86/vp8dsp_loopfilter.o
|
||||
YASM-OBJS-$(CONFIG_VP9_DECODER) += x86/vp9dsp.o
|
||||
|
|
|
|||
277
libavcodec/x86/vp9dsp.asm
Normal file
277
libavcodec/x86/vp9dsp.asm
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
;******************************************************************************
|
||||
;* VP9 SIMD optimizations
|
||||
;*
|
||||
;* Copyright (c) 2013 Ronald S. Bultje <rsbultje gmail com>
|
||||
;*
|
||||
;* This file is part of Libav.
|
||||
;*
|
||||
;* Libav 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.
|
||||
;*
|
||||
;* Libav 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 Libav; if not, write to the Free Software
|
||||
;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
;******************************************************************************
|
||||
|
||||
%include "libavutil/x86/x86util.asm"
|
||||
|
||||
SECTION_RODATA
|
||||
|
||||
; FIXME share with vp8dsp.asm
|
||||
pw_256: times 8 dw 256
|
||||
|
||||
%macro F8_TAPS 8
|
||||
times 8 db %1, %2
|
||||
times 8 db %3, %4
|
||||
times 8 db %5, %6
|
||||
times 8 db %7, %8
|
||||
%endmacro
|
||||
; int8_t ff_filters_ssse3[3][15][4][16]
|
||||
const filters_ssse3 ; smooth
|
||||
F8_TAPS -3, -1, 32, 64, 38, 1, -3, 0
|
||||
F8_TAPS -2, -2, 29, 63, 41, 2, -3, 0
|
||||
F8_TAPS -2, -2, 26, 63, 43, 4, -4, 0
|
||||
F8_TAPS -2, -3, 24, 62, 46, 5, -4, 0
|
||||
F8_TAPS -2, -3, 21, 60, 49, 7, -4, 0
|
||||
F8_TAPS -1, -4, 18, 59, 51, 9, -4, 0
|
||||
F8_TAPS -1, -4, 16, 57, 53, 12, -4, -1
|
||||
F8_TAPS -1, -4, 14, 55, 55, 14, -4, -1
|
||||
F8_TAPS -1, -4, 12, 53, 57, 16, -4, -1
|
||||
F8_TAPS 0, -4, 9, 51, 59, 18, -4, -1
|
||||
F8_TAPS 0, -4, 7, 49, 60, 21, -3, -2
|
||||
F8_TAPS 0, -4, 5, 46, 62, 24, -3, -2
|
||||
F8_TAPS 0, -4, 4, 43, 63, 26, -2, -2
|
||||
F8_TAPS 0, -3, 2, 41, 63, 29, -2, -2
|
||||
F8_TAPS 0, -3, 1, 38, 64, 32, -1, -3
|
||||
; regular
|
||||
F8_TAPS 0, 1, -5, 126, 8, -3, 1, 0
|
||||
F8_TAPS -1, 3, -10, 122, 18, -6, 2, 0
|
||||
F8_TAPS -1, 4, -13, 118, 27, -9, 3, -1
|
||||
F8_TAPS -1, 4, -16, 112, 37, -11, 4, -1
|
||||
F8_TAPS -1, 5, -18, 105, 48, -14, 4, -1
|
||||
F8_TAPS -1, 5, -19, 97, 58, -16, 5, -1
|
||||
F8_TAPS -1, 6, -19, 88, 68, -18, 5, -1
|
||||
F8_TAPS -1, 6, -19, 78, 78, -19, 6, -1
|
||||
F8_TAPS -1, 5, -18, 68, 88, -19, 6, -1
|
||||
F8_TAPS -1, 5, -16, 58, 97, -19, 5, -1
|
||||
F8_TAPS -1, 4, -14, 48, 105, -18, 5, -1
|
||||
F8_TAPS -1, 4, -11, 37, 112, -16, 4, -1
|
||||
F8_TAPS -1, 3, -9, 27, 118, -13, 4, -1
|
||||
F8_TAPS 0, 2, -6, 18, 122, -10, 3, -1
|
||||
F8_TAPS 0, 1, -3, 8, 126, -5, 1, 0
|
||||
; sharp
|
||||
F8_TAPS -1, 3, -7, 127, 8, -3, 1, 0
|
||||
F8_TAPS -2, 5, -13, 125, 17, -6, 3, -1
|
||||
F8_TAPS -3, 7, -17, 121, 27, -10, 5, -2
|
||||
F8_TAPS -4, 9, -20, 115, 37, -13, 6, -2
|
||||
F8_TAPS -4, 10, -23, 108, 48, -16, 8, -3
|
||||
F8_TAPS -4, 10, -24, 100, 59, -19, 9, -3
|
||||
F8_TAPS -4, 11, -24, 90, 70, -21, 10, -4
|
||||
F8_TAPS -4, 11, -23, 80, 80, -23, 11, -4
|
||||
F8_TAPS -4, 10, -21, 70, 90, -24, 11, -4
|
||||
F8_TAPS -3, 9, -19, 59, 100, -24, 10, -4
|
||||
F8_TAPS -3, 8, -16, 48, 108, -23, 10, -4
|
||||
F8_TAPS -2, 6, -13, 37, 115, -20, 9, -4
|
||||
F8_TAPS -2, 5, -10, 27, 121, -17, 7, -3
|
||||
F8_TAPS -1, 3, -6, 17, 125, -13, 5, -2
|
||||
F8_TAPS 0, 1, -3, 8, 127, -7, 3, -1
|
||||
|
||||
SECTION .text
|
||||
|
||||
%macro filter_h_fn 1
|
||||
%assign %%px mmsize/2
|
||||
cglobal %1_8tap_1d_h_ %+ %%px, 6, 6, 11, dst, src, dstride, sstride, h, filtery
|
||||
mova m6, [pw_256]
|
||||
mova m7, [filteryq+ 0]
|
||||
%if ARCH_X86_64 && mmsize > 8
|
||||
mova m8, [filteryq+16]
|
||||
mova m9, [filteryq+32]
|
||||
mova m10, [filteryq+48]
|
||||
%endif
|
||||
.loop:
|
||||
movh m0, [srcq-3]
|
||||
movh m1, [srcq-2]
|
||||
movh m2, [srcq-1]
|
||||
movh m3, [srcq+0]
|
||||
movh m4, [srcq+1]
|
||||
movh m5, [srcq+2]
|
||||
punpcklbw m0, m1
|
||||
punpcklbw m2, m3
|
||||
movh m1, [srcq+3]
|
||||
movh m3, [srcq+4]
|
||||
add srcq, sstrideq
|
||||
punpcklbw m4, m5
|
||||
punpcklbw m1, m3
|
||||
pmaddubsw m0, m7
|
||||
%if ARCH_X86_64 && mmsize > 8
|
||||
pmaddubsw m2, m8
|
||||
pmaddubsw m4, m9
|
||||
pmaddubsw m1, m10
|
||||
%else
|
||||
pmaddubsw m2, [filteryq+16]
|
||||
pmaddubsw m4, [filteryq+32]
|
||||
pmaddubsw m1, [filteryq+48]
|
||||
%endif
|
||||
paddw m0, m2
|
||||
paddw m4, m1
|
||||
paddsw m0, m4
|
||||
pmulhrsw m0, m6
|
||||
%ifidn %1, avg
|
||||
movh m1, [dstq]
|
||||
%endif
|
||||
packuswb m0, m0
|
||||
%ifidn %1, avg
|
||||
pavgb m0, m1
|
||||
%endif
|
||||
movh [dstq], m0
|
||||
add dstq, dstrideq
|
||||
dec hd
|
||||
jg .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_MMX ssse3
|
||||
filter_h_fn put
|
||||
filter_h_fn avg
|
||||
|
||||
INIT_XMM ssse3
|
||||
filter_h_fn put
|
||||
filter_h_fn avg
|
||||
|
||||
%macro filter_v_fn 1
|
||||
%assign %%px mmsize/2
|
||||
%if ARCH_X86_64
|
||||
cglobal %1_8tap_1d_v_ %+ %%px, 6, 8, 11, dst, src, dstride, sstride, h, filtery, src4, sstride3
|
||||
%else
|
||||
cglobal %1_8tap_1d_v_ %+ %%px, 4, 7, 11, dst, src, dstride, sstride, filtery, src4, sstride3
|
||||
mov filteryq, r5mp
|
||||
%define hd r4mp
|
||||
%endif
|
||||
sub srcq, sstrideq
|
||||
lea sstride3q, [sstrideq*3]
|
||||
sub srcq, sstrideq
|
||||
mova m6, [pw_256]
|
||||
sub srcq, sstrideq
|
||||
mova m7, [filteryq+ 0]
|
||||
lea src4q, [srcq+sstrideq*4]
|
||||
%if ARCH_X86_64 && mmsize > 8
|
||||
mova m8, [filteryq+16]
|
||||
mova m9, [filteryq+32]
|
||||
mova m10, [filteryq+48]
|
||||
%endif
|
||||
.loop:
|
||||
; FIXME maybe reuse loads from previous rows, or just more generally
|
||||
; unroll this to prevent multiple loads of the same data?
|
||||
movh m0, [srcq]
|
||||
movh m1, [srcq+sstrideq]
|
||||
movh m2, [srcq+sstrideq*2]
|
||||
movh m3, [srcq+sstride3q]
|
||||
movh m4, [src4q]
|
||||
movh m5, [src4q+sstrideq]
|
||||
punpcklbw m0, m1
|
||||
punpcklbw m2, m3
|
||||
movh m1, [src4q+sstrideq*2]
|
||||
movh m3, [src4q+sstride3q]
|
||||
add srcq, sstrideq
|
||||
add src4q, sstrideq
|
||||
punpcklbw m4, m5
|
||||
punpcklbw m1, m3
|
||||
pmaddubsw m0, m7
|
||||
%if ARCH_X86_64 && mmsize > 8
|
||||
pmaddubsw m2, m8
|
||||
pmaddubsw m4, m9
|
||||
pmaddubsw m1, m10
|
||||
%else
|
||||
pmaddubsw m2, [filteryq+16]
|
||||
pmaddubsw m4, [filteryq+32]
|
||||
pmaddubsw m1, [filteryq+48]
|
||||
%endif
|
||||
paddw m0, m2
|
||||
paddw m4, m1
|
||||
paddsw m0, m4
|
||||
pmulhrsw m0, m6
|
||||
%ifidn %1, avg
|
||||
movh m1, [dstq]
|
||||
%endif
|
||||
packuswb m0, m0
|
||||
%ifidn %1, avg
|
||||
pavgb m0, m1
|
||||
%endif
|
||||
movh [dstq], m0
|
||||
add dstq, dstrideq
|
||||
dec hd
|
||||
jg .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
INIT_MMX ssse3
|
||||
filter_v_fn put
|
||||
filter_v_fn avg
|
||||
|
||||
INIT_XMM ssse3
|
||||
filter_v_fn put
|
||||
filter_v_fn avg
|
||||
|
||||
%macro fpel_fn 6
|
||||
%if %2 == 4
|
||||
%define %%srcfn movh
|
||||
%define %%dstfn movh
|
||||
%else
|
||||
%define %%srcfn movu
|
||||
%define %%dstfn mova
|
||||
%endif
|
||||
|
||||
%if %2 <= 16
|
||||
cglobal %1%2, 5, 7, 4, dst, src, dstride, sstride, h, dstride3, sstride3
|
||||
lea sstride3q, [sstrideq*3]
|
||||
lea dstride3q, [dstrideq*3]
|
||||
%else
|
||||
cglobal %1%2, 5, 5, 4, dst, src, dstride, sstride, h
|
||||
%endif
|
||||
.loop:
|
||||
%%srcfn m0, [srcq]
|
||||
%%srcfn m1, [srcq+s%3]
|
||||
%%srcfn m2, [srcq+s%4]
|
||||
%%srcfn m3, [srcq+s%5]
|
||||
lea srcq, [srcq+sstrideq*%6]
|
||||
%ifidn %1, avg
|
||||
pavgb m0, [dstq]
|
||||
pavgb m1, [dstq+d%3]
|
||||
pavgb m2, [dstq+d%4]
|
||||
pavgb m3, [dstq+d%5]
|
||||
%endif
|
||||
%%dstfn [dstq], m0
|
||||
%%dstfn [dstq+d%3], m1
|
||||
%%dstfn [dstq+d%4], m2
|
||||
%%dstfn [dstq+d%5], m3
|
||||
lea dstq, [dstq+dstrideq*%6]
|
||||
sub hd, %6
|
||||
jnz .loop
|
||||
RET
|
||||
%endmacro
|
||||
|
||||
%define d16 16
|
||||
%define s16 16
|
||||
INIT_MMX mmx
|
||||
fpel_fn put, 4, strideq, strideq*2, stride3q, 4
|
||||
fpel_fn put, 8, strideq, strideq*2, stride3q, 4
|
||||
INIT_MMX sse
|
||||
fpel_fn avg, 4, strideq, strideq*2, stride3q, 4
|
||||
fpel_fn avg, 8, strideq, strideq*2, stride3q, 4
|
||||
INIT_XMM sse
|
||||
fpel_fn put, 16, strideq, strideq*2, stride3q, 4
|
||||
fpel_fn put, 32, mmsize, strideq, strideq+mmsize, 2
|
||||
fpel_fn put, 64, mmsize, mmsize*2, mmsize*3, 1
|
||||
INIT_XMM sse2
|
||||
fpel_fn avg, 16, strideq, strideq*2, stride3q, 4
|
||||
fpel_fn avg, 32, mmsize, strideq, strideq+mmsize, 2
|
||||
fpel_fn avg, 64, mmsize, mmsize*2, mmsize*3, 1
|
||||
%undef s16
|
||||
%undef d16
|
||||
245
libavcodec/x86/vp9dsp_init.c
Normal file
245
libavcodec/x86/vp9dsp_init.c
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* VP9 SIMD optimizations
|
||||
*
|
||||
* Copyright (c) 2013 Ronald S. Bultje <rsbultje@gmail.com>
|
||||
*
|
||||
* This file is part of Libav.
|
||||
*
|
||||
* Libav 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.
|
||||
*
|
||||
* Libav 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 Libav; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/cpu.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/x86/asm.h"
|
||||
#include "libavutil/x86/cpu.h"
|
||||
#include "libavcodec/vp9.h"
|
||||
|
||||
#if HAVE_YASM
|
||||
|
||||
#define fpel_func(avg, sz, opt) \
|
||||
void ff_ ## avg ## sz ## _ ## opt(uint8_t *dst, const uint8_t *src, \
|
||||
ptrdiff_t dst_stride, \
|
||||
ptrdiff_t src_stride, \
|
||||
int h, int mx, int my)
|
||||
|
||||
fpel_func(put, 4, mmx);
|
||||
fpel_func(put, 8, mmx);
|
||||
fpel_func(put, 16, sse);
|
||||
fpel_func(put, 32, sse);
|
||||
fpel_func(put, 64, sse);
|
||||
fpel_func(avg, 4, sse);
|
||||
fpel_func(avg, 8, sse);
|
||||
fpel_func(avg, 16, sse2);
|
||||
fpel_func(avg, 32, sse2);
|
||||
fpel_func(avg, 64, sse2);
|
||||
#undef fpel_func
|
||||
|
||||
#define mc_func(avg, sz, dir, opt) \
|
||||
void \
|
||||
ff_ ## avg ## _8tap_1d_ ## dir ## _ ## sz ## _ ## opt(uint8_t *dst, \
|
||||
const uint8_t *src, \
|
||||
ptrdiff_t dst_stride, \
|
||||
ptrdiff_t src_stride, \
|
||||
int h, \
|
||||
const int8_t (*filter)[16])
|
||||
|
||||
#define mc_funcs(sz) \
|
||||
mc_func(put, sz, h, ssse3); \
|
||||
mc_func(avg, sz, h, ssse3); \
|
||||
mc_func(put, sz, v, ssse3); \
|
||||
mc_func(avg, sz, v, ssse3)
|
||||
|
||||
mc_funcs(4);
|
||||
mc_funcs(8);
|
||||
|
||||
#undef mc_funcs
|
||||
#undef mc_func
|
||||
|
||||
#define mc_rep_func(avg, sz, hsz, dir, opt) \
|
||||
static av_always_inline void \
|
||||
ff_ ## avg ## _8tap_1d_ ## dir ## _ ## sz ## _ ## opt(uint8_t *dst, \
|
||||
const uint8_t *src, \
|
||||
ptrdiff_t dst_stride, \
|
||||
ptrdiff_t src_stride, \
|
||||
int h, \
|
||||
const int8_t (*filter)[16]) \
|
||||
{ \
|
||||
ff_ ## avg ## _8tap_1d_ ## dir ## _ ## hsz ## _ ## opt(dst, src, \
|
||||
dst_stride, \
|
||||
src_stride, \
|
||||
h, \
|
||||
filter); \
|
||||
ff_ ## avg ## _8tap_1d_ ## dir ## _ ## hsz ## _ ## opt(dst + hsz, \
|
||||
src + hsz, \
|
||||
dst_stride, \
|
||||
src_stride, \
|
||||
h, filter); \
|
||||
}
|
||||
|
||||
#define mc_rep_funcs(sz, hsz) \
|
||||
mc_rep_func(put, sz, hsz, h, ssse3); \
|
||||
mc_rep_func(avg, sz, hsz, h, ssse3); \
|
||||
mc_rep_func(put, sz, hsz, v, ssse3); \
|
||||
mc_rep_func(avg, sz, hsz, v, ssse3)
|
||||
|
||||
mc_rep_funcs(16, 8);
|
||||
mc_rep_funcs(32, 16);
|
||||
mc_rep_funcs(64, 32);
|
||||
|
||||
#undef mc_rep_funcs
|
||||
#undef mc_rep_func
|
||||
|
||||
extern const int8_t ff_filters_ssse3[3][15][4][16];
|
||||
|
||||
#define filter_8tap_2d_fn(op, sz, f, fname) \
|
||||
static void \
|
||||
op ## _8tap_ ## fname ## _ ## sz ## hv_ssse3(uint8_t *dst, \
|
||||
const uint8_t *src, \
|
||||
ptrdiff_t dst_stride, \
|
||||
ptrdiff_t src_stride, \
|
||||
int h, int mx, int my) \
|
||||
{ \
|
||||
LOCAL_ALIGNED_16(uint8_t, temp, [71 * 64]); \
|
||||
ff_put_8tap_1d_h_ ## sz ## _ssse3(temp, src - 3 * src_stride, \
|
||||
64, src_stride, \
|
||||
h + 7, \
|
||||
ff_filters_ssse3[f][mx - 1]); \
|
||||
ff_ ## op ## _8tap_1d_v_ ## sz ## _ssse3(dst, temp + 3 * 64, \
|
||||
dst_stride, 64, \
|
||||
h, \
|
||||
ff_filters_ssse3[f][my - 1]); \
|
||||
}
|
||||
|
||||
#define filters_8tap_2d_fn(op, sz) \
|
||||
filter_8tap_2d_fn(op, sz, FILTER_8TAP_REGULAR, regular) \
|
||||
filter_8tap_2d_fn(op, sz, FILTER_8TAP_SHARP, sharp) \
|
||||
filter_8tap_2d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth)
|
||||
|
||||
#define filters_8tap_2d_fn2(op) \
|
||||
filters_8tap_2d_fn(op, 64) \
|
||||
filters_8tap_2d_fn(op, 32) \
|
||||
filters_8tap_2d_fn(op, 16) \
|
||||
filters_8tap_2d_fn(op, 8) \
|
||||
filters_8tap_2d_fn(op, 4)
|
||||
|
||||
filters_8tap_2d_fn2(put)
|
||||
filters_8tap_2d_fn2(avg)
|
||||
|
||||
#undef filters_8tap_2d_fn2
|
||||
#undef filters_8tap_2d_fn
|
||||
#undef filter_8tap_2d_fn
|
||||
|
||||
#define filter_8tap_1d_fn(op, sz, f, fname, dir, dvar) \
|
||||
static void \
|
||||
op ## _8tap_ ## fname ## _ ## sz ## dir ## _ssse3(uint8_t *dst, \
|
||||
const uint8_t *src, \
|
||||
ptrdiff_t dst_stride, \
|
||||
ptrdiff_t src_stride, \
|
||||
int h, int mx, \
|
||||
int my) \
|
||||
{ \
|
||||
ff_ ## op ## _8tap_1d_ ## dir ## _ ## sz ## _ssse3(dst, src, \
|
||||
dst_stride, \
|
||||
src_stride, h, \
|
||||
ff_filters_ssse3[f][dvar - 1]); \
|
||||
}
|
||||
|
||||
#define filters_8tap_1d_fn(op, sz, dir, dvar) \
|
||||
filter_8tap_1d_fn(op, sz, FILTER_8TAP_REGULAR, regular, dir, dvar) \
|
||||
filter_8tap_1d_fn(op, sz, FILTER_8TAP_SHARP, sharp, dir, dvar) \
|
||||
filter_8tap_1d_fn(op, sz, FILTER_8TAP_SMOOTH, smooth, dir, dvar)
|
||||
|
||||
#define filters_8tap_1d_fn2(op, sz) \
|
||||
filters_8tap_1d_fn(op, sz, h, mx) \
|
||||
filters_8tap_1d_fn(op, sz, v, my)
|
||||
|
||||
#define filters_8tap_1d_fn3(op) \
|
||||
filters_8tap_1d_fn2(op, 64) \
|
||||
filters_8tap_1d_fn2(op, 32) \
|
||||
filters_8tap_1d_fn2(op, 16) \
|
||||
filters_8tap_1d_fn2(op, 8) \
|
||||
filters_8tap_1d_fn2(op, 4)
|
||||
|
||||
filters_8tap_1d_fn3(put)
|
||||
filters_8tap_1d_fn3(avg)
|
||||
|
||||
#undef filters_8tap_1d_fn
|
||||
#undef filters_8tap_1d_fn2
|
||||
#undef filters_8tap_1d_fn3
|
||||
#undef filter_8tap_1d_fn
|
||||
|
||||
#endif /* HAVE_YASM */
|
||||
|
||||
av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp)
|
||||
{
|
||||
#if HAVE_YASM
|
||||
int cpu_flags = av_get_cpu_flags();
|
||||
|
||||
#define init_fpel(idx1, idx2, sz, type, opt) \
|
||||
dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][0][0] = \
|
||||
dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][0][0] = \
|
||||
dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][0][0] = \
|
||||
dsp->mc[idx1][FILTER_BILINEAR ][idx2][0][0] = ff_ ## type ## sz ## _ ## opt
|
||||
|
||||
|
||||
#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type, opt) \
|
||||
dsp->mc[idx1][FILTER_8TAP_SMOOTH][idx2][idxh][idxv] = type ## _8tap_smooth_ ## sz ## dir ## _ ## opt; \
|
||||
dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = type ## _8tap_regular_ ## sz ## dir ## _ ## opt; \
|
||||
dsp->mc[idx1][FILTER_8TAP_SHARP][idx2][idxh][idxv] = type ## _8tap_sharp_ ## sz ## dir ## _ ## opt
|
||||
|
||||
#define init_subpel2(idx, idxh, idxv, dir, type, opt) \
|
||||
init_subpel1(0, idx, idxh, idxv, 64, dir, type, opt); \
|
||||
init_subpel1(1, idx, idxh, idxv, 32, dir, type, opt); \
|
||||
init_subpel1(2, idx, idxh, idxv, 16, dir, type, opt); \
|
||||
init_subpel1(3, idx, idxh, idxv, 8, dir, type, opt); \
|
||||
init_subpel1(4, idx, idxh, idxv, 4, dir, type, opt)
|
||||
|
||||
#define init_subpel3(idx, type, opt) \
|
||||
init_subpel2(idx, 1, 1, hv, type, opt); \
|
||||
init_subpel2(idx, 0, 1, v, type, opt); \
|
||||
init_subpel2(idx, 1, 0, h, type, opt)
|
||||
|
||||
if (EXTERNAL_MMX(cpu_flags)) {
|
||||
init_fpel(4, 0, 4, put, mmx);
|
||||
init_fpel(3, 0, 8, put, mmx);
|
||||
}
|
||||
|
||||
if (EXTERNAL_SSE(cpu_flags)) {
|
||||
init_fpel(2, 0, 16, put, sse);
|
||||
init_fpel(1, 0, 32, put, sse);
|
||||
init_fpel(0, 0, 64, put, sse);
|
||||
init_fpel(4, 1, 4, avg, sse);
|
||||
init_fpel(3, 1, 8, avg, sse);
|
||||
}
|
||||
|
||||
if (EXTERNAL_SSE2(cpu_flags)) {
|
||||
init_fpel(2, 1, 16, avg, sse2);
|
||||
init_fpel(1, 1, 32, avg, sse2);
|
||||
init_fpel(0, 1, 64, avg, sse2);
|
||||
}
|
||||
|
||||
if (EXTERNAL_SSSE3(cpu_flags)) {
|
||||
init_subpel3(0, put, ssse3);
|
||||
init_subpel3(1, avg, ssse3);
|
||||
}
|
||||
|
||||
#undef init_fpel
|
||||
#undef init_subpel1
|
||||
#undef init_subpel2
|
||||
#undef init_subpel3
|
||||
|
||||
#endif /* HAVE_YASM */
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue