vp9_cx_iface.c 47.6 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"
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"
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;
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;
  }
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) {
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) {
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) {
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;

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) {
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);
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 559 560
  extra_cfg.noise_sensitivity = CAST(VP8E_SET_NOISE_SENSITIVITY, 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_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;
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 689 690
      set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
      priv->cpi = vp9_create_compressor(&priv->oxcf);
      if (priv->cpi == NULL)
John Koleszar's avatar
John Koleszar committed
691
        res = VPX_CODEC_MEM_ERROR;
692
      else
693
        priv->cpi->output_pkt_list = &priv->pkt_list.head;
John Koleszar's avatar
John Koleszar committed
694
    }
John Koleszar's avatar
John Koleszar committed
695
  }
John Koleszar's avatar
John Koleszar committed
696

John Koleszar's avatar
John Koleszar committed
697
  return res;
John Koleszar's avatar
John Koleszar committed
698 699
}

700
static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
701
  free(ctx->cx_data);
Dmitry Kovalev's avatar
Dmitry Kovalev committed
702
  vp9_remove_compressor(ctx->cpi);
703
  vpx_free(ctx);
John Koleszar's avatar
John Koleszar committed
704
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
705 706
}

707
static void pick_quickcompress_mode(vpx_codec_alg_priv_t *ctx,
708 709
                                    unsigned long duration,
                                    unsigned long deadline) {
710
  MODE new_mode = BEST;
John Koleszar's avatar
John Koleszar committed
711

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
  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
734

735 736
  if (ctx->oxcf.mode != new_mode) {
    ctx->oxcf.mode = new_mode;
737
    vp9_change_config(ctx->cpi, &ctx->oxcf);
John Koleszar's avatar
John Koleszar committed
738
  }
John Koleszar's avatar
John Koleszar committed
739 740
}

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

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

751
  // Add the number of frames to the marker byte
John Koleszar's avatar
John Koleszar committed
752 753
  marker |= ctx->pending_frame_count - 1;

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

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

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

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

801
// vp9 uses 10,000,000 ticks/second as time stamp
802
#define TICKS_PER_SEC 10000000LL
803 804 805 806 807 808 809 810 811 812 813 814

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

815 816 817 818 819 820
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
821
      || (is_two_pass_svc(cpi) && cpi->svc.layer_context[0].is_key_frame)
822 823 824 825 826 827 828 829 830 831
#endif
        )
    flags |= VPX_FRAME_IS_KEY;

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

  return flags;
}

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

842
  if (img != NULL) {
John Koleszar's avatar
John Koleszar committed
843
    res = validate_img(ctx, img);
844 845
    // 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
846
    if (res == VPX_CODEC_OK && cpi != NULL && ctx->cx_data == NULL) {
847 848 849 850
      // 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
851
                        (cpi->multi_arf_allowed ? 8 : 2);
852 853 854 855 856 857 858 859
      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
860

John Koleszar's avatar
John Koleszar committed
861 862
  pick_quickcompress_mode(ctx, duration, deadline);
  vpx_codec_pkt_list_init(&ctx->pkt_list);
John Koleszar's avatar
John Koleszar committed
863

864 865 866
  // 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
867 868 869
    ctx->base.err_detail = "Conflicting flags.";
    return VPX_CODEC_INVALID_PARAM;
  }
John Koleszar's avatar
John Koleszar committed
870

Dmitry Kovalev's avatar
Dmitry Kovalev committed
871
  vp9_apply_encoding_flags(cpi, flags);
John Koleszar's avatar
John Koleszar committed
872

873 874 875
  // 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
876 877 878
    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
879
    }
John Koleszar's avatar
John Koleszar committed
880
  }
John Koleszar's avatar
John Koleszar committed
881

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

892
    // Set up internal flags
John Koleszar's avatar
John Koleszar committed
893
    if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
Dmitry Kovalev's avatar
Dmitry Kovalev committed
894
      cpi->b_calculate_psnr = 1;
John Koleszar's avatar
John Koleszar committed
895

