📄 fame_motion_pmvfast.c
字号:
/* Updates the motion vector and the location in the window ("current") */ if((best_dx | best_dy) != 0) { mv->dx += best_dx; mv->dy += best_dy; if(--count) current_table = &(table[last_motion]); else return; } else return; }}static fame_motion_coding_t pmvfast_estimation(fame_motion_t *motion, int mb_x, int mb_y, fame_motion_vector_t *vectors, unsigned char quant){ int k; int pitch; int x, y, width, height; int offset[4]; int edged_offset[4]; compute_error_t eval_error; fame_motion_vector_t pmv; fame_motion_vector_t *pvector; fame_motion_vector_t *plast; fame_motion_vector_t *pvector_left, *pvector_topleft; fame_motion_vector_t *pvector_top, *pvector_topright; unsigned int weight_left, weight_top, weight_topright; unsigned char *shape; unsigned char *current; fame_yuv_t **ref; int use_median; int threshold0; int threshold1; int threshold2; int sad_inter4v, sad_inter, mad_inter, count; int range; int pred_same; int fcode; int is_left, is_top, is_topright; int diamond_count; int sad_last; int unrestricted; fame_motion_coding_t motion_coding; fcode = motion->fcode;#if DEBUG fprintf(debug_log, "\n***** macroblock : mb_y=%u mb_x=%u *****\n", mb_y, mb_x);#endif /* ***** Initialization ***** */ eval_error = motion->MAE8x8; x = mb_x << 4; y = mb_y << 4; width = motion->mb_width << 4; height = motion->mb_height << 4; shape = motion->shape; current = motion->current->y; pitch = motion->current->p; ref = motion->ref; range = motion->search_range; unrestricted = (motion->flags & FAME_MOTION_UNRESTRICTED_SEARCH)?1:0; offset[0] = y * pitch + x; offset[1] = y * pitch + x+8; offset[2] = (y+8) * pitch + x; offset[3] = (y+8) * pitch + x+8; edged_offset[0] = y * (pitch+32) + x; edged_offset[1] = y * (pitch+32) + x+8; edged_offset[2] = (y+8) * (pitch+32) + x; edged_offset[3] = (y+8) * (pitch+32) + x+8; if(motion->shape) { vectors[0].count = mad_withmask(current+offset[0], shape+offset[0], pitch, &vectors[0].deviation); vectors[1].count = mad_withmask(current+offset[1], shape+offset[1], pitch, &vectors[1].deviation); vectors[2].count = mad_withmask(current+offset[2], shape+offset[2], pitch, &vectors[2].deviation); vectors[3].count = mad_withmask(current+offset[3], shape+offset[3], pitch, &vectors[3].deviation); } else { vectors[0].count = mad_withoutmask(current+offset[0], pitch, &vectors[0].deviation); vectors[1].count = mad_withoutmask(current+offset[1], pitch, &vectors[1].deviation); vectors[2].count = mad_withoutmask(current+offset[2], pitch, &vectors[2].deviation); vectors[3].count = mad_withoutmask(current+offset[3], pitch, &vectors[3].deviation); } /* integer sample search */ /* Step1 : vectors around the current macroblock */ pvector = FAME_MOTION_PMVFAST(motion)->vectors[0] + (mb_y*motion->mb_width + mb_x)*4; plast = FAME_MOTION_PMVFAST(motion)->vectors[0] + (mb_y*motion->mb_width + mb_x)*4; pvector_left = pvector - 4; pvector_topleft = pvector - 4*motion->mb_width - 4; pvector_top = pvector - 4*motion->mb_width; pvector_topright = pvector - 4*motion->mb_width + 4; is_left = mb_x > 0; is_top = mb_y > 0; is_topright = is_top & (mb_x < motion->mb_width - 1); pred_same = 0; diamond_count = 2*range; if(is_left && is_topright /* && is_top */) { /* all vectors are valid */ if(pvector_left->dx == pvector_top->dx && pvector_left->dy == pvector_top->dy && pvector_left->dx == pvector_topright->dx && pvector_left->dy == pvector_topright->dy) /* all vectors are equal : do only one diamond search step */ diamond_count = 1; } /* Compute the weighted mean vector : */ /* dx = (f(e1)*dx1 + f(e2)*dx2 + f(e3)*dx3) / (dx1 + dx2 + dx3) */ /* weight_left = 65536 - (unsigned int)(macroblock_vector_left->error); weight_left = 65536 - (unsigned int)(macroblock_vector_top->error); weight_topright = 65536 - (unsigned int)(macroblock_vector_topright->error); macroblock_vector_barycentre.dx = (weight_left * macroblock_vector_left->dx + weight_top * macroblock_vector_top->dx + weight_topright * macroblock_vector_topright->dx ) / (weight_left + weight_top + weight_topright); macroblock_vector_barycentre.dy = (weight_left * macroblock_vector_left->dy + weight_top * macroblock_vector_top->dy + weight_topright * macroblock_vector_topright->dy ) / (weight_left + weight_top + weight_topright); */ /* saturate prediction to borders */ if(unrestricted) { if((x<<1)+vectors[0].dx<(-16<<1)) vectors[0].dx = (-16-x)<<1; if((y<<1)+vectors[0].dy<(-16<<1)) vectors[0].dy = (-16-y)<<1; if((x<<1)+vectors[0].dx>(width<<1)) vectors[0].dx = (width-x)<<1; if((y<<1)+vectors[0].dy>(height<<1)) vectors[0].dy = (height-y)<<1; } else { if((x<<1)+vectors[0].dx<0) vectors[0].dx = (-x)<<1; if((y<<1)+vectors[0].dy<0) vectors[0].dy = (-y)<<1; if((x<<1)+vectors[0].dx>((width-16)<<1)) vectors[0].dx = (width-16-x)<<1; if((y<<1)+vectors[0].dy>((height-16)<<1)) vectors[0].dy = (height-16-y)<<1; } /* Step2 : Calculate the thresholds */ threshold1 = INFINITE_ERROR; if(mb_x>0) threshold1 = fame_min(threshold1, pvector_left[0].error+pvector_left[1].error+pvector_left[2].error+pvector_left[3].error); if(mb_y>0) threshold1 = fame_min(threshold1, pvector_top[0].error+pvector_top[1].error+pvector_top[2].error+pvector_top[3].error); if(mb_y>0 && mb_x<motion->mb_width-1) threshold1 = fame_min(threshold1, pvector_topright[0].error+pvector_topright[1].error+pvector_topright[2].error+pvector_topright[3].error); threshold0 = vectors[0].count + vectors[1].count + vectors[2].count + vectors[3].count; threshold2 = threshold1 + threshold0; if(threshold1<LOWER_LIMIT_THRESHOLD1) threshold1 = LOWER_LIMIT_THRESHOLD1; if(threshold1>UPPER_LIMIT_THRESHOLD1) threshold1 = UPPER_LIMIT_THRESHOLD1; if(threshold2>UPPER_LIMIT_THRESHOLD2) threshold2 = UPPER_LIMIT_THRESHOLD2;#if DEBUG fprintf(debug_log, "threshold0 = %u\n", threshold0); fprintf(debug_log, "threshold1 = %u\n", threshold1); fprintf(debug_log, "threshold2 = %u\n", threshold2);#endif /* Step3 : Process a set of vectors whose matching probability is very high*/ /* i.e. median, zero, prev, left, top, topright vector */ /* Check the median vector */ pmv.dx = vectors[3].dx = vectors[2].dx = vectors[1].dx = vectors[0].dx; pmv.dy = vectors[3].dy = vectors[2].dy = vectors[1].dy = vectors[0].dy; get_error(ref, current, shape, vectors, offset, edged_offset, pitch, eval_error, 4); sad_inter = vectors[0].error+vectors[1].error+ vectors[2].error+vectors[3].error; sad_last = plast[0].error+plast[1].error+ plast[2].error+plast[3].error+ mv_overhead(&pmv, plast[0].dx, plast[0].dy, fcode, quant); if((sad_inter<threshold0) || (vectors->dx == plast->dx && vectors->dy == plast->dy && sad_inter < sad_last)) { /* keep predicted vector */#if STAT motionstat.num_median++;#endif memcpy(pvector, vectors, 4*sizeof(fame_motion_vector_t)); if((vectors[0].dx ^ vectors[1].dx) + (vectors[0].dx ^ vectors[2].dx) + (vectors[0].dx ^ vectors[3].dx) + (vectors[0].dy ^ vectors[1].dy) + (vectors[0].dy ^ vectors[2].dy) + (vectors[0].dy ^ vectors[3].dy)) return(motion_inter4v); else return(motion_inter); }#if DEBUG fprintf(debug_log, "Median vector : dx=%d dy=%d error=%d\n", vectors[0].dx, vectors[0].dy, vectors[0].error+vectors[1].error+vectors[2].error+vectors[3].error);#endif /* TODO: check performance of current 4MV prediction compared to 1MV */ /* Check the zero vector */ use_median = check_zero_vector(ref, current, shape, x, y, width, height, vectors, offset, edged_offset, pitch, eval_error, &pmv, fcode, quant); /* Check the previous vector */ /* fcode may have changed, make sure the vector is within the search range */ if(plast->dx >= -(range<<1) && plast->dx <= (range<<1)-1 && plast->dy >= -(range<<1) && plast->dy <= (range<<1)-1) use_median = check_vector(ref, current, shape, x, y, width, height, plast, vectors, offset, edged_offset, pitch, eval_error, &pmv, fcode, quant, unrestricted); /* Check the left vector */ if(!pred_same && is_left) { use_median &= check_vector(ref, current, shape, x, y, width, height, pvector_left, vectors, offset, edged_offset, pitch, eval_error, &pmv, fcode, quant, unrestricted); } /* Check the top vector */ if(!pred_same && is_top) { use_median &= check_vector(ref, current, shape, x, y, width, height, pvector_top, vectors, offset, edged_offset, pitch, eval_error, &pmv, fcode, quant, unrestricted); } /* Check the topright vector */ if(!pred_same && is_topright) { use_median &= check_vector(ref, current, shape, x, y, width, height, pvector_topright, vectors, offset, edged_offset, pitch, eval_error, &pmv, fcode, quant, unrestricted); }#if DEBUG fprintf(debug_log, "Best vector of the set : dx=%d dy=%d error=%u\n", vectors[0].dx, vectors[0].dy, vectors[0].error+vectors[1].error+vectors[2].error+vectors[3].error);#endif /* Step4 : check early exit */ sad_inter = vectors[0].error+vectors[1].error+ vectors[2].error+vectors[3].error+ mv_overhead(&pmv, vectors[0].dx, vectors[0].dy, fcode, quant); if(sad_inter < threshold1 || (vectors->dx == plast->dx && vectors->dy == plast->dy && sad_inter < sad_last)) {#if DEBUG fprintf(debug_log, "Early exit\n");#endif memcpy(pvector, vectors, 4*sizeof(fame_motion_vector_t));#if STAT motionstat.num_early++;#endif if((vectors[0].dx ^ vectors[1].dx) + (vectors[0].dx ^ vectors[2].dx) + (vectors[0].dx ^ vectors[3].dx) + (vectors[0].dy ^ vectors[1].dy) + (vectors[0].dy ^ vectors[2].dy) + (vectors[0].dy ^ vectors[3].dy)) return(motion_inter4v); else return(motion_inter); } /* integer sample search *//* Step5 : The previous attempts were not successfull -> apply the diamond search algorithm with the initial vector equal to the best previous vector found */ if(pred_same || pmv.dx != 0 || pmv.dy != 0 || threshold2<THRESHOLD_SMALLDIAMOND) {#if DEBUG fprintf(debug_log, "Choice for 16x16 mb search : small diamond\n");#endif /* pelwise small diamond */ find_macroblockvector(ref, current, shape, offset, edged_offset, x, y, width, height, pitch, td_block_smalldiamond, range, 1, diamond_count, eval_error, vectors, &pmv, fcode, quant, unrestricted);#if STAT motionstat.num_smalldiamond++;#endif } else {#if DEBUG fprintf(debug_log, "Choice for 16x16 mb search : large diamond\n");#endif /* pelwise large diamond */ find_macroblockvector(ref, current, shape, offset, edged_offset, x, y, width, height, pitch, td_block_largediamond, range, 1, diamond_count, eval_error, vectors, &pmv, fcode, quant, unrestricted);#if STAT motionstat.num_largediamond++;#endif } /* ***** Make the intra/inter mode decision ***** */ sad_inter = vectors[0].error + vectors[1].error + vectors[2].error + vectors[3].error+mv_overhead(&pmv, vectors[0].dx, vectors[0].dy, fcode, quant); mad_inter = vectors[0].deviation + vectors[1].deviation + vectors[2].deviation + vectors[3].deviation; count = vectors[0].count + vectors[1].count + vectors[2].count + vectors[3].count;#if DEBUG fprintf(debug_log, "Best 16x16 vector found (integer pixel) : dx=%d dy=%d error=%u\n", vectors->dx, vectors->dy, sad_inter);#endif /* store vectors for future prediction */ memcpy(pvector, vectors, 4*sizeof(fame_motion_vector_t)); /* intra/inter mode decision */ /* -> 1 - COMPUTE THE VARIANCE OF THE MACROBLOCK */ /* (estimated by absolute difference and not square diff.) */ /* The number of bits (at a given quality) needed by the DCT */ /* depends on the variance (in a first approximation) */ /* -> 2 - COMPARE WITH THE COVARIANCE GIVEN BY THE MOTION VECTOR */ /* The number of bits to code residual macroblock */ /* depends on the covariance (in a first approximation) */ /* -> If (1) < (2) - 2*N : Choose INTRA */ /* Substract 2*N to favour INTER mode when there is no */ /* significant difference */ /* TODO: maybe move half pel before decision */ if(mad_inter + count + count < sad_inter) {#if DEBUG fprintf(debug_log, "Coding = intra\n");#endif memset(pvector, 0, 4*sizeof(fame_motion_vector_t)); return(motion_intra); } /* subvector (8x8) search */ if(motion->flags & FAME_MOTION_BLOCK_SEARCH) { for(k = 0; k < 4; k++) { /* TODO: k depends on shape */ /* integer sample search */ find_blockvector(ref, current, shape, offset[k], edged_offset[k], x, y, width, height, pitch, td_block_bbgds, range, 1, diamond_count, eval_error, &vectors[k], &pmv, fcode, quant, unrestricted); /* half sample search */ find_blockvector(ref, current, shape, offset[k], edged_offset[k], x, y, width, height, pitch, td_block_bbgds, range, 0, 1, eval_error, &vectors[k], &pmv, fcode, quant, unrestricted); }#if DEBUG for(i=0; i<4; i++) fprintf(debug_log, "Best 8x8 vector found (integer pixel) for the block %d: dx=%d dy=%d error=%u\n", i, vectors[i].dx, vectors[i].dy, vectors[i].error);#endif } /* half sample search */ find_macroblockvector(ref, current, shape, offset, edged_offset, x, y, width, height, pitch, td_block_bbgds, range, 0, 1, eval_error, pvector, &pmv, fcode, quant, unrestricted);#if DEBUG fprintf(debug_log, "After half pixel search on the macroblock : dx=%d dy=%d error=%u\n", pvector->dx, pvector->dy, pvector[0].error+pvector[1].error+pvector[2].error+pvector[3].error);#endif /* inter4v / inter decision */ sad_inter = pvector[0].error + pvector[1].error + pvector[2].error + pvector[3].error+mv_overhead(&pmv, pvector[0].dx, pvector[0].dy, fcode, quant); mad_inter = vectors[0].deviation + vectors[1].deviation + vectors[2].deviation + vectors[3].deviation; count = vectors[0].count + vectors[1].count + vectors[2].count + vectors[3].count; sad_inter4v = vectors[0].error + vectors[1].error + vectors[2].error + vectors[3].error + mv_overhead(&pmv, vectors[0].dx, vectors[0].dy, fcode, quant) + mv_overhead(&pmv, vectors[1].dx, vectors[1].dy, fcode, quant) + mv_overhead(&pmv, vectors[2].dx, vectors[2].dy, fcode, quant) + mv_overhead(&pmv, vectors[3].dx, vectors[3].dy, fcode, quant); #if DEBUG fprintf(debug_log, "Best 16x16 vector found : dx=%d dy=%d error=%u\n", pvector->dx, pvector->dy, pvector[0].error+pvector[1].error+pvector[2].error+pvector[3].error); for(i=0; i<4; i++) { fprintf(debug_log, "Best 8x8 vector found for the block %d : dx=%d dy=%d error=%u\n", i, vectors[i].dx, vectors[i].dy, vectors[i].error); }#endif /* inter4v/inter mode decision */ if((motion->flags & FAME_MOTION_BLOCK_SEARCH) && (sad_inter4v + ((count>>1)+1) < sad_inter)) {#if DEBUG fprintf(debug_log, "4 vectors\n");#endif /* inter4v prediction */ sad_inter = sad_inter4v; motion_coding = motion_inter4v; } else { memcpy(vectors, pvector, 4*sizeof(fame_motion_vector_t)); motion_coding = motion_inter; }#if DEBUG fprintf(debug_log, "Coding = inter\n");#endif return(motion_coding);}/* End of motion_pmvfast.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -