vp9_cx_iface.c 47.7 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
  vpx_bit_depth_t             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
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
61
  VPX_BITS_8,                 // Bit depth
62
  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
  RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
167

168
  if (cfg->ts_number_layers > 1) {
169
    unsigned int i;
170
171
    for (i = 1; i < cfg->ts_number_layers; ++i)
      if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1])
172
        ERROR("ts_target_bitrate entries are not increasing");
173
174
175
176

    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])
177
178
179
        ERROR("ts_rate_decimator factors are not powers of 2");
  }

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#if CONFIG_SPATIAL_SVC
  if (cfg->ss_number_layers * cfg->ts_number_layers > REF_FRAMES)
    ERROR("Too many layers. Maximum 8 layers could be set");

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

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

210
211
212
213
214
215
216
217
218
  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);
219
220
  RANGE_CHECK(cfg, g_bit_depth, VPX_BITS_8, VPX_BITS_12);
  RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
221
222
  RANGE_CHECK(extra_cfg, content,
              VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1);
John Koleszar's avatar
John Koleszar committed
223

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

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

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

239
    if (cfg->ss_number_layers > 1 || cfg->ts_number_layers > 1) {
240
241
242
243
244
      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) {
245
        const int layer_id = (int)stats[i].spatial_layer_id;
246
247
248
249
250
251
252
253
254
255
256
        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
257

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

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

279
280
281
282
#if !CONFIG_VP9_HIGHBITDEPTH
  if (cfg->g_profile > (unsigned int)PROFILE_1)
    ERROR("Profile > 1 not supported in this build configuration");
#endif
283
  if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
284
285
      extra_cfg->bit_depth > VPX_BITS_8)
    ERROR("Codec high bit-depth not supported in profile < 2");
286
  if (cfg->g_profile > (unsigned int)PROFILE_1 &&
287
288
      extra_cfg->bit_depth == VPX_BITS_8)
    ERROR("Codec bit-depth 8 not supported in profile > 1");
John Koleszar's avatar
John Koleszar committed
289
290

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


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

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

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

314
315
316
317
318
319
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;
320
321
322
    case VPX_IMG_FMT_I42016: return 24;
    case VPX_IMG_FMT_I42216: return 32;
    case VPX_IMG_FMT_I44416: return 48;
323
    default: assert(0 && "Invalid image format"); break;
324
325
326
  }
  return 0;
}
John Koleszar's avatar
John Koleszar committed
327

328
static vpx_codec_err_t set_encoder_config(
329
    VP9EncoderConfig *oxcf,
330
331
    const vpx_codec_enc_cfg_t *cfg,
    const struct vp9_extracfg *extra_cfg) {
Dmitry Kovalev's avatar
Dmitry Kovalev committed
332
  const int is_vbr = cfg->rc_end_usage == VPX_VBR;
333
  oxcf->profile = cfg->g_profile;
334
335
  oxcf->width   = cfg->g_w;
  oxcf->height  = cfg->g_h;
336
  oxcf->bit_depth = extra_cfg->bit_depth;
337
  oxcf->input_bit_depth = cfg->g_input_bit_depth;
338
  // guess a frame rate if out of whack, use 30
339
340
341
  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
342

343
  oxcf->mode = GOOD;
344

345
  switch (cfg->g_pass) {
John Koleszar's avatar
John Koleszar committed
346
    case VPX_RC_ONE_PASS:
347
      oxcf->pass = 0;
John Koleszar's avatar
John Koleszar committed
348
      break;
John Koleszar's avatar
John Koleszar committed
349
    case VPX_RC_FIRST_PASS:
350
      oxcf->pass = 1;
John Koleszar's avatar
John Koleszar committed
351
      break;
John Koleszar's avatar
John Koleszar committed
352
    case VPX_RC_LAST_PASS:
353
      oxcf->pass = 2;
John Koleszar's avatar
John Koleszar committed
354
355
356
      break;
  }

357
358
  oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
                                                         : cfg->g_lag_in_frames;
359
  oxcf->rc_mode = cfg->rc_end_usage;
360

361
362
  // Convert target bandwidth from Kbit/s to Bit/s
  oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
363
  oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
John Koleszar's avatar
John Koleszar committed
364

365
366
367
368
  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);
