av1_cx_iface.c 49.8 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1
/*
Yaowu Xu's avatar
Yaowu Xu committed
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Jingning Han's avatar
Jingning Han committed
3
 *
Yaowu Xu's avatar
Yaowu Xu committed
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>

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

Yaowu Xu's avatar
Yaowu Xu committed
26
struct av1_extracfg {
27
28
  int cpu_used;  // available cpu percentage in 1/16
  unsigned int enable_auto_alt_ref;
29
#if CONFIG_EXT_REFS
30
  unsigned int enable_auto_bwd_ref;
31
#endif  // CONFIG_EXT_REFS
32
33
34
35
36
37
38
39
40
  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;
Yaowu Xu's avatar
Yaowu Xu committed
41
  aom_tune_metric tuning;
42
43
44
45
46
  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;
47
48
49
50
51
#if CONFIG_AOM_QM
  unsigned int enable_qm;
  unsigned int qm_min;
  unsigned int qm_max;
#endif
52
53
54
  unsigned int frame_parallel_decoding_mode;
  AQ_MODE aq_mode;
  unsigned int frame_periodic_boost;
Yaowu Xu's avatar
Yaowu Xu committed
55
56
57
  aom_bit_depth_t bit_depth;
  aom_tune_content content;
  aom_color_space_t color_space;
58
59
60
  int color_range;
  int render_width;
  int render_height;
Yaowu Xu's avatar
Yaowu Xu committed
61
  aom_superblock_size_t superblock_size;
Jingning Han's avatar
Jingning Han committed
62
63
};

Yaowu Xu's avatar
Yaowu Xu committed
64
static struct av1_extracfg default_extra_cfg = {
65
66
  0,  // cpu_used
  1,  // enable_auto_alt_ref
67
#if CONFIG_EXT_REFS
68
  0,    // enable_auto_bwd_ref
69
#endif  // CONFIG_EXT_REFS
70
71
72
  0,    // noise_sensitivity
  0,    // sharpness
  0,    // static_thresh
73
#if CONFIG_EXT_TILE
74
75
  UINT_MAX,  // tile_columns
  UINT_MAX,  // tile_rows
76
#else
77
78
  0,  // tile_columns
  0,  // tile_rows
79
80
81
82
83
#endif            // CONFIG_EXT_TILE
  7,              // arnr_max_frames
  5,              // arnr_strength
  0,              // min_gf_interval; 0 -> default decision
  0,              // max_gf_interval; 0 -> default decision
Yaowu Xu's avatar
Yaowu Xu committed
84
  AOM_TUNE_PSNR,  // tuning
85
86
87
88
89
90
91
92
93
94
  10,             // cq_level
  0,              // rc_max_intra_bitrate_pct
  0,              // rc_max_inter_bitrate_pct
  0,              // gf_cbr_boost_pct
  0,              // lossless
#if CONFIG_AOM_QM
  0,                 // enable_qm
  DEFAULT_QM_FIRST,  // qm_min
  DEFAULT_QM_LAST,   // qm_max
#endif
95
96
97
  1,                           // frame_parallel_decoding_mode
  NO_AQ,                       // aq_mode
  0,                           // frame_periodic_delta_q
Yaowu Xu's avatar
Yaowu Xu committed
98
99
100
  AOM_BITS_8,                  // Bit depth
  AOM_CONTENT_DEFAULT,         // content
  AOM_CS_UNKNOWN,              // color space
101
102
103
  0,                           // color range
  0,                           // render width
  0,                           // render height
Yaowu Xu's avatar
Yaowu Xu committed
104
  AOM_SUPERBLOCK_SIZE_DYNAMIC  // superblock_size
Jingning Han's avatar
Jingning Han committed
105
106
};

Yaowu Xu's avatar
Yaowu Xu committed
107
108
109
110
111
112
struct aom_codec_alg_priv {
  aom_codec_priv_t base;
  aom_codec_enc_cfg_t cfg;
  struct av1_extracfg extra_cfg;
  AV1EncoderConfig oxcf;
  AV1_COMP *cpi;
113
114
115
116
117
118
  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];
Yaowu Xu's avatar
Yaowu Xu committed
119
120
121
122
  aom_image_t preview_img;
  aom_enc_frame_flags_t next_frame_flags;
  aom_postproc_cfg_t preview_ppcfg;
  aom_codec_pkt_list_decl(256) pkt_list;
123
  unsigned int fixed_kf_cntr;
Jingning Han's avatar
Jingning Han committed
124
  // BufferPool that holds all reference frames.
125
  BufferPool *buffer_pool;
Jingning Han's avatar
Jingning Han committed
126
127
};

Yaowu Xu's avatar
Yaowu Xu 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

Yaowu Xu's avatar
Yaowu Xu 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
139
140
141
#define ERROR(str)                  \
  do {                              \
    ctx->base.err_detail = str;     \
Yaowu Xu's avatar
Yaowu Xu committed
142
    return AOM_CODEC_INVALID_PARAM; \
Jingning Han's avatar
Jingning Han committed
143
144
  } while (0)

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

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)

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)

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)

Yaowu Xu's avatar
Yaowu Xu committed
166
167
168
static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
                                       const aom_codec_enc_cfg_t *cfg,
                                       const struct av1_extracfg *extra_cfg) {
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);
178
  RANGE_CHECK(extra_cfg, aq_mode, 0, AQ_MODE_COUNT - 1);
179
  RANGE_CHECK_HI(extra_cfg, frame_periodic_boost, 1);
180
181
  RANGE_CHECK_HI(cfg, g_threads, 64);
  RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS);
Yaowu Xu's avatar
Yaowu Xu committed
182
  RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q);
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);
Yaowu Xu's avatar
Yaowu Xu committed
186
  RANGE_CHECK(cfg, kf_mode, AOM_KF_DISABLED, AOM_KF_AUTO);
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);
Yaowu Xu's avatar
Yaowu Xu committed
191
  RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_LAST_PASS);
192
193
  RANGE_CHECK_HI(extra_cfg, min_gf_interval, MAX_LAG_BUFFERS - 1);
  RANGE_CHECK_HI(extra_cfg, max_gf_interval, MAX_LAG_BUFFERS - 1);
Jingning Han's avatar
Jingning Han committed
194
195
196
197
198
  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,
199
                (MAX_LAG_BUFFERS - 1));
Jingning Han's avatar
Jingning Han committed
200
201
202
  }

  if (cfg->rc_resize_allowed == 1) {
203
204
    RANGE_CHECK_HI(cfg, rc_scaled_width, cfg->g_w);
    RANGE_CHECK_HI(cfg, rc_scaled_height, cfg->g_h);
Jingning Han's avatar
Jingning Han committed
205
206
  }

Yaowu Xu's avatar
Yaowu Xu committed
207
  // AV1 does not support a lower bound on the keyframe interval in
Jingning Han's avatar
Jingning Han committed
208
  // automatic keyframe placement mode.
Yaowu Xu's avatar
Yaowu Xu committed
209
  if (cfg->kf_mode != AOM_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist &&
Jingning Han's avatar
Jingning Han committed
210
      cfg->kf_min_dist > 0)
211
212
213
    ERROR(
        "kf_min_dist not supported in auto mode, use 0 "
        "or kf_max_dist instead.");
Jingning Han's avatar
Jingning Han committed
214

215
  RANGE_CHECK_HI(extra_cfg, enable_auto_alt_ref, 2);
216
#if CONFIG_EXT_REFS
217
  RANGE_CHECK_HI(extra_cfg, enable_auto_bwd_ref, 2);
218
#endif  // CONFIG_EXT_REFS
Jingning Han's avatar
Jingning Han committed
219
220
  RANGE_CHECK(extra_cfg, cpu_used, -8, 8);
  RANGE_CHECK_HI(extra_cfg, noise_sensitivity, 6);
Yaowu Xu's avatar
Yaowu Xu committed
221
222
  RANGE_CHECK(extra_cfg, superblock_size, AOM_SUPERBLOCK_SIZE_64X64,
              AOM_SUPERBLOCK_SIZE_DYNAMIC);
223
#if CONFIG_EXT_TILE
224
225
226
// TODO(any): Waring. If CONFIG_EXT_TILE is true, tile_columns really
// means tile_width, and tile_rows really means tile_hight. The interface
// should be sanitized.
227
#if CONFIG_EXT_PARTITION
Yaowu Xu's avatar
Yaowu Xu committed
228
  if (extra_cfg->superblock_size != AOM_SUPERBLOCK_SIZE_64X64) {
229
230
231
232
233
234
235
236
237
238
239
240
    if (extra_cfg->tile_columns != UINT_MAX)
      RANGE_CHECK(extra_cfg, tile_columns, 1, 32);
    if (extra_cfg->tile_rows != UINT_MAX)
      RANGE_CHECK(extra_cfg, tile_rows, 1, 32);
  } else
#endif  // CONFIG_EXT_PARTITION
  {
    if (extra_cfg->tile_columns != UINT_MAX)
      RANGE_CHECK(extra_cfg, tile_columns, 1, 64);
    if (extra_cfg->tile_rows != UINT_MAX)
      RANGE_CHECK(extra_cfg, tile_rows, 1, 64);
  }
241
#else
242
243
  RANGE_CHECK_HI(extra_cfg, tile_columns, 6);
  RANGE_CHECK_HI(extra_cfg, tile_rows, 2);
244
#endif  // CONFIG_EXT_TILE
Jingning Han's avatar
Jingning Han committed
245
  RANGE_CHECK_HI(extra_cfg, sharpness, 7);
246
  RANGE_CHECK_HI(extra_cfg, arnr_max_frames, 15);
Jingning Han's avatar
Jingning Han committed
247
  RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
248
  RANGE_CHECK_HI(extra_cfg, cq_level, 63);
Yaowu Xu's avatar
Yaowu Xu committed
249
  RANGE_CHECK(cfg, g_bit_depth, AOM_BITS_8, AOM_BITS_12);
Jingning Han's avatar
Jingning Han committed
250
  RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
Yaowu Xu's avatar
Yaowu Xu committed
251
  RANGE_CHECK(extra_cfg, content, AOM_CONTENT_DEFAULT, AOM_CONTENT_INVALID - 1);
Jingning Han's avatar
Jingning Han committed
252

Yaowu Xu's avatar
Yaowu Xu committed
253
254
255
  // TODO(yaowu): remove this when ssim tuning is implemented for av1
  if (extra_cfg->tuning == AOM_TUNE_SSIM)
    ERROR("Option --tune=ssim is not currently supported in AV1.");
Jingning Han's avatar
Jingning Han committed
256

Yaowu Xu's avatar
Yaowu Xu committed
257
  if (cfg->g_pass == AOM_RC_LAST_PASS) {
Jingning Han's avatar
Jingning Han committed
258
259
260
261
262
263
264
265
266
267
    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
268
269
    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
270

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

Yunqing Wang's avatar
Yunqing Wang committed
274
275
    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
276
277
  }

Yaowu Xu's avatar
Yaowu Xu committed
278
#if !CONFIG_AOM_HIGHBITDEPTH
Jingning Han's avatar
Jingning Han committed
279
280
281
282
283
  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 &&
Yaowu Xu's avatar
Yaowu Xu committed
284
      cfg->g_bit_depth > AOM_BITS_8) {
Jingning Han's avatar
Jingning Han committed
285
286
    ERROR("Codec high bit-depth not supported in profile < 2");
  }
287
  if (cfg->g_profile <= (unsigned int)PROFILE_1 && cfg->g_input_bit_depth > 8) {
Jingning Han's avatar
Jingning Han committed
288
289
290
    ERROR("Source high bit-depth not supported in profile < 2");
  }
  if (cfg->g_profile > (unsigned int)PROFILE_1 &&
Yaowu Xu's avatar
Yaowu Xu committed
291
      cfg->g_bit_depth == AOM_BITS_8) {
Jingning Han's avatar
Jingning Han committed
292
293
    ERROR("Codec bit-depth 8 not supported in profile > 1");
  }
Yaowu Xu's avatar
Yaowu Xu committed
294
  RANGE_CHECK(extra_cfg, color_space, AOM_CS_UNKNOWN, AOM_CS_SRGB);
295
  RANGE_CHECK(extra_cfg, color_range, 0, 1);
Yaowu Xu's avatar
Yaowu Xu committed
296
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
297
298
}

Yaowu Xu's avatar
Yaowu Xu committed
299
300
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
301
  switch (img->fmt) {
Yaowu Xu's avatar
Yaowu Xu committed
302
303
304
305
306
307
    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
308
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1) {
309
310
311
        ERROR(
            "Invalid image format. I422, I444, I440 images are "
            "not supported in profile.");
Jingning Han's avatar
Jingning Han committed
312
313
      }
      break;
Yaowu Xu's avatar
Yaowu Xu committed
314
315
316
    case AOM_IMG_FMT_I42216:
    case AOM_IMG_FMT_I44416:
    case AOM_IMG_FMT_I44016:
Jingning Han's avatar
Jingning Han committed
317
318
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1 &&
          ctx->cfg.g_profile != (unsigned int)PROFILE_3) {
319
320
321
        ERROR(
            "Invalid image format. 16-bit I422, I444, I440 images are "
            "not supported in profile.");
Jingning Han's avatar
Jingning Han committed
322
323
324
      }
      break;
    default:
325
326
327
      ERROR(
          "Invalid image format. Only YV12, I420, I422, I444 images are "
          "supported.");
Jingning Han's avatar
Jingning Han committed
328
329
330
331
332
333
      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");

Yaowu Xu's avatar
Yaowu Xu committed
334
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
335
336
}

Yaowu Xu's avatar
Yaowu Xu committed
337
static int get_image_bps(const aom_image_t *img) {
Jingning Han's avatar
Jingning Han committed
338
  switch (img->fmt) {
Yaowu Xu's avatar
Yaowu Xu committed
339
340
341
342
343
344
345
346
347
    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
348
349
350
351
352
    default: assert(0 && "Invalid image format"); break;
  }
  return 0;
}

Yaowu Xu's avatar
Yaowu Xu committed
353
354
355
356
static aom_codec_err_t set_encoder_config(
    AV1EncoderConfig *oxcf, const aom_codec_enc_cfg_t *cfg,
    const struct av1_extracfg *extra_cfg) {
  const int is_vbr = cfg->rc_end_usage == AOM_VBR;
Jingning Han's avatar
Jingning Han committed
357
358
  oxcf->profile = cfg->g_profile;
  oxcf->max_threads = (int)cfg->g_threads;
359
360
  oxcf->width = cfg->g_w;
  oxcf->height = cfg->g_h;
Jingning Han's avatar
Jingning Han committed
361
362
363
364
  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;
365
  if (oxcf->init_framerate > 180) oxcf->init_framerate = 30;
Jingning Han's avatar
Jingning Han committed
366
367
368
369

  oxcf->mode = GOOD;

  switch (cfg->g_pass) {
Yaowu Xu's avatar
Yaowu Xu committed
370
371
372
    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
373
374
  }

375
  oxcf->lag_in_frames =
Yaowu Xu's avatar
Yaowu Xu committed
376
      cfg->g_pass == AOM_RC_FIRST_PASS ? 0 : cfg->g_lag_in_frames;
Jingning Han's avatar
Jingning Han committed
377
378
379
380
381
382
383
384
385
  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 =
Yaowu Xu's avatar
Yaowu Xu committed
386
      extra_cfg->lossless ? 0 : av1_quantizer_to_qindex(cfg->rc_min_quantizer);
Jingning Han's avatar
Jingning Han committed
387
  oxcf->worst_allowed_q =
Yaowu Xu's avatar
Yaowu Xu committed
388
389
      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
390
391
  oxcf->fixed_q = -1;

392
393
394
395
396
397
#if CONFIG_AOM_QM
  oxcf->using_qm = extra_cfg->enable_qm;
  oxcf->qm_minlevel = extra_cfg->qm_min;
  oxcf->qm_maxlevel = extra_cfg->qm_max;
#endif

398
399
  oxcf->under_shoot_pct = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct = cfg->rc_overshoot_pct;
Jingning Han's avatar
Jingning Han committed
400

401
  oxcf->scaled_frame_width = cfg->rc_scaled_width;
Jingning Han's avatar
Jingning Han committed
402
403
404
  oxcf->scaled_frame_height = cfg->rc_scaled_height;
  if (cfg->rc_resize_allowed == 1) {
    oxcf->resize_mode =
405
406
407
        (oxcf->scaled_frame_width == 0 || oxcf->scaled_frame_height == 0)
            ? RESIZE_DYNAMIC
            : RESIZE_FIXED;
Jingning Han's avatar
Jingning Han committed
408
409
410
411
  } else {
    oxcf->resize_mode = RESIZE_NONE;
  }

412
  oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz;
Jingning Han's avatar
Jingning Han committed
413
  oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
414
  oxcf->optimal_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
Jingning Han's avatar
Jingning Han committed
415

416
  oxcf->drop_frames_water_mark = cfg->rc_dropframe_thresh;
Jingning Han's avatar
Jingning Han committed
417

418
419
420
  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
421

422
  oxcf->auto_key =
Yaowu Xu's avatar
Yaowu Xu committed
423
      cfg->kf_mode == AOM_KF_AUTO && cfg->kf_min_dist != cfg->kf_max_dist;
Jingning Han's avatar
Jingning Han committed
424

425
  oxcf->key_freq = cfg->kf_max_dist;
Jingning Han's avatar
Jingning Han committed
426

427
428
  oxcf->speed = abs(extra_cfg->cpu_used);
  oxcf->enable_auto_arf = extra_cfg->enable_auto_alt_ref;
429
#if CONFIG_EXT_REFS
430
  oxcf->enable_auto_brf = extra_cfg->enable_auto_bwd_ref;
431
#endif  // CONFIG_EXT_REFS
432
433
  oxcf->noise_sensitivity = extra_cfg->noise_sensitivity;
  oxcf->sharpness = extra_cfg->sharpness;
Jingning Han's avatar
Jingning Han committed
434

435
  oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in;
Jingning Han's avatar
Jingning Han committed
436
437

#if CONFIG_FP_MB_STATS
438
  oxcf->firstpass_mb_stats_in = cfg->rc_firstpass_mb_stats_in;
Jingning Han's avatar
Jingning Han committed
439
440
441
#endif

  oxcf->color_space = extra_cfg->color_space;
442
  oxcf->color_range = extra_cfg->color_range;
443
  oxcf->render_width = extra_cfg->render_width;
444
  oxcf->render_height = extra_cfg->render_height;
Jingning Han's avatar
Jingning Han committed
445
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
446
  oxcf->arnr_strength = extra_cfg->arnr_strength;
Jingning Han's avatar
Jingning Han committed
447
448
449
450
451
452
  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;

453
454
455
456
457
458
459
460
#if CONFIG_EXT_PARTITION
  oxcf->superblock_size = extra_cfg->superblock_size;
#endif  // CONFIG_EXT_PARTITION

#if CONFIG_EXT_TILE
  {
#if CONFIG_EXT_PARTITION
    const unsigned int max =
Yaowu Xu's avatar
Yaowu Xu committed
461
        extra_cfg->superblock_size == AOM_SUPERBLOCK_SIZE_64X64 ? 64 : 32;
462
463
464
#else
    const unsigned int max = 64;
#endif  // CONFIG_EXT_PARTITION
Yaowu Xu's avatar
Yaowu Xu committed
465
466
    oxcf->tile_columns = AOMMIN(extra_cfg->tile_columns, max);
    oxcf->tile_rows = AOMMIN(extra_cfg->tile_rows, max);
467
468
  }
#else
Jingning Han's avatar
Jingning Han committed
469
  oxcf->tile_columns = extra_cfg->tile_columns;
470
  oxcf->tile_rows = extra_cfg->tile_rows;
471
#endif  // CONFIG_EXT_TILE
Jingning Han's avatar
Jingning Han committed
472

473
  oxcf->error_resilient_mode = cfg->g_error_resilient;
Jingning Han's avatar
Jingning Han committed
474
475
476
477
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;

  oxcf->aq_mode = extra_cfg->aq_mode;

478
  oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
Jingning Han's avatar
Jingning Han committed
479
480

  /*
Yaowu Xu's avatar
Yaowu Xu committed
481
  printf("Current AV1 Settings: \n");
Jingning Han's avatar
Jingning Han committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  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("error resilient: %d\n", oxcf->error_resilient_mode);
  printf("frame parallel detokenization: %d\n",
         oxcf->frame_parallel_decoding_mode);
  */
