2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
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.
13 * VP9 SVC encoding support via libvpx
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"
26 #if defined(__MINGW32__) && !defined(MINGW_HAS_SECURE_API)
27 #define strtok_r strtok_s
28 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
29 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
33 #define strdup _strdup
34 #define strtok_r strtok_s
37 #define SVC_REFERENCE_FRAMES 8
38 #define SUPERFRAME_SLOTS (8)
39 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
40 #define OPTION_BUFFER_SIZE 256
42 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27";
43 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16";
45 typedef struct SvcInternal {
46 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options
47 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers
48 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors
50 // values extracted from option, quantizers
51 int scaling_factor_num[VPX_SS_MAX_LAYERS];
52 int scaling_factor_den[VPX_SS_MAX_LAYERS];
53 int quantizer[VPX_SS_MAX_LAYERS];
55 // accumulated statistics
56 double psnr_in_layer[VPX_SS_MAX_LAYERS];
57 uint32_t bytes_in_layer[VPX_SS_MAX_LAYERS];
59 // codec encoding values
60 int width; // width of highest layer
61 int height; // height of highest layer
62 int kf_dist; // distance between keyframes
65 int encode_frame_count;
67 vpx_enc_frame_flags_t enc_frame_flags;
76 char message_buffer[2048];
77 vpx_codec_ctx_t *codec_ctx;
80 // Superframe is used to generate an index of individual frames (i.e., layers)
83 uint32_t sizes[SUPERFRAME_SLOTS];
85 uint8_t buffer[SUPERFRAME_BUFFER_SIZE];
89 // One encoded frame layer
91 void *buf; // compressed data buffer
92 size_t size; // length of compressed data
93 struct LayerData *next;
96 // create LayerData from encoder output
97 static struct LayerData *ld_create(void *buf, size_t size) {
98 struct LayerData *const layer_data =
99 (struct LayerData *)malloc(sizeof(*layer_data));
100 if (layer_data == NULL) {
103 layer_data->buf = malloc(size);
104 if (layer_data->buf == NULL) {
108 memcpy(layer_data->buf, buf, size);
109 layer_data->size = size;
114 static void ld_free(struct LayerData *layer_data) {
116 if (layer_data->buf) {
117 free(layer_data->buf);
118 layer_data->buf = NULL;
124 // add layer data to list
125 static void ld_list_add(struct LayerData **list, struct LayerData *layer_data) {
126 struct LayerData **p = list;
128 while (*p != NULL) p = &(*p)->next;
130 layer_data->next = NULL;
133 // get accumulated size of layer data
134 static size_t ld_list_get_buffer_size(struct LayerData *list) {
138 for (p = list; p != NULL; p = p->next) {
144 // copy layer data to buffer
145 static void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) {
148 for (p = list; p != NULL; p = p->next) {
150 memcpy(buffer, p->buf, p->size);
155 // free layer data list
156 static void ld_list_free(struct LayerData *list) {
157 struct LayerData *p = list;
166 static void sf_create_index(struct Superframe *sf) {
167 uint8_t marker = 0xc0;
172 if (sf->count == 0 || sf->count >= 8) return;
174 // Add the number of frames to the marker byte
175 marker |= sf->count - 1;
177 // Choose the magnitude
178 for (mag = 0, mask = 0xff; mag < 4; ++mag) {
179 if (sf->magnitude < mask) break;
186 sf->index_size = 2 + (mag + 1) * sf->count;
190 for (i = 0; i < sf->count; ++i) {
191 int this_sz = sf->sizes[i];
194 for (j = 0; j <= mag; ++j) {
195 *bufp++ = this_sz & 0xff;
202 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
203 if (svc_ctx == NULL) return NULL;
204 if (svc_ctx->internal == NULL) {
205 SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si));
207 memset(si, 0, sizeof(*si));
209 svc_ctx->internal = si;
211 return (SvcInternal *)svc_ctx->internal;
214 static const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
215 if (svc_ctx == NULL) return NULL;
216 return (const SvcInternal *)svc_ctx->internal;
219 static void svc_log_reset(SvcContext *svc_ctx) {
220 SvcInternal *const si = (SvcInternal *)svc_ctx->internal;
221 si->message_buffer[0] = '\0';
224 static int svc_log(SvcContext *svc_ctx, int level, const char *fmt, ...) {
228 SvcInternal *const si = get_svc_internal(svc_ctx);
230 if (level > svc_ctx->log_level) {
235 retval = vsnprintf(buf, sizeof(buf), fmt, ap);
238 if (svc_ctx->log_print) {
241 strncat(si->message_buffer, buf,
242 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
245 if (level == SVC_LOG_ERROR) {
246 si->codec_ctx->err_detail = si->message_buffer;
251 static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx,
252 const char *value_str) {
253 if (strcmp(value_str, "i") == 0) {
254 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I;
255 } else if (strcmp(value_str, "alt-ip") == 0) {
256 svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP;
257 } else if (strcmp(value_str, "ip") == 0) {
258 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP;
259 } else if (strcmp(value_str, "gf") == 0) {
260 svc_ctx->encoding_mode = USE_GOLDEN_FRAME;
262 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str);
263 return VPX_CODEC_INVALID_PARAM;
268 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
269 const char *quantizer_values) {
272 const char *delim = ",";
276 vpx_codec_err_t res = VPX_CODEC_OK;
277 SvcInternal *const si = get_svc_internal(svc_ctx);
279 if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
280 input_string = strdup(DEFAULT_QUANTIZER_VALUES);
282 input_string = strdup(quantizer_values);
285 token = strtok_r(input_string, delim, &save_ptr);
286 for (i = 0; i < svc_ctx->spatial_layers; ++i) {
289 if (q <= 0 || q > 100) {
290 svc_log(svc_ctx, SVC_LOG_ERROR,
291 "svc-quantizer-values: invalid value %s\n", token);
292 res = VPX_CODEC_INVALID_PARAM;
295 token = strtok_r(NULL, delim, &save_ptr);
300 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
302 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
303 svc_log(svc_ctx, SVC_LOG_ERROR,
304 "svc: quantizers: %d values required, but only %d specified\n",
305 svc_ctx->spatial_layers, found);
306 res = VPX_CODEC_INVALID_PARAM;
312 static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) {
313 svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n",
317 static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx,
318 const char *scale_factors) {
321 const char *delim = ",";
326 vpx_codec_err_t res = VPX_CODEC_OK;
327 SvcInternal *const si = get_svc_internal(svc_ctx);
329 if (scale_factors == NULL || strlen(scale_factors) == 0) {
330 input_string = strdup(DEFAULT_SCALE_FACTORS);
332 input_string = strdup(scale_factors);
334 token = strtok_r(input_string, delim, &save_ptr);
335 for (i = 0; i < svc_ctx->spatial_layers; ++i) {
338 num = strtol(token, &token, 10);
340 log_invalid_scale_factor(svc_ctx, token);
341 res = VPX_CODEC_INVALID_PARAM;
344 if (*token++ != '/') {
345 log_invalid_scale_factor(svc_ctx, token);
346 res = VPX_CODEC_INVALID_PARAM;
349 den = strtol(token, &token, 10);
351 log_invalid_scale_factor(svc_ctx, token);
352 res = VPX_CODEC_INVALID_PARAM;
355 token = strtok_r(NULL, delim, &save_ptr);
358 si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
360 si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
363 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
364 svc_log(svc_ctx, SVC_LOG_ERROR,
365 "svc: scale-factors: %d values required, but only %d specified\n",
366 svc_ctx->spatial_layers, found);
367 res = VPX_CODEC_INVALID_PARAM;
374 * Parse SVC encoding options
375 * Format: encoding-mode=<svc_mode>,layers=<layer_count>
376 * scale-factors=<n1>/<d1>,<n2>/<d2>,...
377 * quantizers=<q1>,<q2>,...
378 * svc_mode = [i|ip|alt_ip|gf]
380 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
385 vpx_codec_err_t res = VPX_CODEC_OK;
387 if (options == NULL) return VPX_CODEC_OK;
388 input_string = strdup(options);
391 option_name = strtok_r(input_string, "=", &input_ptr);
392 while (option_name != NULL) {
393 // parse option value
394 option_value = strtok_r(NULL, " ", &input_ptr);
395 if (option_value == NULL) {
396 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
398 res = VPX_CODEC_INVALID_PARAM;
401 if (strcmp("encoding-mode", option_name) == 0) {
402 res = set_option_encoding_mode(svc_ctx, option_value);
403 if (res != VPX_CODEC_OK) break;
404 } else if (strcmp("layers", option_name) == 0) {
405 svc_ctx->spatial_layers = atoi(option_value);
406 } else if (strcmp("scale-factors", option_name) == 0) {
407 res = parse_scale_factors(svc_ctx, option_value);
408 if (res != VPX_CODEC_OK) break;
409 } else if (strcmp("quantizers", option_name) == 0) {
410 res = parse_quantizer_values(svc_ctx, option_value);
411 if (res != VPX_CODEC_OK) break;
413 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
414 res = VPX_CODEC_INVALID_PARAM;
417 option_name = strtok_r(NULL, "=", &input_ptr);
423 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
424 SvcInternal *const si = get_svc_internal(svc_ctx);
425 if (svc_ctx == NULL || options == NULL || si == NULL) {
426 return VPX_CODEC_INVALID_PARAM;
428 strncpy(si->options, options, sizeof(si->options));
429 si->options[sizeof(si->options) - 1] = '\0';
433 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
434 const char *quantizers) {
435 SvcInternal *const si = get_svc_internal(svc_ctx);
436 if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
437 return VPX_CODEC_INVALID_PARAM;
439 strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
440 si->quantizers[sizeof(si->quantizers) - 1] = '\0';
444 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
445 const char *scale_factors) {
446 SvcInternal *const si = get_svc_internal(svc_ctx);
447 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) {
448 return VPX_CODEC_INVALID_PARAM;
450 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors));
451 si->scale_factors[sizeof(si->scale_factors) - 1] = '\0';
455 vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
456 vpx_codec_iface_t *iface,
457 vpx_codec_enc_cfg_t *enc_cfg) {
458 int max_intra_size_pct;
460 SvcInternal *const si = get_svc_internal(svc_ctx);
461 if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
463 return VPX_CODEC_INVALID_PARAM;
465 if (si == NULL) return VPX_CODEC_MEM_ERROR;
467 si->codec_ctx = codec_ctx;
469 si->width = enc_cfg->g_w;
470 si->height = enc_cfg->g_h;
472 if (enc_cfg->kf_max_dist < 2) {
473 svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
474 enc_cfg->kf_max_dist);
475 return VPX_CODEC_INVALID_PARAM;
477 si->kf_dist = enc_cfg->kf_max_dist;
479 if (svc_ctx->spatial_layers == 0)
480 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
481 if (svc_ctx->spatial_layers < 1 ||
482 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
483 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
484 svc_ctx->spatial_layers);
485 return VPX_CODEC_INVALID_PARAM;
487 // use SvcInternal value for number of layers to enable forcing single layer
489 si->layers = svc_ctx->spatial_layers;
491 res = parse_quantizer_values(svc_ctx, si->quantizers);
492 if (res != VPX_CODEC_OK) return res;
494 res = parse_scale_factors(svc_ctx, si->scale_factors);
495 if (res != VPX_CODEC_OK) return res;
497 // parse aggregate command line options
498 res = parse_options(svc_ctx, si->options);
499 if (res != VPX_CODEC_OK) return res;
501 // modify encoder configuration
502 enc_cfg->ss_number_layers = si->layers;
503 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder.
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;
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;
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");
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);
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,
544 // SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h
546 // encoder should reference the last frame
547 #define USE_LAST (1 << 0)
549 // encoder should reference the alt ref frame
550 #define USE_ARF (1 << 1)
552 // encoder should reference the golden frame
553 #define USE_GF (1 << 2)
555 // encoder should copy current frame to the last frame buffer
556 #define UPDATE_LAST (1 << 3)
558 // encoder should copy current frame to the alt ref frame buffer
559 #define UPDATE_ARF (1 << 4)
561 // encoder should copy current frame to the golden frame
562 #define UPDATE_GF (1 << 5)
564 static int map_vp8_flags(int svc_flags) {
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;
571 if (svc_flags & UPDATE_LAST) {
572 // last is updated automatically
574 flags |= VP8_EFLAG_NO_UPD_LAST;
576 if (svc_flags & UPDATE_ARF) {
577 flags |= VP8_EFLAG_FORCE_ARF;
579 flags |= VP8_EFLAG_NO_UPD_ARF;
581 if (svc_flags & UPDATE_GF) {
582 flags |= VP8_EFLAG_FORCE_GF;
584 flags |= VP8_EFLAG_NO_UPD_GF;
589 static void calculate_enc_frame_flags(SvcContext *svc_ctx) {
590 vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
591 SvcInternal *const si = get_svc_internal(svc_ctx);
592 const int is_keyframe = (si->frame_within_gop == 0);
594 // keyframe layer zero is identical for all modes
595 if (is_keyframe && si->layer == 0) {
596 si->enc_frame_flags = VPX_EFLAG_FORCE_KF;
600 switch (svc_ctx->encoding_mode) {
601 case ALT_INTER_LAYER_PREDICTION_IP:
602 if (si->layer == 0) {
603 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
604 } else if (is_keyframe) {
605 if (si->layer == si->layers - 1) {
606 flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
608 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
611 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
614 case INTER_LAYER_PREDICTION_I:
615 if (si->layer == 0) {
616 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
617 } else if (is_keyframe) {
618 flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
620 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
623 case INTER_LAYER_PREDICTION_IP:
624 if (si->layer == 0) {
625 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
626 } else if (is_keyframe) {
627 flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
629 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
632 case USE_GOLDEN_FRAME:
633 if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) {
634 if (si->layer == 0) {
635 flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST);
636 } else if (is_keyframe) {
637 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
639 flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST);
642 if (si->layer == 0) {
643 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
644 } else if (is_keyframe) {
645 flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
647 flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
652 svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n",
653 svc_ctx->encoding_mode);
656 si->enc_frame_flags = flags;
659 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
662 unsigned int *height) {
663 int w, h, index, num, den;
664 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
666 if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) {
667 return VPX_CODEC_INVALID_PARAM;
669 if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM;
671 index = layer + VPX_SS_MAX_LAYERS - si->layers;
672 num = si->scaling_factor_num[index];
673 den = si->scaling_factor_den[index];
674 if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM;
676 w = si->width * num / den;
677 h = si->height * num / den;
679 // make height and width even to make chrome player happy
689 static void set_svc_parameters(SvcContext *svc_ctx,
690 vpx_codec_ctx_t *codec_ctx) {
691 int layer, layer_index;
692 vpx_svc_parameters_t svc_params;
693 SvcInternal *const si = get_svc_internal(svc_ctx);
695 memset(&svc_params, 0, sizeof(svc_params));
696 svc_params.temporal_layer = 0;
697 svc_params.spatial_layer = si->layer;
698 svc_params.flags = si->enc_frame_flags;
701 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
702 si->frame_within_gop == 0) {
703 // layers 1 & 3 don't exist in this mode, use the higher one
704 if (layer == 0 || layer == 2) {
708 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
710 &svc_params.height)) {
711 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
713 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
714 svc_params.min_quantizer = si->quantizer[layer_index];
715 svc_params.max_quantizer = si->quantizer[layer_index];
716 svc_params.distance_from_i_frame = si->frame_within_gop;
718 // Use buffer i for layer i LST
719 svc_params.lst_fb_idx = si->layer;
721 // Use buffer i-1 for layer i Alt (Inter-layer prediction)
722 if (si->layer != 0) {
723 const int use_higher_layer =
724 svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
725 si->frame_within_gop == 0;
726 svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1;
729 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) {
730 svc_params.gld_fb_idx = si->layer + 1;
732 if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES)
733 svc_params.gld_fb_idx = svc_params.lst_fb_idx;
735 svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer;
738 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
739 si->encode_frame_count, si->layer, svc_params.width,
740 svc_params.height, svc_params.min_quantizer);
742 if (svc_params.flags == VPX_EFLAG_FORCE_KF) {
743 svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n");
746 svc_ctx, SVC_LOG_DEBUG, "Using: LST/GLD/ALT [%2d|%2d|%2d]\n",
747 svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx,
748 svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx,
749 svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx);
751 svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n",
752 svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx,
753 svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx,
754 svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx);
757 vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
761 * Encode a frame into multiple layers
762 * Create a superframe containing the individual layers
764 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
765 struct vpx_image *rawimg, vpx_codec_pts_t pts,
766 int64_t duration, int deadline) {
768 vpx_codec_iter_t iter;
769 const vpx_codec_cx_pkt_t *cx_pkt;
770 struct LayerData *cx_layer_list = NULL;
771 struct LayerData *layer_data;
772 struct Superframe superframe;
773 SvcInternal *const si = get_svc_internal(svc_ctx);
774 if (svc_ctx == NULL || codec_ctx == NULL || rawimg == NULL || si == NULL) {
775 return VPX_CODEC_INVALID_PARAM;
778 memset(&superframe, 0, sizeof(superframe));
779 svc_log_reset(svc_ctx);
781 si->layers = svc_ctx->spatial_layers;
782 if (si->frame_within_gop >= si->kf_dist ||
783 si->encode_frame_count == 0) {
784 si->frame_within_gop = 0;
786 si->is_keyframe = (si->frame_within_gop == 0);
789 svc_log(svc_ctx, SVC_LOG_DEBUG,
790 "vpx_svc_encode layers: %d, frame_count: %d, frame_within_gop: %d\n",
791 si->layers, si->encode_frame_count, si->frame_within_gop);
794 for (si->layer = 0; si->layer < si->layers; ++si->layer) {
795 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
796 si->is_keyframe && (si->layer == 1 || si->layer == 3)) {
797 svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer);
800 calculate_enc_frame_flags(svc_ctx);
802 set_svc_parameters(svc_ctx, codec_ctx);
804 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration,
805 si->enc_frame_flags, deadline);
806 if (res != VPX_CODEC_OK) {
809 // save compressed data
811 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
812 switch (cx_pkt->kind) {
813 case VPX_CODEC_CX_FRAME_PKT: {
814 const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz);
815 si->bytes_in_layer[si->layer] += frame_pkt_size;
816 svc_log(svc_ctx, SVC_LOG_DEBUG,
817 "SVC frame: %d, layer: %d, size: %u\n",
818 si->encode_frame_count, si->layer, frame_pkt_size);
820 ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size);
821 if (layer_data == NULL) {
822 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n");
825 ld_list_add(&cx_layer_list, layer_data);
827 // save layer size in superframe index
828 superframe.sizes[superframe.count++] = frame_pkt_size;
829 superframe.magnitude |= frame_pkt_size;
832 case VPX_CODEC_PSNR_PKT: {
833 svc_log(svc_ctx, SVC_LOG_DEBUG,
834 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
835 "%2.3f %2.3f %2.3f %2.3f \n",
836 si->encode_frame_count, si->layer,
837 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
838 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]);
839 si->psnr_in_layer[si->layer] += cx_pkt->data.psnr.psnr[0];
848 // add superframe index to layer data list
849 sf_create_index(&superframe);
850 layer_data = ld_create(superframe.buffer, superframe.index_size);
851 ld_list_add(&cx_layer_list, layer_data);
853 // get accumulated size of layer data
854 si->frame_size = ld_list_get_buffer_size(cx_layer_list);
855 if (si->frame_size == 0) return VPX_CODEC_ERROR;
857 // all layers encoded, create single buffer with concatenated layers
858 if (si->frame_size > si->buffer_size) {
860 si->buffer = malloc(si->frame_size);
861 if (si->buffer == NULL) {
862 ld_list_free(cx_layer_list);
863 return VPX_CODEC_MEM_ERROR;
865 si->buffer_size = si->frame_size;
867 // copy layer data into packet
868 ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)si->buffer);
870 ld_list_free(cx_layer_list);
872 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, pts: %d\n",
873 si->encode_frame_count, si->is_keyframe, (int)si->frame_size,
875 ++si->frame_within_gop;
876 ++si->encode_frame_count;
881 const char *vpx_svc_get_message(const SvcContext *svc_ctx) {
882 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
883 if (svc_ctx == NULL || si == NULL) return NULL;
884 return si->message_buffer;
887 void *vpx_svc_get_buffer(const SvcContext *svc_ctx) {
888 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
889 if (svc_ctx == NULL || si == NULL) return NULL;
893 size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) {
894 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
895 if (svc_ctx == NULL || si == NULL) return 0;
896 return si->frame_size;
899 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
900 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
901 if (svc_ctx == NULL || si == NULL) return 0;
902 return si->encode_frame_count;
905 int vpx_svc_is_keyframe(const SvcContext *svc_ctx) {
906 const SvcInternal *const si = get_const_svc_internal(svc_ctx);
907 if (svc_ctx == NULL || si == NULL) return 0;
908 return si->is_keyframe;
911 void vpx_svc_set_keyframe(SvcContext *svc_ctx) {
912 SvcInternal *const si = get_svc_internal(svc_ctx);
913 if (svc_ctx == NULL || si == NULL) return;
914 si->frame_within_gop = 0;
917 // dump accumulated statistics and reset accumulated values
918 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
919 int number_of_frames, number_of_keyframes, encode_frame_count;
921 uint32_t bytes_total = 0;
922 SvcInternal *const si = get_svc_internal(svc_ctx);
923 if (svc_ctx == NULL || si == NULL) return NULL;
925 svc_log_reset(svc_ctx);
927 encode_frame_count = si->encode_frame_count;
928 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
930 svc_log(svc_ctx, SVC_LOG_INFO, "\n");
931 number_of_keyframes = encode_frame_count / si->kf_dist + 1;
932 for (i = 0; i < si->layers; ++i) {
933 number_of_frames = encode_frame_count;
935 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
936 (i == 1 || i == 3)) {
937 number_of_frames -= number_of_keyframes;
939 svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d PSNR=[%2.3f], Bytes=[%u]\n", i,
940 (double)si->psnr_in_layer[i] / number_of_frames,
941 si->bytes_in_layer[i]);
942 bytes_total += si->bytes_in_layer[i];
943 si->psnr_in_layer[i] = 0;
944 si->bytes_in_layer[i] = 0;
947 // only display statistics once
948 si->encode_frame_count = 0;
950 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
951 return vpx_svc_get_message(svc_ctx);
954 void vpx_svc_release(SvcContext *svc_ctx) {
956 if (svc_ctx == NULL) return;
957 // do not use get_svc_internal as it will unnecessarily allocate an
958 // SvcInternal if it was not already allocated
959 si = (SvcInternal *)svc_ctx->internal;
963 svc_ctx->internal = NULL;