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

11 12
#include <stdlib.h>
#include <string.h>
John Koleszar's avatar
John Koleszar committed
13

14
#include "./vpx_config.h"
15
#include "vpx/vpx_encoder.h"
16
#include "vpx_ports/vpx_once.h"
17
#include "vpx/internal/vpx_codec_internal.h"
18
#include "./vpx_version.h"
19
#include "vp9/encoder/vp9_encoder.h"
John Koleszar's avatar
John Koleszar committed
20
#include "vpx/vp8cx.h"
21
#include "vp9/encoder/vp9_firstpass.h"
22
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
23

24
struct vp9_extracfg {
25
  int                         cpu_used;  // available cpu percentage in 1/16
26
  unsigned int                enable_auto_alt_ref;
John Koleszar's avatar
John Koleszar committed
27
  unsigned int                noise_sensitivity;
28
  unsigned int                sharpness;
John Koleszar's avatar
John Koleszar committed
29
  unsigned int                static_thresh;
30
  unsigned int                tile_columns;
31
  unsigned int                tile_rows;
32 33
  unsigned int                arnr_max_frames;
  unsigned int                arnr_strength;
John Koleszar's avatar
John Koleszar committed
34
  vp8e_tuning                 tuning;
35
  unsigned int                cq_level;  // constrained quality level
John Koleszar's avatar
John Koleszar committed
36
  unsigned int                rc_max_intra_bitrate_pct;
37
  unsigned int                rc_max_inter_bitrate_pct;
38
  unsigned int                gf_cbr_boost_pct;
John Koleszar's avatar
John Koleszar committed
39
  unsigned int                lossless;
40
  unsigned int                frame_parallel_decoding_mode;
41
  AQ_MODE                     aq_mode;
42
  unsigned int                frame_periodic_boost;
43
  vpx_bit_depth_t             bit_depth;
44
  vp9e_tune_content           content;
45
  vpx_color_space_t           color_space;
John Koleszar's avatar
John Koleszar committed
46 47
};

48 49 50 51 52 53
static struct vp9_extracfg default_extra_cfg = {
  0,                          // cpu_used
  1,                          // enable_auto_alt_ref
  0,                          // noise_sensitivity
  0,                          // sharpness
  0,                          // static_thresh
54
  6,                          // tile_columns
55 56 57 58 59 60
  0,                          // tile_rows
  7,                          // arnr_max_frames
  5,                          // arnr_strength
  VP8_TUNE_PSNR,              // tuning
  10,                         // cq_level
  0,                          // rc_max_intra_bitrate_pct
61
  0,                          // rc_max_inter_bitrate_pct
62
  0,                          // gf_cbr_boost_pct
63
  0,                          // lossless
64
  1,                          // frame_parallel_decoding_mode
65 66
  NO_AQ,                      // aq_mode
  0,                          // frame_periodic_delta_q
67
  VPX_BITS_8,                 // Bit depth
68 69
  VP9E_CONTENT_DEFAULT,       // content
  VPX_CS_UNKNOWN,             // color space
John Koleszar's avatar
John Koleszar committed
70 71
};

John Koleszar's avatar
John Koleszar committed
72 73 74
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_enc_cfg_t     cfg;
75
  struct vp9_extracfg     extra_cfg;
76
  VP9EncoderConfig        oxcf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
77
  VP9_COMP               *cpi;
John Koleszar's avatar
John Koleszar committed
78
  unsigned char          *cx_data;
79
  size_t                  cx_data_sz;
80
  unsigned char          *pending_cx_data;
81
  size_t                  pending_cx_data_sz;
John Koleszar's avatar
John Koleszar committed
82
  int                     pending_frame_count;
83 84
  size_t                  pending_frame_sizes[8];
  size_t                  pending_frame_magnitude;
John Koleszar's avatar
John Koleszar committed
85
  vpx_image_t             preview_img;
86
  vpx_enc_frame_flags_t   next_frame_flags;
John Koleszar's avatar
John Koleszar committed
87
  vp8_postproc_cfg_t      preview_ppcfg;
88
  vpx_codec_pkt_list_decl(256) pkt_list;
89
  unsigned int                 fixed_kf_cntr;
90
  vpx_codec_priv_output_cx_pkt_cb_pair_t output_cx_pkt_cb;
91 92
  // BufferPool that holds all reference frames.
  BufferPool              *buffer_pool;
John Koleszar's avatar
John Koleszar committed
93 94
};

95
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
96 97 98 99 100 101 102 103
  switch (frame) {
    case VP8_LAST_FRAME:
      return VP9_LAST_FLAG;
    case VP8_GOLD_FRAME:
      return VP9_GOLD_FLAG;
    case VP8_ALTR_FRAME:
      return VP9_ALT_FLAG;
  }
104
  assert(0 && "Invalid Reference Frame");
105 106
  return VP9_LAST_FLAG;
}
John Koleszar's avatar
John Koleszar committed
107

108 109 110
static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
    const struct vpx_internal_error_info *error) {
  const vpx_codec_err_t res = error->error_code;
John Koleszar's avatar
John Koleszar committed
111

112 113
  if (res != VPX_CODEC_OK)
    ctx->base.err_detail = error->has_detail ? error->detail : NULL;
John Koleszar's avatar
John Koleszar committed
114

John Koleszar's avatar
John Koleszar committed
115
  return res;
John Koleszar's avatar
John Koleszar committed
116 117 118
}


119
#undef ERROR
John Koleszar's avatar
John Koleszar committed
120
#define ERROR(str) do {\
John Koleszar's avatar
John Koleszar committed
121 122
    ctx->base.err_detail = str;\
    return VPX_CODEC_INVALID_PARAM;\
123
  } while (0)
John Koleszar's avatar
John Koleszar committed
124

125 126
#define RANGE_CHECK(p, memb, lo, hi) do {\
    if (!(((p)->memb == lo || (p)->memb > (lo)) && (p)->memb <= hi)) \
John Koleszar's avatar
John Koleszar committed
127
      ERROR(#memb " out of range ["#lo".."#hi"]");\
128
  } while (0)
John Koleszar's avatar
John Koleszar committed
129

130 131
#define RANGE_CHECK_HI(p, memb, hi) do {\
    if (!((p)->memb <= (hi))) \
John Koleszar's avatar
John Koleszar committed
132
      ERROR(#memb " out of range [.."#hi"]");\
133
  } while (0)
