vp9_cx_iface.c 46.5 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 16
#include "vpx/vpx_codec.h"
#include "vpx/internal/vpx_codec_internal.h"
17
#include "./vpx_version.h"
Dmitry Kovalev's avatar
Dmitry Kovalev committed
18
#include "vp9/encoder/vp9_encoder.h"
John Koleszar's avatar
John Koleszar committed
19
#include "vpx/vp8cx.h"
20
#include "vp9/encoder/vp9_firstpass.h"
John Koleszar's avatar
John Koleszar committed
21
#include "vp9/vp9_iface_common.h"
John Koleszar's avatar
John Koleszar committed
22

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

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
static struct vp9_extracfg default_extra_cfg = {
  0,                          // cpu_used
  1,                          // enable_auto_alt_ref
  0,                          // noise_sensitivity
  0,                          // sharpness
  0,                          // static_thresh
  0,                          // tile_columns
  0,                          // tile_rows
  7,                          // arnr_max_frames
  5,                          // arnr_strength
  VP8_TUNE_PSNR,              // tuning
  10,                         // cq_level
  0,                          // rc_max_intra_bitrate_pct
  0,                          // lossless
  0,                          // frame_parallel_decoding_mode
  NO_AQ,                      // aq_mode
  0,                          // frame_periodic_delta_q
  BITS_8,                     // Bit depth
  VP9E_CONTENT_DEFAULT        // content
John Koleszar's avatar
John Koleszar committed
63 64
};

John Koleszar's avatar
John Koleszar committed
65 66 67
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_enc_cfg_t     cfg;
68
  struct vp9_extracfg     extra_cfg;
69
  VP9EncoderConfig        oxcf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
70
  VP9_COMP               *cpi;
John Koleszar's avatar
John Koleszar committed
71
  unsigned char          *cx_data;
72
  size_t                  cx_data_sz;
73
  unsigned char          *pending_cx_data;
74
  size_t                  pending_cx_data_sz;
John Koleszar's avatar
John Koleszar committed
75
  int                     pending_frame_count;
76 77
  size_t                  pending_frame_sizes[8];
  size_t                  pending_frame_magnitude;
John Koleszar's avatar
John Koleszar committed
78 79
  vpx_image_t             preview_img;
  vp8_postproc_cfg_t      preview_ppcfg;
80
  vpx_codec_pkt_list_decl(256) pkt_list;
81
  unsigned int                 fixed_kf_cntr;
John Koleszar's avatar
John Koleszar committed
82 83
};

84
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
85 86 87 88 89 90 91 92
  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;
  }
James Zern's avatar
James Zern committed
93
  assert(0 && "Invalid Reference Frame");
94 95
  return VP9_LAST_FLAG;
}
John Koleszar's avatar
John Koleszar committed
96

97 98 99
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
100

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

John Koleszar's avatar
John Koleszar committed
104
  return res;
John Koleszar's avatar
John Koleszar committed
105 106 107
}


108
#undef ERROR
John Koleszar's avatar
John Koleszar committed
109
#define ERROR(str) do {\
John Koleszar's avatar
John Koleszar committed
110 111
    ctx->base.err_detail = str;\
    return VPX_CODEC_INVALID_PARAM;\
112
  } while (0)
John Koleszar's avatar
John Koleszar committed
113

114 115
#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
116
      ERROR(#memb " out of range ["#lo".."#hi"]");\
117
  } while (0)
John Koleszar's avatar
John Koleszar committed
118

119 120
#define RANGE_CHECK_HI(p, memb, hi) do {\
    if (!((p)->memb <= (hi))) \
John Koleszar's avatar
John Koleszar committed
121
      ERROR(#memb " out of range [.."#hi"]");\
122
  } while (0)
123

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

129 130 131
#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
132

133
static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
134
                                       const vpx_codec_enc_cfg_t *cfg,
135
                                       const struct vp9_extracfg *extra_cfg) {
136 137
  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
138 139 140
  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
141

John Koleszar's avatar
John Koleszar committed
142 143
  RANGE_CHECK_HI(cfg, rc_max_quantizer,   63);
  RANGE_CHECK_HI(cfg, rc_min_quantizer,   cfg->rc_max_quantizer);
144 145
  RANGE_CHECK_BOOL(extra_cfg, lossless);
  RANGE_CHECK(extra_cfg, aq_mode,           0, AQ_MODE_COUNT - 1);
146
  RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
John Koleszar's avatar
John Koleszar committed
147 148
  RANGE_CHECK_HI(cfg, g_threads,          64);
  RANGE_CHECK_HI(cfg, g_lag_in_frames,    MAX_LAG_BUFFERS);
149
  RANGE_CHECK(cfg, rc_end_usage,          VPX_VBR, VPX_Q);
John Koleszar's avatar
John Koleszar committed
150 151 152 153 154 155 156 157 158 159
  RANGE_CHECK_HI(cfg, rc_undershoot_pct,  1000);
  RANGE_CHECK_HI(cfg, rc_overshoot_pct,   1000);
  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);

