av1_cx_iface.c 49.2 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Jingning Han's avatar
Jingning Han committed
3
 *
4
5
6
7
8
9
 * 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.
Jingning Han's avatar
Jingning Han committed
10
11
12
13
14
 */

#include <stdlib.h>
#include <string.h>

Adrian Grange's avatar
Adrian Grange committed
15
16
17
18
19
#include "./aom_config.h"
#include "aom/aom_encoder.h"
#include "aom_ports/aom_once.h"
#include "aom/internal/aom_codec_internal.h"
#include "./aom_version.h"
Yaowu Xu's avatar
Yaowu Xu committed
20
#include "av1/encoder/encoder.h"
Adrian Grange's avatar
Adrian Grange committed
21
#include "aom/aomcx.h"
Yaowu Xu's avatar
Yaowu Xu committed
22
#include "av1/encoder/firstpass.h"
Yaowu Xu's avatar
Yaowu Xu committed
23
#include "av1/av1_iface_common.h"
Jingning Han's avatar
Jingning Han committed
24

25
struct av1_extracfg {
clang-format's avatar
clang-format committed
26
27
28
29
30
31
32
33
34
35
36
  int cpu_used;  // available cpu percentage in 1/16
  unsigned int enable_auto_alt_ref;
  unsigned int noise_sensitivity;
  unsigned int sharpness;
  unsigned int static_thresh;
  unsigned int tile_columns;
  unsigned int tile_rows;
  unsigned int arnr_max_frames;
  unsigned int arnr_strength;
  unsigned int min_gf_interval;
  unsigned int max_gf_interval;
Adrian Grange's avatar
Adrian Grange committed
37
  aom_tune_metric tuning;
clang-format's avatar
clang-format committed
38
39
40
41
42
  unsigned int cq_level;  // constrained quality level
  unsigned int rc_max_intra_bitrate_pct;
  unsigned int rc_max_inter_bitrate_pct;
  unsigned int gf_cbr_boost_pct;
  unsigned int lossless;
43
44
#if CONFIG_AOM_QM
  unsigned int enable_qm;
45
46
  unsigned int qm_min;
  unsigned int qm_max;
47
#endif
clang-format's avatar
clang-format committed
48
49
50
  unsigned int frame_parallel_decoding_mode;
  AQ_MODE aq_mode;
  unsigned int frame_periodic_boost;
Adrian Grange's avatar
Adrian Grange committed
51
52
53
  aom_bit_depth_t bit_depth;
  aom_tune_content content;
  aom_color_space_t color_space;
clang-format's avatar
clang-format committed
54
55
56
  int color_range;
  int render_width;
  int render_height;
Jingning Han's avatar
Jingning Han committed
57
58
};

59
static struct av1_extracfg default_extra_cfg = {
60
61
62
63
64
65
66
67
68
69
70
  0,              // cpu_used
  1,              // enable_auto_alt_ref
  0,              // noise_sensitivity
  0,              // sharpness
  0,              // static_thresh
  6,              // tile_columns
  0,              // tile_rows
  7,              // arnr_max_frames
  5,              // arnr_strength
  0,              // min_gf_interval; 0 -> default decision
  0,              // max_gf_interval; 0 -> default decision
Adrian Grange's avatar
Adrian Grange committed
71
  AOM_TUNE_PSNR,  // tuning
72
73
74
75
76
  10,             // cq_level
  0,              // rc_max_intra_bitrate_pct
  0,              // rc_max_inter_bitrate_pct
  0,              // gf_cbr_boost_pct
  0,              // lossless
77
#if CONFIG_AOM_QM
78
79
80
  0,                 // enable_qm
  DEFAULT_QM_FIRST,  // qm_min
  DEFAULT_QM_LAST,   // qm_max
81
#endif
clang-format's avatar
clang-format committed
82
83
84
  1,                    // frame_parallel_decoding_mode
  NO_AQ,                // aq_mode
  0,                    // frame_periodic_delta_q
Adrian Grange's avatar
Adrian Grange committed
85
86
87
  AOM_BITS_8,           // Bit depth
  AOM_CONTENT_DEFAULT,  // content
  AOM_CS_UNKNOWN,       // color space
clang-format's avatar
clang-format committed
88
89
90
  0,                    // color range
  0,                    // render width
  0,                    // render height
Jingning Han's avatar
Jingning Han committed
91
92
};

Adrian Grange's avatar
Adrian Grange committed
93
94
95
struct aom_codec_alg_priv {
  aom_codec_priv_t base;
  aom_codec_enc_cfg_t cfg;
96
97
98
  struct av1_extracfg extra_cfg;
  AV1EncoderConfig oxcf;
  AV1_COMP *cpi;
clang-format's avatar
clang-format committed
99
100
101
102
103
104
  unsigned char *cx_data;
  size_t cx_data_sz;
  unsigned char *pending_cx_data;
  size_t pending_cx_data_sz;
  int pending_frame_count;
  size_t pending_frame_sizes[8];
105
#if !CONFIG_MISC_FIXES
clang-format's avatar
clang-format committed
106
  size_t pending_frame_magnitude;
107
#endif
Adrian Grange's avatar
Adrian Grange committed
108
109
  aom_image_t preview_img;
  aom_enc_frame_flags_t next_frame_flags;
Adrian Grange's avatar
Adrian Grange committed
110
  aom_postproc_cfg_t preview_ppcfg;
Adrian Grange's avatar
Adrian Grange committed
111
  aom_codec_pkt_list_decl(256) pkt_list;
clang-format's avatar
clang-format committed
112
  unsigned int fixed_kf_cntr;
Adrian Grange's avatar
Adrian Grange committed
113
  aom_codec_priv_output_cx_pkt_cb_pair_t output_cx_pkt_cb;
Jingning Han's avatar
Jingning Han committed
114
  // BufferPool that holds all reference frames.
clang-format's avatar
clang-format committed
115
  BufferPool *buffer_pool;
Jingning Han's avatar
Jingning Han committed
116
117
};

Adrian Grange's avatar
Adrian Grange committed
118
static AOM_REFFRAME ref_frame_to_av1_reframe(aom_ref_frame_type_t frame) {
Jingning Han's avatar
Jingning Han committed
119
  switch (frame) {
Adrian Grange's avatar
Adrian Grange committed
120
121
122
    case AOM_LAST_FRAME: return AOM_LAST_FLAG;
    case AOM_GOLD_FRAME: return AOM_GOLD_FLAG;
    case AOM_ALTR_FRAME: return AOM_ALT_FLAG;
Jingning Han's avatar
Jingning Han committed
123
124
  }
  assert(0 && "Invalid Reference Frame");
Adrian Grange's avatar
Adrian Grange committed
125
  return AOM_LAST_FLAG;
Jingning Han's avatar
Jingning Han committed
126
127
}

