static inline int predict(int_fast16_t *src, int_fast16_t *last){ const int LT= last[-1]; const int T= last[ 0]; const int L = src[-1]; return mid_pred(L, L + T - LT, T); }
static int16_t *wmv2_pred_motion(Wmv2Context *w, int *px, int *py) { MpegEncContext *const s = &w->s; int xy, wrap, diff, type; int16_t *A, *B, *C, *mot_val; wrap = s->b8_stride; xy = s->block_index[0]; mot_val = s->current_picture.motion_val[0][xy]; A = s->current_picture.motion_val[0][xy - 1]; B = s->current_picture.motion_val[0][xy - wrap]; C = s->current_picture.motion_val[0][xy + 2 - wrap]; if (s->mb_x && !s->first_slice_line && !s->mspel && w->top_left_mv_flag) diff = FFMAX(FFABS(A[0] - B[0]), FFABS(A[1] - B[1])); else diff = 0; if (diff >= 8) type = get_bits1(&s->gb); else type = 2; if (type == 0) { *px = A[0]; *py = A[1]; } else if (type == 1) { *px = B[0]; *py = B[1]; } else { /* special case for first (slice) line */ if (s->first_slice_line) { *px = A[0]; *py = A[1]; } else { *px = mid_pred(A[0], B[0], C[0]); *py = mid_pred(A[1], B[1], C[1]); } } return mot_val; }
static inline void add_median_prediction(uint8_t *dst, uint8_t *src1, uint8_t *diff, int w, int *left, int *left_top){ int i; uint8_t l, lt; l= *left; lt= *left_top; for(i=0; i<w; i++){ l= mid_pred(l, src1[i], (l + src1[i] - lt)&0xFF) + diff[i]; lt= src1[i]; dst[i]= l; } *left= l; *left_top= lt; }
static void add_hfyu_median_prediction_int16_c(uint16_t *dst, const uint16_t *src, const uint16_t *diff, unsigned mask, int w, int *left, int *left_top){ int i; uint16_t l, lt; l = *left; lt = *left_top; for(i=0; i<w; i++){ l = (mid_pred(l, src[i], (l + src[i] - lt) & mask) + diff[i]) & mask; lt = src[i]; dst[i] = l; } *left = l; *left_top = lt; }
static void sub_hfyu_median_prediction_int16_c(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w, int *left, int *left_top){ int i; uint16_t l, lt; l = *left; lt = *left_top; for(i=0; i<w; i++){ const int pred = mid_pred(l, src1[i], (l + src1[i] - lt) & mask); lt = src1[i]; l = src2[i]; dst[i] = (l - pred) & mask; } *left = l; *left_top = lt; }
static void add_hfyu_median_pred_c(uint8_t *dst, const uint8_t *src1, const uint8_t *diff, intptr_t w, int *left, int *left_top) { int i; uint8_t l, lt; l = *left; lt = *left_top; for (i = 0; i < w; i++) { l = mid_pred(l, src1[i], (l + src1[i] - lt) & 0xFF) + diff[i]; lt = src1[i]; dst[i] = l; } *left = l; *left_top = lt; }
static void sub_hfyu_median_pred_c(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, int w, int *left, int *left_top) { int i; uint8_t l, lt; l = *left; lt = *left_top; for (i = 0; i < w; i++) { const int pred = mid_pred(l, src1[i], (l + src1[i] - lt) & 0xFF); lt = src1[i]; l = src2[i]; dst[i] = l - pred; } *left = l; *left_top = lt; }
static void magicyuv_median_pred10(uint16_t *dst, const uint16_t *src1, const uint16_t *diff, intptr_t w, int *left, int *left_top) { int i; uint16_t l, lt; l = *left; lt = *left_top; for (i = 0; i < w; i++) { l = mid_pred(l, src1[i], (l + src1[i] - lt)) + diff[i]; l &= 0x3FF; lt = src1[i]; dst[i] = l; } *left = l; *left_top = lt; }
static void motion_search(RoqContext *enc, int blocksize) { static const motion_vect offsets[8] = { {{ 0,-1}}, {{ 0, 1}}, {{-1, 0}}, {{ 1, 0}}, {{-1, 1}}, {{ 1,-1}}, {{-1,-1}}, {{ 1, 1}}, }; int diff, lowestdiff, oldbest; int off[3]; motion_vect bestpick = {{0,0}}; int i, j, k, offset; motion_vect *last_motion; motion_vect *this_motion; motion_vect vect, vect2; int max=(enc->width/blocksize)*enc->height/blocksize; if (blocksize == 4) { last_motion = enc->last_motion4; this_motion = enc->this_motion4; } else { last_motion = enc->last_motion8; this_motion = enc->this_motion8; } for (i=0; i<enc->height; i+=blocksize) for (j=0; j<enc->width; j+=blocksize) { lowestdiff = eval_motion_dist(enc, j, i, (motion_vect) {{0,0}}, blocksize); bestpick.d[0] = 0; bestpick.d[1] = 0; if (blocksize == 4) EVAL_MOTION(enc->this_motion8[(i/8)*(enc->width/8) + j/8]); offset = (i/blocksize)*enc->width/blocksize + j/blocksize; if (offset < max && offset >= 0) EVAL_MOTION(last_motion[offset]); offset++; if (offset < max && offset >= 0) EVAL_MOTION(last_motion[offset]); offset = (i/blocksize + 1)*enc->width/blocksize + j/blocksize; if (offset < max && offset >= 0) EVAL_MOTION(last_motion[offset]); off[0]= (i/blocksize)*enc->width/blocksize + j/blocksize - 1; off[1]= off[0] - enc->width/blocksize + 1; off[2]= off[1] + 1; if (i) { for(k=0; k<2; k++) vect.d[k]= mid_pred(this_motion[off[0]].d[k], this_motion[off[1]].d[k], this_motion[off[2]].d[k]); EVAL_MOTION(vect); for(k=0; k<3; k++) EVAL_MOTION(this_motion[off[k]]); } else if(j) EVAL_MOTION(this_motion[off[0]]); vect = bestpick; oldbest = -1; while (oldbest != lowestdiff) { oldbest = lowestdiff; for (k=0; k<8; k++) { vect2 = vect; vect2.d[0] += offsets[k].d[0]; vect2.d[1] += offsets[k].d[1]; EVAL_MOTION(vect2); } vect = bestpick; } offset = (i/blocksize)*enc->width/blocksize + j/blocksize; this_motion[offset] = bestpick; } }
static void pred_spatial_direct_motion(H264Context * const h, int *mb_type){ MpegEncContext * const s = &h->s; int b8_stride = 2; int b4_stride = h->b_stride; int mb_xy = h->mb_xy, mb_y = s->mb_y; int mb_type_col[2]; const int16_t (*l1mv0)[2], (*l1mv1)[2]; const int8_t *l1ref0, *l1ref1; const int is_b8x8 = IS_8X8(*mb_type); unsigned int sub_mb_type= MB_TYPE_L0L1; int i8, i4; int ref[2]; int mv[2]; int list; assert(h->ref_list[1][0].f.reference & 3); await_reference_mb_row(h, &h->ref_list[1][0], s->mb_y + !!IS_INTERLACED(*mb_type)); #define MB_TYPE_16x16_OR_INTRA (MB_TYPE_16x16|MB_TYPE_INTRA4x4|MB_TYPE_INTRA16x16|MB_TYPE_INTRA_PCM) /* ref = min(neighbors) */ for(list=0; list<2; list++){ int left_ref = h->ref_cache[list][scan8[0] - 1]; int top_ref = h->ref_cache[list][scan8[0] - 8]; int refc = h->ref_cache[list][scan8[0] - 8 + 4]; const int16_t *C= h->mv_cache[list][ scan8[0] - 8 + 4]; if(refc == PART_NOT_AVAILABLE){ refc = h->ref_cache[list][scan8[0] - 8 - 1]; C = h-> mv_cache[list][scan8[0] - 8 - 1]; } ref[list] = FFMIN3((unsigned)left_ref, (unsigned)top_ref, (unsigned)refc); if(ref[list] >= 0){ //this is just pred_motion() but with the cases removed that cannot happen for direct blocks const int16_t * const A= h->mv_cache[list][ scan8[0] - 1 ]; const int16_t * const B= h->mv_cache[list][ scan8[0] - 8 ]; int match_count= (left_ref==ref[list]) + (top_ref==ref[list]) + (refc==ref[list]); if(match_count > 1){ //most common mv[list]= pack16to32(mid_pred(A[0], B[0], C[0]), mid_pred(A[1], B[1], C[1]) ); }else { assert(match_count==1); if(left_ref==ref[list]){ mv[list]= AV_RN32A(A); }else if(top_ref==ref[list]){ mv[list]= AV_RN32A(B); }else{ mv[list]= AV_RN32A(C); } } }else{ int mask= ~(MB_TYPE_L0 << (2*list)); mv[list] = 0; ref[list] = -1; if(!is_b8x8) *mb_type &= mask; sub_mb_type &= mask; } } if(ref[0] < 0 && ref[1] < 0){ ref[0] = ref[1] = 0; if(!is_b8x8) *mb_type |= MB_TYPE_L0L1; sub_mb_type |= MB_TYPE_L0L1; } if(!(is_b8x8|mv[0]|mv[1])){ fill_rectangle(&h->ref_cache[0][scan8[0]], 4, 4, 8, (uint8_t)ref[0], 1); fill_rectangle(&h->ref_cache[1][scan8[0]], 4, 4, 8, (uint8_t)ref[1], 1); fill_rectangle(&h->mv_cache[0][scan8[0]], 4, 4, 8, 0, 4); fill_rectangle(&h->mv_cache[1][scan8[0]], 4, 4, 8, 0, 4); *mb_type= (*mb_type & ~(MB_TYPE_8x8|MB_TYPE_16x8|MB_TYPE_8x16|MB_TYPE_P1L0|MB_TYPE_P1L1))|MB_TYPE_16x16|MB_TYPE_DIRECT2; return; } if (IS_INTERLACED(h->ref_list[1][0].f.mb_type[mb_xy])) { // AFL/AFR/FR/FL -> AFL/FL if (!IS_INTERLACED(*mb_type)) { // AFR/FR -> AFL/FL mb_y = (s->mb_y&~1) + h->col_parity; mb_xy= s->mb_x + ((s->mb_y&~1) + h->col_parity)*s->mb_stride; b8_stride = 0; }else{ mb_y += h->col_fieldoff; mb_xy += s->mb_stride*h->col_fieldoff; // non zero for FL -> FL & differ parity } goto single_col; }else{ // AFL/AFR/FR/FL -> AFR/FR if(IS_INTERLACED(*mb_type)){ // AFL /FL -> AFR/FR mb_y = s->mb_y&~1; mb_xy= s->mb_x + (s->mb_y&~1)*s->mb_stride; mb_type_col[0] = h->ref_list[1][0].f.mb_type[mb_xy]; mb_type_col[1] = h->ref_list[1][0].f.mb_type[mb_xy + s->mb_stride]; b8_stride = 2+4*s->mb_stride; b4_stride *= 6; if (IS_INTERLACED(mb_type_col[0]) != IS_INTERLACED(mb_type_col[1])) { mb_type_col[0] &= ~MB_TYPE_INTERLACED; mb_type_col[1] &= ~MB_TYPE_INTERLACED; } sub_mb_type |= MB_TYPE_16x16|MB_TYPE_DIRECT2; /* B_SUB_8x8 */ if( (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA) && (mb_type_col[1] & MB_TYPE_16x16_OR_INTRA) && !is_b8x8){ *mb_type |= MB_TYPE_16x8 |MB_TYPE_DIRECT2; /* B_16x8 */ }else{ *mb_type |= MB_TYPE_8x8; } }else{ // AFR/FR -> AFR/FR single_col: mb_type_col[0] = mb_type_col[1] = h->ref_list[1][0].f.mb_type[mb_xy]; sub_mb_type |= MB_TYPE_16x16|MB_TYPE_DIRECT2; /* B_SUB_8x8 */ if(!is_b8x8 && (mb_type_col[0] & MB_TYPE_16x16_OR_INTRA)){ *mb_type |= MB_TYPE_16x16|MB_TYPE_DIRECT2; /* B_16x16 */ }else if(!is_b8x8 && (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16))){ *mb_type |= MB_TYPE_DIRECT2 | (mb_type_col[0] & (MB_TYPE_16x8|MB_TYPE_8x16)); }else{ if(!h->sps.direct_8x8_inference_flag){ /* FIXME save sub mb types from previous frames (or derive from MVs) * so we know exactly what block size to use */ sub_mb_type += (MB_TYPE_8x8-MB_TYPE_16x16); /* B_SUB_4x4 */ } *mb_type |= MB_TYPE_8x8; } } } await_reference_mb_row(h, &h->ref_list[1][0], mb_y); l1mv0 = &h->ref_list[1][0].f.motion_val[0][h->mb2b_xy [mb_xy]]; l1mv1 = &h->ref_list[1][0].f.motion_val[1][h->mb2b_xy [mb_xy]]; l1ref0 = &h->ref_list[1][0].f.ref_index [0][4 * mb_xy]; l1ref1 = &h->ref_list[1][0].f.ref_index [1][4 * mb_xy]; if(!b8_stride){ if(s->mb_y&1){ l1ref0 += 2; l1ref1 += 2; l1mv0 += 2*b4_stride; l1mv1 += 2*b4_stride; } } if(IS_INTERLACED(*mb_type) != IS_INTERLACED(mb_type_col[0])){ int n=0; for(i8=0; i8<4; i8++){ int x8 = i8&1; int y8 = i8>>1; int xy8 = x8+y8*b8_stride; int xy4 = 3*x8+y8*b4_stride; int a,b; if(is_b8x8 && !IS_DIRECT(h->sub_mb_type[i8])) continue; h->sub_mb_type[i8] = sub_mb_type; fill_rectangle(&h->ref_cache[0][scan8[i8*4]], 2, 2, 8, (uint8_t)ref[0], 1); fill_rectangle(&h->ref_cache[1][scan8[i8*4]], 2, 2, 8, (uint8_t)ref[1], 1); if(!IS_INTRA(mb_type_col[y8]) && !h->ref_list[1][0].long_ref && ( (l1ref0[xy8] == 0 && FFABS(l1mv0[xy4][0]) <= 1 && FFABS(l1mv0[xy4][1]) <= 1) || (l1ref0[xy8] < 0 && l1ref1[xy8] == 0 && FFABS(l1mv1[xy4][0]) <= 1 && FFABS(l1mv1[xy4][1]) <= 1))){ a=b=0; if(ref[0] > 0) a= mv[0]; if(ref[1] > 0) b= mv[1]; n++; }else{ a= mv[0]; b= mv[1]; } fill_rectangle(&h->mv_cache[0][scan8[i8*4]], 2, 2, 8, a, 4); fill_rectangle(&h->mv_cache[1][scan8[i8*4]], 2, 2, 8, b, 4); } if(!is_b8x8 && !(n&3)) *mb_type= (*mb_type & ~(MB_TYPE_8x8|MB_TYPE_16x8|MB_TYPE_8x16|MB_TYPE_P1L0|MB_TYPE_P1L1))|MB_TYPE_16x16|MB_TYPE_DIRECT2; }else if(IS_16X16(*mb_type)){
static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; MEContext *s = ctx->priv; AVMotionEstContext *me_ctx = &s->me_ctx; AVFrameSideData *sd; AVFrame *out; int mb_x, mb_y, dir; int32_t mv_count = 0; int ret; if (frame->pts == AV_NOPTS_VALUE) { ret = ff_filter_frame(ctx->outputs[0], frame); return ret; } av_frame_free(&s->prev); s->prev = s->cur; s->cur = s->next; s->next = frame; s->mv_table[2] = memcpy(s->mv_table[2], s->mv_table[1], sizeof(*s->mv_table[1]) * s->b_count); s->mv_table[1] = memcpy(s->mv_table[1], s->mv_table[0], sizeof(*s->mv_table[0]) * s->b_count); if (!s->cur) { s->cur = av_frame_clone(frame); if (!s->cur) return AVERROR(ENOMEM); } if (!s->prev) return 0; out = av_frame_clone(s->cur); if (!out) return AVERROR(ENOMEM); sd = av_frame_new_side_data(out, AV_FRAME_DATA_MOTION_VECTORS, 2 * s->b_count * sizeof(AVMotionVector)); if (!sd) { av_frame_free(&out); return AVERROR(ENOMEM); } me_ctx->data_cur = s->cur->data[0]; me_ctx->linesize = s->cur->linesize[0]; for (dir = 0; dir < 2; dir++) { me_ctx->data_ref = (dir ? s->next : s->prev)->data[0]; if (s->method == AV_ME_METHOD_DS) SEARCH_MV(ds); else if (s->method == AV_ME_METHOD_ESA) SEARCH_MV(esa); else if (s->method == AV_ME_METHOD_FSS) SEARCH_MV(fss); else if (s->method == AV_ME_METHOD_NTSS) SEARCH_MV(ntss); else if (s->method == AV_ME_METHOD_TDLS) SEARCH_MV(tdls); else if (s->method == AV_ME_METHOD_TSS) SEARCH_MV(tss); else if (s->method == AV_ME_METHOD_HEXBS) SEARCH_MV(hexbs); else if (s->method == AV_ME_METHOD_UMH) { for (mb_y = 0; mb_y < s->b_height; mb_y++) for (mb_x = 0; mb_x < s->b_width; mb_x++) { const int mb_i = mb_x + mb_y * s->b_width; const int x_mb = mb_x << s->log2_mb_size; const int y_mb = mb_y << s->log2_mb_size; int mv[2] = {x_mb, y_mb}; AVMotionEstPredictor *preds = me_ctx->preds; preds[0].nb = 0; ADD_PRED(preds[0], 0, 0); //left mb in current frame if (mb_x > 0) ADD_PRED(preds[0], s->mv_table[0][mb_i - 1][dir][0], s->mv_table[0][mb_i - 1][dir][1]); if (mb_y > 0) { //top mb in current frame ADD_PRED(preds[0], s->mv_table[0][mb_i - s->b_width][dir][0], s->mv_table[0][mb_i - s->b_width][dir][1]); //top-right mb in current frame if (mb_x + 1 < s->b_width) ADD_PRED(preds[0], s->mv_table[0][mb_i - s->b_width + 1][dir][0], s->mv_table[0][mb_i - s->b_width + 1][dir][1]); //top-left mb in current frame else if (mb_x > 0) ADD_PRED(preds[0], s->mv_table[0][mb_i - s->b_width - 1][dir][0], s->mv_table[0][mb_i - s->b_width - 1][dir][1]); } //median predictor if (preds[0].nb == 4) { me_ctx->pred_x = mid_pred(preds[0].mvs[1][0], preds[0].mvs[2][0], preds[0].mvs[3][0]); me_ctx->pred_y = mid_pred(preds[0].mvs[1][1], preds[0].mvs[2][1], preds[0].mvs[3][1]); } else if (preds[0].nb == 3) { me_ctx->pred_x = mid_pred(0, preds[0].mvs[1][0], preds[0].mvs[2][0]); me_ctx->pred_y = mid_pred(0, preds[0].mvs[1][1], preds[0].mvs[2][1]); } else if (preds[0].nb == 2) { me_ctx->pred_x = preds[0].mvs[1][0]; me_ctx->pred_y = preds[0].mvs[1][1]; } else { me_ctx->pred_x = 0; me_ctx->pred_y = 0; } ff_me_search_umh(me_ctx, x_mb, y_mb, mv); s->mv_table[0][mb_i][dir][0] = mv[0] - x_mb; s->mv_table[0][mb_i][dir][1] = mv[1] - y_mb; add_mv_data(((AVMotionVector *) sd->data) + mv_count++, me_ctx->mb_size, x_mb, y_mb, mv[0], mv[1], dir); } } else if (s->method == AV_ME_METHOD_EPZS) { for (mb_y = 0; mb_y < s->b_height; mb_y++) for (mb_x = 0; mb_x < s->b_width; mb_x++) { const int mb_i = mb_x + mb_y * s->b_width; const int x_mb = mb_x << s->log2_mb_size; const int y_mb = mb_y << s->log2_mb_size; int mv[2] = {x_mb, y_mb}; AVMotionEstPredictor *preds = me_ctx->preds; preds[0].nb = 0; preds[1].nb = 0; ADD_PRED(preds[0], 0, 0); //left mb in current frame if (mb_x > 0) ADD_PRED(preds[0], s->mv_table[0][mb_i - 1][dir][0], s->mv_table[0][mb_i - 1][dir][1]); //top mb in current frame if (mb_y > 0) ADD_PRED(preds[0], s->mv_table[0][mb_i - s->b_width][dir][0], s->mv_table[0][mb_i - s->b_width][dir][1]); //top-right mb in current frame if (mb_y > 0 && mb_x + 1 < s->b_width) ADD_PRED(preds[0], s->mv_table[0][mb_i - s->b_width + 1][dir][0], s->mv_table[0][mb_i - s->b_width + 1][dir][1]); //median predictor if (preds[0].nb == 4) { me_ctx->pred_x = mid_pred(preds[0].mvs[1][0], preds[0].mvs[2][0], preds[0].mvs[3][0]); me_ctx->pred_y = mid_pred(preds[0].mvs[1][1], preds[0].mvs[2][1], preds[0].mvs[3][1]); } else if (preds[0].nb == 3) { me_ctx->pred_x = mid_pred(0, preds[0].mvs[1][0], preds[0].mvs[2][0]); me_ctx->pred_y = mid_pred(0, preds[0].mvs[1][1], preds[0].mvs[2][1]); } else if (preds[0].nb == 2) { me_ctx->pred_x = preds[0].mvs[1][0]; me_ctx->pred_y = preds[0].mvs[1][1]; } else { me_ctx->pred_x = 0; me_ctx->pred_y = 0; } //collocated mb in prev frame ADD_PRED(preds[0], s->mv_table[1][mb_i][dir][0], s->mv_table[1][mb_i][dir][1]); //accelerator motion vector of collocated block in prev frame ADD_PRED(preds[1], s->mv_table[1][mb_i][dir][0] + (s->mv_table[1][mb_i][dir][0] - s->mv_table[2][mb_i][dir][0]), s->mv_table[1][mb_i][dir][1] + (s->mv_table[1][mb_i][dir][1] - s->mv_table[2][mb_i][dir][1])); //left mb in prev frame if (mb_x > 0) ADD_PRED(preds[1], s->mv_table[1][mb_i - 1][dir][0], s->mv_table[1][mb_i - 1][dir][1]); //top mb in prev frame if (mb_y > 0) ADD_PRED(preds[1], s->mv_table[1][mb_i - s->b_width][dir][0], s->mv_table[1][mb_i - s->b_width][dir][1]); //right mb in prev frame if (mb_x + 1 < s->b_width) ADD_PRED(preds[1], s->mv_table[1][mb_i + 1][dir][0], s->mv_table[1][mb_i + 1][dir][1]); //bottom mb in prev frame if (mb_y + 1 < s->b_height) ADD_PRED(preds[1], s->mv_table[1][mb_i + s->b_width][dir][0], s->mv_table[1][mb_i + s->b_width][dir][1]); ff_me_search_epzs(me_ctx, x_mb, y_mb, mv); s->mv_table[0][mb_i][dir][0] = mv[0] - x_mb; s->mv_table[0][mb_i][dir][1] = mv[1] - y_mb; add_mv_data(((AVMotionVector *) sd->data) + mv_count++, s->mb_size, x_mb, y_mb, mv[0], mv[1], dir); } } } return ff_filter_frame(ctx->outputs[0], out); }