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