From 57459c69a24168c73e8598663325ea2aabe68e6e Mon Sep 17 00:00:00 2001 From: Andrea Gabriellini Date: Fri, 24 Apr 2009 16:44:35 +0100 Subject: [PATCH] [encoder] Added chroma to mode decision Now the entire motion estimation, subpel refinement and mode decision process use chrominance information as well as luminance. Overall speed affected, the chroma ME/MS cannot be switched on or off. --- schroedinger/schrohierbm.c | 89 ++++---- schroedinger/schrometric.c | 165 ++++++++++----- schroedinger/schrometric.h | 10 +- schroedinger/schromotion.h | 8 +- schroedinger/schromotionest.c | 442 ++++++++++++++++++++++++++++------------ schroedinger/schroroughmotion.c | 20 +- 6 files changed, 493 insertions(+), 241 deletions(-) diff --git a/schroedinger/schrohierbm.c b/schroedinger/schrohierbm.c index 03adb2f..cefd6ea 100644 --- a/schroedinger/schrohierbm.c +++ b/schroedinger/schrohierbm.c @@ -177,15 +177,16 @@ schro_hierarchical_bm_scan_hint (SchroHierBm schro_hbm, int shift, int h_range) int xblen = params->xbsep_luma, yblen = params->ybsep_luma; int i; - int j, k; + int j; int tmp_x, tmp_y; int skip; + int shift_w[3], shift_h[3]; int split = 1 < shift ? 0 : (1 == shift ? 1 : 2); #define LIST_LENGTH 9 SchroMotionVector *temp_hint_mv[LIST_LENGTH], *hint_mv[LIST_LENGTH]; unsigned int hint_mask; int ref = schro_hbm_ref_number (schro_hbm); - int xlen[3], ylen[3]; + int comp_w[3], comp_h[3]; /* sets up for block matching */ scan.frame = schro_hbm_src_frame (schro_hbm, shift);; @@ -205,12 +206,15 @@ schro_hierarchical_bm_scan_hint (SchroHierBm schro_hbm, int shift, int h_range) hint_mask = ~((1<<(shift + 1))-1); skip = 1<k; ++k) { - xlen[k] = 0 == k ? xblen >> shift - : xblen >> (shift+SCHRO_FRAME_FORMAT_H_SHIFT(scan.frame->format)); - ylen[k] = 0 == k ? yblen >> shift - : yblen >> (shift+SCHRO_FRAME_FORMAT_V_SHIFT(scan.frame->format)); - } + shift_w[0] = shift_h[0] = shift; + shift_w[1] = shift_w[2] = shift+SCHRO_FRAME_FORMAT_H_SHIFT(scan.frame->format); + shift_h[1] = shift_h[2] = shift+SCHRO_FRAME_FORMAT_V_SHIFT(scan.frame->format); + comp_w[0] = xblen; + comp_h[0] = yblen; + comp_w[1] = comp_w[2] = + xblen >> SCHRO_FRAME_FORMAT_H_SHIFT(scan.frame->format); + comp_h[1] = comp_h[2] = + yblen >> SCHRO_FRAME_FORMAT_V_SHIFT(scan.frame->format); for(j=0;jy_num_blocks;j+=skip){ for(i=0;ix_num_blocks;i+=skip){ @@ -220,21 +224,21 @@ schro_hierarchical_bm_scan_hint (SchroHierBm schro_hbm, int shift, int h_range) int dx, dy; int min_m; int min_metric; - int width=0, height=0; + int width[3], height[3]; int k; /* get source data, if possible */ - if ( !(scan.frame->width > i * xlen[0]) - || !(scan.frame->height > j * ylen[0]) ) { + if ( !(scan.frame->width > (i * xblen) >> shift) + || !(scan.frame->height > (j * yblen) >> shift) ) { continue; } - for (k=0; 3 > k; ++k) { + for (k=0; 3>k; ++k) { schro_frame_get_subdata (scan.frame, &orig[k], k - , i * xlen[k], j * ylen[k]); + , (i*xblen) >> shift_w[k], (j*yblen) >> shift_h[k]); + width[k] = MIN(orig[k].width, comp_w[k]); + height[k] = MIN(orig[k].height, comp_h[k]); if (0 == k) { - width = MIN(orig[0].width, xblen); - height = MIN(orig[0].height, yblen); - SCHRO_ASSERT(0 < width && 0 < height); + SCHRO_ASSERT(0 < width[k] && 0 < height[k]); } } @@ -305,32 +309,29 @@ schro_hierarchical_bm_scan_hint (SchroHierBm schro_hbm, int shift, int h_range) min_m = -1; min_metric = INT_MAX; /* choose best candidate for refinement based on SAD only. */ - tmp_x = i * xblen; - tmp_y = j * yblen; for(m = 0; m < n; m++) { int metric = 0; - - dx = hint_mv[m]->dx[ref] + tmp_x; - dx >>=shift; - dx = MAX (-width, MIN(scan.ref_frame->width, dx)); - dy = hint_mv[m]->dy[ref] + tmp_y; - dy >>= shift; - dy = MAX (-height, MIN(scan.ref_frame->height, dy)); - for (k=0; 3>k; ++k) { - if (0 == k) { - schro_frame_get_reference_subdata (scan.ref_frame, &ref_data[k] - , k, dx, dy); - } else { - schro_frame_get_reference_subdata (scan.ref_frame, &ref_data[k], k - , dx >> SCHRO_FRAME_FORMAT_H_SHIFT(scan.ref_frame->format) - , dy >> SCHRO_FRAME_FORMAT_V_SHIFT(scan.ref_frame->format) ); + tmp_x = (i * xblen) >> shift_w[k]; + tmp_y = (j * yblen) >> shift_h[k]; + dx = hint_mv[m]->dx[ref]; + dx >>= shift_w[k]; + dx += tmp_x; + dx = MAX(-width[k], MIN((scan.ref_frame->components+k)->width, dx)); + dy = hint_mv[m]->dy[ref]; + dy >>= shift_h[k]; + dy += tmp_y; + dy = MAX(-height[k], MIN((scan.ref_frame->components+k)->height, dy)); + if (k>2) SCHRO_ASSERT(0); + schro_frame_get_reference_subdata (scan.ref_frame, &ref_data[k], k + , dx, dy); + if (width[k] > ref_data[k].width || height[k] > ref_data[k].height) { + metric = INT_MAX; + break; } /* block matching for a single position */ metric += schro_metric_absdiff_u8 (orig[k].data, orig[k].stride - , ref_data[k].data, ref_data[k].stride - , 0 == k ? width : width >> SCHRO_FRAME_FORMAT_H_SHIFT(scan.frame->format) - , 0 == k ? height : height >> SCHRO_FRAME_FORMAT_V_SHIFT(scan.frame->format)); + , ref_data[k].data, ref_data[k].stride, width[k], height[k]); } if (metric < min_metric) { @@ -344,19 +345,21 @@ schro_hierarchical_bm_scan_hint (SchroHierBm schro_hbm, int shift, int h_range) dx = hint_mv[min_m]->dx[ref] >> shift; dy = hint_mv[min_m]->dy[ref] >> shift; - scan.block_width = width; - scan.block_height = height; + scan.block_width = width[0]; + scan.block_height = height[0]; scan.x = i * xblen >> shift; scan.y = j * yblen >> shift; - dx = MAX (-width - scan.x, MIN (scan.ref_frame->width - scan.x, dx)); - dy = MAX (-height - scan.y, MIN (scan.ref_frame->height - scan.y, dy)); - schro_metric_scan_setup (&scan, dx, dy, h_range); + dx = MAX (-width[0] - scan.x, MIN (scan.ref_frame->width - scan.x, dx)); + dy = MAX (-height[0] - scan.y, MIN (scan.ref_frame->height - scan.y, dy)); + scan.gravity_x = dx; + scan.gravity_y = dy; + schro_metric_scan_setup (&scan, dx, dy, h_range, TRUE); SCHRO_ASSERT (!(0 > scan.scan_width) && !(0 > scan.scan_height)); mv = mf->motion_vectors + j*params->x_num_blocks + i; - schro_metric_scan_do_scan (&scan, TRUE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &mv->chroma_metric); dx <<= shift; dy <<= shift; diff --git a/schroedinger/schrometric.c b/schroedinger/schrometric.c index b4be01c..ee43643 100644 --- a/schroedinger/schrometric.c +++ b/schroedinger/schrometric.c @@ -4,6 +4,7 @@ #endif #include #include +#include int @@ -81,107 +82,157 @@ schro_metric_absdiff_u8 (uint8_t *a, int a_stride, uint8_t *b, int b_stride, } void -schro_metric_scan_do_scan (SchroMetricScan *scan, int use_chroma) +schro_metric_scan_do_scan (SchroMetricScan *scan) { - SCHRO_ASSERT (scan->ref_x + scan->block_width + scan->scan_width - 1 <= scan->frame->width + scan->frame->extension); - SCHRO_ASSERT (scan->ref_y + scan->block_height + scan->scan_height - 1 <= scan->frame->height + scan->frame->extension); + SCHRO_ASSERT (scan->ref_x + scan->block_width + scan->scan_width - 1 <= + scan->frame->width + scan->frame->extension); + SCHRO_ASSERT (scan->ref_y + scan->block_height + scan->scan_height - 1 <= + scan->frame->height + scan->frame->extension); SCHRO_ASSERT (scan->ref_x >= -scan->frame->extension); SCHRO_ASSERT (scan->ref_y >= -scan->frame->extension); SCHRO_ASSERT (scan->scan_width > 0); SCHRO_ASSERT (scan->scan_height > 0); - int k; - uint32_t metrics[SCHRO_LIMIT_METRIC_SCAN*SCHRO_LIMIT_METRIC_SCAN]; - int shift_h = SCHRO_FRAME_FORMAT_H_SHIFT(scan->frame->format) - , shift_v = SCHRO_FRAME_FORMAT_V_SHIFT(scan->frame->format); - int components_number = use_chroma ? 3 : 1; - uint8_t zero = 0x0; - oil_splat_u8_ns ((uint8_t *)scan->metrics, &zero, - sizeof(uint32_t)*scan->scan_width * scan->scan_height); - for (k=0; components_number>k; ++k) { - SchroFrameData *fd = scan->frame->components + k; - SchroFrameData *fd_ref = scan->ref_frame->components + k; - int i,j; - int block_width = 0 == k ? scan->block_width : scan->block_width >> shift_h - , block_height = 0 == k ? scan->block_height : scan->block_height >> shift_v - , x = 0 == k ? scan->x : scan->x >> shift_h - , y = 0 == k ? scan->y : scan->y >> shift_v - , ref_x = 0 == k ? scan->ref_x : scan->ref_x >> shift_h - , ref_y = 0 == k ? scan->ref_y : scan->ref_y >> shift_v; - - if (block_width == 8 && block_height == 8) { - for(i=0;iscan_width;i++){ - oil_sad8x8_8xn_u8 (metrics + i * scan->scan_height, - SCHRO_FRAME_DATA_GET_PIXEL_U8(fd, x, y), + /* do luma first */ + SchroFrameData* fd = scan->frame->components + 0; + SchroFrameData* fd_ref = scan->ref_frame->components + 0; + int i, j; + if (scan->block_width == 8 && scan->block_height == 8) { + for(i=0;iscan_width;i++){ + oil_sad8x8_8xn_u8 (scan->metrics + i * scan->scan_height, + SCHRO_FRAME_DATA_GET_PIXEL_U8(fd, scan->x, scan->y), + fd->stride, + SCHRO_FRAME_DATA_GET_PIXEL_U8(fd_ref, scan->ref_x + i, scan->ref_y), + fd_ref->stride, + scan->scan_height); + } + } else { + for(i=0;iscan_width;i++) { + for(j=0;jscan_height;j++) { + scan->metrics[i*scan->scan_height + j] = schro_metric_absdiff_u8 ( + SCHRO_FRAME_DATA_GET_PIXEL_U8(fd, scan->x, scan->y), fd->stride, - SCHRO_FRAME_DATA_GET_PIXEL_U8(fd_ref, ref_x + i, ref_y), - fd_ref->stride, - scan->scan_height); - } - for (i=0; scan->scan_width * scan->scan_height>i; ++i) { - scan->metrics[i] += metrics[i]; + SCHRO_FRAME_DATA_GET_PIXEL_U8(fd_ref, scan->ref_x + i, + scan->ref_y + j), fd_ref->stride, + scan->block_width, scan->block_height); } - } else { - - uint32_t tmp; - for(i=0;iscan_width;i++) { - for(j=0;jscan_height;j++) { - tmp = schro_metric_absdiff_u8 ( - SCHRO_FRAME_DATA_GET_PIXEL_U8(fd, x, y), - fd->stride, - SCHRO_FRAME_DATA_GET_PIXEL_U8(fd_ref, ref_x + i, - ref_y + j), fd_ref->stride, - block_width, block_height); - scan->metrics[i*scan->scan_height+j] += tmp; + } + } + if (scan->use_chroma) { + /* now do chroma ME */ + int skip_h = 1 << SCHRO_FRAME_FORMAT_H_SHIFT(scan->frame->format) + , skip_v = 1 << SCHRO_FRAME_FORMAT_V_SHIFT(scan->frame->format); + int x = scan->x/skip_h, y = scan->y/skip_v, ref_x, ref_y; + int block_width = scan->block_width / skip_h + , block_height = scan->block_height / skip_v; + memset(scan->chroma_metrics, 0, sizeof(scan->chroma_metrics)); + uint32_t metrics[SCHRO_LIMIT_METRIC_SCAN*SCHRO_LIMIT_METRIC_SCAN]; + int k; + for (k=1; 3>k; ++k) { + fd = scan->frame->components + k; + fd_ref = scan->ref_frame->components + k; + int last_i = FALSE, last_j = FALSE; + for (i=0, ref_x = scan->ref_x/skip_h; scan->scan_width > i; ++i, ++ref_x) { + if (last_i && ref_x & 0x01) { + for (j=0; scan->scan_height > j; ++j) { + metrics[i * scan->scan_height + j] = + metrics[(i-1) * scan->scan_height + j]; + } + last_i = FALSE; + } else { + for (j=0, ref_y = scan->ref_y/skip_v; scan->scan_height > j + ; ++j, ++ref_y) { + if (last_j && ref_y & 0x01) { + metrics[i * scan->scan_height + j] = + metrics[i * scan->scan_height + j - 1]; + last_j = FALSE; + } else { + metrics[i * scan->scan_height + j] = schro_metric_absdiff_u8 ( + SCHRO_FRAME_DATA_GET_PIXEL_U8(fd, x, y) + , fd->stride + , SCHRO_FRAME_DATA_GET_PIXEL_U8(fd_ref, ref_x, ref_y) + , fd_ref->stride + , block_width, block_height); + last_j = TRUE; + } + } + last_i = TRUE; } } + for (i=0; scan->scan_width * scan->scan_height > i; ++i) { + scan->chroma_metrics[i] += metrics[i]; + } } } } -/* Note: dx and dy should contain the seed-MV so that we can - * bias the search towards that point - a better solution needed - FIXME */ + +/* note that gravity_x and gravity_y should contain the seed MV + * we use to bias our search */ int -schro_metric_scan_get_min (SchroMetricScan *scan, int *dx, int *dy) +schro_metric_scan_get_min (SchroMetricScan *scan, int *dx, int *dy + , uint32_t* chroma_error) { int i,j; uint32_t min_metric; int min_gravity; uint32_t metric; + uint32_t chroma_metric; + uint32_t min_chroma_metric=0; + uint32_t min_total_metric=0; + uint32_t tmp; int gravity; int x,y; SCHRO_ASSERT (scan->scan_width > 0); SCHRO_ASSERT (scan->scan_height > 0); - i = *dx + scan->x - scan->ref_x; - j = *dy + scan->y - scan->ref_y; + i = scan->gravity_x + scan->x - scan->ref_x; + j = scan->gravity_y + scan->y - scan->ref_y; min_metric = scan->metrics[j + i * scan->scan_height]; + if (scan->use_chroma) { + min_chroma_metric = scan->chroma_metrics[j + i * scan->scan_height]; + min_total_metric = min_metric + min_chroma_metric; + } min_gravity = scan->gravity_scale * (abs(*dx - scan->gravity_x) + abs(*dy - scan->gravity_y)); for(i=0;iscan_width;i++) { for(j=0;jscan_height;j++) { metric = scan->metrics[i*scan->scan_height + j]; + chroma_metric = scan->chroma_metrics[i*scan->scan_height + j]; x = scan->ref_x + i - scan->x; y = scan->ref_y + j - scan->y; gravity = scan->gravity_scale * (abs(x - scan->gravity_x) + abs(y - scan->gravity_y)); - //if (metric + gravity < min_metric + min_gravity) { - if (metric < min_metric) { - min_metric = metric; - min_gravity = gravity; - *dx = x; - *dy = y; + if (scan->use_chroma) { + tmp = metric+chroma_metric; + if (tmp < min_total_metric) { + min_total_metric = tmp; + min_metric = metric; + min_chroma_metric = chroma_metric; + min_gravity = gravity; + *dx = x; + *dy = y; + } + } else { + if (metric < min_metric) { + min_metric = metric; + min_gravity = gravity; + *dx = x; + *dy = y; + } } } } + *chroma_error = min_chroma_metric; return min_metric; } void -schro_metric_scan_setup (SchroMetricScan *scan, int dx, int dy, int dist) +schro_metric_scan_setup (SchroMetricScan *scan, int dx, int dy, int dist + , int use_chroma) { SCHRO_ASSERT(scan && scan->frame && scan->ref_frame && dist > 0); @@ -199,6 +250,8 @@ schro_metric_scan_setup (SchroMetricScan *scan, int dx, int dy, int dist) scan->scan_width = xrange + 1; scan->scan_height = yrange + 1; + scan->use_chroma = use_chroma; + SCHRO_ASSERT (scan->scan_width <= SCHRO_LIMIT_METRIC_SCAN); SCHRO_ASSERT (scan->scan_height <= SCHRO_LIMIT_METRIC_SCAN); } diff --git a/schroedinger/schrometric.h b/schroedinger/schrometric.h index 65d6a50..4c3312e 100644 --- a/schroedinger/schrometric.h +++ b/schroedinger/schrometric.h @@ -25,8 +25,10 @@ struct _SchroMetricScan { int scan_height; int gravity_scale; int gravity_x, gravity_y; + int use_chroma; /* output */ uint32_t metrics[SCHRO_LIMIT_METRIC_SCAN*SCHRO_LIMIT_METRIC_SCAN]; + uint32_t chroma_metrics[SCHRO_LIMIT_METRIC_SCAN*SCHRO_LIMIT_METRIC_SCAN]; }; #define SCHRO_METRIC_INVALID INT_MAX @@ -40,9 +42,11 @@ int schro_metric_haar_const (uint8_t *data, int stride, int dc_value, int schro_metric_abssum_s16 (int16_t *data, int stride, int width, int height); int schro_metric_sum_u8 (uint8_t *data, int stride, int width, int height); -void schro_metric_scan_do_scan (SchroMetricScan *scan, int use_chroma); -int schro_metric_scan_get_min (SchroMetricScan *scan, int *dx, int *dy); -void schro_metric_scan_setup (SchroMetricScan *scan, int dx, int dy, int dist); +void schro_metric_scan_do_scan (SchroMetricScan *scan); +int schro_metric_scan_get_min (SchroMetricScan *scan, int *dx, int *dy + , uint32_t* chroma_metric); +void schro_metric_scan_setup (SchroMetricScan *scan, int dx, int dy, int dist + , int use_chroma); int schro_metric_get (SchroFrameData *src1, SchroFrameData *src2, int width, int height); int schro_metric_get_biref (SchroFrameData *fd, SchroFrameData *src1, diff --git a/schroedinger/schromotion.h b/schroedinger/schromotion.h index 2d3b7fa..82185b1 100644 --- a/schroedinger/schromotion.h +++ b/schroedinger/schromotion.h @@ -20,8 +20,8 @@ struct _SchroMotionVector { unsigned int split : 2; unsigned int unused : 3; unsigned int scan : 8; - unsigned int _pad : 16; - unsigned int metric : 32; + uint32_t metric; + uint32_t chroma_metric; int16_t dx[2]; int16_t dy[2]; }; @@ -32,8 +32,8 @@ struct _SchroMotionVectorDC { unsigned int split : 2; unsigned int unused : 3; unsigned int scan : 8; - unsigned int _pad : 16; - unsigned int metric : 32; + uint32_t metric; + uint32_t chroma_metric; int16_t dc[3]; uint16_t _padding1; }; diff --git a/schroedinger/schromotionest.c b/schroedinger/schromotionest.c index e2b742c..1828511 100644 --- a/schroedinger/schromotionest.c +++ b/schroedinger/schromotionest.c @@ -334,12 +334,6 @@ schro_encoder_motion_predict_subpel_deep (SchroMe me) } width = MIN(xblen, orig.width); height = MIN(yblen, orig.height); - /* fetch reference data for full pel position - luma only */ - schro_upsampled_frame_get_block_fast_precN (upframe, 0 - , mv->dx[ref] + i*xblen, mv->dy[ref] + j*yblen - , 0, &ref_data, &fd); - mv->metric = schro_metric_absdiff_u8 (orig.data, orig.stride - , ref_data.data, ref_data.stride, width, height); /* adjust MV precision */ mv->dx[ref] <<= 1; mv->dy[ref] <<= 1; @@ -584,8 +578,10 @@ schro_motionest_superblock_scan_one (SchroMotionEst *me, int ref, int distance, dx = hint_mv->dx[ref]; dy = hint_mv->dy[ref]; + scan.gravity_x = dx; + scan.gravity_y = dy; - schro_metric_scan_setup (&scan, dx, dy, distance); + schro_metric_scan_setup (&scan, dx, dy, distance, FALSE); if (scan.scan_width <= 0 || scan.scan_height <= 0) { mv->dx[ref] = 0; mv->dy[ref] = 0; @@ -594,8 +590,9 @@ schro_motionest_superblock_scan_one (SchroMotionEst *me, int ref, int distance, return; } - schro_metric_scan_do_scan (&scan, FALSE); - block->error = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + block->error = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); mv->metric = block->error/16; mv->split = 0; @@ -786,10 +783,12 @@ schro_motionest_block_scan_one (SchroMotionEst *me, int ref, int distance, dx = hint_mv->dx[ref]; dy = hint_mv->dy[ref]; + scan.gravity_x = dx; + scan.gravity_y = dy; scan.x = (i + ii) * params->xbsep_luma; scan.y = (j + jj) * params->ybsep_luma; - schro_metric_scan_setup (&scan, dx, dy, distance); + schro_metric_scan_setup (&scan, dx, dy, distance, FALSE); if (scan.scan_width <= 0 || scan.scan_height <= 0) { mv->dx[ref] = 0; mv->dy[ref] = 0; @@ -799,8 +798,9 @@ schro_motionest_block_scan_one (SchroMotionEst *me, int ref, int distance, continue; } - schro_metric_scan_do_scan (&scan, FALSE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); block->error += mv->metric; block->valid &= (mv->metric != SCHRO_METRIC_INVALID); @@ -857,6 +857,8 @@ schro_motionest_block_scan (SchroMotionEst *me, int ref, int distance, dx = hint_mv->dx[ref]; dy = hint_mv->dy[ref]; + scan.gravity_x = dx; + scan.gravity_y = dy; scan.x = (i + ii) * params->xbsep_luma; scan.y = (j + jj) * params->ybsep_luma; @@ -870,7 +872,7 @@ schro_motionest_block_scan (SchroMotionEst *me, int ref, int distance, } scan.block_width = MIN(params->xbsep_luma, scan.frame->width-scan.x); scan.block_height = MIN(params->ybsep_luma, scan.frame->height-scan.y); - schro_metric_scan_setup (&scan, dx, dy, distance); + schro_metric_scan_setup (&scan, dx, dy, distance, FALSE); if (scan.scan_width <= 0 || scan.scan_height <= 0) { mv->dx[ref] = 0; mv->dy[ref] = 0; @@ -880,8 +882,9 @@ schro_motionest_block_scan (SchroMotionEst *me, int ref, int distance, return; } - schro_metric_scan_do_scan (&scan, FALSE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); block->error = mv->metric; block->valid = (mv->metric != SCHRO_METRIC_INVALID); @@ -1015,6 +1018,8 @@ schro_motionest_subsuperblock_scan (SchroMotionEst *me, int ref, int distance, dx = hint_mv->dx[ref]; dy = hint_mv->dy[ref]; + scan.gravity_x = dx; + scan.gravity_y = dy; scan.x = (i + ii) * params->xbsep_luma; scan.y = (j + jj) * params->ybsep_luma; @@ -1027,7 +1032,7 @@ schro_motionest_subsuperblock_scan (SchroMotionEst *me, int ref, int distance, } scan.block_width = MIN(2*params->xbsep_luma, scan.frame->width-scan.x); scan.block_height = MIN(2*params->ybsep_luma, scan.frame->height-scan.y); - schro_metric_scan_setup (&scan, dx, dy, distance); + schro_metric_scan_setup (&scan, dx, dy, distance, FALSE); if (scan.scan_width <= 0 || scan.scan_height <= 0) { mv->dx[ref] = 0; mv->dy[ref] = 0; @@ -1037,8 +1042,9 @@ schro_motionest_subsuperblock_scan (SchroMotionEst *me, int ref, int distance, return; } - schro_metric_scan_do_scan (&scan, FALSE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); block->error = mv->metric; block->valid = (mv->metric != SCHRO_METRIC_INVALID); @@ -1527,6 +1533,81 @@ schro_motion_copy_to (SchroMotion *motion, int i, int j, SchroBlock *block) } } +/* performs single position block matching for split2 + * to calculate SAD */ +static void +schro_get_split2_metric (SchroMe me, int ref, int i, int j + , SchroMotionVector* mv, int* metric, SchroFrameData* fd) +{ + SCHRO_ASSERT(me && mv && metric && fd && (0 == ref || 1 == ref)); + + SchroParams* params = schro_me_params (me); + SchroFrameData orig[2], ref_data[2]; + SchroFrame* frame = schro_me_src (me); + SchroUpsampledFrame* upframe; + int mv_prec = params->mv_precision; + int fd_width, fd_height; + int width[3], height[3], dx, dy; + int k; + int xmin, xmax, ymin, ymax, tmp_x, tmp_y; + + xmin = ymin = -frame->extension; + xmax = (frame->width << mv_prec) + frame->extension; + ymax = (frame->height << mv_prec) + frame->extension; + /* calculates split2 block sizes for all components */ + int block_x[3], block_y[3]; + block_x[0] = params->xbsep_luma; + block_y[0] = params->ybsep_luma; + block_x[1] = block_x[2] = + block_x[0] >> SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + block_y[1] = block_y[2] = + block_y[0] >> SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + + /* get source data if possible */ + for (k=1; 3>k; ++k) { + if (!schro_frame_get_data (frame, &orig[k-1], k + , i * block_x[k], j * block_y[k])) { + *metric = INT_MAX; + return; + } + width[k] = MIN(block_x[k], orig[k].width); + height[k] = MIN(block_y[k], orig[k].height); + } + upframe = schro_me_ref (me, ref); + *metric = 0; + for (k=1; 3>k; ++k) { + /* get ref data, if possible */ + tmp_x = (i * block_x[k]) << mv_prec; + tmp_y = (j * block_y[k]) << mv_prec; + dx = mv->dx[ref]; + dx >>= SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + dx += tmp_x; + dy = mv->dy[ref]; + dy >>= SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + dy += tmp_y; + if (INT_MAX == mv->metric) { + *metric = INT_MAX; + return; + } + /* I need to save the original value of fd width and height */ + fd_width = fd->width; + fd_height = fd->height; + fd->width = width[k]; + fd->height = height[k]; + + schro_upsampled_frame_get_block_fast_precN (upframe, k, dx, dy + , mv_prec, &ref_data[k-1], fd); + fd->width = fd_width; + fd->height = fd_height; + *metric += schro_metric_absdiff_u8 (orig[k-1].data, orig[k-1].stride + , ref_data[k-1].data, ref_data[k-1].stride, width[k], height[k]); + } + mv->chroma_metric = *metric; + *metric += mv->metric; + return; +} + + /* performs mode decision for a superblock, split level 2 * Note that a SchroMotion object is required to estimate * the cost of the different prediction modes. */ @@ -1599,7 +1680,8 @@ schro_do_split2 (SchroMe me, int i, int j, SchroBlock* block mv->using_global = 0; entropy[ref] = schro_motion_block_estimate_entropy (motion, i+ii, j+jj); - score = entropy[ref] + mv->metric * lambda; + schro_get_split2_metric (me, ref, i+ii, j+jj, mv, &error, fd); + score = entropy[ref] + error * lambda; if (min_score > score) { min_score = score; best_mv = *mv; @@ -1653,15 +1735,17 @@ schro_do_split2 (SchroMe me, int i, int j, SchroBlock* block } } if (biref) { - int tmp_metric = 0; - for (k=0; 3>k; ++k) { - tmp_metric += schro_metric_get_biref (&orig[k], &ref_data[k][0], 1 + mv->metric = schro_metric_get_biref (&orig[0], &ref_data[0][0], 1 + , &ref_data[0][1], 1, 1, width[0], height[0]); + mv->chroma_metric = 0; + for (k=1; 3>k; ++k) { + mv->chroma_metric += schro_metric_get_biref (&orig[k], &ref_data[k][0], 1 , &ref_data[k][1], 1, 1, width[k], height[k]); } - mv->metric = tmp_metric; - score = entropy[0]+entropy[1] + mv->metric * lambda; + score = + entropy[0] + entropy[1] + (mv->metric+mv->chroma_metric) * lambda; if (min_score > score) { - best_error = mv->metric; + best_error = mv->metric+mv->chroma_metric; best_entropy = entropy[0]+entropy[1]; best_mv = *mv; min_score = score; @@ -1670,7 +1754,7 @@ schro_do_split2 (SchroMe me, int i, int j, SchroBlock* block } /* FIXME: magic used for considering DC prediction */ - if (((4 * width[0] * height[0])* 2 / 3) < best_error) { + if (4 * (width[0]*height[0] + 2 * width[1]*height[1]) < best_error) { /* let's consider DC prediction */ SchroMotionVectorDC* mvdc; int k; @@ -1679,25 +1763,29 @@ schro_do_split2 (SchroMe me, int i, int j, SchroBlock* block mvdc->split = 2; mvdc->using_global = 0; error = 0; + int ok=TRUE; for (k=0; 3>k; ++k) { int tmp = schro_block_average (&mvdc->dc[k], orig_frame->components+k , (i+ii)*comp_w[k], (j+jj)*comp_h[k], comp_w[k], comp_h[k]); if (SCHRO_METRIC_INVALID_2 == tmp) { SCHRO_DEBUG("Invalid DC metric"); mvdc->metric = INT_MAX; + ok = FALSE; } else { error += tmp; } } - mvdc->metric = error; - /* FIXME: we're assuming that the block doesn't have any predictor */ - entropy[0] = schro_pack_estimate_sint (mvdc->dc[0]); - entropy[0] += schro_pack_estimate_sint (mvdc->dc[1]); - entropy[0] += schro_pack_estimate_sint (mvdc->dc[2]); - if (error < best_error) { - best_mv = *(SchroMotionVector*)mvdc; - best_error = mvdc->metric; - best_entropy = entropy[0]; + if (ok) { + mvdc->metric = error; + /* FIXME: we're assuming that the block doesn't have any predictor */ + entropy[0] = schro_pack_estimate_sint (mvdc->dc[0]); + entropy[0] += schro_pack_estimate_sint (mvdc->dc[1]); + entropy[0] += schro_pack_estimate_sint (mvdc->dc[2]); + if (error < best_error) { + best_mv = *(SchroMotionVector*)mvdc; + best_error = mvdc->metric; + best_entropy = entropy[0]; + } } } *mv = best_mv; @@ -1764,7 +1852,8 @@ schro_get_best_mv_split1 (SchroMe me, int ref, int i, int j int comp_w[3], comp_h[3]; int k; int xmin, xmax, ymin, ymax, tmp_x, tmp_y; - int best_error=SCHRO_METRIC_INVALID, best_entropy=SCHRO_METRIC_INVALID; + int best_error=INT_MAX, best_entropy=INT_MAX; + int best_chroma_error = INT_MAX; xblen = params->xbsep_luma << 1; yblen = params->ybsep_luma << 1; @@ -1790,7 +1879,7 @@ schro_get_best_mv_split1 (SchroMe me, int ref, int i, int j SCHRO_ASSERT (motion); mv_motion = motion->motion_vectors + j * params->x_num_blocks + i; - for (k=0; 3k; ++k) { /* get source data if possible */ if (!schro_frame_get_data (frame, &orig[k], k , i * block_x[k], j * block_y[k])) { @@ -1839,6 +1928,7 @@ schro_get_best_mv_split1 (SchroMe me, int ref, int i, int j upframe = schro_me_ref (me, ref); for (m=0; n > m; ++m) { metric = 0; + int chroma_metric = 0; int ok = TRUE; for (k=0; 3>k; ++k) { tmp_x = (i * block_x[k]) << mv_prec; @@ -1867,28 +1957,35 @@ schro_get_best_mv_split1 (SchroMe me, int ref, int i, int j , mv_prec, &ref_data[k], fd); fd->width = fd_width; fd->height = fd_height; - metric += schro_metric_absdiff_u8 (orig[k].data, orig[k].stride - , ref_data[k].data, ref_data[k].stride, width[k], height[k]); + if (0 == k) { + metric = schro_metric_absdiff_u8 (orig[0].data, orig[0].stride + , ref_data[0].data, ref_data[0].stride, width[0], height[0]); + } else { + chroma_metric += schro_metric_absdiff_u8 (orig[k].data, orig[k].stride + , ref_data[k].data, ref_data[k].stride, width[k], height[k]); + } } if (ok) { *mv_motion = *hint_mv[m]; mv_motion->split = 1; mv_motion->pred_mode = ref + 1; ent = schro_motion_block_estimate_entropy (motion, i, j); - score = ent + metric * lambda; + score = ent + (metric+chroma_metric) * lambda; if (min_score > score) { min_score = score; min_m = m; best_entropy = ent; best_error = metric; + best_chroma_error = chroma_metric; } } } if (-1 < min_m) { - *error = best_error; + *error = best_error+best_chroma_error; *entropy = best_entropy; *mv_ref = *hint_mv[min_m]; mv_ref->metric = best_error >> 2; + mv_ref->chroma_metric = best_chroma_error >> 2; mv_ref->split = 1; mv_ref->pred_mode = ref + 1; } else mv_ref->metric = INT_MAX; @@ -1944,6 +2041,7 @@ schro_do_split1 (SchroMe me, int i, int j, SchroBlock* block double score, min_score = DBL_MAX; int entropy[2], error=INT_MAX; int best_entropy = INT_MAX + , best_chroma_error = INT_MAX , best_error = INT_MAX; /* Note that the metric for the split 1 block will be stored in best_mv * but divided by 4 */ @@ -1977,7 +2075,9 @@ schro_do_split1 (SchroMe me, int i, int j, SchroBlock* block continue; } mv->metric = INT_MAX; + mv->chroma_metric = INT_MAX; best_mv.metric = INT_MAX; + best_mv.chroma_metric = INT_MAX; /* do the 2 references, if available */ for (ref=0; params->num_refs > ref; ++ref) { @@ -2045,14 +2145,19 @@ schro_do_split1 (SchroMe me, int i, int j, SchroBlock* block } if (biref) { error = 0; - for (k=0; 3>k; ++k) { - error += schro_metric_get_biref (&orig[k], &ref_data[k][0], 1 + int chroma_error = 0; + error = schro_metric_get_biref (&orig[0], &ref_data[0][0], 1 + , &ref_data[0][1], 1, 1, width[0], height[0]); + for (k=1; 3>k; ++k) { + chroma_error += schro_metric_get_biref (&orig[k], &ref_data[k][0], 1 , &ref_data[k][1], 1, 1, width[k], height[k]); } - score = entropy[0] + entropy[1] + lambda * error; + score = entropy[0] + entropy[1] + lambda * (error+chroma_error); mv_ref[0].metric = error >> 2; + mv_ref[0].chroma_metric = chroma_error >> 2; if (min_score > score) { best_error = error; + best_chroma_error = chroma_error; best_entropy = entropy[0] + entropy[1]; best_mv = mv_ref[0]; min_score = score; @@ -2063,7 +2168,7 @@ schro_do_split1 (SchroMe me, int i, int j, SchroBlock* block block->valid = FALSE; } else { *mv = best_mv; - total_error += best_error; + total_error += best_error+best_chroma_error; total_entropy += best_entropy; block->mv[jj][ii] = best_mv; set_split1_motion (motion, i+ii, j+jj); @@ -2086,7 +2191,7 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j SchroMotionVector *mv, temp_mv = {0}; SchroMotionField* mf; SchroParams* params = schro_me_params (me); - SchroFrameData orig, ref_data; + SchroFrameData orig[3], ref_data[3]; SchroFrame* frame = schro_me_src (me); SchroUpsampledFrame* upframe; SchroHierBm hbm; @@ -2094,11 +2199,29 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j int n=0, m=0, min_m = -1, metric, ent; int mv_prec = params->mv_precision; int fd_width, fd_height, jj, ii; + int k; double score, min_score = DBL_MAX , lambda = schro_me_lambda (me); - int xblen = params->xbsep_luma << 2, yblen = params->ybsep_luma << 2; - int width, height, dx, dy, xmin, xmax, ymin, ymax, tmp_x, tmp_y; - int best_error = SCHRO_METRIC_INVALID_2, best_entropy = SCHRO_METRIC_INVALID_2; + int width[3], height[3], dx, dy, xmin, xmax, ymin, ymax, tmp_x, tmp_y; + int best_error = INT_MAX, best_chroma_error = INT_MAX + , best_entropy = INT_MAX; + + /* split2 block sizes for all components */ + int block_x[3], block_y[3]; + block_x[0] = params->xbsep_luma; + block_y[0] = params->ybsep_luma; + block_x[1] = block_x[2] = + block_x[0] >> SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + block_y[1] = block_y[2] = + block_y[0] >> SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + /* split0 block sizes for all components */ + int comp_w[3], comp_h[3]; + comp_w[0] = block_x[0] << 2; + comp_h[0] = block_y[0] << 2; + comp_w[1] = comp_w[2] = + comp_w[0] >> SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + comp_h[1] = comp_h[2] = + comp_h[0] >> SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); xmin = -frame->extension; ymin = -frame->extension; @@ -2106,13 +2229,15 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j ymax = (frame->height << mv_prec) + frame->extension; /* get source data if possible */ - if (!schro_frame_get_data (frame, &orig, 0 - , i * params->xbsep_luma, j * params->ybsep_luma)) { - /* this should never happen */ - SCHRO_ASSERT (0); + for (k=0; 3>k; ++k) { + if (!schro_frame_get_data (frame, &orig[k], k + , i * block_x[k], j * block_y[k])) { + /* this should never happen */ + SCHRO_ASSERT (0); + } + width[k] = MIN(comp_w[k], orig[k].width); + height[k] = MIN(comp_h[k], orig[k].height); } - width = MIN(xblen, orig.width); - height = MIN(yblen, orig.height); mv_motion = motion->motion_vectors + j * params->x_num_blocks + i; /* inherit from split 1 level MV */ @@ -2121,7 +2246,7 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j for (jj = 0; 4 > jj; jj += 2) { for (ii = 0; 4 > ii; ii += 2) { mv = mf->motion_vectors + (j+jj)*mf->x_num_blocks + i + ii; - if (SCHRO_METRIC_INVALID != mv->metric) { + if (INT_MAX != mv->metric) { if ((0 < n && !mv_already_in_list (hint_mv, n, mv, ref, 0)) || 0 == n) { hint_mv[n++] = mv; } @@ -2133,7 +2258,7 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j SCHRO_ASSERT (hbm); mf = schro_hbm_motion_field (hbm, 2); mv = mf->motion_vectors + j*mf->x_num_blocks + i; - if (SCHRO_METRIC_INVALID != mv->metric) { + if (INT_MAX != mv->metric) { if ((0 < n && !mv_already_in_list (hint_mv, n, mv, ref, mv_prec)) || 0 == n) { temp_mv = *mv; temp_mv.dx[ref] <<= mv_prec; @@ -2146,43 +2271,68 @@ schro_get_best_split0_mv (SchroMe me, int ref, int i, int j tmp_y = (j * params->ybsep_luma) << mv_prec; upframe = schro_me_ref (me, ref); for (m=0; n > m; ++m) { - dx = hint_mv[m]->dx[ref] + tmp_x; - dy = hint_mv[m]->dy[ref] + tmp_y; - if ( xmin > dx || ymin > dy - || !(xmax > dx + width - 1) || !(ymax > dy + height - 1) ) { - continue; + int ok = TRUE; + int chroma_metric = 0; + for (k=0; 3>k; ++k) { + tmp_x = (i*block_x[k]) << mv_prec; + tmp_y = (j*block_y[k]) << mv_prec; + dx = hint_mv[m]->dx[ref]; + dx >>= 0 == k ? 0 + : SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + dx += tmp_x; + dy = hint_mv[m]->dy[ref]; + dy >>= 0 == k ? 0 + : SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + dy += tmp_y; + if ( 0 == k && (xmin > dx || ymin > dy + || !(xmax > dx + width[k] - 1) || !(ymax > dy + height[k] - 1) )) { + ok = FALSE; + k=3; + continue; + } + if (ok) { + /* I need to save the original values of fd width and height */ + fd_width = fd->width; + fd_height = fd->height; + fd->width = width[k]; + fd->height = height[k]; + schro_upsampled_frame_get_block_fast_precN (upframe, k, dx, dy, mv_prec + , &ref_data[k], fd); + fd->width = fd_width; + fd->height = fd_height; + if (0 == k) { + metric = schro_metric_absdiff_u8 (orig[0].data, orig[0].stride + , ref_data[0].data, ref_data[0].stride, width[0], height[0]); + } else { + chroma_metric += schro_metric_absdiff_u8 (orig[k].data, orig[k].stride + , ref_data[k].data, ref_data[k].stride, width[k], height[k]); + } + } } - /* I need to save the original values of fd width and height */ - fd_width = fd->width; - fd_height = fd->height; - fd->width = width; - fd->height = height; - schro_upsampled_frame_get_block_fast_precN (upframe, 0, dx, dy, mv_prec - , &ref_data, fd); - fd->width = fd_width; - fd->height = fd_height; - metric = schro_metric_absdiff_u8 (orig.data, orig.stride - , ref_data.data, ref_data.stride, width, height); - *mv_motion = *hint_mv[m]; - mv_motion->split = 0; - mv_motion->pred_mode = ref + 1; - ent = schro_motion_block_estimate_entropy (motion, i, j); - score = ent + lambda * metric; - if (min_score > score) { - min_score = score; - min_m = m; - best_entropy = ent; - best_error = metric; + if (ok) { + *mv_motion = *hint_mv[m]; + mv_motion->split = 0; + mv_motion->pred_mode = ref + 1; + ent = schro_motion_block_estimate_entropy (motion, i, j); + score = ent + lambda * (metric+chroma_metric); + if (min_score > score) { + min_score = score; + min_m = m; + best_entropy = ent; + best_error = metric; + best_chroma_error = chroma_metric; + } } } if (-1 < min_m) { - *error = best_error; + *error = best_error+best_chroma_error; *entropy = best_entropy; *mv_ref = *hint_mv[min_m]; mv_ref->metric = best_error >> 4; + mv_ref->chroma_metric = best_chroma_error >> 4; mv_ref->split = 0; mv_ref->pred_mode = ref+1; - } else mv_ref->metric = SCHRO_METRIC_INVALID; + } else mv_ref->metric = INT_MAX; } @@ -2196,25 +2346,40 @@ schro_do_split0 (SchroMe me, int i, int j, SchroBlock* block SchroParams* params = schro_me_params (me); SchroFrame* orig_frame = schro_me_src (me); - SchroFrameData ref_data[2], orig; + SchroFrameData ref_data[3][2], orig[3]; SchroUpsampledFrame* upframe[2]; SchroMotionField* mf; SchroMotionVector mv_ref[2], best_mv={0}, *mv_split0; double lambda = schro_me_lambda (me); int mv_prec = params->mv_precision; - int xblen = params->xbsep_luma << 2 - , yblen = params->ybsep_luma << 2; - int width, height, dx[2], dy[2], tmp_x, tmp_y; - int ref, error=SCHRO_METRIC_INVALID, entropy[2]; - int best_error = SCHRO_METRIC_INVALID - , best_entropy = SCHRO_METRIC_INVALID; + int width[3], height[3], dx[2], dy[2], tmp_x, tmp_y; + int ref, error=INT_MAX, entropy[2]; + int best_error = INT_MAX + , best_entropy = INT_MAX; double score, min_score = DBL_MAX; int xmin = -orig_frame->extension, ymin = -orig_frame->extension , xmax = (orig_frame->width << mv_prec) + orig_frame->extension , ymax = (orig_frame->height << mv_prec) + orig_frame->extension; int biref, fd_width, fd_height; - best_mv.metric = SCHRO_METRIC_INVALID; + best_mv.metric = INT_MAX; + int k; + /* split2 block sizes for all components */ + int block_x[3], block_y[3]; + block_x[0] = params->xbsep_luma; + block_y[0] = params->ybsep_luma; + block_x[1] = block_x[2] = + block_x[0] >> SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + block_y[1] = block_y[2] = + block_y[0] >> SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + /* split0 block sizes for all components */ + int comp_w[3], comp_h[3]; + comp_w[0] = block_x[0] << 2; + comp_h[0] = block_y[0] << 2; + comp_w[1] = comp_w[2] = + comp_w[0] >> SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + comp_h[1] = comp_h[2] = + comp_h[0] >> SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); /* do the 2 references, if available */ for (ref = 0; params->num_refs > ref; ++ref) { @@ -2223,7 +2388,7 @@ schro_do_split0 (SchroMe me, int i, int j, SchroBlock* block mv_split0 = mf->motion_vectors + j*params->x_num_blocks + i; schro_get_best_split0_mv (me, ref, i, j, &mv_ref[ref], &error, &entropy[ref], fd); *mv_split0 = mv_ref[ref]; - if (SCHRO_METRIC_INVALID != mv_ref[ref].metric) { + if (INT_MAX != mv_ref[ref].metric) { score = entropy[ref] + lambda * error; if (min_score > score) { min_score = score; @@ -2235,54 +2400,77 @@ schro_do_split0 (SchroMe me, int i, int j, SchroBlock* block } /* do biref, if available */ if (1 < params->num_refs - && SCHRO_METRIC_INVALID != mv_ref[0].metric - && SCHRO_METRIC_INVALID != mv_ref[1].metric ) { + && INT_MAX != mv_ref[0].metric + && INT_MAX != mv_ref[1].metric ) { mv_ref[0].dx[1] = mv_ref[1].dx[1]; mv_ref[0].dy[1] = mv_ref[1].dy[1]; mv_ref[0].pred_mode = 3; biref = TRUE; - if (schro_frame_get_data (orig_frame, &orig, 0 - , i*params->xbsep_luma, j*params->ybsep_luma)) { - width = MIN(orig.width, xblen); - height = MIN(orig.height, yblen); - tmp_x = i * (params->xbsep_luma << mv_prec); - tmp_y = j * (params->ybsep_luma << mv_prec); + /* fetch source data */ + for (k=0; 3>k; ++k) { + if (schro_frame_get_data (orig_frame, &orig[k], k + , i*block_x[k], j*block_y[k])) { + width[k] = MIN(orig[k].width, comp_w[k]); + height[k] = MIN(orig[k].height, comp_h[k]); + } else { + biref = FALSE; + break; + } + } + if (biref) { + /* fetch reference data, if possible */ for (ref=0; params->num_refs > ref; ++ref) { - dx[ref] = tmp_x + mv_ref[0].dx[ref]; - dy[ref] = tmp_y + mv_ref[0].dy[ref]; - /* check whether we can extract reference blocks */ - if ( xmin > dx[ref] || ymin > dy[ref] - || !(xmax > dx[ref] + width - 1) - || !(ymax > dy[ref] + height - 1) ) { - biref = FALSE; - break; - } else { - fd_width = fd[ref].width; - fd_height = fd[ref].height; - fd[ref].width = width; - fd[ref].height = height; - upframe[ref] = schro_me_ref (me, ref); - schro_upsampled_frame_get_block_fast_precN (upframe[ref], 0 - , dx[ref], dy[ref], mv_prec, &ref_data[ref], &fd[ref]); - fd[ref].width = fd_width; - fd[ref].height = fd_height; + for (k=0; 3>k && biref; ++k) { + tmp_x = (i*block_x[k]) << mv_prec; + tmp_y = (j*block_y[k]) << mv_prec; + dx[ref] = mv_ref[0].dx[ref]; + dx[ref] >>= 0 == k ? 0 + : SCHRO_CHROMA_FORMAT_H_SHIFT(params->video_format->chroma_format); + dx[ref] += tmp_x; + dy[ref] = mv_ref[0].dy[ref]; + dy[ref] >>= 0 == k ? 0 + : SCHRO_CHROMA_FORMAT_V_SHIFT(params->video_format->chroma_format); + dy[ref] += tmp_y; + /* check whether we can extract reference blocks */ + if ( 0 == k && (xmin > dx[ref] || ymin > dy[ref] + || !(xmax > dx[ref] + width[k] - 1) + || !(ymax > dy[ref] + height[k] - 1) )) { + biref = FALSE; + break; + } else { + fd_width = fd[ref].width; + fd_height = fd[ref].height; + fd[ref].width = width[k]; + fd[ref].height = height[k]; + upframe[ref] = schro_me_ref (me, ref); + schro_upsampled_frame_get_block_fast_precN (upframe[ref], k + , dx[ref], dy[ref], mv_prec, &ref_data[k][ref], &fd[ref]); + fd[ref].width = fd_width; + fd[ref].height = fd_height; + } } } if (biref) { - error = schro_metric_get_biref (&orig, &ref_data[0], 1 - , &ref_data[1], 1, 1, width, height); - score = entropy[0] + entropy[1] + lambda * error; - mv_ref[0].metric = error; + int chroma_error = 0; + error = schro_metric_get_biref (&orig[0], &ref_data[0][0], 1 + , &ref_data[0][1], 1, 1, width[0], height[0]); + for (k=1; 3>k; ++k) { + chroma_error += schro_metric_get_biref (&orig[k], &ref_data[k][0], 1 + , &ref_data[k][1], 1, 1, width[k], height[k]); + } + score = entropy[0] + entropy[1] + lambda * (error+chroma_error); + mv_ref[0].metric = error>>4; + mv_ref[0].chroma_metric = chroma_error>>4; if (min_score > score) { min_score = score; best_mv = mv_ref[0]; - best_error = error; + best_error = error+chroma_error; best_entropy = entropy[0] + entropy[1]; } } } } - if (SCHRO_METRIC_INVALID == best_mv.metric) { + if (INT_MAX == best_mv.metric) { block->valid = FALSE; } else { block->valid = TRUE; @@ -2345,14 +2533,12 @@ schro_mode_decision (SchroMe me) min_score = block.score; /* Note: only do split0 if split1 better than split2 */ schro_do_split0 (me, i, j, &tryblock, fd); -#if 0 if (tryblock.valid) { if (min_score > tryblock.score) { memcpy (&block, &tryblock, sizeof(block)); schro_block_fixup (&block); } } -#endif } } schro_motion_copy_to (motion, i, j, &block); diff --git a/schroedinger/schroroughmotion.c b/schroedinger/schroroughmotion.c index 0ccc4ad..f89824d 100644 --- a/schroedinger/schroroughmotion.c +++ b/schroedinger/schroroughmotion.c @@ -101,13 +101,15 @@ schro_rough_me_heirarchical_scan_nohint (SchroRoughME *rme, int shift, skip = 1<y_num_blocks;j+=skip){ for(i=0;ix_num_blocks;i+=skip){ - int dx=0, dy=0; + int dx, dy; + scan.gravity_x = 0; + scan.gravity_y = 0; scan.x = (i>>shift) * params->xbsep_luma; scan.y = (j>>shift) * params->ybsep_luma; scan.block_width = MIN(scan.frame->width - scan.x, params->xbsep_luma); scan.block_height = MIN(scan.frame->height - scan.y, params->ybsep_luma); - schro_metric_scan_setup (&scan, 0, 0, distance); + schro_metric_scan_setup (&scan, 0, 0, distance, FALSE); mv = motion_field_get (mf, i, j); if (scan.scan_width <= 0 || scan.scan_height <= 0) { @@ -128,8 +130,9 @@ schro_rough_me_heirarchical_scan_nohint (SchroRoughME *rme, int shift, } #endif - schro_metric_scan_do_scan (&scan, FALSE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); dx <<= shift; dy <<= shift; @@ -270,12 +273,14 @@ schro_rough_me_heirarchical_scan_hint (SchroRoughME *rme, int shift, dx = hint_mv[min_m]->dx[ref] >> shift; dy = hint_mv[min_m]->dy[ref] >> shift; + scan.gravity_x = dx; + scan.gravity_y = dy; scan.x = (i>>shift) * params->xbsep_luma; scan.y = (j>>shift) * params->ybsep_luma; scan.block_width = MIN(scan.frame->width - scan.x, params->xbsep_luma); scan.block_height = MIN(scan.frame->height - scan.y, params->ybsep_luma); - schro_metric_scan_setup (&scan, dx, dy, distance); + schro_metric_scan_setup (&scan, dx, dy, distance, FALSE); mv = motion_field_get (mf, i, j); if (scan.scan_width <= 0 || scan.scan_height <= 0) { @@ -285,8 +290,9 @@ schro_rough_me_heirarchical_scan_hint (SchroRoughME *rme, int shift, continue; } - schro_metric_scan_do_scan (&scan, FALSE); - mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy); + schro_metric_scan_do_scan (&scan); + uint32_t dummy; + mv->metric = schro_metric_scan_get_min (&scan, &dx, &dy, &dummy); dx <<= shift; dy <<= shift; -- 2.11.4.GIT