Adrian Grange's avatar
Adrian Grange committed
128
129
130
static aom_codec_err_t update_error_state(
    aom_codec_alg_priv_t *ctx, const struct aom_internal_error_info *error) {
  const aom_codec_err_t res = error->error_code;
Jingning Han's avatar
Jingning Han committed
131

Adrian Grange's avatar
Adrian Grange committed
132
  if (res != AOM_CODEC_OK)
Jingning Han's avatar
Jingning Han committed
133
134
135
136
137
138
    ctx->base.err_detail = error->has_detail ? error->detail : NULL;

  return res;
}

#undef ERROR
clang-format's avatar
clang-format committed
139
140
141
#define ERROR(str)                  \
  do {                              \
    ctx->base.err_detail = str;     \
Adrian Grange's avatar
Adrian Grange committed
142
    return AOM_CODEC_INVALID_PARAM; \
Jingning Han's avatar
Jingning Han committed
143
144
  } while (0)

clang-format's avatar
clang-format committed
145
146
#define RANGE_CHECK(p, memb, lo, hi)                                 \
  do {                                                               \
Jingning Han's avatar
Jingning Han committed
147
    if (!(((p)->memb == lo || (p)->memb > (lo)) && (p)->memb <= hi)) \
clang-format's avatar
clang-format committed
148
      ERROR(#memb " out of range [" #lo ".." #hi "]");               \
Jingning Han's avatar
Jingning Han committed
149
150
  } while (0)

clang-format's avatar
clang-format committed
151
152
153
#define RANGE_CHECK_HI(p, memb, hi)                                     \
  do {                                                                  \
    if (!((p)->memb <= (hi))) ERROR(#memb " out of range [.." #hi "]"); \
Jingning Han's avatar
Jingning Han committed
154
155
  } while (0)

clang-format's avatar
clang-format committed
156
157
158
#define RANGE_CHECK_LO(p, memb, lo)                                     \
  do {                                                                  \
    if (!((p)->memb >= (lo))) ERROR(#memb " out of range [" #lo "..]"); \
Jingning Han's avatar
Jingning Han committed
159
160
  } while (0)

clang-format's avatar
clang-format committed
161
162
163
#define RANGE_CHECK_BOOL(p, memb)                                     \
  do {                                                                \
    if (!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean"); \
Jingning Han's avatar
Jingning Han committed
164
165
  } while (0)

Adrian Grange's avatar
Adrian Grange committed
166
167
static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
                                       const aom_codec_enc_cfg_t *cfg,
168
                                       const struct av1_extracfg *extra_cfg) {
clang-format's avatar
clang-format committed
169
170
171
172
173
174
175
176
  RANGE_CHECK(cfg, g_w, 1, 65535);  // 16 bits available
  RANGE_CHECK(cfg, g_h, 1, 65535);  // 16 bits available
  RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000);
  RANGE_CHECK(cfg, g_timebase.num, 1, cfg->g_timebase.den);
  RANGE_CHECK_HI(cfg, g_profile, 3);

  RANGE_CHECK_HI(cfg, rc_max_quantizer, 63);
  RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer);
Jingning Han's avatar
Jingning Han committed
177
  RANGE_CHECK_BOOL(extra_cfg, lossless);
clang-format's avatar
clang-format committed
178
  RANGE_CHECK(extra_cfg, aq_mode, 0, AQ_MODE_COUNT - 1);
Jingning Han's avatar
Jingning Han committed
179
  RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
clang-format's avatar
clang-format committed
180
181
  RANGE_CHECK_HI(cfg, g_threads, 64);
  RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS);
Adrian Grange's avatar
Adrian Grange committed
182
  RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q);
clang-format's avatar
clang-format committed
183
184
  RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100);
  RANGE_CHECK_HI(cfg, rc_overshoot_pct, 100);
Jingning Han's avatar
Jingning Han committed
185
  RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
Adrian Grange's avatar
Adrian Grange committed
186
  RANGE_CHECK(cfg, kf_mode, AOM_KF_DISABLED, AOM_KF_AUTO);
clang-format's avatar
clang-format committed
187
188
189
  RANGE_CHECK_BOOL(cfg, rc_resize_allowed);
  RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100);
  RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100);
Jingning Han's avatar
Jingning Han committed
190
  RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
Adrian Grange's avatar
Adrian Grange committed
191
  RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_LAST_PASS);
Jingning Han's avatar
Jingning Han committed
192
193
194
195
196
197
198
  RANGE_CHECK(extra_cfg, min_gf_interval, 0, (MAX_LAG_BUFFERS - 1));
  RANGE_CHECK(extra_cfg, max_gf_interval, 0, (MAX_LAG_BUFFERS - 1));
  if (extra_cfg->max_gf_interval > 0) {
    RANGE_CHECK(extra_cfg, max_gf_interval, 2, (MAX_LAG_BUFFERS - 1));
  }
  if (extra_cfg->min_gf_interval > 0 && extra_cfg->max_gf_interval > 0) {
    RANGE_CHECK(extra_cfg, max_gf_interval, extra_cfg->min_gf_interval,
clang-format's avatar
clang-format committed
199
                (MAX_LAG_BUFFERS - 1));
Jingning Han's avatar
Jingning Han committed
200
201
202
203
204
205
206
  }

  if (cfg->rc_resize_allowed == 1) {
    RANGE_CHECK(cfg, rc_scaled_width, 0, cfg->g_w);
    RANGE_CHECK(cfg, rc_scaled_height, 0, cfg->g_h);
  }

207
  // Spatial/temporal scalability are not yet supported in AV1.
Yunqing Wang's avatar
Yunqing Wang committed
208
209
210
  // Only accept the default value for range checking.
  RANGE_CHECK(cfg, ss_number_layers, 1, 1);
  RANGE_CHECK(cfg, ts_number_layers, 1, 1);
211
  // AV1 does not support a lower bound on the keyframe interval in
Jingning Han's avatar
Jingning Han committed
212
  // automatic keyframe placement mode.
Adrian Grange's avatar
Adrian Grange committed
213
  if (cfg->kf_mode != AOM_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist &&
Jingning Han's avatar
Jingning Han committed
214
      cfg->kf_min_dist > 0)
clang-format's avatar
clang-format committed
215
216
217
    ERROR(
        "kf_min_dist not supported in auto mode, use 0 "
        "or kf_max_dist instead.");
Jingning Han's avatar
Jingning Han committed
218
219
220
221
222
223
224
225
226
227

  RANGE_CHECK(extra_cfg, enable_auto_alt_ref, 0, 2);
  RANGE_CHECK(extra_cfg, cpu_used, -8, 8);
  RANGE_CHECK_HI(extra_cfg, noise_sensitivity, 6);
  RANGE_CHECK(extra_cfg, tile_columns, 0, 6);
  RANGE_CHECK(extra_cfg, tile_rows, 0, 2);
  RANGE_CHECK_HI(extra_cfg, sharpness, 7);
  RANGE_CHECK(extra_cfg, arnr_max_frames, 0, 15);
  RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
  RANGE_CHECK(extra_cfg, cq_level, 0, 63);
