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