vp9_cx_iface.c 47.8 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 {
John Koleszar's avatar
John Koleszar committed
24
  struct vpx_codec_pkt_list *pkt_list;
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;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
31
  unsigned int                tile_rows;
32
33
  unsigned int                arnr_max_frames;
  unsigned int                arnr_strength;
34
  unsigned int                arnr_type;
John Koleszar's avatar
John Koleszar committed
35
  vp8e_tuning                 tuning;
36
  unsigned int                cq_level;  // constrained quality level
John Koleszar's avatar
John Koleszar committed
37
  unsigned int                rc_max_intra_bitrate_pct;
John Koleszar's avatar
John Koleszar committed
38
  unsigned int                lossless;
39
  unsigned int                frame_parallel_decoding_mode;
40
  AQ_MODE                     aq_mode;
41
  unsigned int                frame_periodic_boost;
42
  BIT_DEPTH                   bit_depth;
43
  vp9e_tune_content           content;
John Koleszar's avatar
John Koleszar committed
44
45
};

John Koleszar's avatar
John Koleszar committed
46
struct extraconfig_map {
47
  unsigned int usage;
48
  struct vp9_extracfg cfg;
John Koleszar's avatar
John Koleszar committed
49
50
};

John Koleszar's avatar
John Koleszar committed
51
52
53
static const struct extraconfig_map extracfg_map[] = {
  {
    0,
54
    { // NOLINT
John Koleszar's avatar
John Koleszar committed
55
      NULL,
56
57
58
59
60
61
62
63
64
      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
65
      3,                          // arnr_type
66
67
68
69
70
71
      VP8_TUNE_PSNR,              // tuning
      10,                         // cq_level
      0,                          // rc_max_intra_bitrate_pct
      0,                          // lossless
      0,                          // frame_parallel_decoding_mode
      NO_AQ,                      // aq_mode
72
      0,                          // frame_periodic_delta_q
73
      BITS_8,                     // Bit depth
74
      VP9E_CONTENT_DEFAULT        // content
John Koleszar's avatar
John Koleszar committed
75
    }
John Koleszar's avatar
John Koleszar committed
76
  }
John Koleszar's avatar
John Koleszar committed
77
78
};

John Koleszar's avatar
John Koleszar committed
79
80
81
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_enc_cfg_t     cfg;
82
  struct vp9_extracfg     extra_cfg;
83
  VP9EncoderConfig        oxcf;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
84
  VP9_COMP               *cpi;
John Koleszar's avatar
John Koleszar committed
85
  unsigned char          *cx_data;
86
  size_t                  cx_data_sz;
87
  unsigned char          *pending_cx_data;
88
  size_t                  pending_cx_data_sz;
John Koleszar's avatar
John Koleszar committed
89
  int                     pending_frame_count;
90
91
  size_t                  pending_frame_sizes[8];
  size_t                  pending_frame_magnitude;
John Koleszar's avatar
John Koleszar committed
92
93
  vpx_image_t             preview_img;
  vp8_postproc_cfg_t      preview_ppcfg;
94
  vpx_codec_pkt_list_decl(256) pkt_list;
95
  unsigned int                 fixed_kf_cntr;
John Koleszar's avatar
John Koleszar committed
96
97
};

98
static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
99
100
101
102
103
104
105
106
  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
107
  assert(0 && "Invalid Reference Frame");
108
109
  return VP9_LAST_FLAG;
}
John Koleszar's avatar
John Koleszar committed
110

111
112
113
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
114

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

John Koleszar's avatar
John Koleszar committed
118
  return res;
John Koleszar's avatar
John Koleszar committed
119
120
121
}


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

128
129
#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
130
      ERROR(#memb " out of range ["#lo".."#hi"]");\
131
  } while (0)
John Koleszar's avatar
John Koleszar committed
132

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

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

143
144
145
#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
146

147
static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
John Koleszar's avatar
John Koleszar committed
148
                                       const vpx_codec_enc_cfg_t *cfg,