Adrian Grange's avatar
Adrian Grange committed
228
  RANGE_CHECK(cfg, g_bit_depth, AOM_BITS_8, AOM_BITS_12);
Jingning Han's avatar
Jingning Han committed
229
  RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
Adrian Grange's avatar
Adrian Grange committed
230
  RANGE_CHECK(extra_cfg, content, AOM_CONTENT_DEFAULT, AOM_CONTENT_INVALID - 1);
Jingning Han's avatar
Jingning Han committed
231

232
  // TODO(yaowu): remove this when ssim tuning is implemented for av1
Adrian Grange's avatar
Adrian Grange committed
233
  if (extra_cfg->tuning == AOM_TUNE_SSIM)
234
    ERROR("Option --tune=ssim is not currently supported in AV1.");
Jingning Han's avatar
Jingning Han committed
235

Adrian Grange's avatar
Adrian Grange committed
236
  if (cfg->g_pass == AOM_RC_LAST_PASS) {
Jingning Han's avatar
Jingning Han committed
237
238
239
240
241
242
243
244
245
246
    const size_t packet_sz = sizeof(FIRSTPASS_STATS);
    const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
    const FIRSTPASS_STATS *stats;

    if (cfg->rc_twopass_stats_in.buf == NULL)
      ERROR("rc_twopass_stats_in.buf not set.");

    if (cfg->rc_twopass_stats_in.sz % packet_sz)
      ERROR("rc_twopass_stats_in.sz indicates truncated packet.");

Yunqing Wang's avatar
Yunqing Wang committed
247
248
    if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz)
      ERROR("rc_twopass_stats_in requires at least two packets.");
Jingning Han's avatar
Jingning Han committed
249

Yunqing Wang's avatar
Yunqing Wang committed
250
251
    stats =
        (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1;
Jingning Han's avatar
Jingning Han committed
252

Yunqing Wang's avatar
Yunqing Wang committed
253
254
    if ((int)(stats->count + 0.5) != n_packets - 1)
      ERROR("rc_twopass_stats_in missing EOS stats packet");
Jingning Han's avatar
Jingning Han committed
255
256
  }

257
#if !CONFIG_AOM_HIGHBITDEPTH
Jingning Han's avatar
Jingning Han committed
258
259
260
261
262
  if (cfg->g_profile > (unsigned int)PROFILE_1) {
    ERROR("Profile > 1 not supported in this build configuration");
  }
#endif
  if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
Adrian Grange's avatar
Adrian Grange committed
263
      cfg->g_bit_depth > AOM_BITS_8) {
Jingning Han's avatar
Jingning Han committed
264
265
    ERROR("Codec high bit-depth not supported in profile < 2");
  }
clang-format's avatar
clang-format committed
266
  if (cfg->g_profile <= (unsigned int)PROFILE_1 && cfg->g_input_bit_depth > 8) {
Jingning Han's avatar
Jingning Han committed
267
268
269
    ERROR("Source high bit-depth not supported in profile < 2");
  }
  if (cfg->g_profile > (unsigned int)PROFILE_1 &&
Adrian Grange's avatar
Adrian Grange committed
270
      cfg->g_bit_depth == AOM_BITS_8) {
Jingning Han's avatar
Jingning Han committed
271
272
    ERROR("Codec bit-depth 8 not supported in profile > 1");
  }
Adrian Grange's avatar
Adrian Grange committed
273
  RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_SRGB);
274
  RANGE_CHECK(extra_cfg, color_range, 0, 1);
Adrian Grange's avatar
Adrian Grange committed
275
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
276
277
}

Adrian Grange's avatar
Adrian Grange committed
278
279
static aom_codec_err_t validate_img(aom_codec_alg_priv_t *ctx,
                                    const aom_image_t *img) {
Jingning Han's avatar
Jingning Han committed
280
  switch (img->fmt) {
Adrian Grange's avatar
Adrian Grange committed
281
282
283
284
285
286
    case AOM_IMG_FMT_YV12:
    case AOM_IMG_FMT_I420:
    case AOM_IMG_FMT_I42016: break;
    case AOM_IMG_FMT_I422:
    case AOM_IMG_FMT_I444:
    case AOM_IMG_FMT_I440:
Jingning Han's avatar
Jingning Han committed
287
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1) {
clang-format's avatar
clang-format committed
288
289
290
        ERROR(
            "Invalid image format. I422, I444, I440 images are "
            "not supported in profile.");
Jingning Han's avatar
Jingning Han committed
291
292
      }
      break;
Adrian Grange's avatar
Adrian Grange committed
293
294
295
    case AOM_IMG_FMT_I42216:
    case AOM_IMG_FMT_I44416:
    case AOM_IMG_FMT_I44016:
Jingning Han's avatar
Jingning Han committed
296
297
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1 &&
          ctx->cfg.g_profile != (unsigned int)PROFILE_3) {
clang-format's avatar
clang-format committed
298
299
300
        ERROR(
            "Invalid image format. 16-bit I422, I444, I440 images are "
            "not supported in profile.");
Jingning Han's avatar
Jingning Han committed
301
302
303
      }
      break;
    default:
clang-format's avatar
clang-format committed
304
305
306
      ERROR(
          "Invalid image format. Only YV12, I420, I422, I444 images are "
          "supported.");
Jingning Han's avatar
Jingning Han committed
307
308
309
310
311
312
      break;
  }

  if (img->d_w != ctx->cfg.g_w || img->d_h != ctx->cfg.g_h)
    ERROR("Image size must match encoder init configuration size");

Adrian Grange's avatar
Adrian Grange committed
313
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
314
315
}

Adrian Grange's avatar
Adrian Grange committed
316
static int get_image_bps(const aom_image_t *img) {
Jingning Han's avatar
Jingning Han committed
317
  switch (img->fmt) {
Adrian Grange's avatar
Adrian Grange committed
318
319
320
321
322
323
324
325
326
    case AOM_IMG_FMT_YV12:
    case AOM_IMG_FMT_I420: return 12;
    case AOM_IMG_FMT_I422: return 16;
    case AOM_IMG_FMT_I444: return 24;
    case AOM_IMG_FMT_I440: return 16;
    case AOM_IMG_FMT_I42016: return 24;
    case AOM_IMG_FMT_I42216: return 32;
    case AOM_IMG_FMT_I44416: return 48;
    case AOM_IMG_FMT_I44016: return 32;
Jingning Han's avatar
Jingning Han committed
327
328
329
330
331
    default: assert(0 && "Invalid image format"); break;
  }
  return 0;
}

