static av_always_inline void mc_luma_scaled(VP9Context *s, vp9_scaled_mc_func smc, vp9_mc_func (*mc)[2], uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *ref, ptrdiff_t ref_stride, ThreadFrame *ref_frame, ptrdiff_t y, ptrdiff_t x, const VP56mv *in_mv, int px, int py, int pw, int ph, int bw, int bh, int w, int h, int bytesperpixel, const uint16_t *scale, const uint8_t *step) { if (s->s.frames[CUR_FRAME].tf.f->width == ref_frame->f->width && s->s.frames[CUR_FRAME].tf.f->height == ref_frame->f->height) { mc_luma_unscaled(s, mc, dst, dst_stride, ref, ref_stride, ref_frame, y, x, in_mv, bw, bh, w, h, bytesperpixel); } else { #define scale_mv(n, dim) (((int64_t)(n) * scale[dim]) >> 14) int mx, my; int refbw_m1, refbh_m1; int th; VP56mv mv; mv.x = av_clip(in_mv->x, -(x + pw - px + 4) * 8, (s->cols * 8 - x + px + 3) * 8); mv.y = av_clip(in_mv->y, -(y + ph - py + 4) * 8, (s->rows * 8 - y + py + 3) * 8); // BUG libvpx seems to scale the two components separately. This introduces // rounding errors but we have to reproduce them to be exactly compatible // with the output from libvpx... mx = scale_mv(mv.x * 2, 0) + scale_mv(x * 16, 0); my = scale_mv(mv.y * 2, 1) + scale_mv(y * 16, 1); y = my >> 4; x = mx >> 4; ref += y * ref_stride + x * bytesperpixel; mx &= 15; my &= 15; refbw_m1 = ((bw - 1) * step[0] + mx) >> 4; refbh_m1 = ((bh - 1) * step[1] + my) >> 4; // FIXME bilinear filter only needs 0/1 pixels, not 3/4 // we use +7 because the last 7 pixels of each sbrow can be changed in // the longest loopfilter of the next sbrow th = (y + refbh_m1 + 4 + 7) >> 6; ff_thread_await_progress(ref_frame, FFMAX(th, 0), 0); if (x < 3 || y < 3 || x + 4 >= w - refbw_m1 || y + 4 >= h - refbh_m1) { s->vdsp.emulated_edge_mc(s->edge_emu_buffer, ref - 3 * ref_stride - 3 * bytesperpixel, 288, ref_stride, refbw_m1 + 8, refbh_m1 + 8, x - 3, y - 3, w, h); ref = s->edge_emu_buffer + 3 * 288 + 3 * bytesperpixel; ref_stride = 288; } smc(dst, dst_stride, ref, ref_stride, bh, mx, my, step[0], step[1]); } }