369
  oxcf->cq_level        = vp9_quantizer_to_qindex(extra_cfg->cq_level);
John Koleszar's avatar
John Koleszar committed
370
371
  oxcf->fixed_q = -1;

372
373
374
  oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
  oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;

375
376
377
378
  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
379
380
381
  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
382

383
  oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
John Koleszar's avatar
John Koleszar committed
384

385
386
387
  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;
388

389
390
  oxcf->auto_key               = cfg->kf_mode == VPX_KF_AUTO &&
                                 cfg->kf_min_dist != cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
391

392
  oxcf->key_freq               = cfg->kf_max_dist;
John Koleszar's avatar
John Koleszar committed
393

394
  oxcf->speed                  =  abs(extra_cfg->cpu_used);
395
396
397
398
  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
399

400
  oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
John Koleszar's avatar
John Koleszar committed
401

402
403
404
405
#if CONFIG_FP_MB_STATS
  oxcf->firstpass_mb_stats_in  = cfg->rc_firstpass_mb_stats_in;
#endif

406
407
  oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
  oxcf->arnr_strength   = extra_cfg->arnr_strength;
John Koleszar's avatar
John Koleszar committed
408

409
  oxcf->tuning = extra_cfg->tuning;
410
  oxcf->content = extra_cfg->content;
John Koleszar's avatar
John Koleszar committed
411

412
413
  oxcf->tile_columns = extra_cfg->tile_columns;
  oxcf->tile_rows    = extra_cfg->tile_rows;
414

415
416
  oxcf->error_resilient_mode         = cfg->g_error_resilient;
  oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
417

418
  oxcf->aq_mode = extra_cfg->aq_mode;
419

420
421
  oxcf->frame_periodic_boost =  extra_cfg->frame_periodic_boost;

422
  oxcf->ss_number_layers = cfg->ss_number_layers;
423

424
  if (oxcf->ss_number_layers > 1) {
425
    int i;
426
    for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
427
      oxcf->ss_target_bitrate[i] =  1000 * cfg->ss_target_bitrate[i];
428
#if CONFIG_SPATIAL_SVC
429
430
431
      oxcf->ss_play_alternate[i] =  cfg->ss_enable_auto_alt_ref[i];
#endif
    }
432
  } else if (oxcf->ss_number_layers == 1) {
Paul Wilkins's avatar
Paul Wilkins committed
433
    oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
434
435
436
#if CONFIG_SPATIAL_SVC
    oxcf->ss_play_alternate[0] = extra_cfg->enable_auto_alt_ref;
#endif
437
438
  }

439
  oxcf->ts_number_layers = cfg->ts_number_layers;
440
441

  if (oxcf->ts_number_layers > 1) {
442
443
444
445
446
    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];
    }
447
  } else if (oxcf->ts_number_layers == 1) {
448
    oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
449
450
451
    oxcf->ts_rate_decimator[0] = 1;
  }

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

487
488
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
489
  vpx_codec_err_t res;
John Koleszar's avatar
John Koleszar committed
490

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

494
495
496
497
498
  // 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
499
    ERROR("Cannot increase lag_in_frames");
John Koleszar's avatar
John Koleszar committed
500

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

Adrian Grange's avatar
Adrian Grange committed
503
  if (res == VPX_CODEC_OK) {
John Koleszar's avatar
John Koleszar committed
504
    ctx->cfg = *cfg;
505
    set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
506
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
507
  }
John Koleszar's avatar
John Koleszar committed
508

John Koleszar's avatar
John Koleszar committed
509
  return res;
John Koleszar's avatar
John Koleszar committed
510
511
}

512
513
514
515
516
517
518
519
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
520

521
522
523
static vpx_codec_err_t ctrl_get_quantizer64(vpx_codec_alg_priv_t *ctx,
                                            va_list args) {
  int *const arg = va_arg(args, int *);
524
525
  if (arg == NULL)
    return VPX_CODEC_INVALID_PARAM;
526
527
528
  *arg = vp9_qindex_to_quantizer(vp9_get_quantizer(ctx->cpi));
  return VPX_CODEC_OK;
}
John Koleszar's avatar
John Koleszar committed
529