160 161 162 163 164
  if (cfg->rc_resize_allowed == 1) {
    RANGE_CHECK(cfg, rc_scaled_width, 1, cfg->g_w);
    RANGE_CHECK(cfg, rc_scaled_height, 1, cfg->g_h);
  }

165
  RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
166

167
#if CONFIG_SPATIAL_SVC
168
  if (cfg->ss_number_layers > 1) {
169
    unsigned int i, alt_ref_sum = 0;
170 171 172 173 174 175 176
    for (i = 0; i < cfg->ss_number_layers; ++i) {
      if (cfg->ss_enable_auto_alt_ref[i])
        ++alt_ref_sum;
    }
    if (alt_ref_sum > REF_FRAMES - cfg->ss_number_layers)
      ERROR("Not enough ref buffers for svc alt ref frames");
  }
177 178
  if (cfg->ss_number_layers > 3 && cfg->g_error_resilient == 0)
    ERROR("Multiple frame contexts are not supported for more than 3 layers");
179 180
#endif

181 182
  RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
  if (cfg->ts_number_layers > 1) {
183
    unsigned int i;
184 185
    for (i = 1; i < cfg->ts_number_layers; ++i)
      if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1])
186
        ERROR("ts_target_bitrate entries are not increasing");
187 188 189 190

    RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
    for (i = cfg->ts_number_layers - 2; i > 0; --i)
      if (cfg->ts_rate_decimator[i - 1] != 2 * cfg->ts_rate_decimator[i])
191 192 193
        ERROR("ts_rate_decimator factors are not powers of 2");
  }

194
  // VP9 does not support a lower bound on the keyframe interval in
195 196 197 198
  // 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
199 200 201
    ERROR("kf_min_dist not supported in auto mode, use 0 "
          "or kf_max_dist instead.");

202 203 204 205 206 207 208 209 210
  RANGE_CHECK_BOOL(extra_cfg,  enable_auto_alt_ref);
  RANGE_CHECK(extra_cfg, cpu_used, -16, 16);
  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);
211 212
  RANGE_CHECK(extra_cfg, content,
              VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1);
John Koleszar's avatar
John Koleszar committed
213

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

John Koleszar's avatar
John Koleszar committed
218
  if (cfg->g_pass == VPX_RC_LAST_PASS) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
219 220
    const size_t packet_sz = sizeof(FIRSTPASS_STATS);
    const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
221
    const FIRSTPASS_STATS *stats;
John Koleszar's avatar
John Koleszar committed
222

Adrian Grange's avatar
Adrian Grange committed
223
    if (cfg->rc_twopass_stats_in.buf == NULL)
John Koleszar's avatar
John Koleszar committed
224 225 226 227 228
      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.");

229 230 231 232 233 234
    if (cfg->ss_number_layers > 1) {
      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) {
235
        const int layer_id = (int)stats[i].spatial_layer_id;
236 237 238 239 240 241 242 243 244 245 246
        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
247

248 249
        stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf +
                n_packets - cfg->ss_number_layers + i;
250
        layer_id = (int)stats->spatial_layer_id;
John Koleszar's avatar
John Koleszar committed
251

252
        if (layer_id >= cfg->ss_number_layers
253 254
            ||(unsigned int)(stats->count + 0.5) !=
               n_packets_per_layer[layer_id] - 1)
255 256 257 258 259 260 261 262 263 264 265 266
          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
267
  }
268

269 270 271 272 273 274
  if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
      extra_cfg->bit_depth > BITS_8)
    ERROR("High bit-depth not supported in profile < 2");
  if (cfg->g_profile > (unsigned int)PROFILE_1 &&
      extra_cfg->bit_depth == BITS_8)
    ERROR("Bit-depth 8 not supported in profile > 1");
John Koleszar's avatar
John Koleszar committed
275 276

  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
277 278 279 280
}