149
                                       const struct vp9_extracfg *extra_cfg) {
150
151
  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
152
153
154
  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
155

John Koleszar's avatar
John Koleszar committed
156
157
  RANGE_CHECK_HI(cfg, rc_max_quantizer,   63);
  RANGE_CHECK_HI(cfg, rc_min_quantizer,   cfg->rc_max_quantizer);
158
159
  RANGE_CHECK_BOOL(extra_cfg, lossless);
  RANGE_CHECK(extra_cfg, aq_mode,           0, AQ_MODE_COUNT - 1);
160
  RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
John Koleszar's avatar
John Koleszar committed
161
162
  RANGE_CHECK_HI(cfg, g_threads,          64);
  RANGE_CHECK_HI(cfg, g_lag_in_frames,    MAX_LAG_BUFFERS);
163
  RANGE_CHECK(cfg, rc_end_usage,          VPX_VBR, VPX_Q);
John Koleszar's avatar
John Koleszar committed
164
165
166
167
168
169
170
171
172
173
  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);

174
175
176
177
178
  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);
  }

179
  RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
180

181
#if CONFIG_SPATIAL_SVC
182
  if (cfg->ss_number_layers > 1) {
183
    unsigned int i, alt_ref_sum = 0;
184
185
186
187
188
189
190
191
192
    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");
  }
#endif

193
194
  RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
  if (cfg->ts_number_layers > 1) {
195
    unsigned int i;
196
197
    for (i = 1; i < cfg->ts_number_layers; ++i)
      if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1])
198
        ERROR("ts_target_bitrate entries are not increasing");
199
200
201
202

    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])
203
204
205
        ERROR("ts_rate_decimator factors are not powers of 2");
  }

206
  // VP9 does not support a lower bound on the keyframe interval in
207
208
209
210
  // 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
211
212
213
    ERROR("kf_min_dist not supported in auto mode, use 0 "
          "or kf_max_dist instead.");

214
215
216
217
218
219
220
221
  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);
222
  RANGE_CHECK(extra_cfg, arnr_type, 1, 3);
223
  RANGE_CHECK(extra_cfg, cq_level, 0, 63);
224
225
  RANGE_CHECK(extra_cfg, content,
              VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1);
John Koleszar's avatar
John Koleszar committed
226

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

John Koleszar's avatar
John Koleszar committed
231
  if (cfg->g_pass == VPX_RC_LAST_PASS) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
232
233
    const size_t packet_sz = sizeof(FIRSTPASS_STATS);
    const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
234
    const FIRSTPASS_STATS *stats;
John Koleszar's avatar
John Koleszar committed
235

Adrian Grange's avatar
Adrian Grange committed
236
    if (cfg->rc_twopass_stats_in.buf == NULL)
John Koleszar's avatar
John Koleszar committed
237
238
239
240
241
      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.");

242
243
244
245
246
247
    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) {
248
        const int layer_id = (int)stats[i].spatial_layer_id;
249
250
251
252
253
254
255
256
257
258
259
        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
260

261
262
        stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf +
                n_packets - cfg->ss_number_layers + i;
263
        layer_id = (int)stats->spatial_layer_id;
John Koleszar's avatar
John Koleszar committed
264

265
        if (layer_id >= cfg->ss_number_layers
266
267
            ||(unsigned int)(stats->count + 0.5) !=
               n_packets_per_layer[layer_id] - 1)
268
269
270
271
272
273
274
275
276
277
278
279
          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
280
  }
281

282
283
284
285
286
287
  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
288
289

  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
290
291
292
293
}


static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
294
                                    const vpx_image_t *img) {
John Koleszar's avatar
John Koleszar committed
295
  switch (img->fmt) {
James Zern's avatar
James Zern committed
296
297
    case VPX_IMG_FMT_YV12:
    case VPX_IMG_FMT_I420:
298
299
    case VPX_IMG_FMT_I422:
    case VPX_IMG_FMT_I444:
John Koleszar's avatar
John Koleszar committed
300
      break;
John Koleszar's avatar
John Koleszar committed
301
    default:
302
303
      ERROR("Invalid image format. Only YV12, I420, I422, I444 images are "
            "supported.");
304
      break;
John Koleszar's avatar
John Koleszar committed
305
  }
John Koleszar's avatar
John Koleszar committed
306

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

John Koleszar's avatar
John Koleszar committed
310
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
311
312
}

313
314
315
316
317
318
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;
319
    default: assert(0 && "Invalid image format"); break;
320
321
322
  }
  return 0;
}
John Koleszar's avatar
John Koleszar committed
323