530
531
532
533
534
535
536
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
537
  }
538
539
  return res;
}
John Koleszar's avatar
John Koleszar committed
540

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

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

555
556
static vpx_codec_err_t ctrl_set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
                                                  va_list args) {
557
  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
558
  extra_cfg.noise_sensitivity = CAST(VP9E_SET_NOISE_SENSITIVITY, args);
559
560
  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_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
568

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

576
577
578
579
580
581
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
582

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
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) {
606
607
608
  (void)ctx;
  (void)args;
  return VPX_CODEC_OK;
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
653
654
655
656
657
658
659
}

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
660
}
661

662
663
static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
                                    vpx_codec_priv_enc_mr_cfg_t *data) {
664
  vpx_codec_err_t res = VPX_CODEC_OK;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
665
  (void)data;
John Koleszar's avatar
John Koleszar committed
666

Adrian Grange's avatar
Adrian Grange committed
667
  if (ctx->priv == NULL) {
668
669
    vpx_codec_alg_priv_t *const priv = vpx_calloc(1, sizeof(*priv));
    if (priv == NULL)
670
      return VPX_CODEC_MEM_ERROR;
671

672
    ctx->priv = (vpx_codec_priv_t *)priv;
John Koleszar's avatar
John Koleszar committed
673
    ctx->priv->init_flags = ctx->init_flags;
John Koleszar's avatar
John Koleszar committed
674
    ctx->priv->enc.total_encoders = 1;
John Koleszar's avatar
John Koleszar committed
675
676

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

682
    priv->extra_cfg = default_extra_cfg;
683
    vp9_initialize_enc();
John Koleszar's avatar
John Koleszar committed
684

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

Adrian Grange's avatar
Adrian Grange committed
687
    if (res == VPX_CODEC_OK) {
688
      set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
689
690
691
692
#if CONFIG_VP9_HIGHBITDEPTH
      priv->oxcf.use_highbitdepth =
          (ctx->init_flags & VPX_CODEC_USE_HIGHBITDEPTH) ? 1 : 0;
#endif
693
694
      priv->cpi = vp9_create_compressor(&priv->oxcf);
      if (priv->cpi == NULL)
John Koleszar's avatar
John Koleszar committed
695
        res = VPX_CODEC_MEM_ERROR;
696
      else
697
        priv->cpi->output_pkt_list = &priv->pkt_list.head;
John Koleszar's avatar
John Koleszar committed
698
    }
John Koleszar's avatar
John Koleszar committed
699
  }
John Koleszar's avatar
John Koleszar committed
700

John Koleszar's avatar
John Koleszar committed
701
  return res;
John Koleszar's avatar
John Koleszar committed
702
703
}

704
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
705
  free(ctx->cx_data);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
706
  vp9_remove_compressor(ctx->cpi);
707
  vpx_free(ctx);
John Koleszar's avatar
John Koleszar committed
708
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
709
710
}

711
static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
712
713
                                    unsigned long duration,
                                    unsigned long deadline) {
714
  MODE new_mode = BEST;
John Koleszar's avatar
John Koleszar committed
715

716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  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
738

739
740
  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
741
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
742
  }
John Koleszar's avatar
John Koleszar committed
743
744
}

745
746
// Turn on to test if supplemental superframe data breaks decoding
// #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
747
static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
748
  uint8_t marker = 0xc0;
Yaowu Xu's avatar
Yaowu Xu committed
749
750
  unsigned int mask;
  int mag, index_sz;
John Koleszar's avatar
John Koleszar committed
751
752
753
754

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

755
  // Add the number of frames to the marker byte
John Koleszar's avatar
John Koleszar committed
756
757
  marker |= ctx->pending_frame_count - 1;

758
  // Choose the magnitude
John Koleszar's avatar
John Koleszar committed
759
760
761
762
763
764
765
766
  for (mag = 0, mask = 0xff; mag < 4; mag++) {
    if (ctx->pending_frame_magnitude < mask)
      break;
    mask <<= 8;
    mask |= 0xff;
  }
  marker |= mag << 3;

