av1_cx_iface.c 50 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

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

Yaowu Xu's avatar
Yaowu Xu committed
14 15 16
#include "./aom_config.h"
#include "aom/aom_encoder.h"
#include "aom_ports/aom_once.h"
17
#include "aom_ports/system_state.h"
Yaowu Xu's avatar
Yaowu Xu committed
18 19
#include "aom/internal/aom_codec_internal.h"
#include "./aom_version.h"
20
#include "av1/encoder/encoder.h"
Yaowu Xu's avatar
Yaowu Xu committed
21
#include "aom/aomcx.h"
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

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

Yaowu Xu's avatar
Yaowu Xu committed
63
static struct av1_extracfg default_extra_cfg = {
64 65
  0,  // cpu_used
  1,  // enable_auto_alt_ref
66
#if CONFIG_EXT_REFS
67
  0,    // enable_auto_bwd_ref
68
#endif  // CONFIG_EXT_REFS
69 70 71
  0,    // noise_sensitivity
  0,    // sharpness
  0,    // static_thresh
72
#if CONFIG_EXT_TILE
73 74
  UINT_MAX,  // tile_columns
  UINT_MAX,  // tile_rows
75
#else
76 77
  0,  // tile_columns
  0,  // tile_rows
78 79 80 81 82
#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
83
  AOM_TUNE_PSNR,  // tuning
84 85 86 87 88 89 90 91 92 93
  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
94 95 96
  1,                           // frame_parallel_decoding_mode
  NO_AQ,                       // aq_mode
  0,                           // frame_periodic_delta_q
Yaowu Xu's avatar
Yaowu Xu committed
97 98 99
  AOM_BITS_8,                  // Bit depth
  AOM_CONTENT_DEFAULT,         // content
  AOM_CS_UNKNOWN,              // color space
100 101 102
  0,                           // color range
  0,                           // render width
  0,                           // render height
Yaowu Xu's avatar
Yaowu Xu committed
103
  AOM_SUPERBLOCK_SIZE_DYNAMIC  // superblock_size
Jingning Han's avatar
Jingning Han committed
104 105
};

Yaowu Xu's avatar
Yaowu Xu committed
106 107 108 109 110 111
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;
112 113 114 115 116 117
  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
118 119 120 121
  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;
122
  unsigned int fixed_kf_cntr;
Jingning Han's avatar
Jingning Han committed
123
  // BufferPool that holds all reference frames.
124
  BufferPool *buffer_pool;
Jingning Han's avatar
Jingning Han committed
125 126
};

Yaowu Xu's avatar
Yaowu Xu committed
127 128 129
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
130

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

  return res;
}

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

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

150 151 152
#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
153 154
  } while (0)

155 156 157
#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
158 159
  } while (0)

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

Yaowu Xu's avatar
Yaowu Xu committed
165 166 167
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) {
168 169 170 171 172 173 174 175
  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
176
  RANGE_CHECK_BOOL(extra_cfg, lossless);
177
  RANGE_CHECK(extra_cfg, aq_mode, 0, AQ_MODE_COUNT - 1);
Jingning Han's avatar
Jingning Han committed
178
  RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
179 180
  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
181
  RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q);
182 183
  RANGE_CHECK_HI(cfg, rc_undershoot_pct, 100);
  RANGE_CHECK_HI(cfg, rc_overshoot_pct, 100);
Jingning Han's avatar
Jingning Han committed
184
  RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
Yaowu Xu's avatar
Yaowu Xu committed
185
  RANGE_CHECK(cfg, kf_mode, AOM_KF_DISABLED, AOM_KF_AUTO);
186 187 188
  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
189
  RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
Yaowu Xu's avatar
Yaowu Xu committed
190
  RANGE_CHECK(cfg, g_pass, AOM_RC_ONE_PASS, AOM_RC_LAST_PASS);
Jingning Han's avatar
Jingning Han committed
191 192 193 194 195 196 197
  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,
198
                (MAX_LAG_BUFFERS - 1));
Jingning Han's avatar
Jingning Han committed
199 200 201 202 203 204 205
  }

  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);
  }

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

  RANGE_CHECK(extra_cfg, enable_auto_alt_ref, 0, 2);
215
#if CONFIG_EXT_REFS
216
  RANGE_CHECK(extra_cfg, enable_auto_bwd_ref, 0, 2);
217
#endif  // CONFIG_EXT_REFS
Jingning Han's avatar
Jingning Han committed
218 219
  RANGE_CHECK(extra_cfg, cpu_used, -8, 8);
  RANGE_CHECK_HI(extra_cfg, noise_sensitivity, 6);