324
static vpx_codec_err_t set_encoder_config(
325
    VP9EncoderConfig *oxcf,
326
327
328
    const vpx_codec_enc_cfg_t *cfg,
    const struct vp9_extracfg *extra_cfg) {
  oxcf->profile = cfg->g_profile;
329
330
  oxcf->width   = cfg->g_w;
  oxcf->height  = cfg->g_h;
331
  oxcf->bit_depth = extra_cfg->bit_depth;
332
  // guess a frame rate if out of whack, use 30
333
334
335
  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
336

337
338
  oxcf->mode = BEST;

339
  switch (cfg->g_pass) {
John Koleszar's avatar
John Koleszar committed
340
    case VPX_RC_ONE_PASS:
341
      oxcf->pass = 0;
John Koleszar's avatar
John Koleszar committed
342
      break;
John Koleszar's avatar
John Koleszar committed
343
    case VPX_RC_FIRST_PASS:
344
      oxcf->pass = 1;
John Koleszar's avatar
John Koleszar committed
345
      break;
John Koleszar's avatar
John Koleszar committed
346
    case VPX_RC_LAST_PASS:
347
      oxcf->pass = 2;
John Koleszar's avatar
John Koleszar committed
348
349
350
      break;
  }

351
352
  oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
                                                         : cfg->g_lag_in_frames;
353
  oxcf->rc_mode = cfg->rc_end_usage;
354

355
356
  // Convert target bandwidth from Kbit/s to Bit/s
  oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
357
  oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
John Koleszar's avatar
John Koleszar committed
358

359
360
361
362
  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);
363
  oxcf->cq_level        = vp9_quantizer_to_qindex(extra_cfg->cq_level);
John Koleszar's avatar
John Koleszar committed
364
365
  oxcf->fixed_q = -1;

366
367
368
  oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;

369
370
371
372
  oxcf->allow_spatial_resampling = cfg->rc_resize_allowed;
  oxcf->scaled_frame_width       = cfg->rc_scaled_width;
  oxcf->scaled_frame_height      = cfg->rc_scaled_height;

373
374
375
  oxcf->maximum_buffer_size_ms   = cfg->rc_buf_sz;
  oxcf->starting_buffer_level_ms = cfg->rc_buf_initial_sz;
  oxcf->optimal_buffer_level_ms  = cfg->rc_buf_optimal_sz;
John Koleszar's avatar
John Koleszar committed
376

377
  oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
John Koleszar's avatar
John Koleszar committed
378

379
380
381
  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;
382

383
384
  oxcf->auto_key               = cfg->kf_mode == VPX_KF_AUTO &&
                                 cfg->kf_min_dist != cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
385

386
  oxcf->key_freq               = cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
387

388
  oxcf->speed                  =  abs(extra_cfg->cpu_used);
389
390
391
392
  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
393

394
395
  oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
  oxcf->output_pkt_list        =  extra_cfg->pkt_list;
John Koleszar's avatar
John Koleszar committed
396

397
398
399
400
#if CONFIG_FP_MB_STATS
  oxcf->firstpass_mb_stats_in  = cfg->rc_firstpass_mb_stats_in;
#endif

401
402
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
  oxcf->arnr_strength   = extra_cfg->arnr_strength;
403
  oxcf->arnr_type       = extra_cfg->arnr_type;
John Koleszar's avatar
John Koleszar committed
404

405
  oxcf->tuning = extra_cfg->tuning;
406
  oxcf->content = extra_cfg->content;
John Koleszar's avatar
John Koleszar committed
407

408
409
  oxcf->tile_columns = extra_cfg->tile_columns;
  oxcf->tile_rows    = extra_cfg->tile_rows;
410

411
412
  oxcf->error_resilient_mode         = cfg->g_error_resilient;
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
413

414
  oxcf->aq_mode = extra_cfg->aq_mode;
415

416
417
  oxcf->frame_periodic_boost =  extra_cfg->frame_periodic_boost;

418
  oxcf->ss_number_layers = cfg->ss_number_layers;
419

420
  if (oxcf->ss_number_layers > 1) {
421
    int i;
422
    for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
423
      oxcf->ss_target_bitrate[i] =  1000 * cfg->ss_target_bitrate[i];
424
#if CONFIG_SPATIAL_SVC
425
426
427
      oxcf->ss_play_alternate[i] =  cfg->ss_enable_auto_alt_ref[i];
#endif
    }
428
  } else if (oxcf->ss_number_layers == 1) {
Paul Wilkins's avatar
Paul Wilkins committed
429
    oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
430
431
  }

432
  oxcf->ts_number_layers = cfg->ts_number_layers;
433
434

  if (oxcf->ts_number_layers > 1) {
435
436
437
438
439
    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];
    }
440
  } else if (oxcf->ts_number_layers == 1) {
441
    oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
442
443
444
    oxcf->ts_rate_decimator[0] = 1;
  }

