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