/* * 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
*/
staticvoid vp9_report_tile_progress(VP9Context *s, int field, int n) {
pthread_mutex_lock(&s->progress_mutex);
atomic_fetch_add_explicit(&s->entries[field], n, memory_order_release);
pthread_cond_signal(&s->progress_cond);
pthread_mutex_unlock(&s->progress_mutex);
}
staticvoid vp9_await_tile_progress(VP9Context *s, int field, int n) { if (atomic_load_explicit(&s->entries[field], memory_order_acquire) >= n) return;
// The sign bit is at the end, not the start, of a bit sequence static av_always_inline int get_sbits_inv(GetBitContext *gb, int n)
{ int v = get_bits(gb, n); return get_bits1(gb) ? -v : v;
}
static av_always_inline int inv_recenter_nonneg(int v, int m)
{ if (v > 2 * m) return v; if (v & 1) return m - ((v + 1) >> 1); return m + (v >> 1);
}
/* This code is trying to do a differential probability update. For a * current probability A in the range [1, 255], the difference to a new * probability of any value can be expressed differentially as 1-A, 255-A * where some part of this (absolute range) exists both in positive as * well as the negative part, whereas another part only exists in one * half. We're trying to code this shared part differentially, i.e. * times two where the value of the lowest bit specifies the sign, and * the single part is then coded on top of this. This absolute difference * then again has a value of [0, 254], but a bigger value in this range * indicates that we're further away from the original value A, so we * can code this as a VLC code, since higher values are increasingly * unlikely. The first 20 values in inv_map_table[] allow 'cheap, rough' * updates vs. the 'fine, exact' updates further down the range, which
* adds one extra dimension to this differential update model. */
if (!vp89_rac_get(c)) {
d = vp89_rac_get_uint(c, 4) + 0;
} elseif (!vp89_rac_get(c)) {
d = vp89_rac_get_uint(c, 4) + 16;
} elseif (!vp89_rac_get(c)) {
d = vp89_rac_get_uint(c, 5) + 32;
} else {
d = vp89_rac_get_uint(c, 7); if (d >= 65)
d = (d << 1) - 65 + vp89_rac_get(c);
d += 64;
av_assert2(d < FF_ARRAY_ELEMS(inv_map_table));
}
return p <= 128 ? 1 + inv_recenter_nonneg(inv_map_table[d], p - 1) :
255 - inv_recenter_nonneg(inv_map_table[d], 255 - p);
}
staticint decode_frame_header(AVCodecContext *avctx, const uint8_t *data, int size, int *ref)
{
VP9Context *s = avctx->priv_data; int c, i, j, k, l, m, n, w, h, max, size2, ret, sharp; int last_invisible; const uint8_t *data2;
/* general header */ if ((ret = init_get_bits8(&s->gb, data, size)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Failed to initialize bitstream reader\n"); return ret;
} if (get_bits(&s->gb, 2) != 0x2) { // frame marker
av_log(avctx, AV_LOG_ERROR, "Invalid frame marker\n"); return AVERROR_INVALIDDATA;
}
avctx->profile = get_bits1(&s->gb);
avctx->profile |= get_bits1(&s->gb) << 1; if (avctx->profile == 3) avctx->profile += get_bits1(&s->gb); if (avctx->profile > 3) {
av_log(avctx, AV_LOG_ERROR, "Profile %d is not yet supported\n", avctx->profile); return AVERROR_INVALIDDATA;
}
s->s.h.profile = avctx->profile; if (get_bits1(&s->gb)) {
*ref = get_bits(&s->gb, 3); return 0;
}
/* segmentation header info */ if ((s->s.h.segmentation.enabled = get_bits1(&s->gb))) { if ((s->s.h.segmentation.update_map = get_bits1(&s->gb))) { for (i = 0; i < 7; i++)
s->s.h.segmentation.prob[i] = get_bits1(&s->gb) ?
get_bits(&s->gb, 8) : 255; if ((s->s.h.segmentation.temporal = get_bits1(&s->gb))) for (i = 0; i < 3; i++)
s->s.h.segmentation.pred_prob[i] = get_bits1(&s->gb) ?
get_bits(&s->gb, 8) : 255;
}
if (get_bits1(&s->gb)) {
s->s.h.segmentation.absolute_vals = get_bits1(&s->gb); for (i = 0; i < 8; i++) { if ((s->s.h.segmentation.feat[i].q_enabled = get_bits1(&s->gb)))
s->s.h.segmentation.feat[i].q_val = get_sbits_inv(&s->gb, 8); if ((s->s.h.segmentation.feat[i].lf_enabled = get_bits1(&s->gb)))
s->s.h.segmentation.feat[i].lf_val = get_sbits_inv(&s->gb, 6); if ((s->s.h.segmentation.feat[i].ref_enabled = get_bits1(&s->gb)))
s->s.h.segmentation.feat[i].ref_val = get_bits(&s->gb, 2);
s->s.h.segmentation.feat[i].skip_enabled = get_bits1(&s->gb);
}
}
} else { // Reset fields under segmentation switch if segmentation is disabled. // This is necessary because some hwaccels don't ignore these fields // if segmentation is disabled.
s->s.h.segmentation.temporal = 0;
s->s.h.segmentation.update_map = 0;
}
// set qmul[] based on Y/UV, AC/DC and segmentation Q idx deltas for (i = 0; i < (s->s.h.segmentation.enabled ? 8 : 1); i++) { int qyac, qydc, quvac, quvdc, lflvl, sh;
// next 16 bits is size of the rest of the header (arith-coded)
s->s.h.compressed_header_size = size2 = get_bits(&s->gb, 16);
s->s.h.uncompressed_header_size = (get_bits_count(&s->gb) + 7) / 8;
if (vpx_rac_get_prob_branchy(&s->c, 128)) { // marker bit
av_log(avctx, AV_LOG_ERROR, "Marker bit was set\n"); return AVERROR_INVALIDDATA;
}
for (i = 0; i < s->active_tile_cols; i++) { if (s->s.h.keyframe || s->s.h.intraonly) {
memset(s->td[i].counts.coef, 0, sizeof(s->td[0].counts.coef));
memset(s->td[i].counts.eob, 0, sizeof(s->td[0].counts.eob));
} else {
memset(&s->td[i].counts, 0, sizeof(s->td[0].counts));
}
s->td[i].nb_block_structure = 0;
}
/* FIXME is it faster to not copy here, but do it down in the fw updates * as explicit copies if the fw update is missing (and skip the copy upon
* fw update)? */
s->prob.p = s->prob_ctx[c].p;
if (s->s.h.txfmmode == TX_SWITCHABLE) { for (i = 0; i < 2; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.tx8p[i] = update_prob(&s->c, s->prob.p.tx8p[i]); for (i = 0; i < 2; i++) for (j = 0; j < 2; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.tx16p[i][j] =
update_prob(&s->c, s->prob.p.tx16p[i][j]); for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.tx32p[i][j] =
update_prob(&s->c, s->prob.p.tx32p[i][j]);
}
}
// coef updates for (i = 0; i < 4; i++) {
uint8_t (*ref)[2][6][6][3] = s->prob_ctx[c].coef[i]; if (vp89_rac_get(&s->c)) { 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 *p = s->prob.coef[i][j][k][l][m];
uint8_t *r = ref[j][k][l][m]; if (m >= 3 && l == 0) // dc only has 3 pt break; for (n = 0; n < 3; n++) { if (vpx_rac_get_prob_branchy(&s->c, 252))
p[n] = update_prob(&s->c, r[n]); else
p[n] = r[n];
}
memcpy(&p[3], ff_vp9_model_pareto8[p[2]], 8);
}
} else { 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 *p = s->prob.coef[i][j][k][l][m];
uint8_t *r = ref[j][k][l][m]; if (m > 3 && l == 0) // dc only has 3 pt break;
memcpy(p, r, 3);
memcpy(&p[3], ff_vp9_model_pareto8[p[2]], 8);
}
} if (s->s.h.txfmmode == i) break;
}
// mode updates for (i = 0; i < 3; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.skip[i] = update_prob(&s->c, s->prob.p.skip[i]); if (!s->s.h.keyframe && !s->s.h.intraonly) { for (i = 0; i < 7; i++) for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_mode[i][j] =
update_prob(&s->c, s->prob.p.mv_mode[i][j]);
if (s->s.h.filtermode == FILTER_SWITCHABLE) for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.filter[i][j] =
update_prob(&s->c, s->prob.p.filter[i][j]);
for (i = 0; i < 4; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.intra[i] = update_prob(&s->c, s->prob.p.intra[i]);
if (s->s.h.allowcompinter) {
s->s.h.comppredmode = vp89_rac_get(&s->c); if (s->s.h.comppredmode)
s->s.h.comppredmode += vp89_rac_get(&s->c); if (s->s.h.comppredmode == PRED_SWITCHABLE) for (i = 0; i < 5; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.comp[i] =
update_prob(&s->c, s->prob.p.comp[i]);
} else {
s->s.h.comppredmode = PRED_SINGLEREF;
}
if (s->s.h.comppredmode != PRED_COMPREF) { for (i = 0; i < 5; i++) { if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.single_ref[i][0] =
update_prob(&s->c, s->prob.p.single_ref[i][0]); if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.single_ref[i][1] =
update_prob(&s->c, s->prob.p.single_ref[i][1]);
}
}
if (s->s.h.comppredmode != PRED_SINGLEREF) { for (i = 0; i < 5; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.comp_ref[i] =
update_prob(&s->c, s->prob.p.comp_ref[i]);
}
for (i = 0; i < 4; i++) for (j = 0; j < 9; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.y_mode[i][j] =
update_prob(&s->c, s->prob.p.y_mode[i][j]);
for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) for (k = 0; k < 3; k++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.partition[3 - i][j][k] =
update_prob(&s->c,
s->prob.p.partition[3 - i][j][k]);
// mv fields don't use the update_prob subexp model for some reason for (i = 0; i < 3; i++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_joint[i] = (vp89_rac_get_uint(&s->c, 7) << 1) | 1;
for (i = 0; i < 2; i++) { if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].sign =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
for (j = 0; j < 10; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].classes[j] =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
for (j = 0; j < 10; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].bits[j] =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
}
for (i = 0; i < 2; i++) { for (j = 0; j < 2; j++) for (k = 0; k < 3; k++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].class0_fp[j][k] =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
for (j = 0; j < 3; j++) if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].fp[j] =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
}
if (s->s.h.highprecisionmvs) { for (i = 0; i < 2; i++) { if (vpx_rac_get_prob_branchy(&s->c, 252))
s->prob.p.mv_comp[i].class0_hp =
(vp89_rac_get_uint(&s->c, 7) << 1) | 1;
staticvoid set_tile_offset(int *start, int *end, int idx, int log2_n, int n)
{ int sb_start = ( idx * n) >> log2_n; int sb_end = ((idx + 1) * n) >> log2_n;
*start = FFMIN(sb_start, n) << 3;
*end = FFMIN(sb_end, n) << 3;
}
staticvoid free_buffers(VP9Context *s)
{ int i;
av_freep(&s->intra_pred_data[0]); for (i = 0; i < s->active_tile_cols; i++)
vp9_tile_data_free(&s->td[i]);
}
static av_cold int vp9_decode_free(AVCodecContext *avctx)
{
VP9Context *s = avctx->priv_data; int i;
for (int i = 0; i < 3; i++)
vp9_frame_unref(&s->s.frames[i]);
av_refstruct_pool_uninit(&s->frame_extradata_pool); for (i = 0; i < 8; i++) {
ff_progress_frame_unref(&s->s.refs[i]);
ff_progress_frame_unref(&s->next_refs[i]);
}
for (col = tile_col_start;
col < tile_col_end;
col += 8, yoff2 += 64 * bytesperpixel,
uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) { // FIXME integrate with lf code (i.e. zero after each // use, similar to invtxfm coefficients, or similar) if (s->pass != 1) {
memset(lflvl_ptr->mask, 0, sizeof(lflvl_ptr->mask));
}
// loopfilter one row if (s->s.h.filter.level) {
yoff2 = yoff;
uvoff2 = uvoff;
lflvl_ptr = s->lflvl; for (col = 0; col < s->cols;
col += 8, yoff2 += 64 * bytesperpixel,
uvoff2 += 64 * bytesperpixel >> s->ss_h, lflvl_ptr++) {
ff_vp9_loopfilter_sb(avctx, lflvl_ptr, row, col,
yoff2, uvoff2);
}
}
// FIXME maybe we can make this more finegrained by running the // loopfilter per-block instead of after each sbrow // In fact that would also make intra pred left preparation easier?
ff_progress_frame_report(&s->s.frames[CUR_FRAME].tf, row >> 3);
}
} return 0;
}
#if HAVE_THREADS static av_always_inline int decode_tiles_mt(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr)
{
VP9Context *s = avctx->priv_data;
VP9TileData *td = &s->td[jobnr];
ptrdiff_t uvoff, yoff, ls_y, ls_uv; int bytesperpixel = s->bytesperpixel, row, col, tile_row; unsigned tile_cols_len; int tile_row_start, tile_row_end, tile_col_start, tile_col_end;
VP9Filter *lflvl_ptr_base;
AVFrame *f;
f = s->s.frames[CUR_FRAME].tf.f;
ls_y = f->linesize[0];
ls_uv =f->linesize[1];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.