John Koleszar's avatar
John Koleszar committed
445
  /*
446
447
448
  printf("Current VP9 Settings: \n");
  printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
  printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
449
  printf("sharpness: %d\n",    oxcf->sharpness);
450
  printf("cpu_used: %d\n",  oxcf->cpu_used);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
451
  printf("Mode: %d\n",     oxcf->mode);
452
453
454
455
456
457
458
459
460
461
462
  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);
463
464
465
  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);
466
467
468
469
470
471
472
473
  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);
474
475
  printf("frame parallel detokenization: %d\n",
         oxcf->frame_parallel_decoding_mode);
John Koleszar's avatar
John Koleszar committed
476
477
  */
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
478
479
}

480
481
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
482
  vpx_codec_err_t res;
John Koleszar's avatar
John Koleszar committed
483

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

487
488
489
490
491
  // 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
492
    ERROR("Cannot increase lag_in_frames");
John Koleszar's avatar
John Koleszar committed
493

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

Adrian Grange's avatar
Adrian Grange committed
496
  if (res == VPX_CODEC_OK) {
John Koleszar's avatar
John Koleszar committed
497
    ctx->cfg = *cfg;
498
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
499
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
500
  }
John Koleszar's avatar
John Koleszar committed
501

John Koleszar's avatar
John Koleszar committed
502
  return res;
John Koleszar's avatar
John Koleszar committed
503
504
}

505
506
507
508
509
510
511
512
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
513

514
515
516
static vpx_codec_err_t ctrl_get_quantizer64(vpx_codec_alg_priv_t *ctx,
                                            va_list args) {
  int *const arg = va_arg(args, int *);
517
518
  if (arg == NULL)
    return VPX_CODEC_INVALID_PARAM;
519
520
521
  *arg = vp9_qindex_to_quantizer(vp9_get_quantizer(ctx->cpi));
  return VPX_CODEC_OK;
}
John Koleszar's avatar
John Koleszar committed
522

523
524
525
526
527
528
529
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
530
  }
531
532
  return res;
}
John Koleszar's avatar
John Koleszar committed
533

534
535
536
537
538
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
539
540
}

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

548
549
static vpx_codec_err_t ctrl_set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
                                                  va_list args) {
550
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
551
552
553
  extra_cfg.noise_sensitivity = CAST(VP8E_SET_NOISE_SENSITIVITY, 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_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
561

562
563
564
565
566
567
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
568

569
570
571
572
573
574
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
575

576
577
578
579
580
581
582
583
584
585
586
587
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
639
640
641
642
643
644
645
646
647
648
649
650
651
652
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) {
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
  extra_cfg.arnr_type = CAST(VP8E_SET_ARNR_TYPE, args);
  return update_extra_cfg(ctx, &extra_cfg);
}

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
653
}
654

655
656
static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
657
  vpx_codec_err_t res = VPX_CODEC_OK;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
658
  (void)data;
John Koleszar's avatar
John Koleszar committed
659

Adrian Grange's avatar
Adrian Grange committed
660
  if (ctx->priv == NULL) {
661
662
663
    int i;
    vpx_codec_enc_cfg_t *cfg;
    struct vpx_codec_alg_priv *priv = calloc(1, sizeof(*priv));
John Koleszar's avatar
John Koleszar committed
664

665
666
    if (priv == NULL)
      return VPX_CODEC_MEM_ERROR;
667

John Koleszar's avatar
John Koleszar committed
668
669
670
671
672
    ctx->priv = &priv->base;
    ctx->priv->sz = sizeof(*ctx->priv);
    ctx->priv->iface = ctx->iface;
    ctx->priv->alg_priv = priv;
    ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
673
    ctx->priv->enc.total_encoders = 1;
John Koleszar's avatar
John Koleszar committed
674
675

    if (ctx->config.enc) {
676
      // Update the reference to the config structure to an internal copy.
John Koleszar's avatar
John Koleszar committed
677
678
679
      ctx->priv->alg_priv->cfg = *ctx->config.enc;
      ctx->config.enc = &ctx->priv->alg_priv->cfg;
    }
680

681
    cfg = &ctx->priv->alg_priv->cfg;
John Koleszar's avatar
John Koleszar committed
682

683
684
685
    // Select the extra vp6 configuration table based on the current
    // usage value. If the current usage value isn't found, use the
    // values for usage case 0.
John Koleszar's avatar
John Koleszar committed
686
687
    for (i = 0;
         extracfg_map[i].usage && extracfg_map[i].usage != cfg->g_usage;
688
         ++i) {}
John Koleszar's avatar
John Koleszar committed
689

690
691
    priv->extra_cfg = extracfg_map[i].cfg;
    priv->extra_cfg.pkt_list = &priv->pkt_list.head;
692

693
    vp9_initialize_enc();
John Koleszar's avatar
John Koleszar committed
694

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

Adrian Grange's avatar
Adrian Grange committed
697
    if (res == VPX_CODEC_OK) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
698
      VP9_COMP *cpi;
699
      set_encoder_config(&ctx->priv->alg_priv->oxcf,
700
701
                         &ctx->priv->alg_priv->cfg,
                         &ctx->priv->alg_priv->extra_cfg);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
702
703
      cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
      if (cpi == NULL)
John Koleszar's avatar
John Koleszar committed
704
705
        res = VPX_CODEC_MEM_ERROR;
      else
Dmitry Kovalev's avatar
Dmitry Kovalev committed
706
        ctx->priv->alg_priv->cpi = cpi;
John Koleszar's avatar
John Koleszar committed
707
    }