134

135 136
#define RANGE_CHECK_LO(p, memb, lo) do {\
    if (!((p)->memb >= (lo))) \
John Koleszar's avatar
John Koleszar committed
137
      ERROR(#memb " out of range ["#lo"..]");\
138
  } while (0)
John Koleszar's avatar
John Koleszar committed
139

140 141 142
#define RANGE_CHECK_BOOL(p, memb) do {\
    if (!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean");\
  } while (0)
John Koleszar's avatar
John Koleszar committed
143

144
static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
145
                                       const vpx_codec_enc_cfg_t *cfg,
146
                                       const struct vp9_extracfg *extra_cfg) {
147 148
  RANGE_CHECK(cfg, g_w,                   1, 65535);  // 16 bits available
  RANGE_CHECK(cfg, g_h,                   1, 65535);  // 16 bits available
John Koleszar's avatar
John Koleszar committed
149 150 151
  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);
John Koleszar's avatar
John Koleszar committed
152

John Koleszar's avatar
John Koleszar committed
153 154
  RANGE_CHECK_HI(cfg, rc_max_quantizer,   63);
  RANGE_CHECK_HI(cfg, rc_min_quantizer,   cfg->rc_max_quantizer);
155 156
  RANGE_CHECK_BOOL(extra_cfg, lossless);
  RANGE_CHECK(extra_cfg, aq_mode,           0, AQ_MODE_COUNT - 1);
157
  RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
John Koleszar's avatar
John Koleszar committed
158 159
  RANGE_CHECK_HI(cfg, g_threads,          64);
  RANGE_CHECK_HI(cfg, g_lag_in_frames,    MAX_LAG_BUFFERS);
160
  RANGE_CHECK(cfg, rc_end_usage,          VPX_VBR, VPX_Q);
161 162
  RANGE_CHECK_HI(cfg, rc_undershoot_pct,  100);
  RANGE_CHECK_HI(cfg, rc_overshoot_pct,   100);
John Koleszar's avatar
John Koleszar committed
163 164 165 166 167 168 169 170
  RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
  RANGE_CHECK(cfg, kf_mode,               VPX_KF_DISABLED, VPX_KF_AUTO);
  RANGE_CHECK_BOOL(cfg,                   rc_resize_allowed);
  RANGE_CHECK_HI(cfg, rc_dropframe_thresh,   100);
  RANGE_CHECK_HI(cfg, rc_resize_up_thresh,   100);
  RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
  RANGE_CHECK(cfg,        g_pass,         VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);

171
  if (cfg->rc_resize_allowed == 1) {
172 173
    RANGE_CHECK(cfg, rc_scaled_width, 0, cfg->g_w);
    RANGE_CHECK(cfg, rc_scaled_height, 0, cfg->g_h);
174 175
  }

176
  RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
177
  RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
178

179 180
  if (cfg->ss_number_layers * cfg->ts_number_layers > VPX_MAX_LAYERS)
    ERROR("ss_number_layers * ts_number_layers is out of range");
181
  if (cfg->ts_number_layers > 1) {
182 183 184 185 186 187 188
    unsigned int sl, tl;
    for (sl = 1; sl < cfg->ss_number_layers; ++sl) {
      for (tl = 1; tl < cfg->ts_number_layers; ++tl) {
        const int layer =
            LAYER_IDS_TO_IDX(sl, tl, cfg->ts_number_layers);
        if (cfg->layer_target_bitrate[layer] <
            cfg->layer_target_bitrate[layer - 1])
189
        ERROR("ts_target_bitrate entries are not increasing");
190 191
      }
    }
192 193

    RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
194 195
    for (tl = cfg->ts_number_layers - 2; tl > 0; --tl)
      if (cfg->ts_rate_decimator[tl - 1] != 2 * cfg->ts_rate_decimator[tl])
196 197 198
        ERROR("ts_rate_decimator factors are not powers of 2");
  }

199 200 201 202 203 204 205 206 207
#if CONFIG_SPATIAL_SVC

  if ((cfg->ss_number_layers > 1 || cfg->ts_number_layers > 1) &&
      cfg->g_pass == VPX_RC_LAST_PASS) {
    unsigned int i, alt_ref_sum = 0;
    for (i = 0; i < cfg->ss_number_layers; ++i) {
      if (cfg->ss_enable_auto_alt_ref[i])
        ++alt_ref_sum;
    }
208
    if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers)
209
      ERROR("Not enough ref buffers for svc alt ref frames");
210
    if (cfg->ss_number_layers * cfg->ts_number_layers > 3 &&
211
        cfg->g_error_resilient == 0)
212
    ERROR("Multiple frame context are not supported for more than 3 layers");
213 214 215
  }
#endif

216
  // VP9 does not support a lower bound on the keyframe interval in
217 218 219 220
  // automatic keyframe placement mode.
  if (cfg->kf_mode != VPX_KF_DISABLED &&
      cfg->kf_min_dist != cfg->kf_max_dist &&
      cfg->kf_min_dist > 0)
John Koleszar's avatar
John Koleszar committed
221 222 223
    ERROR("kf_min_dist not supported in auto mode, use 0 "
          "or kf_max_dist instead.");

224
  RANGE_CHECK(extra_cfg, enable_auto_alt_ref, 0, 2);
225
  RANGE_CHECK(extra_cfg, cpu_used, -8, 8);
226 227 228 229 230 231 232
  RANGE_CHECK_HI(extra_cfg, noise_sensitivity, 6);
  RANGE_CHECK(extra_cfg, tile_columns, 0, 6);
  RANGE_CHECK(extra_cfg, tile_rows, 0, 2);
  RANGE_CHECK_HI(extra_cfg, sharpness, 7);
  RANGE_CHECK(extra_cfg, arnr_max_frames, 0, 15);
  RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
  RANGE_CHECK(extra_cfg, cq_level, 0, 63);
233 234
  RANGE_CHECK(cfg, g_bit_depth, VPX_BITS_8, VPX_BITS_12);
  RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
235 236
  RANGE_CHECK(extra_cfg, content,
              VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1);
John Koleszar's avatar
John Koleszar committed
237

Yaowu Xu's avatar
Yaowu Xu committed
238
  // TODO(yaowu): remove this when ssim tuning is implemented for vp9
239
  if (extra_cfg->tuning == VP8_TUNE_SSIM)