John Koleszar's avatar
John Koleszar committed
896 897
    if (img != NULL) {
      res = image2yuvconfig(img, &sd);
John Koleszar's avatar
John Koleszar committed
898

899 900
      // 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
901
      if (vp9_receive_raw_frame(cpi, flags,
John Koleszar's avatar
John Koleszar committed
902 903 904 905
                                &sd, dst_time_stamp, dst_end_time_stamp)) {
        res = update_error_state(ctx, &cpi->common.error);
      }
    }
John Koleszar's avatar
John Koleszar committed
906

907 908
    cx_data = ctx->cx_data;
    cx_data_sz = ctx->cx_data_sz;
John Koleszar's avatar
John Koleszar committed
909

910 911 912 913 914 915 916 917 918 919 920 921 922 923
    /* 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;
      }
924 925
    }

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

933
#if CONFIG_SPATIAL_SVC
934
        if (is_two_pass_svc(cpi))
935 936 937
          cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size;
#endif

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

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

963 964 965 966 967 968 969 970 971 972 973 974 975 976
        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
977
        }
978 979 980 981
        pkt.data.frame.partition_id = -1;
        vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
        cx_data += size;
        cx_data_sz -= size;
982
#if CONFIG_SPATIAL_SVC
983
        if (is_two_pass_svc(cpi)) {
984
          vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr;
985
          int i;
986 987 988 989
          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;
990
          for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
991 992 993 994
            LAYER_CONTEXT *lc = &cpi->svc.layer_context[i];
            pkt_sizes.data.layer_sizes[i] = lc->layer_size;
            pkt_psnr.data.layer_psnr[i] = lc->psnr_pkt;
            lc->layer_size = 0;
995
          }
996 997
          vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_sizes);
          vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_psnr);
998 999
        }
#endif
John Koleszar's avatar
John Koleszar committed
1000
      }
John Koleszar's avatar
John Koleszar committed
1001
    }
John Koleszar's avatar
John Koleszar committed
1002
  }
John Koleszar's avatar
John Koleszar committed
1003

John Koleszar's avatar
John Koleszar committed
1004
  return res;
John Koleszar's avatar
John Koleszar committed
1005 1006
}

1007
static const vpx_codec_cx_pkt_t *encoder_get_cxdata(vpx_codec_alg_priv_t *ctx,
1008
                                                    vpx_codec_iter_t *iter) {
John Koleszar's avatar
John Koleszar committed
1009
  return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
John Koleszar's avatar
John Koleszar committed
1010 1011
}

1012
static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
1013
                                          va_list args) {
1014
  vpx_ref_frame_t *const frame = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
1015

1016
  if (frame != NULL) {
John Koleszar's avatar
John Koleszar committed
1017
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
1018

John Koleszar's avatar
John Koleszar committed
1019
    image2yuvconfig(&frame->img, &sd);
1020 1021
    vp9_set_reference_enc(ctx->cpi, ref_frame_to_vp9_reframe(frame->frame_type),
                          &sd);
John Koleszar's avatar
John Koleszar committed
1022
    return VPX_CODEC_OK;
1023
  } else {
John Koleszar's avatar
John Koleszar committed
1024
    return VPX_CODEC_INVALID_PARAM;
1025
  }
John Koleszar's avatar
John Koleszar committed
1026 1027
}

1028
static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
1029
                                           va_list args) {
1030
  vpx_ref_frame_t *const frame = va_arg(args, vpx_ref_frame_t *);
John Koleszar's avatar
John Koleszar committed
1031

1032
  if (frame != NULL) {
John Koleszar's avatar
John Koleszar committed
1033
    YV12_BUFFER_CONFIG sd;
John Koleszar's avatar
John Koleszar committed
1034

John Koleszar's avatar
John Koleszar committed
1035
    image2yuvconfig(&frame->img, &sd);
1036 1037
    vp9_copy_reference_enc(ctx->cpi,
                           ref_frame_to_vp9_reframe(frame->frame_type), &sd);
John Koleszar's avatar
John Koleszar committed
1038
    return VPX_CODEC_OK;
1039
  } else {
John Koleszar's avatar
John Koleszar committed
1040
    return VPX_CODEC_INVALID_PARAM;
1041
  }
John Koleszar's avatar
John Koleszar committed
1042 1043
}

1044
static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
1045
                                          va_list args) {
1046
  vp9_ref_frame_t *const frame = va_arg(args, vp9_ref_frame_t *);
1047

1048
  if (frame != NULL) {
1049 1050
    YV12_BUFFER_CONFIG *fb = get_ref_frame(&ctx->cpi->common, frame->idx);
    if (fb == NULL) return VPX_CODEC_ERROR;
1051

1052
    yuvconfig2image(&frame->img, fb, NULL);
1053 1054 1055 1056 1057 1058
    return VPX_CODEC_OK;
  } else {
    return VPX_CODEC_INVALID_PARAM;
  }
}

1059
static vpx_codec_err_t ctrl_set_previewpp(vpx_codec_alg_priv_t *ctx,
1060
                                          va_list args) {
1061
#if CONFIG_VP9_POSTPROC
1062 1063 1064
  vp8_postproc_cfg_t *config = va_arg(args, vp8_postproc_cfg_t *);
  if (config != NULL) {
    ctx->preview_ppcfg = *config;
John Koleszar's avatar
John Koleszar committed
1065
    return VPX_CODEC_OK;
1066
  } else {
John Koleszar's avatar
John Koleszar committed
1067
    return VPX_CODEC_INVALID_PARAM;
1068
  }
1069
#else
John Koleszar's avatar
John Koleszar committed
1070 1071 1072
  (void)ctx;
  (void)args;
  return VPX_CODEC_INCAPABLE;
1073
#endif
John Koleszar's avatar
John Koleszar committed
1074 1075 1076
}


1077
static vpx_image_t *encoder_get_preview(vpx_codec_alg_priv_t *ctx) {
John Koleszar's avatar
John Koleszar committed
1078
  YV12_BUFFER_CONFIG sd;
1079 1080
  vp9_ppflags_t flags;
  vp9_zero(flags);
John Koleszar's avatar
John Koleszar committed
1081

John Koleszar's avatar
John Koleszar committed
1082
  if (ctx->preview_ppcfg.post_proc_flag) {
1083 1084 1085
    flags.post_proc_flag   = ctx->preview_ppcfg.post_proc_flag;
    flags.deblocking_level = ctx->preview_ppcfg.deblocking_level;
    flags.noise_level      = ctx->preview_ppcfg.noise_level;
John Koleszar's avatar
John Koleszar committed
1086
  }
1087

1088
  if (vp9_get_preview_raw_frame(ctx->cpi, &sd, &flags) == 0) {
1089
    yuvconfig2image(&ctx->preview_img, &sd, NULL);
John Koleszar's avatar
John Koleszar committed
1090
    return &ctx->preview_img;
1091
  } else {
John Koleszar's avatar
John Koleszar committed
1092
    return NULL;
1093
  }
John Koleszar's avatar
John Koleszar committed
1094 1095
}

1096
static vpx_codec_err_t ctrl_update_entropy(vpx_codec_alg_priv_t *ctx,
1097
                                           va_list args) {
1098
  const int update = va_arg(args, int);
1099

1100
  vp9_update_entropy(ctx->cpi, update);
John Koleszar's avatar
John Koleszar committed
1101
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
1102 1103
}

1104
static vpx_codec_err_t ctrl_update_reference(vpx_codec_alg_priv_t *ctx,
1105
                                             va_list args) {
1106
  const int ref_frame_flags = va_arg(args, int);
1107

1108
  vp9_update_reference(ctx->cpi, ref_frame_flags);
John Koleszar's avatar
John Koleszar committed
1109
  return VPX_CODEC_OK;
John Koleszar's avatar
John Koleszar committed
1110 1111
}

1112
static vpx_codec_err_t ctrl_use_reference(vpx_codec_alg_priv_t *ctx,
1113
                                          va_list args) {
1114
  const int reference_flag = va_arg(args, int);
1115

1116
  vp9_use_as_reference(ctx->cpi, reference_flag);
John Koleszar's avatar
John Koleszar committed
1117
<