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