Line data Source code
1 : /*
2 : * Copyright(c) 2019 Intel Corporation
3 : * SPDX - License - Identifier: BSD - 2 - Clause - Patent
4 : */
5 :
6 : /*
7 : * Copyright (c) 2016, Alliance for Open Media. All rights reserved
8 : *
9 : * This source code is subject to the terms of the BSD 2 Clause License and
10 : * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
11 : * was not distributed with this source code in the LICENSE file, you can
12 : * obtain it at www.aomedia.org/license/software. If the Alliance for Open
13 : * Media Patent License 1.0 was not distributed with this source code in the
14 : * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
15 : */
16 :
17 : #include "EbSegmentation.h"
18 : #include "EbSegmentationParams.h"
19 : #include "EbMotionEstimationContext.h"
20 :
21 : const int segmentation_feature_signed[SEG_LVL_MAX] = {
22 : 1, 1, 1, 1, 1, 0, 0, 0
23 : };
24 :
25 : const int segmentation_feature_bits[SEG_LVL_MAX] = {8, 6, 6, 6, 6, 3, 0, 0};
26 :
27 : const int segmentation_feature_max[SEG_LVL_MAX] = {MAXQ,
28 : MAX_LOOP_FILTER,
29 : MAX_LOOP_FILTER,
30 : MAX_LOOP_FILTER,
31 : MAX_LOOP_FILTER,
32 : 7,
33 : 0,
34 : 0};
35 :
36 :
37 : static const uint8_t q_index_to_quantizer[] = {
38 : 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
39 : 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
40 : 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16,
41 : 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21,
42 : 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26,
43 : 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
44 : 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36,
45 : 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41,
46 : 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46,
47 : 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
48 : 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56,
49 : 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60,
50 : 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 63
51 : };
52 :
53 :
54 0 : uint16_t get_variance_for_cu(const BlockGeom *blk_geom,
55 : uint16_t *variance_ptr) {
56 : int index0, index1;
57 : //Assumes max CU size is 64
58 0 : switch (blk_geom->bsize) {
59 0 : case BLOCK_4X4:
60 : case BLOCK_4X8:
61 : case BLOCK_8X4:
62 : case BLOCK_8X8:
63 0 : index0 = index1 = ME_TIER_ZERO_PU_8x8_0 + ((blk_geom->origin_x >> 3) + blk_geom->origin_y);
64 0 : break;
65 :
66 0 : case BLOCK_8X16:
67 0 : index0 = ME_TIER_ZERO_PU_8x8_0 + ((blk_geom->origin_x >> 3) + blk_geom->origin_y);
68 0 : index1 = index0 + 1;
69 0 : break;
70 :
71 0 : case BLOCK_16X8:
72 0 : index0 = ME_TIER_ZERO_PU_8x8_0 + ((blk_geom->origin_x >> 3) + blk_geom->origin_y);
73 0 : index1 = index0 + blk_geom->origin_y;
74 0 : break;
75 :
76 0 : case BLOCK_4X16:
77 : case BLOCK_16X4:
78 : case BLOCK_16X16:
79 0 : index0 = index1 = ME_TIER_ZERO_PU_16x16_0 + ((blk_geom->origin_x >> 4) + (blk_geom->origin_y >> 2));
80 0 : break;
81 :
82 0 : case BLOCK_16X32:
83 0 : index0 = ME_TIER_ZERO_PU_16x16_0 + ((blk_geom->origin_x >> 4) + (blk_geom->origin_y >> 2));
84 0 : index1 = index0 + 1;
85 0 : break;
86 :
87 0 : case BLOCK_32X16:
88 0 : index0 = ME_TIER_ZERO_PU_16x16_0 + ((blk_geom->origin_x >> 4) + (blk_geom->origin_y >> 2));
89 0 : index1 = index0 + (blk_geom->origin_y >> 2);
90 0 : break;
91 :
92 0 : case BLOCK_8X32:
93 : case BLOCK_32X8:
94 : case BLOCK_32X32:
95 0 : index0 = index1 = ME_TIER_ZERO_PU_32x32_0 + ((blk_geom->origin_x >> 5) + (blk_geom->origin_y >> 4));
96 0 : break;
97 :
98 0 : case BLOCK_32X64:
99 0 : index0 = ME_TIER_ZERO_PU_32x32_0 + ((blk_geom->origin_x >> 5) + (blk_geom->origin_y >> 4));
100 0 : index1 = index0 + 1;
101 0 : break;
102 :
103 0 : case BLOCK_64X32:
104 0 : index0 = ME_TIER_ZERO_PU_32x32_0 + ((blk_geom->origin_x >> 5) + (blk_geom->origin_y >> 4));
105 0 : index1 = index0 + (blk_geom->origin_y >> 4);
106 0 : break;
107 :
108 0 : case BLOCK_64X64:
109 : case BLOCK_16X64:
110 : case BLOCK_64X16:
111 : default:
112 0 : index0 = index1 = 0;
113 0 : break;
114 :
115 : }
116 0 : return (variance_ptr[index0] + variance_ptr[index1]) >> 1;
117 :
118 : }
119 :
120 0 : void apply_segmentation_based_quantization(
121 : const BlockGeom *blk_geom,
122 : PictureControlSet *picture_control_set_ptr,
123 : LargestCodingUnit *sb_ptr,
124 : CodingUnit *cu_ptr) {
125 0 : uint16_t *variance_ptr = picture_control_set_ptr->parent_pcs_ptr->variance[sb_ptr->index];
126 0 : SegmentationParams *segmentation_params = &picture_control_set_ptr->parent_pcs_ptr->frm_hdr.segmentation_params;
127 0 : uint16_t variance = get_variance_for_cu(blk_geom, variance_ptr);
128 0 : for (int i = 0; i < MAX_SEGMENTS; i++) {
129 0 : if (variance <= segmentation_params->variance_bin_edge[i]) {
130 0 : cu_ptr->segment_id = i;
131 0 : break;
132 : }
133 : }
134 0 : int32_t q_index = picture_control_set_ptr->parent_pcs_ptr->frm_hdr.quantization_params.base_q_idx +
135 0 : picture_control_set_ptr->parent_pcs_ptr->frm_hdr.segmentation_params.feature_data[cu_ptr->segment_id][SEG_LVL_ALT_Q];
136 0 : cu_ptr->qp = q_index_to_quantizer[q_index];
137 :
138 0 : }
139 :
140 120 : void setup_segmentation(
141 : PictureControlSet *picture_control_set_ptr,
142 : SequenceControlSet *sequence_control_set_ptr,
143 : RateControlLayerContext *rateControlLayerPtr)
144 : {
145 120 : SegmentationParams *segmentation_params = &picture_control_set_ptr->parent_pcs_ptr->frm_hdr.segmentation_params;
146 120 : segmentation_params->segmentation_enabled = (EbBool)(sequence_control_set_ptr->static_config.enable_adaptive_quantization == 1);
147 120 : if (segmentation_params->segmentation_enabled) {
148 0 : int32_t segment_qps[MAX_SEGMENTS] = {0};
149 0 : segmentation_params->segmentation_update_data = 1; //always updating for now. Need to set this based on actual deltas
150 0 : segmentation_params->segmentation_update_map = 1;
151 0 : segmentation_params->segmentation_temporal_update = EB_FALSE; //!(picture_control_set_ptr->parent_pcs_ptr->av1FrameType == KEY_FRAME || picture_control_set_ptr->parent_pcs_ptr->av1FrameType == INTRA_ONLY_FRAME);
152 0 : find_segment_qps(segmentation_params, picture_control_set_ptr);
153 0 : temporally_update_qps(segment_qps, rateControlLayerPtr->prev_segment_qps,
154 0 : segmentation_params->segmentation_temporal_update);
155 0 : for (int i = 0; i < MAX_SEGMENTS; i++)
156 0 : segmentation_params->feature_enabled[i][SEG_LVL_ALT_Q] = 1;
157 :
158 0 : calculate_segmentation_data(segmentation_params);
159 : }
160 :
161 120 : }
162 :
163 0 : void calculate_segmentation_data(SegmentationParams *segmentation_params) {
164 0 : for (int i = 0; i < MAX_SEGMENTS; i++) {
165 0 : for (int j = 0; j < SEG_LVL_MAX; j++) {
166 0 : if (segmentation_params->feature_enabled[i][j]) {
167 0 : segmentation_params->last_active_seg_id = i;
168 0 : if (j >= SEG_LVL_REF_FRAME) {
169 0 : segmentation_params->seg_id_pre_skip = 1;
170 : }
171 : }
172 : }
173 : }
174 0 : }
175 :
176 0 : void find_segment_qps(
177 : SegmentationParams *segmentation_params,
178 : PictureControlSet *picture_control_set_ptr) { //QP needs to be specified as qpindex, not qp.
179 :
180 : uint16_t *variancePtr;
181 0 : uint16_t min_var = UINT16_MAX, max_var = MIN_UNSIGNED_VALUE, avg_var = 0;
182 0 : float strength = 2;//to tune
183 :
184 : // get range of variance
185 0 : for (uint32_t lcuIdx = 0; lcuIdx < picture_control_set_ptr->sb_total_count; ++lcuIdx) {
186 0 : variancePtr = picture_control_set_ptr->parent_pcs_ptr->variance[lcuIdx];
187 0 : uint32_t var_index, local_avg = 0;
188 : // Loop over all 8x8s in a 64x64
189 0 : for (var_index = ME_TIER_ZERO_PU_8x8_0; var_index <= ME_TIER_ZERO_PU_8x8_63; var_index++) {
190 0 : max_var = MAX(max_var, variancePtr[var_index]);
191 0 : min_var = MIN(min_var, variancePtr[var_index]);
192 0 : local_avg += variancePtr[var_index];
193 : }
194 0 : avg_var += (local_avg >> 6);
195 : }
196 0 : avg_var /= picture_control_set_ptr->sb_total_count;
197 0 : avg_var = Log2f(avg_var);
198 :
199 : //get variance bin edges & QPs
200 0 : uint16_t min_var_log = Log2f(MAX(1, min_var));
201 0 : uint16_t max_var_log = Log2f(MAX(1, max_var));
202 0 : uint16_t step_size = (uint16_t)(max_var_log - min_var_log) <= MAX_SEGMENTS ? 1 : ROUND(
203 : ((max_var_log - min_var_log)) / MAX_SEGMENTS);
204 0 : uint16_t bin_edge = min_var_log + step_size;
205 0 : uint16_t bin_center = bin_edge >> 1;
206 :
207 0 : for (int i = 0; i < MAX_SEGMENTS; i++) {
208 0 : segmentation_params->variance_bin_edge[i] = POW2(bin_edge);
209 0 : segmentation_params->feature_data[i][SEG_LVL_ALT_Q] =
210 0 : ROUND((uint16_t)strength * (MAX(1, bin_center) - avg_var));
211 0 : bin_edge += step_size;
212 0 : bin_center += step_size;
213 : }
214 :
215 0 : }
216 :
217 0 : void temporally_update_qps(
218 : int32_t *segment_qp_ptr,
219 : int32_t *prev_segment_qp_ptr,
220 : EbBool temporal_update) {
221 0 : for (int i = 0; i < MAX_SEGMENTS; i++) {
222 0 : int32_t diff = segment_qp_ptr[i] - prev_segment_qp_ptr[i];
223 0 : prev_segment_qp_ptr[i] = segment_qp_ptr[i];
224 0 : segment_qp_ptr[i] = temporal_update ? diff : segment_qp_ptr[i];
225 : }
226 0 : }
|