static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
281
                                    const vpx_image_t *img) {
John Koleszar's avatar
John Koleszar committed
282
  switch (img->fmt) {
James Zern's avatar
James Zern committed
283 284
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_I420:
285 286
    case VPX_IMG_FMT_I422:
    case VPX_IMG_FMT_I444:
John Koleszar's avatar
John Koleszar committed
287
      break;
John Koleszar's avatar
John Koleszar committed
288
    default:
289 290
      ERROR("Invalid image format. Only YV12, I420, I422, I444 images are "
            "supported.");
291
      break;
John Koleszar's avatar
John Koleszar committed
292
  }
John Koleszar's avatar
John Koleszar committed
293

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

John Koleszar's avatar
John Koleszar committed
297
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
298 299
}

300 301 302 303 304 305
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;
306
    default: assert(0 && "Invalid image format"); break;
307 308 309
  }
  return 0;
}
John Koleszar's avatar
John Koleszar committed
310

311
static vpx_codec_err_t set_encoder_config(
312
    VP9EncoderConfig *oxcf,
313 314
    const vpx_codec_enc_cfg_t *cfg,
    const struct vp9_extracfg *extra_cfg) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
315
  const int is_vbr = cfg->rc_end_usage == VPX_VBR;
316
  oxcf->profile = cfg->g_profile;
317 318
  oxcf->width   = cfg->g_w;
  oxcf->height  = cfg->g_h;
319
  oxcf->bit_depth = extra_cfg->bit_depth;
320
  // guess a frame rate if out of whack, use 30
321 322 323
  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
324

325
  oxcf->mode = GOOD;
326

327
  switch (cfg->g_pass) {
John Koleszar's avatar
John Koleszar committed
328
    case VPX_RC_ONE_PASS:
329
      oxcf->pass = 0;
John Koleszar's avatar
John Koleszar committed
330
      break;
John Koleszar's avatar
John Koleszar committed
331
    case VPX_RC_FIRST_PASS:
332
      oxcf->pass = 1;
John Koleszar's avatar
John Koleszar committed
333
      break;
John Koleszar's avatar
John Koleszar committed
334
    case VPX_RC_LAST_PASS:
335
      oxcf->pass = 2;
John Koleszar's avatar
John Koleszar committed
336 337 338
      break;
  }

339 340
  oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
                                                         : cfg->g_lag_in_frames;
341
  oxcf->rc_mode = cfg->rc_end_usage;
342

343 344
  // Convert target bandwidth from Kbit/s to Bit/s
  oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
345
  oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
John Koleszar's avatar
John Koleszar committed
346

347 348 349 350
  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);
351
  oxcf->cq_level        = vp9_quantizer_to_qindex(extra_cfg->cq_level);
John Koleszar's avatar
John Koleszar committed
352 353
  oxcf->fixed_q = -1;

354 355 356
  oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;

357 358 359 360
  oxcf->allow_spatial_resampling = cfg->rc_resize_allowed;
  oxcf->scaled_frame_width       = cfg->rc_scaled_width;
  oxcf->scaled_frame_height      = cfg->rc_scaled_height;

Dmitry Kovalev's avatar
Dmitry Kovalev committed
361 362 363
  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
364

365
  oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
John Koleszar's avatar
John Koleszar committed
366

367 368 369
  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;
370

371 372
  oxcf->auto_key               = cfg->kf_mode == VPX_KF_AUTO &&
                                 cfg->kf_min_dist != cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
373

374
  oxcf->key_freq               = cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
375

376
  oxcf->speed                  =  abs(extra_cfg->cpu_used);
377 378 379 380
  oxcf->encode_breakout        =  extra_cfg->static_thresh;
  oxcf->play_alternate         =  extra_cfg->enable_auto_alt_ref;
  oxcf->noise_sensitivity      =  extra_cfg->noise_sensitivity;
  oxcf->sharpness              =  extra_cfg->sharpness;
John Koleszar's avatar
John Koleszar committed
381

382
  oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
John Koleszar's avatar
John Koleszar committed
383

384 385 386 387
#if CONFIG_FP_MB_STATS
  oxcf->firstpass_mb_stats_in  = cfg->rc_firstpass_mb_stats_in;
#endif

388 389
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
  oxcf->arnr_strength   = extra_cfg->arnr_strength;
John Koleszar's avatar
John Koleszar committed
390

391
  oxcf->tuning = extra_cfg->tuning;
392
  oxcf->content = extra_cfg->content;
John Koleszar's avatar
John Koleszar committed
393

394 395
  oxcf->tile_columns = extra_cfg->tile_columns;
  oxcf->tile_rows    = extra_cfg->tile_rows;