Adrian Grange's avatar
Adrian Grange committed
332
static aom_codec_err_t set_encoder_config(
333
334
    AV1EncoderConfig *oxcf, const aom_codec_enc_cfg_t *cfg,
    const struct av1_extracfg *extra_cfg) {
Adrian Grange's avatar
Adrian Grange committed
335
  const int is_vbr = cfg->rc_end_usage == AOM_VBR;
Jingning Han's avatar
Jingning Han committed
336
337
  oxcf->profile = cfg->g_profile;
  oxcf->max_threads = (int)cfg->g_threads;
clang-format's avatar
clang-format committed
338
339
  oxcf->width = cfg->g_w;
  oxcf->height = cfg->g_h;
Jingning Han's avatar
Jingning Han committed
340
341
342
343
  oxcf->bit_depth = cfg->g_bit_depth;
  oxcf->input_bit_depth = cfg->g_input_bit_depth;
  // guess a frame rate if out of whack, use 30
  oxcf->init_framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
clang-format's avatar
clang-format committed
344
  if (oxcf->init_framerate > 180) oxcf->init_framerate = 30;
Jingning Han's avatar
Jingning Han committed
345
346
347
348

  oxcf->mode = GOOD;

  switch (cfg->g_pass) {
Adrian Grange's avatar
Adrian Grange committed
349
350
351
    case AOM_RC_ONE_PASS: oxcf->pass = 0; break;
    case AOM_RC_FIRST_PASS: oxcf->pass = 1; break;
    case AOM_RC_LAST_PASS: oxcf->pass = 2; break;
Jingning Han's avatar
Jingning Han committed
352
353
  }

clang-format's avatar
clang-format committed
354
  oxcf->lag_in_frames =
Adrian Grange's avatar
Adrian Grange committed
355
      cfg->g_pass == AOM_RC_FIRST_PASS ? 0 : cfg->g_lag_in_frames;
Jingning Han's avatar
Jingning Han committed
356
357
358
359
360
361
362
363
364
  oxcf->rc_mode = cfg->rc_end_usage;

  // Convert target bandwidth from Kbit/s to Bit/s
  oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
  oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
  oxcf->rc_max_inter_bitrate_pct = extra_cfg->rc_max_inter_bitrate_pct;
  oxcf->gf_cbr_boost_pct = extra_cfg->gf_cbr_boost_pct;

  oxcf->best_allowed_q =
365
      extra_cfg->lossless ? 0 : av1_quantizer_to_qindex(cfg->rc_min_quantizer);
Jingning Han's avatar
Jingning Han committed
366
  oxcf->worst_allowed_q =
367
368
      extra_cfg->lossless ? 0 : av1_quantizer_to_qindex(cfg->rc_max_quantizer);
  oxcf->cq_level = av1_quantizer_to_qindex(extra_cfg->cq_level);
Jingning Han's avatar
Jingning Han committed
369
370
  oxcf->fixed_q = -1;

371
372
#if CONFIG_AOM_QM
  oxcf->using_qm = extra_cfg->enable_qm;
373
374
  oxcf->qm_minlevel = extra_cfg->qm_min;
  oxcf->qm_maxlevel = extra_cfg->qm_max;
375
376
#endif

clang-format's avatar
clang-format committed
377
378
  oxcf->under_shoot_pct = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct = cfg->rc_overshoot_pct;
Jingning Han's avatar
Jingning Han committed
379

clang-format's avatar
clang-format committed
380
  oxcf->scaled_frame_width = cfg->rc_scaled_width;
Jingning Han's avatar
Jingning Han committed
381
382
383
  oxcf->scaled_frame_height = cfg->rc_scaled_height;
  if (cfg->rc_resize_allowed == 1) {
    oxcf->resize_mode =
clang-format's avatar
clang-format committed
384
385
386
        (oxcf->scaled_frame_width == 0 || oxcf->scaled_frame_height == 0)
            ? RESIZE_DYNAMIC
            : RESIZE_FIXED;
Jingning Han's avatar
Jingning Han committed
387
388
389
390
  } else {
    oxcf->resize_mode = RESIZE_NONE;
  }

clang-format's avatar
clang-format committed
391
  oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz;
Jingning Han's avatar
Jingning Han committed
392
  oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
clang-format's avatar
clang-format committed
393
  oxcf->optimal_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
Jingning Han's avatar
Jingning Han committed
394

clang-format's avatar
clang-format committed
395
  oxcf->drop_frames_water_mark = cfg->rc_dropframe_thresh;
Jingning Han's avatar
Jingning Han committed
396

clang-format's avatar
clang-format committed
397
398
399
  oxcf->two_pass_vbrbias = cfg->rc_2pass_vbr_bias_pct;
  oxcf->two_pass_vbrmin_section = cfg->rc_2pass_vbr_minsection_pct;
  oxcf->two_pass_vbrmax_section = cfg->rc_2pass_vbr_maxsection_pct;
Jingning Han's avatar
Jingning Han committed
400

clang-format's avatar
clang-format committed
401
  oxcf->auto_key =
Adrian Grange's avatar
Adrian Grange committed
402
      cfg->kf_mode == AOM_KF_AUTO && cfg->kf_min_dist != cfg->kf_max_dist;
Jingning Han's avatar
Jingning Han committed
403

clang-format's avatar
clang-format committed
404
  oxcf->key_freq = cfg->kf_max_dist;
Jingning Han's avatar
Jingning Han committed
405

clang-format's avatar
clang-format committed
406
407
408
409
410
  oxcf->speed = abs(extra_cfg->cpu_used);
  oxcf->encode_breakout = extra_cfg->static_thresh;
  oxcf->enable_auto_arf = extra_cfg->enable_auto_alt_ref;
  oxcf->noise_sensitivity = extra_cfg->noise_sensitivity;
  oxcf->sharpness = extra_cfg->sharpness;
Jingning Han's avatar
Jingning Han committed
411

clang-format's avatar
clang-format committed
412
  oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in;
Jingning Han's avatar
Jingning Han committed
413
414

#if CONFIG_FP_MB_STATS
clang-format's avatar
clang-format committed
415
  oxcf->firstpass_mb_stats_in = cfg->rc_firstpass_mb_stats_in;
Jingning Han's avatar
Jingning Han committed
416
417
418
#endif

  oxcf->color_space = extra_cfg->color_space;
419
  oxcf->color_range = extra_cfg->color_range;
clang-format's avatar
clang-format committed
420
  oxcf->render_width = extra_cfg->render_width;
421
  oxcf->render_height = extra_cfg->render_height;
Jingning Han's avatar
Jingning Han committed
422
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
clang-format's avatar
clang-format committed
423
  oxcf->arnr_strength = extra_cfg->arnr_strength;
Jingning Han's avatar
Jingning Han committed
424
425
426
427
428
429
430
  oxcf->min_gf_interval = extra_cfg->min_gf_interval;
  oxcf->max_gf_interval = extra_cfg->max_gf_interval;

  oxcf->tuning = extra_cfg->tuning;
  oxcf->content = extra_cfg->content;

  oxcf->tile_columns = extra_cfg->tile_columns;
clang-format's avatar
clang-format committed
431
  oxcf->tile_rows = extra_cfg->tile_rows;
Jingning Han's avatar
Jingning Han committed
432

clang-format's avatar
clang-format committed
433
  oxcf->error_resilient_mode = cfg->g_error_resilient;
Jingning Han's avatar
Jingning Han committed
434
435
436
437
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;

  oxcf->aq_mode = extra_cfg->aq_mode;

clang-format's avatar
clang-format committed
438
  oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
Jingning Han's avatar
Jingning Han committed
439
440

  /*
441
  printf("Current AV1 Settings: \n");
Jingning Han's avatar
Jingning Han committed
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
  printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
  printf("sharpness: %d\n",    oxcf->sharpness);
  printf("cpu_used: %d\n",  oxcf->cpu_used);
  printf("Mode: %d\n",     oxcf->mode);
  printf("auto_key: %d\n",  oxcf->auto_key);
  printf("key_freq: %d\n", oxcf->key_freq);
  printf("end_usage: %d\n", oxcf->end_usage);
  printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct);
  printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct);
  printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level);
  printf("optimal_buffer_level: %d\n",  oxcf->optimal_buffer_level);
  printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size);
  printf("fixed_q: %d\n",  oxcf->fixed_q);
  printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q);
  printf("best_allowed_q: %d\n", oxcf->best_allowed_q);
  printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling);
  printf("scaled_frame_width: %d\n", oxcf->scaled_frame_width);
  printf("scaled_frame_height: %d\n", oxcf->scaled_frame_height);
  printf("two_pass_vbrbias: %d\n",  oxcf->two_pass_vbrbias);
  printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section);
  printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section);
  printf("lag_in_frames: %d\n", oxcf->lag_in_frames);
  printf("enable_auto_arf: %d\n", oxcf->enable_auto_arf);
  printf("Version: %d\n", oxcf->Version);
  printf("encode_breakout: %d\n", oxcf->encode_breakout);
  printf("error resilient: %d\n", oxcf->error_resilient_mode);
  printf("frame parallel detokenization: %d\n",
         oxcf->frame_parallel_decoding_mode);
  */
Adrian Grange's avatar
Adrian Grange committed
472
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
473
474
}

