2
0

vp9_noise_estimate.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (c) 2015 The WebM project authors. All Rights Reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #include <assert.h>
  11. #include <limits.h>
  12. #include <math.h>
  13. #include "./vpx_dsp_rtcd.h"
  14. #include "vpx_dsp/vpx_dsp_common.h"
  15. #include "vpx_scale/yv12config.h"
  16. #include "vpx/vpx_integer.h"
  17. #include "vp9/common/vp9_reconinter.h"
  18. #include "vp9/encoder/vp9_context_tree.h"
  19. #include "vp9/encoder/vp9_noise_estimate.h"
  20. #include "vp9/encoder/vp9_encoder.h"
  21. void vp9_noise_estimate_init(NOISE_ESTIMATE *const ne, int width, int height) {
  22. ne->enabled = 0;
  23. ne->level = kLowLow;
  24. ne->value = 0;
  25. ne->count = 0;
  26. ne->thresh = 90;
  27. ne->last_w = 0;
  28. ne->last_h = 0;
  29. if (width * height >= 1920 * 1080) {
  30. ne->thresh = 200;
  31. } else if (width * height >= 1280 * 720) {
  32. ne->thresh = 130;
  33. }
  34. ne->num_frames_estimate = 20;
  35. }
  36. static int enable_noise_estimation(VP9_COMP *const cpi) {
  37. // Enable noise estimation if denoising is on.
  38. #if CONFIG_VP9_TEMPORAL_DENOISING
  39. if (cpi->oxcf.noise_sensitivity > 0) return 1;
  40. #endif
  41. // Only allow noise estimate under certain encoding mode.
  42. // Enabled for 1 pass CBR, speed >=5, and if resolution is same as original.
  43. // Not enabled for SVC mode and screen_content_mode.
  44. // Not enabled for low resolutions.
  45. if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR &&
  46. cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cpi->oxcf.speed >= 5 &&
  47. cpi->resize_state == ORIG && cpi->resize_pending == 0 && !cpi->use_svc &&
  48. cpi->oxcf.content != VP9E_CONTENT_SCREEN && cpi->common.width >= 640 &&
  49. cpi->common.height >= 480)
  50. return 1;
  51. else
  52. return 0;
  53. }
  54. #if CONFIG_VP9_TEMPORAL_DENOISING
  55. static void copy_frame(YV12_BUFFER_CONFIG *const dest,
  56. const YV12_BUFFER_CONFIG *const src) {
  57. int r;
  58. const uint8_t *srcbuf = src->y_buffer;
  59. uint8_t *destbuf = dest->y_buffer;
  60. assert(dest->y_width == src->y_width);
  61. assert(dest->y_height == src->y_height);
  62. for (r = 0; r < dest->y_height; ++r) {
  63. memcpy(destbuf, srcbuf, dest->y_width);
  64. destbuf += dest->y_stride;
  65. srcbuf += src->y_stride;
  66. }
  67. }
  68. #endif // CONFIG_VP9_TEMPORAL_DENOISING
  69. NOISE_LEVEL vp9_noise_estimate_extract_level(NOISE_ESTIMATE *const ne) {
  70. int noise_level = kLowLow;
  71. if (ne->value > (ne->thresh << 1)) {
  72. noise_level = kHigh;
  73. } else {
  74. if (ne->value > ne->thresh)
  75. noise_level = kMedium;
  76. else if (ne->value > ((9 * ne->thresh) >> 4))
  77. noise_level = kLow;
  78. else
  79. noise_level = kLowLow;
  80. }
  81. return noise_level;
  82. }
  83. void vp9_update_noise_estimate(VP9_COMP *const cpi) {
  84. const VP9_COMMON *const cm = &cpi->common;
  85. NOISE_ESTIMATE *const ne = &cpi->noise_estimate;
  86. // Estimate of noise level every frame_period frames.
  87. int frame_period = 8;
  88. int thresh_consec_zeromv = 6;
  89. unsigned int thresh_sum_diff = 100;
  90. unsigned int thresh_sum_spatial = (200 * 200) << 8;
  91. unsigned int thresh_spatial_var = (32 * 32) << 8;
  92. int min_blocks_estimate = cm->mi_rows * cm->mi_cols >> 7;
  93. // Estimate is between current source and last source.
  94. YV12_BUFFER_CONFIG *last_source = cpi->Last_Source;
  95. #if CONFIG_VP9_TEMPORAL_DENOISING
  96. if (cpi->oxcf.noise_sensitivity > 0) last_source = &cpi->denoiser.last_source;
  97. #endif
  98. ne->enabled = enable_noise_estimation(cpi);
  99. if (!ne->enabled || cm->current_video_frame % frame_period != 0 ||
  100. last_source == NULL || ne->last_w != cm->width ||
  101. ne->last_h != cm->height) {
  102. #if CONFIG_VP9_TEMPORAL_DENOISING
  103. if (cpi->oxcf.noise_sensitivity > 0)
  104. copy_frame(&cpi->denoiser.last_source, cpi->Source);
  105. #endif
  106. if (last_source != NULL) {
  107. ne->last_w = cm->width;
  108. ne->last_h = cm->height;
  109. }
  110. return;
  111. } else if (cpi->rc.avg_frame_low_motion < 50) {
  112. // Force noise estimation to 0 and denoiser off if content has high motion.
  113. ne->level = kLowLow;
  114. #if CONFIG_VP9_TEMPORAL_DENOISING
  115. if (cpi->oxcf.noise_sensitivity > 0)
  116. vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
  117. #endif
  118. return;
  119. } else {
  120. int num_samples = 0;
  121. uint64_t avg_est = 0;
  122. int bsize = BLOCK_16X16;
  123. static const unsigned char const_source[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
  124. 0, 0, 0, 0, 0, 0, 0, 0 };
  125. // Loop over sub-sample of 16x16 blocks of frame, and for blocks that have
  126. // been encoded as zero/small mv at least x consecutive frames, compute
  127. // the variance to update estimate of noise in the source.
  128. const uint8_t *src_y = cpi->Source->y_buffer;
  129. const int src_ystride = cpi->Source->y_stride;
  130. const uint8_t *last_src_y = last_source->y_buffer;
  131. const int last_src_ystride = last_source->y_stride;
  132. const uint8_t *src_u = cpi->Source->u_buffer;
  133. const uint8_t *src_v = cpi->Source->v_buffer;
  134. const int src_uvstride = cpi->Source->uv_stride;
  135. int mi_row, mi_col;
  136. int num_low_motion = 0;
  137. int frame_low_motion = 1;
  138. for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
  139. for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
  140. int bl_index = mi_row * cm->mi_cols + mi_col;
  141. if (cpi->consec_zero_mv[bl_index] > thresh_consec_zeromv)
  142. num_low_motion++;
  143. }
  144. }
  145. if (num_low_motion < ((3 * cm->mi_rows * cm->mi_cols) >> 3))
  146. frame_low_motion = 0;
  147. for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) {
  148. for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
  149. // 16x16 blocks, 1/4 sample of frame.
  150. if (mi_row % 4 == 0 && mi_col % 4 == 0 && mi_row < cm->mi_rows - 1 &&
  151. mi_col < cm->mi_cols - 1) {
  152. int bl_index = mi_row * cm->mi_cols + mi_col;
  153. int bl_index1 = bl_index + 1;
  154. int bl_index2 = bl_index + cm->mi_cols;
  155. int bl_index3 = bl_index2 + 1;
  156. // Only consider blocks that are likely steady background. i.e, have
  157. // been encoded as zero/low motion x (= thresh_consec_zeromv) frames
  158. // in a row. consec_zero_mv[] defined for 8x8 blocks, so consider all
  159. // 4 sub-blocks for 16x16 block. Also, avoid skin blocks.
  160. int consec_zeromv =
  161. VPXMIN(cpi->consec_zero_mv[bl_index],
  162. VPXMIN(cpi->consec_zero_mv[bl_index1],
  163. VPXMIN(cpi->consec_zero_mv[bl_index2],
  164. cpi->consec_zero_mv[bl_index3])));
  165. int is_skin = 0;
  166. if (cpi->use_skin_detection) {
  167. is_skin =
  168. vp9_compute_skin_block(src_y, src_u, src_v, src_ystride,
  169. src_uvstride, bsize, consec_zeromv, 0);
  170. }
  171. if (frame_low_motion &&
  172. cpi->consec_zero_mv[bl_index] > thresh_consec_zeromv &&
  173. cpi->consec_zero_mv[bl_index1] > thresh_consec_zeromv &&
  174. cpi->consec_zero_mv[bl_index2] > thresh_consec_zeromv &&
  175. cpi->consec_zero_mv[bl_index3] > thresh_consec_zeromv &&
  176. !is_skin) {
  177. // Compute variance.
  178. unsigned int sse;
  179. unsigned int variance = cpi->fn_ptr[bsize].vf(
  180. src_y, src_ystride, last_src_y, last_src_ystride, &sse);
  181. // Only consider this block as valid for noise measurement if the
  182. // average term (sse - variance = N * avg^{2}, N = 16X16) of the
  183. // temporal residual is small (avoid effects from lighting change).
  184. if ((sse - variance) < thresh_sum_diff) {
  185. unsigned int sse2;
  186. const unsigned int spatial_variance = cpi->fn_ptr[bsize].vf(
  187. src_y, src_ystride, const_source, 0, &sse2);
  188. // Avoid blocks with high brightness and high spatial variance.
  189. if ((sse2 - spatial_variance) < thresh_sum_spatial &&
  190. spatial_variance < thresh_spatial_var) {
  191. avg_est += variance / ((spatial_variance >> 9) + 1);
  192. num_samples++;
  193. }
  194. }
  195. }
  196. }
  197. src_y += 8;
  198. last_src_y += 8;
  199. src_u += 4;
  200. src_v += 4;
  201. }
  202. src_y += (src_ystride << 3) - (cm->mi_cols << 3);
  203. last_src_y += (last_src_ystride << 3) - (cm->mi_cols << 3);
  204. src_u += (src_uvstride << 2) - (cm->mi_cols << 2);
  205. src_v += (src_uvstride << 2) - (cm->mi_cols << 2);
  206. }
  207. ne->last_w = cm->width;
  208. ne->last_h = cm->height;
  209. // Update noise estimate if we have at a minimum number of block samples,
  210. // and avg_est > 0 (avg_est == 0 can happen if the application inputs
  211. // duplicate frames).
  212. if (num_samples > min_blocks_estimate && avg_est > 0) {
  213. // Normalize.
  214. avg_est = avg_est / num_samples;
  215. // Update noise estimate.
  216. ne->value = (int)((15 * ne->value + avg_est) >> 4);
  217. ne->count++;
  218. if (ne->count == ne->num_frames_estimate) {
  219. // Reset counter and check noise level condition.
  220. ne->num_frames_estimate = 30;
  221. ne->count = 0;
  222. ne->level = vp9_noise_estimate_extract_level(ne);
  223. #if CONFIG_VP9_TEMPORAL_DENOISING
  224. if (cpi->oxcf.noise_sensitivity > 0)
  225. vp9_denoiser_set_noise_level(&cpi->denoiser, ne->level);
  226. #endif
  227. }
  228. }
  229. }
  230. #if CONFIG_VP9_TEMPORAL_DENOISING
  231. if (cpi->oxcf.noise_sensitivity > 0)
  232. copy_frame(&cpi->denoiser.last_source, cpi->Source);
  233. #endif
  234. }