John Koleszar's avatar
John Koleszar committed
708
  }
John Koleszar's avatar
John Koleszar committed
709

John Koleszar's avatar
John Koleszar committed
710
  return res;
John Koleszar's avatar
John Koleszar committed
711
712
}

713
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
714
  free(ctx->cx_data);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
715
  vp9_remove_compressor(ctx->cpi);
John Koleszar's avatar
John Koleszar committed
716
717
  free(ctx);
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
718
719
}

720
static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
721
722
                                    unsigned long duration,
                                    unsigned long deadline) {
723
  MODE new_mode = BEST;
John Koleszar's avatar
John Koleszar committed
724

725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  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
747

748
749
  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
750
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
751
  }
John Koleszar's avatar
John Koleszar committed
752
753
}

754
755
// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
756
static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
757
  uint8_t marker = 0xc0;
Yaowu Xu's avatar
Yaowu Xu committed
758
759
  unsigned int mask;
  int mag, index_sz;
John Koleszar's avatar
John Koleszar committed
760
761
762
763

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

764
  // Add the number of frames to the marker byte
John Koleszar's avatar
John Koleszar committed
765
766
  marker |= ctx->pending_frame_count - 1;

767
  // Choose the magnitude
John Koleszar's avatar
John Koleszar committed
768
769
770
771
772
773
774
775
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
    if (ctx->pending_frame_magnitude < mask)
      break;
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

776
  // Write the index
John Koleszar's avatar
John Koleszar committed
777
778
779
780
  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;
781
782
783
784
785
786
787
788
789
790
791
792
793
794
#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
795
796
797

    *x++ = marker;
    for (i = 0; i < ctx->pending_frame_count; i++) {
798
      unsigned int this_sz = (unsigned int)ctx->pending_frame_sizes[i];
John Koleszar's avatar
John Koleszar committed
799
800
801
802
803
804
805
806

      for (j = 0; j <= mag; j++) {
        *x++ = this_sz & 0xff;
        this_sz >>= 8;
      }
    }
    *x++ = marker;
    ctx->pending_cx_data_sz += index_sz;
807
808
809
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    index_sz += index_sz_test;
#endif
John Koleszar's avatar
John Koleszar committed
810
  }
811
  return index_sz;
John Koleszar's avatar
John Koleszar committed
812
813
}

814
// vp9 uses 10,000,000 ticks/second as time stamp
Yaowu Xu's avatar
Yaowu Xu committed
815
#define TICKS_PER_SEC 10000000LL
816
817
818
819
820
821
822
823
824
825
826
827

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

828
829
830
831
832
833
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
834
  vpx_codec_err_t res = VPX_CODEC_OK;
835
  const vpx_rational_t *const timebase = &ctx->cfg.g_timebase;
John Koleszar's avatar
John Koleszar committed
836

837
  if (img != NULL) {
John Koleszar's avatar
John Koleszar committed
838
    res = validate_img(ctx, img);
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
    // 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
855

John Koleszar's avatar
John Koleszar committed
856
857
  pick_quickcompress_mode(ctx, duration, deadline);
  vpx_codec_pkt_list_init(&ctx->pkt_list);
John Koleszar's avatar
John Koleszar committed
858

859
860
861
  // 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
862
863
864
    ctx->base.err_detail = "Conflicting flags.";
    return VPX_CODEC_INVALID_PARAM;
  }
