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