Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 1 | /* |
Yaowu Xu | 2ab7ff0 | 2016-09-02 12:04:54 -0700 | [diff] [blame] | 2 | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 3 | * |
Yaowu Xu | 2ab7ff0 | 2016-09-02 12:04:54 -0700 | [diff] [blame] | 4 | * This source code is subject to the terms of the BSD 2 Clause License and |
| 5 | * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| 6 | * was not distributed with this source code in the LICENSE file, you can |
| 7 | * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| 8 | * Media Patent License 1.0 was not distributed with this source code in the |
| 9 | * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 10 | */ |
| 11 | |
| 12 | #include <math.h> |
| 13 | |
| 14 | #include "aom_ports/mem.h" |
| 15 | |
| 16 | #include "av1/encoder/aq_variance.h" |
| 17 | |
| 18 | #include "av1/common/seg_common.h" |
| 19 | #include "av1/encoder/ratectrl.h" |
| 20 | #include "av1/encoder/rd.h" |
| 21 | #include "av1/encoder/segmentation.h" |
| 22 | #include "aom_ports/system_state.h" |
| 23 | |
| 24 | #define ENERGY_MIN (-4) |
| 25 | #define ENERGY_MAX (1) |
| 26 | #define ENERGY_SPAN (ENERGY_MAX - ENERGY_MIN + 1) |
| 27 | #define ENERGY_IN_BOUNDS(energy) \ |
| 28 | assert((energy) >= ENERGY_MIN && (energy) <= ENERGY_MAX) |
| 29 | |
| 30 | static const double rate_ratio[MAX_SEGMENTS] = { 2.5, 2.0, 1.5, 1.0, |
| 31 | 0.75, 1.0, 1.0, 1.0 }; |
| 32 | static const int segment_id[ENERGY_SPAN] = { 0, 1, 1, 2, 3, 4 }; |
| 33 | |
| 34 | #define SEGMENT_ID(i) segment_id[(i)-ENERGY_MIN] |
| 35 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 36 | DECLARE_ALIGNED(16, static const uint8_t, av1_all_zeros[MAX_SB_SIZE]) = { 0 }; |
| 37 | #if CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 38 | DECLARE_ALIGNED(16, static const uint16_t, |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 39 | av1_highbd_all_zeros[MAX_SB_SIZE]) = { 0 }; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 40 | #endif |
| 41 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 42 | unsigned int av1_vaq_segment_id(int energy) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 43 | ENERGY_IN_BOUNDS(energy); |
| 44 | return SEGMENT_ID(energy); |
| 45 | } |
| 46 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 47 | void av1_vaq_frame_setup(AV1_COMP *cpi) { |
| 48 | AV1_COMMON *cm = &cpi->common; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 49 | struct segmentation *seg = &cm->seg; |
| 50 | int i; |
| 51 | |
| 52 | if (frame_is_intra_only(cm) || cm->error_resilient_mode || |
| 53 | cpi->refresh_alt_ref_frame || |
| 54 | (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref)) { |
| 55 | cpi->vaq_refresh = 1; |
| 56 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 57 | av1_enable_segmentation(seg); |
| 58 | av1_clearall_segfeatures(seg); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 59 | |
| 60 | seg->abs_delta = SEGMENT_DELTADATA; |
| 61 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 62 | aom_clear_system_state(); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 63 | |
| 64 | for (i = 0; i < MAX_SEGMENTS; ++i) { |
| 65 | int qindex_delta = |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 66 | av1_compute_qdelta_by_rate(&cpi->rc, cm->frame_type, cm->base_qindex, |
| 67 | rate_ratio[i], cm->bit_depth); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 68 | |
| 69 | // We don't allow qindex 0 in a segment if the base value is not 0. |
| 70 | // Q index 0 (lossless) implies 4x4 encoding only and in AQ mode a segment |
| 71 | // Q delta is sometimes applied without going back around the rd loop. |
| 72 | // This could lead to an illegal combination of partition size and q. |
| 73 | if ((cm->base_qindex != 0) && ((cm->base_qindex + qindex_delta) == 0)) { |
| 74 | qindex_delta = -cm->base_qindex + 1; |
| 75 | } |
| 76 | |
| 77 | // No need to enable SEG_LVL_ALT_Q for this segment. |
| 78 | if (rate_ratio[i] == 1.0) { |
| 79 | continue; |
| 80 | } |
| 81 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 82 | av1_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta); |
| 83 | av1_enable_segfeature(seg, i, SEG_LVL_ALT_Q); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 84 | } |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | /* TODO(agrange, paulwilkins): The block_variance calls the unoptimized versions |
| 89 | * of variance() and highbd_8_variance(). It should not. |
| 90 | */ |
| 91 | static void aq_variance(const uint8_t *a, int a_stride, const uint8_t *b, |
| 92 | int b_stride, int w, int h, unsigned int *sse, |
| 93 | int *sum) { |
| 94 | int i, j; |
| 95 | |
| 96 | *sum = 0; |
| 97 | *sse = 0; |
| 98 | |
| 99 | for (i = 0; i < h; i++) { |
| 100 | for (j = 0; j < w; j++) { |
| 101 | const int diff = a[j] - b[j]; |
| 102 | *sum += diff; |
| 103 | *sse += diff * diff; |
| 104 | } |
| 105 | |
| 106 | a += a_stride; |
| 107 | b += b_stride; |
| 108 | } |
| 109 | } |
| 110 | |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 111 | #if CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 112 | static void aq_highbd_variance64(const uint8_t *a8, int a_stride, |
| 113 | const uint8_t *b8, int b_stride, int w, int h, |
| 114 | uint64_t *sse, uint64_t *sum) { |
| 115 | int i, j; |
| 116 | |
| 117 | uint16_t *a = CONVERT_TO_SHORTPTR(a8); |
| 118 | uint16_t *b = CONVERT_TO_SHORTPTR(b8); |
| 119 | *sum = 0; |
| 120 | *sse = 0; |
| 121 | |
| 122 | for (i = 0; i < h; i++) { |
| 123 | for (j = 0; j < w; j++) { |
| 124 | const int diff = a[j] - b[j]; |
| 125 | *sum += diff; |
| 126 | *sse += diff * diff; |
| 127 | } |
| 128 | a += a_stride; |
| 129 | b += b_stride; |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | static void aq_highbd_8_variance(const uint8_t *a8, int a_stride, |
| 134 | const uint8_t *b8, int b_stride, int w, int h, |
| 135 | unsigned int *sse, int *sum) { |
| 136 | uint64_t sse_long = 0; |
| 137 | uint64_t sum_long = 0; |
| 138 | aq_highbd_variance64(a8, a_stride, b8, b_stride, w, h, &sse_long, &sum_long); |
| 139 | *sse = (unsigned int)sse_long; |
| 140 | *sum = (int)sum_long; |
| 141 | } |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 142 | #endif // CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 143 | |
Urvang Joshi | 5264844 | 2016-10-13 17:27:51 -0700 | [diff] [blame] | 144 | static unsigned int block_variance(const AV1_COMP *const cpi, MACROBLOCK *x, |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 145 | BLOCK_SIZE bs) { |
| 146 | MACROBLOCKD *xd = &x->e_mbd; |
| 147 | unsigned int var, sse; |
| 148 | int right_overflow = |
| 149 | (xd->mb_to_right_edge < 0) ? ((-xd->mb_to_right_edge) >> 3) : 0; |
| 150 | int bottom_overflow = |
| 151 | (xd->mb_to_bottom_edge < 0) ? ((-xd->mb_to_bottom_edge) >> 3) : 0; |
| 152 | |
| 153 | if (right_overflow || bottom_overflow) { |
| 154 | const int bw = 8 * num_8x8_blocks_wide_lookup[bs] - right_overflow; |
| 155 | const int bh = 8 * num_8x8_blocks_high_lookup[bs] - bottom_overflow; |
| 156 | int avg; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 157 | #if CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 158 | if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { |
| 159 | aq_highbd_8_variance(x->plane[0].src.buf, x->plane[0].src.stride, |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 160 | CONVERT_TO_BYTEPTR(av1_highbd_all_zeros), 0, bw, bh, |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 161 | &sse, &avg); |
| 162 | sse >>= 2 * (xd->bd - 8); |
| 163 | avg >>= (xd->bd - 8); |
| 164 | } else { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 165 | aq_variance(x->plane[0].src.buf, x->plane[0].src.stride, av1_all_zeros, 0, |
| 166 | bw, bh, &sse, &avg); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 167 | } |
| 168 | #else |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 169 | aq_variance(x->plane[0].src.buf, x->plane[0].src.stride, av1_all_zeros, 0, |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 170 | bw, bh, &sse, &avg); |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 171 | #endif // CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 172 | var = sse - (((int64_t)avg * avg) / (bw * bh)); |
Yaowu Xu | aa8729c | 2016-05-20 07:48:46 -0700 | [diff] [blame] | 173 | return ((uint64_t)var * 256) / (bw * bh); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 174 | } else { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 175 | #if CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 176 | if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 177 | var = |
| 178 | cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride, |
| 179 | CONVERT_TO_BYTEPTR(av1_highbd_all_zeros), 0, &sse); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 180 | } else { |
| 181 | var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride, |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 182 | av1_all_zeros, 0, &sse); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 183 | } |
| 184 | #else |
| 185 | var = cpi->fn_ptr[bs].vf(x->plane[0].src.buf, x->plane[0].src.stride, |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 186 | av1_all_zeros, 0, &sse); |
| 187 | #endif // CONFIG_AOM_HIGHBITDEPTH |
Yaowu Xu | aa8729c | 2016-05-20 07:48:46 -0700 | [diff] [blame] | 188 | return ((uint64_t)var * 256) >> num_pels_log2_lookup[bs]; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 189 | } |
| 190 | } |
| 191 | |
Urvang Joshi | 5264844 | 2016-10-13 17:27:51 -0700 | [diff] [blame] | 192 | double av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 193 | unsigned int var = block_variance(cpi, x, bs); |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 194 | aom_clear_system_state(); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 195 | return log(var + 1.0); |
| 196 | } |
| 197 | |
| 198 | #define DEFAULT_E_MIDPOINT 10.0 |
Urvang Joshi | 5264844 | 2016-10-13 17:27:51 -0700 | [diff] [blame] | 199 | int av1_block_energy(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) { |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 200 | double energy; |
| 201 | double energy_midpoint; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 202 | aom_clear_system_state(); |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 203 | energy_midpoint = |
| 204 | (cpi->oxcf.pass == 2) ? cpi->twopass.mb_av_energy : DEFAULT_E_MIDPOINT; |
Yaowu Xu | f883b42 | 2016-08-30 14:01:10 -0700 | [diff] [blame] | 205 | energy = av1_log_block_var(cpi, x, bs) - energy_midpoint; |
Yaowu Xu | c27fc14 | 2016-08-22 16:08:15 -0700 | [diff] [blame] | 206 | return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX); |
| 207 | } |