static int mc_subpel(DiracContext *s, DiracBlock *block, const uint8_t *src[5], int x, int y, int ref, int plane) { Plane *p = &s->plane[plane]; uint8_t **ref_hpel = s->ref_pics[ref]->hpel[plane]; int motion_x = block->u.mv[ref][0]; int motion_y = block->u.mv[ref][1]; int mx, my, i, epel, nplanes = 0; if (plane) { motion_x >>= s->chroma_x_shift; motion_y >>= s->chroma_y_shift; } mx = motion_x & ~(-1 << s->mv_precision); my = motion_y & ~(-1 << s->mv_precision); motion_x >>= s->mv_precision; motion_y >>= s->mv_precision; /* normalize subpel coordinates to epel */ /* TODO: template this function? */ mx <<= 3 - s->mv_precision; my <<= 3 - s->mv_precision; x += motion_x; y += motion_y; epel = (mx|my)&1; /* hpel position */ if (!((mx|my)&3)) { nplanes = 1; src[0] = ref_hpel[(my>>1)+(mx>>2)] + y*p->stride + x; } else { /* qpel or epel */ nplanes = 4; for (i = 0; i < 4; i++) src[i] = ref_hpel[i] + y*p->stride + x; /* if we're interpolating in the right/bottom halves, adjust the planes as needed we increment x/y because the edge changes for half of the pixels */ if (mx > 4) { src[0] += 1; src[2] += 1; x++; } if (my > 4) { src[0] += p->stride; src[1] += p->stride; y++; } /* hpel planes are: [0]: F [1]: H [2]: V [3]: C */ if (!epel) { /* check if we really only need 2 planes since either mx or my is a hpel position. (epel weights of 0 handle this there) */ if (!(mx&3)) { /* mx == 0: average [0] and [2] mx == 4: average [1] and [3] */ src[!mx] = src[2 + !!mx]; nplanes = 2; } else if (!(my&3)) { src[0] = src[(my>>1) ]; src[1] = src[(my>>1)+1]; nplanes = 2; } } else { /* adjust the ordering if needed so the weights work */ if (mx > 4) { FFSWAP(const uint8_t *, src[0], src[1]); FFSWAP(const uint8_t *, src[2], src[3]); } if (my > 4) { FFSWAP(const uint8_t *, src[0], src[2]); FFSWAP(const uint8_t *, src[1], src[3]); } src[4] = epel_weights[my&3][mx&3]; } } /* fixme: v/h _edge_pos */ if ((unsigned)x > p->width +EDGE_WIDTH/2 - p->xblen || (unsigned)y > p->height+EDGE_WIDTH/2 - p->yblen) { for (i = 0; i < nplanes; i++) { ff_emulated_edge_mc(s->edge_emu_buffer[i], src[i], p->stride, p->xblen, p->yblen, x, y, p->width+EDGE_WIDTH/2, p->height+EDGE_WIDTH/2); src[i] = s->edge_emu_buffer[i]; } } return (nplanes>>1) + epel; }