Yaowu Xu's avatar
Yaowu Xu committed
511
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
512
513
}

Yaowu Xu's avatar
Yaowu Xu committed
514
515
516
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
517
518
519
  int force_key = 0;

  if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
Yaowu Xu's avatar
Yaowu Xu committed
520
    if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS)
Jingning Han's avatar
Jingning Han committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
      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);

Yaowu Xu's avatar
Yaowu Xu committed
537
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
538
539
540
541
    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;
Yaowu Xu's avatar
Yaowu Xu committed
542
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
543
544
  }

Yaowu Xu's avatar
Yaowu Xu committed
545
  if (force_key) ctx->next_frame_flags |= AOM_EFLAG_FORCE_KF;
Jingning Han's avatar
Jingning Han committed
546
547
548
549

  return res;
}

Yaowu Xu's avatar
Yaowu Xu committed
550
static aom_codec_err_t ctrl_get_quantizer(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
551
552
                                          va_list args) {
  int *const arg = va_arg(args, int *);
Yaowu Xu's avatar
Yaowu Xu committed
553
554
555
  if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
  *arg = av1_get_quantizer(ctx->cpi);
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
556
557
}

Yaowu Xu's avatar
Yaowu Xu committed
558
static aom_codec_err_t ctrl_get_quantizer64(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
559
560
                                            va_list args) {
  int *const arg = va_arg(args, int *);
Yaowu Xu's avatar
Yaowu Xu committed
561
562
563
  if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
  *arg = av1_qindex_to_quantizer(av1_get_quantizer(ctx->cpi));
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
564
565
}

