| Index: source/libvpx/vp8/encoder/onyx_if.c
|
| ===================================================================
|
| --- source/libvpx/vp8/encoder/onyx_if.c (revision 290053)
|
| +++ source/libvpx/vp8/encoder/onyx_if.c (working copy)
|
| @@ -613,6 +613,24 @@
|
| while(block_count && i != cpi->cyclic_refresh_mode_index);
|
|
|
| cpi->cyclic_refresh_mode_index = i;
|
| +
|
| +#if CONFIG_TEMPORAL_DENOISING
|
| + if (cpi->denoiser.denoiser_mode == kDenoiserOnYUVAggressive &&
|
| + Q < (int)cpi->denoiser.denoise_pars.qp_thresh) {
|
| + // Under aggressive denoising mode, use segmentation to turn off loop
|
| + // filter below some qp thresh. The loop filter is turned off for all
|
| + // blocks that have been encoded as ZEROMV LAST x frames in a row,
|
| + // where x is set by cpi->denoiser.denoise_pars.consec_zerolast.
|
| + // This is to avoid "dot" artifacts that can occur from repeated
|
| + // loop filtering on noisy input source.
|
| + cpi->cyclic_refresh_q = Q;
|
| + lf_adjustment = -MAX_LOOP_FILTER;
|
| + for (i = 0; i < mbs_in_frame; ++i) {
|
| + seg_map[i] = (cpi->consec_zero_last[i] >
|
| + cpi->denoiser.denoise_pars.consec_zerolast) ? 1 : 0;
|
| + }
|
| + }
|
| +#endif
|
| }
|
|
|
| /* Activate segmentation. */
|
| @@ -1264,7 +1282,8 @@
|
| if (cpi->oxcf.noise_sensitivity > 0) {
|
| vp8_denoiser_free(&cpi->denoiser);
|
| vp8_denoiser_allocate(&cpi->denoiser, width, height,
|
| - cm->mb_rows, cm->mb_cols);
|
| + cm->mb_rows, cm->mb_cols,
|
| + cpi->oxcf.noise_sensitivity);
|
| }
|
| #endif
|
| }
|
| @@ -1760,7 +1779,8 @@
|
| int width = (cpi->oxcf.Width + 15) & ~15;
|
| int height = (cpi->oxcf.Height + 15) & ~15;
|
| vp8_denoiser_allocate(&cpi->denoiser, width, height,
|
| - cpi->common.mb_rows, cpi->common.mb_cols);
|
| + cm->mb_rows, cm->mb_cols,
|
| + cpi->oxcf.noise_sensitivity);
|
| }
|
| }
|
| #endif
|
| @@ -1887,6 +1907,13 @@
|
| */
|
| cpi->cyclic_refresh_mode_enabled = cpi->oxcf.error_resilient_mode;
|
| cpi->cyclic_refresh_mode_max_mbs_perframe = (cpi->common.mb_rows * cpi->common.mb_cols) / 5;
|
| + if (cpi->oxcf.number_of_layers == 1) {
|
| + cpi->cyclic_refresh_mode_max_mbs_perframe =
|
| + (cpi->common.mb_rows * cpi->common.mb_cols) / 20;
|
| + } else if (cpi->oxcf.number_of_layers == 2) {
|
| + cpi->cyclic_refresh_mode_max_mbs_perframe =
|
| + (cpi->common.mb_rows * cpi->common.mb_cols) / 10;
|
| + }
|
| cpi->cyclic_refresh_mode_index = 0;
|
| cpi->cyclic_refresh_q = 32;
|
|
|
| @@ -1897,6 +1924,9 @@
|
| else
|
| cpi->cyclic_refresh_map = (signed char *) NULL;
|
|
|
| + CHECK_MEM_ERROR(cpi->consec_zero_last,
|
| + vpx_calloc(cpi->common.mb_rows * cpi->common.mb_cols, 1));
|
| +
|
| #ifdef VP8_ENTROPY_STATS
|
| init_context_counters();
|
| #endif
|
| @@ -2417,6 +2447,7 @@
|
| vpx_free(cpi->mb.ss);
|
| vpx_free(cpi->tok);
|
| vpx_free(cpi->cyclic_refresh_map);
|
| + vpx_free(cpi->consec_zero_last);
|
|
|
| vp8_remove_common(&cpi->common);
|
| vpx_free(cpi);
|
| @@ -3119,10 +3150,8 @@
|
|
|
| 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 */
|
| {
|
| @@ -3134,9 +3163,7 @@
|
| 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)
|
| {
|
| @@ -3150,10 +3177,8 @@
|
| 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) */
|
| @@ -3164,10 +3189,8 @@
|
| 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
|
| }
|
| }
|
| }
|
| @@ -3180,9 +3203,7 @@
|
| 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)
|
| {
|
| @@ -3196,10 +3217,8 @@
|
| 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) */
|
| @@ -3210,10 +3229,8 @@
|
| 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
|
| }
|
| }
|
| }
|
| @@ -3225,9 +3242,7 @@
|
| 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 CONFIG_TEMPORAL_DENOISING
|
| @@ -3268,12 +3283,119 @@
|
| &cpi->denoiser.yv12_running_avg[LAST_FRAME]);
|
| }
|
| }
|
| + if (cpi->oxcf.noise_sensitivity == 4)
|
| + vp8_yv12_copy_frame(cpi->Source, &cpi->denoiser.yv12_last_source);
|
|
|
| }
|
| #endif
|
|
|
| }
|
|
|
| +static void process_denoiser_mode_change(VP8_COMP *cpi) {
|
| + const VP8_COMMON *const cm = &cpi->common;
|
| + int i, j;
|
| + int total = 0;
|
| + int num_blocks = 0;
|
| + // Number of blocks skipped along row/column in computing the
|
| + // nmse (normalized mean square error) of source.
|
| + int skip = 2;
|
| + // Only select blocks for computing nmse that have been encoded
|
| + // as ZERO LAST min_consec_zero_last frames in a row.
|
| + int min_consec_zero_last = 10;
|
| + // Decision is tested for changing the denoising mode every
|
| + // num_mode_change times this function is called. Note that this
|
| + // function called every 8 frames, so (8 * num_mode_change) is number
|
| + // of frames where denoising mode change is tested for switch.
|
| + int num_mode_change = 15;
|
| + // Framerate factor, to compensate for larger mse at lower framerates.
|
| + // TODO(marpan): Adjust this factor,
|
| + int fac_framerate = cpi->output_framerate < 25.0f ? 80 : 100;
|
| + int tot_num_blocks = cm->mb_rows * cm->mb_cols;
|
| + int ystride = cpi->Source->y_stride;
|
| + unsigned char *src = cpi->Source->y_buffer;
|
| + unsigned char *dst = cpi->denoiser.yv12_last_source.y_buffer;
|
| + static const unsigned char const_source[16] = {
|
| + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
|
| + 128, 128, 128};
|
| +
|
| + // Loop through the Y plane, every skip blocks along rows and columns,
|
| + // summing the normalized mean square error, only for blocks that have
|
| + // been encoded as ZEROMV LAST at least min_consec_zero_last least frames in
|
| + // a row and have small sum difference between current and previous frame.
|
| + // Normalization here is by the contrast of the current frame block.
|
| + for (i = 0; i < cm->Height; i += 16 * skip) {
|
| + int block_index_row = (i >> 4) * cm->mb_cols;
|
| + for (j = 0; j < cm->Width; j += 16 * skip) {
|
| + int index = block_index_row + (j >> 4);
|
| + if (cpi->consec_zero_last[index] >= min_consec_zero_last) {
|
| + unsigned int sse;
|
| + const unsigned int mse = vp8_mse16x16(src + j,
|
| + ystride,
|
| + dst + j,
|
| + ystride,
|
| + &sse);
|
| + const unsigned int var = vp8_variance16x16(src + j,
|
| + ystride,
|
| + dst + j,
|
| + ystride,
|
| + &sse);
|
| + // Only consider this block as valid for noise measurement
|
| + // if the sum_diff average of the current and previous frame
|
| + // is small (to avoid effects from lighting change).
|
| + if ((mse - var) < 256) {
|
| + const unsigned int act = vp8_variance16x16(src + j,
|
| + ystride,
|
| + const_source,
|
| + 0,
|
| + &sse);
|
| + if (act > 0)
|
| + total += mse / act;
|
| + num_blocks++;
|
| + }
|
| + }
|
| + }
|
| + src += 16 * skip * ystride;
|
| + dst += 16 * skip * ystride;
|
| + }
|
| + total = total * fac_framerate / 100;
|
| +
|
| + // Only consider this frame as valid sample if we have computed nmse over
|
| + // at least ~1/16 blocks, and Total > 0 (Total == 0 can happen if the
|
| + // application inputs duplicate frames, or contrast is all zero).
|
| + if (total > 0 &&
|
| + (num_blocks > (tot_num_blocks >> 4))) {
|
| + // Update the recursive mean square source_diff.
|
| + if (cpi->denoiser.nmse_source_diff_count == 0)
|
| + // First sample in new interval.
|
| + cpi->denoiser.nmse_source_diff = total;
|
| + else
|
| + // For subsequent samples, use average with weight ~1/4 for new sample.
|
| + cpi->denoiser.nmse_source_diff = (int)((total >> 2) +
|
| + 3 * (cpi->denoiser.nmse_source_diff >> 2));
|
| + cpi->denoiser.nmse_source_diff_count++;
|
| + }
|
| + // Check for changing the denoiser mode, when we have obtained #samples =
|
| + // num_mode_change.
|
| + if (cpi->denoiser.nmse_source_diff_count == num_mode_change) {
|
| + // Check for going up: from normal to aggressive mode.
|
| + if ((cpi->denoiser.denoiser_mode = kDenoiserOnYUV) &&
|
| + (cpi->denoiser.nmse_source_diff >
|
| + cpi->denoiser.threshold_aggressive_mode)) {
|
| + vp8_denoiser_set_parameters(&cpi->denoiser, kDenoiserOnYUVAggressive);
|
| + } else {
|
| + // Check for going down: from aggressive to normal mode.
|
| + if ((cpi->denoiser.denoiser_mode = kDenoiserOnYUVAggressive) &&
|
| + (cpi->denoiser.nmse_source_diff <
|
| + cpi->denoiser.threshold_aggressive_mode)) {
|
| + vp8_denoiser_set_parameters(&cpi->denoiser, kDenoiserOnYUV);
|
| + }
|
| + }
|
| + // Reset metric and counter for next interval.
|
| + cpi->denoiser.nmse_source_diff = 0;
|
| + cpi->denoiser.nmse_source_diff_count = 0;
|
| + }
|
| +}
|
| +
|
| void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm)
|
| {
|
| const FRAME_TYPE frame_type = cm->frame_type;
|
| @@ -3430,6 +3552,12 @@
|
| {
|
| /* Key frame from VFW/auto-keyframe/first frame */
|
| cm->frame_type = KEY_FRAME;
|
| +#if CONFIG_TEMPORAL_DENOISING
|
| + if (cpi->oxcf.noise_sensitivity == 4) {
|
| + // For adaptive mode, reset denoiser to normal mode on key frame.
|
| + vp8_denoiser_set_parameters(&cpi->denoiser, kDenoiserOnYUV);
|
| + }
|
| +#endif
|
| }
|
|
|
| #if CONFIG_MULTI_RES_ENCODING
|
| @@ -3463,6 +3591,31 @@
|
| }
|
| #endif
|
|
|
| + // Find the reference frame closest to the current frame.
|
| + cpi->closest_reference_frame = LAST_FRAME;
|
| + if (cm->frame_type != KEY_FRAME) {
|
| + int i;
|
| + MV_REFERENCE_FRAME closest_ref = INTRA_FRAME;
|
| + if (cpi->ref_frame_flags & VP8_LAST_FRAME) {
|
| + closest_ref = LAST_FRAME;
|
| + } else if (cpi->ref_frame_flags & VP8_GOLD_FRAME) {
|
| + closest_ref = GOLDEN_FRAME;
|
| + } else if (cpi->ref_frame_flags & VP8_ALTR_FRAME) {
|
| + closest_ref = ALTREF_FRAME;
|
| + }
|
| + for (i = 1; i <= 3; i++) {
|
| + vpx_ref_frame_type_t ref_frame_type = (vpx_ref_frame_type_t)
|
| + ((i == 3) ? 4 : i);
|
| + if (cpi->ref_frame_flags & ref_frame_type) {
|
| + if ((cm->current_video_frame - cpi->current_ref_frames[i]) <
|
| + (cm->current_video_frame - cpi->current_ref_frames[closest_ref])) {
|
| + closest_ref = i;
|
| + }
|
| + }
|
| + }
|
| + cpi->closest_reference_frame = closest_ref;
|
| + }
|
| +
|
| /* Set various flags etc to special state if it is a key frame */
|
| if (cm->frame_type == KEY_FRAME)
|
| {
|
| @@ -3479,6 +3632,9 @@
|
| {
|
| cpi->mb.rd_thresh_mult[i] = 128;
|
| }
|
| +
|
| + // Reset the zero_last counter to 0 on key frame.
|
| + vpx_memset(cpi->consec_zero_last, 0, cm->mb_rows * cm->mb_cols);
|
| }
|
|
|
| #if 0
|
| @@ -3900,6 +4056,7 @@
|
|
|
| #endif
|
|
|
| +
|
| #ifdef OUTPUT_YUV_SRC
|
| vp8_write_yuv_frame(yuv_file, cpi->Source);
|
| #endif
|
| @@ -3995,6 +4152,8 @@
|
| else
|
| disable_segmentation(cpi);
|
| }
|
| + // Reset the consec_zero_last counter on key frame.
|
| + vpx_memset(cpi->consec_zero_last, 0, cm->mb_rows * cm->mb_cols);
|
| vp8_set_quantizer(cpi, Q);
|
| }
|
|
|
| @@ -4383,7 +4542,8 @@
|
| {
|
| for (mb_col = 0; mb_col < cm->mb_cols; mb_col ++)
|
| {
|
| - if(tmp->mbmi.mode == ZEROMV)
|
| + if (tmp->mbmi.mode == ZEROMV &&
|
| + tmp->mbmi.ref_frame == LAST_FRAME)
|
| cpi->zeromv_count++;
|
| tmp++;
|
| }
|
| @@ -4425,6 +4585,21 @@
|
|
|
| cm->frame_to_show = &cm->yv12_fb[cm->new_fb_idx];
|
|
|
| +#if CONFIG_TEMPORAL_DENOISING
|
| + // For the adaptive denoising mode (noise_sensitivity == 4), sample the mse
|
| + // of source diff (between current and previous frame), and determine if we
|
| + // should switch the denoiser mode. Sampling refers to computing the mse for
|
| + // a sub-sample of the frame (i.e., skip x blocks along row/column), and
|
| + // only for blocks in that set that have used ZEROMV LAST, along with some
|
| + // constraint on the sum diff between blocks. This process is called every
|
| + // ~8 frames, to further reduce complexity.
|
| + if (cpi->oxcf.noise_sensitivity == 4 &&
|
| + cpi->frames_since_key % 8 == 0 &&
|
| + cm->frame_type != KEY_FRAME) {
|
| + process_denoiser_mode_change(cpi);
|
| + }
|
| +#endif
|
| +
|
| #if CONFIG_MULTITHREAD
|
| if (cpi->b_multi_threaded)
|
| {
|
|
|