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