Yaowu Xu's avatar
Yaowu Xu committed
240 241
      ERROR("Option --tune=ssim is not currently supported in VP9.");

John Koleszar's avatar
John Koleszar committed
242
  if (cfg->g_pass == VPX_RC_LAST_PASS) {
243 244
    const size_t packet_sz = sizeof(FIRSTPASS_STATS);
    const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
245
    const FIRSTPASS_STATS *stats;
John Koleszar's avatar
John Koleszar committed
246

Adrian Grange's avatar
Adrian Grange committed
247
    if (cfg->rc_twopass_stats_in.buf == NULL)
John Koleszar's avatar
John Koleszar committed
248 249 250 251 252
      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.");

253
    if (cfg->ss_number_layers > 1 || cfg->ts_number_layers > 1) {
254 255 256 257 258
      int i;
      unsigned int n_packets_per_layer[VPX_SS_MAX_LAYERS] = {0};

      stats = cfg->rc_twopass_stats_in.buf;
      for (i = 0; i < n_packets; ++i) {
259
        const int layer_id = (int)stats[i].spatial_layer_id;
260 261 262 263 264 265 266 267 268 269 270
        if (layer_id >= 0 && layer_id < (int)cfg->ss_number_layers) {
          ++n_packets_per_layer[layer_id];
        }
      }

      for (i = 0; i < (int)cfg->ss_number_layers; ++i) {
        unsigned int layer_id;
        if (n_packets_per_layer[i] < 2) {
          ERROR("rc_twopass_stats_in requires at least two packets for each "
                "layer.");
        }
John Koleszar's avatar
John Koleszar committed
271

272 273
        stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf +
                n_packets - cfg->ss_number_layers + i;
274
        layer_id = (int)stats->spatial_layer_id;
John Koleszar's avatar
John Koleszar committed
275

276
        if (layer_id >= cfg->ss_number_layers
277 278
            ||(unsigned int)(stats->count + 0.5) !=
               n_packets_per_layer[layer_id] - 1)
279 280 281 282 283 284 285 286 287 288 289 290
          ERROR("rc_twopass_stats_in missing EOS stats packet");
      }
    } else {
      if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz)
        ERROR("rc_twopass_stats_in requires at least two packets.");

      stats =
          (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1;

      if ((int)(stats->count + 0.5) != n_packets - 1)
        ERROR("rc_twopass_stats_in missing EOS stats packet");
    }
John Koleszar's avatar
John Koleszar committed
291
  }
292

293
#if !CONFIG_VP9_HIGHBITDEPTH
294
  if (cfg->g_profile > (unsigned int)PROFILE_1) {
295
    ERROR("Profile > 1 not supported in this build configuration");
296
  }
297
#endif
298
  if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
299
      cfg->g_bit_depth > VPX_BITS_8) {
300
    ERROR("Codec high bit-depth not supported in profile < 2");
301 302 303 304 305
  }
  if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
      cfg->g_input_bit_depth > 8) {
    ERROR("Source high bit-depth not supported in profile < 2");
  }
306
  if (cfg->g_profile > (unsigned int)PROFILE_1 &&
307
      cfg->g_bit_depth == VPX_BITS_8) {
308
    ERROR("Codec bit-depth 8 not supported in profile > 1");
309
  }
310
  RANGE_CHECK(extra_cfg, color_space, VPX_CS_UNKNOWN, VPX_CS_SRGB);
John Koleszar's avatar
John Koleszar committed
311
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
312 313 314
}

static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
315
                                    const vpx_image_t *img) {
John Koleszar's avatar
John Koleszar committed
316
  switch (img->fmt) {
317 318
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_I420:
319 320
    case VPX_IMG_FMT_I42016:
      break;
321 322
    case VPX_IMG_FMT_I422:
    case VPX_IMG_FMT_I444:
323
    case VPX_IMG_FMT_I440:
324
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1) {
325
        ERROR("Invalid image format. I422, I444, I440 images are "
326 327 328 329 330
              "not supported in profile.");
      }
      break;
    case VPX_IMG_FMT_I42216:
    case VPX_IMG_FMT_I44416:
331
    case VPX_IMG_FMT_I44016:
332 333
      if (ctx->cfg.g_profile != (unsigned int)PROFILE_1 &&
          ctx->cfg.g_profile != (unsigned int)PROFILE_3) {
334
        ERROR("Invalid image format. 16-bit I422, I444, I440 images are "
335 336
              "not supported in profile.");
      }
John Koleszar's avatar
John Koleszar committed
337
      break;
John Koleszar's avatar
John Koleszar committed
338
    default:
339 340
      ERROR("Invalid image format. Only YV12, I420, I422, I444 images are "
            "supported.");
341
      break;
John Koleszar's avatar
John Koleszar committed
342
  }
John Koleszar's avatar
John Koleszar committed
343

344
  if (img->d_w != ctx->cfg.g_w || img->d_h != ctx->cfg.g_h)
John Koleszar's avatar
John Koleszar committed
345
    ERROR("Image size must match encoder init configuration size");
John Koleszar's avatar
John Koleszar committed
346

John Koleszar's avatar
John Koleszar committed
347
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
348 349
}

350 351 352 353 354 355
static int get_image_bps(const vpx_image_t *img) {
  switch (img->fmt) {
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_I420: return 12;
    case VPX_IMG_FMT_I422: return 16;
    case VPX_IMG_FMT_I444: return 24;
356
    case VPX_IMG_FMT_I440: return 16;
357 358 359
    case VPX_IMG_FMT_I42016: return 24;
    case VPX_IMG_FMT_I42216: return 32;
    case VPX_IMG_FMT_I44416: return 48;
360
    case VPX_IMG_FMT_I44016: return 32;
361
    default: assert(0 && "Invalid image format"); break;
362 363 364
  }
  return 0;
}
John Koleszar's avatar
John Koleszar committed
365