Yaowu Xu's avatar
Yaowu Xu committed
220 221
  RANGE_CHECK(extra_cfg, superblock_size, AOM_SUPERBLOCK_SIZE_64X64,
              AOM_SUPERBLOCK_SIZE_DYNAMIC);
222
#if CONFIG_EXT_TILE
223 224 225
// 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.
226
#if CONFIG_EXT_PARTITION
Yaowu Xu's avatar
Yaowu Xu committed
227
  if (extra_cfg->superblock_size != AOM_SUPERBLOCK_SIZE_64X64) {
228 229 230 231 232 233 234 235 236 237 238 239
    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);
  }
240
#else
Jingning Han's avatar
Jingning Han committed
241 242
  RANGE_CHECK(extra_cfg, tile_columns, 0, 6);
  RANGE_CHECK(extra_cfg, tile_rows, 0, 2);
243
#endif  // CONFIG_EXT_TILE
Jingning Han's avatar
Jingning Han committed
244 245 246 247
  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);
Yaowu Xu's avatar
Yaowu Xu committed
248
  RANGE_CHECK(cfg, g_bit_depth, AOM_BITS_8, AOM_BITS_12);
Jingning Han's avatar
Jingning Han committed
249
  RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
Yaowu Xu's avatar
Yaowu Xu committed
250
  RANGE_CHECK(extra_cfg, content, AOM_CONTENT_DEFAULT, AOM_CONTENT_INVALID - 1);
Jingning Han's avatar
Jingning Han committed
251

Yaowu Xu's avatar
Yaowu Xu committed
252 253 254
  // 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
255

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

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

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

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

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

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

Yaowu Xu's avatar
Yaowu Xu committed
352 353 354 355
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
356 357
  oxcf->profile = cfg->g_profile;
  oxcf->max_threads = (int)cfg->g_threads;
358 359
  oxcf->width = cfg->g_w;
  oxcf->height = cfg->g_h;
Jingning Han's avatar
Jingning Han committed
360 361 362 363
  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;
364
  if (oxcf->init_framerate > 180) oxcf->init_framerate = 30;
Jingning Han's avatar
Jingning Han committed
365 366 367 368

  oxcf->mode = GOOD;

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

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

391 392 393 394 395 396
#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

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

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

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

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

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

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

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

426 427 428
  oxcf->speed = abs(extra_cfg->cpu_used);
  oxcf->encode_breakout = extra_cfg->static_thresh;
  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 511
  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);
  */
Yaowu Xu's avatar
Yaowu Xu committed
512
  return AOM_CODEC_OK;
Jingning Han's avatar
Jingning Han committed
513 514
}

Yaowu Xu's avatar
Yaowu Xu committed
515 516 517
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
518 519 520
  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
521
    if (cfg->g_lag_in_frames > 1 || cfg->g_pass != AOM_RC_ONE_PASS)
Jingning Han's avatar
Jingning Han committed
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
      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
538
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
539 540 541 542
    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
543
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
544 545
  }

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

  return res;
}

Yaowu Xu's avatar
Yaowu Xu committed
551
static aom_codec_err_t ctrl_get_quantizer(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
552 553
                                          va_list args) {
  int *const arg = va_arg(args, int *);
Yaowu Xu's avatar
Yaowu Xu committed
554 555 556
  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
557 558
}

Yaowu Xu's avatar
Yaowu Xu committed
559
static aom_codec_err_t ctrl_get_quantizer64(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
560 561
                                            va_list args) {
  int *const arg = va_arg(args, int *);
Yaowu Xu's avatar
Yaowu Xu committed
562 563 564
  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
565 566
}

Yaowu Xu's avatar
Yaowu Xu committed
567 568 569 570
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
571 572
    ctx->extra_cfg = *extra_cfg;
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
Yaowu Xu's avatar
Yaowu Xu committed
573
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
574 575 576 577
  }
  return res;
}

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

Yaowu Xu's avatar
Yaowu Xu committed
585
static aom_codec_err_t ctrl_set_enable_auto_alt_ref(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
586
                                                    va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
587 588
  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
589 590 591
  return update_extra_cfg(ctx, &extra_cfg);
}

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

Yaowu Xu's avatar
Yaowu Xu committed
601
static aom_codec_err_t ctrl_set_noise_sensitivity(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
602
                                                  va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
603 604
  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
605 606 607
  return update_extra_cfg(ctx, &extra_cfg);
}

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