Yaowu Xu's avatar
Yaowu Xu committed
566
567
568
569
static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx,
                                        const struct av1_extracfg *extra_cfg) {
  const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
570
571
    ctx->extra_cfg = *extra_cfg;
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
Yaowu Xu's avatar
Yaowu Xu committed
572
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
573
574
575
576
  }
  return res;
}

Yaowu Xu's avatar
Yaowu Xu committed
577
static aom_codec_err_t ctrl_set_cpuused(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
578
                                        va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
579
580
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.cpu_used = CAST(AOME_SET_CPUUSED, args);
Jingning Han's avatar
Jingning Han committed
581
582
583
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
584
static aom_codec_err_t ctrl_set_enable_auto_alt_ref(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
585
                                                    va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
586
587
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.enable_auto_alt_ref = CAST(AOME_SET_ENABLEAUTOALTREF, args);
Jingning Han's avatar
Jingning Han committed
588
589
590
  return update_extra_cfg(ctx, &extra_cfg);
}

591
#if CONFIG_EXT_REFS
Yaowu Xu's avatar
Yaowu Xu committed
592
static aom_codec_err_t ctrl_set_enable_auto_bwd_ref(aom_codec_alg_priv_t *ctx,
593
                                                    va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
594
595
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.enable_auto_bwd_ref = CAST(AOME_SET_ENABLEAUTOBWDREF, args);
596
597
  return update_extra_cfg(ctx, &extra_cfg);
}
598
#endif  // CONFIG_EXT_REFS
599

Yaowu Xu's avatar
Yaowu Xu committed
600
static aom_codec_err_t ctrl_set_noise_sensitivity(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
601
                                                  va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
602
603
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.noise_sensitivity = CAST(AV1E_SET_NOISE_SENSITIVITY, args);
Jingning Han's avatar
Jingning Han committed
604
605
606
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
607
static aom_codec_err_t ctrl_set_sharpness(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
608
                                          va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
609
610
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.sharpness = CAST(AOME_SET_SHARPNESS, args);
Jingning Han's avatar
Jingning Han committed
611
612
613
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
614
static aom_codec_err_t ctrl_set_static_thresh(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
615
                                              va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
616
617
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.static_thresh = CAST(AOME_SET_STATIC_THRESHOLD, args);
Jingning Han's avatar
Jingning Han committed
618
619
620
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
621
static aom_codec_err_t ctrl_set_tile_columns(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
622
                                             va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
623
624
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tile_columns = CAST(AV1E_SET_TILE_COLUMNS, args);
Jingning Han's avatar
Jingning Han committed
625
626
627
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
628
static aom_codec_err_t ctrl_set_tile_rows(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
629
                                          va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
630
631
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tile_rows = CAST(AV1E_SET_TILE_ROWS, args);
Jingning Han's avatar
Jingning Han committed
632
633
634
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
635
static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
636
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
637
638
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.arnr_max_frames = CAST(AOME_SET_ARNR_MAXFRAMES, args);
Jingning Han's avatar
Jingning Han committed
639
640
641
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
642
static aom_codec_err_t ctrl_set_arnr_strength(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
643
                                              va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
644
645
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.arnr_strength = CAST(AOME_SET_ARNR_STRENGTH, args);
Jingning Han's avatar
Jingning Han committed
646
647
648
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
649
static aom_codec_err_t ctrl_set_arnr_type(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
650
651
652
                                          va_list args) {
  (void)ctx;
  (void)args;
Yaowu Xu's avatar
Yaowu Xu committed
653
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
654
655
}

Yaowu Xu's avatar
Yaowu Xu committed
656
static aom_codec_err_t ctrl_set_tuning(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
657
                                       va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
658
659
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tuning = CAST(AOME_SET_TUNING, args);
Jingning Han's avatar
Jingning Han committed
660
661
662
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
663
static aom_codec_err_t ctrl_set_cq_level(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
664
                                         va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
665
666
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.cq_level = CAST(AOME_SET_CQ_LEVEL, args);
Jingning Han's avatar
Jingning Han committed
667
668
669
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
670
671
672
static aom_codec_err_t ctrl_set_rc_max_intra_bitrate_pct(
    aom_codec_alg_priv_t *ctx, va_list args) {
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
673
  extra_cfg.rc_max_intra_bitrate_pct =
Yaowu Xu's avatar
Yaowu Xu committed
674
      CAST(AOME_SET_MAX_INTRA_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
675
676
677
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
678
679
680
static aom_codec_err_t ctrl_set_rc_max_inter_bitrate_pct(
    aom_codec_alg_priv_t *ctx, va_list args) {
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
681
  extra_cfg.rc_max_inter_bitrate_pct =
Yaowu Xu's avatar
Yaowu Xu committed
682
      CAST(AOME_SET_MAX_INTER_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
683
684
685
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
686
static aom_codec_err_t ctrl_set_rc_gf_cbr_boost_pct(aom_codec_alg_priv_t *ctx,
687
                                                    va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
688
689
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.gf_cbr_boost_pct = CAST(AV1E_SET_GF_CBR_BOOST_PCT, args);
Jingning Han's avatar
Jingning Han committed
690
691
692
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
693
static aom_codec_err_t ctrl_set_lossless(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
694
                                         va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
695
696
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.lossless = CAST(AV1E_SET_LOSSLESS, args);
Jingning Han's avatar
Jingning Han committed
697
698
699
  return update_extra_cfg(ctx, &extra_cfg);
}

700
#if CONFIG_AOM_QM
Yaowu Xu's avatar
Yaowu Xu committed
701
static aom_codec_err_t ctrl_set_enable_qm(aom_codec_alg_priv_t *ctx,
702
                                          va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
703
704
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.enable_qm = CAST(AV1E_SET_ENABLE_QM, args);
705
706
707
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
708
static aom_codec_err_t ctrl_set_qm_min(aom_codec_alg_priv_t *ctx,
709
                                       va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
710
711
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.qm_min = CAST(AV1E_SET_QM_MIN, args);
712
713
714
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
715
static aom_codec_err_t ctrl_set_qm_max(aom_codec_alg_priv_t *ctx,
716
                                       va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
717
718
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.qm_max = CAST(AV1E_SET_QM_MAX, args);
719
720
721
722
  return update_extra_cfg(ctx, &extra_cfg);
}
#endif

Yaowu Xu's avatar
Yaowu Xu committed
723
724
725
static aom_codec_err_t ctrl_set_frame_parallel_decoding_mode(
    aom_codec_alg_priv_t *ctx, va_list args) {
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
Jingning Han's avatar
Jingning Han committed
726
  extra_cfg.frame_parallel_decoding_mode =
Yaowu Xu's avatar
Yaowu Xu committed
727
      CAST(AV1E_SET_FRAME_PARALLEL_DECODING, args);
Jingning Han's avatar
Jingning Han committed
728
729
730
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
731
static aom_codec_err_t ctrl_set_aq_mode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
732
                                        va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
733
734
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.aq_mode = CAST(AV1E_SET_AQ_MODE, args);
Jingning Han's avatar
Jingning Han committed
735
736
737
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
738
static aom_codec_err_t ctrl_set_min_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
739
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
740
741
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.min_gf_interval = CAST(AV1E_SET_MIN_GF_INTERVAL, args);
Jingning Han's avatar
Jingning Han committed
742
743
744
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
745
static aom_codec_err_t ctrl_set_max_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
746
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
747
748
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.max_gf_interval = CAST(AV1E_SET_MAX_GF_INTERVAL, args);
Jingning Han's avatar
Jingning Han committed
749
750
751
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
752
static aom_codec_err_t ctrl_set_frame_periodic_boost(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
753
                                                     va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
754
755
  struct av1_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.frame_periodic_boost = CAST(AV1E_SET_FRAME_PERIODIC_BOOST, args);
Jingning Han's avatar
Jingning Han committed
756
757
758
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
759
760
761
static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx,
                                    aom_codec_priv_enc_mr_cfg_t *data) {
  aom_codec_err_t res = AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
762
763
764
  (void)data;

  if (ctx->priv == NULL) {
Yaowu Xu's avatar
Yaowu Xu committed
765
766
    aom_codec_alg_priv_t *const priv = aom_calloc(1, sizeof(*priv));
    if (priv == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
767

Yaowu Xu's avatar
Yaowu Xu committed
768
    ctx->priv = (aom_codec_priv_t *)priv;
Jingning Han's avatar
Jingning Han committed
769
770
    ctx->priv->init_flags = ctx->init_flags;
    ctx->priv->enc.total_encoders = 1;
Yaowu Xu's avatar
Yaowu Xu committed
771
772
    priv->buffer_pool = (BufferPool *)aom_calloc(1, sizeof(BufferPool));
    if (priv->buffer_pool == NULL) return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
773
774
775

#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&priv->buffer_pool->pool_mutex, NULL)) {
Yaowu Xu's avatar
Yaowu Xu committed
776
      return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
777
778
779
780
781
782
783
784
785
786
    }
#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;
Yaowu Xu's avatar
Yaowu Xu committed
787
    once(av1_initialize_enc);
Jingning Han's avatar
Jingning Han committed
788
789
790

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

Yaowu Xu's avatar
Yaowu Xu committed
791
    if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
792
      set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
Yaowu Xu's avatar
Yaowu Xu committed
793
#if CONFIG_AOM_HIGHBITDEPTH
Jingning Han's avatar
Jingning Han committed
794
      priv->oxcf.use_highbitdepth =
Yaowu Xu's avatar
Yaowu Xu committed
795
          (ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) ? 1 : 0;
Jingning Han's avatar
Jingning Han committed
796
#endif
Yaowu Xu's avatar
Yaowu Xu committed
797
      priv->cpi = av1_create_compressor(&priv->oxcf, priv->buffer_pool);
Jingning Han's avatar
Jingning Han committed
798
      if (priv->cpi == NULL)
Yaowu Xu's avatar
Yaowu Xu committed
799
        res = AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
800
801
802
803
804
805
806
807
      else
        priv->cpi->output_pkt_list = &priv->pkt_list.head;
    }
  }

  return res;
}

Yaowu Xu's avatar
Yaowu Xu committed
808
static aom_codec_err_t encoder_destroy(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
809
  free(ctx->cx_data);
Yaowu Xu's avatar
Yaowu Xu committed
810
  av1_remove_compressor(ctx->cpi);
Jingning Han's avatar
Jingning Han committed
811
812
813
#if CONFIG_MULTITHREAD
  pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
#endif
Yaowu Xu's avatar
Yaowu Xu committed
814
815
816
  aom_free(ctx->buffer_pool);
  aom_free(ctx);
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
817
818
}

Yaowu Xu's avatar
Yaowu Xu committed
819
static void pick_quickcompress_mode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
820
821
822
823
                                    unsigned long deadline) {
  MODE new_mode = BEST;

  switch (ctx->cfg.g_pass) {
Yaowu Xu's avatar
Yaowu Xu committed
824
    case AOM_RC_ONE_PASS:
825
826
827
828
      switch (deadline) {
        case AOM_DL_BEST_QUALITY: new_mode = BEST; break;
        case AOM_DL_REALTIME: new_mode = REALTIME; break;
        default: new_mode = GOOD; break;
Jingning Han's avatar
Jingning Han committed
829
830
      }
      break;
Yaowu Xu's avatar
Yaowu Xu committed
831
832
    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
833
834
835
836
  }

  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
Yaowu Xu's avatar
Yaowu Xu committed
837
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
838
839
840
841
842
  }
}

// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
Yaowu Xu's avatar
Yaowu Xu committed
843
static int write_superframe_index(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
844
845
846
  uint8_t marker = 0xc0;
  unsigned int mask;
  int mag, index_sz;
847
848
  int i;
  size_t max_frame_sz = 0;
Jingning Han's avatar
Jingning Han committed
849
850
851
852
853
854

  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;
855
  for (i = 0; i < ctx->pending_frame_count - 1; i++) {
856
    const size_t frame_sz = (unsigned int)ctx->pending_frame_sizes[i] - 1;
857
858
    max_frame_sz = frame_sz > max_frame_sz ? frame_sz : max_frame_sz;
  }
Jingning Han's avatar
Jingning Han committed
859
860
861

  // Choose the magnitude
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
862
    if (max_frame_sz <= mask) break;
Jingning Han's avatar
Jingning Han committed
863
864
865
866
867
868
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

  // Write the index
hui su's avatar
hui su committed
869
  index_sz = 2 + (mag + 1) * (ctx->pending_frame_count - 1);
Jingning Han's avatar
Jingning Han committed
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  if (ctx->pending_cx_data_sz + index_sz < ctx->cx_data_sz) {
    uint8_t *x = ctx->pending_cx_data + ctx->pending_cx_data_sz;
#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;
hui su's avatar
hui su committed
888
    for (i = 0; i < ctx->pending_frame_count - 1; i++) {
889
      unsigned int this_sz;
890
      int j;
Jingning Han's avatar
Jingning Han committed
891

892
      assert(ctx->pending_frame_sizes[i] > 0);
hui su's avatar
hui su committed
893
      this_sz = (unsigned int)ctx->pending_frame_sizes[i] - 1;
Jingning Han's avatar
Jingning Han committed
894
895
896
897
898
899
900
901
902
903
904
905
906
907
      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;
}

Yaowu Xu's avatar
Yaowu Xu committed
908
// av1 uses 10,000,000 ticks/second as time stamp
Jingning Han's avatar
Jingning Han committed
909
910
#define TICKS_PER_SEC 10000000LL

Yaowu Xu's avatar
Yaowu Xu committed
911
static int64_t timebase_units_to_ticks(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
912
913
914
915
                                       int64_t n) {
  return n * TICKS_PER_SEC * timebase->num / timebase->den;
}

Yaowu Xu's avatar
Yaowu Xu committed
916
static int64_t ticks_to_timebase_units(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
917
918
919
920
921
                                       int64_t n) {
  const int64_t round = TICKS_PER_SEC * timebase->num / 2 - 1;
  return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC;
}

Yaowu Xu's avatar
Yaowu Xu committed
922
static aom_codec_frame_flags_t get_frame_pkt_flags(const AV1_COMP *cpi,
Jingning Han's avatar
Jingning Han committed
923
                                                   unsigned int lib_flags) {
Yaowu Xu's avatar
Yaowu Xu committed
924
  aom_codec_frame_flags_t flags = lib_flags << 16;
Jingning Han's avatar
Jingning Han committed
925

Yaowu Xu's avatar
Yaowu Xu committed
926
  if (lib_flags & FRAMEFLAGS_KEY) flags |= AOM_FRAME_IS_KEY;
Jingning Han's avatar
Jingning Han committed
927

Yaowu Xu's avatar
Yaowu Xu committed
928
  if (cpi->droppable) flags |= AOM_FRAME_IS_DROPPABLE;
Jingning Han's avatar
Jingning Han committed
929
930
931
932

  return flags;
}

933
const size_t kMinCompressedSize = 8192;
Yaowu Xu's avatar
Yaowu Xu committed
934
935
936
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
937
                                      unsigned long duration,
Yaowu Xu's avatar
Yaowu Xu committed
938
                                      aom_enc_frame_flags_t enc_flags,
Jingning Han's avatar
Jingning Han committed
939
                                      unsigned long deadline) {
Yaowu Xu's avatar
Yaowu Xu committed
940
941
942
943
  volatile aom_codec_err_t res = AOM_CODEC_OK;
  volatile aom_enc_frame_flags_t flags = enc_flags;
  AV1_COMP *const cpi = ctx->cpi;
  const aom_rational_t *const timebase = &ctx->cfg.g_timebase;
Jingning Han's avatar
Jingning Han committed
944
945
  size_t data_sz;

Yaowu Xu's avatar
Yaowu Xu committed
946
  if (cpi == NULL) return AOM_CODEC_INVALID_PARAM;
947

Jingning Han's avatar
Jingning Han committed
948
949
950
951
  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.
Yaowu Xu's avatar
Yaowu Xu committed
952
    if (res == AOM_CODEC_OK) {
953
#if CONFIG_EXT_REFS
954
955
      data_sz = ALIGN_POWER_OF_TWO(ctx->cfg.g_w, 5) *
                ALIGN_POWER_OF_TWO(ctx->cfg.g_h, 5) * get_image_bps(img);
956
#else
957
958
      // There's no codec control for multiple alt-refs so check the encoder
      // instance for its status to determine the compressed data size.
959
960
      data_sz = ALIGN_POWER_OF_TWO(ctx->cfg.g_w, 5) *
                ALIGN_POWER_OF_TWO(ctx->cfg.g_h, 5) * get_image_bps(img) / 8 *
Jingning Han's avatar
Jingning Han committed
961
                (cpi->multi_arf_allowed ? 8 : 2);
962
#endif  // CONFIG_EXT_REFS
963
      if (data_sz < kMinCompressedSize) data_sz = kMinCompressedSize;
Jingning Han's avatar
Jingning Han committed
964
965
966
      if (ctx->cx_data == NULL || ctx->cx_data_sz < data_sz) {
        ctx->cx_data_sz = data_sz;
        free(ctx->cx_data);
967
        ctx->cx_data = (unsigned char *)malloc(ctx->cx_data_sz);
Jingning Han's avatar
Jingning Han committed
968
        if (ctx->cx_data == NULL) {
Yaowu Xu's avatar
Yaowu Xu committed
969
          return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
970
971
972
973
974
        }
      }
    }
  }

975
  pick_quickcompress_mode(ctx, deadline);
Yaowu Xu's avatar
Yaowu Xu committed
976
  aom_codec_pkt_list_init(&ctx->pkt_list);
Jingning Han's avatar
Jingning Han committed
977
978

  // Handle Flags
Yaowu Xu's avatar
Yaowu Xu committed
979
980
  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
981
    ctx->base.err_detail = "Conflicting flags.";
Yaowu Xu's avatar
Yaowu Xu committed
982
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
983
984
  }

James Zern's avatar
James Zern committed
985
986
987
  if (setjmp(cpi->common.error.jmp)) {
    cpi->common.error.setjmp = 0;
    res = update_error_state(ctx, &cpi->common