Change intra reconstruction to use the same prediction function as search.

- This fixes a bug with intra search. It sometimes used filtered reference
  pixels for 4x4 blocks leading to inaccurate cost estimate.
This commit is contained in:
Ari Koivula 2014-04-10 11:55:32 +03:00
parent d5c3ad7a2b
commit 40c2fa4d46
2 changed files with 43 additions and 42 deletions

View file

@ -238,25 +238,41 @@ static uint32_t intra_pred_ratecost(int16_t mode, int8_t *intra_preds)
* \param recstride Stride for rec pixel arrays. * \param recstride Stride for rec pixel arrays.
* \param dst * \param dst
*/ */
static void intra_get_pred(pixel *rec[2], int recstride, pixel *dst, int width, int mode) static void intra_get_pred(pixel *rec[2], int recstride, pixel *dst, int width, int mode, int is_chroma)
{ {
if (mode == 0) { pixel *ref_pixels = rec[0];
intra_get_planar_pred(rec[1], recstride, width, dst, width); if (is_chroma || mode == 1 || width == 4) {
} else if (mode == 1) { // For chroma, DC and 4x4 blocks, always use unfiltered reference.
int i; } else if (mode == 0) {
pixel val = intra_get_dc_pred(rec[0], recstride, width); // Otherwise, use filtered for planar.
for (i = 0; i < width * width; i++) { ref_pixels = rec[1];
dst[i] = val;
}
} else { } else {
// Angular modes use smoothed reference pixels, unless the mode is close // Angular modes use smoothed reference pixels, unless the mode is close
// to being either vertical or horizontal. // to being either vertical or horizontal.
int filter_threshold = intra_hor_ver_dist_thres[g_to_bits[width]]; int filter_threshold = intra_hor_ver_dist_thres[g_to_bits[width]];
int dist_from_vert_or_hor = MIN(abs(mode - 26), abs(mode - 10)); int dist_from_vert_or_hor = MIN(abs(mode - 26), abs(mode - 10));
if (dist_from_vert_or_hor <= filter_threshold) { if (dist_from_vert_or_hor > filter_threshold) {
intra_get_angular_pred(rec[0], recstride, dst, width, width, mode, width<32); ref_pixels = rec[1];
}
}
if (mode == 0) {
intra_get_planar_pred(ref_pixels, recstride, width, dst, width);
} else if (mode == 1) {
int i;
pixel val = intra_get_dc_pred(ref_pixels, recstride, width);
for (i = 0; i < width * width; i++) {
dst[i] = val;
}
} else { } else {
intra_get_angular_pred(rec[1], recstride, dst, width, width, mode, width<32);
int filter_threshold = intra_hor_ver_dist_thres[g_to_bits[width]];
int dist_from_vert_or_hor = MIN(abs(mode - 26), abs(mode - 10));
int filter = !is_chroma && width < 32;
if (dist_from_vert_or_hor <= filter_threshold) {
intra_get_angular_pred(ref_pixels, recstride, dst, width, width, mode, filter);
} else {
intra_get_angular_pred(ref_pixels, recstride, dst, width, width, mode, filter);
} }
} }
} }
@ -310,7 +326,7 @@ int16_t intra_prediction(pixel *orig, int32_t origstride, pixel *rec, int16_t re
// Try all modes and select the best one. // Try all modes and select the best one.
for (mode = 0; mode < 35; mode++) { for (mode = 0; mode < 35; mode++) {
intra_get_pred(ref, recstride, pred, width, mode); intra_get_pred(ref, recstride, pred, width, mode, 0);
{ {
uint32_t mode_cost = intra_pred_ratecost(mode, intra_preds); uint32_t mode_cost = intra_pred_ratecost(mode, intra_preds);
@ -343,42 +359,27 @@ int16_t intra_prediction(pixel *orig, int32_t origstride, pixel *rec, int16_t re
* \param chroma chroma-block flag * \param chroma chroma-block flag
*/ */
void intra_recon(pixel* rec, uint32_t recstride, uint32_t width, pixel* dst, int32_t dststride, int8_t mode, int8_t chroma) void intra_recon(pixel* rec, int32_t recstride, uint32_t width, pixel* dst, int32_t dststride, int8_t mode, int8_t chroma)
{ {
int32_t x,y;
pixel pred[LCU_WIDTH * LCU_WIDTH]; pixel pred[LCU_WIDTH * LCU_WIDTH];
int8_t filter = !chroma && width < 32; pixel rec_filtered_temp[(LCU_WIDTH * 2 + 8) * (LCU_WIDTH * 2 + 8) + 1];
pixel *ref[2] = {rec, &rec_filtered_temp[recstride + 1]};
// Generate filtered reference pixels.
// Filtering apply if luma and not DC {
if (!chroma && mode != 1 && width > 4) { int x, y;
uint8_t threshold = intra_hor_ver_dist_thres[g_to_bits[width]]; for (y = -1; y < recstride; y++) {
if(MIN(abs(mode-26),abs(mode-10)) > threshold) { ref[1][y*recstride - 1] = rec[y*recstride - 1];
intra_filter(rec,recstride,width,0);
} }
for (x = 0; x < recstride; x++) {
ref[1][x - recstride] = rec[x - recstride];
}
intra_filter(ref[1], recstride, width, 0);
} }
// planar intra_get_pred(ref, recstride, pred, width, mode, chroma);
if (mode == 0) {
intra_get_planar_pred(rec, recstride, width, pred, width);
} else if (mode == 1) { // DC
pixel val = intra_get_dc_pred(rec, (uint16_t)recstride, (uint8_t)width);
for (y = 0; y < (int32_t)width; y++) {
for (x = 0; x < (int32_t)width; x++) {
dst[x + y*dststride] = val;
}
}
// Assigned value directly to output, no need to stay here
return;
} else { // directional predictions
intra_get_angular_pred(rec, recstride,pred, width, width, mode, filter);
}
for(y = 0; y < (int32_t)width; y++) { picture_blit_pixels(pred, dst, width, width, width, dststride);
for(x = 0; x < (int32_t)width; x++) {
dst[x+y*dststride] = pred[x+y*width];
}
}
} }
/** /**

View file

@ -47,7 +47,7 @@ pixel intra_get_dc_pred(pixel* pic, uint16_t pic_width, uint8_t width);
void intra_get_planar_pred(pixel* src,int32_t srcstride, uint32_t width, pixel* dst, int32_t dststride); void intra_get_planar_pred(pixel* src,int32_t srcstride, uint32_t width, pixel* dst, int32_t dststride);
void intra_get_angular_pred(pixel* src, int32_t src_stride, pixel* p_dst, int32_t dst_stride, int32_t width, int32_t dir_mode, int8_t filter); void intra_get_angular_pred(pixel* src, int32_t src_stride, pixel* p_dst, int32_t dst_stride, int32_t width, int32_t dir_mode, int8_t filter);
void intra_recon(pixel* rec, uint32_t rec_stride, uint32_t width, pixel* dst, int32_t dst_stride, int8_t mode, int8_t chroma); void intra_recon(pixel* rec, int32_t rec_stride, uint32_t width, pixel* dst, int32_t dst_stride, int8_t mode, int8_t chroma);
void intra_recon_lcu(encoder_control* encoder, cabac_data *cabac, int x, int y, int depth, lcu_t *lcu, uint32_t pic_width, uint32_t pic_height); void intra_recon_lcu(encoder_control* encoder, cabac_data *cabac, int x, int y, int depth, lcu_t *lcu, uint32_t pic_width, uint32_t pic_height);