Yaowu Xu's avatar
Yaowu Xu committed
615
static aom_codec_err_t ctrl_set_static_thresh(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
616
                                              va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
617 618
  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
619 620 621
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
622
static aom_codec_err_t ctrl_set_tile_columns(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
623
                                             va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
624 625
  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
626 627 628
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
629
static aom_codec_err_t ctrl_set_tile_rows(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
630
                                          va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
631 632
  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
633 634 635
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
636
static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
637
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
638 639
  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
640 641 642
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
643
static aom_codec_err_t ctrl_set_arnr_strength(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
644
                                              va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
645 646
  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
647 648 649
  return update_extra_cfg(ctx, &extra_cfg);
}

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

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

Yaowu Xu's avatar
Yaowu Xu committed
664
static aom_codec_err_t ctrl_set_cq_level(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
665
                                         va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
666 667
  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
668 669 670
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
671 672 673
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
674
  extra_cfg.rc_max_intra_bitrate_pct =
Yaowu Xu's avatar
Yaowu Xu committed
675
      CAST(AOME_SET_MAX_INTRA_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
676 677 678
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
679 680 681
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
682
  extra_cfg.rc_max_inter_bitrate_pct =
Yaowu Xu's avatar
Yaowu Xu committed
683
      CAST(AOME_SET_MAX_INTER_BITRATE_PCT, args);
Jingning Han's avatar
Jingning Han committed
684 685 686
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
687
static aom_codec_err_t ctrl_set_rc_gf_cbr_boost_pct(aom_codec_alg_priv_t *ctx,
688
                                                    va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
689 690
  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
691 692 693
  return update_extra_cfg(ctx, &extra_cfg);
}

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

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

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

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

Yaowu Xu's avatar
Yaowu Xu committed
724 725 726
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
727
  extra_cfg.frame_parallel_decoding_mode =
Yaowu Xu's avatar
Yaowu Xu committed
728
      CAST(AV1E_SET_FRAME_PARALLEL_DECODING, args);
Jingning Han's avatar
Jingning Han committed
729 730 731
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
732
static aom_codec_err_t ctrl_set_aq_mode(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
733
                                        va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
734 735
  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
736 737 738
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
739
static aom_codec_err_t ctrl_set_min_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
740
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
741 742
  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
743 744 745
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
746
static aom_codec_err_t ctrl_set_max_gf_interval(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
747
                                                va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
748 749
  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
750 751 752
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
753
static aom_codec_err_t ctrl_set_frame_periodic_boost(aom_codec_alg_priv_t *ctx,
Jingning Han's avatar
Jingning Han committed
754
                                                     va_list args) {
Yaowu Xu's avatar
Yaowu Xu committed
755 756
  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
757 758 759
  return update_extra_cfg(ctx, &extra_cfg);
}

Yaowu Xu's avatar
Yaowu Xu committed
760 761 762
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
763 764 765
  (void)data;

  if (ctx->priv == NULL) {
Yaowu Xu's avatar
Yaowu Xu committed
766 767
    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
768

Yaowu Xu's avatar
Yaowu Xu committed
769
    ctx->priv = (aom_codec_priv_t *)priv;
Jingning Han's avatar
Jingning Han committed
770 771
    ctx->priv->init_flags = ctx->init_flags;
    ctx->priv->enc.total_encoders = 1;
Yaowu Xu's avatar
Yaowu Xu committed
772 773
    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
774 775 776

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

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

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

  return res;
}

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

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

  switch (ctx->cfg.g_pass) {
Yaowu Xu's avatar
Yaowu Xu committed
826
    case AOM_RC_ONE_PASS:
Jingning Han's avatar
Jingning Han committed
827
      if (deadline > 0) {
Yaowu Xu's avatar
Yaowu Xu committed
828
        const aom_codec_enc_cfg_t *const cfg = &ctx->cfg;
Jingning Han's avatar
Jingning Han committed
829 830 831

        // Convert duration parameter from stream timebase to microseconds.
        const uint64_t duration_us = (uint64_t)duration * 1000000 *
832 833
                                     (uint64_t)cfg->g_timebase.num /
                                     (uint64_t)cfg->g_timebase.den;
Jingning Han's avatar
Jingning Han committed
834 835 836 837 838 839 840 841

        // 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;
Yaowu Xu's avatar
Yaowu Xu committed
842 843
    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
844 845 846 847
  }

  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
Yaowu Xu's avatar
Yaowu Xu committed
848
    av1_change_config(ctx->cpi, &ctx->oxcf);
Jingning Han's avatar
Jingning Han committed
849 850 851 852 853
  }
}

// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
Yaowu Xu's avatar
Yaowu Xu committed
854
static int write_superframe_index(aom_codec_alg_priv_t *ctx) {
Jingning Han's avatar
Jingning Han committed
855 856 857
  uint8_t marker = 0xc0;
  unsigned int mask;
  int mag, index_sz;
858 859
  int i;
  size_t max_frame_sz = 0;
Jingning Han's avatar
Jingning Han committed
860 861 862 863 864 865

  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;
866
  for (i = 0; i < ctx->pending_frame_count - 1; i++) {
867
    const size_t frame_sz = (unsigned int)ctx->pending_frame_sizes[i] - 1;
868 869
    max_frame_sz = frame_sz > max_frame_sz ? frame_sz : max_frame_sz;
  }
Jingning Han's avatar
Jingning Han committed
870 871 872

  // Choose the magnitude
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
873
    if (max_frame_sz <= mask) break;
Jingning Han's avatar
Jingning Han committed
874 875 876 877 878 879
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

  // Write the index
hui su's avatar
hui su committed
880
  index_sz = 2 + (mag + 1) * (ctx->pending_frame_count - 1);
Jingning Han's avatar
Jingning Han committed
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
  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;
hui su's avatar
hui su committed
900
    for (i = 0; i < ctx->pending_frame_count - 1; i++) {
901
      unsigned int this_sz;
Jingning Han's avatar
Jingning Han committed
902

903
      assert(ctx->pending_frame_sizes[i] > 0);
hui su's avatar
hui su committed
904
      this_sz = (unsigned int)ctx->pending_frame_sizes[i] - 1;
Jingning Han's avatar
Jingning Han committed
905 906 907 908 909 910 911 912 913 914 915 916 917 918
      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
919
// av1 uses 10,000,000 ticks/second as time stamp
Jingning Han's avatar
Jingning Han committed
920 921
#define TICKS_PER_SEC 10000000LL

Yaowu Xu's avatar
Yaowu Xu committed
922
static int64_t timebase_units_to_ticks(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
923 924 925 926
                                       int64_t n) {
  return n * TICKS_PER_SEC * timebase->num / timebase->den;
}

Yaowu Xu's avatar
Yaowu Xu committed
927
static int64_t ticks_to_timebase_units(const aom_rational_t *timebase,
Jingning Han's avatar
Jingning Han committed
928 929 930 931 932
                                       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
933
static aom_codec_frame_flags_t get_frame_pkt_flags(const AV1_COMP *cpi,
Jingning Han's avatar
Jingning Han committed
934
                                                   unsigned int lib_flags) {
Yaowu Xu's avatar
Yaowu Xu committed
935
  aom_codec_frame_flags_t flags = lib_flags << 16;
Jingning Han's avatar
Jingning Han committed
936

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

Yaowu Xu's avatar
Yaowu Xu committed
939
  if (cpi->droppable) flags |= AOM_FRAME_IS_DROPPABLE;
Jingning Han's avatar
Jingning Han committed
940 941 942 943

  return flags;
}

Yaowu Xu's avatar
Yaowu Xu committed
944 945 946
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
947
                                      unsigned long duration,
Yaowu Xu's avatar
Yaowu Xu committed
948
                                      aom_enc_frame_flags_t enc_flags,
Jingning Han's avatar
Jingning Han committed
949
                                      unsigned long deadline) {
Yaowu Xu's avatar
Yaowu Xu committed
950 951 952 953
  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
954 955
  size_t data_sz;

Yaowu Xu's avatar
Yaowu Xu committed
956
  if (cpi == NULL) return AOM_CODEC_INVALID_PARAM;
957

Jingning Han's avatar
Jingning Han committed
958 959 960 961
  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
962
    if (res == AOM_CODEC_OK) {
963
#if CONFIG_EXT_REFS
964 965
      data_sz = ctx->cfg.g_w * ctx->cfg.g_h * get_image_bps(img);
#else
966 967
      // There's no codec control for multiple alt-refs so check the encoder
      // instance for its status to determine the compressed data size.
Jingning Han's avatar
Jingning Han committed
968 969
      data_sz = ctx->cfg.g_w * ctx->cfg.g_h * get_image_bps(img) / 8 *
                (cpi->multi_arf_allowed ? 8 : 2);
970
#endif  // CONFIG_EXT_REFS
971
      if (data_sz < 4096) data_sz = 4096;
Jingning Han's avatar
Jingning Han committed
972 973 974
      if (ctx->cx_data == NULL || ctx->cx_data_sz < data_sz) {
        ctx->cx_data_sz = data_sz;
        free(ctx->cx_data);
975
        ctx->cx_data = (unsigned char *)malloc(ctx->cx_data_sz);
Jingning Han's avatar
Jingning Han committed
976
        if (ctx->cx_data == NULL) {
Yaowu Xu's avatar
Yaowu Xu committed
977
          return AOM_CODEC_MEM_ERROR;
Jingning Han's avatar
Jingning Han committed
978 979 980 981 982 983
        }
      }
    }
  }

  pick_quickcompress_mode(ctx, duration, deadline);
Yaowu Xu's avatar
Yaowu Xu committed
984
  aom_codec_pkt_list_init(&ctx->pkt_list);
Jingning Han's avatar
Jingning Han committed
985 986

  // Handle Flags
Yaowu Xu's avatar
Yaowu Xu committed
987 988
  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
989
    ctx->base.err_detail = "Conflicting flags.";
Yaowu Xu's avatar
Yaowu Xu committed
990
    return AOM_CODEC_INVALID_PARAM;
Jingning Han's avatar
Jingning Han committed
991 992
  }

James Zern's avatar
James Zern committed
993 994 995
  if (setjmp(cpi->common.error.jmp)) {
    cpi->common.error.setjmp = 0;
    res = update_error_state(ctx, &cpi->common.error);
Yaowu Xu's avatar
Yaowu Xu committed
996
    aom_clear_system_state();
James Zern's avatar
James Zern committed
997 998 999 1000
    return res;
  }
  cpi->common.error.setjmp = 1;

Yaowu Xu's avatar
Yaowu Xu committed
1001
  av1_apply_encoding_flags(cpi, flags);
Jingning Han's avatar
Jingning Han committed
1002 1003

  // Handle fixed keyframe intervals
Yaowu Xu's avatar
Yaowu Xu committed
1004
  if (ctx->cfg.kf_mode == AOM_KF_AUTO &&
Jingning Han's avatar
Jingning Han committed
1005 1006
      ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) {
    if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) {
Yaowu Xu's avatar
Yaowu Xu committed
1007
      flags |= AOM_EFLAG_FORCE_KF;
Jingning Han's avatar
Jingning Han committed
1008 1009 1010 1011
      ctx->fixed_kf_cntr = 1;
    }
  }

Yaowu Xu's avatar
Yaowu Xu committed
1012
  if (res == AOM_CODEC_OK) {
Jingning Han's avatar
Jingning Han committed
1013 1014 1015 1016 1017 1018 1019 1020 1021
    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
Yaowu Xu's avatar
Yaowu Xu committed
1022
    if (ctx->base.init_flags & AOM_CODEC_USE_PSNR) cpi->b_calculate_psnr = 1;
Jingning Han's avatar
Jingning Han committed
1023 1024 1025 1026 1027 1028

    if (img != NULL) {
      res = image2yuvconfig(img, &sd);

      // Store the original flags in to the frame buffer. Will extract the
      // key frame flag when we actually encode this frame.
Yaowu Xu's avatar
Yaowu Xu committed
1029 1030
      if (av1_receive_raw_frame(cpi, flags | ctx->next_frame_flags, &sd,
                                dst_time_stamp, dst_end_time_stamp)) {
Jingning Han's avatar
Jingning Han committed
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
        res = update_error_state(ctx, &cpi->common.error);
      }
      ctx->next_frame_flags = 0;
    }

    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;

    /* Any pending invisible frames? */
    if (ctx->pending_cx_data) {
      memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz);
      ctx->pending_cx_data = cx_data;
      cx_data += ctx->pending_cx_data_sz;
      cx_data_sz -= ctx->pending_cx_data_sz;

      /* TODO: this is a minimal check, the underlying codec doesn't respect
       * the buffer size anyway.
       */
      if (cx_data_sz < ctx->cx_data_sz / 2) {
Yaowu Xu's avatar
Yaowu Xu committed
1050
        aom_internal_error(&cpi->common.error, AOM_CODEC_ERROR,
James Zern's avatar
James Zern committed
1051
                           "Compressed data buffer too small");
Yaowu Xu's avatar
Yaowu Xu committed
1052
        return AOM_CODEC_ERROR;
Jingning Han's avatar
Jingning Han committed
1053 1054 1055 1056
      }
    }

    while (cx_data_sz >= ctx->cx_data_sz / 2 &&
Yaowu Xu's avatar
Yaowu Xu committed
1057 1058