767
  // Write the index
John Koleszar's avatar
John Koleszar committed
768
769
770
771
  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;
772
773
774
775
776
777
778
779
780
781
782
783
784
785
#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
786
787
788

    *x++ = marker;
    for (i = 0; i < ctx->pending_frame_count; i++) {
789
      unsigned int this_sz = (unsigned int)ctx->pending_frame_sizes[i];
John Koleszar's avatar
John Koleszar committed
790
791
792
793
794
795
796
797

      for (j = 0; j <= mag; j++) {
        *x++ = this_sz & 0xff;
        this_sz >>= 8;
      }
    }
    *x++ = marker;
    ctx->pending_cx_data_sz += index_sz;
798
799
800
#ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
    index_sz += index_sz_test;
#endif
John Koleszar's avatar
John Koleszar committed
801
  }
802
  return index_sz;
John Koleszar's avatar
John Koleszar committed
803
804
}

805
// vp9 uses 10,000,000 ticks/second as time stamp
Yaowu Xu's avatar
Yaowu Xu committed
806
#define TICKS_PER_SEC 10000000LL
807
808
809
810
811
812
813
814
815
816
817
818

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

819
820
821
822
823
824
static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
                                                   unsigned int lib_flags) {
  vpx_codec_frame_flags_t flags = lib_flags << 16;

  if (lib_flags & FRAMEFLAGS_KEY
#if CONFIG_SPATIAL_SVC
825
      || (is_two_pass_svc(cpi) && cpi->svc.layer_context[0].is_key_frame)
826
827
828
829
830
831
832
833
834
835
#endif
        )
    flags |= VPX_FRAME_IS_KEY;

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

  return flags;
}

836
837
838
839
840
841
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
842
  vpx_codec_err_t res = VPX_CODEC_OK;
Dmitry Kovalev's avatar
Dmitry Kovalev committed
843
  VP9_COMP *const cpi = ctx->cpi;
844
  const vpx_rational_t *const timebase = &ctx->cfg.g_timebase;
John Koleszar's avatar
John Koleszar committed
845

846
  if (img != NULL) {
John Koleszar's avatar
John Koleszar committed
847
    res = validate_img(ctx, img);
848
849
    // TODO(jzern) the checks related to cpi's validity should be treated as a
    // failure condition, encoder setup is done fully in init() currently.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
850
    if (res == VPX_CODEC_OK && cpi != NULL && ctx->cx_data == NULL) {
851
852
853
854
      // 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 *
Dmitry Kovalev's avatar
Dmitry Kovalev committed
855
                        (cpi->multi_arf_allowed ? 8 : 2);
856
857
858
859
860
861
862
863
      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
864

John Koleszar's avatar
John Koleszar committed
865
866
  pick_quickcompress_mode(ctx, duration, deadline);
  vpx_codec_pkt_list_init(&ctx->pkt_list);
John Koleszar's avatar
John Koleszar committed
867

868
869
870
  // 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
871
872
873
    ctx->base.err_detail = "Conflicting flags.";
    return VPX_CODEC_INVALID_PARAM;
  }
John Koleszar's avatar
John Koleszar committed
874

Dmitry Kovalev's avatar
Dmitry Kovalev committed
875
  vp9_apply_encoding_flags(cpi, flags);
John Koleszar's avatar
John Koleszar committed
876

877
878
879
  // 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
880
881
882
    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
883
    }
John Koleszar's avatar
John Koleszar committed
884
  }
John Koleszar's avatar
John Koleszar committed
885

886
  // Initialize the encoder instance on the first frame.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
