mirror of https://github.com/FFmpeg/FFmpeg.git
This is following Libav layout to ease merges.pull/131/merge
parent
487ca38e8b
commit
1c9f4b5078
25 changed files with 5502 additions and 5373 deletions
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,137 +0,0 @@ |
||||
/*
|
||||
* 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 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_VP9DSP_H |
||||
#define AVCODEC_VP9DSP_H |
||||
|
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
|
||||
#include "vp9.h" |
||||
|
||||
typedef void (*vp9_mc_func)(uint8_t *dst, ptrdiff_t dst_stride, |
||||
const uint8_t *ref, ptrdiff_t ref_stride, |
||||
int h, int mx, int my); |
||||
typedef void (*vp9_scaled_mc_func)(uint8_t *dst, ptrdiff_t dst_stride, |
||||
const uint8_t *ref, ptrdiff_t ref_stride, |
||||
int h, int mx, int my, int dx, int dy); |
||||
|
||||
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 H.264/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 (0: none, 1: 8tap/bilin) |
||||
* |
||||
* dst/stride are aligned by hsize |
||||
*/ |
||||
vp9_mc_func mc[5][4][2][2][2]; |
||||
|
||||
/*
|
||||
* for scalable MC, first 3 dimensions identical to above, the other two |
||||
* don't exist since it changes per stepsize. |
||||
*/ |
||||
vp9_scaled_mc_func smc[5][4][2]; |
||||
} VP9DSPContext; |
||||
|
||||
|
||||
extern const int16_t ff_vp9_subpel_filters[3][16][8]; |
||||
|
||||
void ff_vp9dsp_init(VP9DSPContext *dsp, int bpp, int bitexact); |
||||
|
||||
void ff_vp9dsp_init_8(VP9DSPContext *dsp); |
||||
void ff_vp9dsp_init_10(VP9DSPContext *dsp); |
||||
void ff_vp9dsp_init_12(VP9DSPContext *dsp); |
||||
|
||||
void ff_vp9dsp_init_aarch64(VP9DSPContext *dsp, int bpp); |
||||
void ff_vp9dsp_init_arm(VP9DSPContext *dsp, int bpp); |
||||
void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact); |
||||
void ff_vp9dsp_init_mips(VP9DSPContext *dsp, int bpp); |
||||
|
||||
#endif /* AVCODEC_VP9DSP_H */ |
@ -0,0 +1,361 @@ |
||||
/*
|
||||
* 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 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 "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 *b = s->b; |
||||
int row = s->row, col = s->col, row7 = s->row7; |
||||
const int8_t (*p)[2] = mv_ref_blk_off[b->bs]; |
||||
#define INVALID_MV 0x80008000U |
||||
uint32_t mem = INVALID_MV, mem_sub8x8 = 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; \
|
||||
av_assert2(idx == 1); \
|
||||
av_assert2(mem != INVALID_MV); \
|
||||
if (mem_sub8x8 == INVALID_MV) { \
|
||||
clamp_mv(&tmp, &mv, s); \
|
||||
m = AV_RN32A(&tmp); \
|
||||
if (m != mem) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
return; \
|
||||
} \
|
||||
mem_sub8x8 = AV_RN32A(&mv); \
|
||||
} else if (mem_sub8x8 != AV_RN32A(&mv)) { \
|
||||
clamp_mv(&tmp, &mv, s); \
|
||||
m = AV_RN32A(&tmp); \
|
||||
if (m != mem) { \
|
||||
AV_WN32A(pmv, m); \
|
||||
} else { \
|
||||
/* BUG I'm pretty sure this isn't the intention */ \
|
||||
AV_WN32A(pmv, 0); \
|
||||
} \
|
||||
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) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[(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->tile_col_start) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[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 this neighbourhood, using same reference frame
|
||||
for (; i < 8; i++) { |
||||
int c = p[i][0] + col, r = p[i][1] + row; |
||||
|
||||
if (c >= s->tile_col_start && c < s->cols && r >= 0 && r < s->rows) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[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->s.h.use_last_frame_mvs) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col]; |
||||
|
||||
if (!s->s.frames[REF_FRAME_MVPAIR].uses_2pass) |
||||
ff_thread_await_progress(&s->s.frames[REF_FRAME_MVPAIR].tf, row >> 3, 0); |
||||
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 this neighbourhood, using different reference frame
|
||||
for (i = 0; i < 8; i++) { |
||||
int c = p[i][0] + col, r = p[i][1] + row; |
||||
|
||||
if (c >= s->tile_col_start && c < s->cols && r >= 0 && r < s->rows) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[CUR_FRAME].mv[r * s->sb_cols * 8 + c]; |
||||
|
||||
if (mv->ref[0] != ref && mv->ref[0] >= 0) { |
||||
RETURN_SCALE_MV(mv->mv[0], s->s.h.signbias[mv->ref[0]] != s->s.h.signbias[ref]); |
||||
} |
||||
if (mv->ref[1] != ref && mv->ref[1] >= 0 && |
||||
// BUG - libvpx has this condition regardless of whether
|
||||
// we used the first ref MV and pre-scaling
|
||||
AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) { |
||||
RETURN_SCALE_MV(mv->mv[1], s->s.h.signbias[mv->ref[1]] != s->s.h.signbias[ref]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// MV at this position in previous frame, using different reference frame
|
||||
if (s->s.h.use_last_frame_mvs) { |
||||
struct VP9mvrefPair *mv = &s->s.frames[REF_FRAME_MVPAIR].mv[row * s->sb_cols * 8 + col]; |
||||
|
||||
// no need to await_progress, because we already did that above
|
||||
if (mv->ref[0] != ref && mv->ref[0] >= 0) { |
||||
RETURN_SCALE_MV(mv->mv[0], s->s.h.signbias[mv->ref[0]] != s->s.h.signbias[ref]); |
||||
} |
||||
if (mv->ref[1] != ref && mv->ref[1] >= 0 && |
||||
// BUG - libvpx has this condition regardless of whether
|
||||
// we used the first ref MV and pre-scaling
|
||||
AV_RN32A(&mv->mv[0]) != AV_RN32A(&mv->mv[1])) { |
||||
RETURN_SCALE_MV(mv->mv[1], s->s.h.signbias[mv->ref[1]] != s->s.h.signbias[ref]); |
||||
} |
||||
} |
||||
|
||||
AV_ZERO32(pmv); |
||||
clamp_mv(pmv, pmv, s); |
||||
#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 *b = s->b; |
||||
|
||||
if (mode == ZEROMV) { |
||||
AV_ZERO64(mv); |
||||
} 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->s.h.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->s.h.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); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,265 @@ |
||||
/*
|
||||
* 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 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 "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; |
||||
|
||||
update_factor = FASTDIV(update_factor * FFMIN(ct, max_count), max_count); |
||||
p1 = *p; |
||||
p2 = ((((int64_t) ct0) << 8) + (ct >> 1)) / ct; |
||||
p2 = av_clip(p2, 1, 255); |
||||
|
||||
// (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->s.h.framectxid].p; |
||||
int uf = (s->s.h.keyframe || s->s.h.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->s.h.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->s.h.keyframe || s->s.h.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->s.h.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->s.h.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->s.h.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->s.h.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->s.h.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->s.h.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); |
||||
} |
||||
} |
Loading…
Reference in new issue