|
1 /* |
|
2 * Copyright (c) 2013 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 /** |
|
12 * @file |
|
13 * VP9 SVC encoding support via libvpx |
|
14 */ |
|
15 |
|
16 #include <stdarg.h> |
|
17 #include <stdio.h> |
|
18 #include <stdlib.h> |
|
19 #include <string.h> |
|
20 #define VPX_DISABLE_CTRL_TYPECHECKS 1 |
|
21 #define VPX_CODEC_DISABLE_COMPAT 1 |
|
22 #include "vpx/svc_context.h" |
|
23 #include "vpx/vp8cx.h" |
|
24 #include "vpx/vpx_encoder.h" |
|
25 |
|
26 #ifdef __MINGW32__ |
|
27 #define strtok_r strtok_s |
|
28 #ifndef MINGW_HAS_SECURE_API |
|
29 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h |
|
30 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); |
|
31 #endif /* MINGW_HAS_SECURE_API */ |
|
32 #endif /* __MINGW32__ */ |
|
33 |
|
34 #ifdef _MSC_VER |
|
35 #define strdup _strdup |
|
36 #define strtok_r strtok_s |
|
37 #endif |
|
38 |
|
39 #define SVC_REFERENCE_FRAMES 8 |
|
40 #define SUPERFRAME_SLOTS (8) |
|
41 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) |
|
42 #define OPTION_BUFFER_SIZE 256 |
|
43 |
|
44 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; |
|
45 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; |
|
46 |
|
47 typedef struct SvcInternal { |
|
48 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options |
|
49 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers |
|
50 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors |
|
51 |
|
52 // values extracted from option, quantizers |
|
53 int scaling_factor_num[VPX_SS_MAX_LAYERS]; |
|
54 int scaling_factor_den[VPX_SS_MAX_LAYERS]; |
|
55 int quantizer[VPX_SS_MAX_LAYERS]; |
|
56 |
|
57 // accumulated statistics |
|
58 double psnr_in_layer[VPX_SS_MAX_LAYERS]; |
|
59 uint32_t bytes_in_layer[VPX_SS_MAX_LAYERS]; |
|
60 |
|
61 // codec encoding values |
|
62 int width; // width of highest layer |
|
63 int height; // height of highest layer |
|
64 int kf_dist; // distance between keyframes |
|
65 |
|
66 // state variables |
|
67 int encode_frame_count; |
|
68 int frame_within_gop; |
|
69 vpx_enc_frame_flags_t enc_frame_flags; |
|
70 int layers; |
|
71 int layer; |
|
72 int is_keyframe; |
|
73 |
|
74 size_t frame_size; |
|
75 size_t buffer_size; |
|
76 void *buffer; |
|
77 |
|
78 char message_buffer[2048]; |
|
79 vpx_codec_ctx_t *codec_ctx; |
|
80 } SvcInternal; |
|
81 |
|
82 // Superframe is used to generate an index of individual frames (i.e., layers) |
|
83 struct Superframe { |
|
84 int count; |
|
85 uint32_t sizes[SUPERFRAME_SLOTS]; |
|
86 uint32_t magnitude; |
|
87 uint8_t buffer[SUPERFRAME_BUFFER_SIZE]; |
|
88 size_t index_size; |
|
89 }; |
|
90 |
|
91 // One encoded frame layer |
|
92 struct LayerData { |
|
93 void *buf; // compressed data buffer |
|
94 size_t size; // length of compressed data |
|
95 struct LayerData *next; |
|
96 }; |
|
97 |
|
98 // create LayerData from encoder output |
|
99 static struct LayerData *ld_create(void *buf, size_t size) { |
|
100 struct LayerData *const layer_data = malloc(sizeof(*layer_data)); |
|
101 if (layer_data == NULL) { |
|
102 return NULL; |
|
103 } |
|
104 layer_data->buf = malloc(size); |
|
105 if (layer_data->buf == NULL) { |
|
106 free(layer_data); |
|
107 return NULL; |
|
108 } |
|
109 memcpy(layer_data->buf, buf, size); |
|
110 layer_data->size = size; |
|
111 return layer_data; |
|
112 } |
|
113 |
|
114 // free LayerData |
|
115 static void ld_free(struct LayerData *layer_data) { |
|
116 if (layer_data) { |
|
117 if (layer_data->buf) { |
|
118 free(layer_data->buf); |
|
119 layer_data->buf = NULL; |
|
120 } |
|
121 free(layer_data); |
|
122 } |
|
123 } |
|
124 |
|
125 // add layer data to list |
|
126 static void ld_list_add(struct LayerData **list, struct LayerData *layer_data) { |
|
127 struct LayerData **p = list; |
|
128 |
|
129 while (*p != NULL) p = &(*p)->next; |
|
130 *p = layer_data; |
|
131 layer_data->next = NULL; |
|
132 } |
|
133 |
|
134 // get accumulated size of layer data |
|
135 static size_t ld_list_get_buffer_size(struct LayerData *list) { |
|
136 struct LayerData *p; |
|
137 size_t size = 0; |
|
138 |
|
139 for (p = list; p != NULL; p = p->next) { |
|
140 size += p->size; |
|
141 } |
|
142 return size; |
|
143 } |
|
144 |
|
145 // copy layer data to buffer |
|
146 static void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) { |
|
147 struct LayerData *p; |
|
148 |
|
149 for (p = list; p != NULL; p = p->next) { |
|
150 buffer[0] = 1; |
|
151 memcpy(buffer, p->buf, p->size); |
|
152 buffer += p->size; |
|
153 } |
|
154 } |
|
155 |
|
156 // free layer data list |
|
157 static void ld_list_free(struct LayerData *list) { |
|
158 struct LayerData *p = list; |
|
159 |
|
160 while (p) { |
|
161 list = list->next; |
|
162 ld_free(p); |
|
163 p = list; |
|
164 } |
|
165 } |
|
166 |
|
167 static void sf_create_index(struct Superframe *sf) { |
|
168 uint8_t marker = 0xc0; |
|
169 int i; |
|
170 uint32_t mag, mask; |
|
171 uint8_t *bufp; |
|
172 |
|
173 if (sf->count == 0 || sf->count >= 8) return; |
|
174 |
|
175 // Add the number of frames to the marker byte |
|
176 marker |= sf->count - 1; |
|
177 |
|
178 // Choose the magnitude |
|
179 for (mag = 0, mask = 0xff; mag < 4; ++mag) { |
|
180 if (sf->magnitude < mask) break; |
|
181 mask <<= 8; |
|
182 mask |= 0xff; |
|
183 } |
|
184 marker |= mag << 3; |
|
185 |
|
186 // Write the index |
|
187 sf->index_size = 2 + (mag + 1) * sf->count; |
|
188 bufp = sf->buffer; |
|
189 |
|
190 *bufp++ = marker; |
|
191 for (i = 0; i < sf->count; ++i) { |
|
192 int this_sz = sf->sizes[i]; |
|
193 uint32_t j; |
|
194 |
|
195 for (j = 0; j <= mag; ++j) { |
|
196 *bufp++ = this_sz & 0xff; |
|
197 this_sz >>= 8; |
|
198 } |
|
199 } |
|
200 *bufp++ = marker; |
|
201 } |
|
202 |
|
203 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) { |
|
204 if (svc_ctx == NULL) return NULL; |
|
205 if (svc_ctx->internal == NULL) { |
|
206 SvcInternal *const si = malloc(sizeof(*si)); |
|
207 if (si != NULL) { |
|
208 memset(si, 0, sizeof(*si)); |
|
209 } |
|
210 svc_ctx->internal = si; |
|
211 } |
|
212 return svc_ctx->internal; |
|
213 } |
|
214 |
|
215 static const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) { |
|
216 if (svc_ctx == NULL) return NULL; |
|
217 return svc_ctx->internal; |
|
218 } |
|
219 |
|
220 static void svc_log_reset(SvcContext *svc_ctx) { |
|
221 SvcInternal *const si = (SvcInternal *)svc_ctx->internal; |
|
222 si->message_buffer[0] = '\0'; |
|
223 } |
|
224 |
|
225 static int svc_log(SvcContext *svc_ctx, int level, const char *fmt, ...) { |
|
226 char buf[512]; |
|
227 int retval = 0; |
|
228 va_list ap; |
|
229 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
230 |
|
231 if (level > svc_ctx->log_level) { |
|
232 return retval; |
|
233 } |
|
234 |
|
235 va_start(ap, fmt); |
|
236 retval = vsnprintf(buf, sizeof(buf), fmt, ap); |
|
237 va_end(ap); |
|
238 |
|
239 if (svc_ctx->log_print) { |
|
240 printf("%s", buf); |
|
241 } else { |
|
242 strncat(si->message_buffer, buf, |
|
243 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); |
|
244 } |
|
245 |
|
246 if (level == SVC_LOG_ERROR) { |
|
247 si->codec_ctx->err_detail = si->message_buffer; |
|
248 } |
|
249 return retval; |
|
250 } |
|
251 |
|
252 static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx, |
|
253 const char *value_str) { |
|
254 if (strcmp(value_str, "i") == 0) { |
|
255 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I; |
|
256 } else if (strcmp(value_str, "alt-ip") == 0) { |
|
257 svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP; |
|
258 } else if (strcmp(value_str, "ip") == 0) { |
|
259 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP; |
|
260 } else if (strcmp(value_str, "gf") == 0) { |
|
261 svc_ctx->encoding_mode = USE_GOLDEN_FRAME; |
|
262 } else { |
|
263 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str); |
|
264 return VPX_CODEC_INVALID_PARAM; |
|
265 } |
|
266 return VPX_CODEC_OK; |
|
267 } |
|
268 |
|
269 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, |
|
270 const char *quantizer_values) { |
|
271 char *input_string; |
|
272 char *token; |
|
273 const char *delim = ","; |
|
274 char *save_ptr; |
|
275 int found = 0; |
|
276 int i, q; |
|
277 int res = VPX_CODEC_OK; |
|
278 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
279 |
|
280 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { |
|
281 input_string = strdup(DEFAULT_QUANTIZER_VALUES); |
|
282 } else { |
|
283 input_string = strdup(quantizer_values); |
|
284 } |
|
285 |
|
286 token = strtok_r(input_string, delim, &save_ptr); |
|
287 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
|
288 if (token != NULL) { |
|
289 q = atoi(token); |
|
290 if (q <= 0 || q > 100) { |
|
291 svc_log(svc_ctx, SVC_LOG_ERROR, |
|
292 "svc-quantizer-values: invalid value %s\n", token); |
|
293 res = VPX_CODEC_INVALID_PARAM; |
|
294 break; |
|
295 } |
|
296 token = strtok_r(NULL, delim, &save_ptr); |
|
297 found = i + 1; |
|
298 } else { |
|
299 q = 0; |
|
300 } |
|
301 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; |
|
302 } |
|
303 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { |
|
304 svc_log(svc_ctx, SVC_LOG_ERROR, |
|
305 "svc: quantizers: %d values required, but only %d specified\n", |
|
306 svc_ctx->spatial_layers, found); |
|
307 res = VPX_CODEC_INVALID_PARAM; |
|
308 } |
|
309 free(input_string); |
|
310 return res; |
|
311 } |
|
312 |
|
313 static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) { |
|
314 svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n", |
|
315 value); |
|
316 } |
|
317 |
|
318 static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx, |
|
319 const char *scale_factors) { |
|
320 char *input_string; |
|
321 char *token; |
|
322 const char *delim = ","; |
|
323 char *save_ptr; |
|
324 int found = 0; |
|
325 int i; |
|
326 int64_t num, den; |
|
327 int res = VPX_CODEC_OK; |
|
328 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
329 |
|
330 if (scale_factors == NULL || strlen(scale_factors) == 0) { |
|
331 input_string = strdup(DEFAULT_SCALE_FACTORS); |
|
332 } else { |
|
333 input_string = strdup(scale_factors); |
|
334 } |
|
335 token = strtok_r(input_string, delim, &save_ptr); |
|
336 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
|
337 num = den = 0; |
|
338 if (token != NULL) { |
|
339 num = strtol(token, &token, 10); |
|
340 if (num <= 0) { |
|
341 log_invalid_scale_factor(svc_ctx, token); |
|
342 res = VPX_CODEC_INVALID_PARAM; |
|
343 break; |
|
344 } |
|
345 if (*token++ != '/') { |
|
346 log_invalid_scale_factor(svc_ctx, token); |
|
347 res = VPX_CODEC_INVALID_PARAM; |
|
348 break; |
|
349 } |
|
350 den = strtol(token, &token, 10); |
|
351 if (den <= 0) { |
|
352 log_invalid_scale_factor(svc_ctx, token); |
|
353 res = VPX_CODEC_INVALID_PARAM; |
|
354 break; |
|
355 } |
|
356 token = strtok_r(NULL, delim, &save_ptr); |
|
357 found = i + 1; |
|
358 } |
|
359 si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = |
|
360 (int)num; |
|
361 si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = |
|
362 (int)den; |
|
363 } |
|
364 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { |
|
365 svc_log(svc_ctx, SVC_LOG_ERROR, |
|
366 "svc: scale-factors: %d values required, but only %d specified\n", |
|
367 svc_ctx->spatial_layers, found); |
|
368 res = VPX_CODEC_INVALID_PARAM; |
|
369 } |
|
370 free(input_string); |
|
371 return res; |
|
372 } |
|
373 |
|
374 /** |
|
375 * Parse SVC encoding options |
|
376 * Format: encoding-mode=<svc_mode>,layers=<layer_count> |
|
377 * scale-factors=<n1>/<d1>,<n2>/<d2>,... |
|
378 * quantizers=<q1>,<q2>,... |
|
379 * svc_mode = [i|ip|alt_ip|gf] |
|
380 */ |
|
381 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { |
|
382 char *input_string; |
|
383 char *option_name; |
|
384 char *option_value; |
|
385 char *input_ptr; |
|
386 int res = VPX_CODEC_OK; |
|
387 |
|
388 if (options == NULL) return VPX_CODEC_OK; |
|
389 input_string = strdup(options); |
|
390 |
|
391 // parse option name |
|
392 option_name = strtok_r(input_string, "=", &input_ptr); |
|
393 while (option_name != NULL) { |
|
394 // parse option value |
|
395 option_value = strtok_r(NULL, " ", &input_ptr); |
|
396 if (option_value == NULL) { |
|
397 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", |
|
398 option_name); |
|
399 res = VPX_CODEC_INVALID_PARAM; |
|
400 break; |
|
401 } |
|
402 if (strcmp("encoding-mode", option_name) == 0) { |
|
403 res = set_option_encoding_mode(svc_ctx, option_value); |
|
404 if (res != VPX_CODEC_OK) break; |
|
405 } else if (strcmp("layers", option_name) == 0) { |
|
406 svc_ctx->spatial_layers = atoi(option_value); |
|
407 } else if (strcmp("scale-factors", option_name) == 0) { |
|
408 res = parse_scale_factors(svc_ctx, option_value); |
|
409 if (res != VPX_CODEC_OK) break; |
|
410 } else if (strcmp("quantizers", option_name) == 0) { |
|
411 res = parse_quantizer_values(svc_ctx, option_value); |
|
412 if (res != VPX_CODEC_OK) break; |
|
413 } else { |
|
414 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); |
|
415 res = VPX_CODEC_INVALID_PARAM; |
|
416 break; |
|
417 } |
|
418 option_name = strtok_r(NULL, "=", &input_ptr); |
|
419 } |
|
420 free(input_string); |
|
421 return res; |
|
422 } |
|
423 |
|
424 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { |
|
425 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
426 if (svc_ctx == NULL || options == NULL || si == NULL) { |
|
427 return VPX_CODEC_INVALID_PARAM; |
|
428 } |
|
429 strncpy(si->options, options, sizeof(si->options)); |
|
430 si->options[sizeof(si->options) - 1] = '\0'; |
|
431 return VPX_CODEC_OK; |
|
432 } |
|
433 |
|
434 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, |
|
435 const char *quantizers) { |
|
436 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
437 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { |
|
438 return VPX_CODEC_INVALID_PARAM; |
|
439 } |
|
440 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); |
|
441 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; |
|
442 return VPX_CODEC_OK; |
|
443 } |
|
444 |
|
445 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, |
|
446 const char *scale_factors) { |
|
447 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
448 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { |
|
449 return VPX_CODEC_INVALID_PARAM; |
|
450 } |
|
451 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); |
|
452 si->scale_factors[sizeof(si->scale_factors) - 1] = '\0'; |
|
453 return VPX_CODEC_OK; |
|
454 } |
|
455 |
|
456 vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, |
|
457 vpx_codec_iface_t *iface, |
|
458 vpx_codec_enc_cfg_t *enc_cfg) { |
|
459 int max_intra_size_pct; |
|
460 vpx_codec_err_t res; |
|
461 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
462 if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || |
|
463 enc_cfg == NULL) { |
|
464 return VPX_CODEC_INVALID_PARAM; |
|
465 } |
|
466 if (si == NULL) return VPX_CODEC_MEM_ERROR; |
|
467 |
|
468 si->codec_ctx = codec_ctx; |
|
469 |
|
470 si->width = enc_cfg->g_w; |
|
471 si->height = enc_cfg->g_h; |
|
472 |
|
473 if (enc_cfg->kf_max_dist < 2) { |
|
474 svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n", |
|
475 enc_cfg->kf_max_dist); |
|
476 return VPX_CODEC_INVALID_PARAM; |
|
477 } |
|
478 si->kf_dist = enc_cfg->kf_max_dist; |
|
479 |
|
480 if (svc_ctx->spatial_layers == 0) |
|
481 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; |
|
482 if (svc_ctx->spatial_layers < 1 || |
|
483 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { |
|
484 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", |
|
485 svc_ctx->spatial_layers); |
|
486 return VPX_CODEC_INVALID_PARAM; |
|
487 } |
|
488 // use SvcInternal value for number of layers to enable forcing single layer |
|
489 // for first frame |
|
490 si->layers = svc_ctx->spatial_layers; |
|
491 |
|
492 res = parse_quantizer_values(svc_ctx, si->quantizers); |
|
493 if (res != VPX_CODEC_OK) return res; |
|
494 |
|
495 res = parse_scale_factors(svc_ctx, si->scale_factors); |
|
496 if (res != VPX_CODEC_OK) return res; |
|
497 |
|
498 // parse aggregate command line options |
|
499 res = parse_options(svc_ctx, si->options); |
|
500 if (res != VPX_CODEC_OK) return res; |
|
501 |
|
502 // modify encoder configuration |
|
503 enc_cfg->ss_number_layers = si->layers; |
|
504 enc_cfg->kf_mode = VPX_KF_DISABLED; |
|
505 enc_cfg->g_pass = VPX_RC_ONE_PASS; |
|
506 // Lag in frames not currently supported |
|
507 enc_cfg->g_lag_in_frames = 0; |
|
508 |
|
509 // TODO(ivanmaltz): determine if these values need to be set explicitly for |
|
510 // svc, or if the normal default/override mechanism can be used |
|
511 enc_cfg->rc_dropframe_thresh = 0; |
|
512 enc_cfg->rc_end_usage = VPX_CBR; |
|
513 enc_cfg->rc_resize_allowed = 0; |
|
514 enc_cfg->rc_min_quantizer = 33; |
|
515 enc_cfg->rc_max_quantizer = 33; |
|
516 enc_cfg->rc_undershoot_pct = 100; |
|
517 enc_cfg->rc_overshoot_pct = 15; |
|
518 enc_cfg->rc_buf_initial_sz = 500; |
|
519 enc_cfg->rc_buf_optimal_sz = 600; |
|
520 enc_cfg->rc_buf_sz = 1000; |
|
521 enc_cfg->g_error_resilient = 1; |
|
522 |
|
523 // Initialize codec |
|
524 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); |
|
525 if (res != VPX_CODEC_OK) { |
|
526 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); |
|
527 return res; |
|
528 } |
|
529 |
|
530 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); |
|
531 vpx_codec_control(codec_ctx, VP8E_SET_CPUUSED, 1); |
|
532 vpx_codec_control(codec_ctx, VP8E_SET_STATIC_THRESHOLD, 1); |
|
533 vpx_codec_control(codec_ctx, VP8E_SET_NOISE_SENSITIVITY, 1); |
|
534 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); |
|
535 |
|
536 max_intra_size_pct = |
|
537 (int)(((double)enc_cfg->rc_buf_optimal_sz * 0.5) * |
|
538 ((double)enc_cfg->g_timebase.den / enc_cfg->g_timebase.num) / 10.0); |
|
539 vpx_codec_control(codec_ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
|
540 max_intra_size_pct); |
|
541 return VPX_CODEC_OK; |
|
542 } |
|
543 |
|
544 // SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h |
|
545 |
|
546 // encoder should reference the last frame |
|
547 #define USE_LAST (1 << 0) |
|
548 |
|
549 // encoder should reference the alt ref frame |
|
550 #define USE_ARF (1 << 1) |
|
551 |
|
552 // encoder should reference the golden frame |
|
553 #define USE_GF (1 << 2) |
|
554 |
|
555 // encoder should copy current frame to the last frame buffer |
|
556 #define UPDATE_LAST (1 << 3) |
|
557 |
|
558 // encoder should copy current frame to the alt ref frame buffer |
|
559 #define UPDATE_ARF (1 << 4) |
|
560 |
|
561 // encoder should copy current frame to the golden frame |
|
562 #define UPDATE_GF (1 << 5) |
|
563 |
|
564 static int map_vp8_flags(int svc_flags) { |
|
565 int flags = 0; |
|
566 |
|
567 if (!(svc_flags & USE_LAST)) flags |= VP8_EFLAG_NO_REF_LAST; |
|
568 if (!(svc_flags & USE_ARF)) flags |= VP8_EFLAG_NO_REF_ARF; |
|
569 if (!(svc_flags & USE_GF)) flags |= VP8_EFLAG_NO_REF_GF; |
|
570 |
|
571 if (svc_flags & UPDATE_LAST) { |
|
572 // last is updated automatically |
|
573 } else { |
|
574 flags |= VP8_EFLAG_NO_UPD_LAST; |
|
575 } |
|
576 if (svc_flags & UPDATE_ARF) { |
|
577 flags |= VP8_EFLAG_FORCE_ARF; |
|
578 } else { |
|
579 flags |= VP8_EFLAG_NO_UPD_ARF; |
|
580 } |
|
581 if (svc_flags & UPDATE_GF) { |
|
582 flags |= VP8_EFLAG_FORCE_GF; |
|
583 } else { |
|
584 flags |= VP8_EFLAG_NO_UPD_GF; |
|
585 } |
|
586 return flags; |
|
587 } |
|
588 |
|
589 /** |
|
590 * Helper to check if the current frame is the first, full resolution dummy. |
|
591 */ |
|
592 static int vpx_svc_dummy_frame(SvcContext *svc_ctx) { |
|
593 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
594 return svc_ctx->first_frame_full_size == 1 && si->encode_frame_count == 0; |
|
595 } |
|
596 |
|
597 static void calculate_enc_frame_flags(SvcContext *svc_ctx) { |
|
598 vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF; |
|
599 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
600 const int is_keyframe = (si->frame_within_gop == 0); |
|
601 |
|
602 // keyframe layer zero is identical for all modes |
|
603 if ((is_keyframe && si->layer == 0) || vpx_svc_dummy_frame(svc_ctx)) { |
|
604 si->enc_frame_flags = VPX_EFLAG_FORCE_KF; |
|
605 return; |
|
606 } |
|
607 |
|
608 switch (svc_ctx->encoding_mode) { |
|
609 case ALT_INTER_LAYER_PREDICTION_IP: |
|
610 if (si->layer == 0) { |
|
611 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
612 } else if (is_keyframe) { |
|
613 if (si->layer == si->layers - 1) { |
|
614 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); |
|
615 } else { |
|
616 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); |
|
617 } |
|
618 } else { |
|
619 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); |
|
620 } |
|
621 break; |
|
622 case INTER_LAYER_PREDICTION_I: |
|
623 if (si->layer == 0) { |
|
624 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
625 } else if (is_keyframe) { |
|
626 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); |
|
627 } else { |
|
628 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
629 } |
|
630 break; |
|
631 case INTER_LAYER_PREDICTION_IP: |
|
632 if (si->layer == 0) { |
|
633 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
634 } else if (is_keyframe) { |
|
635 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); |
|
636 } else { |
|
637 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); |
|
638 } |
|
639 break; |
|
640 case USE_GOLDEN_FRAME: |
|
641 if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) { |
|
642 if (si->layer == 0) { |
|
643 flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST); |
|
644 } else if (is_keyframe) { |
|
645 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); |
|
646 } else { |
|
647 flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST); |
|
648 } |
|
649 } else { |
|
650 if (si->layer == 0) { |
|
651 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
652 } else if (is_keyframe) { |
|
653 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); |
|
654 } else { |
|
655 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
|
656 } |
|
657 } |
|
658 break; |
|
659 default: |
|
660 svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n", |
|
661 svc_ctx->encoding_mode); |
|
662 break; |
|
663 } |
|
664 si->enc_frame_flags = flags; |
|
665 } |
|
666 |
|
667 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx, |
|
668 int layer, |
|
669 unsigned int *width, |
|
670 unsigned int *height) { |
|
671 int w, h, index, num, den; |
|
672 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
673 |
|
674 if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) { |
|
675 return VPX_CODEC_INVALID_PARAM; |
|
676 } |
|
677 if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM; |
|
678 |
|
679 index = layer + VPX_SS_MAX_LAYERS - si->layers; |
|
680 num = si->scaling_factor_num[index]; |
|
681 den = si->scaling_factor_den[index]; |
|
682 if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM; |
|
683 |
|
684 w = si->width * num / den; |
|
685 h = si->height * num / den; |
|
686 |
|
687 // make height and width even to make chrome player happy |
|
688 w += w % 2; |
|
689 h += h % 2; |
|
690 |
|
691 *width = w; |
|
692 *height = h; |
|
693 |
|
694 return VPX_CODEC_OK; |
|
695 } |
|
696 |
|
697 static void set_svc_parameters(SvcContext *svc_ctx, |
|
698 vpx_codec_ctx_t *codec_ctx) { |
|
699 int layer, layer_index; |
|
700 vpx_svc_parameters_t svc_params; |
|
701 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
702 |
|
703 memset(&svc_params, 0, sizeof(svc_params)); |
|
704 svc_params.layer = si->layer; |
|
705 svc_params.flags = si->enc_frame_flags; |
|
706 |
|
707 layer = si->layer; |
|
708 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
|
709 si->frame_within_gop == 0) { |
|
710 // layers 1 & 3 don't exist in this mode, use the higher one |
|
711 if (layer == 0 || layer == 2) { |
|
712 layer += 1; |
|
713 } |
|
714 } |
|
715 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, |
|
716 &svc_params.width, |
|
717 &svc_params.height)) { |
|
718 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); |
|
719 } |
|
720 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; |
|
721 svc_params.min_quantizer = si->quantizer[layer_index]; |
|
722 svc_params.max_quantizer = si->quantizer[layer_index]; |
|
723 svc_params.distance_from_i_frame = si->frame_within_gop; |
|
724 |
|
725 // Use buffer i for layer i LST |
|
726 svc_params.lst_fb_idx = si->layer; |
|
727 |
|
728 // Use buffer i-1 for layer i Alt (Inter-layer prediction) |
|
729 if (si->layer != 0) { |
|
730 const int use_higher_layer = |
|
731 svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
|
732 si->frame_within_gop == 0; |
|
733 svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1; |
|
734 } |
|
735 |
|
736 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) { |
|
737 svc_params.gld_fb_idx = si->layer + 1; |
|
738 } else { |
|
739 if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES) |
|
740 svc_params.gld_fb_idx = svc_params.lst_fb_idx; |
|
741 else |
|
742 svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer; |
|
743 } |
|
744 |
|
745 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n", |
|
746 si->encode_frame_count, si->layer, svc_params.width, |
|
747 svc_params.height, svc_params.min_quantizer); |
|
748 |
|
749 if (svc_params.flags == VPX_EFLAG_FORCE_KF) { |
|
750 svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n"); |
|
751 } else { |
|
752 svc_log( |
|
753 svc_ctx, SVC_LOG_DEBUG, "Using: LST/GLD/ALT [%2d|%2d|%2d]\n", |
|
754 svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx, |
|
755 svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx, |
|
756 svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx); |
|
757 svc_log( |
|
758 svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n", |
|
759 svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx, |
|
760 svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx, |
|
761 svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx); |
|
762 } |
|
763 |
|
764 vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params); |
|
765 } |
|
766 |
|
767 /** |
|
768 * Encode a frame into multiple layers |
|
769 * Create a superframe containing the individual layers |
|
770 */ |
|
771 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, |
|
772 struct vpx_image *rawimg, vpx_codec_pts_t pts, |
|
773 int64_t duration, int deadline) { |
|
774 vpx_codec_err_t res; |
|
775 vpx_codec_iter_t iter; |
|
776 const vpx_codec_cx_pkt_t *cx_pkt; |
|
777 struct LayerData *cx_layer_list = NULL; |
|
778 struct LayerData *layer_data; |
|
779 struct Superframe superframe; |
|
780 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
781 if (svc_ctx == NULL || codec_ctx == NULL || rawimg == NULL || si == NULL) { |
|
782 return VPX_CODEC_INVALID_PARAM; |
|
783 } |
|
784 |
|
785 memset(&superframe, 0, sizeof(superframe)); |
|
786 svc_log_reset(svc_ctx); |
|
787 |
|
788 si->layers = vpx_svc_dummy_frame(svc_ctx) ? 1 : svc_ctx->spatial_layers; |
|
789 if (si->frame_within_gop >= si->kf_dist || |
|
790 si->encode_frame_count == 0 || |
|
791 (si->encode_frame_count == 1 && svc_ctx->first_frame_full_size == 1)) { |
|
792 si->frame_within_gop = 0; |
|
793 } |
|
794 si->is_keyframe = (si->frame_within_gop == 0); |
|
795 si->frame_size = 0; |
|
796 |
|
797 svc_log(svc_ctx, SVC_LOG_DEBUG, |
|
798 "vpx_svc_encode layers: %d, frame_count: %d, frame_within_gop: %d\n", |
|
799 si->layers, si->encode_frame_count, si->frame_within_gop); |
|
800 |
|
801 // encode each layer |
|
802 for (si->layer = 0; si->layer < si->layers; ++si->layer) { |
|
803 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
|
804 si->is_keyframe && (si->layer == 1 || si->layer == 3)) { |
|
805 svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer); |
|
806 continue; |
|
807 } |
|
808 calculate_enc_frame_flags(svc_ctx); |
|
809 |
|
810 if (vpx_svc_dummy_frame(svc_ctx)) { |
|
811 // do not set svc parameters, use normal encode |
|
812 svc_log(svc_ctx, SVC_LOG_DEBUG, "encoding full size first frame\n"); |
|
813 } else { |
|
814 set_svc_parameters(svc_ctx, codec_ctx); |
|
815 } |
|
816 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, |
|
817 si->enc_frame_flags, deadline); |
|
818 if (res != VPX_CODEC_OK) { |
|
819 return res; |
|
820 } |
|
821 // save compressed data |
|
822 iter = NULL; |
|
823 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { |
|
824 switch (cx_pkt->kind) { |
|
825 case VPX_CODEC_CX_FRAME_PKT: { |
|
826 const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz); |
|
827 if (!vpx_svc_dummy_frame(svc_ctx)) { |
|
828 si->bytes_in_layer[si->layer] += frame_pkt_size; |
|
829 svc_log(svc_ctx, SVC_LOG_DEBUG, |
|
830 "SVC frame: %d, layer: %d, size: %u\n", |
|
831 si->encode_frame_count, si->layer, frame_pkt_size); |
|
832 } |
|
833 layer_data = |
|
834 ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size); |
|
835 if (layer_data == NULL) { |
|
836 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n"); |
|
837 return 0; |
|
838 } |
|
839 ld_list_add(&cx_layer_list, layer_data); |
|
840 |
|
841 // save layer size in superframe index |
|
842 superframe.sizes[superframe.count++] = frame_pkt_size; |
|
843 superframe.magnitude |= frame_pkt_size; |
|
844 break; |
|
845 } |
|
846 case VPX_CODEC_PSNR_PKT: { |
|
847 if (!vpx_svc_dummy_frame(svc_ctx)) { |
|
848 svc_log(svc_ctx, SVC_LOG_DEBUG, |
|
849 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " |
|
850 "%2.3f %2.3f %2.3f %2.3f \n", |
|
851 si->encode_frame_count, si->layer, |
|
852 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], |
|
853 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); |
|
854 si->psnr_in_layer[si->layer] += cx_pkt->data.psnr.psnr[0]; |
|
855 } |
|
856 break; |
|
857 } |
|
858 default: { |
|
859 break; |
|
860 } |
|
861 } |
|
862 } |
|
863 } |
|
864 // add superframe index to layer data list |
|
865 if (!vpx_svc_dummy_frame(svc_ctx)) { |
|
866 sf_create_index(&superframe); |
|
867 layer_data = ld_create(superframe.buffer, superframe.index_size); |
|
868 ld_list_add(&cx_layer_list, layer_data); |
|
869 } |
|
870 // get accumulated size of layer data |
|
871 si->frame_size = ld_list_get_buffer_size(cx_layer_list); |
|
872 if (si->frame_size == 0) return VPX_CODEC_ERROR; |
|
873 |
|
874 // all layers encoded, create single buffer with concatenated layers |
|
875 if (si->frame_size > si->buffer_size) { |
|
876 free(si->buffer); |
|
877 si->buffer = malloc(si->frame_size); |
|
878 if (si->buffer == NULL) { |
|
879 ld_list_free(cx_layer_list); |
|
880 return VPX_CODEC_MEM_ERROR; |
|
881 } |
|
882 si->buffer_size = si->frame_size; |
|
883 } |
|
884 // copy layer data into packet |
|
885 ld_list_copy_to_buffer(cx_layer_list, si->buffer); |
|
886 |
|
887 ld_list_free(cx_layer_list); |
|
888 |
|
889 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, pts: %d\n", |
|
890 si->encode_frame_count, si->is_keyframe, (int)si->frame_size, |
|
891 (int)pts); |
|
892 ++si->frame_within_gop; |
|
893 ++si->encode_frame_count; |
|
894 |
|
895 return VPX_CODEC_OK; |
|
896 } |
|
897 |
|
898 const char *vpx_svc_get_message(const SvcContext *svc_ctx) { |
|
899 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
900 if (svc_ctx == NULL || si == NULL) return NULL; |
|
901 return si->message_buffer; |
|
902 } |
|
903 |
|
904 void *vpx_svc_get_buffer(const SvcContext *svc_ctx) { |
|
905 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
906 if (svc_ctx == NULL || si == NULL) return NULL; |
|
907 return si->buffer; |
|
908 } |
|
909 |
|
910 size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) { |
|
911 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
912 if (svc_ctx == NULL || si == NULL) return 0; |
|
913 return si->frame_size; |
|
914 } |
|
915 |
|
916 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) { |
|
917 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
918 if (svc_ctx == NULL || si == NULL) return 0; |
|
919 return si->encode_frame_count; |
|
920 } |
|
921 |
|
922 int vpx_svc_is_keyframe(const SvcContext *svc_ctx) { |
|
923 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
|
924 if (svc_ctx == NULL || si == NULL) return 0; |
|
925 return si->is_keyframe; |
|
926 } |
|
927 |
|
928 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { |
|
929 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
930 if (svc_ctx == NULL || si == NULL) return; |
|
931 si->frame_within_gop = 0; |
|
932 } |
|
933 |
|
934 // dump accumulated statistics and reset accumulated values |
|
935 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { |
|
936 int number_of_frames, number_of_keyframes, encode_frame_count; |
|
937 int i; |
|
938 uint32_t bytes_total = 0; |
|
939 SvcInternal *const si = get_svc_internal(svc_ctx); |
|
940 if (svc_ctx == NULL || si == NULL) return NULL; |
|
941 |
|
942 svc_log_reset(svc_ctx); |
|
943 |
|
944 encode_frame_count = si->encode_frame_count; |
|
945 if (svc_ctx->first_frame_full_size) encode_frame_count--; |
|
946 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); |
|
947 |
|
948 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); |
|
949 number_of_keyframes = encode_frame_count / si->kf_dist + 1; |
|
950 for (i = 0; i < si->layers; ++i) { |
|
951 number_of_frames = encode_frame_count; |
|
952 |
|
953 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && |
|
954 (i == 1 || i == 3)) { |
|
955 number_of_frames -= number_of_keyframes; |
|
956 } |
|
957 svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i, |
|
958 (double)si->psnr_in_layer[i] / number_of_frames, |
|
959 si->bytes_in_layer[i]); |
|
960 bytes_total += si->bytes_in_layer[i]; |
|
961 si->psnr_in_layer[i] = 0; |
|
962 si->bytes_in_layer[i] = 0; |
|
963 } |
|
964 |
|
965 // only display statistics once |
|
966 si->encode_frame_count = 0; |
|
967 |
|
968 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); |
|
969 return vpx_svc_get_message(svc_ctx); |
|
970 } |
|
971 |
|
972 void vpx_svc_release(SvcContext *svc_ctx) { |
|
973 SvcInternal *si; |
|
974 if (svc_ctx == NULL) return; |
|
975 // do not use get_svc_internal as it will unnecessarily allocate an |
|
976 // SvcInternal if it was not already allocated |
|
977 si = (SvcInternal *)svc_ctx->internal; |
|
978 if (si != NULL) { |
|
979 free(si->buffer); |
|
980 free(si); |
|
981 svc_ctx->internal = NULL; |
|
982 } |
|
983 } |