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