396

397 398
  oxcf->error_resilient_mode         = cfg->g_error_resilient;
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
399

400
  oxcf->aq_mode = extra_cfg->aq_mode;
401

402 403
  oxcf->frame_periodic_boost =  extra_cfg->frame_periodic_boost;

404
  oxcf->ss_number_layers = cfg->ss_number_layers;
405

406
  if (oxcf->ss_number_layers > 1) {
407
    int i;
408
    for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
409
      oxcf->ss_target_bitrate[i] =  1000 * cfg->ss_target_bitrate[i];
410
#if CONFIG_SPATIAL_SVC
411 412 413
      oxcf->ss_play_alternate[i] =  cfg->ss_enable_auto_alt_ref[i];
#endif
    }
414
  } else if (oxcf->ss_number_layers == 1) {
Paul Wilkins's avatar
Paul Wilkins committed
415
    oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
416 417
  }

418
  oxcf->ts_number_layers = cfg->ts_number_layers;
419 420

  if (oxcf->ts_number_layers > 1) {
421 422 423 424 425
    int i;
    for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) {
      oxcf->ts_target_bitrate[i] = 1000 * cfg->ts_target_bitrate[i];
      oxcf->ts_rate_decimator[i] = cfg->ts_rate_decimator[i];
    }
426
  } else if (oxcf->ts_number_layers == 1) {
427
    oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
428 429 430
    oxcf->ts_rate_decimator[0] = 1;
  }

John Koleszar's avatar
John Koleszar committed
431
  /*
432 433 434
  printf("Current VP9 Settings: \n");
  printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
  printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
435
  printf("sharpness: %d\n",    oxcf->sharpness);
436
  printf("cpu_used: %d\n",  oxcf->cpu_used);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
437
  printf("Mode: %d\n",     oxcf->mode);
438 439 440 441 442 443 444 445 446 447 448
  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);
449 450 451
  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);
452 453 454 455 456 457 458 459
  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("play_alternate: %d\n", oxcf->play_alternate);
  printf("Version: %d\n", oxcf->Version);
  printf("encode_breakout: %d\n", oxcf->encode_breakout);
  printf("error resilient: %d\n", oxcf->error_resilient_mode);
460 461
  printf("frame parallel detokenization: %d\n",
         oxcf->frame_parallel_decoding_mode);
John Koleszar's avatar
John Koleszar committed
462 463
  */
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
464 465
}

466 467
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
468
  vpx_codec_err_t res;
John Koleszar's avatar
John Koleszar committed
469

470
  if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h)
John Koleszar's avatar
John Koleszar committed
471
    ERROR("Cannot change width or height after initialization");
John Koleszar's avatar
John Koleszar committed
472

473 474 475 476 477
  // 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
478
    ERROR("Cannot increase lag_in_frames");
John Koleszar's avatar
John Koleszar committed
479

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

Adrian Grange's avatar
Adrian Grange committed
482
  if (res == VPX_CODEC_OK) {
John Koleszar's avatar
John Koleszar committed
483
    ctx->cfg = *cfg;
484
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
485
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
486
  }
John Koleszar's avatar
John Koleszar committed
487

John Koleszar's avatar
John Koleszar committed
488
  return res;
John Koleszar's avatar
John Koleszar committed
489 490
}

491 492 493 494 495 496 497 498
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
499

500 501 502
static vpx_codec_err_t ctrl_get_quantizer64(vpx_codec_alg_priv_t *ctx,
                                            va_list args) {
  int *const arg = va_arg(args, int *);
503 504
  if (arg == NULL)
    return VPX_CODEC_INVALID_PARAM;
505 506 507
  *arg = vp9_qindex_to_quantizer(vp9_get_quantizer(ctx->cpi));
  return VPX_CODEC_OK;
}
John Koleszar's avatar
John Koleszar committed
508

509 510 511 512 513 514 515
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
516
  }
517 518
  return res;
}
John Koleszar's avatar
John Koleszar committed
519

520 521 522 523 524
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
525 526
}

527 528 529 530 531 532
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
533

534 535
static vpx_codec_err_t ctrl_set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
                                                  va_list args) {
536
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
537 538 539
  extra_cfg.noise_sensitivity = CAST(VP8E_SET_NOISE_SENSITIVITY, args);
  return update_extra_cfg(ctx, &extra_cfg);
}
John Koleszar's avatar
John Koleszar committed
540

541 542 543 544 545 546
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
547

548 549 550 551 552 553
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
554

