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