John Koleszar's avatar
John Koleszar committed
865

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

868
869
870
  // 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
871
872
873
    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
874
    }
John Koleszar's avatar
John Koleszar committed
875
  }
John Koleszar's avatar
John Koleszar committed
876

877
  // Initialize the encoder instance on the first frame.
Adrian Grange's avatar
Adrian Grange committed
878
  if (res == VPX_CODEC_OK && ctx->cpi != NULL) {
879
    unsigned int lib_flags = 0;
John Koleszar's avatar
John Koleszar committed
880
    YV12_BUFFER_CONFIG sd;
881
882
883
    int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
    int64_t dst_end_time_stamp =
        timebase_units_to_ticks(timebase, pts + duration);
884
    size_t size, cx_data_sz;
John Koleszar's avatar
John Koleszar committed
885
    unsigned char *cx_data;
John Koleszar's avatar
John Koleszar committed
886

887
    // Set up internal flags
John Koleszar's avatar
John Koleszar committed
888
    if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
889
      ((VP9_COMP *)ctx->cpi)->b_calculate_psnr = 1;
John Koleszar's avatar
John Koleszar committed
890

John Koleszar's avatar
John Koleszar committed
891
892
    if (img != NULL) {
      res = image2yuvconfig(img, &sd);
John Koleszar's avatar
John Koleszar committed
893

894
895
896
      // 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
897
                                &sd, dst_time_stamp, dst_end_time_stamp)) {
898
        VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
John Koleszar's avatar
John Koleszar committed
899
900
901
        res = update_error_state(ctx, &cpi->common.error);
      }
    }
John Koleszar's avatar
John Koleszar committed
902

903
904
    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;
John Koleszar's avatar
John Koleszar committed
905

906
907
908
909
910
911
912
913
914
915
916
917
918
919
    /* 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;
      }
920
921
    }

922
923
924
925
    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
926
      if (size) {
927
        VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
928
        vpx_codec_cx_pkt_t pkt;
John Koleszar's avatar
John Koleszar committed
929

930
#if CONFIG_SPATIAL_SVC
931
        if (is_spatial_svc(cpi))
932
933
934
          cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size;
#endif

935
        // Pack invisible frames with the next visible frame
936
        if (cpi->common.show_frame == 0
937
#if CONFIG_SPATIAL_SVC
938
            || (is_spatial_svc(cpi) &&
939
940
941
                cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
#endif
            ) {
Adrian Grange's avatar
Adrian Grange committed
942
          if (ctx->pending_cx_data == 0)
943
944
            ctx->pending_cx_data = cx_data;
          ctx->pending_cx_data_sz += size;
John Koleszar's avatar
John Koleszar committed
945
946
          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
          ctx->pending_frame_magnitude |= size;
947
948
949
950
951
          cx_data += size;
          cx_data_sz -= size;
          continue;
        }

952
        // Add the frame packet to the list of returned packets.
John Koleszar's avatar
John Koleszar committed
953
        pkt.kind = VPX_CODEC_CX_FRAME_PKT;
954
955
956
957
        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);
John Koleszar's avatar
John Koleszar committed
958
959
        pkt.data.frame.flags = lib_flags << 16;

960
        if (lib_flags & FRAMEFLAGS_KEY
961
#if CONFIG_SPATIAL_SVC
962
            || (is_spatial_svc(cpi) &&
963
964
965
                cpi->svc.layer_context[0].is_key_frame)
#endif
            )
John Koleszar's avatar
John Koleszar committed
966
967
          pkt.data.frame.flags |= VPX_FRAME_IS_KEY;

Adrian Grange's avatar
Adrian Grange committed
968
        if (cpi->common.show_frame == 0) {
John Koleszar's avatar
John Koleszar committed
969
970
971
972
973
974
          pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE;

          // This timestamp should be as close as possible to the
          // prior PTS so that if a decoder uses pts to schedule when
          // to do this, we start right after last frame was decoded.
          // Invisible frames have no duration.
975
976
          pkt.data.frame.pts =
              ticks_to_timebase_units(timebase, cpi->last_time_stamp_seen) + 1;
John Koleszar's avatar
John Koleszar committed
977
          pkt.data.frame.duration = 0;
John Koleszar's avatar
John Koleszar committed
978
979
        }

John Koleszar's avatar
John Koleszar committed
980
981
        if (cpi->droppable)
          pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE;
John Koleszar's avatar
John Koleszar committed
982

983
984
985
986
987
988
989
990
991
992
993
994