366
static vpx_codec_err_t set_encoder_config(
Yaowu Xu's avatar
Yaowu Xu committed
367 368 369
  VP9EncoderConfig *oxcf,
  const vpx_codec_enc_cfg_t *cfg,
  const struct vp9_extracfg *extra_cfg) {
370
  const int is_vbr = cfg->rc_end_usage == VPX_VBR;
371
  int sl, tl;
372
  oxcf->profile = cfg->g_profile;
373
  oxcf->max_threads = (int)cfg->g_threads;
374 375
  oxcf->width   = cfg->g_w;
  oxcf->height  = cfg->g_h;
376
  oxcf->bit_depth = cfg->g_bit_depth;
377
  oxcf->input_bit_depth = cfg->g_input_bit_depth;
378
  // guess a frame rate if out of whack, use 30
379 380 381
  oxcf->init_framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
  if (oxcf->init_framerate > 180)
    oxcf->init_framerate = 30;
John Koleszar's avatar
John Koleszar committed
382

383
  oxcf->mode = GOOD;
384

385
  switch (cfg->g_pass) {
John Koleszar's avatar
John Koleszar committed
386
    case VPX_RC_ONE_PASS:
387
      oxcf->pass = 0;
John Koleszar's avatar
John Koleszar committed
388
      break;
John Koleszar's avatar
John Koleszar committed
389
    case VPX_RC_FIRST_PASS:
390
      oxcf->pass = 1;
John Koleszar's avatar
John Koleszar committed
391
      break;
John Koleszar's avatar
John Koleszar committed
392
    case VPX_RC_LAST_PASS:
393
      oxcf->pass = 2;
John Koleszar's avatar
John Koleszar committed
394 395 396
      break;
  }

397 398
  oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
                                                         : cfg->g_lag_in_frames;
399
  oxcf->rc_mode = cfg->rc_end_usage;
400

401 402
  // Convert target bandwidth from Kbit/s to Bit/s
  oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
403
  oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
404
  oxcf->rc_max_inter_bitrate_pct = extra_cfg->rc_max_inter_bitrate_pct;
405
  oxcf->gf_cbr_boost_pct = extra_cfg->gf_cbr_boost_pct;
John Koleszar's avatar
John Koleszar committed
406

407 408 409 410
  oxcf->best_allowed_q =
      extra_cfg->lossless ? 0 : vp9_quantizer_to_qindex(cfg->rc_min_quantizer);
  oxcf->worst_allowed_q =
      extra_cfg->lossless ? 0 : vp9_quantizer_to_qindex(cfg->rc_max_quantizer);
411
  oxcf->cq_level        = vp9_quantizer_to_qindex(extra_cfg->cq_level);
John Koleszar's avatar
John Koleszar committed
412 413
  oxcf->fixed_q = -1;

414 415 416
  oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;

417 418 419 420 421 422 423 424 425
  oxcf->scaled_frame_width  = cfg->rc_scaled_width;
  oxcf->scaled_frame_height = cfg->rc_scaled_height;
  if (cfg->rc_resize_allowed == 1) {
    oxcf->resize_mode =
        (oxcf->scaled_frame_width == 0 || oxcf->scaled_frame_height == 0) ?
            RESIZE_DYNAMIC : RESIZE_FIXED;
  } else {
    oxcf->resize_mode = RESIZE_NONE;
  }
426

427 428 429
  oxcf->maximum_buffer_size_ms   = is_vbr ? 240000 : cfg->rc_buf_sz;
  oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
  oxcf->optimal_buffer_level_ms  = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
John Koleszar's avatar
John Koleszar committed
430

431
  oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
John Koleszar's avatar
John Koleszar committed
432

433 434 435
  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;
436

437 438
  oxcf->auto_key               = cfg->kf_mode == VPX_KF_AUTO &&
                                 cfg->kf_min_dist != cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
439

440
  oxcf->key_freq               = cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
441

442
  oxcf->speed                  =  abs(extra_cfg->cpu_used);
443
  oxcf->encode_breakout        =  extra_cfg->static_thresh;
444
  oxcf->enable_auto_arf        =  extra_cfg->enable_auto_alt_ref;
445 446
  oxcf->noise_sensitivity      =  extra_cfg->noise_sensitivity;
  oxcf->sharpness              =  extra_cfg->sharpness;
John Koleszar's avatar
John Koleszar committed
447

448
  oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
John Koleszar's avatar
John Koleszar committed
449

450 451 452 453
#if CONFIG_FP_MB_STATS
  oxcf->firstpass_mb_stats_in  = cfg->rc_firstpass_mb_stats_in;
#endif

454
  oxcf->color_space = extra_cfg->color_space;
455 456
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
  oxcf->arnr_strength   = extra_cfg->arnr_strength;
John Koleszar's avatar
John Koleszar committed
457

458
  oxcf->tuning = extra_cfg->tuning;
459
  oxcf->content = extra_cfg->content;
John Koleszar's avatar
John Koleszar committed
460

461 462
  oxcf->tile_columns = extra_cfg->tile_columns;
  oxcf->tile_rows    = extra_cfg->tile_rows;
463

464 465
  oxcf->error_resilient_mode         = cfg->g_error_resilient;
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
466

467
  oxcf->aq_mode = extra_cfg->aq_mode;
468

469 470
  oxcf->frame_periodic_boost =  extra_cfg->frame_periodic_boost;

471
  oxcf->ss_number_layers = cfg->ss_number_layers;
472 473 474
  oxcf->ts_number_layers = cfg->ts_number_layers;
  oxcf->temporal_layering_mode = (enum vp9e_temporal_layering_mode)
      cfg->temporal_layering_mode;
475

476
  for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
477
#if CONFIG_SPATIAL_SVC
478
    oxcf->ss_enable_auto_arf[sl] = cfg->ss_enable_auto_alt_ref[sl];
479
#endif
480 481 482
    for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
      oxcf->layer_target_bitrate[sl * oxcf->ts_number_layers + tl] =
          1000 * cfg->layer_target_bitrate[sl * oxcf->ts_number_layers + tl];
483
    }
484 485
  }
  if (oxcf->ss_number_layers == 1 && oxcf->pass != 0) {
486
    oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
487
#if CONFIG_SPATIAL_SVC
488
    oxcf->ss_enable_auto_arf[0] = extra_cfg->enable_auto_alt_ref;
489
#endif
490
  }
491
  if (oxcf->ts_number_layers > 1) {
492 493 494
    for (tl = 0; tl < VPX_TS_MAX_LAYERS; ++tl) {
      oxcf->ts_rate_decimator[tl] = cfg->ts_rate_decimator[tl] ?
          cfg->ts_rate_decimator[tl] : 1;
495
    }
496 497 498
  } else if (oxcf->ts_number_layers == 1) {
    oxcf->ts_rate_decimator[0] = 1;
  }
