/* * Copyright © 2018, VideoLAN and dav1d authors * Copyright © 2018, Two Orioles, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include <errno.h>#include <limits.h>#include <string.h>#ifndef __plan9__#include <stdio.h>#endif#include <inttypes.h> #include "dav1d/data.h" #include "common/intops.h" #include "src/ctx.h"#include "src/decode.h"#include "src/dequant_tables.h"#include "src/env.h"#include "src/film_grain.h"#include "src/log.h"#include "src/qm.h"#include "src/recon.h"#include "src/ref.h"#include "src/tables.h"#include "src/thread_task.h"#include "src/warpmv.h" static void init_quant_tables(const Dav1dSequenceHeader *const seq_hdr, const Dav1dFrameHeader *const frame_hdr, const int qidx, uint16_t (*dq)[3][2]){ for (int i = 0; i < (frame_hdr->segmentation.enabled ? 8 : 1); i++) { const int yac = frame_hdr->segmentation.enabled ? iclip_u8(qidx + frame_hdr->segmentation.seg_data.d[i].delta_q) : qidx; const int ydc = iclip_u8(yac + frame_hdr->quant.ydc_delta); const int uac = iclip_u8(yac + frame_hdr->quant.uac_delta); const int udc = iclip_u8(yac + frame_hdr->quant.udc_delta); const int vac = iclip_u8(yac + frame_hdr->quant.vac_delta); const int vdc = iclip_u8(yac + frame_hdr->quant.vdc_delta); dq[i][0][0] = dav1d_dq_tbl[seq_hdr->hbd][ydc][0]; dq[i][0][1] = dav1d_dq_tbl[seq_hdr->hbd][yac][1]; dq[i][1][0] = dav1d_dq_tbl[seq_hdr->hbd][udc][0]; dq[i][1][1] = dav1d_dq_tbl[seq_hdr->hbd][uac][1]; dq[i][2][0] = dav1d_dq_tbl[seq_hdr->hbd][vdc][0]; dq[i][2][1] = dav1d_dq_tbl[seq_hdr->hbd][vac][1]; }} static int read_mv_component_diff(Dav1dTileContext *const t, CdfMvComponent *const mv_comp, const int have_fp){ Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; const int have_hp = f->frame_hdr->hp; const int sign = dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->sign); const int cl = dav1d_msac_decode_symbol_adapt16(&ts->msac, mv_comp->classes, 10); int up, fp, hp; if (!cl) { up = dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->class0); if (have_fp) { fp = dav1d_msac_decode_symbol_adapt4(&ts->msac, mv_comp->class0_fp[up], 3); hp = have_hp ? dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->class0_hp) : 1; } else { fp = 3; hp = 1; } } else { up = 1 << cl; for (int n = 0; n < cl; n++) up |= dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->classN[n]) << n; if (have_fp) { fp = dav1d_msac_decode_symbol_adapt4(&ts->msac, mv_comp->classN_fp, 3); hp = have_hp ? dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->classN_hp) : 1; } else { fp = 3; hp = 1; } } const int diff = ((up << 3) | (fp << 1) | hp) + 1; return sign ? -diff : diff;} static void read_mv_residual(Dav1dTileContext *const t, mv *const ref_mv, CdfMvContext *const mv_cdf, const int have_fp){ switch (dav1d_msac_decode_symbol_adapt4(&t->ts->msac, t->ts->cdf.mv.joint, N_MV_JOINTS - 1)) { case MV_JOINT_HV: ref_mv->y += read_mv_component_diff(t, &mv_cdf->comp[0], have_fp); ref_mv->x += read_mv_component_diff(t, &mv_cdf->comp[1], have_fp); break; case MV_JOINT_H: ref_mv->x += read_mv_component_diff(t, &mv_cdf->comp[1], have_fp); break; case MV_JOINT_V: ref_mv->y += read_mv_component_diff(t, &mv_cdf->comp[0], have_fp); break; default: break; }} static void read_tx_tree(Dav1dTileContext *const t, const enum RectTxfmSize from, const int depth, uint16_t *const masks, const int x_off, const int y_off){ const Dav1dFrameContext *const f = t->f; const int bx4 = t->bx & 31, by4 = t->by & 31; const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from]; const int txw = t_dim->lw, txh = t_dim->lh; int is_split; if (depth < 2 && from > (int) TX_4X4) { const int cat = 2 * (TX_64X64 - t_dim->max) - depth; const int a = t->a->tx[bx4] < txw; const int l = t->l.tx[by4] < txh; is_split = dav1d_msac_decode_bool_adapt(&t->ts->msac, t->ts->cdf.m.txpart[cat][a + l]); if (is_split) masks[depth] |= 1 << (y_off * 4 + x_off); } else { is_split = 0; } if (is_split && t_dim->max > TX_8X8) { const enum RectTxfmSize sub = t_dim->sub; const TxfmInfo *const sub_t_dim = &dav1d_txfm_dimensions[sub]; const int txsw = sub_t_dim->w, txsh = sub_t_dim->h; read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 0); t->bx += txsw; if (txw >= txh && t->bx < f->bw) read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 1, y_off * 2 + 0); t->bx -= txsw; t->by += txsh; if (txh >= txw && t->by < f->bh) { read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 1); t->bx += txsw; if (txw >= txh && t->bx < f->bw) read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 1, y_off * 2 + 1); t->bx -= txsw; } t->by -= txsh; } else {#define set_ctx(type, dir, diridx, off, mul, rep_macro) \ rep_macro(type, t->dir tx, off, is_split ? TX_4X4 : mul * txh) case_set_upto16(t_dim->h, l., 1, by4);#undef set_ctx#define set_ctx(type, dir, diridx, off, mul, rep_macro) \ rep_macro(type, t->dir tx, off, is_split ? TX_4X4 : mul * txw) case_set_upto16(t_dim->w, a->, 0, bx4);#undef set_ctx }} static int neg_deinterleave(int diff, int ref, int max) { if (!ref) return diff; if (ref >= (max - 1)) return max - diff - 1; if (2 * ref < max) { if (diff <= 2 * ref) { if (diff & 1) return ref + ((diff + 1) >> 1); else return ref - (diff >> 1); } return diff; } else { if (diff <= 2 * (max - ref - 1)) { if (diff & 1) return ref + ((diff + 1) >> 1); else return ref - (diff >> 1); } return max - (diff + 1); }} static void find_matching_ref(const Dav1dTileContext *const t, const enum EdgeFlags intra_edge_flags, const int bw4, const int bh4, const int w4, const int h4, const int have_left, const int have_top, const int ref, uint64_t masks[2]){ /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5]; int count = 0; int have_topleft = have_top && have_left; int have_topright = imax(bw4, bh4) < 32 && have_top && t->bx + bw4 < t->ts->tiling.col_end && (intra_edge_flags & EDGE_I444_TOP_HAS_RIGHT); #define bs(rp) dav1d_block_dimensions[(rp)->bs]#define matches(rp) ((rp)->ref.ref[0] == ref + 1 && (rp)->ref.ref[1] == -1) if (have_top) { const refmvs_block *r2 = &r[-1][t->bx]; if (matches(r2)) { masks[0] |= 1; count = 1; } int aw4 = bs(r2)[0]; if (aw4 >= bw4) { const int off = t->bx & (aw4 - 1); if (off) have_topleft = 0; if (aw4 - off > bw4) have_topright = 0; } else { unsigned mask = 1 << aw4; for (int x = aw4; x < w4; x += aw4) { r2 += aw4; if (matches(r2)) { masks[0] |= mask; if (++count >= 8) return; } aw4 = bs(r2)[0]; mask <<= aw4; } } } if (have_left) { /*const*/ refmvs_block *const *r2 = r; if (matches(&r2[0][t->bx - 1])) { masks[1] |= 1; if (++count >= 8) return; } int lh4 = bs(&r2[0][t->bx - 1])[1]; if (lh4 >= bh4) { if (t->by & (lh4 - 1)) have_topleft = 0; } else { unsigned mask = 1 << lh4; for (int y = lh4; y < h4; y += lh4) { r2 += lh4; if (matches(&r2[0][t->bx - 1])) { masks[1] |= mask; if (++count >= 8) return; } lh4 = bs(&r2[0][t->bx - 1])[1]; mask <<= lh4; } } } if (have_topleft && matches(&r[-1][t->bx - 1])) { masks[1] |= 1ULL << 32; if (++count >= 8) return; } if (have_topright && matches(&r[-1][t->bx + bw4])) { masks[0] |= 1ULL << 32; }#undef matches} static void derive_warpmv(const Dav1dTileContext *const t, const int bw4, const int bh4, const uint64_t masks[2], const union mv mv, Dav1dWarpedMotionParams *const wmp){ int pts[8][2 /* in, out */][2 /* x, y */], np = 0; /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5]; #define add_sample(dx, dy, sx, sy, rp) do { \ pts[np][0][0] = 16 * (2 * dx + sx * bs(rp)[0]) - 8; \ pts[np][0][1] = 16 * (2 * dy + sy * bs(rp)[1]) - 8; \ pts[np][1][0] = pts[np][0][0] + (rp)->mv.mv[0].x; \ pts[np][1][1] = pts[np][0][1] + (rp)->mv.mv[0].y; \ np++; \} while (0) // use masks[] to find the projectable motion vectors in the edges if ((unsigned) masks[0] == 1 && !(masks[1] >> 32)) { const int off = t->bx & (bs(&r[-1][t->bx])[0] - 1); add_sample(-off, 0, 1, -1, &r[-1][t->bx]); } else for (unsigned off = 0, xmask = (uint32_t) masks[0]; np < 8 && xmask;) { // top const int tz = ctz(xmask); off += tz; xmask >>= tz; add_sample(off, 0, 1, -1, &r[-1][t->bx + off]); xmask &= ~1; } if (np < 8 && masks[1] == 1) { const int off = t->by & (bs(&r[0][t->bx - 1])[1] - 1); add_sample(0, -off, -1, 1, &r[-off][t->bx - 1]); } else for (unsigned off = 0, ymask = (uint32_t) masks[1]; np < 8 && ymask;) { // left const int tz = ctz(ymask); off += tz; ymask >>= tz; add_sample(0, off, -1, 1, &r[off][t->bx - 1]); ymask &= ~1; } if (np < 8 && masks[1] >> 32) // top/left add_sample(0, 0, -1, -1, &r[-1][t->bx - 1]); if (np < 8 && masks[0] >> 32) // top/right add_sample(bw4, 0, 1, -1, &r[-1][t->bx + bw4]); assert(np > 0 && np <= 8);#undef bs // select according to motion vector difference against a threshold int mvd[8], ret = 0; const int thresh = 4 * iclip(imax(bw4, bh4), 4, 28); for (int i = 0; i < np; i++) { mvd[i] = abs(pts[i][1][0] - pts[i][0][0] - mv.x) + abs(pts[i][1][1] - pts[i][0][1] - mv.y); if (mvd[i] > thresh) mvd[i] = -1; else ret++; } if (!ret) { ret = 1; } else for (int i = 0, j = np - 1, k = 0; k < np - ret; k++, i++, j--) { while (mvd[i] != -1) i++; while (mvd[j] == -1) j--; assert(i != j); if (i > j) break; // replace the discarded samples; mvd[i] = mvd[j]; memcpy(pts[i], pts[j], sizeof(*pts)); } if (!dav1d_find_affine_int(pts, ret, bw4, bh4, mv, wmp, t->bx, t->by) && !dav1d_get_shear_params(wmp)) { wmp->type = DAV1D_WM_TYPE_AFFINE; } else wmp->type = DAV1D_WM_TYPE_IDENTITY;} static inline int findoddzero(const uint8_t *buf, int len) { for (int n = 0; n < len; n++) if (!buf[n * 2]) return 1; return 0;} static void read_pal_plane(Dav1dTileContext *const t, Av1Block *const b, const int pl, const int sz_ctx, const int bx4, const int by4){ Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; const int pal_sz = b->pal_sz[pl] = dav1d_msac_decode_symbol_adapt8(&ts->msac, ts->cdf.m.pal_sz[pl][sz_ctx], 6) + 2; uint16_t cache[16], used_cache[8]; int l_cache = pl ? t->pal_sz_uv[1][by4] : t->l.pal_sz[by4]; int n_cache = 0; // don't reuse above palette outside SB64 boundaries int a_cache = by4 & 15 ? pl ? t->pal_sz_uv[0][bx4] : t->a->pal_sz[bx4] : 0; const uint16_t *l = t->al_pal[1][by4][pl], *a = t->al_pal[0][bx4][pl]; // fill/sort cache while (l_cache && a_cache) { if (*l < *a) { if (!n_cache || cache[n_cache - 1] != *l) cache[n_cache++] = *l; l++; l_cache--; } else { if (*a == *l) { l++; l_cache--; } if (!n_cache || cache[n_cache - 1] != *a) cache[n_cache++] = *a; a++; a_cache--; } } if (l_cache) { do { if (!n_cache || cache[n_cache - 1] != *l) cache[n_cache++] = *l; l++; } while (--l_cache > 0); } else if (a_cache) { do { if (!n_cache || cache[n_cache - 1] != *a) cache[n_cache++] = *a; a++; } while (--a_cache > 0); } // find reused cache entries int i = 0; for (int n = 0; n < n_cache && i < pal_sz; n++) if (dav1d_msac_decode_bool_equi(&ts->msac)) used_cache[i++] = cache[n]; const int n_used_cache = i; // parse new entries uint16_t *const pal = f->frame_thread.pass ? f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) + ((t->bx >> 1) + (t->by & 1))][pl] : t->scratch.pal[pl]; if (i < pal_sz) { int prev = pal[i++] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc); if (i < pal_sz) { int bits = f->cur.p.bpc - 3 + dav1d_msac_decode_bools(&ts->msac, 2); const int max = (1 << f->cur.p.bpc) - 1; do { const int delta = dav1d_msac_decode_bools(&ts->msac, bits); prev = pal[i++] = imin(prev + delta + !pl, max); if (prev + !pl >= max) { for (; i < pal_sz; i++) pal[i] = max; break; } bits = imin(bits, 1 + ulog2(max - prev - !pl)); } while (i < pal_sz); } // merge cache+new entries int n = 0, m = n_used_cache; for (i = 0; i < pal_sz; i++) { if (n < n_used_cache && (m >= pal_sz || used_cache[n] <= pal[m])) { pal[i] = used_cache[n++]; } else { assert(m < pal_sz); pal[i] = pal[m++]; } } } else { memcpy(pal, used_cache, n_used_cache * sizeof(*used_cache)); } if (DEBUG_BLOCK_INFO) { printf("Post-pal[pl=%d,sz=%d,cache_size=%d,used_cache=%d]: r=%d, cache=", pl, pal_sz, n_cache, n_used_cache, ts->msac.rng); for (int n = 0; n < n_cache; n++) printf("%c%02x", n ? ' ' : '[', cache[n]); printf("%s, pal=", n_cache ? "]" : "[]"); for (int n = 0; n < pal_sz; n++) printf("%c%02x", n ? ' ' : '[', pal[n]); printf("]\n"); }} static void read_pal_uv(Dav1dTileContext *const t, Av1Block *const b, const int sz_ctx, const int bx4, const int by4){ read_pal_plane(t, b, 1, sz_ctx, bx4, by4); // V pal coding Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; uint16_t *const pal = f->frame_thread.pass ? f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) + ((t->bx >> 1) + (t->by & 1))][2] : t->scratch.pal[2]; if (dav1d_msac_decode_bool_equi(&ts->msac)) { const int bits = f->cur.p.bpc - 4 + dav1d_msac_decode_bools(&ts->msac, 2); int prev = pal[0] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc); const int max = (1 << f->cur.p.bpc) - 1; for (int i = 1; i < b->pal_sz[1]; i++) { int delta = dav1d_msac_decode_bools(&ts->msac, bits); if (delta && dav1d_msac_decode_bool_equi(&ts->msac)) delta = -delta; prev = pal[i] = (prev + delta) & max; } } else { for (int i = 0; i < b->pal_sz[1]; i++) pal[i] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc);Lines 1–500 of 3641. Load more
/* * Copyright © 2018, VideoLAN and dav1d authors * Copyright © 2018, Two Orioles, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include <errno.h> #include <limits.h> #include <string.h> #ifndef __plan9__ #include <stdio.h> #endif #include <inttypes.h> #include "dav1d/data.h" #include "common/intops.h" #include "src/ctx.h" #include "src/decode.h" #include "src/dequant_tables.h" #include "src/env.h" #include "src/film_grain.h" #include "src/log.h" #include "src/qm.h" #include "src/recon.h" #include "src/ref.h" #include "src/tables.h" #include "src/thread_task.h" #include "src/warpmv.h" static void init_quant_tables(const Dav1dSequenceHeader *const seq_hdr, const Dav1dFrameHeader *const frame_hdr, const int qidx, uint16_t (*dq)[3][2]) { for (int i = 0; i < (frame_hdr->segmentation.enabled ? 8 : 1); i++) { const int yac = frame_hdr->segmentation.enabled ? iclip_u8(qidx + frame_hdr->segmentation.seg_data.d[i].delta_q) : qidx; const int ydc = iclip_u8(yac + frame_hdr->quant.ydc_delta); const int uac = iclip_u8(yac + frame_hdr->quant.uac_delta); const int udc = iclip_u8(yac + frame_hdr->quant.udc_delta); const int vac = iclip_u8(yac + frame_hdr->quant.vac_delta); const int vdc = iclip_u8(yac + frame_hdr->quant.vdc_delta); dq[i][0][0] = dav1d_dq_tbl[seq_hdr->hbd][ydc][0]; dq[i][0][1] = dav1d_dq_tbl[seq_hdr->hbd][yac][1]; dq[i][1][0] = dav1d_dq_tbl[seq_hdr->hbd][udc][0]; dq[i][1][1] = dav1d_dq_tbl[seq_hdr->hbd][uac][1]; dq[i][2][0] = dav1d_dq_tbl[seq_hdr->hbd][vdc][0]; dq[i][2][1] = dav1d_dq_tbl[seq_hdr->hbd][vac][1]; } } static int read_mv_component_diff(Dav1dTileContext *const t, CdfMvComponent *const mv_comp, const int have_fp) { Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; const int have_hp = f->frame_hdr->hp; const int sign = dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->sign); const int cl = dav1d_msac_decode_symbol_adapt16(&ts->msac, mv_comp->classes, 10); int up, fp, hp; if (!cl) { up = dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->class0); if (have_fp) { fp = dav1d_msac_decode_symbol_adapt4(&ts->msac, mv_comp->class0_fp[up], 3); hp = have_hp ? dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->class0_hp) : 1; } else { fp = 3; hp = 1; } } else { up = 1 << cl; for (int n = 0; n < cl; n++) up |= dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->classN[n]) << n; if (have_fp) { fp = dav1d_msac_decode_symbol_adapt4(&ts->msac, mv_comp->classN_fp, 3); hp = have_hp ? dav1d_msac_decode_bool_adapt(&ts->msac, mv_comp->classN_hp) : 1; } else { fp = 3; hp = 1; } } const int diff = ((up << 3) | (fp << 1) | hp) + 1; return sign ? -diff : diff; } static void read_mv_residual(Dav1dTileContext *const t, mv *const ref_mv, CdfMvContext *const mv_cdf, const int have_fp) { switch (dav1d_msac_decode_symbol_adapt4(&t->ts->msac, t->ts->cdf.mv.joint, N_MV_JOINTS - 1)) { case MV_JOINT_HV: ref_mv->y += read_mv_component_diff(t, &mv_cdf->comp[0], have_fp); ref_mv->x += read_mv_component_diff(t, &mv_cdf->comp[1], have_fp); break; case MV_JOINT_H: ref_mv->x += read_mv_component_diff(t, &mv_cdf->comp[1], have_fp); break; case MV_JOINT_V: ref_mv->y += read_mv_component_diff(t, &mv_cdf->comp[0], have_fp); break; default: break; } } static void read_tx_tree(Dav1dTileContext *const t, const enum RectTxfmSize from, const int depth, uint16_t *const masks, const int x_off, const int y_off) { const Dav1dFrameContext *const f = t->f; const int bx4 = t->bx & 31, by4 = t->by & 31; const TxfmInfo *const t_dim = &dav1d_txfm_dimensions[from]; const int txw = t_dim->lw, txh = t_dim->lh; int is_split; if (depth < 2 && from > (int) TX_4X4) { const int cat = 2 * (TX_64X64 - t_dim->max) - depth; const int a = t->a->tx[bx4] < txw; const int l = t->l.tx[by4] < txh; is_split = dav1d_msac_decode_bool_adapt(&t->ts->msac, t->ts->cdf.m.txpart[cat][a + l]); if (is_split) masks[depth] |= 1 << (y_off * 4 + x_off); } else { is_split = 0; } if (is_split && t_dim->max > TX_8X8) { const enum RectTxfmSize sub = t_dim->sub; const TxfmInfo *const sub_t_dim = &dav1d_txfm_dimensions[sub]; const int txsw = sub_t_dim->w, txsh = sub_t_dim->h; read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 0); t->bx += txsw; if (txw >= txh && t->bx < f->bw) read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 1, y_off * 2 + 0); t->bx -= txsw; t->by += txsh; if (txh >= txw && t->by < f->bh) { read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 0, y_off * 2 + 1); t->bx += txsw; if (txw >= txh && t->bx < f->bw) read_tx_tree(t, sub, depth + 1, masks, x_off * 2 + 1, y_off * 2 + 1); t->bx -= txsw; } t->by -= txsh; } else { #define set_ctx(type, dir, diridx, off, mul, rep_macro) \ rep_macro(type, t->dir tx, off, is_split ? TX_4X4 : mul * txh) case_set_upto16(t_dim->h, l., 1, by4); #undef set_ctx #define set_ctx(type, dir, diridx, off, mul, rep_macro) \ rep_macro(type, t->dir tx, off, is_split ? TX_4X4 : mul * txw) case_set_upto16(t_dim->w, a->, 0, bx4); #undef set_ctx } } static int neg_deinterleave(int diff, int ref, int max) { if (!ref) return diff; if (ref >= (max - 1)) return max - diff - 1; if (2 * ref < max) { if (diff <= 2 * ref) { if (diff & 1) return ref + ((diff + 1) >> 1); else return ref - (diff >> 1); } return diff; } else { if (diff <= 2 * (max - ref - 1)) { if (diff & 1) return ref + ((diff + 1) >> 1); else return ref - (diff >> 1); } return max - (diff + 1); } } static void find_matching_ref(const Dav1dTileContext *const t, const enum EdgeFlags intra_edge_flags, const int bw4, const int bh4, const int w4, const int h4, const int have_left, const int have_top, const int ref, uint64_t masks[2]) { /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5]; int count = 0; int have_topleft = have_top && have_left; int have_topright = imax(bw4, bh4) < 32 && have_top && t->bx + bw4 < t->ts->tiling.col_end && (intra_edge_flags & EDGE_I444_TOP_HAS_RIGHT); #define bs(rp) dav1d_block_dimensions[(rp)->bs] #define matches(rp) ((rp)->ref.ref[0] == ref + 1 && (rp)->ref.ref[1] == -1) if (have_top) { const refmvs_block *r2 = &r[-1][t->bx]; if (matches(r2)) { masks[0] |= 1; count = 1; } int aw4 = bs(r2)[0]; if (aw4 >= bw4) { const int off = t->bx & (aw4 - 1); if (off) have_topleft = 0; if (aw4 - off > bw4) have_topright = 0; } else { unsigned mask = 1 << aw4; for (int x = aw4; x < w4; x += aw4) { r2 += aw4; if (matches(r2)) { masks[0] |= mask; if (++count >= 8) return; } aw4 = bs(r2)[0]; mask <<= aw4; } } } if (have_left) { /*const*/ refmvs_block *const *r2 = r; if (matches(&r2[0][t->bx - 1])) { masks[1] |= 1; if (++count >= 8) return; } int lh4 = bs(&r2[0][t->bx - 1])[1]; if (lh4 >= bh4) { if (t->by & (lh4 - 1)) have_topleft = 0; } else { unsigned mask = 1 << lh4; for (int y = lh4; y < h4; y += lh4) { r2 += lh4; if (matches(&r2[0][t->bx - 1])) { masks[1] |= mask; if (++count >= 8) return; } lh4 = bs(&r2[0][t->bx - 1])[1]; mask <<= lh4; } } } if (have_topleft && matches(&r[-1][t->bx - 1])) { masks[1] |= 1ULL << 32; if (++count >= 8) return; } if (have_topright && matches(&r[-1][t->bx + bw4])) { masks[0] |= 1ULL << 32; } #undef matches } static void derive_warpmv(const Dav1dTileContext *const t, const int bw4, const int bh4, const uint64_t masks[2], const union mv mv, Dav1dWarpedMotionParams *const wmp) { int pts[8][2 /* in, out */][2 /* x, y */], np = 0; /*const*/ refmvs_block *const *r = &t->rt.r[(t->by & 31) + 5]; #define add_sample(dx, dy, sx, sy, rp) do { \ pts[np][0][0] = 16 * (2 * dx + sx * bs(rp)[0]) - 8; \ pts[np][0][1] = 16 * (2 * dy + sy * bs(rp)[1]) - 8; \ pts[np][1][0] = pts[np][0][0] + (rp)->mv.mv[0].x; \ pts[np][1][1] = pts[np][0][1] + (rp)->mv.mv[0].y; \ np++; \ } while (0) // use masks[] to find the projectable motion vectors in the edges if ((unsigned) masks[0] == 1 && !(masks[1] >> 32)) { const int off = t->bx & (bs(&r[-1][t->bx])[0] - 1); add_sample(-off, 0, 1, -1, &r[-1][t->bx]); } else for (unsigned off = 0, xmask = (uint32_t) masks[0]; np < 8 && xmask;) { // top const int tz = ctz(xmask); off += tz; xmask >>= tz; add_sample(off, 0, 1, -1, &r[-1][t->bx + off]); xmask &= ~1; } if (np < 8 && masks[1] == 1) { const int off = t->by & (bs(&r[0][t->bx - 1])[1] - 1); add_sample(0, -off, -1, 1, &r[-off][t->bx - 1]); } else for (unsigned off = 0, ymask = (uint32_t) masks[1]; np < 8 && ymask;) { // left const int tz = ctz(ymask); off += tz; ymask >>= tz; add_sample(0, off, -1, 1, &r[off][t->bx - 1]); ymask &= ~1; } if (np < 8 && masks[1] >> 32) // top/left add_sample(0, 0, -1, -1, &r[-1][t->bx - 1]); if (np < 8 && masks[0] >> 32) // top/right add_sample(bw4, 0, 1, -1, &r[-1][t->bx + bw4]); assert(np > 0 && np <= 8); #undef bs // select according to motion vector difference against a threshold int mvd[8], ret = 0; const int thresh = 4 * iclip(imax(bw4, bh4), 4, 28); for (int i = 0; i < np; i++) { mvd[i] = abs(pts[i][1][0] - pts[i][0][0] - mv.x) + abs(pts[i][1][1] - pts[i][0][1] - mv.y); if (mvd[i] > thresh) mvd[i] = -1; else ret++; } if (!ret) { ret = 1; } else for (int i = 0, j = np - 1, k = 0; k < np - ret; k++, i++, j--) { while (mvd[i] != -1) i++; while (mvd[j] == -1) j--; assert(i != j); if (i > j) break; // replace the discarded samples; mvd[i] = mvd[j]; memcpy(pts[i], pts[j], sizeof(*pts)); } if (!dav1d_find_affine_int(pts, ret, bw4, bh4, mv, wmp, t->bx, t->by) && !dav1d_get_shear_params(wmp)) { wmp->type = DAV1D_WM_TYPE_AFFINE; } else wmp->type = DAV1D_WM_TYPE_IDENTITY; } static inline int findoddzero(const uint8_t *buf, int len) { for (int n = 0; n < len; n++) if (!buf[n * 2]) return 1; return 0; } static void read_pal_plane(Dav1dTileContext *const t, Av1Block *const b, const int pl, const int sz_ctx, const int bx4, const int by4) { Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; const int pal_sz = b->pal_sz[pl] = dav1d_msac_decode_symbol_adapt8(&ts->msac, ts->cdf.m.pal_sz[pl][sz_ctx], 6) + 2; uint16_t cache[16], used_cache[8]; int l_cache = pl ? t->pal_sz_uv[1][by4] : t->l.pal_sz[by4]; int n_cache = 0; // don't reuse above palette outside SB64 boundaries int a_cache = by4 & 15 ? pl ? t->pal_sz_uv[0][bx4] : t->a->pal_sz[bx4] : 0; const uint16_t *l = t->al_pal[1][by4][pl], *a = t->al_pal[0][bx4][pl]; // fill/sort cache while (l_cache && a_cache) { if (*l < *a) { if (!n_cache || cache[n_cache - 1] != *l) cache[n_cache++] = *l; l++; l_cache--; } else { if (*a == *l) { l++; l_cache--; } if (!n_cache || cache[n_cache - 1] != *a) cache[n_cache++] = *a; a++; a_cache--; } } if (l_cache) { do { if (!n_cache || cache[n_cache - 1] != *l) cache[n_cache++] = *l; l++; } while (--l_cache > 0); } else if (a_cache) { do { if (!n_cache || cache[n_cache - 1] != *a) cache[n_cache++] = *a; a++; } while (--a_cache > 0); } // find reused cache entries int i = 0; for (int n = 0; n < n_cache && i < pal_sz; n++) if (dav1d_msac_decode_bool_equi(&ts->msac)) used_cache[i++] = cache[n]; const int n_used_cache = i; // parse new entries uint16_t *const pal = f->frame_thread.pass ? f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) + ((t->bx >> 1) + (t->by & 1))][pl] : t->scratch.pal[pl]; if (i < pal_sz) { int prev = pal[i++] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc); if (i < pal_sz) { int bits = f->cur.p.bpc - 3 + dav1d_msac_decode_bools(&ts->msac, 2); const int max = (1 << f->cur.p.bpc) - 1; do { const int delta = dav1d_msac_decode_bools(&ts->msac, bits); prev = pal[i++] = imin(prev + delta + !pl, max); if (prev + !pl >= max) { for (; i < pal_sz; i++) pal[i] = max; break; } bits = imin(bits, 1 + ulog2(max - prev - !pl)); } while (i < pal_sz); } // merge cache+new entries int n = 0, m = n_used_cache; for (i = 0; i < pal_sz; i++) { if (n < n_used_cache && (m >= pal_sz || used_cache[n] <= pal[m])) { pal[i] = used_cache[n++]; } else { assert(m < pal_sz); pal[i] = pal[m++]; } } } else { memcpy(pal, used_cache, n_used_cache * sizeof(*used_cache)); } if (DEBUG_BLOCK_INFO) { printf("Post-pal[pl=%d,sz=%d,cache_size=%d,used_cache=%d]: r=%d, cache=", pl, pal_sz, n_cache, n_used_cache, ts->msac.rng); for (int n = 0; n < n_cache; n++) printf("%c%02x", n ? ' ' : '[', cache[n]); printf("%s, pal=", n_cache ? "]" : "[]"); for (int n = 0; n < pal_sz; n++) printf("%c%02x", n ? ' ' : '[', pal[n]); printf("]\n"); } } static void read_pal_uv(Dav1dTileContext *const t, Av1Block *const b, const int sz_ctx, const int bx4, const int by4) { read_pal_plane(t, b, 1, sz_ctx, bx4, by4); // V pal coding Dav1dTileState *const ts = t->ts; const Dav1dFrameContext *const f = t->f; uint16_t *const pal = f->frame_thread.pass ? f->frame_thread.pal[((t->by >> 1) + (t->bx & 1)) * (f->b4_stride >> 1) + ((t->bx >> 1) + (t->by & 1))][2] : t->scratch.pal[2]; if (dav1d_msac_decode_bool_equi(&ts->msac)) { const int bits = f->cur.p.bpc - 4 + dav1d_msac_decode_bools(&ts->msac, 2); int prev = pal[0] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc); const int max = (1 << f->cur.p.bpc) - 1; for (int i = 1; i < b->pal_sz[1]; i++) { int delta = dav1d_msac_decode_bools(&ts->msac, bits); if (delta && dav1d_msac_decode_bool_equi(&ts->msac)) delta = -delta; prev = pal[i] = (prev + delta) & max; } } else { for (int i = 0; i < b->pal_sz[1]; i++) pal[i] = dav1d_msac_decode_bools(&ts->msac, f->cur.p.bpc);