]> granicus.if.org Git - libvpx/blob - vp9/vp9_cx_iface.c
[spatial svc]Implement lag in frames for spatial svc
[libvpx] / vp9 / vp9_cx_iface.c
1 /*
2  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  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.
9  */
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "vpx/vpx_codec.h"
15 #include "vpx/internal/vpx_codec_internal.h"
16 #include "./vpx_version.h"
17 #include "vp9/encoder/vp9_encoder.h"
18 #include "vpx/vp8cx.h"
19 #include "vp9/encoder/vp9_firstpass.h"
20 #include "vp9/vp9_iface_common.h"
21
22 struct vp9_extracfg {
23   struct vpx_codec_pkt_list *pkt_list;
24   int                         cpu_used;  // available cpu percentage in 1/16
25   unsigned int                enable_auto_alt_ref;
26   unsigned int                noise_sensitivity;
27   unsigned int                sharpness;
28   unsigned int                static_thresh;
29   unsigned int                tile_columns;
30   unsigned int                tile_rows;
31   unsigned int                arnr_max_frames;
32   unsigned int                arnr_strength;
33   unsigned int                arnr_type;
34   vp8e_tuning                 tuning;
35   unsigned int                cq_level;  // constrained quality level
36   unsigned int                rc_max_intra_bitrate_pct;
37   unsigned int                lossless;
38   unsigned int                frame_parallel_decoding_mode;
39   AQ_MODE                     aq_mode;
40   unsigned int                frame_periodic_boost;
41   BIT_DEPTH                   bit_depth;
42 };
43
44 struct extraconfig_map {
45   unsigned int usage;
46   struct vp9_extracfg cfg;
47 };
48
49 static const struct extraconfig_map extracfg_map[] = {
50   {
51     0,
52     { // NOLINT
53       NULL,
54       0,                          // cpu_used
55       1,                          // enable_auto_alt_ref
56       0,                          // noise_sensitivity
57       0,                          // sharpness
58       0,                          // static_thresh
59       0,                          // tile_columns
60       0,                          // tile_rows
61       7,                          // arnr_max_frames
62       5,                          // arnr_strength
63       3,                          // arnr_type
64       VP8_TUNE_PSNR,              // tuning
65       10,                         // cq_level
66       0,                          // rc_max_intra_bitrate_pct
67       0,                          // lossless
68       0,                          // frame_parallel_decoding_mode
69       NO_AQ,                      // aq_mode
70       0,                          // frame_periodic_delta_q
71       BITS_8,                     // Bit depth
72     }
73   }
74 };
75
76 struct vpx_codec_alg_priv {
77   vpx_codec_priv_t        base;
78   vpx_codec_enc_cfg_t     cfg;
79   struct vp9_extracfg     extra_cfg;
80   VP9EncoderConfig        oxcf;
81   VP9_COMP               *cpi;
82   unsigned char          *cx_data;
83   size_t                  cx_data_sz;
84   unsigned char          *pending_cx_data;
85   size_t                  pending_cx_data_sz;
86   int                     pending_frame_count;
87   size_t                  pending_frame_sizes[8];
88   size_t                  pending_frame_magnitude;
89   vpx_image_t             preview_img;
90   vp8_postproc_cfg_t      preview_ppcfg;
91   vpx_codec_pkt_list_decl(128) pkt_list;
92   unsigned int                 fixed_kf_cntr;
93 };
94
95 static VP9_REFFRAME ref_frame_to_vp9_reframe(vpx_ref_frame_type_t frame) {
96   switch (frame) {
97     case VP8_LAST_FRAME:
98       return VP9_LAST_FLAG;
99     case VP8_GOLD_FRAME:
100       return VP9_GOLD_FLAG;
101     case VP8_ALTR_FRAME:
102       return VP9_ALT_FLAG;
103   }
104   assert(0 && "Invalid Reference Frame");
105   return VP9_LAST_FLAG;
106 }
107
108 static vpx_codec_err_t update_error_state(vpx_codec_alg_priv_t *ctx,
109     const struct vpx_internal_error_info *error) {
110   const vpx_codec_err_t res = error->error_code;
111
112   if (res != VPX_CODEC_OK)
113     ctx->base.err_detail = error->has_detail ? error->detail : NULL;
114
115   return res;
116 }
117
118
119 #undef ERROR
120 #define ERROR(str) do {\
121     ctx->base.err_detail = str;\
122     return VPX_CODEC_INVALID_PARAM;\
123   } while (0)
124
125 #define RANGE_CHECK(p, memb, lo, hi) do {\
126     if (!(((p)->memb == lo || (p)->memb > (lo)) && (p)->memb <= hi)) \
127       ERROR(#memb " out of range ["#lo".."#hi"]");\
128   } while (0)
129
130 #define RANGE_CHECK_HI(p, memb, hi) do {\
131     if (!((p)->memb <= (hi))) \
132       ERROR(#memb " out of range [.."#hi"]");\
133   } while (0)
134
135 #define RANGE_CHECK_LO(p, memb, lo) do {\
136     if (!((p)->memb >= (lo))) \
137       ERROR(#memb " out of range ["#lo"..]");\
138   } while (0)
139
140 #define RANGE_CHECK_BOOL(p, memb) do {\
141     if (!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean");\
142   } while (0)
143
144 static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
145                                        const vpx_codec_enc_cfg_t *cfg,
146                                        const struct vp9_extracfg *extra_cfg) {
147   RANGE_CHECK(cfg, g_w,                   1, 65535);  // 16 bits available
148   RANGE_CHECK(cfg, g_h,                   1, 65535);  // 16 bits available
149   RANGE_CHECK(cfg, g_timebase.den,        1, 1000000000);
150   RANGE_CHECK(cfg, g_timebase.num,        1, cfg->g_timebase.den);
151   RANGE_CHECK_HI(cfg, g_profile,          3);
152
153   RANGE_CHECK_HI(cfg, rc_max_quantizer,   63);
154   RANGE_CHECK_HI(cfg, rc_min_quantizer,   cfg->rc_max_quantizer);
155   RANGE_CHECK_BOOL(extra_cfg, lossless);
156   RANGE_CHECK(extra_cfg, aq_mode,           0, AQ_MODE_COUNT - 1);
157   RANGE_CHECK(extra_cfg, frame_periodic_boost, 0, 1);
158   RANGE_CHECK_HI(cfg, g_threads,          64);
159   RANGE_CHECK_HI(cfg, g_lag_in_frames,    MAX_LAG_BUFFERS);
160   RANGE_CHECK(cfg, rc_end_usage,          VPX_VBR, VPX_Q);
161   RANGE_CHECK_HI(cfg, rc_undershoot_pct,  1000);
162   RANGE_CHECK_HI(cfg, rc_overshoot_pct,   1000);
163   RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
164   RANGE_CHECK(cfg, kf_mode,               VPX_KF_DISABLED, VPX_KF_AUTO);
165   RANGE_CHECK_BOOL(cfg,                   rc_resize_allowed);
166   RANGE_CHECK_HI(cfg, rc_dropframe_thresh,   100);
167   RANGE_CHECK_HI(cfg, rc_resize_up_thresh,   100);
168   RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
169   RANGE_CHECK(cfg,        g_pass,         VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);
170
171   if (cfg->rc_resize_allowed == 1) {
172     RANGE_CHECK(cfg, rc_scaled_width, 1, cfg->g_w);
173     RANGE_CHECK(cfg, rc_scaled_height, 1, cfg->g_h);
174   }
175
176   RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
177   RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
178   if (cfg->ts_number_layers > 1) {
179     unsigned int i;
180     for (i = 1; i < cfg->ts_number_layers; ++i)
181       if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1])
182         ERROR("ts_target_bitrate entries are not increasing");
183
184     RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
185     for (i = cfg->ts_number_layers - 2; i > 0; --i)
186       if (cfg->ts_rate_decimator[i - 1] != 2 * cfg->ts_rate_decimator[i])
187         ERROR("ts_rate_decimator factors are not powers of 2");
188   }
189
190   // VP9 does not support a lower bound on the keyframe interval in
191   // automatic keyframe placement mode.
192   if (cfg->kf_mode != VPX_KF_DISABLED &&
193       cfg->kf_min_dist != cfg->kf_max_dist &&
194       cfg->kf_min_dist > 0)
195     ERROR("kf_min_dist not supported in auto mode, use 0 "
196           "or kf_max_dist instead.");
197
198   RANGE_CHECK_BOOL(extra_cfg,  enable_auto_alt_ref);
199   RANGE_CHECK(extra_cfg, cpu_used, -16, 16);
200   RANGE_CHECK_HI(extra_cfg, noise_sensitivity, 6);
201   RANGE_CHECK(extra_cfg, tile_columns, 0, 6);
202   RANGE_CHECK(extra_cfg, tile_rows, 0, 2);
203   RANGE_CHECK_HI(extra_cfg, sharpness, 7);
204   RANGE_CHECK(extra_cfg, arnr_max_frames, 0, 15);
205   RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
206   RANGE_CHECK(extra_cfg, arnr_type, 1, 3);
207   RANGE_CHECK(extra_cfg, cq_level, 0, 63);
208
209   // TODO(yaowu): remove this when ssim tuning is implemented for vp9
210   if (extra_cfg->tuning == VP8_TUNE_SSIM)
211       ERROR("Option --tune=ssim is not currently supported in VP9.");
212
213   if (cfg->g_pass == VPX_RC_LAST_PASS) {
214     const size_t packet_sz = sizeof(FIRSTPASS_STATS);
215     const int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
216     const FIRSTPASS_STATS *stats;
217
218     if (cfg->rc_twopass_stats_in.buf == NULL)
219       ERROR("rc_twopass_stats_in.buf not set.");
220
221     if (cfg->rc_twopass_stats_in.sz % packet_sz)
222       ERROR("rc_twopass_stats_in.sz indicates truncated packet.");
223
224     if (cfg->ss_number_layers > 1) {
225       int i;
226       unsigned int n_packets_per_layer[VPX_SS_MAX_LAYERS] = {0};
227
228       stats = cfg->rc_twopass_stats_in.buf;
229       for (i = 0; i < n_packets; ++i) {
230         const int layer_id = (int)stats[i].spatial_layer_id;
231         if (layer_id >= 0 && layer_id < (int)cfg->ss_number_layers) {
232           ++n_packets_per_layer[layer_id];
233         }
234       }
235
236       for (i = 0; i < (int)cfg->ss_number_layers; ++i) {
237         unsigned int layer_id;
238         if (n_packets_per_layer[i] < 2) {
239           ERROR("rc_twopass_stats_in requires at least two packets for each "
240                 "layer.");
241         }
242
243         stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf +
244                 n_packets - cfg->ss_number_layers + i;
245         layer_id = (int)stats->spatial_layer_id;
246
247         if (layer_id >= cfg->ss_number_layers
248             ||(unsigned int)(stats->count + 0.5) !=
249                n_packets_per_layer[layer_id] - 1)
250           ERROR("rc_twopass_stats_in missing EOS stats packet");
251       }
252     } else {
253       if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz)
254         ERROR("rc_twopass_stats_in requires at least two packets.");
255
256       stats =
257           (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1;
258
259       if ((int)(stats->count + 0.5) != n_packets - 1)
260         ERROR("rc_twopass_stats_in missing EOS stats packet");
261     }
262   }
263   if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
264       extra_cfg->bit_depth > BITS_8)
265     ERROR("High bit-depth not supported in profile < 2");
266   if (cfg->g_profile > (unsigned int)PROFILE_1 &&
267       extra_cfg->bit_depth == BITS_8)
268     ERROR("Bit-depth 8 not supported in profile > 1");
269
270   return VPX_CODEC_OK;
271 }
272
273
274 static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
275                                     const vpx_image_t *img) {
276   switch (img->fmt) {
277     case VPX_IMG_FMT_YV12:
278     case VPX_IMG_FMT_I420:
279     case VPX_IMG_FMT_I422:
280     case VPX_IMG_FMT_I444:
281       break;
282     default:
283       ERROR("Invalid image format. Only YV12, I420, I422, I444 images are "
284             "supported.");
285   }
286
287   if (img->d_w != ctx->cfg.g_w || img->d_h != ctx->cfg.g_h)
288     ERROR("Image size must match encoder init configuration size");
289
290   return VPX_CODEC_OK;
291 }
292
293
294 static vpx_codec_err_t set_encoder_config(
295     VP9EncoderConfig *oxcf,
296     const vpx_codec_enc_cfg_t *cfg,
297     const struct vp9_extracfg *extra_cfg) {
298   oxcf->profile = cfg->g_profile;
299   oxcf->width   = cfg->g_w;
300   oxcf->height  = cfg->g_h;
301   oxcf->bit_depth = extra_cfg->bit_depth;
302   // guess a frame rate if out of whack, use 30
303   oxcf->framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
304   if (oxcf->framerate > 180)
305     oxcf->framerate = 30;
306
307   switch (cfg->g_pass) {
308     case VPX_RC_ONE_PASS:
309       oxcf->mode = ONE_PASS_GOOD;
310       break;
311     case VPX_RC_FIRST_PASS:
312       oxcf->mode = TWO_PASS_FIRST;
313       break;
314     case VPX_RC_LAST_PASS:
315       oxcf->mode = TWO_PASS_SECOND_BEST;
316       break;
317   }
318
319   oxcf->lag_in_frames = cfg->g_pass == VPX_RC_FIRST_PASS ? 0
320                                                          : cfg->g_lag_in_frames;
321   oxcf->rc_mode = cfg->rc_end_usage;
322
323   // Convert target bandwidth from Kbit/s to Bit/s
324   oxcf->target_bandwidth = 1000 * cfg->rc_target_bitrate;
325   oxcf->rc_max_intra_bitrate_pct = extra_cfg->rc_max_intra_bitrate_pct;
326
327   oxcf->best_allowed_q =
328       extra_cfg->lossless ? 0 : vp9_quantizer_to_qindex(cfg->rc_min_quantizer);
329   oxcf->worst_allowed_q =
330       extra_cfg->lossless ? 0 : vp9_quantizer_to_qindex(cfg->rc_max_quantizer);
331   oxcf->cq_level        = vp9_quantizer_to_qindex(extra_cfg->cq_level);
332   oxcf->fixed_q = -1;
333
334   oxcf->under_shoot_pct         = cfg->rc_undershoot_pct;
335   oxcf->over_shoot_pct          = cfg->rc_overshoot_pct;
336
337   oxcf->allow_spatial_resampling = cfg->rc_resize_allowed;
338   oxcf->scaled_frame_width       = cfg->rc_scaled_width;
339   oxcf->scaled_frame_height      = cfg->rc_scaled_height;
340
341   oxcf->maximum_buffer_size_ms   = cfg->rc_buf_sz;
342   oxcf->starting_buffer_level_ms = cfg->rc_buf_initial_sz;
343   oxcf->optimal_buffer_level_ms  = cfg->rc_buf_optimal_sz;
344
345   oxcf->drop_frames_water_mark   = cfg->rc_dropframe_thresh;
346
347   oxcf->two_pass_vbrbias         = cfg->rc_2pass_vbr_bias_pct;
348   oxcf->two_pass_vbrmin_section  = cfg->rc_2pass_vbr_minsection_pct;
349   oxcf->two_pass_vbrmax_section  = cfg->rc_2pass_vbr_maxsection_pct;
350
351   oxcf->auto_key               = cfg->kf_mode == VPX_KF_AUTO &&
352                                  cfg->kf_min_dist != cfg->kf_max_dist;
353
354   oxcf->key_freq               = cfg->kf_max_dist;
355
356   oxcf->speed                  =  clamp(abs(extra_cfg->cpu_used), 0, 7);
357   oxcf->encode_breakout        =  extra_cfg->static_thresh;
358   oxcf->play_alternate         =  extra_cfg->enable_auto_alt_ref;
359   oxcf->noise_sensitivity      =  extra_cfg->noise_sensitivity;
360   oxcf->sharpness              =  extra_cfg->sharpness;
361
362   oxcf->two_pass_stats_in      =  cfg->rc_twopass_stats_in;
363   oxcf->output_pkt_list        =  extra_cfg->pkt_list;
364
365   oxcf->arnr_max_frames = extra_cfg->arnr_max_frames;
366   oxcf->arnr_strength   = extra_cfg->arnr_strength;
367   oxcf->arnr_type       = extra_cfg->arnr_type;
368
369   oxcf->tuning = extra_cfg->tuning;
370
371   oxcf->tile_columns = extra_cfg->tile_columns;
372   oxcf->tile_rows    = extra_cfg->tile_rows;
373
374   oxcf->error_resilient_mode         = cfg->g_error_resilient;
375   oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
376
377   oxcf->aq_mode = extra_cfg->aq_mode;
378
379   oxcf->frame_periodic_boost =  extra_cfg->frame_periodic_boost;
380
381   oxcf->ss_number_layers = cfg->ss_number_layers;
382
383   if (oxcf->ss_number_layers > 1) {
384     int i;
385     for (i = 0; i < VPX_SS_MAX_LAYERS; ++i)
386       oxcf->ss_target_bitrate[i] =  1000 * cfg->ss_target_bitrate[i];
387   } else if (oxcf->ss_number_layers == 1) {
388     oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
389   }
390
391   oxcf->ts_number_layers = cfg->ts_number_layers;
392
393   if (oxcf->ts_number_layers > 1) {
394     int i;
395     for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) {
396       oxcf->ts_target_bitrate[i] = 1000 * cfg->ts_target_bitrate[i];
397       oxcf->ts_rate_decimator[i] = cfg->ts_rate_decimator[i];
398     }
399   } else if (oxcf->ts_number_layers == 1) {
400     oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
401     oxcf->ts_rate_decimator[0] = 1;
402   }
403
404   /*
405   printf("Current VP9 Settings: \n");
406   printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
407   printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
408   printf("sharpness: %d\n",    oxcf->sharpness);
409   printf("cpu_used: %d\n",  oxcf->cpu_used);
410   printf("Mode: %d\n",     oxcf->mode);
411   printf("auto_key: %d\n",  oxcf->auto_key);
412   printf("key_freq: %d\n", oxcf->key_freq);
413   printf("end_usage: %d\n", oxcf->end_usage);
414   printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct);
415   printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct);
416   printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level);
417   printf("optimal_buffer_level: %d\n",  oxcf->optimal_buffer_level);
418   printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size);
419   printf("fixed_q: %d\n",  oxcf->fixed_q);
420   printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q);
421   printf("best_allowed_q: %d\n", oxcf->best_allowed_q);
422   printf("allow_spatial_resampling: %d\n", oxcf->allow_spatial_resampling);
423   printf("scaled_frame_width: %d\n", oxcf->scaled_frame_width);
424   printf("scaled_frame_height: %d\n", oxcf->scaled_frame_height);
425   printf("two_pass_vbrbias: %d\n",  oxcf->two_pass_vbrbias);
426   printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section);
427   printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section);
428   printf("lag_in_frames: %d\n", oxcf->lag_in_frames);
429   printf("play_alternate: %d\n", oxcf->play_alternate);
430   printf("Version: %d\n", oxcf->Version);
431   printf("encode_breakout: %d\n", oxcf->encode_breakout);
432   printf("error resilient: %d\n", oxcf->error_resilient_mode);
433   printf("frame parallel detokenization: %d\n",
434          oxcf->frame_parallel_decoding_mode);
435   */
436   return VPX_CODEC_OK;
437 }
438
439 static vpx_codec_err_t encoder_set_config(vpx_codec_alg_priv_t *ctx,
440                                           const vpx_codec_enc_cfg_t  *cfg) {
441   vpx_codec_err_t res;
442
443   if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h)
444     ERROR("Cannot change width or height after initialization");
445
446   // Prevent increasing lag_in_frames. This check is stricter than it needs
447   // to be -- the limit is not increasing past the first lag_in_frames
448   // value, but we don't track the initial config, only the last successful
449   // config.
450   if (cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames)
451     ERROR("Cannot increase lag_in_frames");
452
453   res = validate_config(ctx, cfg, &ctx->extra_cfg);
454
455   if (res == VPX_CODEC_OK) {
456     ctx->cfg = *cfg;
457     set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
458     vp9_change_config(ctx->cpi, &ctx->oxcf);
459   }
460
461   return res;
462 }
463
464 static vpx_codec_err_t ctrl_get_quantizer(vpx_codec_alg_priv_t *ctx,
465                                           va_list args) {
466   int *const arg = va_arg(args, int *);
467   if (arg == NULL)
468     return VPX_CODEC_INVALID_PARAM;
469   *arg = vp9_get_quantizer(ctx->cpi);
470   return VPX_CODEC_OK;
471 }
472
473 static vpx_codec_err_t ctrl_get_quantizer64(vpx_codec_alg_priv_t *ctx,
474                                             va_list args) {
475   int *const arg = va_arg(args, int *);
476   if (arg == NULL)
477     return VPX_CODEC_INVALID_PARAM;
478   *arg = vp9_qindex_to_quantizer(vp9_get_quantizer(ctx->cpi));
479   return VPX_CODEC_OK;
480 }
481
482 static vpx_codec_err_t update_extra_cfg(vpx_codec_alg_priv_t *ctx,
483                                         const struct vp9_extracfg *extra_cfg) {
484   const vpx_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
485   if (res == VPX_CODEC_OK) {
486     ctx->extra_cfg = *extra_cfg;
487     set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
488     vp9_change_config(ctx->cpi, &ctx->oxcf);
489   }
490   return res;
491 }
492
493 static vpx_codec_err_t ctrl_set_cpuused(vpx_codec_alg_priv_t *ctx,
494                                         va_list args) {
495   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
496   extra_cfg.cpu_used = CAST(VP8E_SET_CPUUSED, args);
497   return update_extra_cfg(ctx, &extra_cfg);
498 }
499
500 static vpx_codec_err_t ctrl_set_enable_auto_alt_ref(vpx_codec_alg_priv_t *ctx,
501                                                     va_list args) {
502   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
503   extra_cfg.enable_auto_alt_ref = CAST(VP8E_SET_ENABLEAUTOALTREF, args);
504   return update_extra_cfg(ctx, &extra_cfg);
505 }
506
507 static vpx_codec_err_t ctrl_set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
508                                                   va_list args) {
509   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
510   extra_cfg.noise_sensitivity = CAST(VP8E_SET_NOISE_SENSITIVITY, args);
511   return update_extra_cfg(ctx, &extra_cfg);
512 }
513
514 static vpx_codec_err_t ctrl_set_sharpness(vpx_codec_alg_priv_t *ctx,
515                                           va_list args) {
516   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
517   extra_cfg.sharpness = CAST(VP8E_SET_SHARPNESS, args);
518   return update_extra_cfg(ctx, &extra_cfg);
519 }
520
521 static vpx_codec_err_t ctrl_set_static_thresh(vpx_codec_alg_priv_t *ctx,
522                                               va_list args) {
523   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
524   extra_cfg.static_thresh = CAST(VP8E_SET_STATIC_THRESHOLD, args);
525   return update_extra_cfg(ctx, &extra_cfg);
526 }
527
528 static vpx_codec_err_t ctrl_set_tile_columns(vpx_codec_alg_priv_t *ctx,
529                                              va_list args) {
530   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
531   extra_cfg.tile_columns = CAST(VP9E_SET_TILE_COLUMNS, args);
532   return update_extra_cfg(ctx, &extra_cfg);
533 }
534
535 static vpx_codec_err_t ctrl_set_tile_rows(vpx_codec_alg_priv_t *ctx,
536                                           va_list args) {
537   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
538   extra_cfg.tile_rows = CAST(VP9E_SET_TILE_ROWS, args);
539   return update_extra_cfg(ctx, &extra_cfg);
540 }
541
542 static vpx_codec_err_t ctrl_set_arnr_max_frames(vpx_codec_alg_priv_t *ctx,
543                                                 va_list args) {
544   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
545   extra_cfg.arnr_max_frames = CAST(VP8E_SET_ARNR_MAXFRAMES, args);
546   return update_extra_cfg(ctx, &extra_cfg);
547 }
548
549 static vpx_codec_err_t ctrl_set_arnr_strength(vpx_codec_alg_priv_t *ctx,
550                                               va_list args) {
551   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
552   extra_cfg.arnr_strength = CAST(VP8E_SET_ARNR_STRENGTH, args);
553   return update_extra_cfg(ctx, &extra_cfg);
554 }
555
556 static vpx_codec_err_t ctrl_set_arnr_type(vpx_codec_alg_priv_t *ctx,
557                                           va_list args) {
558   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
559   extra_cfg.arnr_type = CAST(VP8E_SET_ARNR_TYPE, args);
560   return update_extra_cfg(ctx, &extra_cfg);
561 }
562
563 static vpx_codec_err_t ctrl_set_tuning(vpx_codec_alg_priv_t *ctx,
564                                        va_list args) {
565   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
566   extra_cfg.tuning = CAST(VP8E_SET_TUNING, args);
567   return update_extra_cfg(ctx, &extra_cfg);
568 }
569
570 static vpx_codec_err_t ctrl_set_cq_level(vpx_codec_alg_priv_t *ctx,
571                                          va_list args) {
572   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
573   extra_cfg.cq_level = CAST(VP8E_SET_CQ_LEVEL, args);
574   return update_extra_cfg(ctx, &extra_cfg);
575 }
576
577 static vpx_codec_err_t ctrl_set_rc_max_intra_bitrate_pct(
578     vpx_codec_alg_priv_t *ctx, va_list args) {
579   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
580   extra_cfg.rc_max_intra_bitrate_pct =
581       CAST(VP8E_SET_MAX_INTRA_BITRATE_PCT, args);
582   return update_extra_cfg(ctx, &extra_cfg);
583 }
584
585 static vpx_codec_err_t ctrl_set_lossless(vpx_codec_alg_priv_t *ctx,
586                                          va_list args) {
587   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
588   extra_cfg.lossless = CAST(VP9E_SET_LOSSLESS, args);
589   return update_extra_cfg(ctx, &extra_cfg);
590 }
591
592 static vpx_codec_err_t ctrl_set_frame_parallel_decoding_mode(
593     vpx_codec_alg_priv_t *ctx, va_list args) {
594   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
595   extra_cfg.frame_parallel_decoding_mode =
596       CAST(VP9E_SET_FRAME_PARALLEL_DECODING, args);
597   return update_extra_cfg(ctx, &extra_cfg);
598 }
599
600 static vpx_codec_err_t ctrl_set_aq_mode(vpx_codec_alg_priv_t *ctx,
601                                         va_list args) {
602   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
603   extra_cfg.aq_mode = CAST(VP9E_SET_AQ_MODE, args);
604   return update_extra_cfg(ctx, &extra_cfg);
605 }
606
607 static vpx_codec_err_t ctrl_set_frame_periodic_boost(vpx_codec_alg_priv_t *ctx,
608                                                      va_list args) {
609   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
610   extra_cfg.frame_periodic_boost = CAST(VP9E_SET_FRAME_PERIODIC_BOOST, args);
611   return update_extra_cfg(ctx, &extra_cfg);
612 }
613
614 static vpx_codec_err_t encoder_init(vpx_codec_ctx_t *ctx,
615                                     vpx_codec_priv_enc_mr_cfg_t *data) {
616   vpx_codec_err_t res = VPX_CODEC_OK;
617   (void)data;
618
619   if (ctx->priv == NULL) {
620     int i;
621     vpx_codec_enc_cfg_t *cfg;
622     struct vpx_codec_alg_priv *priv = calloc(1, sizeof(*priv));
623
624     if (priv == NULL)
625       return VPX_CODEC_MEM_ERROR;
626
627     ctx->priv = &priv->base;
628     ctx->priv->sz = sizeof(*ctx->priv);
629     ctx->priv->iface = ctx->iface;
630     ctx->priv->alg_priv = priv;
631     ctx->priv->init_flags = ctx->init_flags;
632     ctx->priv->enc.total_encoders = 1;
633
634     if (ctx->config.enc) {
635       // Update the reference to the config structure to an internal copy.
636       ctx->priv->alg_priv->cfg = *ctx->config.enc;
637       ctx->config.enc = &ctx->priv->alg_priv->cfg;
638     }
639
640     cfg = &ctx->priv->alg_priv->cfg;
641
642     // Select the extra vp6 configuration table based on the current
643     // usage value. If the current usage value isn't found, use the
644     // values for usage case 0.
645     for (i = 0;
646          extracfg_map[i].usage && extracfg_map[i].usage != cfg->g_usage;
647          ++i) {}
648
649     priv->extra_cfg = extracfg_map[i].cfg;
650     priv->extra_cfg.pkt_list = &priv->pkt_list.head;
651      // Maximum buffer size approximated based on having multiple ARF.
652     priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 8;
653
654     if (priv->cx_data_sz < 4096)
655       priv->cx_data_sz = 4096;
656
657     priv->cx_data = (unsigned char *)malloc(priv->cx_data_sz);
658     if (priv->cx_data == NULL)
659       return VPX_CODEC_MEM_ERROR;
660
661     vp9_initialize_enc();
662
663     res = validate_config(priv, &priv->cfg, &priv->extra_cfg);
664
665     if (res == VPX_CODEC_OK) {
666       VP9_COMP *cpi;
667       set_encoder_config(&ctx->priv->alg_priv->oxcf,
668                          &ctx->priv->alg_priv->cfg,
669                          &ctx->priv->alg_priv->extra_cfg);
670       cpi = vp9_create_compressor(&ctx->priv->alg_priv->oxcf);
671       if (cpi == NULL)
672         res = VPX_CODEC_MEM_ERROR;
673       else
674         ctx->priv->alg_priv->cpi = cpi;
675     }
676   }
677
678   return res;
679 }
680
681 static vpx_codec_err_t encoder_destroy(vpx_codec_alg_priv_t *ctx) {
682   free(ctx->cx_data);
683   vp9_remove_compressor(ctx->cpi);
684   free(ctx);
685   return VPX_CODEC_OK;
686 }
687
688 static void pick_quickcompress_mode(vpx_codec_alg_priv_t  *ctx,
689                                     unsigned long duration,
690                                     unsigned long deadline) {
691   // Use best quality mode if no deadline is given.
692   MODE new_qc = ONE_PASS_BEST;
693
694   if (deadline) {
695     // Convert duration parameter from stream timebase to microseconds
696     const uint64_t duration_us = (uint64_t)duration * 1000000 *
697                                (uint64_t)ctx->cfg.g_timebase.num /
698                                (uint64_t)ctx->cfg.g_timebase.den;
699
700     // If the deadline is more that the duration this frame is to be shown,
701     // use good quality mode. Otherwise use realtime mode.
702     new_qc = (deadline > duration_us) ? ONE_PASS_GOOD : REALTIME;
703   }
704
705   if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS)
706     new_qc = TWO_PASS_FIRST;
707   else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS)
708     new_qc = (new_qc == ONE_PASS_BEST) ? TWO_PASS_SECOND_BEST
709                                           : TWO_PASS_SECOND_GOOD;
710
711   if (ctx->oxcf.mode != new_qc) {
712     ctx->oxcf.mode = new_qc;
713     vp9_change_config(ctx->cpi, &ctx->oxcf);
714   }
715 }
716
717 // Turn on to test if supplemental superframe data breaks decoding
718 // #define TEST_SUPPLEMENTAL_SUPERFRAME_DATA
719 static int write_superframe_index(vpx_codec_alg_priv_t *ctx) {
720   uint8_t marker = 0xc0;
721   unsigned int mask;
722   int mag, index_sz;
723
724   assert(ctx->pending_frame_count);
725   assert(ctx->pending_frame_count <= 8);
726
727   // Add the number of frames to the marker byte
728   marker |= ctx->pending_frame_count - 1;
729
730   // Choose the magnitude
731   for (mag = 0, mask = 0xff; mag < 4; mag++) {
732     if (ctx->pending_frame_magnitude < mask)
733       break;
734     mask <<= 8;
735     mask |= 0xff;
736   }
737   marker |= mag << 3;
738
739   // Write the index
740   index_sz = 2 + (mag + 1) * ctx->pending_frame_count;
741   if (ctx->pending_cx_data_sz + index_sz < ctx->cx_data_sz) {
742     uint8_t *x = ctx->pending_cx_data + ctx->pending_cx_data_sz;
743     int i, j;
744 #ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
745     uint8_t marker_test = 0xc0;
746     int mag_test = 2;     // 1 - 4
747     int frames_test = 4;  // 1 - 8
748     int index_sz_test = 2 + mag_test * frames_test;
749     marker_test |= frames_test - 1;
750     marker_test |= (mag_test - 1) << 3;
751     *x++ = marker_test;
752     for (i = 0; i < mag_test * frames_test; ++i)
753       *x++ = 0;  // fill up with arbitrary data
754     *x++ = marker_test;
755     ctx->pending_cx_data_sz += index_sz_test;
756     printf("Added supplemental superframe data\n");
757 #endif
758
759     *x++ = marker;
760     for (i = 0; i < ctx->pending_frame_count; i++) {
761       unsigned int this_sz = (unsigned int)ctx->pending_frame_sizes[i];
762
763       for (j = 0; j <= mag; j++) {
764         *x++ = this_sz & 0xff;
765         this_sz >>= 8;
766       }
767     }
768     *x++ = marker;
769     ctx->pending_cx_data_sz += index_sz;
770 #ifdef TEST_SUPPLEMENTAL_SUPERFRAME_DATA
771     index_sz += index_sz_test;
772 #endif
773   }
774   return index_sz;
775 }
776
777 static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t  *ctx,
778                                       const vpx_image_t *img,
779                                       vpx_codec_pts_t pts,
780                                       unsigned long duration,
781                                       vpx_enc_frame_flags_t flags,
782                                       unsigned long deadline) {
783   vpx_codec_err_t res = VPX_CODEC_OK;
784
785   if (img)
786     res = validate_img(ctx, img);
787
788   pick_quickcompress_mode(ctx, duration, deadline);
789   vpx_codec_pkt_list_init(&ctx->pkt_list);
790
791   // Handle Flags
792   if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF)) ||
793        ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF))) {
794     ctx->base.err_detail = "Conflicting flags.";
795     return VPX_CODEC_INVALID_PARAM;
796   }
797
798   vp9_apply_encoding_flags(ctx->cpi, flags);
799
800   // Handle fixed keyframe intervals
801   if (ctx->cfg.kf_mode == VPX_KF_AUTO &&
802       ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) {
803     if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) {
804       flags |= VPX_EFLAG_FORCE_KF;
805       ctx->fixed_kf_cntr = 1;
806     }
807   }
808
809   // Initialize the encoder instance on the first frame.
810   if (res == VPX_CODEC_OK && ctx->cpi != NULL) {
811     unsigned int lib_flags = 0;
812     YV12_BUFFER_CONFIG sd;
813     int64_t dst_time_stamp, dst_end_time_stamp;
814     size_t size, cx_data_sz;
815     unsigned char *cx_data;
816
817     // Set up internal flags
818     if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
819       ((VP9_COMP *)ctx->cpi)->b_calculate_psnr = 1;
820
821     /* vp9 use 10,000,000 ticks/second as time stamp */
822     dst_time_stamp = (pts * 10000000 * ctx->cfg.g_timebase.num)
823                      / ctx->cfg.g_timebase.den;
824     dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num /
825                          ctx->cfg.g_timebase.den;
826
827     if (img != NULL) {
828       res = image2yuvconfig(img, &sd);
829
830       // Store the original flags in to the frame buffer. Will extract the
831       // key frame flag when we actually encode this frame.
832       if (vp9_receive_raw_frame(ctx->cpi, flags,
833                                 &sd, dst_time_stamp, dst_end_time_stamp)) {
834         VP9_COMP *cpi = (VP9_COMP *)ctx->cpi;
835         res = update_error_state(ctx, &cpi->common.error);
836       }
837     }
838
839     cx_data = ctx->cx_data;
840     cx_data_sz = ctx->cx_data_sz;
841
842     /* Any pending invisible frames? */
843     if (ctx->pending_cx_data) {
844       memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz);
845       ctx->pending_cx_data = cx_data;
846       cx_data += ctx->pending_cx_data_sz;
847       cx_data_sz -= ctx->pending_cx_data_sz;
848
849       /* TODO: this is a minimal check, the underlying codec doesn't respect
850        * the buffer size anyway.
851        */
852       if (cx_data_sz < ctx->cx_data_sz / 2) {
853         ctx->base.err_detail = "Compressed data buffer too small";
854         return VPX_CODEC_ERROR;
855       }
856     }
857
858     while (cx_data_sz >= ctx->cx_data_sz / 2 &&
859            -1 != vp9_get_compressed_data(ctx->cpi, &lib_flags, &size,
860                                          cx_data, &dst_time_stamp,
861                                          &dst_end_time_stamp, !img)) {
862       if (size) {
863         vpx_codec_pts_t round, delta;
864         vpx_codec_cx_pkt_t pkt;
865         VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
866
867         // Pack invisible frames with the next visible frame
868         if (cpi->common.show_frame == 0
869 #ifdef CONFIG_SPATIAL_SVC
870             || (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
871                 cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
872 #endif
873             ) {
874           if (ctx->pending_cx_data == 0)
875             ctx->pending_cx_data = cx_data;
876           ctx->pending_cx_data_sz += size;
877           ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
878           ctx->pending_frame_magnitude |= size;
879           cx_data += size;
880           cx_data_sz -= size;
881           continue;
882         }
883
884         // Add the frame packet to the list of returned packets.
885         round = (vpx_codec_pts_t)10000000 * ctx->cfg.g_timebase.num / 2 - 1;
886         delta = (dst_end_time_stamp - dst_time_stamp);
887         pkt.kind = VPX_CODEC_CX_FRAME_PKT;
888         pkt.data.frame.pts =
889           (dst_time_stamp * ctx->cfg.g_timebase.den + round)
890           / ctx->cfg.g_timebase.num / 10000000;
891         pkt.data.frame.duration = (unsigned long)
892           ((delta * ctx->cfg.g_timebase.den + round)
893           / ctx->cfg.g_timebase.num / 10000000);
894         pkt.data.frame.flags = lib_flags << 16;
895
896         if (lib_flags & FRAMEFLAGS_KEY
897 #ifdef CONFIG_SPATIAL_SVC
898             || (cpi->use_svc && cpi->svc.number_temporal_layers == 1 &&
899                 cpi->svc.layer_context[0].is_key_frame)
900 #endif
901             )
902           pkt.data.frame.flags |= VPX_FRAME_IS_KEY;
903
904         if (cpi->common.show_frame == 0) {
905           pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE;
906
907           // This timestamp should be as close as possible to the
908           // prior PTS so that if a decoder uses pts to schedule when
909           // to do this, we start right after last frame was decoded.
910           // Invisible frames have no duration.
911           pkt.data.frame.pts = ((cpi->last_time_stamp_seen
912                                  * ctx->cfg.g_timebase.den + round)
913                                 / ctx->cfg.g_timebase.num / 10000000) + 1;
914           pkt.data.frame.duration = 0;
915         }
916
917         if (cpi->droppable)
918           pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE;
919
920         if (ctx->pending_cx_data) {
921           ctx->pending_frame_sizes[ctx->pending_frame_count++] = size;
922           ctx->pending_frame_magnitude |= size;
923           ctx->pending_cx_data_sz += size;
924           size += write_superframe_index(ctx);
925           pkt.data.frame.buf = ctx->pending_cx_data;
926           pkt.data.frame.sz  = ctx->pending_cx_data_sz;
927           ctx->pending_cx_data = NULL;
928           ctx->pending_cx_data_sz = 0;
929           ctx->pending_frame_count = 0;
930           ctx->pending_frame_magnitude = 0;
931         } else {
932           pkt.data.frame.buf = cx_data;
933           pkt.data.frame.sz  = size;
934         }
935         pkt.data.frame.partition_id = -1;
936         vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
937         cx_data += size;
938         cx_data_sz -= size;
939       }
940     }
941   }
942
943   return res;
944 }
945
946 static const vpx_codec_cx_pkt_t *encoder_get_cxdata(vpx_codec_alg_priv_t *ctx,
947                                                     vpx_codec_iter_t *iter) {
948   return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
949 }
950
951 static vpx_codec_err_t ctrl_set_reference(vpx_codec_alg_priv_t *ctx,
952                                           va_list args) {
953   vpx_ref_frame_t *const frame = va_arg(args, vpx_ref_frame_t *);
954
955   if (frame != NULL) {
956     YV12_BUFFER_CONFIG sd;
957
958     image2yuvconfig(&frame->img, &sd);
959     vp9_set_reference_enc(ctx->cpi, ref_frame_to_vp9_reframe(frame->frame_type),
960                           &sd);
961     return VPX_CODEC_OK;
962   } else {
963     return VPX_CODEC_INVALID_PARAM;
964   }
965 }
966
967 static vpx_codec_err_t ctrl_copy_reference(vpx_codec_alg_priv_t *ctx,
968                                            va_list args) {
969   vpx_ref_frame_t *const frame = va_arg(args, vpx_ref_frame_t *);
970
971   if (frame != NULL) {
972     YV12_BUFFER_CONFIG sd;
973
974     image2yuvconfig(&frame->img, &sd);
975     vp9_copy_reference_enc(ctx->cpi,
976                            ref_frame_to_vp9_reframe(frame->frame_type), &sd);
977     return VPX_CODEC_OK;
978   } else {
979     return VPX_CODEC_INVALID_PARAM;
980   }
981 }
982
983 static vpx_codec_err_t ctrl_get_reference(vpx_codec_alg_priv_t *ctx,
984                                           va_list args) {
985   vp9_ref_frame_t *const frame = va_arg(args, vp9_ref_frame_t *);
986
987   if (frame != NULL) {
988     YV12_BUFFER_CONFIG *fb;
989
990     vp9_get_reference_enc(ctx->cpi, frame->idx, &fb);
991     yuvconfig2image(&frame->img, fb, NULL);
992     return VPX_CODEC_OK;
993   } else {
994     return VPX_CODEC_INVALID_PARAM;
995   }
996 }
997
998 static vpx_codec_err_t ctrl_set_previewpp(vpx_codec_alg_priv_t *ctx,
999                                           va_list args) {
1000 #if CONFIG_VP9_POSTPROC
1001   vp8_postproc_cfg_t *config = va_arg(args, vp8_postproc_cfg_t *);
1002   if (config != NULL) {
1003     ctx->preview_ppcfg = *config;
1004     return VPX_CODEC_OK;
1005   } else {
1006     return VPX_CODEC_INVALID_PARAM;
1007   }
1008 #else
1009   (void)ctx;
1010   (void)args;
1011   return VPX_CODEC_INCAPABLE;
1012 #endif
1013 }
1014
1015
1016 static vpx_image_t *encoder_get_preview(vpx_codec_alg_priv_t *ctx) {
1017   YV12_BUFFER_CONFIG sd;
1018   vp9_ppflags_t flags;
1019   vp9_zero(flags);
1020
1021   if (ctx->preview_ppcfg.post_proc_flag) {
1022     flags.post_proc_flag   = ctx->preview_ppcfg.post_proc_flag;
1023     flags.deblocking_level = ctx->preview_ppcfg.deblocking_level;
1024     flags.noise_level      = ctx->preview_ppcfg.noise_level;
1025   }
1026
1027   if (vp9_get_preview_raw_frame(ctx->cpi, &sd, &flags) == 0) {
1028     yuvconfig2image(&ctx->preview_img, &sd, NULL);
1029     return &ctx->preview_img;
1030   } else {
1031     return NULL;
1032   }
1033 }
1034
1035 static vpx_codec_err_t ctrl_update_entropy(vpx_codec_alg_priv_t *ctx,
1036                                            va_list args) {
1037   const int update = va_arg(args, int);
1038
1039   vp9_update_entropy(ctx->cpi, update);
1040   return VPX_CODEC_OK;
1041 }
1042
1043 static vpx_codec_err_t ctrl_update_reference(vpx_codec_alg_priv_t *ctx,
1044                                              va_list args) {
1045   const int ref_frame_flags = va_arg(args, int);
1046
1047   vp9_update_reference(ctx->cpi, ref_frame_flags);
1048   return VPX_CODEC_OK;
1049 }
1050
1051 static vpx_codec_err_t ctrl_use_reference(vpx_codec_alg_priv_t *ctx,
1052                                           va_list args) {
1053   const int reference_flag = va_arg(args, int);
1054
1055   vp9_use_as_reference(ctx->cpi, reference_flag);
1056   return VPX_CODEC_OK;
1057 }
1058
1059 static vpx_codec_err_t ctrl_set_roi_map(vpx_codec_alg_priv_t *ctx,
1060                                         va_list args) {
1061   (void)ctx;
1062   (void)args;
1063
1064   // TODO(yaowu): Need to re-implement and test for VP9.
1065   return VPX_CODEC_INVALID_PARAM;
1066 }
1067
1068
1069 static vpx_codec_err_t ctrl_set_active_map(vpx_codec_alg_priv_t *ctx,
1070                                            va_list args) {
1071   vpx_active_map_t *const map = va_arg(args, vpx_active_map_t *);
1072
1073   if (map) {
1074     if (!vp9_set_active_map(ctx->cpi, map->active_map,
1075                             (int)map->rows, (int)map->cols))
1076       return VPX_CODEC_OK;
1077     else
1078       return VPX_CODEC_INVALID_PARAM;
1079   } else {
1080     return VPX_CODEC_INVALID_PARAM;
1081   }
1082 }
1083
1084 static vpx_codec_err_t ctrl_set_scale_mode(vpx_codec_alg_priv_t *ctx,
1085                                            va_list args) {
1086   vpx_scaling_mode_t *const mode = va_arg(args, vpx_scaling_mode_t *);
1087
1088   if (mode) {
1089     const int res = vp9_set_internal_size(ctx->cpi,
1090                                           (VPX_SCALING)mode->h_scaling_mode,
1091                                           (VPX_SCALING)mode->v_scaling_mode);
1092     return (res == 0) ? VPX_CODEC_OK : VPX_CODEC_INVALID_PARAM;
1093   } else {
1094     return VPX_CODEC_INVALID_PARAM;
1095   }
1096 }
1097
1098 static vpx_codec_err_t ctrl_set_svc(vpx_codec_alg_priv_t *ctx, va_list args) {
1099   int data = va_arg(args, int);
1100   const vpx_codec_enc_cfg_t *cfg = &ctx->cfg;
1101
1102   vp9_set_svc(ctx->cpi, data);
1103   // CBR or two pass mode for SVC with both temporal and spatial layers
1104   // not yet supported.
1105   if (data == 1 &&
1106       (cfg->rc_end_usage == VPX_CBR ||
1107        cfg->g_pass == VPX_RC_FIRST_PASS ||
1108        cfg->g_pass == VPX_RC_LAST_PASS) &&
1109       cfg->ss_number_layers > 1 &&
1110       cfg->ts_number_layers > 1) {
1111     return VPX_CODEC_INVALID_PARAM;
1112   }
1113   return VPX_CODEC_OK;
1114 }
1115
1116 static vpx_codec_err_t ctrl_set_svc_layer_id(vpx_codec_alg_priv_t *ctx,
1117                                              va_list args) {
1118   vpx_svc_layer_id_t *const data = va_arg(args, vpx_svc_layer_id_t *);
1119   VP9_COMP *const cpi = (VP9_COMP *)ctx->cpi;
1120   SVC *const svc = &cpi->svc;
1121
1122   svc->spatial_layer_id = data->spatial_layer_id;
1123   svc->temporal_layer_id = data->temporal_layer_id;
1124   // Checks on valid layer_id input.
1125   if (svc->temporal_layer_id < 0 ||
1126       svc->temporal_layer_id >= (int)ctx->cfg.ts_number_layers) {
1127     return VPX_CODEC_INVALID_PARAM;
1128   }
1129   if (svc->spatial_layer_id < 0 ||
1130       svc->spatial_layer_id >= (int)ctx->cfg.ss_number_layers) {
1131     return VPX_CODEC_INVALID_PARAM;
1132   }
1133   return VPX_CODEC_OK;
1134 }
1135
1136 static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
1137                                                va_list args) {
1138   VP9_COMP *const cpi = ctx->cpi;
1139   vpx_svc_parameters_t *const params = va_arg(args, vpx_svc_parameters_t *);
1140
1141   if (params == NULL || params->spatial_layer < 0 ||
1142       params->spatial_layer >= cpi->svc.number_spatial_layers)
1143     return VPX_CODEC_INVALID_PARAM;
1144
1145   if (params->spatial_layer == 0) {
1146     int i;
1147     for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
1148       cpi->svc.layer_context[i].svc_params_received.spatial_layer = -1;
1149     }
1150   }
1151
1152   cpi->svc.layer_context[params->spatial_layer].svc_params_received =
1153       *params;
1154
1155   return VPX_CODEC_OK;
1156 }
1157
1158 static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
1159   {VP8_COPY_REFERENCE,                ctrl_copy_reference},
1160   {VP8E_UPD_ENTROPY,                  ctrl_update_entropy},
1161   {VP8E_UPD_REFERENCE,                ctrl_update_reference},
1162   {VP8E_USE_REFERENCE,                ctrl_use_reference},
1163
1164   // Setters
1165   {VP8_SET_REFERENCE,                 ctrl_set_reference},
1166   {VP8_SET_POSTPROC,                  ctrl_set_previewpp},
1167   {VP8E_SET_ROI_MAP,                  ctrl_set_roi_map},
1168   {VP8E_SET_ACTIVEMAP,                ctrl_set_active_map},
1169   {VP8E_SET_SCALEMODE,                ctrl_set_scale_mode},
1170   {VP8E_SET_CPUUSED,                  ctrl_set_cpuused},
1171   {VP8E_SET_NOISE_SENSITIVITY,        ctrl_set_noise_sensitivity},
1172   {VP8E_SET_ENABLEAUTOALTREF,         ctrl_set_enable_auto_alt_ref},
1173   {VP8E_SET_SHARPNESS,                ctrl_set_sharpness},
1174   {VP8E_SET_STATIC_THRESHOLD,         ctrl_set_static_thresh},
1175   {VP9E_SET_TILE_COLUMNS,             ctrl_set_tile_columns},
1176   {VP9E_SET_TILE_ROWS,                ctrl_set_tile_rows},
1177   {VP8E_SET_ARNR_MAXFRAMES,           ctrl_set_arnr_max_frames},
1178   {VP8E_SET_ARNR_STRENGTH,            ctrl_set_arnr_strength},
1179   {VP8E_SET_ARNR_TYPE,                ctrl_set_arnr_type},
1180   {VP8E_SET_TUNING,                   ctrl_set_tuning},
1181   {VP8E_SET_CQ_LEVEL,                 ctrl_set_cq_level},
1182   {VP8E_SET_MAX_INTRA_BITRATE_PCT,    ctrl_set_rc_max_intra_bitrate_pct},
1183   {VP9E_SET_LOSSLESS,                 ctrl_set_lossless},
1184   {VP9E_SET_FRAME_PARALLEL_DECODING,  ctrl_set_frame_parallel_decoding_mode},
1185   {VP9E_SET_AQ_MODE,                  ctrl_set_aq_mode},
1186   {VP9E_SET_FRAME_PERIODIC_BOOST,     ctrl_set_frame_periodic_boost},
1187   {VP9E_SET_SVC,                      ctrl_set_svc},
1188   {VP9E_SET_SVC_PARAMETERS,           ctrl_set_svc_parameters},
1189   {VP9E_SET_SVC_LAYER_ID,             ctrl_set_svc_layer_id},
1190
1191   // Getters
1192   {VP8E_GET_LAST_QUANTIZER,           ctrl_get_quantizer},
1193   {VP8E_GET_LAST_QUANTIZER_64,        ctrl_get_quantizer64},
1194   {VP9_GET_REFERENCE,                 ctrl_get_reference},
1195
1196   { -1, NULL},
1197 };
1198
1199 static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
1200   {
1201     0,
1202     {  // NOLINT
1203       0,                  // g_usage
1204       0,                  // g_threads
1205       0,                  // g_profile
1206
1207       320,                // g_width
1208       240,                // g_height
1209       {1, 30},            // g_timebase
1210
1211       0,                  // g_error_resilient
1212
1213       VPX_RC_ONE_PASS,    // g_pass
1214
1215       25,                 // g_lag_in_frames
1216
1217       0,                  // rc_dropframe_thresh
1218       0,                  // rc_resize_allowed
1219       1,                  // rc_scaled_width
1220       1,                  // rc_scaled_height
1221       60,                 // rc_resize_down_thresold
1222       30,                 // rc_resize_up_thresold
1223
1224       VPX_VBR,            // rc_end_usage
1225 #if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
1226       {NULL, 0},          // rc_twopass_stats_in
1227 #endif
1228       256,                // rc_target_bandwidth
1229       0,                  // rc_min_quantizer
1230       63,                 // rc_max_quantizer
1231       100,                // rc_undershoot_pct
1232       100,                // rc_overshoot_pct
1233
1234       6000,               // rc_max_buffer_size
1235       4000,               // rc_buffer_initial_size
1236       5000,               // rc_buffer_optimal_size
1237
1238       50,                 // rc_two_pass_vbrbias
1239       0,                  // rc_two_pass_vbrmin_section
1240       2000,               // rc_two_pass_vbrmax_section
1241
1242       // keyframing settings (kf)
1243       VPX_KF_AUTO,        // g_kfmode
1244       0,                  // kf_min_dist
1245       9999,               // kf_max_dist
1246
1247       VPX_SS_DEFAULT_LAYERS,  // ss_number_layers
1248       {0},                    // ss_target_bitrate
1249       1,                      // ts_number_layers
1250       {0},                    // ts_target_bitrate
1251       {0},                    // ts_rate_decimator
1252       0,                      // ts_periodicity
1253       {0},                    // ts_layer_id
1254 #if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION)
1255       "vp8.fpf"           // first pass filename
1256 #endif
1257     }
1258   },
1259   { -1, {NOT_IMPLEMENTED}}
1260 };
1261
1262 #ifndef VERSION_STRING
1263 #define VERSION_STRING
1264 #endif
1265 CODEC_INTERFACE(vpx_codec_vp9_cx) = {
1266   "WebM Project VP9 Encoder" VERSION_STRING,
1267   VPX_CODEC_INTERNAL_ABI_VERSION,
1268   VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR,  // vpx_codec_caps_t
1269   encoder_init,       // vpx_codec_init_fn_t
1270   encoder_destroy,    // vpx_codec_destroy_fn_t
1271   encoder_ctrl_maps,  // vpx_codec_ctrl_fn_map_t
1272   NOT_IMPLEMENTED,    // vpx_codec_get_mmap_fn_t
1273   NOT_IMPLEMENTED,    // vpx_codec_set_mmap_fn_t
1274   {  // NOLINT
1275     NOT_IMPLEMENTED,  // vpx_codec_peek_si_fn_t
1276     NOT_IMPLEMENTED,  // vpx_codec_get_si_fn_t
1277     NOT_IMPLEMENTED,  // vpx_codec_decode_fn_t
1278     NOT_IMPLEMENTED,  // vpx_codec_frame_get_fn_t
1279     NOT_IMPLEMENTED   // vpx_codec_set_fb_fn_t
1280   },
1281   {  // NOLINT
1282     encoder_usage_cfg_map,  // vpx_codec_enc_cfg_map_t
1283     encoder_encode,         // vpx_codec_encode_fn_t
1284     encoder_get_cxdata,     // vpx_codec_get_cx_data_fn_t
1285     encoder_set_config,     // vpx_codec_enc_config_set_fn_t
1286     NOT_IMPLEMENTED,        // vpx_codec_get_global_headers_fn_t
1287     encoder_get_preview,    // vpx_codec_get_preview_frame_fn_t
1288     NOT_IMPLEMENTED         // vpx_codec_enc_mr_get_mem_loc_fn_t
1289   }
1290 };