tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

env.h (19366B)


      1 /*
      2 * Copyright © 2018, VideoLAN and dav1d authors
      3 * Copyright © 2018, Two Orioles, LLC
      4 * All rights reserved.
      5 *
      6 * Redistribution and use in source and binary forms, with or without
      7 * modification, are permitted provided that the following conditions are met:
      8 *
      9 * 1. Redistributions of source code must retain the above copyright notice, this
     10 *    list of conditions and the following disclaimer.
     11 *
     12 * 2. Redistributions in binary form must reproduce the above copyright notice,
     13 *    this list of conditions and the following disclaimer in the documentation
     14 *    and/or other materials provided with the distribution.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27 
     28 #ifndef DAV1D_SRC_ENV_H
     29 #define DAV1D_SRC_ENV_H
     30 
     31 #include <stddef.h>
     32 #include <stdint.h>
     33 #include <stdlib.h>
     34 
     35 #include "src/levels.h"
     36 #include "src/refmvs.h"
     37 #include "src/tables.h"
     38 
     39 typedef struct BlockContext {
     40    uint8_t ALIGN(mode[32], 8);
     41    uint8_t ALIGN(lcoef[32], 8);
     42    uint8_t ALIGN(ccoef[2][32], 8);
     43    uint8_t ALIGN(seg_pred[32], 8);
     44    uint8_t ALIGN(skip[32], 8);
     45    uint8_t ALIGN(skip_mode[32], 8);
     46    uint8_t ALIGN(intra[32], 8);
     47    uint8_t ALIGN(comp_type[32], 8);
     48    int8_t ALIGN(ref[2][32], 8); // -1 means intra
     49    uint8_t ALIGN(filter[2][32], 8); // 3 means unset
     50    int8_t ALIGN(tx_intra[32], 8);
     51    int8_t ALIGN(tx[32], 8);
     52    uint8_t ALIGN(tx_lpf_y[32], 8);
     53    uint8_t ALIGN(tx_lpf_uv[32], 8);
     54    uint8_t ALIGN(partition[16], 8);
     55    uint8_t ALIGN(uvmode[32], 8);
     56    uint8_t ALIGN(pal_sz[32], 8);
     57 } BlockContext;
     58 
     59 static inline int get_intra_ctx(const BlockContext *const a,
     60                                const BlockContext *const l,
     61                                const int yb4, const int xb4,
     62                                const int have_top, const int have_left)
     63 {
     64    if (have_left) {
     65        if (have_top) {
     66            const int ctx = l->intra[yb4] + a->intra[xb4];
     67            return ctx + (ctx == 2);
     68        } else
     69            return l->intra[yb4] * 2;
     70    } else {
     71        return have_top ? a->intra[xb4] * 2 : 0;
     72    }
     73 }
     74 
     75 static inline int get_tx_ctx(const BlockContext *const a,
     76                             const BlockContext *const l,
     77                             const TxfmInfo *const max_tx,
     78                             const int yb4, const int xb4)
     79 {
     80    return (l->tx_intra[yb4] >= max_tx->lh) + (a->tx_intra[xb4] >= max_tx->lw);
     81 }
     82 
     83 static inline int get_partition_ctx(const BlockContext *const a,
     84                                    const BlockContext *const l,
     85                                    const enum BlockLevel bl,
     86                                    const int yb8, const int xb8)
     87 {
     88    return ((a->partition[xb8] >> (4 - bl)) & 1) +
     89          (((l->partition[yb8] >> (4 - bl)) & 1) << 1);
     90 }
     91 
     92 static inline unsigned gather_left_partition_prob(const uint16_t *const in,
     93                                                  const enum BlockLevel bl)
     94 {
     95    unsigned out = in[PARTITION_H - 1] - in[PARTITION_H];
     96    // Exploit the fact that cdfs for PARTITION_SPLIT, PARTITION_T_TOP_SPLIT,
     97    // PARTITION_T_BOTTOM_SPLIT and PARTITION_T_LEFT_SPLIT are neighbors.
     98    out += in[PARTITION_SPLIT - 1] - in[PARTITION_T_LEFT_SPLIT];
     99    if (bl != BL_128X128)
    100        out += in[PARTITION_H4 - 1] - in[PARTITION_H4];
    101    return out;
    102 }
    103 
    104 static inline unsigned gather_top_partition_prob(const uint16_t *const in,
    105                                                 const enum BlockLevel bl)
    106 {
    107    // Exploit the fact that cdfs for PARTITION_V, PARTITION_SPLIT and
    108    // PARTITION_T_TOP_SPLIT are neighbors.
    109    unsigned out = in[PARTITION_V - 1] - in[PARTITION_T_TOP_SPLIT];
    110    // Exploit the facts that cdfs for PARTITION_T_LEFT_SPLIT and
    111    // PARTITION_T_RIGHT_SPLIT are neighbors, the probability for
    112    // PARTITION_V4 is always zero, and the probability for
    113    // PARTITION_T_RIGHT_SPLIT is zero in 128x128 blocks.
    114    out += in[PARTITION_T_LEFT_SPLIT - 1];
    115    if (bl != BL_128X128)
    116        out += in[PARTITION_V4 - 1] - in[PARTITION_T_RIGHT_SPLIT];
    117    return out;
    118 }
    119 
    120 static inline enum TxfmType get_uv_inter_txtp(const TxfmInfo *const uvt_dim,
    121                                              const enum TxfmType ytxtp)
    122 {
    123    if (uvt_dim->max == TX_32X32)
    124        return ytxtp == IDTX ? IDTX : DCT_DCT;
    125    if (uvt_dim->min == TX_16X16 &&
    126        ((1 << ytxtp) & ((1 << H_FLIPADST) | (1 << V_FLIPADST) |
    127                         (1 << H_ADST) | (1 << V_ADST))))
    128    {
    129        return DCT_DCT;
    130    }
    131 
    132    return ytxtp;
    133 }
    134 
    135 static inline int get_filter_ctx(const BlockContext *const a,
    136                                 const BlockContext *const l,
    137                                 const int comp, const int dir, const int ref,
    138                                 const int yb4, const int xb4)
    139 {
    140    const int a_filter = (a->ref[0][xb4] == ref || a->ref[1][xb4] == ref) ?
    141                         a->filter[dir][xb4] : DAV1D_N_SWITCHABLE_FILTERS;
    142    const int l_filter = (l->ref[0][yb4] == ref || l->ref[1][yb4] == ref) ?
    143                         l->filter[dir][yb4] : DAV1D_N_SWITCHABLE_FILTERS;
    144 
    145    if (a_filter == l_filter) {
    146        return comp * 4 + a_filter;
    147    } else if (a_filter == DAV1D_N_SWITCHABLE_FILTERS) {
    148        return comp * 4 + l_filter;
    149    } else if (l_filter == DAV1D_N_SWITCHABLE_FILTERS) {
    150        return comp * 4 + a_filter;
    151    } else {
    152        return comp * 4 + DAV1D_N_SWITCHABLE_FILTERS;
    153    }
    154 }
    155 
    156 static inline int get_comp_ctx(const BlockContext *const a,
    157                               const BlockContext *const l,
    158                               const int yb4, const int xb4,
    159                               const int have_top, const int have_left)
    160 {
    161    if (have_top) {
    162        if (have_left) {
    163            if (a->comp_type[xb4]) {
    164                if (l->comp_type[yb4]) {
    165                    return 4;
    166                } else {
    167                    // 4U means intra (-1) or bwd (>= 4)
    168                    return 2 + ((unsigned)l->ref[0][yb4] >= 4U);
    169                }
    170            } else if (l->comp_type[yb4]) {
    171                // 4U means intra (-1) or bwd (>= 4)
    172                return 2 + ((unsigned)a->ref[0][xb4] >= 4U);
    173            } else {
    174                return (l->ref[0][yb4] >= 4) ^ (a->ref[0][xb4] >= 4);
    175            }
    176        } else {
    177            return a->comp_type[xb4] ? 3 : a->ref[0][xb4] >= 4;
    178        }
    179    } else if (have_left) {
    180        return l->comp_type[yb4] ? 3 : l->ref[0][yb4] >= 4;
    181    } else {
    182        return 1;
    183    }
    184 }
    185 
    186 static inline int get_comp_dir_ctx(const BlockContext *const a,
    187                                   const BlockContext *const l,
    188                                   const int yb4, const int xb4,
    189                                   const int have_top, const int have_left)
    190 {
    191 #define has_uni_comp(edge, off) \
    192    ((edge->ref[0][off] < 4) == (edge->ref[1][off] < 4))
    193 
    194    if (have_top && have_left) {
    195        const int a_intra = a->intra[xb4], l_intra = l->intra[yb4];
    196 
    197        if (a_intra && l_intra) return 2;
    198        if (a_intra || l_intra) {
    199            const BlockContext *const edge = a_intra ? l : a;
    200            const int off = a_intra ? yb4 : xb4;
    201 
    202            if (edge->comp_type[off] == COMP_INTER_NONE) return 2;
    203            return 1 + 2 * has_uni_comp(edge, off);
    204        }
    205 
    206        const int a_comp = a->comp_type[xb4] != COMP_INTER_NONE;
    207        const int l_comp = l->comp_type[yb4] != COMP_INTER_NONE;
    208        const int a_ref0 = a->ref[0][xb4], l_ref0 = l->ref[0][yb4];
    209 
    210        if (!a_comp && !l_comp) {
    211            return 1 + 2 * ((a_ref0 >= 4) == (l_ref0 >= 4));
    212        } else if (!a_comp || !l_comp) {
    213            const BlockContext *const edge = a_comp ? a : l;
    214            const int off = a_comp ? xb4 : yb4;
    215 
    216            if (!has_uni_comp(edge, off)) return 1;
    217            return 3 + ((a_ref0 >= 4) == (l_ref0 >= 4));
    218        } else {
    219            const int a_uni = has_uni_comp(a, xb4), l_uni = has_uni_comp(l, yb4);
    220 
    221            if (!a_uni && !l_uni) return 0;
    222            if (!a_uni || !l_uni) return 2;
    223            return 3 + ((a_ref0 == 4) == (l_ref0 == 4));
    224        }
    225    } else if (have_top || have_left) {
    226        const BlockContext *const edge = have_left ? l : a;
    227        const int off = have_left ? yb4 : xb4;
    228 
    229        if (edge->intra[off]) return 2;
    230        if (edge->comp_type[off] == COMP_INTER_NONE) return 2;
    231        return 4 * has_uni_comp(edge, off);
    232    } else {
    233        return 2;
    234    }
    235 }
    236 
    237 static inline int get_poc_diff(const int order_hint_n_bits,
    238                               const int poc0, const int poc1)
    239 {
    240    if (!order_hint_n_bits) return 0;
    241    const int mask = 1 << (order_hint_n_bits - 1);
    242    const int diff = poc0 - poc1;
    243    return (diff & (mask - 1)) - (diff & mask);
    244 }
    245 
    246 static inline int get_jnt_comp_ctx(const int order_hint_n_bits, const int poc,
    247                                   const int ref0poc, const int ref1poc,
    248                                   const BlockContext *const a,
    249                                   const BlockContext *const l,
    250                                   const int yb4, const int xb4)
    251 {
    252    const int d0 = abs(get_poc_diff(order_hint_n_bits, ref0poc, poc));
    253    const int d1 = abs(get_poc_diff(order_hint_n_bits, poc, ref1poc));
    254    const int offset = d0 == d1;
    255    const int a_ctx = a->comp_type[xb4] >= COMP_INTER_AVG ||
    256                      a->ref[0][xb4] == 6;
    257    const int l_ctx = l->comp_type[yb4] >= COMP_INTER_AVG ||
    258                      l->ref[0][yb4] == 6;
    259 
    260    return 3 * offset + a_ctx + l_ctx;
    261 }
    262 
    263 static inline int get_mask_comp_ctx(const BlockContext *const a,
    264                                    const BlockContext *const l,
    265                                    const int yb4, const int xb4)
    266 {
    267    const int a_ctx = a->comp_type[xb4] >= COMP_INTER_SEG ? 1 :
    268                      a->ref[0][xb4] == 6 ? 3 : 0;
    269    const int l_ctx = l->comp_type[yb4] >= COMP_INTER_SEG ? 1 :
    270                      l->ref[0][yb4] == 6 ? 3 : 0;
    271 
    272    return imin(a_ctx + l_ctx, 5);
    273 }
    274 
    275 #define av1_get_ref_2_ctx av1_get_bwd_ref_ctx
    276 #define av1_get_ref_3_ctx av1_get_fwd_ref_ctx
    277 #define av1_get_ref_4_ctx av1_get_fwd_ref_1_ctx
    278 #define av1_get_ref_5_ctx av1_get_fwd_ref_2_ctx
    279 #define av1_get_ref_6_ctx av1_get_bwd_ref_1_ctx
    280 #define av1_get_uni_p_ctx av1_get_ref_ctx
    281 #define av1_get_uni_p2_ctx av1_get_fwd_ref_2_ctx
    282 
    283 static inline int av1_get_ref_ctx(const BlockContext *const a,
    284                                  const BlockContext *const l,
    285                                  const int yb4, const int xb4,
    286                                  int have_top, int have_left)
    287 {
    288    int cnt[2] = { 0 };
    289 
    290    if (have_top && !a->intra[xb4]) {
    291        cnt[a->ref[0][xb4] >= 4]++;
    292        if (a->comp_type[xb4]) cnt[a->ref[1][xb4] >= 4]++;
    293    }
    294 
    295    if (have_left && !l->intra[yb4]) {
    296        cnt[l->ref[0][yb4] >= 4]++;
    297        if (l->comp_type[yb4]) cnt[l->ref[1][yb4] >= 4]++;
    298    }
    299 
    300    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
    301 }
    302 
    303 static inline int av1_get_fwd_ref_ctx(const BlockContext *const a,
    304                                      const BlockContext *const l,
    305                                      const int yb4, const int xb4,
    306                                      const int have_top, const int have_left)
    307 {
    308    int cnt[4] = { 0 };
    309 
    310    if (have_top && !a->intra[xb4]) {
    311        if (a->ref[0][xb4] < 4) cnt[a->ref[0][xb4]]++;
    312        if (a->comp_type[xb4] && a->ref[1][xb4] < 4) cnt[a->ref[1][xb4]]++;
    313    }
    314 
    315    if (have_left && !l->intra[yb4]) {
    316        if (l->ref[0][yb4] < 4) cnt[l->ref[0][yb4]]++;
    317        if (l->comp_type[yb4] && l->ref[1][yb4] < 4) cnt[l->ref[1][yb4]]++;
    318    }
    319 
    320    cnt[0] += cnt[1];
    321    cnt[2] += cnt[3];
    322 
    323    return cnt[0] == cnt[2] ? 1 : cnt[0] < cnt[2] ? 0 : 2;
    324 }
    325 
    326 static inline int av1_get_fwd_ref_1_ctx(const BlockContext *const a,
    327                                        const BlockContext *const l,
    328                                        const int yb4, const int xb4,
    329                                        const int have_top, const int have_left)
    330 {
    331    int cnt[2] = { 0 };
    332 
    333    if (have_top && !a->intra[xb4]) {
    334        if (a->ref[0][xb4] < 2) cnt[a->ref[0][xb4]]++;
    335        if (a->comp_type[xb4] && a->ref[1][xb4] < 2) cnt[a->ref[1][xb4]]++;
    336    }
    337 
    338    if (have_left && !l->intra[yb4]) {
    339        if (l->ref[0][yb4] < 2) cnt[l->ref[0][yb4]]++;
    340        if (l->comp_type[yb4] && l->ref[1][yb4] < 2) cnt[l->ref[1][yb4]]++;
    341    }
    342 
    343    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
    344 }
    345 
    346 static inline int av1_get_fwd_ref_2_ctx(const BlockContext *const a,
    347                                        const BlockContext *const l,
    348                                        const int yb4, const int xb4,
    349                                        const int have_top, const int have_left)
    350 {
    351    int cnt[2] = { 0 };
    352 
    353    if (have_top && !a->intra[xb4]) {
    354        if ((a->ref[0][xb4] ^ 2U) < 2) cnt[a->ref[0][xb4] - 2]++;
    355        if (a->comp_type[xb4] && (a->ref[1][xb4] ^ 2U) < 2) cnt[a->ref[1][xb4] - 2]++;
    356    }
    357 
    358    if (have_left && !l->intra[yb4]) {
    359        if ((l->ref[0][yb4] ^ 2U) < 2) cnt[l->ref[0][yb4] - 2]++;
    360        if (l->comp_type[yb4] && (l->ref[1][yb4] ^ 2U) < 2) cnt[l->ref[1][yb4] - 2]++;
    361    }
    362 
    363    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
    364 }
    365 
    366 static inline int av1_get_bwd_ref_ctx(const BlockContext *const a,
    367                                      const BlockContext *const l,
    368                                      const int yb4, const int xb4,
    369                                      const int have_top, const int have_left)
    370 {
    371    int cnt[3] = { 0 };
    372 
    373    if (have_top && !a->intra[xb4]) {
    374        if (a->ref[0][xb4] >= 4) cnt[a->ref[0][xb4] - 4]++;
    375        if (a->comp_type[xb4] && a->ref[1][xb4] >= 4) cnt[a->ref[1][xb4] - 4]++;
    376    }
    377 
    378    if (have_left && !l->intra[yb4]) {
    379        if (l->ref[0][yb4] >= 4) cnt[l->ref[0][yb4] - 4]++;
    380        if (l->comp_type[yb4] && l->ref[1][yb4] >= 4) cnt[l->ref[1][yb4] - 4]++;
    381    }
    382 
    383    cnt[1] += cnt[0];
    384 
    385    return cnt[2] == cnt[1] ? 1 : cnt[1] < cnt[2] ? 0 : 2;
    386 }
    387 
    388 static inline int av1_get_bwd_ref_1_ctx(const BlockContext *const a,
    389                                        const BlockContext *const l,
    390                                        const int yb4, const int xb4,
    391                                        const int have_top, const int have_left)
    392 {
    393    int cnt[3] = { 0 };
    394 
    395    if (have_top && !a->intra[xb4]) {
    396        if (a->ref[0][xb4] >= 4) cnt[a->ref[0][xb4] - 4]++;
    397        if (a->comp_type[xb4] && a->ref[1][xb4] >= 4) cnt[a->ref[1][xb4] - 4]++;
    398    }
    399 
    400    if (have_left && !l->intra[yb4]) {
    401        if (l->ref[0][yb4] >= 4) cnt[l->ref[0][yb4] - 4]++;
    402        if (l->comp_type[yb4] && l->ref[1][yb4] >= 4) cnt[l->ref[1][yb4] - 4]++;
    403    }
    404 
    405    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
    406 }
    407 
    408 static inline int av1_get_uni_p1_ctx(const BlockContext *const a,
    409                                     const BlockContext *const l,
    410                                     const int yb4, const int xb4,
    411                                     const int have_top, const int have_left)
    412 {
    413    int cnt[3] = { 0 };
    414 
    415    if (have_top && !a->intra[xb4]) {
    416        if (a->ref[0][xb4] - 1U < 3) cnt[a->ref[0][xb4] - 1]++;
    417        if (a->comp_type[xb4] && a->ref[1][xb4] - 1U < 3) cnt[a->ref[1][xb4] - 1]++;
    418    }
    419 
    420    if (have_left && !l->intra[yb4]) {
    421        if (l->ref[0][yb4] - 1U < 3) cnt[l->ref[0][yb4] - 1]++;
    422        if (l->comp_type[yb4] && l->ref[1][yb4] - 1U < 3) cnt[l->ref[1][yb4] - 1]++;
    423    }
    424 
    425    cnt[1] += cnt[2];
    426 
    427    return cnt[0] == cnt[1] ? 1 : cnt[0] < cnt[1] ? 0 : 2;
    428 }
    429 
    430 static inline int get_drl_context(const refmvs_candidate *const ref_mv_stack,
    431                                  const int ref_idx)
    432 {
    433    if (ref_mv_stack[ref_idx].weight >= 640)
    434        return ref_mv_stack[ref_idx + 1].weight < 640;
    435 
    436    return ref_mv_stack[ref_idx + 1].weight < 640 ? 2 : 0;
    437 }
    438 
    439 static inline unsigned get_cur_frame_segid(const int by, const int bx,
    440                                           const int have_top,
    441                                           const int have_left,
    442                                           int *const seg_ctx,
    443                                           const uint8_t *cur_seg_map,
    444                                           const ptrdiff_t stride)
    445 {
    446    cur_seg_map += bx + by * stride;
    447    if (have_left && have_top) {
    448        const int l = cur_seg_map[-1];
    449        const int a = cur_seg_map[-stride];
    450        const int al = cur_seg_map[-(stride + 1)];
    451 
    452        if (l == a && al == l) *seg_ctx = 2;
    453        else if (l == a || al == l || a == al) *seg_ctx = 1;
    454        else *seg_ctx = 0;
    455        return a == al ? a : l;
    456    } else {
    457        *seg_ctx = 0;
    458        return have_left ? cur_seg_map[-1] : have_top ? cur_seg_map[-stride] : 0;
    459    }
    460 }
    461 
    462 static inline void fix_int_mv_precision(mv *const mv) {
    463    mv->x = (mv->x - (mv->x >> 15) + 3) & ~7U;
    464    mv->y = (mv->y - (mv->y >> 15) + 3) & ~7U;
    465 }
    466 
    467 static inline void fix_mv_precision(const Dav1dFrameHeader *const hdr,
    468                                    mv *const mv)
    469 {
    470    if (hdr->force_integer_mv) {
    471        fix_int_mv_precision(mv);
    472    } else if (!hdr->hp) {
    473        mv->x = (mv->x - (mv->x >> 15)) & ~1U;
    474        mv->y = (mv->y - (mv->y >> 15)) & ~1U;
    475    }
    476 }
    477 
    478 static inline mv get_gmv_2d(const Dav1dWarpedMotionParams *const gmv,
    479                            const int bx4, const int by4,
    480                            const int bw4, const int bh4,
    481                            const Dav1dFrameHeader *const hdr)
    482 {
    483    switch (gmv->type) {
    484    case DAV1D_WM_TYPE_ROT_ZOOM:
    485        assert(gmv->matrix[5] ==  gmv->matrix[2]);
    486        assert(gmv->matrix[4] == -gmv->matrix[3]);
    487        // fall-through
    488    default:
    489    case DAV1D_WM_TYPE_AFFINE: {
    490        const int x = bx4 * 4 + bw4 * 2 - 1;
    491        const int y = by4 * 4 + bh4 * 2 - 1;
    492        const int xc = (gmv->matrix[2] - (1 << 16)) * x +
    493                       gmv->matrix[3] * y + gmv->matrix[0];
    494        const int yc = (gmv->matrix[5] - (1 << 16)) * y +
    495                       gmv->matrix[4] * x + gmv->matrix[1];
    496        const int shift = 16 - (3 - !hdr->hp);
    497        const int round = (1 << shift) >> 1;
    498        mv res = (mv) {
    499            .y = apply_sign(((abs(yc) + round) >> shift) << !hdr->hp, yc),
    500            .x = apply_sign(((abs(xc) + round) >> shift) << !hdr->hp, xc),
    501        };
    502        if (hdr->force_integer_mv)
    503            fix_int_mv_precision(&res);
    504        return res;
    505    }
    506    case DAV1D_WM_TYPE_TRANSLATION: {
    507        mv res = (mv) {
    508            .y = gmv->matrix[0] >> 13,
    509            .x = gmv->matrix[1] >> 13,
    510        };
    511        if (hdr->force_integer_mv)
    512            fix_int_mv_precision(&res);
    513        return res;
    514    }
    515    case DAV1D_WM_TYPE_IDENTITY:
    516        return (mv) { .x = 0, .y = 0 };
    517    }
    518 }
    519 
    520 #endif /* DAV1D_SRC_ENV_H */