555 556 557 558 559 560
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
561

562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
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) {
585 586 587
  (void)ctx;
  (void)args;
  return VPX_CODEC_OK;
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
}

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

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
639
}
640

641 642
static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
643
  vpx_codec_err_t res = VPX_CODEC_OK;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
644
  (void)data;
John Koleszar's avatar
John Koleszar committed
645

Adrian Grange's avatar
Adrian Grange committed
646
  if (ctx->priv == NULL) {
647
    struct vpx_codec_alg_priv *priv = calloc(1, sizeof(*priv));
John Koleszar's avatar
John Koleszar committed
648

649 650
    if (priv == NULL)
      return VPX_CODEC_MEM_ERROR;
651

John Koleszar's avatar
John Koleszar committed
652 653 654 655
    ctx->priv = &priv->base;
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->alg_priv = priv;
    ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
656
    ctx->priv->enc.total_encoders = 1;
John Koleszar's avatar
John Koleszar committed
657 658

    if (ctx->config.enc) {
659
      // Update the reference to the config structure to an internal copy.
John Koleszar's avatar
John Koleszar committed
660 661 662
      ctx->priv->alg_priv->cfg = *ctx->config.enc;
      ctx->config.enc = &ctx->priv->alg_priv->cfg;
    }
663

664
    priv->extra_cfg = default_extra_cfg;
665

666
    vp9_initialize_enc();
John Koleszar's avatar
John Koleszar committed
667

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

Adrian Grange's avatar
Adrian Grange committed
670
    if (res == VPX_CODEC_OK) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
671
      VP9_COMP *cpi;
672
      set_encoder_config(&ctx->priv->alg_priv->oxcf,
673 674
                         &ctx->priv->alg_priv->cfg,
                         &ctx->priv->alg_priv->extra_cfg);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
675
      cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
676
      if (cpi == NULL) {
John Koleszar's avatar
John Koleszar committed
677
        res = VPX_CODEC_MEM_ERROR;
678 679
      } else {
        cpi->output_pkt_list = &priv->pkt_list.head;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
680
        ctx->priv->alg_priv->cpi = cpi;
681
      }
John Koleszar's avatar
John Koleszar committed
682
    }
John Koleszar's avatar
John Koleszar committed
683
  }
John Koleszar's avatar
John Koleszar committed
684

John Koleszar's avatar
John Koleszar committed
685
  return res;
John Koleszar's avatar
John Koleszar committed
686 687
}

688
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
689
  free(ctx->cx_data);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
690
  vp9_remove_compressor(ctx->cpi);
John Koleszar's avatar
John Koleszar committed
691 692
  free(ctx);
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
693 694
}

695
static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
696 697
                                    unsigned long duration,
                                    unsigned long deadline) {
698
  MODE new_mode = BEST;
John Koleszar's avatar
John Koleszar committed
699

700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
  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
722

723 724
  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
725
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
726
  }
John Koleszar's avatar
John Koleszar committed
727 728
}

729 730
// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
731
static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
732
  uint8_t marker = 0xc0;
Yaowu Xu's avatar
Yaowu Xu committed
733 734
  unsigned int mask;
  int mag, index_sz;
John Koleszar's avatar
John Koleszar committed
735 736 737 738

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

739
  // Add the number of frames to the marker byte
John Koleszar's avatar
John Koleszar committed
740 741
  marker |= ctx->pending_frame_count - 1;

742
  // Choose the magnitude
John Koleszar's avatar
John Koleszar committed
743 744 745 746 747 748 749 750
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
    if (ctx->pending_frame_magnitude < mask)
      break;
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

751
  // Write the index
John Koleszar's avatar
John Koleszar committed
752 753 754 755
  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;
756 757 758 759 760 761 762 763 764 765 766 767 768 769
#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
770 771 772

    *x++ = marker;
    for (i = 0; i < ctx->pending_frame_count; i++) {
773
      unsigned int this_sz = (unsigned int)ctx->pending_frame_sizes[i];
John Koleszar's avatar
John Koleszar committed
774 775 776 777 778 779 780 781

      for (j = 0; j <= mag; j++) {
        *x++ = this_sz & 0xff;
        this_sz >>= 8;
      }
    }
    *x++ = marker;
    ctx->pending_cx_data_sz += index_sz;
782 783 784
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    index_sz += index_sz_test;
#endif
John Koleszar's avatar
John Koleszar committed
785
  }
786
  return index_sz;
John Koleszar's avatar
John Koleszar committed
787 788
}

