Added drop_frame support in multi-resolution encoder.
If one frame is dropped at a lower-resolution level, the next
upper-resolution level encoder needs to encode that frame
independently without any lower-resolution level motion
information.
Another issue is that if one frame is dropped at some but not all
resolution levels, a frame after that one may use different set
of reference frames at different resolution levels. This reference
frame asynchronization could degrade motion search precision in
upper-resolution level encoding, which uses lower-resolution level
motion result. This change compares the lower-resolution and upper-
resolution level's reference frames. If they are not the same, the
upper-resolution level encoder can not use lower-resolution level
motion result.
Change-Id: I61afa4f313630e75b7cbdd5742e230e8724a988a
typedef struct
{
FRAME_TYPE frame_type;
+ int is_frame_dropped;
+ /* The frame number of each reference frames */
+ unsigned int low_res_ref_frames[MAX_REF_FRAMES];
LOWER_RES_MB_INFO *mb_info;
} LOWER_RES_FRAME_INFO;
#endif
void vp8_cal_dissimilarity(VP8_COMP *cpi)
{
VP8_COMMON *cm = &cpi->common;
+ int i;
/* Note: The first row & first column in mip are outside the frame, which
* were initialized to all 0.(ref_frame, mode, mv...)
store_info->frame_type = cm->frame_type;
+ if(cm->frame_type != KEY_FRAME)
+ {
+ store_info->is_frame_dropped = 0;
+ for (i = 1; i < MAX_REF_FRAMES; i++)
+ store_info->low_res_ref_frames[i] = cpi->current_ref_frames[i];
+ }
+
if(cm->frame_type != KEY_FRAME)
{
int mb_row;
}
}
}
+
+/* This function is called only when this frame is dropped at current
+ resolution level. */
+void vp8_store_drop_frame_info(VP8_COMP *cpi)
+{
+ /* If the frame is dropped in lower-resolution encoding, this information
+ is passed to higher resolution level so that the encoder knows there
+ is no mode & motion info available.
+ */
+ if (cpi->oxcf.mr_total_resolutions >1
+ && cpi->oxcf.mr_encoder_id < (cpi->oxcf.mr_total_resolutions - 1))
+ {
+ /* Store info for show/no-show frames for supporting alt_ref.
+ * If parent frame is alt_ref, child has one too.
+ */
+ LOWER_RES_FRAME_INFO* store_info
+ = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info;
+
+ /* Set frame_type to be INTER_FRAME since we won't drop key frame. */
+ store_info->frame_type = INTER_FRAME;
+ store_info->is_frame_dropped = 1;
+ }
+}
extern void vp8_cal_low_res_mb_cols(VP8_COMP *cpi);
extern void vp8_cal_dissimilarity(VP8_COMP *cpi);
+extern void vp8_store_drop_frame_info(VP8_COMP *cpi);
#endif
return force_recode;
}
-static void update_reference_frames(VP8_COMMON *cm)
+static void update_reference_frames(VP8_COMP *cpi)
{
+ VP8_COMMON *cm = &cpi->common;
YV12_BUFFER_CONFIG *yv12_fb = cm->yv12_fb;
/* At this point the new frame has been encoded.
yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALTR_FRAME;
cm->alt_fb_idx = cm->gld_fb_idx = cm->new_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[GOLDEN_FRAME] = cm->current_video_frame;
+ cpi->current_ref_frames[ALTREF_FRAME] = cm->current_video_frame;
+#endif
}
else /* For non key frames */
{
cm->yv12_fb[cm->new_fb_idx].flags |= VP8_ALTR_FRAME;
cm->yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALTR_FRAME;
cm->alt_fb_idx = cm->new_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[ALTREF_FRAME] = cm->current_video_frame;
+#endif
}
else if (cm->copy_buffer_to_arf)
{
yv12_fb[cm->lst_fb_idx].flags |= VP8_ALTR_FRAME;
yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALTR_FRAME;
cm->alt_fb_idx = cm->lst_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[ALTREF_FRAME] =
+ cpi->current_ref_frames[LAST_FRAME];
+#endif
}
}
else /* if (cm->copy_buffer_to_arf == 2) */
yv12_fb[cm->gld_fb_idx].flags |= VP8_ALTR_FRAME;
yv12_fb[cm->alt_fb_idx].flags &= ~VP8_ALTR_FRAME;
cm->alt_fb_idx = cm->gld_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[ALTREF_FRAME] =
+ cpi->current_ref_frames[GOLDEN_FRAME];
+#endif
}
}
}
cm->yv12_fb[cm->new_fb_idx].flags |= VP8_GOLD_FRAME;
cm->yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FRAME;
cm->gld_fb_idx = cm->new_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[GOLDEN_FRAME] = cm->current_video_frame;
+#endif
}
else if (cm->copy_buffer_to_gf)
{
yv12_fb[cm->lst_fb_idx].flags |= VP8_GOLD_FRAME;
yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FRAME;
cm->gld_fb_idx = cm->lst_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[GOLDEN_FRAME] =
+ cpi->current_ref_frames[LAST_FRAME];
+#endif
}
}
else /* if (cm->copy_buffer_to_gf == 2) */
yv12_fb[cm->alt_fb_idx].flags |= VP8_GOLD_FRAME;
yv12_fb[cm->gld_fb_idx].flags &= ~VP8_GOLD_FRAME;
cm->gld_fb_idx = cm->alt_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[GOLDEN_FRAME] =
+ cpi->current_ref_frames[ALTREF_FRAME];
+#endif
}
}
}
cm->yv12_fb[cm->new_fb_idx].flags |= VP8_LAST_FRAME;
cm->yv12_fb[cm->lst_fb_idx].flags &= ~VP8_LAST_FRAME;
cm->lst_fb_idx = cm->new_fb_idx;
+
+#if CONFIG_MULTI_RES_ENCODING
+ cpi->current_ref_frames[LAST_FRAME] = cm->current_video_frame;
+#endif
}
}
*/
if (cpi->oxcf.mr_encoder_id)
{
- cm->frame_type =
- ((LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info)->frame_type;
+ LOWER_RES_FRAME_INFO* low_res_frame_info
+ = (LOWER_RES_FRAME_INFO*)cpi->oxcf.mr_low_res_mode_info;
+
+ cm->frame_type = low_res_frame_info->frame_type;
+
+ if(cm->frame_type != KEY_FRAME)
+ {
+ cpi->mr_low_res_mv_avail = 1;
+ cpi->mr_low_res_mv_avail &= !(low_res_frame_info->is_frame_dropped);
+
+ if (cpi->ref_frame_flags & VP8_LAST_FRAME)
+ cpi->mr_low_res_mv_avail &= (cpi->current_ref_frames[LAST_FRAME]
+ == low_res_frame_info->low_res_ref_frames[LAST_FRAME]);
+
+ if (cpi->ref_frame_flags & VP8_GOLD_FRAME)
+ cpi->mr_low_res_mv_avail &= (cpi->current_ref_frames[GOLDEN_FRAME]
+ == low_res_frame_info->low_res_ref_frames[GOLDEN_FRAME]);
+
+ if (cpi->ref_frame_flags & VP8_ALTR_FRAME)
+ cpi->mr_low_res_mv_avail &= (cpi->current_ref_frames[ALTREF_FRAME]
+ == low_res_frame_info->low_res_ref_frames[ALTREF_FRAME]);
+ }
}
#endif
if (cpi->bits_off_target > cpi->oxcf.maximum_buffer_size)
cpi->bits_off_target = cpi->oxcf.maximum_buffer_size;
+#if CONFIG_MULTI_RES_ENCODING
+ vp8_store_drop_frame_info(cpi);
+#endif
+
cm->current_video_frame++;
cpi->frames_since_key++;
/* Decide how big to make the frame */
if (!vp8_pick_frame_size(cpi))
{
+ /*TODO: 2 drop_frame and return code could be put together. */
+#if CONFIG_MULTI_RES_ENCODING
+ vp8_store_drop_frame_info(cpi);
+#endif
cm->current_video_frame++;
cpi->frames_since_key++;
return;
vp8_loopfilter_frame(cpi, cm);
}
- update_reference_frames(cm);
+ update_reference_frames(cpi);
#if !(CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
if (cpi->oxcf.error_resilient_mode)
#if CONFIG_MULTI_RES_ENCODING
/* Number of MBs per row at lower-resolution level */
int mr_low_res_mb_cols;
+ /* Indicate if lower-res mv info is available */
+ unsigned char mr_low_res_mv_avail;
+ /* The frame number of each reference frames */
+ unsigned int current_ref_frames[MAX_REF_FRAMES];
#endif
struct rd_costs_struct
int_mv parent_ref_mv;
MB_PREDICTION_MODE parent_mode = 0;
- if (cpi->oxcf.mr_encoder_id)
+ if (cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail)
get_lower_res_motion_info(cpi, xd, &dissim, &parent_ref_frame,
&parent_mode, &parent_ref_mv, mb_row, mb_col);
#endif
x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame;
#if CONFIG_MULTI_RES_ENCODING
- if (cpi->oxcf.mr_encoder_id)
+ if (cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail)
{
- /* If parent MB is intra, child MB is intra. */
- if (!parent_ref_frame && this_ref_frame)
- continue;
+ /* TODO: If parent MB is intra, child MB is intra. This is removed
+ * now since it cause noticeable quality loss for some test clip.
+ * Will come back to evaluate more.
+ * if (!parent_ref_frame && this_ref_frame)
+ * continue;
+ */
/* If parent MB is inter, and it is unlikely there are multiple
* objects in parent MB, we use parent ref frame as child MB's
}
#if CONFIG_MULTI_RES_ENCODING
- if (cpi->oxcf.mr_encoder_id)
+ if (cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail)
{
if (vp8_mode_order[mode_index] == NEARESTMV &&
mode_mv[NEARESTMV].as_int ==0)
step_param = cpi->sf.first_step + speed_adjust;
#if CONFIG_MULTI_RES_ENCODING
- if (cpi->oxcf.mr_encoder_id)
+ /* If lower-res drops this frame, then higher-res encoder does
+ motion search without any previous knowledge. Also, since
+ last frame motion info is not stored, then we can not
+ use improved_mv_pred. */
+ if (cpi->oxcf.mr_encoder_id && !cpi->mr_low_res_mv_avail)
+ cpi->sf.improved_mv_pred = 0;
+
+ if (cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail)
{
/* Use parent MV as predictor. Adjust search range
* accordingly.
}
#if CONFIG_MULTI_RES_ENCODING
- if (cpi->oxcf.mr_encoder_id && dissim <= 2 &&
+ if (cpi->oxcf.mr_encoder_id && cpi->mr_low_res_mv_avail &&
+ dissim <= 2 &&
MAX(abs(best_ref_mv.as_mv.row - parent_ref_mv.as_mv.row),
abs(best_ref_mv.as_mv.col - parent_ref_mv.as_mv.col)) <= 4)
{
* change the behavior in lowest-resolution encoder.
* Will improve it later.
*/
- if (!cpi->oxcf.mr_encoder_id)
+ /* Set step_param to 0 to ensure large-range motion search
+ when encoder drops this frame at lower-resolution.
+ */
+ if (!cpi->oxcf.mr_encoder_id || !cpi->mr_low_res_mv_avail)
step_param = 0;
#endif
bestsme = vp8_hex_search(x, b, d, &mvp_full, &d->bmi.mv,
* multi-res-encoder.*/
#if CONFIG_MULTI_RES_ENCODING
if (ctx->base.enc.total_encoders > 1)
- {
RANGE_CHECK_HI(cfg, rc_resize_allowed, 0);
- RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 0);
- }
#else
RANGE_CHECK_BOOL(cfg, rc_resize_allowed);
- RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100);
#endif
+ RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100);
RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100);
RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
cfg[0].g_w = width;
cfg[0].g_h = height;
cfg[0].g_threads = 1; /* number of threads used */
- cfg[0].rc_dropframe_thresh = 0;
+ cfg[0].rc_dropframe_thresh = 30;
cfg[0].rc_end_usage = VPX_CBR;
cfg[0].rc_resize_allowed = 0;
cfg[0].rc_min_quantizer = 4;
cfg[0].rc_buf_initial_sz = 500;
cfg[0].rc_buf_optimal_sz = 600;
cfg[0].rc_buf_sz = 1000;
- //cfg[0].rc_dropframe_thresh = 10;
cfg[0].g_error_resilient = 1; /* Enable error resilient mode */
cfg[0].g_lag_in_frames = 0;
*/
//cfg[0].kf_mode = VPX_KF_DISABLED;
cfg[0].kf_mode = VPX_KF_AUTO;
- cfg[0].kf_min_dist = 0;
- cfg[0].kf_max_dist = 150;
+ cfg[0].kf_min_dist = 3000;
+ cfg[0].kf_max_dist = 3000;
cfg[0].rc_target_bitrate = target_bitrate[0]; /* Set target bitrate */
cfg[0].g_timebase.num = 1; /* Set fps */
if(vpx_codec_control(&codec[i], VP8E_SET_STATIC_THRESHOLD, static_thresh))
die_codec(&codec[i], "Failed to set static threshold");
}
+ /* Set NOISE_SENSITIVITY to do TEMPORAL_DENOISING */
+ for ( i=0; i< NUM_ENCODERS; i++)
+ {
+ if(vpx_codec_control(&codec[i], VP8E_SET_NOISE_SENSITIVITY, 0))
+ die_codec(&codec[i], "Failed to set noise_sensitivity");
+ }
frame_avail = 1;
got_data = 0;