1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
|
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#ifndef AOM_AV1_ENCODER_RDOPT_H_
#define AOM_AV1_ENCODER_RDOPT_H_
#include <stdbool.h>
#include "av1/common/blockd.h"
#include "av1/common/txb_common.h"
#include "av1/encoder/block.h"
#include "av1/encoder/context_tree.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/encodetxb.h"
#include "av1/encoder/rdopt_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
#define COMP_TYPE_RD_THRESH_SCALE 11
#define COMP_TYPE_RD_THRESH_SHIFT 4
#define MAX_WINNER_MOTION_MODES 10
struct TileInfo;
struct macroblock;
struct RD_STATS;
/*!\brief AV1 intra mode selection for intra frames.
*
* \ingroup intra_mode_search
* \callgraph
* Top level function for rd-based intra mode selection during intra frame
* encoding. This function will first search for the best luma prediction by
* calling av1_rd_pick_intra_sby_mode, then it searches for chroma prediction
* with av1_rd_pick_intra_sbuv_mode. If applicable, this function ends the
* search with an evaluation for intrabc.
*
* \param[in] cpi Top-level encoder structure.
* \param[in] x Pointer to structure holding all the data for
the current macroblock.
* \param[in] rd_cost Struct to keep track of the RD information.
* \param[in] bsize Current block size.
* \param[in] ctx Structure to hold snapshot of coding context
during the mode picking process.
* \param[in] best_rd Best RD seen for this block so far.
*
* \return Nothing is returned. Instead, the MB_MODE_INFO struct inside x
* is modified to store information about the best mode computed
* in this function. The rd_cost struct is also updated with the RD stats
* corresponding to the best mode found.
*/
void av1_rd_pick_intra_mode_sb(const struct AV1_COMP *cpi, struct macroblock *x,
struct RD_STATS *rd_cost, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx, int64_t best_rd);
/*!\brief AV1 inter mode selection.
*
* \ingroup inter_mode_search
* \callgraph
* Top level function for inter mode selection. This function will loop over
* all possible inter modes and select the best one for the current block by
* computing the RD cost. The mode search and RD are computed in
* handle_inter_mode(), which is called from this function within the main
* loop.
*
* \param[in] cpi Top-level encoder structure
* \param[in] tile_data Pointer to struct holding adaptive
data/contexts/models for the tile during
encoding
* \param[in] x Pointer to structure holding all the data for
the current macroblock
* \param[in] rd_cost Struct to keep track of the RD information
* \param[in] bsize Current block size
* \param[in] ctx Structure to hold snapshot of coding context
during the mode picking process
* \param[in] best_rd_so_far Best RD seen for this block so far
*
* \return Nothing is returned. Instead, the MB_MODE_INFO struct inside x
* is modified to store information about the best mode computed
* in this function. The rd_cost struct is also updated with the RD stats
* corresponding to the best mode found.
*/
void av1_rd_pick_inter_mode(struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
struct macroblock *x, struct RD_STATS *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
int64_t best_rd_so_far);
/*!\brief AV1 intra mode selection based on Non-RD optimized model.
*
* \ingroup nonrd_mode_search
* \callgraph
* \callergraph
* Top level function for Non-RD optimized intra mode selection.
* This finction will loop over subset of intra modes and select the best one
* based on calculated modelled RD cost. Only 4 intra modes are checked as
* specified in \c intra_mode_list. When calculating RD cost Hadamard transform
* of residual is used to calculate rate. Estmation of RD cost is performed
* in \c estimate_block_intra which is called from this function
*
* \param[in] cpi Top-level encoder structure
* \param[in] x Pointer to structure holding all the data for
the current macroblock
* \param[in] rd_cost Struct to keep track of the RD information
* \param[in] bsize Current block size
* \param[in] ctx Structure to hold snapshot of coding context
during the mode picking process
*
* \return Nothing is returned. Instead, the MB_MODE_INFO struct inside x
* is modified to store information about the best mode computed
* in this function. The rd_cost struct is also updated with the RD stats
* corresponding to the best mode found.
*/
void av1_nonrd_pick_intra_mode(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx);
/*!\brief AV1 inter mode selection based on Non-RD optimized model.
*
* \ingroup nonrd_mode_search
* \callgraph
* Top level function for Non-RD optimized inter mode selection.
* This finction will loop over subset of inter modes and select the best one
* based on calculated modelled RD cost. While making decisions which modes to
* check, this function applies heuristics based on previously checked modes,
* block residual variance, block size, and other factors to prune certain
* modes and reference frames. Currently only single reference frame modes
* are checked. Additional heuristics are applied to decide if intra modes
* need to be checked.
* *
* \param[in] cpi Top-level encoder structure
* \param[in] tile_data Pointer to struct holding adaptive
data/contexts/models for the tile during
encoding
* \param[in] x Pointer to structure holding all the data for
the current macroblock
* \param[in] rd_cost Struct to keep track of the RD information
* \param[in] bsize Current block size
* \param[in] ctx Structure to hold snapshot of coding context
during the mode picking process
*
* \return Nothing is returned. Instead, the MB_MODE_INFO struct inside x
* is modified to store information about the best mode computed
* in this function. The rd_cost struct is also updated with the RD stats
* corresponding to the best mode found.
*/
void av1_nonrd_pick_inter_mode_sb(struct AV1_COMP *cpi,
struct TileDataEnc *tile_data,
struct macroblock *x,
struct RD_STATS *rd_cost, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx);
void av1_rd_pick_inter_mode_sb_seg_skip(
const struct AV1_COMP *cpi, struct TileDataEnc *tile_data,
struct macroblock *x, int mi_row, int mi_col, struct RD_STATS *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd_so_far);
void av1_inter_mode_data_init(struct TileDataEnc *tile_data);
void av1_inter_mode_data_fit(TileDataEnc *tile_data, int rdmult);
void av1_block_yrd(const AV1_COMP *const cpi, MACROBLOCK *x, int mi_row,
int mi_col, RD_STATS *this_rdc, int *skippable,
BLOCK_SIZE bsize, TX_SIZE tx_size, TX_TYPE tx_type,
int is_inter_mode);
static INLINE int coded_to_superres_mi(int mi_col, int denom) {
return (mi_col * denom + SCALE_NUMERATOR / 2) / SCALE_NUMERATOR;
}
static INLINE int av1_encoder_get_relative_dist(int a, int b) {
assert(a >= 0 && b >= 0);
return (a - b);
}
// This function will return number of mi's in a superblock.
static INLINE int av1_get_sb_mi_size(const AV1_COMMON *const cm) {
const int mi_alloc_size_1d = mi_size_wide[cm->mi_params.mi_alloc_bsize];
int sb_mi_rows =
(mi_size_wide[cm->seq_params->sb_size] + mi_alloc_size_1d - 1) /
mi_alloc_size_1d;
assert(mi_size_wide[cm->seq_params->sb_size] ==
mi_size_high[cm->seq_params->sb_size]);
int sb_mi_size = sb_mi_rows * sb_mi_rows;
return sb_mi_size;
}
// This function prunes the mode if either of the reference frame falls in the
// pruning list
static INLINE int prune_ref(const MV_REFERENCE_FRAME *const ref_frame,
const unsigned int *const ref_display_order_hint,
const unsigned int frame_display_order_hint,
const int *ref_frame_list) {
for (int i = 0; i < 2; i++) {
if (ref_frame_list[i] == NONE_FRAME) continue;
if (ref_frame[0] == ref_frame_list[i] ||
ref_frame[1] == ref_frame_list[i]) {
if (av1_encoder_get_relative_dist(
ref_display_order_hint[ref_frame_list[i] - LAST_FRAME],
frame_display_order_hint) < 0)
return 1;
}
}
return 0;
}
static INLINE int has_closest_ref_frames(const MV_REFERENCE_FRAME *ref_frame,
int8_t closest_past_ref,
int8_t closest_future_ref) {
int has_closest_past_ref =
(ref_frame[0] == closest_past_ref) || (ref_frame[1] == closest_past_ref);
int has_closest_future_ref = (ref_frame[0] == closest_future_ref) ||
(ref_frame[1] == closest_future_ref);
return (has_closest_past_ref && has_closest_future_ref);
}
static INLINE int has_best_pred_mv_sad(const MV_REFERENCE_FRAME *ref_frame,
const MACROBLOCK *const x) {
int has_best_past_pred_mv_sad = 0;
int has_best_future_pred_mv_sad = 0;
if (x->best_pred_mv_sad[0] < INT_MAX && x->best_pred_mv_sad[1] < INT_MAX) {
has_best_past_pred_mv_sad =
(x->pred_mv_sad[ref_frame[0]] == x->best_pred_mv_sad[0]) ||
(x->pred_mv_sad[ref_frame[1]] == x->best_pred_mv_sad[0]);
has_best_future_pred_mv_sad =
(x->pred_mv_sad[ref_frame[0]] == x->best_pred_mv_sad[1]) ||
(x->pred_mv_sad[ref_frame[1]] == x->best_pred_mv_sad[1]);
}
return (has_best_past_pred_mv_sad && has_best_future_pred_mv_sad);
}
static INLINE int prune_ref_by_selective_ref_frame(
const AV1_COMP *const cpi, const MACROBLOCK *const x,
const MV_REFERENCE_FRAME *const ref_frame,
const unsigned int *const ref_display_order_hint) {
const SPEED_FEATURES *const sf = &cpi->sf;
if (!sf->inter_sf.selective_ref_frame) return 0;
const int comp_pred = ref_frame[1] > INTRA_FRAME;
if (sf->inter_sf.selective_ref_frame >= 2 ||
(sf->inter_sf.selective_ref_frame == 1 && comp_pred)) {
int ref_frame_list[2] = { LAST3_FRAME, LAST2_FRAME };
if (x != NULL) {
// Disable pruning if either tpl suggests that we keep the frame or
// the pred_mv gives us the best sad
if (x->tpl_keep_ref_frame[LAST3_FRAME] ||
x->pred_mv_sad[LAST3_FRAME] == x->best_pred_mv_sad[0]) {
ref_frame_list[0] = NONE_FRAME;
}
if (x->tpl_keep_ref_frame[LAST2_FRAME] ||
x->pred_mv_sad[LAST2_FRAME] == x->best_pred_mv_sad[0]) {
ref_frame_list[1] = NONE_FRAME;
}
}
if (prune_ref(ref_frame, ref_display_order_hint,
ref_display_order_hint[GOLDEN_FRAME - LAST_FRAME],
ref_frame_list))
return 1;
}
if (sf->inter_sf.selective_ref_frame >= 3) {
int ref_frame_list[2] = { ALTREF2_FRAME, BWDREF_FRAME };
if (x != NULL) {
// Disable pruning if either tpl suggests that we keep the frame or
// the pred_mv gives us the best sad
if (x->tpl_keep_ref_frame[ALTREF2_FRAME] ||
x->pred_mv_sad[ALTREF2_FRAME] == x->best_pred_mv_sad[0]) {
ref_frame_list[0] = NONE_FRAME;
}
if (x->tpl_keep_ref_frame[BWDREF_FRAME] ||
x->pred_mv_sad[BWDREF_FRAME] == x->best_pred_mv_sad[0]) {
ref_frame_list[1] = NONE_FRAME;
}
}
if (prune_ref(ref_frame, ref_display_order_hint,
ref_display_order_hint[LAST_FRAME - LAST_FRAME],
ref_frame_list))
return 1;
}
if (x != NULL && sf->inter_sf.prune_comp_ref_frames && comp_pred) {
int closest_ref_frames = has_closest_ref_frames(
ref_frame, cpi->ref_frame_dist_info.nearest_past_ref,
cpi->ref_frame_dist_info.nearest_future_ref);
if (closest_ref_frames == 0) {
// Prune reference frames which are not the closest to the current frame.
if (sf->inter_sf.prune_comp_ref_frames >= 2) {
return 1;
} else if (sf->inter_sf.prune_comp_ref_frames == 1) {
// Prune reference frames with non minimum pred_mv_sad.
if (has_best_pred_mv_sad(ref_frame, x) == 0) return 1;
}
}
}
return 0;
}
// This function will copy the best reference mode information from
// MB_MODE_INFO_EXT to MB_MODE_INFO_EXT_FRAME.
static INLINE void av1_copy_mbmi_ext_to_mbmi_ext_frame(
MB_MODE_INFO_EXT_FRAME *mbmi_ext_best,
const MB_MODE_INFO_EXT *const mbmi_ext, uint8_t ref_frame_type) {
memcpy(mbmi_ext_best->ref_mv_stack, mbmi_ext->ref_mv_stack[ref_frame_type],
sizeof(mbmi_ext->ref_mv_stack[USABLE_REF_MV_STACK_SIZE]));
memcpy(mbmi_ext_best->weight, mbmi_ext->weight[ref_frame_type],
sizeof(mbmi_ext->weight[USABLE_REF_MV_STACK_SIZE]));
mbmi_ext_best->mode_context = mbmi_ext->mode_context[ref_frame_type];
mbmi_ext_best->ref_mv_count = mbmi_ext->ref_mv_count[ref_frame_type];
memcpy(mbmi_ext_best->global_mvs, mbmi_ext->global_mvs,
sizeof(mbmi_ext->global_mvs));
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AOM_AV1_ENCODER_RDOPT_H_
|