Adrian Grange's avatar
Adrian Grange committed
475
476
477
static aom_codec_err_t encoder_set_config(aom_codec_alg_priv_t *ctx,
                                          const aom_codec_enc_cfg_t *cfg) {
  aom_codec_err_t res;
Jingning Han's avatar
Jingning Han committed
478
479
480
  int force_key = 0;

  if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
Adrian Grange's avatar
Adrian Grange committed
481
    if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS)
Jingning Han's avatar
Jingning Han committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
      ERROR("Cannot change width or height after initialization");
    if (!valid_ref_frame_size(ctx->cfg.g_w, ctx->cfg.g_h, cfg->g_w, cfg->g_h) ||
        (ctx->cpi->initial_width && (int)cfg->g_w > ctx->cpi->initial_width) ||
        (ctx->cpi->initial_height && (int)cfg->g_h > ctx->cpi->initial_height))
      force_key = 1;
  }

  // Prevent increasing lag_in_frames. This check is stricter than it needs
  // to be -- the limit is not increasing past the first lag_in_frames
  // value, but we don't track the initial config, only the last successful
  // config.
  if (cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames)
    ERROR("Cannot increase lag_in_frames");

  res = validate_config(ctx, cfg, &ctx->extra_cfg);

Adrian Grange's avatar
Adrian Grange committed
498
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
499
500
501
502
    ctx->cfg = *cfg;
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
    // On profile change, request a key frame
    force_key |= ctx->cpi->common.profile != ctx->oxcf.profile;
503
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
504
505
  }

Adrian Grange's avatar
Adrian Grange committed
506
  if (force_key) ctx->next_frame_flags |= AOM_EFLAG_FORCE_KF;
Jingning Han's avatar
Jingning Han committed
507
508
509
510

  return res;
}

Adrian Grange's avatar
Adrian Grange committed
511
static aom_codec_err_t ctrl_get_quantizer(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
512
513
                                          va_list args) {
  int *const arg = va_arg(args, int *);
Adrian Grange's avatar
Adrian Grange committed
514
  if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
515
  *arg = av1_get_quantizer(ctx->cpi);
Adrian Grange's avatar
Adrian Grange committed
516
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
517
518
}

Adrian Grange's avatar
Adrian Grange committed
519
static aom_codec_err_t ctrl_get_quantizer64(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
520
521
                                            va_list args) {
  int *const arg = va_arg(args, int *);
Adrian Grange's avatar
Adrian Grange committed
522
  if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
523
  *arg = av1_qindex_to_quantizer(av1_get_quantizer(ctx->cpi));
Adrian Grange's avatar
Adrian Grange committed
524
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
525
526
}

Adrian Grange's avatar
Adrian Grange committed
527
static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx,
528
                                        const struct av1_extracfg *extra_cfg) {
Adrian Grange's avatar
Adrian Grange committed
529
  const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
Adrian Grange's avatar
Adrian Grange committed
530
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
531
532
    ctx->extra_cfg = *extra_cfg;
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
533
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
534
535
536
537
  }
  return res;
}

