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
12#include "vp8_rtcd.h"
13#include "vpx/vpx_codec.h"
14#include "vpx/internal/vpx_codec_internal.h"
15#include "vpx_version.h"
16#include "vp8/encoder/onyx_int.h"
17#include "vpx/vp8cx.h"
18#include "vp8/encoder/firstpass.h"
19#include "vp8/common/onyx.h"
20#include <stdlib.h>
21#include <string.h>
22
23struct vp8_extracfg
24{
25    struct vpx_codec_pkt_list *pkt_list;
26    int                         cpu_used;                    /** available cpu percentage in 1/16*/
27    unsigned int                enable_auto_alt_ref;           /** if encoder decides to uses alternate reference frame */
28    unsigned int                noise_sensitivity;
29    unsigned int                Sharpness;
30    unsigned int                static_thresh;
31    unsigned int                token_partitions;
32    unsigned int                arnr_max_frames;    /* alt_ref Noise Reduction Max Frame Count */
33    unsigned int                arnr_strength;    /* alt_ref Noise Reduction Strength */
34    unsigned int                arnr_type;        /* alt_ref filter type */
35    vp8e_tuning                 tuning;
36    unsigned int                cq_level;         /* constrained quality level */
37    unsigned int                rc_max_intra_bitrate_pct;
38
39};
40
41struct extraconfig_map
42{
43    int                 usage;
44    struct vp8_extracfg cfg;
45};
46
47static const struct extraconfig_map extracfg_map[] =
48{
49    {
50        0,
51        {
52            NULL,
53#if !(CONFIG_REALTIME_ONLY)
54            0,                          /* cpu_used      */
55#else
56            4,                          /* cpu_used      */
57#endif
58            0,                          /* enable_auto_alt_ref */
59            0,                          /* noise_sensitivity */
60            0,                          /* Sharpness */
61            0,                          /* static_thresh */
62#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
63            VP8_EIGHT_TOKENPARTITION,
64#else
65            VP8_ONE_TOKENPARTITION,     /* token_partitions */
66#endif
67            0,                          /* arnr_max_frames */
68            3,                          /* arnr_strength */
69            3,                          /* arnr_type*/
70            0,                          /* tuning*/
71            10,                         /* cq_level */
72            0,                          /* rc_max_intra_bitrate_pct */
73        }
74    }
75};
76
77struct vpx_codec_alg_priv
78{
79    vpx_codec_priv_t        base;
80    vpx_codec_enc_cfg_t     cfg;
81    struct vp8_extracfg     vp8_cfg;
82    VP8_CONFIG              oxcf;
83    struct VP8_COMP        *cpi;
84    unsigned char          *cx_data;
85    unsigned int            cx_data_sz;
86    vpx_image_t             preview_img;
87    unsigned int            next_frame_flag;
88    vp8_postproc_cfg_t      preview_ppcfg;
89    /* pkt_list size depends on the maximum number of lagged frames allowed. */
90    vpx_codec_pkt_list_decl(64) pkt_list;
91    unsigned int                fixed_kf_cntr;
92};
93
94
95static vpx_codec_err_t
96update_error_state(vpx_codec_alg_priv_t                 *ctx,
97                   const struct vpx_internal_error_info *error)
98{
99    vpx_codec_err_t res;
100
101    if ((res = error->error_code))
102        ctx->base.err_detail = error->has_detail
103                               ? error->detail
104                               : NULL;
105
106    return res;
107}
108
109
110#undef ERROR
111#define ERROR(str) do {\
112        ctx->base.err_detail = str;\
113        return VPX_CODEC_INVALID_PARAM;\
114    } while(0)
115
116#define RANGE_CHECK(p,memb,lo,hi) do {\
117        if(!(((p)->memb == lo || (p)->memb > (lo)) && (p)->memb <= hi)) \
118            ERROR(#memb " out of range ["#lo".."#hi"]");\
119    } while(0)
120
121#define RANGE_CHECK_HI(p,memb,hi) do {\
122        if(!((p)->memb <= (hi))) \
123            ERROR(#memb " out of range [.."#hi"]");\
124    } while(0)
125
126#define RANGE_CHECK_LO(p,memb,lo) do {\
127        if(!((p)->memb >= (lo))) \
128            ERROR(#memb " out of range ["#lo"..]");\
129    } while(0)
130
131#define RANGE_CHECK_BOOL(p,memb) do {\
132        if(!!((p)->memb) != (p)->memb) ERROR(#memb " expected boolean");\
133    } while(0)
134
135static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t      *ctx,
136                                       const vpx_codec_enc_cfg_t *cfg,
137                                       const struct vp8_extracfg *vp8_cfg,
138                                       int                        finalize)
139{
140    RANGE_CHECK(cfg, g_w,                   1, 16383); /* 14 bits available */
141    RANGE_CHECK(cfg, g_h,                   1, 16383); /* 14 bits available */
142    RANGE_CHECK(cfg, g_timebase.den,        1, 1000000000);
143    RANGE_CHECK(cfg, g_timebase.num,        1, cfg->g_timebase.den);
144    RANGE_CHECK_HI(cfg, g_profile,          3);
145    RANGE_CHECK_HI(cfg, rc_max_quantizer,   63);
146    RANGE_CHECK_HI(cfg, rc_min_quantizer,   cfg->rc_max_quantizer);
147    RANGE_CHECK_HI(cfg, g_threads,          64);
148#if CONFIG_REALTIME_ONLY
149    RANGE_CHECK_HI(cfg, g_lag_in_frames,    0);
150#elif CONFIG_MULTI_RES_ENCODING
151    if (ctx->base.enc.total_encoders > 1)
152        RANGE_CHECK_HI(cfg, g_lag_in_frames,    0);
153#else
154    RANGE_CHECK_HI(cfg, g_lag_in_frames,    25);
155#endif
156    RANGE_CHECK(cfg, rc_end_usage,          VPX_VBR, VPX_Q);
157    RANGE_CHECK_HI(cfg, rc_undershoot_pct,  1000);
158    RANGE_CHECK_HI(cfg, rc_overshoot_pct,   1000);
159    RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
160    RANGE_CHECK(cfg, kf_mode,               VPX_KF_DISABLED, VPX_KF_AUTO);
161
162/* TODO: add spatial re-sampling support and frame dropping in
163 * multi-res-encoder.*/
164#if CONFIG_MULTI_RES_ENCODING
165    if (ctx->base.enc.total_encoders > 1)
166        RANGE_CHECK_HI(cfg, rc_resize_allowed,     0);
167#else
168    RANGE_CHECK_BOOL(cfg, rc_resize_allowed);
169#endif
170    RANGE_CHECK_HI(cfg, rc_dropframe_thresh,   100);
171    RANGE_CHECK_HI(cfg, rc_resize_up_thresh,   100);
172    RANGE_CHECK_HI(cfg, rc_resize_down_thresh, 100);
173
174#if CONFIG_REALTIME_ONLY
175    RANGE_CHECK(cfg,        g_pass,         VPX_RC_ONE_PASS, VPX_RC_ONE_PASS);
176#elif CONFIG_MULTI_RES_ENCODING
177    if (ctx->base.enc.total_encoders > 1)
178        RANGE_CHECK(cfg,    g_pass,         VPX_RC_ONE_PASS, VPX_RC_ONE_PASS);
179#else
180    RANGE_CHECK(cfg,        g_pass,         VPX_RC_ONE_PASS, VPX_RC_LAST_PASS);
181#endif
182
183    /* VP8 does not support a lower bound on the keyframe interval in
184     * automatic keyframe placement mode.
185     */
186    if (cfg->kf_mode != VPX_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist
187        && cfg->kf_min_dist > 0)
188        ERROR("kf_min_dist not supported in auto mode, use 0 "
189              "or kf_max_dist instead.");
190
191    RANGE_CHECK_BOOL(vp8_cfg,               enable_auto_alt_ref);
192    RANGE_CHECK(vp8_cfg, cpu_used,           -16, 16);
193
194#if CONFIG_REALTIME_ONLY && !CONFIG_TEMPORAL_DENOISING
195    RANGE_CHECK(vp8_cfg, noise_sensitivity,  0, 0);
196#else
197    RANGE_CHECK_HI(vp8_cfg, noise_sensitivity,  6);
198#endif
199
200    RANGE_CHECK(vp8_cfg, token_partitions,   VP8_ONE_TOKENPARTITION,
201                VP8_EIGHT_TOKENPARTITION);
202    RANGE_CHECK_HI(vp8_cfg, Sharpness,       7);
203    RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15);
204    RANGE_CHECK_HI(vp8_cfg, arnr_strength,   6);
205    RANGE_CHECK(vp8_cfg, arnr_type,       1, 3);
206    RANGE_CHECK(vp8_cfg, cq_level, 0, 63);
207    if (finalize && (cfg->rc_end_usage == VPX_CQ || cfg->rc_end_usage == VPX_Q))
208        RANGE_CHECK(vp8_cfg, cq_level,
209                    cfg->rc_min_quantizer, cfg->rc_max_quantizer);
210
211#if !(CONFIG_REALTIME_ONLY)
212    if (cfg->g_pass == VPX_RC_LAST_PASS)
213    {
214        size_t           packet_sz = sizeof(FIRSTPASS_STATS);
215        int              n_packets = (int)(cfg->rc_twopass_stats_in.sz /
216                                          packet_sz);
217        FIRSTPASS_STATS *stats;
218
219        if (!cfg->rc_twopass_stats_in.buf)
220            ERROR("rc_twopass_stats_in.buf not set.");
221
222        if (cfg->rc_twopass_stats_in.sz % packet_sz)
223            ERROR("rc_twopass_stats_in.sz indicates truncated packet.");
224
225        if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz)
226            ERROR("rc_twopass_stats_in requires at least two packets.");
227
228        stats = (void*)((char *)cfg->rc_twopass_stats_in.buf
229                + (n_packets - 1) * packet_sz);
230
231        if ((int)(stats->count + 0.5) != n_packets - 1)
232            ERROR("rc_twopass_stats_in missing EOS stats packet");
233    }
234#endif
235
236    RANGE_CHECK(cfg, ts_number_layers, 1, 5);
237
238    if (cfg->ts_number_layers > 1)
239    {
240        unsigned int i;
241        RANGE_CHECK_HI(cfg, ts_periodicity, 16);
242
243        for (i=1; i<cfg->ts_number_layers; i++)
244            if (cfg->ts_target_bitrate[i] <= cfg->ts_target_bitrate[i-1])
245                ERROR("ts_target_bitrate entries are not strictly increasing");
246
247        RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers-1], 1, 1);
248        for (i=cfg->ts_number_layers-2; i>0; i--)
249            if (cfg->ts_rate_decimator[i-1] != 2*cfg->ts_rate_decimator[i])
250                ERROR("ts_rate_decimator factors are not powers of 2");
251
252        RANGE_CHECK_HI(cfg, ts_layer_id[i], cfg->ts_number_layers-1);
253    }
254
255#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
256    if(cfg->g_threads > (1 << vp8_cfg->token_partitions))
257        ERROR("g_threads cannot be bigger than number of token partitions");
258#endif
259
260    return VPX_CODEC_OK;
261}
262
263
264static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
265                                    const vpx_image_t    *img)
266{
267    switch (img->fmt)
268    {
269    case VPX_IMG_FMT_YV12:
270    case VPX_IMG_FMT_I420:
271    case VPX_IMG_FMT_VPXI420:
272    case VPX_IMG_FMT_VPXYV12:
273        break;
274    default:
275        ERROR("Invalid image format. Only YV12 and I420 images are supported");
276    }
277
278    if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h))
279        ERROR("Image size must match encoder init configuration size");
280
281    return VPX_CODEC_OK;
282}
283
284
285static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
286                                       vpx_codec_enc_cfg_t cfg,
287                                       struct vp8_extracfg vp8_cfg,
288                                       vpx_codec_priv_enc_mr_cfg_t *mr_cfg)
289{
290    oxcf->multi_threaded         = cfg.g_threads;
291    oxcf->Version               = cfg.g_profile;
292
293    oxcf->Width                 = cfg.g_w;
294    oxcf->Height                = cfg.g_h;
295    oxcf->timebase              = cfg.g_timebase;
296
297    oxcf->error_resilient_mode = cfg.g_error_resilient;
298
299    (void)mr_cfg;
300
301    switch (cfg.g_pass)
302    {
303    case VPX_RC_ONE_PASS:
304        oxcf->Mode = MODE_BESTQUALITY;
305        break;
306    case VPX_RC_FIRST_PASS:
307        oxcf->Mode = MODE_FIRSTPASS;
308        break;
309    case VPX_RC_LAST_PASS:
310        oxcf->Mode = MODE_SECONDPASS_BEST;
311        break;
312    }
313
314    if (cfg.g_pass == VPX_RC_FIRST_PASS || cfg.g_pass == VPX_RC_ONE_PASS)
315    {
316        oxcf->allow_lag     = 0;
317        oxcf->lag_in_frames = 0;
318    }
319    else
320    {
321        oxcf->allow_lag     = (cfg.g_lag_in_frames) > 0;
322        oxcf->lag_in_frames = cfg.g_lag_in_frames;
323    }
324
325    oxcf->allow_df               = (cfg.rc_dropframe_thresh > 0);
326    oxcf->drop_frames_water_mark   = cfg.rc_dropframe_thresh;
327
328    oxcf->allow_spatial_resampling = cfg.rc_resize_allowed;
329    oxcf->resample_up_water_mark   = cfg.rc_resize_up_thresh;
330    oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh;
331
332    if (cfg.rc_end_usage == VPX_VBR) {
333      oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
334    } else if (cfg.rc_end_usage == VPX_CBR) {
335      oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
336    } else if (cfg.rc_end_usage == VPX_CQ) {
337      oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
338    } else if (cfg.rc_end_usage == VPX_Q) {
339      oxcf->end_usage = USAGE_CONSTANT_QUALITY;
340    }
341
342    oxcf->target_bandwidth         = cfg.rc_target_bitrate;
343    oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct;
344
345    oxcf->best_allowed_q           = cfg.rc_min_quantizer;
346    oxcf->worst_allowed_q          = cfg.rc_max_quantizer;
347    oxcf->cq_level                 = vp8_cfg.cq_level;
348    oxcf->fixed_q = -1;
349
350    oxcf->under_shoot_pct          = cfg.rc_undershoot_pct;
351    oxcf->over_shoot_pct           = cfg.rc_overshoot_pct;
352
353    oxcf->maximum_buffer_size_in_ms   = cfg.rc_buf_sz;
354    oxcf->starting_buffer_level_in_ms = cfg.rc_buf_initial_sz;
355    oxcf->optimal_buffer_level_in_ms  = cfg.rc_buf_optimal_sz;
356
357    oxcf->maximum_buffer_size      = cfg.rc_buf_sz;
358    oxcf->starting_buffer_level    = cfg.rc_buf_initial_sz;
359    oxcf->optimal_buffer_level     = cfg.rc_buf_optimal_sz;
360
361    oxcf->two_pass_vbrbias         = cfg.rc_2pass_vbr_bias_pct;
362    oxcf->two_pass_vbrmin_section  = cfg.rc_2pass_vbr_minsection_pct;
363    oxcf->two_pass_vbrmax_section  = cfg.rc_2pass_vbr_maxsection_pct;
364
365    oxcf->auto_key                 = cfg.kf_mode == VPX_KF_AUTO
366                                       && cfg.kf_min_dist != cfg.kf_max_dist;
367    oxcf->key_freq                 = cfg.kf_max_dist;
368
369    oxcf->number_of_layers         = cfg.ts_number_layers;
370    oxcf->periodicity              = cfg.ts_periodicity;
371
372    if (oxcf->number_of_layers > 1)
373    {
374        memcpy (oxcf->target_bitrate, cfg.ts_target_bitrate,
375                          sizeof(cfg.ts_target_bitrate));
376        memcpy (oxcf->rate_decimator, cfg.ts_rate_decimator,
377                          sizeof(cfg.ts_rate_decimator));
378        memcpy (oxcf->layer_id, cfg.ts_layer_id, sizeof(cfg.ts_layer_id));
379    }
380
381#if CONFIG_MULTI_RES_ENCODING
382    /* When mr_cfg is NULL, oxcf->mr_total_resolutions and oxcf->mr_encoder_id
383     * are both memset to 0, which ensures the correct logic under this
384     * situation.
385     */
386    if(mr_cfg)
387    {
388        oxcf->mr_total_resolutions        = mr_cfg->mr_total_resolutions;
389        oxcf->mr_encoder_id               = mr_cfg->mr_encoder_id;
390        oxcf->mr_down_sampling_factor.num = mr_cfg->mr_down_sampling_factor.num;
391        oxcf->mr_down_sampling_factor.den = mr_cfg->mr_down_sampling_factor.den;
392        oxcf->mr_low_res_mode_info        = mr_cfg->mr_low_res_mode_info;
393    }
394#endif
395
396    oxcf->cpu_used               = vp8_cfg.cpu_used;
397    oxcf->encode_breakout        = vp8_cfg.static_thresh;
398    oxcf->play_alternate         = vp8_cfg.enable_auto_alt_ref;
399    oxcf->noise_sensitivity      = vp8_cfg.noise_sensitivity;
400    oxcf->Sharpness              = vp8_cfg.Sharpness;
401    oxcf->token_partitions       = vp8_cfg.token_partitions;
402
403    oxcf->two_pass_stats_in      = cfg.rc_twopass_stats_in;
404    oxcf->output_pkt_list        = vp8_cfg.pkt_list;
405
406    oxcf->arnr_max_frames        = vp8_cfg.arnr_max_frames;
407    oxcf->arnr_strength          = vp8_cfg.arnr_strength;
408    oxcf->arnr_type              = vp8_cfg.arnr_type;
409
410    oxcf->tuning                 = vp8_cfg.tuning;
411
412    /*
413        printf("Current VP8 Settings: \n");
414        printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
415        printf("noise_sensitivity: %d\n", oxcf->noise_sensitivity);
416        printf("Sharpness: %d\n",    oxcf->Sharpness);
417        printf("cpu_used: %d\n",  oxcf->cpu_used);
418        printf("Mode: %d\n",     oxcf->Mode);
419        printf("auto_key: %d\n",  oxcf->auto_key);
420        printf("key_freq: %d\n", oxcf->key_freq);
421        printf("end_usage: %d\n", oxcf->end_usage);
422        printf("under_shoot_pct: %d\n", oxcf->under_shoot_pct);
423        printf("over_shoot_pct: %d\n", oxcf->over_shoot_pct);
424        printf("starting_buffer_level: %d\n", oxcf->starting_buffer_level);
425        printf("optimal_buffer_level: %d\n",  oxcf->optimal_buffer_level);
426        printf("maximum_buffer_size: %d\n", oxcf->maximum_buffer_size);
427        printf("fixed_q: %d\n",  oxcf->fixed_q);
428        printf("worst_allowed_q: %d\n", oxcf->worst_allowed_q);
429        printf("best_allowed_q: %d\n", oxcf->best_allowed_q);
430        printf("allow_spatial_resampling: %d\n",  oxcf->allow_spatial_resampling);
431        printf("resample_down_water_mark: %d\n", oxcf->resample_down_water_mark);
432        printf("resample_up_water_mark: %d\n", oxcf->resample_up_water_mark);
433        printf("allow_df: %d\n", oxcf->allow_df);
434        printf("drop_frames_water_mark: %d\n", oxcf->drop_frames_water_mark);
435        printf("two_pass_vbrbias: %d\n",  oxcf->two_pass_vbrbias);
436        printf("two_pass_vbrmin_section: %d\n", oxcf->two_pass_vbrmin_section);
437        printf("two_pass_vbrmax_section: %d\n", oxcf->two_pass_vbrmax_section);
438        printf("allow_lag: %d\n", oxcf->allow_lag);
439        printf("lag_in_frames: %d\n", oxcf->lag_in_frames);
440        printf("play_alternate: %d\n", oxcf->play_alternate);
441        printf("Version: %d\n", oxcf->Version);
442        printf("multi_threaded: %d\n",   oxcf->multi_threaded);
443        printf("encode_breakout: %d\n", oxcf->encode_breakout);
444    */
445    return VPX_CODEC_OK;
446}
447
448static vpx_codec_err_t vp8e_set_config(vpx_codec_alg_priv_t       *ctx,
449                                       const vpx_codec_enc_cfg_t  *cfg)
450{
451    vpx_codec_err_t res;
452
453    if (((cfg->g_w != ctx->cfg.g_w) || (cfg->g_h != ctx->cfg.g_h))
454        && (cfg->g_lag_in_frames > 1 || cfg->g_pass != VPX_RC_ONE_PASS))
455        ERROR("Cannot change width or height after initialization");
456
457    /* Prevent increasing lag_in_frames. This check is stricter than it needs
458     * to be -- the limit is not increasing past the first lag_in_frames
459     * value, but we don't track the initial config, only the last successful
460     * config.
461     */
462    if ((cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames))
463        ERROR("Cannot increase lag_in_frames");
464
465    res = validate_config(ctx, cfg, &ctx->vp8_cfg, 0);
466
467    if (!res)
468    {
469        ctx->cfg = *cfg;
470        set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL);
471        vp8_change_config(ctx->cpi, &ctx->oxcf);
472    }
473
474    return res;
475}
476
477
478int vp8_reverse_trans(int);
479
480
481static vpx_codec_err_t get_param(vpx_codec_alg_priv_t *ctx,
482                                 int                   ctrl_id,
483                                 va_list               args)
484{
485    void *arg = va_arg(args, void *);
486
487#define MAP(id, var) case id: *(RECAST(id, arg)) = var; break
488
489    if (!arg)
490        return VPX_CODEC_INVALID_PARAM;
491
492    switch (ctrl_id)
493    {
494        MAP(VP8E_GET_LAST_QUANTIZER, vp8_get_quantizer(ctx->cpi));
495        MAP(VP8E_GET_LAST_QUANTIZER_64, vp8_reverse_trans(vp8_get_quantizer(ctx->cpi)));
496    }
497
498    return VPX_CODEC_OK;
499#undef MAP
500}
501
502
503static vpx_codec_err_t set_param(vpx_codec_alg_priv_t *ctx,
504                                 int                   ctrl_id,
505                                 va_list               args)
506{
507    vpx_codec_err_t     res  = VPX_CODEC_OK;
508    struct vp8_extracfg xcfg = ctx->vp8_cfg;
509
510#define MAP(id, var) case id: var = CAST(id, args); break;
511
512    switch (ctrl_id)
513    {
514        MAP(VP8E_SET_CPUUSED,               xcfg.cpu_used);
515        MAP(VP8E_SET_ENABLEAUTOALTREF,      xcfg.enable_auto_alt_ref);
516        MAP(VP8E_SET_NOISE_SENSITIVITY,     xcfg.noise_sensitivity);
517        MAP(VP8E_SET_SHARPNESS,             xcfg.Sharpness);
518        MAP(VP8E_SET_STATIC_THRESHOLD,      xcfg.static_thresh);
519        MAP(VP8E_SET_TOKEN_PARTITIONS,      xcfg.token_partitions);
520
521        MAP(VP8E_SET_ARNR_MAXFRAMES,        xcfg.arnr_max_frames);
522        MAP(VP8E_SET_ARNR_STRENGTH ,        xcfg.arnr_strength);
523        MAP(VP8E_SET_ARNR_TYPE     ,        xcfg.arnr_type);
524        MAP(VP8E_SET_TUNING,                xcfg.tuning);
525        MAP(VP8E_SET_CQ_LEVEL,              xcfg.cq_level);
526        MAP(VP8E_SET_MAX_INTRA_BITRATE_PCT, xcfg.rc_max_intra_bitrate_pct);
527
528    }
529
530    res = validate_config(ctx, &ctx->cfg, &xcfg, 0);
531
532    if (!res)
533    {
534        ctx->vp8_cfg = xcfg;
535        set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL);
536        vp8_change_config(ctx->cpi, &ctx->oxcf);
537    }
538
539    return res;
540#undef MAP
541}
542
543static vpx_codec_err_t vp8e_mr_alloc_mem(const vpx_codec_enc_cfg_t *cfg,
544                                        void **mem_loc)
545{
546    vpx_codec_err_t res = 0;
547    (void)cfg;
548    (void)mem_loc;
549#if CONFIG_MULTI_RES_ENCODING
550    LOWER_RES_FRAME_INFO *shared_mem_loc;
551    int mb_rows = ((cfg->g_w + 15) >>4);
552    int mb_cols = ((cfg->g_h + 15) >>4);
553
554    shared_mem_loc = calloc(1, sizeof(LOWER_RES_FRAME_INFO));
555    if(!shared_mem_loc)
556    {
557        res = VPX_CODEC_MEM_ERROR;
558    }
559
560    shared_mem_loc->mb_info = calloc(mb_rows*mb_cols, sizeof(LOWER_RES_MB_INFO));
561    if(!(shared_mem_loc->mb_info))
562    {
563        res = VPX_CODEC_MEM_ERROR;
564    }
565    else
566    {
567        *mem_loc = (void *)shared_mem_loc;
568        res = VPX_CODEC_OK;
569    }
570#endif
571    return res;
572}
573
574static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx,
575                                 vpx_codec_priv_enc_mr_cfg_t *mr_cfg)
576{
577    vpx_codec_err_t        res = VPX_CODEC_OK;
578    struct vpx_codec_alg_priv *priv;
579    vpx_codec_enc_cfg_t       *cfg;
580    unsigned int               i;
581
582    struct VP8_COMP *optr;
583
584    vp8_rtcd();
585
586    if (!ctx->priv)
587    {
588        priv = calloc(1, sizeof(struct vpx_codec_alg_priv));
589
590        if (!priv)
591        {
592            return VPX_CODEC_MEM_ERROR;
593        }
594
595        ctx->priv = &priv->base;
596        ctx->priv->sz = sizeof(*ctx->priv);
597        ctx->priv->iface = ctx->iface;
598        ctx->priv->alg_priv = priv;
599        ctx->priv->init_flags = ctx->init_flags;
600
601        if (ctx->config.enc)
602        {
603            /* Update the reference to the config structure to an
604             * internal copy.
605             */
606            ctx->priv->alg_priv->cfg = *ctx->config.enc;
607            ctx->config.enc = &ctx->priv->alg_priv->cfg;
608        }
609
610        cfg =  &ctx->priv->alg_priv->cfg;
611
612        /* Select the extra vp8 configuration table based on the current
613         * usage value. If the current usage value isn't found, use the
614         * values for usage case 0.
615         */
616        for (i = 0;
617             extracfg_map[i].usage && extracfg_map[i].usage != (int32_t)cfg->g_usage;
618             i++);
619
620        priv->vp8_cfg = extracfg_map[i].cfg;
621        priv->vp8_cfg.pkt_list = &priv->pkt_list.head;
622
623        priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 2;
624
625        if (priv->cx_data_sz < 32768) priv->cx_data_sz = 32768;
626
627        priv->cx_data = malloc(priv->cx_data_sz);
628
629        if (!priv->cx_data)
630        {
631            return VPX_CODEC_MEM_ERROR;
632        }
633
634        if(mr_cfg)
635            ctx->priv->enc.total_encoders   = mr_cfg->mr_total_resolutions;
636        else
637            ctx->priv->enc.total_encoders   = 1;
638
639        res = validate_config(priv, &priv->cfg, &priv->vp8_cfg, 0);
640
641        if (!res)
642        {
643            set_vp8e_config(&ctx->priv->alg_priv->oxcf,
644                             ctx->priv->alg_priv->cfg,
645                             ctx->priv->alg_priv->vp8_cfg,
646                             mr_cfg);
647
648            optr = vp8_create_compressor(&ctx->priv->alg_priv->oxcf);
649
650            if (!optr)
651                res = VPX_CODEC_MEM_ERROR;
652            else
653                ctx->priv->alg_priv->cpi = optr;
654        }
655    }
656
657    return res;
658}
659
660static vpx_codec_err_t vp8e_destroy(vpx_codec_alg_priv_t *ctx)
661{
662#if CONFIG_MULTI_RES_ENCODING
663    /* Free multi-encoder shared memory */
664    if (ctx->oxcf.mr_total_resolutions > 0 && (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions-1))
665    {
666        LOWER_RES_FRAME_INFO *shared_mem_loc = (LOWER_RES_FRAME_INFO *)ctx->oxcf.mr_low_res_mode_info;
667        free(shared_mem_loc->mb_info);
668        free(ctx->oxcf.mr_low_res_mode_info);
669    }
670#endif
671
672    free(ctx->cx_data);
673    vp8_remove_compressor(&ctx->cpi);
674    free(ctx);
675    return VPX_CODEC_OK;
676}
677
678static vpx_codec_err_t image2yuvconfig(const vpx_image_t   *img,
679                                       YV12_BUFFER_CONFIG  *yv12)
680{
681    vpx_codec_err_t        res = VPX_CODEC_OK;
682    yv12->y_buffer = img->planes[VPX_PLANE_Y];
683    yv12->u_buffer = img->planes[VPX_PLANE_U];
684    yv12->v_buffer = img->planes[VPX_PLANE_V];
685
686    yv12->y_crop_width  = img->d_w;
687    yv12->y_crop_height = img->d_h;
688    yv12->y_width  = img->d_w;
689    yv12->y_height = img->d_h;
690    yv12->uv_width = (1 + yv12->y_width) / 2;
691    yv12->uv_height = (1 + yv12->y_height) / 2;
692
693    yv12->y_stride = img->stride[VPX_PLANE_Y];
694    yv12->uv_stride = img->stride[VPX_PLANE_U];
695
696    yv12->border  = (img->stride[VPX_PLANE_Y] - img->w) / 2;
697    return res;
698}
699
700static void pick_quickcompress_mode(vpx_codec_alg_priv_t  *ctx,
701                                    unsigned long          duration,
702                                    unsigned long          deadline)
703{
704    unsigned int new_qc;
705
706#if !(CONFIG_REALTIME_ONLY)
707    /* Use best quality mode if no deadline is given. */
708    new_qc = MODE_BESTQUALITY;
709
710    if (deadline)
711    {
712        uint64_t     duration_us;
713
714        /* Convert duration parameter from stream timebase to microseconds */
715        duration_us = (uint64_t)duration * 1000000
716                      * (uint64_t)ctx->cfg.g_timebase.num
717                      / (uint64_t)ctx->cfg.g_timebase.den;
718
719        /* If the deadline is more that the duration this frame is to be shown,
720         * use good quality mode. Otherwise use realtime mode.
721         */
722        new_qc = (deadline > duration_us) ? MODE_GOODQUALITY : MODE_REALTIME;
723    }
724
725#else
726    new_qc = MODE_REALTIME;
727#endif
728
729    if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS)
730        new_qc = MODE_FIRSTPASS;
731    else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS)
732        new_qc = (new_qc == MODE_BESTQUALITY)
733                 ? MODE_SECONDPASS_BEST
734                 : MODE_SECONDPASS;
735
736    if (ctx->oxcf.Mode != (int32_t)new_qc)
737    {
738        ctx->oxcf.Mode = new_qc;
739        vp8_change_config(ctx->cpi, &ctx->oxcf);
740    }
741}
742
743
744static vpx_codec_err_t vp8e_encode(vpx_codec_alg_priv_t  *ctx,
745                                   const vpx_image_t     *img,
746                                   vpx_codec_pts_t        pts,
747                                   unsigned long          duration,
748                                   vpx_enc_frame_flags_t  flags,
749                                   unsigned long          deadline)
750{
751    vpx_codec_err_t res = VPX_CODEC_OK;
752
753    if (!ctx->cfg.rc_target_bitrate)
754        return res;
755
756    if (img)
757        res = validate_img(ctx, img);
758
759    if (!res)
760        res = validate_config(ctx, &ctx->cfg, &ctx->vp8_cfg, 1);
761
762    pick_quickcompress_mode(ctx, duration, deadline);
763    vpx_codec_pkt_list_init(&ctx->pkt_list);
764
765    /* Handle Flags */
766    if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF))
767        || ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF)))
768    {
769        ctx->base.err_detail = "Conflicting flags.";
770        return VPX_CODEC_INVALID_PARAM;
771    }
772
773    if (flags & (VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF
774                 | VP8_EFLAG_NO_REF_ARF))
775    {
776        int ref = 7;
777
778        if (flags & VP8_EFLAG_NO_REF_LAST)
779            ref ^= VP8_LAST_FRAME;
780
781        if (flags & VP8_EFLAG_NO_REF_GF)
782            ref ^= VP8_GOLD_FRAME;
783
784        if (flags & VP8_EFLAG_NO_REF_ARF)
785            ref ^= VP8_ALTR_FRAME;
786
787        vp8_use_as_reference(ctx->cpi, ref);
788    }
789
790    if (flags & (VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF
791                 | VP8_EFLAG_NO_UPD_ARF | VP8_EFLAG_FORCE_GF
792                 | VP8_EFLAG_FORCE_ARF))
793    {
794        int upd = 7;
795
796        if (flags & VP8_EFLAG_NO_UPD_LAST)
797            upd ^= VP8_LAST_FRAME;
798
799        if (flags & VP8_EFLAG_NO_UPD_GF)
800            upd ^= VP8_GOLD_FRAME;
801
802        if (flags & VP8_EFLAG_NO_UPD_ARF)
803            upd ^= VP8_ALTR_FRAME;
804
805        vp8_update_reference(ctx->cpi, upd);
806    }
807
808    if (flags & VP8_EFLAG_NO_UPD_ENTROPY)
809    {
810        vp8_update_entropy(ctx->cpi, 0);
811    }
812
813    /* Handle fixed keyframe intervals */
814    if (ctx->cfg.kf_mode == VPX_KF_AUTO
815        && ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist)
816    {
817        if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist)
818        {
819            flags |= VPX_EFLAG_FORCE_KF;
820            ctx->fixed_kf_cntr = 1;
821        }
822    }
823
824    /* Initialize the encoder instance on the first frame*/
825    if (!res && ctx->cpi)
826    {
827        unsigned int lib_flags;
828        YV12_BUFFER_CONFIG sd;
829        int64_t dst_time_stamp, dst_end_time_stamp;
830        unsigned long size, cx_data_sz;
831        unsigned char *cx_data;
832        unsigned char *cx_data_end;
833        int comp_data_state = 0;
834
835        /* Set up internal flags */
836        if (ctx->base.init_flags & VPX_CODEC_USE_PSNR)
837            ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1;
838
839        if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION)
840            ((VP8_COMP *)ctx->cpi)->output_partition = 1;
841
842        /* Convert API flags to internal codec lib flags */
843        lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
844
845        /* vp8 use 10,000,000 ticks/second as time stamp */
846        dst_time_stamp    = pts * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den;
847        dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den;
848
849        if (img != NULL)
850        {
851            res = image2yuvconfig(img, &sd);
852
853            if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags,
854                                      &sd, dst_time_stamp, dst_end_time_stamp))
855            {
856                VP8_COMP *cpi = (VP8_COMP *)ctx->cpi;
857                res = update_error_state(ctx, &cpi->common.error);
858            }
859
860            /* reset for next frame */
861            ctx->next_frame_flag = 0;
862        }
863
864        cx_data = ctx->cx_data;
865        cx_data_sz = ctx->cx_data_sz;
866        cx_data_end = ctx->cx_data + cx_data_sz;
867        lib_flags = 0;
868
869        while (cx_data_sz >= ctx->cx_data_sz / 2)
870        {
871            comp_data_state = vp8_get_compressed_data(ctx->cpi,
872                                                  &lib_flags,
873                                                  &size,
874                                                  cx_data,
875                                                  cx_data_end,
876                                                  &dst_time_stamp,
877                                                  &dst_end_time_stamp,
878                                                  !img);
879
880            if(comp_data_state == VPX_CODEC_CORRUPT_FRAME)
881                return VPX_CODEC_CORRUPT_FRAME;
882            else if(comp_data_state == -1)
883                break;
884
885            if (size)
886            {
887                vpx_codec_pts_t    round, delta;
888                vpx_codec_cx_pkt_t pkt;
889                VP8_COMP *cpi = (VP8_COMP *)ctx->cpi;
890
891                /* Add the frame packet to the list of returned packets. */
892                round = (vpx_codec_pts_t)1000000
893                        * ctx->cfg.g_timebase.num / 2 - 1;
894                delta = (dst_end_time_stamp - dst_time_stamp);
895                pkt.kind = VPX_CODEC_CX_FRAME_PKT;
896                pkt.data.frame.pts =
897                    (dst_time_stamp * ctx->cfg.g_timebase.den + round)
898                    / ctx->cfg.g_timebase.num / 10000000;
899                pkt.data.frame.duration = (unsigned long)
900                    ((delta * ctx->cfg.g_timebase.den + round)
901                    / ctx->cfg.g_timebase.num / 10000000);
902                pkt.data.frame.flags = lib_flags << 16;
903
904                if (lib_flags & FRAMEFLAGS_KEY)
905                    pkt.data.frame.flags |= VPX_FRAME_IS_KEY;
906
907                if (!cpi->common.show_frame)
908                {
909                    pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE;
910
911                    /* This timestamp should be as close as possible to the
912                     * prior PTS so that if a decoder uses pts to schedule when
913                     * to do this, we start right after last frame was decoded.
914                     * Invisible frames have no duration.
915                     */
916                    pkt.data.frame.pts = ((cpi->last_time_stamp_seen
917                        * ctx->cfg.g_timebase.den + round)
918                        / ctx->cfg.g_timebase.num / 10000000) + 1;
919                    pkt.data.frame.duration = 0;
920                }
921
922                if (cpi->droppable)
923                    pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE;
924
925                if (cpi->output_partition)
926                {
927                    int i;
928                    const int num_partitions =
929                            (1 << cpi->common.multi_token_partition) + 1;
930
931                    pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT;
932
933                    for (i = 0; i < num_partitions; ++i)
934                    {
935#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
936                        pkt.data.frame.buf = cpi->partition_d[i];
937#else
938                        pkt.data.frame.buf = cx_data;
939                        cx_data += cpi->partition_sz[i];
940                        cx_data_sz -= cpi->partition_sz[i];
941#endif
942                        pkt.data.frame.sz = cpi->partition_sz[i];
943                        pkt.data.frame.partition_id = i;
944                        /* don't set the fragment bit for the last partition */
945                        if (i == (num_partitions - 1))
946                            pkt.data.frame.flags &= ~VPX_FRAME_IS_FRAGMENT;
947                        vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
948                    }
949#if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
950                    /* In lagged mode the encoder can buffer multiple frames.
951                     * We don't want this in partitioned output because
952                     * partitions are spread all over the output buffer.
953                     * So, force an exit!
954                     */
955                    cx_data_sz -= ctx->cx_data_sz / 2;
956#endif
957                }
958                else
959                {
960                    pkt.data.frame.buf = cx_data;
961                    pkt.data.frame.sz  = size;
962                    pkt.data.frame.partition_id = -1;
963                    vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
964                    cx_data += size;
965                    cx_data_sz -= size;
966                }
967            }
968        }
969    }
970
971    return res;
972}
973
974
975static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t  *ctx,
976        vpx_codec_iter_t      *iter)
977{
978    return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
979}
980
981static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx,
982        int ctr_id,
983        va_list args)
984{
985    vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
986    (void)ctr_id;
987    if (data)
988    {
989        vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
990        YV12_BUFFER_CONFIG sd;
991
992        image2yuvconfig(&frame->img, &sd);
993        vp8_set_reference(ctx->cpi, frame->frame_type, &sd);
994        return VPX_CODEC_OK;
995    }
996    else
997        return VPX_CODEC_INVALID_PARAM;
998
999}
1000
1001static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx,
1002        int ctr_id,
1003        va_list args)
1004{
1005
1006    vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
1007    (void)ctr_id;
1008    if (data)
1009    {
1010        vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
1011        YV12_BUFFER_CONFIG sd;
1012
1013        image2yuvconfig(&frame->img, &sd);
1014        vp8_get_reference(ctx->cpi, frame->frame_type, &sd);
1015        return VPX_CODEC_OK;
1016    }
1017    else
1018        return VPX_CODEC_INVALID_PARAM;
1019}
1020
1021static vpx_codec_err_t vp8e_set_previewpp(vpx_codec_alg_priv_t *ctx,
1022        int ctr_id,
1023        va_list args)
1024{
1025#if CONFIG_POSTPROC
1026    vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
1027    (void)ctr_id;
1028
1029    if (data)
1030    {
1031        ctx->preview_ppcfg = *((vp8_postproc_cfg_t *)data);
1032        return VPX_CODEC_OK;
1033    }
1034    else
1035        return VPX_CODEC_INVALID_PARAM;
1036#else
1037    (void)ctx;
1038    (void)ctr_id;
1039    (void)args;
1040    return VPX_CODEC_INCAPABLE;
1041#endif
1042}
1043
1044
1045static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx)
1046{
1047
1048    YV12_BUFFER_CONFIG sd;
1049    vp8_ppflags_t flags = {0};
1050
1051    if (ctx->preview_ppcfg.post_proc_flag)
1052    {
1053        flags.post_proc_flag        = ctx->preview_ppcfg.post_proc_flag;
1054        flags.deblocking_level      = ctx->preview_ppcfg.deblocking_level;
1055        flags.noise_level           = ctx->preview_ppcfg.noise_level;
1056    }
1057
1058    if (0 == vp8_get_preview_raw_frame(ctx->cpi, &sd, &flags))
1059    {
1060
1061        /*
1062        vpx_img_wrap(&ctx->preview_img, VPX_IMG_FMT_YV12,
1063            sd.y_width + 2*VP8BORDERINPIXELS,
1064            sd.y_height + 2*VP8BORDERINPIXELS,
1065            1,
1066            sd.buffer_alloc);
1067        vpx_img_set_rect(&ctx->preview_img,
1068            VP8BORDERINPIXELS, VP8BORDERINPIXELS,
1069            sd.y_width, sd.y_height);
1070            */
1071
1072        ctx->preview_img.bps = 12;
1073        ctx->preview_img.planes[VPX_PLANE_Y] = sd.y_buffer;
1074        ctx->preview_img.planes[VPX_PLANE_U] = sd.u_buffer;
1075        ctx->preview_img.planes[VPX_PLANE_V] = sd.v_buffer;
1076
1077        ctx->preview_img.fmt = VPX_IMG_FMT_I420;
1078        ctx->preview_img.x_chroma_shift = 1;
1079        ctx->preview_img.y_chroma_shift = 1;
1080
1081        ctx->preview_img.d_w = sd.y_width;
1082        ctx->preview_img.d_h = sd.y_height;
1083        ctx->preview_img.stride[VPX_PLANE_Y] = sd.y_stride;
1084        ctx->preview_img.stride[VPX_PLANE_U] = sd.uv_stride;
1085        ctx->preview_img.stride[VPX_PLANE_V] = sd.uv_stride;
1086        ctx->preview_img.w   = sd.y_width;
1087        ctx->preview_img.h   = sd.y_height;
1088
1089        return &ctx->preview_img;
1090    }
1091    else
1092        return NULL;
1093}
1094
1095static vpx_codec_err_t vp8e_update_entropy(vpx_codec_alg_priv_t *ctx,
1096        int ctr_id,
1097        va_list args)
1098{
1099    int update = va_arg(args, int);
1100    (void)ctr_id;
1101    vp8_update_entropy(ctx->cpi, update);
1102    return VPX_CODEC_OK;
1103
1104}
1105
1106static vpx_codec_err_t vp8e_update_reference(vpx_codec_alg_priv_t *ctx,
1107        int ctr_id,
1108        va_list args)
1109{
1110    int update = va_arg(args, int);
1111    (void)ctr_id;
1112    vp8_update_reference(ctx->cpi, update);
1113    return VPX_CODEC_OK;
1114}
1115
1116static vpx_codec_err_t vp8e_use_reference(vpx_codec_alg_priv_t *ctx,
1117        int ctr_id,
1118        va_list args)
1119{
1120    int reference_flag = va_arg(args, int);
1121    (void)ctr_id;
1122    vp8_use_as_reference(ctx->cpi, reference_flag);
1123    return VPX_CODEC_OK;
1124}
1125
1126static vpx_codec_err_t vp8e_set_roi_map(vpx_codec_alg_priv_t *ctx,
1127                                        int ctr_id,
1128                                        va_list args)
1129{
1130    vpx_roi_map_t *data = va_arg(args, vpx_roi_map_t *);
1131    (void)ctr_id;
1132    if (data)
1133    {
1134        vpx_roi_map_t *roi = (vpx_roi_map_t *)data;
1135
1136        if (!vp8_set_roimap(ctx->cpi, roi->roi_map, roi->rows, roi->cols, roi->delta_q, roi->delta_lf, roi->static_threshold))
1137            return VPX_CODEC_OK;
1138        else
1139            return VPX_CODEC_INVALID_PARAM;
1140    }
1141    else
1142        return VPX_CODEC_INVALID_PARAM;
1143}
1144
1145
1146static vpx_codec_err_t vp8e_set_activemap(vpx_codec_alg_priv_t *ctx,
1147        int ctr_id,
1148        va_list args)
1149{
1150    vpx_active_map_t *data = va_arg(args, vpx_active_map_t *);
1151    (void)ctr_id;
1152    if (data)
1153    {
1154
1155        vpx_active_map_t *map = (vpx_active_map_t *)data;
1156
1157        if (!vp8_set_active_map(ctx->cpi, map->active_map, map->rows, map->cols))
1158            return VPX_CODEC_OK;
1159        else
1160            return VPX_CODEC_INVALID_PARAM;
1161    }
1162    else
1163        return VPX_CODEC_INVALID_PARAM;
1164}
1165
1166static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx,
1167        int ctr_id,
1168        va_list args)
1169{
1170
1171    vpx_scaling_mode_t *data =  va_arg(args, vpx_scaling_mode_t *);
1172    (void)ctr_id;
1173    if (data)
1174    {
1175        int res;
1176        vpx_scaling_mode_t scalemode = *(vpx_scaling_mode_t *)data ;
1177        res = vp8_set_internal_size(ctx->cpi,
1178                                    (VPX_SCALING)scalemode.h_scaling_mode,
1179                                    (VPX_SCALING)scalemode.v_scaling_mode);
1180
1181        if (!res)
1182        {
1183            /*force next frame a key frame to effect scaling mode */
1184            ctx->next_frame_flag |= FRAMEFLAGS_KEY;
1185            return VPX_CODEC_OK;
1186        }
1187        else
1188            return VPX_CODEC_INVALID_PARAM;
1189    }
1190    else
1191        return VPX_CODEC_INVALID_PARAM;
1192}
1193
1194
1195static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] =
1196{
1197    {VP8_SET_REFERENCE,                 vp8e_set_reference},
1198    {VP8_COPY_REFERENCE,                vp8e_get_reference},
1199    {VP8_SET_POSTPROC,                  vp8e_set_previewpp},
1200    {VP8E_UPD_ENTROPY,                  vp8e_update_entropy},
1201    {VP8E_UPD_REFERENCE,                vp8e_update_reference},
1202    {VP8E_USE_REFERENCE,                vp8e_use_reference},
1203    {VP8E_SET_ROI_MAP,                  vp8e_set_roi_map},
1204    {VP8E_SET_ACTIVEMAP,                vp8e_set_activemap},
1205    {VP8E_SET_SCALEMODE,                vp8e_set_scalemode},
1206    {VP8E_SET_CPUUSED,                  set_param},
1207    {VP8E_SET_NOISE_SENSITIVITY,        set_param},
1208    {VP8E_SET_ENABLEAUTOALTREF,         set_param},
1209    {VP8E_SET_SHARPNESS,                set_param},
1210    {VP8E_SET_STATIC_THRESHOLD,         set_param},
1211    {VP8E_SET_TOKEN_PARTITIONS,         set_param},
1212    {VP8E_GET_LAST_QUANTIZER,           get_param},
1213    {VP8E_GET_LAST_QUANTIZER_64,        get_param},
1214    {VP8E_SET_ARNR_MAXFRAMES,           set_param},
1215    {VP8E_SET_ARNR_STRENGTH ,           set_param},
1216    {VP8E_SET_ARNR_TYPE     ,           set_param},
1217    {VP8E_SET_TUNING,                   set_param},
1218    {VP8E_SET_CQ_LEVEL,                 set_param},
1219    {VP8E_SET_MAX_INTRA_BITRATE_PCT,    set_param},
1220    { -1, NULL},
1221};
1222
1223static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] =
1224{
1225    {
1226    0,
1227    {
1228        0,                  /* g_usage */
1229        0,                  /* g_threads */
1230        0,                  /* g_profile */
1231
1232        320,                /* g_width */
1233        240,                /* g_height */
1234        {1, 30},            /* g_timebase */
1235
1236        0,                  /* g_error_resilient */
1237
1238        VPX_RC_ONE_PASS,    /* g_pass */
1239
1240        0,                  /* g_lag_in_frames */
1241
1242        0,                  /* rc_dropframe_thresh */
1243        0,                  /* rc_resize_allowed */
1244        60,                 /* rc_resize_down_thresold */
1245        30,                 /* rc_resize_up_thresold */
1246
1247        VPX_VBR,            /* rc_end_usage */
1248#if VPX_ENCODER_ABI_VERSION > (1 + VPX_CODEC_ABI_VERSION)
1249        {0},                /* rc_twopass_stats_in */
1250#endif
1251        256,                /* rc_target_bandwidth */
1252        4,                  /* rc_min_quantizer */
1253        63,                 /* rc_max_quantizer */
1254        100,                /* rc_undershoot_pct */
1255        100,                /* rc_overshoot_pct */
1256
1257        6000,               /* rc_max_buffer_size */
1258        4000,               /* rc_buffer_initial_size; */
1259        5000,               /* rc_buffer_optimal_size; */
1260
1261        50,                 /* rc_two_pass_vbrbias  */
1262        0,                  /* rc_two_pass_vbrmin_section */
1263        400,                /* rc_two_pass_vbrmax_section */
1264
1265        /* keyframing settings (kf) */
1266        VPX_KF_AUTO,        /* g_kfmode*/
1267        0,                  /* kf_min_dist */
1268        128,                /* kf_max_dist */
1269
1270#if VPX_ENCODER_ABI_VERSION == (1 + VPX_CODEC_ABI_VERSION)
1271        "vp8.fpf"           /* first pass filename */
1272#endif
1273        VPX_SS_DEFAULT_LAYERS, /* ss_number_layers */
1274        {0},                /* ss_target_bitrate */
1275        1,                  /* ts_number_layers */
1276        {0},                /* ts_target_bitrate */
1277        {0},                /* ts_rate_decimator */
1278        0,                  /* ts_periodicity */
1279        {0},                /* ts_layer_id */
1280    }},
1281    { -1, {NOT_IMPLEMENTED}}
1282};
1283
1284
1285#ifndef VERSION_STRING
1286#define VERSION_STRING
1287#endif
1288CODEC_INTERFACE(vpx_codec_vp8_cx) =
1289{
1290    "WebM Project VP8 Encoder" VERSION_STRING,
1291    VPX_CODEC_INTERNAL_ABI_VERSION,
1292    VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR |
1293    VPX_CODEC_CAP_OUTPUT_PARTITION,
1294    /* vpx_codec_caps_t          caps; */
1295    vp8e_init,          /* vpx_codec_init_fn_t       init; */
1296    vp8e_destroy,       /* vpx_codec_destroy_fn_t    destroy; */
1297    vp8e_ctf_maps,      /* vpx_codec_ctrl_fn_map_t  *ctrl_maps; */
1298    NOT_IMPLEMENTED,    /* vpx_codec_get_mmap_fn_t   get_mmap; */
1299    NOT_IMPLEMENTED,    /* vpx_codec_set_mmap_fn_t   set_mmap; */
1300    {
1301        NOT_IMPLEMENTED,    /* vpx_codec_peek_si_fn_t    peek_si; */
1302        NOT_IMPLEMENTED,    /* vpx_codec_get_si_fn_t     get_si; */
1303        NOT_IMPLEMENTED,    /* vpx_codec_decode_fn_t     decode; */
1304        NOT_IMPLEMENTED,    /* vpx_codec_frame_get_fn_t  frame_get; */
1305        NOT_IMPLEMENTED,    /*vpx_codec_frame_set_fn_t set_fb_fn*/
1306    },
1307    {
1308        vp8e_usage_cfg_map, /* vpx_codec_enc_cfg_map_t    peek_si; */
1309        vp8e_encode,        /* vpx_codec_encode_fn_t      encode; */
1310        vp8e_get_cxdata,    /* vpx_codec_get_cx_data_fn_t   frame_get; */
1311        vp8e_set_config,
1312        NOT_IMPLEMENTED,
1313        vp8e_get_preview,
1314        vp8e_mr_alloc_mem,
1315    } /* encoder functions */
1316};
1317