Line data Source code
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 0 : 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 0 : if ((res = error->error_code)) {
95 0 : ctx->base.err_detail = error->has_detail ? error->detail : NULL;
96 : }
97 :
98 0 : 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 0 : 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 0 : RANGE_CHECK(cfg, g_w, 1, 16383); /* 14 bits available */
134 0 : RANGE_CHECK(cfg, g_h, 1, 16383); /* 14 bits available */
135 0 : RANGE_CHECK(cfg, g_timebase.den, 1, 1000000000);
136 0 : RANGE_CHECK(cfg, g_timebase.num, 1, 1000000000);
137 0 : RANGE_CHECK_HI(cfg, g_profile, 3);
138 0 : RANGE_CHECK_HI(cfg, rc_max_quantizer, 63);
139 0 : RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer);
140 0 : 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 0 : 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 0 : RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_Q);
149 0 : RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000);
150 0 : RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000);
151 0 : RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
152 0 : 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 0 : if (ctx->base.enc.total_encoders > 1)
158 0 : RANGE_CHECK_HI(cfg, rc_resize_allowed, 0);
159 : #else
160 : RANGE_CHECK_BOOL(cfg, rc_resize_allowed);
161 : #endif
162 0 : RANGE_CHECK_HI(cfg, rc_dropframe_thresh, 100);
163 0 : RANGE_CHECK_HI(cfg, rc_resize_up_thresh, 100);
164 0 : 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 0 : if (ctx->base.enc.total_encoders > 1)
170 0 : 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 0 : if (cfg->kf_mode != VPX_KF_DISABLED && cfg->kf_min_dist != cfg->kf_max_dist &&
179 0 : cfg->kf_min_dist > 0)
180 0 : ERROR(
181 : "kf_min_dist not supported in auto mode, use 0 "
182 : "or kf_max_dist instead.");
183 :
184 0 : RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref);
185 0 : 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 0 : RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6);
191 : #endif
192 :
193 0 : RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION,
194 : VP8_EIGHT_TOKENPARTITION);
195 0 : RANGE_CHECK_HI(vp8_cfg, Sharpness, 7);
196 0 : RANGE_CHECK(vp8_cfg, arnr_max_frames, 0, 15);
197 0 : RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6);
198 0 : RANGE_CHECK(vp8_cfg, arnr_type, 1, 3);
199 0 : RANGE_CHECK(vp8_cfg, cq_level, 0, 63);
200 0 : RANGE_CHECK_HI(vp8_cfg, screen_content_mode, 2);
201 0 : if (finalize && (cfg->rc_end_usage == VPX_CQ || cfg->rc_end_usage == VPX_Q))
202 0 : RANGE_CHECK(vp8_cfg, cq_level, cfg->rc_min_quantizer,
203 : cfg->rc_max_quantizer);
204 :
205 : #if !(CONFIG_REALTIME_ONLY)
206 0 : if (cfg->g_pass == VPX_RC_LAST_PASS) {
207 0 : size_t packet_sz = sizeof(FIRSTPASS_STATS);
208 0 : int n_packets = (int)(cfg->rc_twopass_stats_in.sz / packet_sz);
209 : FIRSTPASS_STATS *stats;
210 :
211 0 : if (!cfg->rc_twopass_stats_in.buf)
212 0 : ERROR("rc_twopass_stats_in.buf not set.");
213 :
214 0 : if (cfg->rc_twopass_stats_in.sz % packet_sz)
215 0 : ERROR("rc_twopass_stats_in.sz indicates truncated packet.");
216 :
217 0 : if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz)
218 0 : ERROR("rc_twopass_stats_in requires at least two packets.");
219 :
220 0 : stats = (void *)((char *)cfg->rc_twopass_stats_in.buf +
221 0 : (n_packets - 1) * packet_sz);
222 :
223 0 : if ((int)(stats->count + 0.5) != n_packets - 1)
224 0 : ERROR("rc_twopass_stats_in missing EOS stats packet");
225 : }
226 : #endif
227 :
228 0 : RANGE_CHECK(cfg, ts_number_layers, 1, 5);
229 :
230 0 : if (cfg->ts_number_layers > 1) {
231 : unsigned int i;
232 0 : RANGE_CHECK_HI(cfg, ts_periodicity, 16);
233 :
234 0 : for (i = 1; i < cfg->ts_number_layers; ++i) {
235 0 : if (cfg->ts_target_bitrate[i] <= cfg->ts_target_bitrate[i - 1] &&
236 0 : cfg->rc_target_bitrate > 0)
237 0 : ERROR("ts_target_bitrate entries are not strictly increasing");
238 : }
239 :
240 0 : RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
241 0 : for (i = cfg->ts_number_layers - 2; i > 0; i--) {
242 0 : if (cfg->ts_rate_decimator[i - 1] != 2 * cfg->ts_rate_decimator[i])
243 0 : ERROR("ts_rate_decimator factors are not powers of 2");
244 : }
245 :
246 0 : 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 0 : return VPX_CODEC_OK;
255 : }
256 :
257 0 : static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx,
258 : const vpx_image_t *img) {
259 0 : switch (img->fmt) {
260 : case VPX_IMG_FMT_YV12:
261 : case VPX_IMG_FMT_I420:
262 : case VPX_IMG_FMT_VPXI420:
263 0 : case VPX_IMG_FMT_VPXYV12: break;
264 : default:
265 0 : ERROR("Invalid image format. Only YV12 and I420 images are supported");
266 : }
267 :
268 0 : if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h))
269 0 : ERROR("Image size must match encoder init configuration size");
270 :
271 0 : return VPX_CODEC_OK;
272 : }
273 :
274 0 : 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 0 : oxcf->multi_threaded = cfg.g_threads;
279 0 : oxcf->Version = cfg.g_profile;
280 :
281 0 : oxcf->Width = cfg.g_w;
282 0 : oxcf->Height = cfg.g_h;
283 0 : oxcf->timebase = cfg.g_timebase;
284 :
285 0 : oxcf->error_resilient_mode = cfg.g_error_resilient;
286 :
287 0 : switch (cfg.g_pass) {
288 0 : case VPX_RC_ONE_PASS: oxcf->Mode = MODE_BESTQUALITY; break;
289 0 : case VPX_RC_FIRST_PASS: oxcf->Mode = MODE_FIRSTPASS; break;
290 0 : case VPX_RC_LAST_PASS: oxcf->Mode = MODE_SECONDPASS_BEST; break;
291 : }
292 :
293 0 : if (cfg.g_pass == VPX_RC_FIRST_PASS || cfg.g_pass == VPX_RC_ONE_PASS) {
294 0 : oxcf->allow_lag = 0;
295 0 : oxcf->lag_in_frames = 0;
296 : } else {
297 0 : oxcf->allow_lag = (cfg.g_lag_in_frames) > 0;
298 0 : oxcf->lag_in_frames = cfg.g_lag_in_frames;
299 : }
300 :
301 0 : oxcf->allow_df = (cfg.rc_dropframe_thresh > 0);
302 0 : oxcf->drop_frames_water_mark = cfg.rc_dropframe_thresh;
303 :
304 0 : oxcf->allow_spatial_resampling = cfg.rc_resize_allowed;
305 0 : oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh;
306 0 : oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh;
307 :
308 0 : if (cfg.rc_end_usage == VPX_VBR) {
309 0 : oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
310 0 : } else if (cfg.rc_end_usage == VPX_CBR) {
311 0 : oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
312 0 : } else if (cfg.rc_end_usage == VPX_CQ) {
313 0 : oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
314 0 : } else if (cfg.rc_end_usage == VPX_Q) {
315 0 : oxcf->end_usage = USAGE_CONSTANT_QUALITY;
316 : }
317 :
318 0 : oxcf->target_bandwidth = cfg.rc_target_bitrate;
319 0 : oxcf->rc_max_intra_bitrate_pct = vp8_cfg.rc_max_intra_bitrate_pct;
320 0 : oxcf->gf_cbr_boost_pct = vp8_cfg.gf_cbr_boost_pct;
321 :
322 0 : oxcf->best_allowed_q = cfg.rc_min_quantizer;
323 0 : oxcf->worst_allowed_q = cfg.rc_max_quantizer;
324 0 : oxcf->cq_level = vp8_cfg.cq_level;
325 0 : oxcf->fixed_q = -1;
326 :
327 0 : oxcf->under_shoot_pct = cfg.rc_undershoot_pct;
328 0 : oxcf->over_shoot_pct = cfg.rc_overshoot_pct;
329 :
330 0 : oxcf->maximum_buffer_size_in_ms = cfg.rc_buf_sz;
331 0 : oxcf->starting_buffer_level_in_ms = cfg.rc_buf_initial_sz;
332 0 : oxcf->optimal_buffer_level_in_ms = cfg.rc_buf_optimal_sz;
333 :
334 0 : oxcf->maximum_buffer_size = cfg.rc_buf_sz;
335 0 : oxcf->starting_buffer_level = cfg.rc_buf_initial_sz;
336 0 : oxcf->optimal_buffer_level = cfg.rc_buf_optimal_sz;
337 :
338 0 : oxcf->two_pass_vbrbias = cfg.rc_2pass_vbr_bias_pct;
339 0 : oxcf->two_pass_vbrmin_section = cfg.rc_2pass_vbr_minsection_pct;
340 0 : oxcf->two_pass_vbrmax_section = cfg.rc_2pass_vbr_maxsection_pct;
341 :
342 0 : oxcf->auto_key =
343 0 : cfg.kf_mode == VPX_KF_AUTO && cfg.kf_min_dist != cfg.kf_max_dist;
344 0 : oxcf->key_freq = cfg.kf_max_dist;
345 :
346 0 : oxcf->number_of_layers = cfg.ts_number_layers;
347 0 : oxcf->periodicity = cfg.ts_periodicity;
348 :
349 0 : if (oxcf->number_of_layers > 1) {
350 0 : memcpy(oxcf->target_bitrate, cfg.ts_target_bitrate,
351 : sizeof(cfg.ts_target_bitrate));
352 0 : memcpy(oxcf->rate_decimator, cfg.ts_rate_decimator,
353 : sizeof(cfg.ts_rate_decimator));
354 0 : 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 0 : if (mr_cfg) {
363 0 : oxcf->mr_total_resolutions = mr_cfg->mr_total_resolutions;
364 0 : oxcf->mr_encoder_id = mr_cfg->mr_encoder_id;
365 0 : oxcf->mr_down_sampling_factor.num = mr_cfg->mr_down_sampling_factor.num;
366 0 : oxcf->mr_down_sampling_factor.den = mr_cfg->mr_down_sampling_factor.den;
367 0 : oxcf->mr_low_res_mode_info = mr_cfg->mr_low_res_mode_info;
368 : }
369 : #else
370 : (void)mr_cfg;
371 : #endif
372 :
373 0 : oxcf->cpu_used = vp8_cfg.cpu_used;
374 0 : oxcf->encode_breakout = vp8_cfg.static_thresh;
375 0 : oxcf->play_alternate = vp8_cfg.enable_auto_alt_ref;
376 0 : oxcf->noise_sensitivity = vp8_cfg.noise_sensitivity;
377 0 : oxcf->Sharpness = vp8_cfg.Sharpness;
378 0 : oxcf->token_partitions = vp8_cfg.token_partitions;
379 :
380 0 : oxcf->two_pass_stats_in = cfg.rc_twopass_stats_in;
381 0 : oxcf->output_pkt_list = vp8_cfg.pkt_list;
382 :
383 0 : oxcf->arnr_max_frames = vp8_cfg.arnr_max_frames;
384 0 : oxcf->arnr_strength = vp8_cfg.arnr_strength;
385 0 : oxcf->arnr_type = vp8_cfg.arnr_type;
386 :
387 0 : oxcf->tuning = vp8_cfg.tuning;
388 :
389 0 : 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 0 : return VPX_CODEC_OK;
425 : }
426 :
427 0 : 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 0 : if (cfg->g_w != ctx->cfg.g_w || cfg->g_h != ctx->cfg.g_h) {
432 0 : if (cfg->g_lag_in_frames > 1 || cfg->g_pass != VPX_RC_ONE_PASS)
433 0 : ERROR("Cannot change width or height after initialization");
434 0 : if ((ctx->cpi->initial_width && (int)cfg->g_w > ctx->cpi->initial_width) ||
435 0 : (ctx->cpi->initial_height && (int)cfg->g_h > ctx->cpi->initial_height))
436 0 : 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 0 : if ((cfg->g_lag_in_frames > ctx->cfg.g_lag_in_frames))
445 0 : ERROR("Cannot increase lag_in_frames");
446 :
447 0 : res = validate_config(ctx, cfg, &ctx->vp8_cfg, 0);
448 :
449 0 : if (!res) {
450 0 : ctx->cfg = *cfg;
451 0 : set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL);
452 0 : vp8_change_config(ctx->cpi, &ctx->oxcf);
453 : }
454 :
455 0 : return res;
456 : }
457 :
458 0 : static vpx_codec_err_t get_quantizer(vpx_codec_alg_priv_t *ctx, va_list args) {
459 0 : int *const arg = va_arg(args, int *);
460 0 : if (arg == NULL) return VPX_CODEC_INVALID_PARAM;
461 0 : *arg = vp8_get_quantizer(ctx->cpi);
462 0 : return VPX_CODEC_OK;
463 : }
464 :
465 0 : static vpx_codec_err_t get_quantizer64(vpx_codec_alg_priv_t *ctx,
466 : va_list args) {
467 0 : int *const arg = va_arg(args, int *);
468 0 : if (arg == NULL) return VPX_CODEC_INVALID_PARAM;
469 0 : *arg = vp8_reverse_trans(vp8_get_quantizer(ctx->cpi));
470 0 : return VPX_CODEC_OK;
471 : }
472 :
473 0 : static vpx_codec_err_t update_extracfg(vpx_codec_alg_priv_t *ctx,
474 : const struct vp8_extracfg *extra_cfg) {
475 0 : const vpx_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg, 0);
476 0 : if (res == VPX_CODEC_OK) {
477 0 : ctx->vp8_cfg = *extra_cfg;
478 0 : set_vp8e_config(&ctx->oxcf, ctx->cfg, ctx->vp8_cfg, NULL);
479 0 : vp8_change_config(ctx->cpi, &ctx->oxcf);
480 : }
481 0 : return res;
482 : }
483 :
484 0 : static vpx_codec_err_t set_cpu_used(vpx_codec_alg_priv_t *ctx, va_list args) {
485 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
486 0 : extra_cfg.cpu_used = CAST(VP8E_SET_CPUUSED, args);
487 0 : return update_extracfg(ctx, &extra_cfg);
488 : }
489 :
490 0 : static vpx_codec_err_t set_enable_auto_alt_ref(vpx_codec_alg_priv_t *ctx,
491 : va_list args) {
492 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
493 0 : extra_cfg.enable_auto_alt_ref = CAST(VP8E_SET_ENABLEAUTOALTREF, args);
494 0 : return update_extracfg(ctx, &extra_cfg);
495 : }
496 :
497 0 : static vpx_codec_err_t set_noise_sensitivity(vpx_codec_alg_priv_t *ctx,
498 : va_list args) {
499 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
500 0 : extra_cfg.noise_sensitivity = CAST(VP8E_SET_NOISE_SENSITIVITY, args);
501 0 : return update_extracfg(ctx, &extra_cfg);
502 : }
503 :
504 0 : static vpx_codec_err_t set_sharpness(vpx_codec_alg_priv_t *ctx, va_list args) {
505 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
506 0 : extra_cfg.Sharpness = CAST(VP8E_SET_SHARPNESS, args);
507 0 : return update_extracfg(ctx, &extra_cfg);
508 : }
509 :
510 0 : static vpx_codec_err_t set_static_thresh(vpx_codec_alg_priv_t *ctx,
511 : va_list args) {
512 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
513 0 : extra_cfg.static_thresh = CAST(VP8E_SET_STATIC_THRESHOLD, args);
514 0 : return update_extracfg(ctx, &extra_cfg);
515 : }
516 :
517 0 : static vpx_codec_err_t set_token_partitions(vpx_codec_alg_priv_t *ctx,
518 : va_list args) {
519 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
520 0 : extra_cfg.token_partitions = CAST(VP8E_SET_TOKEN_PARTITIONS, args);
521 0 : return update_extracfg(ctx, &extra_cfg);
522 : }
523 :
524 0 : static vpx_codec_err_t set_arnr_max_frames(vpx_codec_alg_priv_t *ctx,
525 : va_list args) {
526 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
527 0 : extra_cfg.arnr_max_frames = CAST(VP8E_SET_ARNR_MAXFRAMES, args);
528 0 : return update_extracfg(ctx, &extra_cfg);
529 : }
530 :
531 0 : static vpx_codec_err_t set_arnr_strength(vpx_codec_alg_priv_t *ctx,
532 : va_list args) {
533 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
534 0 : extra_cfg.arnr_strength = CAST(VP8E_SET_ARNR_STRENGTH, args);
535 0 : return update_extracfg(ctx, &extra_cfg);
536 : }
537 :
538 0 : static vpx_codec_err_t set_arnr_type(vpx_codec_alg_priv_t *ctx, va_list args) {
539 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
540 0 : extra_cfg.arnr_type = CAST(VP8E_SET_ARNR_TYPE, args);
541 0 : return update_extracfg(ctx, &extra_cfg);
542 : }
543 :
544 0 : static vpx_codec_err_t set_tuning(vpx_codec_alg_priv_t *ctx, va_list args) {
545 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
546 0 : extra_cfg.tuning = CAST(VP8E_SET_TUNING, args);
547 0 : return update_extracfg(ctx, &extra_cfg);
548 : }
549 :
550 0 : static vpx_codec_err_t set_cq_level(vpx_codec_alg_priv_t *ctx, va_list args) {
551 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
552 0 : extra_cfg.cq_level = CAST(VP8E_SET_CQ_LEVEL, args);
553 0 : return update_extracfg(ctx, &extra_cfg);
554 : }
555 :
556 0 : static vpx_codec_err_t set_rc_max_intra_bitrate_pct(vpx_codec_alg_priv_t *ctx,
557 : va_list args) {
558 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
559 0 : extra_cfg.rc_max_intra_bitrate_pct =
560 0 : CAST(VP8E_SET_MAX_INTRA_BITRATE_PCT, args);
561 0 : return update_extracfg(ctx, &extra_cfg);
562 : }
563 :
564 0 : static vpx_codec_err_t ctrl_set_rc_gf_cbr_boost_pct(vpx_codec_alg_priv_t *ctx,
565 : va_list args) {
566 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
567 0 : extra_cfg.gf_cbr_boost_pct = CAST(VP8E_SET_GF_CBR_BOOST_PCT, args);
568 0 : return update_extracfg(ctx, &extra_cfg);
569 : }
570 :
571 0 : static vpx_codec_err_t set_screen_content_mode(vpx_codec_alg_priv_t *ctx,
572 : va_list args) {
573 0 : struct vp8_extracfg extra_cfg = ctx->vp8_cfg;
574 0 : extra_cfg.screen_content_mode = CAST(VP8E_SET_SCREEN_CONTENT_MODE, args);
575 0 : return update_extracfg(ctx, &extra_cfg);
576 : }
577 :
578 0 : static vpx_codec_err_t vp8e_mr_alloc_mem(const vpx_codec_enc_cfg_t *cfg,
579 : void **mem_loc) {
580 0 : vpx_codec_err_t res = 0;
581 :
582 : #if CONFIG_MULTI_RES_ENCODING
583 : LOWER_RES_FRAME_INFO *shared_mem_loc;
584 0 : int mb_rows = ((cfg->g_w + 15) >> 4);
585 0 : int mb_cols = ((cfg->g_h + 15) >> 4);
586 :
587 0 : shared_mem_loc = calloc(1, sizeof(LOWER_RES_FRAME_INFO));
588 0 : if (!shared_mem_loc) {
589 0 : res = VPX_CODEC_MEM_ERROR;
590 : }
591 :
592 0 : shared_mem_loc->mb_info =
593 0 : calloc(mb_rows * mb_cols, sizeof(LOWER_RES_MB_INFO));
594 0 : if (!(shared_mem_loc->mb_info)) {
595 0 : res = VPX_CODEC_MEM_ERROR;
596 : } else {
597 0 : *mem_loc = (void *)shared_mem_loc;
598 0 : res = VPX_CODEC_OK;
599 : }
600 : #else
601 : (void)cfg;
602 : (void)mem_loc;
603 : #endif
604 0 : return res;
605 : }
606 :
607 0 : static vpx_codec_err_t vp8e_init(vpx_codec_ctx_t *ctx,
608 : vpx_codec_priv_enc_mr_cfg_t *mr_cfg) {
609 0 : vpx_codec_err_t res = VPX_CODEC_OK;
610 :
611 0 : vp8_rtcd();
612 0 : vpx_dsp_rtcd();
613 0 : vpx_scale_rtcd();
614 :
615 0 : if (!ctx->priv) {
616 0 : struct vpx_codec_alg_priv *priv =
617 : (struct vpx_codec_alg_priv *)vpx_calloc(1, sizeof(*priv));
618 :
619 0 : if (!priv) {
620 0 : return VPX_CODEC_MEM_ERROR;
621 : }
622 :
623 0 : ctx->priv = (vpx_codec_priv_t *)priv;
624 0 : ctx->priv->init_flags = ctx->init_flags;
625 :
626 0 : if (ctx->config.enc) {
627 : /* Update the reference to the config structure to an
628 : * internal copy.
629 : */
630 0 : priv->cfg = *ctx->config.enc;
631 0 : ctx->config.enc = &priv->cfg;
632 : }
633 :
634 0 : priv->vp8_cfg = default_extracfg;
635 0 : priv->vp8_cfg.pkt_list = &priv->pkt_list.head;
636 :
637 0 : priv->cx_data_sz = priv->cfg.g_w * priv->cfg.g_h * 3 / 2 * 2;
638 :
639 0 : if (priv->cx_data_sz < 32768) priv->cx_data_sz = 32768;
640 :
641 0 : priv->cx_data = malloc(priv->cx_data_sz);
642 :
643 0 : if (!priv->cx_data) {
644 0 : return VPX_CODEC_MEM_ERROR;
645 : }
646 :
647 0 : if (mr_cfg) {
648 0 : ctx->priv->enc.total_encoders = mr_cfg->mr_total_resolutions;
649 : } else {
650 0 : ctx->priv->enc.total_encoders = 1;
651 : }
652 :
653 0 : once(vp8_initialize_enc);
654 :
655 0 : res = validate_config(priv, &priv->cfg, &priv->vp8_cfg, 0);
656 :
657 0 : if (!res) {
658 0 : set_vp8e_config(&priv->oxcf, priv->cfg, priv->vp8_cfg, mr_cfg);
659 0 : priv->cpi = vp8_create_compressor(&priv->oxcf);
660 0 : if (!priv->cpi) res = VPX_CODEC_MEM_ERROR;
661 : }
662 : }
663 :
664 0 : return res;
665 : }
666 :
667 0 : 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 0 : if (ctx->oxcf.mr_total_resolutions > 0 &&
671 0 : (ctx->oxcf.mr_encoder_id == ctx->oxcf.mr_total_resolutions - 1)) {
672 0 : LOWER_RES_FRAME_INFO *shared_mem_loc =
673 : (LOWER_RES_FRAME_INFO *)ctx->oxcf.mr_low_res_mode_info;
674 0 : free(shared_mem_loc->mb_info);
675 0 : free(ctx->oxcf.mr_low_res_mode_info);
676 : }
677 : #endif
678 :
679 0 : free(ctx->cx_data);
680 0 : vp8_remove_compressor(&ctx->cpi);
681 0 : vpx_free(ctx);
682 0 : return VPX_CODEC_OK;
683 : }
684 :
685 0 : static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img,
686 : YV12_BUFFER_CONFIG *yv12) {
687 0 : const int y_w = img->d_w;
688 0 : const int y_h = img->d_h;
689 0 : const int uv_w = (img->d_w + 1) / 2;
690 0 : const int uv_h = (img->d_h + 1) / 2;
691 0 : vpx_codec_err_t res = VPX_CODEC_OK;
692 0 : yv12->y_buffer = img->planes[VPX_PLANE_Y];
693 0 : yv12->u_buffer = img->planes[VPX_PLANE_U];
694 0 : yv12->v_buffer = img->planes[VPX_PLANE_V];
695 :
696 0 : yv12->y_crop_width = y_w;
697 0 : yv12->y_crop_height = y_h;
698 0 : yv12->y_width = y_w;
699 0 : yv12->y_height = y_h;
700 0 : yv12->uv_crop_width = uv_w;
701 0 : yv12->uv_crop_height = uv_h;
702 0 : yv12->uv_width = uv_w;
703 0 : yv12->uv_height = uv_h;
704 :
705 0 : yv12->y_stride = img->stride[VPX_PLANE_Y];
706 0 : yv12->uv_stride = img->stride[VPX_PLANE_U];
707 :
708 0 : yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2;
709 0 : return res;
710 : }
711 :
712 0 : 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 0 : new_qc = MODE_BESTQUALITY;
720 :
721 0 : if (deadline) {
722 : uint64_t duration_us;
723 :
724 : /* Convert duration parameter from stream timebase to microseconds */
725 0 : duration_us = (uint64_t)duration * 1000000 *
726 0 : (uint64_t)ctx->cfg.g_timebase.num /
727 0 : (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 0 : 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 0 : if (deadline == VPX_DL_REALTIME) {
741 0 : new_qc = MODE_REALTIME;
742 0 : } else if (ctx->cfg.g_pass == VPX_RC_FIRST_PASS) {
743 0 : new_qc = MODE_FIRSTPASS;
744 0 : } else if (ctx->cfg.g_pass == VPX_RC_LAST_PASS) {
745 0 : new_qc =
746 0 : (new_qc == MODE_BESTQUALITY) ? MODE_SECONDPASS_BEST : MODE_SECONDPASS;
747 : }
748 :
749 0 : if (ctx->oxcf.Mode != new_qc) {
750 0 : ctx->oxcf.Mode = new_qc;
751 0 : vp8_change_config(ctx->cpi, &ctx->oxcf);
752 : }
753 0 : }
754 :
755 0 : 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 0 : if (((flags & VP8_EFLAG_NO_UPD_GF) && (flags & VP8_EFLAG_FORCE_GF)) ||
759 0 : ((flags & VP8_EFLAG_NO_UPD_ARF) && (flags & VP8_EFLAG_FORCE_ARF))) {
760 0 : ctx->base.err_detail = "Conflicting flags.";
761 0 : return VPX_CODEC_INVALID_PARAM;
762 : }
763 :
764 0 : if (flags &
765 : (VP8_EFLAG_NO_REF_LAST | VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_REF_ARF)) {
766 0 : int ref = 7;
767 :
768 0 : if (flags & VP8_EFLAG_NO_REF_LAST) ref ^= VP8_LAST_FRAME;
769 :
770 0 : if (flags & VP8_EFLAG_NO_REF_GF) ref ^= VP8_GOLD_FRAME;
771 :
772 0 : if (flags & VP8_EFLAG_NO_REF_ARF) ref ^= VP8_ALTR_FRAME;
773 :
774 0 : vp8_use_as_reference(ctx->cpi, ref);
775 : }
776 :
777 0 : 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 0 : int upd = 7;
781 :
782 0 : if (flags & VP8_EFLAG_NO_UPD_LAST) upd ^= VP8_LAST_FRAME;
783 :
784 0 : if (flags & VP8_EFLAG_NO_UPD_GF) upd ^= VP8_GOLD_FRAME;
785 :
786 0 : if (flags & VP8_EFLAG_NO_UPD_ARF) upd ^= VP8_ALTR_FRAME;
787 :
788 0 : vp8_update_reference(ctx->cpi, upd);
789 : }
790 :
791 0 : if (flags & VP8_EFLAG_NO_UPD_ENTROPY) {
792 0 : vp8_update_entropy(ctx->cpi, 0);
793 : }
794 :
795 0 : return VPX_CODEC_OK;
796 : }
797 :
798 0 : 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 0 : vpx_codec_err_t res = VPX_CODEC_OK;
804 :
805 0 : if (!ctx->cfg.rc_target_bitrate) return res;
806 :
807 0 : if (img) res = validate_img(ctx, img);
808 :
809 0 : if (!res) res = validate_config(ctx, &ctx->cfg, &ctx->vp8_cfg, 1);
810 :
811 0 : pick_quickcompress_mode(ctx, duration, deadline);
812 0 : 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 0 : if (!flags) {
817 0 : flags = ctx->control_frame_flags;
818 : }
819 0 : ctx->control_frame_flags = 0;
820 :
821 0 : if (!res) res = set_reference_and_update(ctx, flags);
822 :
823 : /* Handle fixed keyframe intervals */
824 0 : if (ctx->cfg.kf_mode == VPX_KF_AUTO &&
825 0 : ctx->cfg.kf_min_dist == ctx->cfg.kf_max_dist) {
826 0 : if (++ctx->fixed_kf_cntr > ctx->cfg.kf_min_dist) {
827 0 : flags |= VPX_EFLAG_FORCE_KF;
828 0 : ctx->fixed_kf_cntr = 1;
829 : }
830 : }
831 :
832 : /* Initialize the encoder instance on the first frame*/
833 0 : 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 0 : int comp_data_state = 0;
841 :
842 : /* Set up internal flags */
843 0 : if (ctx->base.init_flags & VPX_CODEC_USE_PSNR) {
844 0 : ((VP8_COMP *)ctx->cpi)->b_calculate_psnr = 1;
845 : }
846 :
847 0 : if (ctx->base.init_flags & VPX_CODEC_USE_OUTPUT_PARTITION) {
848 0 : ((VP8_COMP *)ctx->cpi)->output_partition = 1;
849 : }
850 :
851 : /* Convert API flags to internal codec lib flags */
852 0 : lib_flags = (flags & VPX_EFLAG_FORCE_KF) ? FRAMEFLAGS_KEY : 0;
853 :
854 : /* vp8 use 10,000,000 ticks/second as time stamp */
855 0 : dst_time_stamp =
856 0 : pts * 10000000 * ctx->cfg.g_timebase.num / ctx->cfg.g_timebase.den;
857 0 : dst_end_time_stamp = (pts + duration) * 10000000 * ctx->cfg.g_timebase.num /
858 0 : ctx->cfg.g_timebase.den;
859 :
860 0 : if (img != NULL) {
861 0 : res = image2yuvconfig(img, &sd);
862 :
863 0 : if (sd.y_width != ctx->cfg.g_w || sd.y_height != ctx->cfg.g_h) {
864 : /* from vpx_encoder.h for g_w/g_h:
865 : "Note that the frames passed as input to the encoder must have this
866 : resolution"
867 : */
868 0 : ctx->base.err_detail = "Invalid input frame resolution";
869 0 : res = VPX_CODEC_INVALID_PARAM;
870 : } else {
871 0 : if (vp8_receive_raw_frame(ctx->cpi, ctx->next_frame_flag | lib_flags,
872 : &sd, dst_time_stamp, dst_end_time_stamp)) {
873 0 : VP8_COMP *cpi = (VP8_COMP *)ctx->cpi;
874 0 : res = update_error_state(ctx, &cpi->common.error);
875 : }
876 : }
877 :
878 : /* reset for next frame */
879 0 : ctx->next_frame_flag = 0;
880 : }
881 :
882 0 : cx_data = ctx->cx_data;
883 0 : cx_data_sz = ctx->cx_data_sz;
884 0 : cx_data_end = ctx->cx_data + cx_data_sz;
885 0 : lib_flags = 0;
886 :
887 0 : while (cx_data_sz >= ctx->cx_data_sz / 2) {
888 0 : comp_data_state = vp8_get_compressed_data(
889 : ctx->cpi, &lib_flags, &size, cx_data, cx_data_end, &dst_time_stamp,
890 : &dst_end_time_stamp, !img);
891 :
892 0 : if (comp_data_state == VPX_CODEC_CORRUPT_FRAME) {
893 0 : return VPX_CODEC_CORRUPT_FRAME;
894 0 : } else if (comp_data_state == -1) {
895 0 : break;
896 : }
897 :
898 0 : if (size) {
899 : vpx_codec_pts_t round, delta;
900 : vpx_codec_cx_pkt_t pkt;
901 0 : VP8_COMP *cpi = (VP8_COMP *)ctx->cpi;
902 :
903 : /* Add the frame packet to the list of returned packets. */
904 0 : round = (vpx_codec_pts_t)10000000 * ctx->cfg.g_timebase.num / 2 - 1;
905 0 : delta = (dst_end_time_stamp - dst_time_stamp);
906 0 : pkt.kind = VPX_CODEC_CX_FRAME_PKT;
907 0 : pkt.data.frame.pts =
908 0 : (dst_time_stamp * ctx->cfg.g_timebase.den + round) /
909 0 : ctx->cfg.g_timebase.num / 10000000;
910 0 : pkt.data.frame.duration =
911 0 : (unsigned long)((delta * ctx->cfg.g_timebase.den + round) /
912 0 : ctx->cfg.g_timebase.num / 10000000);
913 0 : pkt.data.frame.flags = lib_flags << 16;
914 :
915 0 : if (lib_flags & FRAMEFLAGS_KEY) {
916 0 : pkt.data.frame.flags |= VPX_FRAME_IS_KEY;
917 : }
918 :
919 0 : if (!cpi->common.show_frame) {
920 0 : pkt.data.frame.flags |= VPX_FRAME_IS_INVISIBLE;
921 :
922 : /* This timestamp should be as close as possible to the
923 : * prior PTS so that if a decoder uses pts to schedule when
924 : * to do this, we start right after last frame was decoded.
925 : * Invisible frames have no duration.
926 : */
927 0 : pkt.data.frame.pts =
928 0 : ((cpi->last_time_stamp_seen * ctx->cfg.g_timebase.den + round) /
929 0 : ctx->cfg.g_timebase.num / 10000000) +
930 : 1;
931 0 : pkt.data.frame.duration = 0;
932 : }
933 :
934 0 : if (cpi->droppable) pkt.data.frame.flags |= VPX_FRAME_IS_DROPPABLE;
935 :
936 0 : if (cpi->output_partition) {
937 : int i;
938 0 : const int num_partitions =
939 0 : (1 << cpi->common.multi_token_partition) + 1;
940 :
941 0 : pkt.data.frame.flags |= VPX_FRAME_IS_FRAGMENT;
942 :
943 0 : for (i = 0; i < num_partitions; ++i) {
944 : #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
945 : pkt.data.frame.buf = cpi->partition_d[i];
946 : #else
947 0 : pkt.data.frame.buf = cx_data;
948 0 : cx_data += cpi->partition_sz[i];
949 0 : cx_data_sz -= cpi->partition_sz[i];
950 : #endif
951 0 : pkt.data.frame.sz = cpi->partition_sz[i];
952 0 : pkt.data.frame.partition_id = i;
953 : /* don't set the fragment bit for the last partition */
954 0 : if (i == (num_partitions - 1)) {
955 0 : pkt.data.frame.flags &= ~VPX_FRAME_IS_FRAGMENT;
956 : }
957 0 : vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
958 : }
959 : #if CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING
960 : /* In lagged mode the encoder can buffer multiple frames.
961 : * We don't want this in partitioned output because
962 : * partitions are spread all over the output buffer.
963 : * So, force an exit!
964 : */
965 : cx_data_sz -= ctx->cx_data_sz / 2;
966 : #endif
967 : } else {
968 0 : pkt.data.frame.buf = cx_data;
969 0 : pkt.data.frame.sz = size;
970 0 : pkt.data.frame.partition_id = -1;
971 0 : vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
972 0 : cx_data += size;
973 0 : cx_data_sz -= size;
974 : }
975 : }
976 : }
977 : }
978 :
979 0 : return res;
980 : }
981 :
982 0 : static const vpx_codec_cx_pkt_t *vp8e_get_cxdata(vpx_codec_alg_priv_t *ctx,
983 : vpx_codec_iter_t *iter) {
984 0 : return vpx_codec_pkt_list_get(&ctx->pkt_list.head, iter);
985 : }
986 :
987 0 : static vpx_codec_err_t vp8e_set_reference(vpx_codec_alg_priv_t *ctx,
988 : va_list args) {
989 0 : vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
990 :
991 0 : if (data) {
992 0 : vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
993 : YV12_BUFFER_CONFIG sd;
994 :
995 0 : image2yuvconfig(&frame->img, &sd);
996 0 : vp8_set_reference(ctx->cpi, frame->frame_type, &sd);
997 0 : return VPX_CODEC_OK;
998 : } else {
999 0 : return VPX_CODEC_INVALID_PARAM;
1000 : }
1001 : }
1002 :
1003 0 : static vpx_codec_err_t vp8e_get_reference(vpx_codec_alg_priv_t *ctx,
1004 : va_list args) {
1005 0 : vpx_ref_frame_t *data = va_arg(args, vpx_ref_frame_t *);
1006 :
1007 0 : if (data) {
1008 0 : vpx_ref_frame_t *frame = (vpx_ref_frame_t *)data;
1009 : YV12_BUFFER_CONFIG sd;
1010 :
1011 0 : image2yuvconfig(&frame->img, &sd);
1012 0 : vp8_get_reference(ctx->cpi, frame->frame_type, &sd);
1013 0 : return VPX_CODEC_OK;
1014 : } else {
1015 0 : return VPX_CODEC_INVALID_PARAM;
1016 : }
1017 : }
1018 :
1019 0 : static vpx_codec_err_t vp8e_set_previewpp(vpx_codec_alg_priv_t *ctx,
1020 : va_list args) {
1021 : #if CONFIG_POSTPROC
1022 0 : vp8_postproc_cfg_t *data = va_arg(args, vp8_postproc_cfg_t *);
1023 :
1024 0 : if (data) {
1025 0 : ctx->preview_ppcfg = *((vp8_postproc_cfg_t *)data);
1026 0 : return VPX_CODEC_OK;
1027 : } else {
1028 0 : return VPX_CODEC_INVALID_PARAM;
1029 : }
1030 : #else
1031 : (void)ctx;
1032 : (void)args;
1033 : return VPX_CODEC_INCAPABLE;
1034 : #endif
1035 : }
1036 :
1037 0 : static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx) {
1038 : YV12_BUFFER_CONFIG sd;
1039 : vp8_ppflags_t flags;
1040 0 : vp8_zero(flags);
1041 :
1042 0 : if (ctx->preview_ppcfg.post_proc_flag) {
1043 0 : flags.post_proc_flag = ctx->preview_ppcfg.post_proc_flag;
1044 0 : flags.deblocking_level = ctx->preview_ppcfg.deblocking_level;
1045 0 : flags.noise_level = ctx->preview_ppcfg.noise_level;
1046 : }
1047 :
1048 0 : if (0 == vp8_get_preview_raw_frame(ctx->cpi, &sd, &flags)) {
1049 : /*
1050 : vpx_img_wrap(&ctx->preview_img, VPX_IMG_FMT_YV12,
1051 : sd.y_width + 2*VP8BORDERINPIXELS,
1052 : sd.y_height + 2*VP8BORDERINPIXELS,
1053 : 1,
1054 : sd.buffer_alloc);
1055 : vpx_img_set_rect(&ctx->preview_img,
1056 : VP8BORDERINPIXELS, VP8BORDERINPIXELS,
1057 : sd.y_width, sd.y_height);
1058 : */
1059 :
1060 0 : ctx->preview_img.bps = 12;
1061 0 : ctx->preview_img.planes[VPX_PLANE_Y] = sd.y_buffer;
1062 0 : ctx->preview_img.planes[VPX_PLANE_U] = sd.u_buffer;
1063 0 : ctx->preview_img.planes[VPX_PLANE_V] = sd.v_buffer;
1064 :
1065 0 : ctx->preview_img.fmt = VPX_IMG_FMT_I420;
1066 0 : ctx->preview_img.x_chroma_shift = 1;
1067 0 : ctx->preview_img.y_chroma_shift = 1;
1068 :
1069 0 : ctx->preview_img.d_w = sd.y_width;
1070 0 : ctx->preview_img.d_h = sd.y_height;
1071 0 : ctx->preview_img.stride[VPX_PLANE_Y] = sd.y_stride;
1072 0 : ctx->preview_img.stride[VPX_PLANE_U] = sd.uv_stride;
1073 0 : ctx->preview_img.stride[VPX_PLANE_V] = sd.uv_stride;
1074 0 : ctx->preview_img.w = sd.y_width;
1075 0 : ctx->preview_img.h = sd.y_height;
1076 :
1077 0 : return &ctx->preview_img;
1078 : } else {
1079 0 : return NULL;
1080 : }
1081 : }
1082 :
1083 0 : static vpx_codec_err_t vp8e_set_frame_flags(vpx_codec_alg_priv_t *ctx,
1084 : va_list args) {
1085 0 : int frame_flags = va_arg(args, int);
1086 0 : ctx->control_frame_flags = frame_flags;
1087 0 : return set_reference_and_update(ctx, frame_flags);
1088 : }
1089 :
1090 0 : static vpx_codec_err_t vp8e_set_temporal_layer_id(vpx_codec_alg_priv_t *ctx,
1091 : va_list args) {
1092 0 : int layer_id = va_arg(args, int);
1093 0 : if (layer_id < 0 || layer_id >= (int)ctx->cfg.ts_number_layers) {
1094 0 : return VPX_CODEC_INVALID_PARAM;
1095 : }
1096 0 : ctx->cpi->temporal_layer_id = layer_id;
1097 0 : return VPX_CODEC_OK;
1098 : }
1099 :
1100 0 : static vpx_codec_err_t vp8e_set_roi_map(vpx_codec_alg_priv_t *ctx,
1101 : va_list args) {
1102 0 : vpx_roi_map_t *data = va_arg(args, vpx_roi_map_t *);
1103 :
1104 0 : if (data) {
1105 0 : vpx_roi_map_t *roi = (vpx_roi_map_t *)data;
1106 :
1107 0 : if (!vp8_set_roimap(ctx->cpi, roi->roi_map, roi->rows, roi->cols,
1108 0 : roi->delta_q, roi->delta_lf, roi->static_threshold)) {
1109 0 : return VPX_CODEC_OK;
1110 : } else {
1111 0 : return VPX_CODEC_INVALID_PARAM;
1112 : }
1113 : } else {
1114 0 : return VPX_CODEC_INVALID_PARAM;
1115 : }
1116 : }
1117 :
1118 0 : static vpx_codec_err_t vp8e_set_activemap(vpx_codec_alg_priv_t *ctx,
1119 : va_list args) {
1120 0 : vpx_active_map_t *data = va_arg(args, vpx_active_map_t *);
1121 :
1122 0 : if (data) {
1123 0 : vpx_active_map_t *map = (vpx_active_map_t *)data;
1124 :
1125 0 : if (!vp8_set_active_map(ctx->cpi, map->active_map, map->rows, map->cols)) {
1126 0 : return VPX_CODEC_OK;
1127 : } else {
1128 0 : return VPX_CODEC_INVALID_PARAM;
1129 : }
1130 : } else {
1131 0 : return VPX_CODEC_INVALID_PARAM;
1132 : }
1133 : }
1134 :
1135 0 : static vpx_codec_err_t vp8e_set_scalemode(vpx_codec_alg_priv_t *ctx,
1136 : va_list args) {
1137 0 : vpx_scaling_mode_t *data = va_arg(args, vpx_scaling_mode_t *);
1138 :
1139 0 : if (data) {
1140 : int res;
1141 0 : vpx_scaling_mode_t scalemode = *(vpx_scaling_mode_t *)data;
1142 0 : res = vp8_set_internal_size(ctx->cpi, (VPX_SCALING)scalemode.h_scaling_mode,
1143 0 : (VPX_SCALING)scalemode.v_scaling_mode);
1144 :
1145 0 : if (!res) {
1146 : /*force next frame a key frame to effect scaling mode */
1147 0 : ctx->next_frame_flag |= FRAMEFLAGS_KEY;
1148 0 : return VPX_CODEC_OK;
1149 : } else {
1150 0 : return VPX_CODEC_INVALID_PARAM;
1151 : }
1152 : } else {
1153 0 : return VPX_CODEC_INVALID_PARAM;
1154 : }
1155 : }
1156 :
1157 : static vpx_codec_ctrl_fn_map_t vp8e_ctf_maps[] = {
1158 : { VP8_SET_REFERENCE, vp8e_set_reference },
1159 : { VP8_COPY_REFERENCE, vp8e_get_reference },
1160 : { VP8_SET_POSTPROC, vp8e_set_previewpp },
1161 : { VP8E_SET_FRAME_FLAGS, vp8e_set_frame_flags },
1162 : { VP8E_SET_TEMPORAL_LAYER_ID, vp8e_set_temporal_layer_id },
1163 : { VP8E_SET_ROI_MAP, vp8e_set_roi_map },
1164 : { VP8E_SET_ACTIVEMAP, vp8e_set_activemap },
1165 : { VP8E_SET_SCALEMODE, vp8e_set_scalemode },
1166 : { VP8E_SET_CPUUSED, set_cpu_used },
1167 : { VP8E_SET_NOISE_SENSITIVITY, set_noise_sensitivity },
1168 : { VP8E_SET_ENABLEAUTOALTREF, set_enable_auto_alt_ref },
1169 : { VP8E_SET_SHARPNESS, set_sharpness },
1170 : { VP8E_SET_STATIC_THRESHOLD, set_static_thresh },
1171 : { VP8E_SET_TOKEN_PARTITIONS, set_token_partitions },
1172 : { VP8E_GET_LAST_QUANTIZER, get_quantizer },
1173 : { VP8E_GET_LAST_QUANTIZER_64, get_quantizer64 },
1174 : { VP8E_SET_ARNR_MAXFRAMES, set_arnr_max_frames },
1175 : { VP8E_SET_ARNR_STRENGTH, set_arnr_strength },
1176 : { VP8E_SET_ARNR_TYPE, set_arnr_type },
1177 : { VP8E_SET_TUNING, set_tuning },
1178 : { VP8E_SET_CQ_LEVEL, set_cq_level },
1179 : { VP8E_SET_MAX_INTRA_BITRATE_PCT, set_rc_max_intra_bitrate_pct },
1180 : { VP8E_SET_SCREEN_CONTENT_MODE, set_screen_content_mode },
1181 : { VP8E_SET_GF_CBR_BOOST_PCT, ctrl_set_rc_gf_cbr_boost_pct },
1182 : { -1, NULL },
1183 : };
1184 :
1185 : static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] = {
1186 : { 0,
1187 : {
1188 : 0, /* g_usage */
1189 : 0, /* g_threads */
1190 : 0, /* g_profile */
1191 :
1192 : 320, /* g_width */
1193 : 240, /* g_height */
1194 : VPX_BITS_8, /* g_bit_depth */
1195 : 8, /* g_input_bit_depth */
1196 :
1197 : { 1, 30 }, /* g_timebase */
1198 :
1199 : 0, /* g_error_resilient */
1200 :
1201 : VPX_RC_ONE_PASS, /* g_pass */
1202 :
1203 : 0, /* g_lag_in_frames */
1204 :
1205 : 0, /* rc_dropframe_thresh */
1206 : 0, /* rc_resize_allowed */
1207 : 1, /* rc_scaled_width */
1208 : 1, /* rc_scaled_height */
1209 : 60, /* rc_resize_down_thresold */
1210 : 30, /* rc_resize_up_thresold */
1211 :
1212 : VPX_VBR, /* rc_end_usage */
1213 : { NULL, 0 }, /* rc_twopass_stats_in */
1214 : { NULL, 0 }, /* rc_firstpass_mb_stats_in */
1215 : 256, /* rc_target_bandwidth */
1216 : 4, /* rc_min_quantizer */
1217 : 63, /* rc_max_quantizer */
1218 : 100, /* rc_undershoot_pct */
1219 : 100, /* rc_overshoot_pct */
1220 :
1221 : 6000, /* rc_max_buffer_size */
1222 : 4000, /* rc_buffer_initial_size; */
1223 : 5000, /* rc_buffer_optimal_size; */
1224 :
1225 : 50, /* rc_two_pass_vbrbias */
1226 : 0, /* rc_two_pass_vbrmin_section */
1227 : 400, /* rc_two_pass_vbrmax_section */
1228 :
1229 : /* keyframing settings (kf) */
1230 : VPX_KF_AUTO, /* g_kfmode*/
1231 : 0, /* kf_min_dist */
1232 : 128, /* kf_max_dist */
1233 :
1234 : VPX_SS_DEFAULT_LAYERS, /* ss_number_layers */
1235 : { 0 },
1236 : { 0 }, /* ss_target_bitrate */
1237 : 1, /* ts_number_layers */
1238 : { 0 }, /* ts_target_bitrate */
1239 : { 0 }, /* ts_rate_decimator */
1240 : 0, /* ts_periodicity */
1241 : { 0 }, /* ts_layer_id */
1242 : { 0 }, /* layer_target_bitrate */
1243 : 0 /* temporal_layering_mode */
1244 : } },
1245 : };
1246 :
1247 : #ifndef VERSION_STRING
1248 : #define VERSION_STRING
1249 : #endif
1250 0 : CODEC_INTERFACE(vpx_codec_vp8_cx) = {
1251 : "WebM Project VP8 Encoder" VERSION_STRING,
1252 : VPX_CODEC_INTERNAL_ABI_VERSION,
1253 : VPX_CODEC_CAP_ENCODER | VPX_CODEC_CAP_PSNR | VPX_CODEC_CAP_OUTPUT_PARTITION,
1254 : /* vpx_codec_caps_t caps; */
1255 : vp8e_init, /* vpx_codec_init_fn_t init; */
1256 : vp8e_destroy, /* vpx_codec_destroy_fn_t destroy; */
1257 : vp8e_ctf_maps, /* vpx_codec_ctrl_fn_map_t *ctrl_maps; */
1258 : {
1259 : NULL, /* vpx_codec_peek_si_fn_t peek_si; */
1260 : NULL, /* vpx_codec_get_si_fn_t get_si; */
1261 : NULL, /* vpx_codec_decode_fn_t decode; */
1262 : NULL, /* vpx_codec_frame_get_fn_t frame_get; */
1263 : NULL, /* vpx_codec_set_fb_fn_t set_fb_fn; */
1264 : },
1265 : {
1266 : 1, /* 1 cfg map */
1267 : vp8e_usage_cfg_map, /* vpx_codec_enc_cfg_map_t cfg_maps; */
1268 : vp8e_encode, /* vpx_codec_encode_fn_t encode; */
1269 : vp8e_get_cxdata, /* vpx_codec_get_cx_data_fn_t get_cx_data; */
1270 : vp8e_set_config, NULL, vp8e_get_preview, vp8e_mr_alloc_mem,
1271 : } /* encoder functions */
1272 : };
|