789
// vp9 uses 10,000,000 ticks/second as time stamp
Yaowu Xu's avatar
Yaowu Xu committed
790
#define TICKS_PER_SEC 10000000LL
791 792 793 794 795 796 797 798 799 800 801 802

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

803 804 805 806 807 808
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
809
  vpx_codec_err_t res = VPX_CODEC_OK;
810
  const vpx_rational_t *const timebase = &ctx->cfg.g_timebase;
John Koleszar's avatar
John Koleszar committed
811

812
  if (img != NULL) {
John Koleszar's avatar
John Koleszar committed
813
    res = validate_img(ctx, img);
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
    // TODO(jzern) the checks related to cpi's validity should be treated as a
    // failure condition, encoder setup is done fully in init() currently.
    if (res == VPX_CODEC_OK && ctx->cpi != NULL && ctx->cx_data == NULL) {
      // There's no codec control for multiple alt-refs so check the encoder
      // instance for its status to determine the compressed data size.
      ctx->cx_data_sz = ctx->cfg.g_w * ctx->cfg.g_h *
                        get_image_bps(img) / 8 *
                        (ctx->cpi->multi_arf_allowed ? 8 : 2);
      if (ctx->cx_data_sz < 4096) ctx->cx_data_sz = 4096;

      ctx->cx_data = (unsigned char *)malloc(ctx->cx_data_sz);
      if (ctx->cx_data == NULL) {
        return VPX_CODEC_MEM_ERROR;
      }
    }
  }
John Koleszar's avatar
John Koleszar committed
830

John Koleszar's avatar
John Koleszar committed
831 832
  pick_quickcompress_mode(ctx, duration, deadline);
  vpx_codec_pkt_list_init(&ctx->pkt_list);
John Koleszar's avatar
John Koleszar committed
833

834 835 836
  // 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
837 838 839
    ctx->base.err_detail = "Conflicting flags.";
    return VPX_CODEC_INVALID_PARAM;
  }
John Koleszar's avatar
John Koleszar committed
840

841
  vp9_apply_encoding_flags(ctx->cpi, flags);
John Koleszar's avatar
John Koleszar committed
842

843 844 845
  // 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
846 847 848
    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
849
    }
John Koleszar's avatar
John Koleszar committed
850
  }
John Koleszar's avatar
John Koleszar committed
851

852
  // Initialize the encoder instance on the first frame.
Adrian Grange's avatar
Adrian Grange committed
853
  if (res == VPX_CODEC_OK && ctx->cpi != NULL) {
854
    unsigned int lib_flags = 0;
John Koleszar's avatar
John Koleszar committed
855
    YV12_BUFFER_CONFIG sd;
856 857 858
    int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
    int64_t dst_end_time_stamp =
        timebase_units_to_ticks(timebase, pts + duration);
859
    size_t size, cx_data_sz;
John Koleszar's avatar
John Koleszar committed
860
    unsigned char *cx_data;
John Koleszar's avatar
John Koleszar committed
861

862
    // Set up internal flags
John Koleszar's avatar
John Koleszar committed
863
    if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
864
      ((VP9_COMP *)ctx->cpi)->b_calculate_psnr = 1;
John Koleszar's avatar
John Koleszar committed
865

John Koleszar's avatar
John Koleszar committed
866 867
    if (img != NULL) {
      res = image2yuvconfig(img, &sd);
John Koleszar's avatar
John Koleszar committed
868

869 870 871
      // Store the original flags in to the frame buffer. Will extract the
      // key frame flag when we actually encode this frame.
      if (vp9_receive_raw_frame(ctx->cpi, flags,
John Koleszar's avatar
John Koleszar committed
872
                                &sd, dst_time_stamp, dst_end_time_stamp)) {
873
        VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
John Koleszar's avatar
John Koleszar committed
874 875 876
        res = update_error_state(ctx, &cpi->common.error);
      }
    }
John Koleszar's avatar
John Koleszar committed
877

878 879
    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;
John Koleszar's avatar
John Koleszar committed
880

881 882 883 884 885 886 887 888 889 890 891 892 893 894
    /* 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;
      }
895 896
    }

897 898 899 900
    while (cx_data_sz >= ctx->cx_data_sz / 2 &&
           -1 != vp9_get_compressed_data(ctx->cpi, &lib_flags, &size,
                                         cx_data, &dst_time_stamp,
                                         &dst_end_time_stamp, !img)) {
John Koleszar's avatar
John Koleszar committed
901
      if (size) {
902
        VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;