static av_always_inline void mc_dir_part(H264Context *h, Picture *pic, int n, int square, int height, int delta, int list, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int src_x_offset, int src_y_offset, qpel_mc_func *qpix_op, h264_chroma_mc_func chroma_op, int pixel_shift, int chroma_idc) { const int mx = h->mv_cache[list][scan8[n]][0] + src_x_offset * 8; int my = h->mv_cache[list][scan8[n]][1] + src_y_offset * 8; const int luma_xy = (mx & 3) + ((my & 3) << 2); int offset = ((mx >> 2) << pixel_shift) + (my >> 2) * h->mb_linesize; uint8_t *src_y = pic->f.data[0] + offset; uint8_t *src_cb, *src_cr; int extra_width = 0; int extra_height = 0; int emu = 0; const int full_mx = mx >> 2; const int full_my = my >> 2; const int pic_width = 16 * h->mb_width; const int pic_height = 16 * h->mb_height >> MB_FIELD(h); int ysh; if (mx & 7) extra_width -= 3; if (my & 7) extra_height -= 3; if (full_mx < 0 - extra_width || full_my < 0 - extra_height || full_mx + 16 /*FIXME*/ > pic_width + extra_width || full_my + 16 /*FIXME*/ > pic_height + extra_height) { h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_y - (2 << pixel_shift) - 2 * h->mb_linesize, h->mb_linesize, 16 + 5, 16 + 5 /*FIXME*/, full_mx - 2, full_my - 2, pic_width, pic_height); src_y = h->edge_emu_buffer + (2 << pixel_shift) + 2 * h->mb_linesize; emu = 1; } qpix_op[luma_xy](dest_y, src_y, h->mb_linesize); // FIXME try variable height perhaps? if (!square) qpix_op[luma_xy](dest_y + delta, src_y + delta, h->mb_linesize); if (CONFIG_GRAY && h->flags & CODEC_FLAG_GRAY) return; if (chroma_idc == 3 /* yuv444 */) { src_cb = pic->f.data[1] + offset; if (emu) { h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cb - (2 << pixel_shift) - 2 * h->mb_linesize, h->mb_linesize, 16 + 5, 16 + 5 /*FIXME*/, full_mx - 2, full_my - 2, pic_width, pic_height); src_cb = h->edge_emu_buffer + (2 << pixel_shift) + 2 * h->mb_linesize; } qpix_op[luma_xy](dest_cb, src_cb, h->mb_linesize); // FIXME try variable height perhaps? if (!square) qpix_op[luma_xy](dest_cb + delta, src_cb + delta, h->mb_linesize); src_cr = pic->f.data[2] + offset; if (emu) { h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cr - (2 << pixel_shift) - 2 * h->mb_linesize, h->mb_linesize, 16 + 5, 16 + 5 /*FIXME*/, full_mx - 2, full_my - 2, pic_width, pic_height); src_cr = h->edge_emu_buffer + (2 << pixel_shift) + 2 * h->mb_linesize; } qpix_op[luma_xy](dest_cr, src_cr, h->mb_linesize); // FIXME try variable height perhaps? if (!square) qpix_op[luma_xy](dest_cr + delta, src_cr + delta, h->mb_linesize); return; } ysh = 3 - (chroma_idc == 2 /* yuv422 */); if (chroma_idc == 1 /* yuv420 */ && MB_FIELD(h)) { // chroma offset when predicting from a field of opposite parity my += 2 * ((h->mb_y & 1) - (pic->reference - 1)); emu |= (my >> 3) < 0 || (my >> 3) + 8 >= (pic_height >> 1); } src_cb = pic->f.data[1] + ((mx >> 3) << pixel_shift) + (my >> ysh) * h->mb_uvlinesize; src_cr = pic->f.data[2] + ((mx >> 3) << pixel_shift) + (my >> ysh) * h->mb_uvlinesize; if (emu) { h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cb, h->mb_uvlinesize, 9, 8 * chroma_idc + 1, (mx >> 3), (my >> ysh), pic_width >> 1, pic_height >> (chroma_idc == 1 /* yuv420 */)); src_cb = h->edge_emu_buffer; } chroma_op(dest_cb, src_cb, h->mb_uvlinesize, height >> (chroma_idc == 1 /* yuv420 */), mx & 7, (my << (chroma_idc == 2 /* yuv422 */)) & 7); if (emu) { h->vdsp.emulated_edge_mc(h->edge_emu_buffer, src_cr, h->mb_uvlinesize, 9, 8 * chroma_idc + 1, (mx >> 3), (my >> ysh), pic_width >> 1, pic_height >> (chroma_idc == 1 /* yuv420 */)); src_cr = h->edge_emu_buffer; } chroma_op(dest_cr, src_cr, h->mb_uvlinesize, height >> (chroma_idc == 1 /* yuv420 */), mx & 7, (my << (chroma_idc == 2 /* yuv422 */)) & 7); }