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