887
  if (res == VPX_CODEC_OK && cpi != NULL) {
888
    unsigned int lib_flags = 0;
John Koleszar's avatar
John Koleszar committed
889
    YV12_BUFFER_CONFIG sd;
890
891
892
    int64_t dst_time_stamp = timebase_units_to_ticks(timebase, pts);
    int64_t dst_end_time_stamp =
        timebase_units_to_ticks(timebase, pts + duration);
893
    size_t size, cx_data_sz;
John Koleszar's avatar
John Koleszar committed
894
    unsigned char *cx_data;
John Koleszar's avatar
John Koleszar committed
895

896
    // Set up internal flags
John Koleszar's avatar
John Koleszar committed
897
    if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
898
      cpi->b_calculate_psnr = 1;
John Koleszar's avatar
John Koleszar committed
899

John Koleszar's avatar
John Koleszar committed
900
901
    if (img != NULL) {
      res = image2yuvconfig(img, &sd);
John Koleszar's avatar
John Koleszar committed
902

903
904
      // Store the original flags in to the frame buffer. Will extract the
      // key frame flag when we actually encode this frame.
Dmitry Kovalev's avatar
Dmitry Kovalev committed
905
      if (vp9_receive_raw_frame(cpi, flags,
John Koleszar's avatar
John Koleszar committed
906
907
908
909
                                &sd, dst_time_stamp, dst_end_time_stamp)) {
        res = update_error_state(ctx, &cpi->common.error);
      }
    }
John Koleszar's avatar
John Koleszar committed
910

911
912
    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;
John Koleszar's avatar
John Koleszar committed
913

914
915
916
917
918
919
920
921
922
923
924
925
926
927
    /* 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;
      }
928
929
    }

930
    while (cx_data_sz >= ctx->cx_data_sz / 2 &&
Dmitry Kovalev's avatar
Dmitry Kovalev committed
931
           -1 != vp9_get_compressed_data(cpi, &lib_flags, &size,
932
933
                                         cx_data, &dst_time_stamp,
                                         &dst_end_time_stamp, !img)) {
John Koleszar's avatar
John Koleszar committed
934
      if (size) {
935
        vpx_codec_cx_pkt_t pkt;
John Koleszar's avatar
John Koleszar committed
936

937
#if CONFIG_SPATIAL_SVC
938
        if (is_two_pass_svc(cpi))
939
940
941
          cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size;
#endif

942
        // Pack invisible frames with the next visible frame
943
        if (!cpi->common.show_frame
944
#if CONFIG_SPATIAL_SVC
945
            || (is_two_pass_svc(cpi) &&
946
947
948
                cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
#endif
            ) {
Adrian Grange's avatar
Adrian Grange committed
949
          if (ctx->pending_cx_data == 0)
950
951
            ctx->pending_cx_data = cx_data;
          ctx->pending_cx_data_sz += size;
John Koleszar's avatar
John Koleszar committed
952
953
          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
          ctx->pending_frame_magnitude |= size;
954
955
956
957
958
          cx_data += size;
          cx_data_sz -= size;
          continue;
        }

959
        // Add the frame packet to the list of returned packets.
John Koleszar's avatar
John Koleszar committed
960
        pkt.kind = VPX_CODEC_CX_FRAME_PKT;
961
962
963
964
        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);
965
        pkt.data.frame.flags = get_frame_pkt_flags(cpi, lib_flags);
John Koleszar's avatar
John Koleszar committed
966

967
968
969
970
971
972
973
974
975
976
977
978
979
980
        if (ctx->pending_cx_data) {
          ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
          ctx->pending_frame_magnitude |= size;
          ctx->pending_cx_data_sz += size;
          size += write_superframe_index(ctx);
          pkt.data.frame.buf = ctx->pending_cx_data;
          pkt.data.frame.sz  = ctx->pending_cx_data_sz;
          ctx->pending_cx_data = NULL;
          ctx->pending_cx_data_sz = 0;
          ctx->pending_frame_count = 0;
          ctx->pending_frame_magnitude = 0;
        } else {
          pkt.data.frame.buf = cx_data;
          pkt.data.frame.sz  = size;
John Koleszar's avatar
John Koleszar committed
981
        }
982
983
984
985
        pkt.data.frame.partition_id = -1;
        vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
        cx_data += size;
        cx_data_sz -= size;
986
#if CONFIG_SPATIAL_SVC
987
        if (is_two_pass_svc(cpi)) {
988
          vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr;
989
          int i;
990
991
992
993
          vp9_zero(pkt_sizes);
          vp9_zero(pkt_psnr);
          pkt_sizes.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES;
          pkt_psnr.kind = VPX_CODEC_SPATIAL_SVC_LAYER_PSNR;