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