John Koleszar's avatar
John Koleszar committed
499
  /*
500 501 502
  printf("Current VP9 Settings: \n");
  printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
  printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
503
  printf("sharpness: %d\n",    oxcf->sharpness);
504
  printf("cpu_used: %d\n",  oxcf->cpu_used);
505
  printf("Mode: %d\n",     oxcf->mode);
506 507 508 509 510 511 512 513 514 515 516
  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);
517 518 519
  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);
520 521 522 523
  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);
524
  printf("enable_auto_arf: %d\n", oxcf->enable_auto_arf);
525 526 527
  printf("Version: %d\n", oxcf->Version);
  printf("encode_breakout: %d\n", oxcf->encode_breakout);
  printf("error resilient: %d\n", oxcf->error_resilient_mode);
528 529
  printf("frame parallel detokenization: %d\n",
         oxcf->frame_parallel_decoding_mode);
John Koleszar's avatar
John Koleszar committed
530 531
  */
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
532 533
}

534 535
static vpx_codec_err_t encoder_set_config(vpx_codec_alg_priv_t *ctx,
                                          const vpx_codec_enc_cfg_t  *cfg) {
John Koleszar's avatar
John Koleszar committed
536
  vpx_codec_err_t res;
537 538 539 540 541
  int force_key = 0;

  if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
    if (cfg->g_lag_in_frames > 1 || cfg->g_pass != VPX_RC_ONE_PASS)
      ERROR("Cannot change width or height after initialization");
542 543
    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) ||
544 545 546
        (ctx->cpi->initial_height && (int)cfg->g_h > ctx->cpi->initial_height))
      force_key = 1;
  }
John Koleszar's avatar
John Koleszar committed
547

548 549 550 551 552
  // 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)
John Koleszar's avatar
John Koleszar committed
553
    ERROR("Cannot increase lag_in_frames");
John Koleszar's avatar
John Koleszar committed
554

555
  res = validate_config(ctx, cfg, &ctx->extra_cfg);
John Koleszar's avatar
John Koleszar committed
556

Adrian Grange's avatar
Adrian Grange committed
557
  if (res == VPX_CODEC_OK) {
John Koleszar's avatar
John Koleszar committed
558
    ctx->cfg = *cfg;
559
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
560 561
    // On profile change, request a key frame
    force_key |= ctx->cpi->common.profile != ctx->oxcf.profile;
562
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
563
  }
John Koleszar's avatar
John Koleszar committed
564

565 566 567
  if (force_key)
    ctx->next_frame_flags |= VPX_EFLAG_FORCE_KF;

John Koleszar's avatar
John Koleszar committed
568
  return res;
John Koleszar's avatar
John Koleszar committed
569 570
}

571 572 573 574 575 576 577 578
static vpx_codec_err_t ctrl_get_quantizer(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  int *const arg = va_arg(args, int *);
  if (arg == NULL)
    return VPX_CODEC_INVALID_PARAM;
  *arg = vp9_get_quantizer(ctx->cpi);
  return VPX_CODEC_OK;
}
John Koleszar's avatar
John Koleszar committed
579

580 581 582
static vpx_codec_err_t ctrl_get_quantizer64(vpx_codec_alg_priv_t *ctx,
                                            va_list args) {
  int *const arg = va_arg(args, int *);
583 584
  if (arg == NULL)
    return VPX_CODEC_INVALID_PARAM;
585 586 587
  *arg = vp9_qindex_to_quantizer(vp9_get_quantizer(ctx->cpi));
  return VPX_CODEC_OK;
}
John Koleszar's avatar
John Koleszar committed
588

589 590 591 592 593 594 595
static vpx_codec_err_t update_extra_cfg(vpx_codec_alg_priv_t *ctx,
                                        const struct vp9_extracfg *extra_cfg) {
  const vpx_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
  if (res == VPX_CODEC_OK) {
    ctx->extra_cfg = *extra_cfg;
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
596
  }
597 598
  return res;
}
John Koleszar's avatar
John Koleszar committed
599

600 601 602 603 604
static vpx_codec_err_t ctrl_set_cpuused(vpx_codec_alg_priv_t *ctx,
                                        va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.cpu_used = CAST(VP8E_SET_CPUUSED, args);
  return update_extra_cfg(ctx, &extra_cfg);
John Koleszar's avatar
John Koleszar committed
605 606
}