Adrian Grange's avatar
Adrian Grange committed
538
static aom_codec_err_t ctrl_set_cpuused(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
539
                                        va_list args) {
540
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
541
  extra_cfg.cpu_used = CAST(AOME_SET_CPUUSED, args);
Jingning Han's avatar
Jingning Han committed
542
543
544
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
545
static aom_codec_err_t ctrl_set_enable_auto_alt_ref(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
546
                                                    va_list args) {
547
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
548
  extra_cfg.enable_auto_alt_ref = CAST(AOME_SET_ENABLEAUTOALTREF, args);
Jingning Han's avatar
Jingning Han committed
549
550
551
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
552
static aom_codec_err_t ctrl_set_noise_sensitivity(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
553
                                                  va_list args) {
554
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
555
  extra_cfg.noise_sensitivity = CAST(AV1E_SET_NOISE_SENSITIVITY, args);
Jingning Han's avatar
Jingning Han committed
556
557
558
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
559
static aom_codec_err_t ctrl_set_sharpness(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
560
                                          va_list args) {
561
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
562
  extra_cfg.sharpness = CAST(AOME_SET_SHARPNESS, args);
Jingning Han's avatar
Jingning Han committed
563
564
565
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
566
static aom_codec_err_t ctrl_set_static_thresh(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
567
                                              va_list args) {
568
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
569
  extra_cfg.static_thresh = CAST(AOME_SET_STATIC_THRESHOLD, args);
Jingning Han's avatar
Jingning Han committed
570
571
572
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
573
static aom_codec_err_t ctrl_set_tile_columns(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
574
                                             va_list args) {
575
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
576
  extra_cfg.tile_columns = CAST(AV1E_SET_TILE_COLUMNS, args);
Jingning Han's avatar
Jingning Han committed
577
578
579
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
580
static aom_codec_err_t ctrl_set_tile_rows(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
581
                                          va_list args) {
582
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
583
  extra_cfg.tile_rows = CAST(AV1E_SET_TILE_ROWS, args);
Jingning Han's avatar
Jingning Han committed
584
585
586
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
587
static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
588
                                                va_list args) {
589
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
590
  extra_cfg.arnr_max_frames = CAST(AOME_SET_ARNR_MAXFRAMES, args);
Jingning Han's avatar
Jingning Han committed
591
592
593
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
594
static aom_codec_err_t ctrl_set_arnr_strength(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
595
                                              va_list args) {
596
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
597
  extra_cfg.arnr_strength = CAST(AOME_SET_ARNR_STRENGTH, args);
Jingning Han's avatar
Jingning Han committed
598
599
600
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
601
static aom_codec_err_t ctrl_set_arnr_type(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
602
603
604
                                          va_list args) {
  (void)ctx;
  (void)args;
Adrian Grange's avatar
Adrian Grange committed
605
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
606
607
}

Adrian Grange's avatar
Adrian Grange committed
608
static aom_codec_err_t ctrl_set_tuning(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
609
                                       va_list args) {
610
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
611
  extra_cfg.tuning = CAST(AOME_SET_TUNING, args);
Jingning Han's avatar
Jingning Han committed
612
613
614
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
615
static aom_codec_err_t ctrl_set_cq_level(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
616
                                         va_list args) {
617
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
618
  extra_cfg.cq_level = CAST(AOME_SET_CQ_LEVEL, args);
Jingning Han's avatar
Jingning Han committed
619
620
621
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
622
623
static aom_codec_err_t ctrl_set_rc_max_intra_bitrate_pct(
    aom_codec_alg_priv_t *ctx, va_list args) {
624
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
625
  extra_cfg.rc_max_intra_bitrate_pct =
Adrian Grange's avatar
Adrian Grange committed
626
      CAST(AOME_SET_MAX_INTRA_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
627
628
629
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
630
631
static aom_codec_err_t ctrl_set_rc_max_inter_bitrate_pct(
    aom_codec_alg_priv_t *ctx, va_list args) {
632
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
633
  extra_cfg.rc_max_inter_bitrate_pct =
Adrian Grange's avatar
Adrian Grange committed
634
      CAST(AOME_SET_MAX_INTER_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
635
636
637
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
638
static aom_codec_err_t ctrl_set_rc_gf_cbr_boost_pct(aom_codec_alg_priv_t *ctx,
clang-format's avatar
clang-format committed
639
                                                    va_list args) {
640
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
641
  extra_cfg.gf_cbr_boost_pct = CAST(AV1E_SET_GF_CBR_BOOST_PCT, args);
Jingning Han's avatar
Jingning Han committed
642
643
644
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
645
static aom_codec_err_t ctrl_set_lossless(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
646
                                         va_list args) {
647
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
648
  extra_cfg.lossless = CAST(AV1E_SET_LOSSLESS, args);
Jingning Han's avatar
Jingning Han committed
649
650
651
  return update_extra_cfg(ctx, &extra_cfg);
}

652
#if CONFIG_AOM_QM
Adrian Grange's avatar
Adrian Grange committed
653
static aom_codec_err_t ctrl_set_enable_qm(aom_codec_alg_priv_t *ctx,
654
                                         va_list args) {
655
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
656
  extra_cfg.enable_qm = CAST(AV1E_SET_ENABLE_QM, args);
657
658
  return update_extra_cfg(ctx, &extra_cfg);
}
659

Adrian Grange's avatar
Adrian Grange committed
660
static aom_codec_err_t ctrl_set_qm_min(aom_codec_alg_priv_t *ctx,
661
                                       va_list args) {
662
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
663
  extra_cfg.qm_min = CAST(AV1E_SET_QM_MIN, args);
664
665
666
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
667
static aom_codec_err_t ctrl_set_qm_max(aom_codec_alg_priv_t *ctx,
668
                                       va_list args) {
669
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
670
  extra_cfg.qm_max = CAST(AV1E_SET_QM_MAX, args);
671
672
  return update_extra_cfg(ctx, &extra_cfg);
}
673
674
#endif

Adrian Grange's avatar
Adrian Grange committed
675
676
static aom_codec_err_t ctrl_set_frame_parallel_decoding_mode(
    aom_codec_alg_priv_t *ctx, va_list args) {
677
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
678
  extra_cfg.frame_parallel_decoding_mode =
Adrian Grange's avatar
Adrian Grange committed
679
      CAST(AV1E_SET_FRAME_PARALLEL_DECODING, args);
Jingning Han's avatar
Jingning Han committed
680
681
682
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
683
static aom_codec_err_t ctrl_set_aq_mode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
684
                                        va_list args) {
685
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
686
  extra_cfg.aq_mode = CAST(AV1E_SET_AQ_MODE, args);
Jingning Han's avatar
Jingning Han committed
687
688
689
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
690
static aom_codec_err_t ctrl_set_min_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
691
                                                va_list args) {
692
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
693
  extra_cfg.min_gf_interval = CAST(AV1E_SET_MIN_GF_INTERVAL, args);
Jingning Han's avatar
Jingning Han committed
694
695
696
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
697
static aom_codec_err_t ctrl_set_max_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
698
                                                va_list args) {
699
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
700
  extra_cfg.max_gf_interval = CAST(AV1E_SET_MAX_GF_INTERVAL, args);
Jingning Han's avatar
Jingning Han committed
701
702
703
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
704
static aom_codec_err_t ctrl_set_frame_periodic_boost(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
705
                                                     va_list args) {
706
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Adrian Grange's avatar
Adrian Grange committed
707
  extra_cfg.frame_periodic_boost = CAST(AV1E_SET_FRAME_PERIODIC_BOOST, args);
Jingning Han's avatar
Jingning Han committed
708
709
710
  return update_extra_cfg(ctx, &extra_cfg);
}

Adrian Grange's avatar
Adrian Grange committed
711
712
static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx,
                                    aom_codec_priv_enc_mr_cfg_t *data) {
Adrian Grange's avatar
Adrian Grange committed
713
  aom_codec_err_t res = AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
714
715
716
  (void)data;

  if (ctx->priv == NULL) {
Adrian Grange's avatar
Adrian Grange committed
717
    aom_codec_alg_priv_t *const priv = aom_calloc(1, sizeof(*priv));
Adrian Grange's avatar
Adrian Grange committed
718
    if (priv == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
719

Adrian Grange's avatar
Adrian Grange committed
720
    ctx->priv = (aom_codec_priv_t *)priv;
Jingning Han's avatar
Jingning Han committed
721
722
    ctx->priv->init_flags = ctx->init_flags;
    ctx->priv->enc.total_encoders = 1;
Adrian Grange's avatar
Adrian Grange committed
723
    priv->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool));
Adrian Grange's avatar
Adrian Grange committed
724
    if (priv->buffer_pool == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
725
726
727

#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&priv->buffer_pool->pool_mutex, NULL)) {
Adrian Grange's avatar
Adrian Grange committed
728
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
729
730
731
732
733
734
735
736
737
738
    }
#endif

    if (ctx->config.enc) {
      // Update the reference to the config structure to an internal copy.
      priv->cfg = *ctx->config.enc;
      ctx->config.enc = &priv->cfg;
    }

    priv->extra_cfg = default_extra_cfg;
739
    once(av1_initialize_enc);
Jingning Han's avatar
Jingning Han committed
740
741
742

    res = validate_config(priv, &priv->cfg, &priv->extra_cfg);

Adrian Grange's avatar
Adrian Grange committed
743
    if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
744
      set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
745
#if CONFIG_AOM_HIGHBITDEPTH
Jingning Han's avatar
Jingning Han committed
746
      priv->oxcf.use_highbitdepth =
Adrian Grange's avatar
Adrian Grange committed
747
          (ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) ? 1 : 0;
Jingning Han's avatar
Jingning Han committed
748
#endif
749
      priv->cpi = av1_create_compressor(&priv->oxcf, priv->buffer_pool);
Jingning Han's avatar
Jingning Han committed
750
      if (priv->cpi == NULL)
Adrian Grange's avatar
Adrian Grange committed
751
        res = AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
752
753
754
755
756
757
758
759
      else
        priv->cpi->output_pkt_list = &priv->pkt_list.head;
    }
  }

  return res;
}

Adrian Grange's avatar
Adrian Grange committed
760
static aom_codec_err_t encoder_destroy(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
761
  free(ctx->cx_data);
762
  av1_remove_compressor(ctx->cpi);
Jingning Han's avatar
Jingning Han committed
763
764
765
#if CONFIG_MULTITHREAD
  pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
#endif
Adrian Grange's avatar
Adrian Grange committed
766
767
  aom_free(ctx->buffer_pool);
  aom_free(ctx);
Adrian Grange's avatar
Adrian Grange committed
768
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
769
770
}

Adrian Grange's avatar
Adrian Grange committed
771
static void pick_quickcompress_mode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
772
773
774
775
776
                                    unsigned long duration,
                                    unsigned long deadline) {
  MODE new_mode = BEST;

  switch (ctx->cfg.g_pass) {
Adrian Grange's avatar
Adrian Grange committed
777
    case AOM_RC_ONE_PASS:
Jingning Han's avatar
Jingning Han committed
778
      if (deadline > 0) {
Adrian Grange's avatar
Adrian Grange committed
779
        const aom_codec_enc_cfg_t *const cfg = &ctx->cfg;
Jingning Han's avatar
Jingning Han committed
780
781
782

        // Convert duration parameter from stream timebase to microseconds.
        const uint64_t duration_us = (uint64_t)duration * 1000000 *
clang-format's avatar
clang-format committed
783
784
                                     (uint64_t)cfg->g_timebase.num /
                                     (uint64_t)cfg->g_timebase.den;
Jingning Han's avatar
Jingning Han committed
785
786
787
788
789
790
791
792

        // If the deadline is more that the duration this frame is to be shown,
        // use good quality mode. Otherwise use realtime mode.
        new_mode = (deadline > duration_us) ? GOOD : REALTIME;
      } else {
        new_mode = BEST;
      }
      break;
Adrian Grange's avatar
Adrian Grange committed
793
794
    case AOM_RC_FIRST_PASS: break;
    case AOM_RC_LAST_PASS: new_mode = deadline > 0 ? GOOD : BEST; break;
Jingning Han's avatar
Jingning Han committed
795
796
797
798
  }

  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
799
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
800
801
802
803
804
  }
}

// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
Adrian Grange's avatar
Adrian Grange committed
805
static int write_superframe_index(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
806
807
808
  uint8_t marker = 0xc0;
  unsigned int mask;
  int mag, index_sz;
809
810
811
812
#if CONFIG_MISC_FIXES
  int i;
  size_t max_frame_sz = 0;
#endif
Jingning Han's avatar
Jingning Han committed
813
814
815
816
817
818

  assert(ctx->pending_frame_count);
  assert(ctx->pending_frame_count <= 8);

  // Add the number of frames to the marker byte
  marker |= ctx->pending_frame_count - 1;
819
820
#if CONFIG_MISC_FIXES
  for (i = 0; i < ctx->pending_frame_count - 1; i++) {
clang-format's avatar
clang-format committed
821
    const size_t frame_sz = (unsigned int)ctx->pending_frame_sizes[i] - 1;
822
823
824
    max_frame_sz = frame_sz > max_frame_sz ? frame_sz : max_frame_sz;
  }
#endif
Jingning Han's avatar
Jingning Han committed
825
826
827

  // Choose the magnitude
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
828
#if CONFIG_MISC_FIXES
clang-format's avatar
clang-format committed
829
    if (max_frame_sz <= mask) break;
830
#else
clang-format's avatar
clang-format committed
831
    if (ctx->pending_frame_magnitude < mask) break;
832
#endif
Jingning Han's avatar
Jingning Han committed
833
834
835
836
837
838
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

  // Write the index
839
  index_sz = 2 + (mag + 1) * (ctx->pending_frame_count - CONFIG_MISC_FIXES);
Jingning Han's avatar
Jingning Han committed
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  if (ctx->pending_cx_data_sz + index_sz < ctx->cx_data_sz) {
    uint8_t *x = ctx->pending_cx_data + ctx->pending_cx_data_sz;
    int i, j;
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    uint8_t marker_test = 0xc0;
    int mag_test = 2;     // 1 - 4
    int frames_test = 4;  // 1 - 8
    int index_sz_test = 2 + mag_test * frames_test;
    marker_test |= frames_test - 1;
    marker_test |= (mag_test - 1) << 3;
    *x++ = marker_test;
    for (i = 0; i < mag_test * frames_test; ++i)
      *x++ = 0;  // fill up with arbitrary data
    *x++ = marker_test;
    ctx->pending_cx_data_sz += index_sz_test;
    printf("Added supplemental superframe data\n");
#endif

    *x++ = marker;
859
    for (i = 0; i < ctx->pending_frame_count - CONFIG_MISC_FIXES; i++) {
860
      unsigned int this_sz;
Jingning Han's avatar
Jingning Han committed
861

862
863
      assert(ctx->pending_frame_sizes[i] > 0);
      this_sz = (unsigned int)ctx->pending_frame_sizes[i] - CONFIG_MISC_FIXES;
Jingning Han's avatar
Jingning Han committed
864
865
866
867
868
869
870
871
872
873
874
875
876
877
      for (j = 0; j <= mag; j++) {
        *x++ = this_sz & 0xff;
        this_sz >>= 8;
      }
    }
    *x++ = marker;
    ctx->pending_cx_data_sz += index_sz;
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    index_sz += index_sz_test;
#endif
  }
  return index_sz;
}

878
// av1 uses 10,000,000 ticks/second as time stamp
Jingning Han's avatar
Jingning Han committed
879
880
#define TICKS_PER_SEC 10000000LL

Adrian Grange's avatar
Adrian Grange committed
881
static int64_t timebase_units_to_ticks(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
882
883
884
885
                                       int64_t n) {
  return n * TICKS_PER_SEC * timebase->num / timebase->den;
}

Adrian Grange's avatar
Adrian Grange committed
886
static int64_t ticks_to_timebase_units(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
887
888
889
890
891
                                       int64_t n) {
  const int64_t round = TICKS_PER_SEC * timebase->num / 2 - 1;
  return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC;
}

892
static aom_codec_frame_flags_t get_frame_pkt_flags(const AV1_COMP *cpi,
Jingning Han's avatar
Jingning Han committed
893
                                                   unsigned int lib_flags) {
Adrian Grange's avatar
Adrian Grange committed
894
  aom_codec_frame_flags_t flags = lib_flags << 16;
Jingning Han's avatar
Jingning Han committed
895

Adrian Grange's avatar
Adrian Grange committed
896
  if (lib_flags & FRAMEFLAGS_KEY) flags |= AOM_FRAME_IS_KEY;
Jingning Han's avatar
Jingning Han committed
897

Adrian Grange's avatar
Adrian Grange committed
898
  if (cpi->droppable) flags |= AOM_FRAME_IS_DROPPABLE;
Jingning Han's avatar
Jingning Han committed
899
900
901
902

  return flags;
}

Adrian Grange's avatar
Adrian Grange committed
903
904
905
static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx,
                                      const aom_image_t *img,
                                      aom_codec_pts_t pts,
Jingning Han's avatar
Jingning Han committed
906
                                      unsigned long duration,
Adrian Grange's avatar
Adrian Grange committed
907
                                      aom_enc_frame_flags_t flags,
Jingning Han's avatar
Jingning Han committed
908
                                      unsigned long deadline) {
Adrian Grange's avatar
Adrian Grange committed
909
  aom_codec_err_t res = AOM_CODEC_OK;
910
  AV1_COMP *const cpi = ctx->cpi;
Adrian Grange's avatar
Adrian Grange committed
911
  const aom_rational_t *const timebase = &ctx->cfg.g_timebase;
Jingning Han's avatar
Jingning Han committed
912
913
914
915
916
917
  size_t data_sz;

  if (img != NULL) {
    res = validate_img(ctx, img);
    // TODO(jzern) the checks related to cpi's validity should be treated as a
    // failure condition, encoder setup is done fully in init() currently.
Adrian Grange's avatar
Adrian Grange committed
918
    if (res == AOM_CODEC_OK && cpi != NULL) {
Jingning Han's avatar
Jingning Han committed
919
920
921
922
      // There's no codec control for multiple alt-refs so check the encoder
      // instance for its status to determine the compressed data size.
      data_sz = ctx->cfg.g_w * ctx->cfg.g_h * get_image_bps(img) / 8 *
                (cpi->multi_arf_allowed ? 8 : 2);
clang-format's avatar
clang-format committed
923
      if (data_sz < 4096) data_sz = 4096;
Jingning Han's avatar
Jingning Han committed
924
925
926
      if (ctx->cx_data == NULL || ctx->cx_data_sz < data_sz) {
        ctx->cx_data_sz = data_sz;
        free(ctx->cx_data);
clang-format's avatar
clang-format committed
927
        ctx->cx_data = (unsigned char *)malloc(ctx->cx_data_sz);
Jingning Han's avatar
Jingning Han committed
928
        if (ctx->cx_data == NULL) {
Adrian Grange's avatar
Adrian Grange committed
929
          return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
930
931
932
933
934
935
        }
      }
    }
  }

  pick_quickcompress_mode(ctx, duration, deadline);
Adrian Grange's avatar
Adrian Grange committed
936
  aom_codec_pkt_list_init(&ctx->pkt_list);
Jingning Han's avatar
Jingning Han committed
937
938

  // Handle Flags
Adrian Grange's avatar
Adrian Grange committed
939
940
  if (((flags & AOM_EFLAG_NO_UPD_GF) && (flags & AOM_EFLAG_FORCE_GF)) ||
      ((flags & AOM_EFLAG_NO_UPD_ARF) && (flags & AOM_EFLAG_FORCE_ARF))) {
Jingning Han's avatar
Jingning Han committed
941
    ctx->base.err_detail = "Conflicting flags.";
Adrian Grange's avatar
Adrian Grange committed
942
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
943
944
  }

945
  av1_apply_encoding_flags(cpi, flags);
Jingning Han's avatar
Jingning Han committed
946
947

  // Handle fixed keyframe intervals
Adrian Grange's avatar
Adrian Grange committed
948
  if (ctx->cfg.kf_mode == AOM_KF_AUTO &&
Jingning Han's avatar
Jingning Han committed
949
950
      ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) {
    if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) {
Adrian Grange's avatar
Adrian Grange committed
951
      flags |= AOM_EFLAG_FORCE_KF;
Jingning Han's avatar
Jingning Han committed
952
953
954
955
956
      ctx->fixed_kf_cntr = 1;
    }
  }

  // Initialize the encoder instance on the first frame.
Adrian Grange's avatar
Adrian Grange committed
957
  if (res == AOM_CODEC_OK && cpi != NULL) {
Jingning Han's avatar
Jingning Han committed
958
959
960
961
962
963
964
965
966
    unsigned int lib_flags = 0;
    YV12_BUFFER_CONFIG sd;
    int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
    int64_t dst_end_time_stamp =
        timebase_units_to_ticks(timebase, pts + duration);
    size_t size, cx_data_sz;
    unsigned char *cx_data;

    // Set up internal flags
Adrian Grange's avatar
Adrian Grange committed
967
    if (ctx->base.init_flags & AOM_CODEC_USE_PSNR) cpi->b_calculate_psnr = 1;
Jingning Han's avatar
Jingning Han committed