607 608 609 610 611 612
static vpx_codec_err_t ctrl_set_enable_auto_alt_ref(vpx_codec_alg_priv_t *ctx,
                                                    va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.enable_auto_alt_ref = CAST(VP8E_SET_ENABLEAUTOALTREF, args);
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
613

614 615
static vpx_codec_err_t ctrl_set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
                                                  va_list args) {
616
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
617
  extra_cfg.noise_sensitivity = CAST(VP9E_SET_NOISE_SENSITIVITY, args);
618 619
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
620

621 622 623 624 625 626
static vpx_codec_err_t ctrl_set_sharpness(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.sharpness = CAST(VP8E_SET_SHARPNESS, args);
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
627

628 629 630 631 632 633
static vpx_codec_err_t ctrl_set_static_thresh(vpx_codec_alg_priv_t *ctx,
                                              va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.static_thresh = CAST(VP8E_SET_STATIC_THRESHOLD, args);
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
634

635 636 637 638 639 640
static vpx_codec_err_t ctrl_set_tile_columns(vpx_codec_alg_priv_t *ctx,
                                             va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tile_columns = CAST(VP9E_SET_TILE_COLUMNS, args);
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
641

642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
static vpx_codec_err_t ctrl_set_tile_rows(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tile_rows = CAST(VP9E_SET_TILE_ROWS, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_arnr_max_frames(vpx_codec_alg_priv_t *ctx,
                                                va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.arnr_max_frames = CAST(VP8E_SET_ARNR_MAXFRAMES, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_arnr_strength(vpx_codec_alg_priv_t *ctx,
                                              va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.arnr_strength = CAST(VP8E_SET_ARNR_STRENGTH, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_arnr_type(vpx_codec_alg_priv_t *ctx,
                                          va_list args) {
665 666 667
  (void)ctx;
  (void)args;
  return VPX_CODEC_OK;
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
}

static vpx_codec_err_t ctrl_set_tuning(vpx_codec_alg_priv_t *ctx,
                                       va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.tuning = CAST(VP8E_SET_TUNING, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_cq_level(vpx_codec_alg_priv_t *ctx,
                                         va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.cq_level = CAST(VP8E_SET_CQ_LEVEL, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_rc_max_intra_bitrate_pct(
    vpx_codec_alg_priv_t *ctx, va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.rc_max_intra_bitrate_pct =
      CAST(VP8E_SET_MAX_INTRA_BITRATE_PCT, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

692 693 694 695 696 697 698 699
static vpx_codec_err_t ctrl_set_rc_max_inter_bitrate_pct(
    vpx_codec_alg_priv_t *ctx, va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.rc_max_inter_bitrate_pct =
      CAST(VP8E_SET_MAX_INTER_BITRATE_PCT, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

700 701 702 703
static vpx_codec_err_t ctrl_set_rc_gf_cbr_boost_pct(
    vpx_codec_alg_priv_t *ctx, va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.gf_cbr_boost_pct =
704
      CAST(VP9E_SET_GF_CBR_BOOST_PCT, args);
705 706 707
  return update_extra_cfg(ctx, &extra_cfg);
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
static vpx_codec_err_t ctrl_set_lossless(vpx_codec_alg_priv_t *ctx,
                                         va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.lossless = CAST(VP9E_SET_LOSSLESS, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_frame_parallel_decoding_mode(
    vpx_codec_alg_priv_t *ctx, va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.frame_parallel_decoding_mode =
      CAST(VP9E_SET_FRAME_PARALLEL_DECODING, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_aq_mode(vpx_codec_alg_priv_t *ctx,
                                        va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.aq_mode = CAST(VP9E_SET_AQ_MODE, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

static vpx_codec_err_t ctrl_set_frame_periodic_boost(vpx_codec_alg_priv_t *ctx,
                                                     va_list args) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.frame_periodic_boost = CAST(VP9E_SET_FRAME_PERIODIC_BOOST, args);
  return update_extra_cfg(ctx, &extra_cfg);
John Koleszar's avatar
John Koleszar committed
735
}
736

737 738
static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
739
  vpx_codec_err_t res = VPX_CODEC_OK;
740
  (void)data;
John Koleszar's avatar
John Koleszar committed
741

Adrian Grange's avatar
Adrian Grange committed
742
  if (ctx->priv == NULL) {
743 744
    vpx_codec_alg_priv_t *const priv = vpx_calloc(1, sizeof(*priv));
    if (priv == NULL)
745
      return VPX_CODEC_MEM_ERROR;
746

747
    ctx->priv = (vpx_codec_priv_t *)priv;
John Koleszar's avatar
John Koleszar committed
748
    ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
749
    ctx->priv->enc.total_encoders = 1;
750 751 752 753
    priv->buffer_pool =
        (BufferPool *)vpx_calloc(1, sizeof(BufferPool));
    if (priv->buffer_pool == NULL)
      return VPX_CODEC_MEM_ERROR;
John Koleszar's avatar
John Koleszar committed
754

755 756 757 758 759 760
#if CONFIG_MULTITHREAD
    if (pthread_mutex_init(&priv->buffer_pool->pool_mutex, NULL)) {
      return VPX_CODEC_MEM_ERROR;
    }
#endif

John Koleszar's avatar
John Koleszar committed
761
    if (ctx->config.enc) {
762
      // Update the reference to the config structure to an internal copy.
763 764
      priv->cfg = *ctx->config.enc;
      ctx->config.enc = &priv->cfg;
John Koleszar's avatar
John Koleszar committed
765
    }
766

767
    priv->extra_cfg = default_extra_cfg;
768
    once(vp9_initialize_enc);
John Koleszar's avatar
John Koleszar committed
769

770
    res = validate_config(priv, &priv->cfg, &priv->extra_cfg);
John Koleszar's avatar
John Koleszar committed
771

Adrian Grange's avatar
Adrian Grange committed
772
    if (res == VPX_CODEC_OK) {
773
      set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
774 775 776 777
#if CONFIG_VP9_HIGHBITDEPTH
      priv->oxcf.use_highbitdepth =
          (ctx->init_flags & VPX_CODEC_USE_HIGHBITDEPTH) ? 1 : 0;
#endif
778
      priv->cpi = vp9_create_compressor(&priv->oxcf, priv->buffer_pool);
779
      if (priv->cpi == NULL)
John Koleszar's avatar
John Koleszar committed
780
        res = VPX_CODEC_MEM_ERROR;
781
      else
782
        priv->cpi->output_pkt_list = &priv->pkt_list.head;
John Koleszar's avatar
John Koleszar committed
783
    }
John Koleszar's avatar
John Koleszar committed
784
  }
John Koleszar's avatar
John Koleszar committed
785

John Koleszar's avatar
John Koleszar committed
786
  return res;
John Koleszar's avatar
John Koleszar committed
787 788
}

789
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
790
  free(ctx->cx_data);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
791
  vp9_remove_compressor(ctx->cpi);
792 793 794
#if CONFIG_MULTITHREAD
  pthread_mutex_destroy(&ctx->buffer_pool->pool_mutex);
#endif
795
  vpx_free(ctx->buffer_pool);
796
  vpx_free(ctx);
John Koleszar's avatar
John Koleszar committed
797
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
798 799
}

800
static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
801 802
                                    unsigned long duration,
                                    unsigned long deadline) {
803
  MODE new_mode = BEST;
John Koleszar's avatar
John Koleszar committed
804

805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
  switch (ctx->cfg.g_pass) {
    case VPX_RC_ONE_PASS:
      if (deadline > 0) {
        const vpx_codec_enc_cfg_t *const cfg = &ctx->cfg;

        // Convert duration parameter from stream timebase to microseconds.
        const uint64_t duration_us = (uint64_t)duration * 1000000 *
           (uint64_t)cfg->g_timebase.num /(uint64_t)cfg->g_timebase.den;

        // 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;
    case VPX_RC_FIRST_PASS:
      break;
    case VPX_RC_LAST_PASS:
      new_mode = deadline > 0 ? GOOD : BEST;
      break;
  }
John Koleszar's avatar
John Koleszar committed
827

828 829
  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
830
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
831
  }
John Koleszar's avatar
John Koleszar committed
832 833
}

834 835
// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
836
static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
837
  uint8_t marker = 0xc0;
838 839
  unsigned int mask;
  int mag, index_sz;
John Koleszar's avatar
John Koleszar committed
840 841 842 843

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

844
  // Add the number of frames to the marker byte
John Koleszar's avatar
John Koleszar committed
845 846
  marker |= ctx->pending_frame_count - 1;

847
  // Choose the magnitude
John Koleszar's avatar
John Koleszar committed
848 849 850 851 852 853 854 855
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
    if (ctx->pending_frame_magnitude < mask)
      break;
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

856
  // Write the index
John Koleszar's avatar
John Koleszar committed
857 858 859 860
  index_sz = 2 + (mag + 1) * ctx->pending_frame_count;
  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;
861 862 863 864 865 866 867 868 869 870 871 872 873 874
#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
John Koleszar's avatar
John Koleszar committed
875 876 877

    *x++ = marker;
    for (i = 0; i < ctx->pending_frame_count; i++) {
878
      unsigned int this_sz = (unsigned int)ctx->pending_frame_sizes[i];
John Koleszar's avatar
John Koleszar committed
879 880 881 882 883 884 885 886

      for (j = 0; j <= mag; j++) {
        *x++ = this_sz & 0xff;
        this_sz >>= 8;
      }
    }
    *x++ = marker;
    ctx->pending_cx_data_sz += index_sz;
887 888 889
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    index_sz += index_sz_test;
#endif
John Koleszar's avatar
John Koleszar committed
890
  }
891
  return index_sz;
John Koleszar's avatar
John Koleszar committed
892 893
}

894
// vp9 uses 10,000,000 ticks/second as time stamp
895
#define TICKS_PER_SEC 10000000LL
896 897 898 899 900 901 902 903 904 905 906 907

static int64_t timebase_units_to_ticks(const vpx_rational_t *timebase,
                                       int64_t n) {
  return n * TICKS_PER_SEC * timebase->num / timebase->den;
}

static int64_t ticks_to_timebase_units(const vpx_rational_t *timebase,
                                       int64_t n) {
  const int64_t round = TICKS_PER_SEC * timebase->num / 2 - 1;
  return (n * timebase->den + round) / timebase->num / TICKS_PER_SEC;
}

908 909 910 911
static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
                                                   unsigned int lib_flags) {
  vpx_codec_frame_flags_t flags = lib_flags << 16;

912 913 914 915 916 917
  if (lib_flags & FRAMEFLAGS_KEY ||
      (cpi->use_svc &&
          cpi->svc.layer_context[cpi->svc.spatial_layer_id *
              cpi->svc.number_temporal_layers +
              cpi->svc.temporal_layer_id].is_key_frame)
     )
918 919 920 921 922 923 924 925
    flags |= VPX_FRAME_IS_KEY;

  if (cpi->droppable)
    flags |= VPX_FRAME_IS_DROPPABLE;

  return flags;
}

926 927 928 929 930 931
static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t  *ctx,
                                      const vpx_image_t *img,
                                      vpx_codec_pts_t pts,
                                      unsigned long duration,
                                      vpx_enc_frame_flags_t flags,
                                      unsigned long deadline) {
John Koleszar's avatar
John Koleszar committed
932
  vpx_codec_err_t res = VPX_CODEC_OK;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
933
  VP9_COMP *const cpi = ctx->cpi;
934
  const vpx_rational_t *const timebase = &ctx->cfg.g_timebase;
935
  size_t data_sz;
John Koleszar's avatar
John Koleszar committed
936

937
  if (img != NULL) {
John Koleszar's avatar
John Koleszar committed
938
    res = validate_img(ctx, img);
939 940
    // TODO(jzern) the checks related to cpi's validity should be treated as a
    // failure condition, encoder setup is done fully in init() currently.
941
    if (res == VPX_CODEC_OK && cpi != NULL) {
942 943
      // There's no codec control for multiple alt-refs so check the encoder
      // instance for its status to determine the compressed data size.
944 945 946 947 948 949 950 951 952 953 954
      data_sz = ctx->cfg.g_w * ctx->cfg.g_h * get_image_bps(img) / 8 *
                (cpi->multi_arf_allowed ? 8 : 2);
      if (data_sz < 4096)
        data_sz = 4096;
      if (ctx->cx_data == NULL || ctx->cx_data_sz < data_sz) {
        ctx->cx_data_sz = data_sz;
        free(ctx->cx_data);
        ctx->cx_data = (unsigned char*)malloc(ctx->cx_data_sz);
        if (ctx->cx_data == NULL) {
          return VPX_CODEC_MEM_ERROR;
        }
955 956 957
      }
    }
  }
John Koleszar's avatar
John Koleszar committed
958

John Koleszar's avatar
John Koleszar committed
959 960
  pick_quickcompress_mode(ctx, duration, deadline);
  vpx_codec_pkt_list_init(&ctx->pkt_list);
John Koleszar's avatar
John Koleszar committed
961

962 963 964
  // Handle Flags
  if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF)) ||
       ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF))) {
John Koleszar's avatar
John Koleszar committed
965 966 967
    ctx->base.err_detail = "Conflicting flags.";
    return VPX_CODEC_INVALID_PARAM;
  }
John Koleszar's avatar
John Koleszar committed
968

Dmitry Kovalev's avatar
Dmitry Kovalev committed
969
  vp9_apply_encoding_flags(cpi, flags);
John Koleszar's avatar
John Koleszar committed
970

971 972 973
  // Handle fixed keyframe intervals
  if (ctx->cfg.kf_mode == VPX_KF_AUTO &&
      ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) {
John Koleszar's avatar
John Koleszar committed
974 975 976
    if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) {
      flags |= VPX_EFLAG_FORCE_KF;
      ctx->fixed_kf_cntr = 1;
John Koleszar's avatar
John Koleszar committed
977
    }
John Koleszar's avatar
John Koleszar committed
978
  }
John Koleszar's avatar
John Koleszar committed
979

980
  // Initialize the encoder instance on the first frame.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
981
  if (res == VPX_CODEC_OK && cpi != NULL) {
982
    unsigned int lib_flags = 0;
John Koleszar's avatar
John Koleszar committed
983
    YV12_BUFFER_CONFIG sd;
984 985 986
    int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
    int64_t dst_end_time_stamp =
        timebase_units_to_ticks(timebase, pts + duration);
987
    size_t size, cx_data_sz;
John Koleszar's avatar
John Koleszar committed
988
    unsigned char *cx_data;
John Koleszar's avatar
John Koleszar committed
989

990
    // Set up internal flags
John Koleszar's avatar
John Koleszar committed
991
    if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
992
      cpi->b_calculate_psnr = 1;
John Koleszar's avatar
John Koleszar committed
993

John Koleszar's avatar
John Koleszar committed
994 995
    if (img != NULL) {
      res = image2yuvconfig(img, &sd);
John Koleszar's avatar
John Koleszar committed
996

997 998
      // Store the original flags in to the frame buffer. Will extract the
      // key frame flag when we actually encode this frame.
999
      if (vp9_receive_raw_frame(cpi, flags | ctx->next_frame_flags,
John Koleszar's avatar
John Koleszar committed
1000 1001 1002
                                &sd, dst_time_stamp, dst_end_time_stamp)) {
        res = update_error_state(ctx, &cpi->common.error);
      }
1003
      ctx->next_frame_flags = 0;
John Koleszar's avatar
John Koleszar committed
1004
    }
John Koleszar's avatar
John Koleszar committed
1005

1006 1007
    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;
John Koleszar's avatar
John Koleszar committed
1008

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
    /* 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) {
        ctx->base.err_detail = "Compressed data buffer too small";
        return VPX_CODEC_ERROR;
      }
1023 1024
    }

1025
    while (cx_data_sz >= ctx->cx_data_sz / 2 &&
Dmitry Kovalev's avatar
Dmitry Kovalev committed
1026
           -1 != vp9_get_compressed_data(cpi, &lib_flags, &size,
1027 1028
                                         cx_data, &dst_time_stamp,
                                         &dst_end_time_stamp, !img)) {
John Koleszar's avatar
John Koleszar committed
1029
      if (size) {
1030
        vpx_codec_cx_pkt_t pkt;
John Koleszar's avatar
John Koleszar committed
1031

1032
#if CONFIG_SPATIAL_SVC
1033 1034 1035
        if (cpi->use_svc)
          cpi->svc.layer_context[cpi->svc.spatial_layer_id *
              cpi->svc.number_temporal_layers].layer_size += size;
1036 1037
#endif

1038
        // Pack invisible frames with the next visible frame
1039 1040 1041
        if (!cpi->common.show_frame ||
            (cpi->use_svc &&
             cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
1042
            ) {
Adrian Grange's avatar
Adrian Grange committed
1043
          if (ctx->pending_cx_data == 0)
1044 1045
            ctx->pending_cx_data = cx_data;
          ctx->pending_cx_data_sz += size;
John Koleszar's avatar
John Koleszar committed
1046 1047
          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
          ctx->pending_frame_magnitude |= size;
1048 1049
          cx_data += size;
          cx_data_sz -= size;
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067

          if (ctx->output_cx_pkt_cb.output_cx_pkt) {
            pkt.kind = VPX_CODEC_CX_FRAME_PKT;
            pkt.data.frame.pts = ticks_to_timebase_units(timebase,
                                                         dst_time_stamp);
            pkt.data.frame.duration =
               (unsigned long)ticks_to_timebase_units(timebase,
                   dst_end_time_stamp - dst_time_stamp);
            pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
            pkt.data.frame.buf = ctx->pending_cx_data;
            pkt.data.frame.sz  = size;
            ctx->pending_cx_data = NULL;
            ctx->pending_cx_data_sz = 0;
            ctx->pending_frame_count = 0;
            ctx->pending_frame_magnitude = 0;
            ctx->output_cx_pkt_cb.output_cx_pkt(
                &pkt, ctx->output_cx_pkt_cb.user_priv);
          }
1068 1069 1070
          continue;
        }

1071
        // Add the frame packet to the list of returned packets.
John Koleszar's avatar
John Koleszar committed
1072
        pkt.kind = VPX_CODEC_CX_FRAME_PKT;
1073 1074 1075 1076
        pkt.data.frame.pts = ticks_to_timebase_units(timebase, dst_time_stamp);
        pkt.data.frame.duration =
           (unsigned long)ticks_to_timebase_units(timebase,
               dst_end_time_stamp - dst_time_stamp);
1077
        pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
John Koleszar's avatar
John Koleszar committed
1078

1079 1080 1081 1082
        if (ctx->pending_cx_data) {
          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
          ctx->pending_frame_magnitude |= size;
          ctx->pending_cx_data_sz += size;
1083 1084 1085
          // write the superframe only for the case when
          if (!ctx->output_cx_pkt_cb.output_cx_pkt)
            size += write_superframe_index(ctx);
1086 1087 1088 1089 1090 1091 1092 1093 1094
          pkt.data.frame.buf = ctx->pending_cx_data;
          pkt.data.frame.sz  = ctx->pending_cx_data_sz;
          ctx->pending_cx_data = NULL;
          ctx->pending_cx_data_sz = 0;
          ctx->pending_frame_count = 0;
          ctx->pending_frame_magnitude = 0;
        } else {
          pkt.data.frame.buf = cx_data;
          pkt.data.frame.sz  = size;
John Koleszar's avatar
John Koleszar committed
1095
        }
1096
        pkt.data.frame.partition_id = -1;
1097 1098

        if(ctx->output_cx_pkt_cb.output_cx_pkt)
1099 1100
          ctx->output_cx_pkt_cb.output_cx_pkt(&pkt,
                                              ctx->output_cx_pkt_cb.user_priv);
1101 1102 1103
        else
          vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);

1104 1105
        cx_data += size;
        cx_data_sz -= size;
1106
#if VPX_ENCODER_ABI_VERSION > (5 + VPX_CODEC_ABI_VERSION)
1107
#if CONFIG_SPATIAL_SVC
1108
        if (cpi->use_svc && !ctx->output_cx_pkt_cb.output_cx_pkt) {
1109
          vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr;
1110
          int sl;
1111 1112 1113 1114
          vp9_zero(pkt_sizes);
          vp9_zero(pkt_psnr);
          pkt_sizes.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES;
          pkt_psnr.kind = VPX_CODEC_SPATIAL_SVC_LAYER_PSNR;
1115 1116 1117 1118 1119
          for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
            LAYER_CONTEXT *lc =
                &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers];
            pkt_sizes.data.layer_sizes[sl] = lc->layer_size;
            pkt_psnr.data.layer_psnr[sl] = lc->psnr_pkt;
1120
            lc->layer_size = 0;
1121
          }
1122

1123
          vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_sizes);