]> granicus.if.org Git - libvpx/blob - vpx/src/svc_encodeframe.c
ed33fb2a50e267f381512c65227e4669ca1836c0
[libvpx] / vpx / src / svc_encodeframe.c
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 <limits.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #define VPX_DISABLE_CTRL_TYPECHECKS 1
24 #include "./vpx_config.h"
25 #include "vpx/svc_context.h"
26 #include "vpx/vp8cx.h"
27 #include "vpx/vpx_encoder.h"
28 #include "vpx_mem/vpx_mem.h"
29 #include "vp9/common/vp9_onyxc_int.h"
30
31 #ifdef __MINGW32__
32 #define strtok_r strtok_s
33 #ifndef MINGW_HAS_SECURE_API
34 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
35 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
36 #endif  /* MINGW_HAS_SECURE_API */
37 #endif  /* __MINGW32__ */
38
39 #ifdef _MSC_VER
40 #define strdup _strdup
41 #define strtok_r strtok_s
42 #endif
43
44 #define SVC_REFERENCE_FRAMES 8
45 #define SUPERFRAME_SLOTS (8)
46 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
47 #define OPTION_BUFFER_SIZE 256
48 #define COMPONENTS 4  // psnr & sse statistics maintained for total, y, u, v
49
50 static const int DEFAULT_QUANTIZER_VALUES[VPX_SS_MAX_LAYERS] = {
51   60, 53, 39, 33, 27
52 };
53
54 static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = {
55   4, 5, 7, 11, 16
56 };
57
58 static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = {
59   16, 16, 16, 16, 16
60 };
61
62 typedef enum {
63   QUANTIZER = 0,
64   BITRATE,
65   SCALE_FACTOR,
66   AUTO_ALT_REF,
67   ALL_OPTION_TYPES
68 } LAYER_OPTION_TYPE;
69
70 static const int option_max_values[ALL_OPTION_TYPES] = {
71   63, INT_MAX, INT_MAX, 1
72 };
73
74 static const int option_min_values[ALL_OPTION_TYPES] = {
75   0, 0, 1, 0
76 };
77
78 // One encoded frame
79 typedef struct FrameData {
80   void                     *buf;    // compressed data buffer
81   size_t                    size;  // length of compressed data
82   vpx_codec_frame_flags_t   flags;    /**< flags for this frame */
83   struct FrameData         *next;
84 } FrameData;
85
86 typedef struct SvcInternal {
87   char options[OPTION_BUFFER_SIZE];        // set by vpx_svc_set_options
88   char quantizers[OPTION_BUFFER_SIZE];     // set by vpx_svc_set_quantizers
89   char scale_factors[OPTION_BUFFER_SIZE];  // set by vpx_svc_set_scale_factors
90
91   // values extracted from option, quantizers
92   int scaling_factor_num[VPX_SS_MAX_LAYERS];
93   int scaling_factor_den[VPX_SS_MAX_LAYERS];
94   int quantizer[VPX_SS_MAX_LAYERS];
95   int enable_auto_alt_ref[VPX_SS_MAX_LAYERS];
96   int bitrates[VPX_SS_MAX_LAYERS];
97
98   // accumulated statistics
99   double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS];   // total/Y/U/V
100   uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS];
101   uint32_t bytes_sum[VPX_SS_MAX_LAYERS];
102
103   // codec encoding values
104   int width;    // width of highest layer
105   int height;   // height of highest layer
106   int kf_dist;  // distance between keyframes
107
108   // state variables
109   int encode_frame_count;
110   int frame_received;
111   int frame_within_gop;
112   int layers;
113   int layer;
114   int is_keyframe;
115   int use_multiple_frame_contexts;
116
117   char message_buffer[2048];
118   vpx_codec_ctx_t *codec_ctx;
119 } SvcInternal;
120
121 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
122   if (svc_ctx == NULL) return NULL;
123   if (svc_ctx->internal == NULL) {
124     SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si));
125     if (si != NULL) {
126       memset(si, 0, sizeof(*si));
127     }
128     svc_ctx->internal = si;
129   }
130   return (SvcInternal *)svc_ctx->internal;
131 }
132
133 static const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
134   if (svc_ctx == NULL) return NULL;
135   return (const SvcInternal *)svc_ctx->internal;
136 }
137
138 static void svc_log_reset(SvcContext *svc_ctx) {
139   SvcInternal *const si = (SvcInternal *)svc_ctx->internal;
140   si->message_buffer[0] = '\0';
141 }
142
143 static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level,
144                    const char *fmt, ...) {
145   char buf[512];
146   int retval = 0;
147   va_list ap;
148   SvcInternal *const si = get_svc_internal(svc_ctx);
149
150   if (level > svc_ctx->log_level) {
151     return retval;
152   }
153
154   va_start(ap, fmt);
155   retval = vsnprintf(buf, sizeof(buf), fmt, ap);
156   va_end(ap);
157
158   if (svc_ctx->log_print) {
159     printf("%s", buf);
160   } else {
161     strncat(si->message_buffer, buf,
162             sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
163   }
164
165   if (level == SVC_LOG_ERROR) {
166     si->codec_ctx->err_detail = si->message_buffer;
167   }
168   return retval;
169 }
170
171 static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type,
172                                       char *input,
173                                       int *value0,
174                                       int *value1) {
175   if (type == SCALE_FACTOR) {
176     *value0 = strtol(input, &input, 10);
177     if (*input++ != '/')
178       return VPX_CODEC_INVALID_PARAM;
179     *value1 = strtol(input, &input, 10);
180
181     if (*value0 < option_min_values[SCALE_FACTOR] ||
182         *value1 < option_min_values[SCALE_FACTOR] ||
183         *value0 > option_max_values[SCALE_FACTOR] ||
184         *value1 > option_max_values[SCALE_FACTOR])
185       return VPX_CODEC_INVALID_PARAM;
186   } else {
187     *value0 = atoi(input);
188     if (*value0 < option_min_values[type] ||
189         *value0 > option_max_values[type])
190       return VPX_CODEC_INVALID_PARAM;
191   }
192   return VPX_CODEC_OK;
193 }
194
195 static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
196                                                        LAYER_OPTION_TYPE type,
197                                                        const char *input,
198                                                        int *option0,
199                                                        int *option1) {
200   int i;
201   vpx_codec_err_t res = VPX_CODEC_OK;
202   char *input_string;
203   char *token;
204   const char *delim = ",";
205   char *save_ptr;
206
207   if (input == NULL || option0 == NULL ||
208       (option1 == NULL && type == SCALE_FACTOR))
209     return VPX_CODEC_INVALID_PARAM;
210
211   input_string = strdup(input);
212   token = strtok_r(input_string, delim, &save_ptr);
213   for (i = 0; i < svc_ctx->spatial_layers; ++i) {
214     if (token != NULL) {
215       res = extract_option(type, token, option0 + i, option1 + i);
216       if (res != VPX_CODEC_OK)
217         break;
218       token = strtok_r(NULL, delim, &save_ptr);
219     } else {
220       break;
221     }
222   }
223   if (res == VPX_CODEC_OK && i != svc_ctx->spatial_layers) {
224     svc_log(svc_ctx, SVC_LOG_ERROR,
225             "svc: layer params type: %d    %d values required, "
226             "but only %d specified\n", type, svc_ctx->spatial_layers, i);
227     res = VPX_CODEC_INVALID_PARAM;
228   }
229   free(input_string);
230   return res;
231 }
232
233 /**
234  * Parse SVC encoding options
235  * Format: encoding-mode=<svc_mode>,layers=<layer_count>
236  *         scale-factors=<n1>/<d1>,<n2>/<d2>,...
237  *         quantizers=<q1>,<q2>,...
238  * svc_mode = [i|ip|alt_ip|gf]
239  */
240 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
241   char *input_string;
242   char *option_name;
243   char *option_value;
244   char *input_ptr;
245   SvcInternal *const si = get_svc_internal(svc_ctx);
246   vpx_codec_err_t res = VPX_CODEC_OK;
247   int i, alt_ref_enabled = 0;
248
249   if (options == NULL) return VPX_CODEC_OK;
250   input_string = strdup(options);
251
252   // parse option name
253   option_name = strtok_r(input_string, "=", &input_ptr);
254   while (option_name != NULL) {
255     // parse option value
256     option_value = strtok_r(NULL, " ", &input_ptr);
257     if (option_value == NULL) {
258       svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
259               option_name);
260       res = VPX_CODEC_INVALID_PARAM;
261       break;
262     }
263     if (strcmp("spatial-layers", option_name) == 0) {
264       svc_ctx->spatial_layers = atoi(option_value);
265     } else if (strcmp("temporal-layers", option_name) == 0) {
266       svc_ctx->temporal_layers = atoi(option_value);
267     } else if (strcmp("scale-factors", option_name) == 0) {
268       res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
269                                             si->scaling_factor_num,
270                                             si->scaling_factor_den);
271       if (res != VPX_CODEC_OK) break;
272     } else if (strcmp("quantizers", option_name) == 0) {
273       res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
274                                             si->quantizer, NULL);
275       if (res != VPX_CODEC_OK) break;
276     } else if (strcmp("auto-alt-refs", option_name) == 0) {
277       res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
278                                             si->enable_auto_alt_ref, NULL);
279       if (res != VPX_CODEC_OK) break;
280     } else if (strcmp("bitrates", option_name) == 0) {
281       res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value,
282                                             si->bitrates, NULL);
283       if (res != VPX_CODEC_OK) break;
284     } else if (strcmp("multi-frame-contexts", option_name) == 0) {
285       si->use_multiple_frame_contexts = atoi(option_value);
286     } else {
287       svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
288       res = VPX_CODEC_INVALID_PARAM;
289       break;
290     }
291     option_name = strtok_r(NULL, "=", &input_ptr);
292   }
293   free(input_string);
294
295   if (si->use_multiple_frame_contexts &&
296       (svc_ctx->spatial_layers > 3 ||
297        svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
298     res = VPX_CODEC_INVALID_PARAM;
299
300   for (i = 0; i < svc_ctx->spatial_layers; ++i)
301     alt_ref_enabled += si->enable_auto_alt_ref[i];
302   if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) {
303     svc_log(svc_ctx, SVC_LOG_ERROR,
304             "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
305             "enabled auto alt reference frame, but % layers are enabled\n",
306             REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled);
307     res = VPX_CODEC_INVALID_PARAM;
308   }
309
310   return res;
311 }
312
313 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
314   SvcInternal *const si = get_svc_internal(svc_ctx);
315   if (svc_ctx == NULL || options == NULL || si == NULL) {
316     return VPX_CODEC_INVALID_PARAM;
317   }
318   strncpy(si->options, options, sizeof(si->options));
319   si->options[sizeof(si->options) - 1] = '\0';
320   return VPX_CODEC_OK;
321 }
322
323 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
324                                        const char *quantizers) {
325   SvcInternal *const si = get_svc_internal(svc_ctx);
326   if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
327     return VPX_CODEC_INVALID_PARAM;
328   }
329   strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
330   si->quantizers[sizeof(si->quantizers) - 1] = '\0';
331   return VPX_CODEC_OK;
332 }
333
334 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
335                                           const char *scale_factors) {
336   SvcInternal *const si = get_svc_internal(svc_ctx);
337   if (svc_ctx == NULL || scale_factors == NULL || si == NULL) {
338     return VPX_CODEC_INVALID_PARAM;
339   }
340   strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors));
341   si->scale_factors[sizeof(si->scale_factors) - 1] = '\0';
342   return VPX_CODEC_OK;
343 }
344
345 void assign_layer_bitrates(const SvcInternal *const si,
346                            vpx_codec_enc_cfg_t *const enc_cfg) {
347   int i;
348
349   if (si->bitrates[0] != 0) {
350     enc_cfg->rc_target_bitrate = 0;
351     for (i = 0; i < si->layers; ++i) {
352       enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i];
353       enc_cfg->rc_target_bitrate += si->bitrates[i];
354     }
355   } else {
356     float total = 0;
357     float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
358
359     for (i = 0; i < si->layers; ++i) {
360       if (si->scaling_factor_den[i] > 0) {
361         alloc_ratio[i] = (float)(si->scaling_factor_num[i] * 1.0 /
362             si->scaling_factor_den[i]);
363
364         alloc_ratio[i] *= alloc_ratio[i];
365         total += alloc_ratio[i];
366       }
367     }
368
369     for (i = 0; i < si->layers; ++i) {
370       if (total > 0) {
371         enc_cfg->ss_target_bitrate[i] = (unsigned int)
372             (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total);
373       }
374     }
375   }
376 }
377
378 vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
379                              vpx_codec_iface_t *iface,
380                              vpx_codec_enc_cfg_t *enc_cfg) {
381   vpx_codec_err_t res;
382   int i;
383   SvcInternal *const si = get_svc_internal(svc_ctx);
384   if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
385       enc_cfg == NULL) {
386     return VPX_CODEC_INVALID_PARAM;
387   }
388   if (si == NULL) return VPX_CODEC_MEM_ERROR;
389
390   si->codec_ctx = codec_ctx;
391
392   si->width = enc_cfg->g_w;
393   si->height = enc_cfg->g_h;
394
395   if (enc_cfg->kf_max_dist < 2) {
396     svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
397             enc_cfg->kf_max_dist);
398     return VPX_CODEC_INVALID_PARAM;
399   }
400   si->kf_dist = enc_cfg->kf_max_dist;
401
402   if (svc_ctx->spatial_layers == 0)
403     svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
404   if (svc_ctx->spatial_layers < 1 ||
405       svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
406     svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
407             svc_ctx->spatial_layers);
408     return VPX_CODEC_INVALID_PARAM;
409   }
410
411   for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
412     si->quantizer[i] = DEFAULT_QUANTIZER_VALUES[i];
413     si->scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i];
414     si->scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i];
415   }
416
417   if (strlen(si->quantizers) > 0) {
418     res = parse_layer_options_from_string(svc_ctx, QUANTIZER, si->quantizers,
419                                           si->quantizer, NULL);
420     if (res != VPX_CODEC_OK)
421       return res;
422   }
423
424   if (strlen(si->scale_factors) > 0) {
425     res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR,
426                                           si->scale_factors,
427                                           si->scaling_factor_num,
428                                           si->scaling_factor_den);
429     if (res != VPX_CODEC_OK)
430       return res;
431   }
432
433   // Parse aggregate command line options. Options must start with
434   // "layers=xx" then followed by other options
435   res = parse_options(svc_ctx, si->options);
436   if (res != VPX_CODEC_OK) return res;
437
438   if (svc_ctx->spatial_layers < 1)
439     svc_ctx->spatial_layers = 1;
440   if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS)
441     svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS;
442
443   if (svc_ctx->temporal_layers < 1)
444     svc_ctx->temporal_layers = 1;
445   if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS)
446     svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS;
447
448   si->layers = svc_ctx->spatial_layers;
449
450   assign_layer_bitrates(si, enc_cfg);
451
452 #if CONFIG_SPATIAL_SVC
453   for (i = 0; i < si->layers; ++i)
454     enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i];
455 #endif
456
457   if (svc_ctx->temporal_layers > 1) {
458     int i;
459     for (i = 0; i < svc_ctx->temporal_layers; ++i) {
460       enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate /
461                                       svc_ctx->temporal_layers;
462       enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i);
463     }
464   }
465
466   // modify encoder configuration
467   enc_cfg->ss_number_layers = si->layers;
468   enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
469
470   // TODO(ivanmaltz): determine if these values need to be set explicitly for
471   // svc, or if the normal default/override mechanism can be used
472   enc_cfg->rc_dropframe_thresh = 0;
473   enc_cfg->rc_resize_allowed = 0;
474
475   if (enc_cfg->g_pass == VPX_RC_ONE_PASS) {
476     enc_cfg->rc_min_quantizer = 33;
477     enc_cfg->rc_max_quantizer = 33;
478   }
479
480   enc_cfg->rc_undershoot_pct = 100;
481   enc_cfg->rc_overshoot_pct = 15;
482   enc_cfg->rc_buf_initial_sz = 500;
483   enc_cfg->rc_buf_optimal_sz = 600;
484   enc_cfg->rc_buf_sz = 1000;
485   if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
486     enc_cfg->g_error_resilient = 1;
487
488   // Initialize codec
489   res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
490   if (res != VPX_CODEC_OK) {
491     svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
492     return res;
493   }
494
495   vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
496   vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1);
497
498   return VPX_CODEC_OK;
499 }
500
501 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
502                                              int layer,
503                                              unsigned int *width,
504                                              unsigned int *height) {
505   int w, h, num, den;
506   const SvcInternal *const si = get_const_svc_internal(svc_ctx);
507
508   if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) {
509     return VPX_CODEC_INVALID_PARAM;
510   }
511   if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM;
512
513   num = si->scaling_factor_num[layer];
514   den = si->scaling_factor_den[layer];
515   if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM;
516
517   w = si->width * num / den;
518   h = si->height * num / den;
519
520   // make height and width even to make chrome player happy
521   w += w % 2;
522   h += h % 2;
523
524   *width = w;
525   *height = h;
526
527   return VPX_CODEC_OK;
528 }
529
530 static void set_svc_parameters(SvcContext *svc_ctx,
531                                vpx_codec_ctx_t *codec_ctx) {
532   int layer;
533   vpx_svc_parameters_t svc_params;
534   SvcInternal *const si = get_svc_internal(svc_ctx);
535
536   memset(&svc_params, 0, sizeof(svc_params));
537   svc_params.temporal_layer = 0;
538   svc_params.spatial_layer = si->layer;
539
540   layer = si->layer;
541   if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
542                                                    &svc_params.width,
543                                                    &svc_params.height)) {
544     svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
545   }
546
547   if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) {
548     svc_params.min_quantizer = si->quantizer[layer];
549     svc_params.max_quantizer = si->quantizer[layer];
550   } else {
551     svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
552     svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
553   }
554
555   svc_params.distance_from_i_frame = si->frame_within_gop;
556   vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
557 }
558
559 /**
560  * Encode a frame into multiple layers
561  * Create a superframe containing the individual layers
562  */
563 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
564                                struct vpx_image *rawimg, vpx_codec_pts_t pts,
565                                int64_t duration, int deadline) {
566   vpx_codec_err_t res;
567   vpx_codec_iter_t iter;
568   const vpx_codec_cx_pkt_t *cx_pkt;
569   int layer_for_psnr = 0;
570   SvcInternal *const si = get_svc_internal(svc_ctx);
571   if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
572     return VPX_CODEC_INVALID_PARAM;
573   }
574
575   svc_log_reset(svc_ctx);
576
577   si->layers = svc_ctx->spatial_layers;
578   if (si->encode_frame_count == 0) {
579     si->frame_within_gop = 0;
580   }
581   si->is_keyframe = (si->frame_within_gop == 0);
582
583   if (rawimg != NULL) {
584     svc_log(svc_ctx, SVC_LOG_DEBUG,
585             "vpx_svc_encode  layers: %d, frame_count: %d, "
586             "frame_within_gop: %d\n", si->layers, si->encode_frame_count,
587             si->frame_within_gop);
588   }
589
590   if (rawimg != NULL) {
591     // encode each layer
592     for (si->layer = 0; si->layer < si->layers; ++si->layer) {
593       set_svc_parameters(svc_ctx, codec_ctx);
594     }
595   }
596
597   res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0,
598                          deadline);
599   if (res != VPX_CODEC_OK) {
600     return res;
601   }
602   // save compressed data
603   iter = NULL;
604   while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
605     switch (cx_pkt->kind) {
606       case VPX_CODEC_PSNR_PKT: {
607         int i;
608         svc_log(svc_ctx, SVC_LOG_DEBUG,
609                 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
610                 "%2.3f  %2.3f  %2.3f  %2.3f \n",
611                 si->frame_received, layer_for_psnr,
612                 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
613                 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]);
614         svc_log(svc_ctx, SVC_LOG_DEBUG,
615                 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): "
616                 "%2.3f  %2.3f  %2.3f  %2.3f \n",
617                 si->frame_received, layer_for_psnr,
618                 cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1],
619                 cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]);
620         for (i = 0; i < COMPONENTS; i++) {
621           si->psnr_sum[layer_for_psnr][i] += cx_pkt->data.psnr.psnr[i];
622           si->sse_sum[layer_for_psnr][i] += cx_pkt->data.psnr.sse[i];
623         }
624         ++layer_for_psnr;
625         if (layer_for_psnr == svc_ctx->spatial_layers)
626           layer_for_psnr = 0;
627         break;
628       }
629 #if CONFIG_SPATIAL_SVC
630       case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: {
631         int i;
632         for (i = 0; i < si->layers; ++i)
633           si->bytes_sum[i] += cx_pkt->data.layer_sizes[i];
634         break;
635       }
636 #endif
637       default: {
638         break;
639       }
640     }
641   }
642
643   if (rawimg != NULL) {
644     ++si->frame_within_gop;
645     ++si->encode_frame_count;
646   }
647
648   return VPX_CODEC_OK;
649 }
650
651 const char *vpx_svc_get_message(const SvcContext *svc_ctx) {
652   const SvcInternal *const si = get_const_svc_internal(svc_ctx);
653   if (svc_ctx == NULL || si == NULL) return NULL;
654   return si->message_buffer;
655 }
656
657 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
658   const SvcInternal *const si = get_const_svc_internal(svc_ctx);
659   if (svc_ctx == NULL || si == NULL) return 0;
660   return si->encode_frame_count;
661 }
662
663 void vpx_svc_set_keyframe(SvcContext *svc_ctx) {
664   SvcInternal *const si = get_svc_internal(svc_ctx);
665   if (svc_ctx == NULL || si == NULL) return;
666   si->frame_within_gop = 0;
667 }
668
669 static double calc_psnr(double d) {
670   if (d == 0) return 100;
671   return -10.0 * log(d) / log(10.0);
672 }
673
674 // dump accumulated statistics and reset accumulated values
675 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
676   int number_of_frames, encode_frame_count;
677   int i, j;
678   uint32_t bytes_total = 0;
679   double scale[COMPONENTS];
680   double psnr[COMPONENTS];
681   double mse[COMPONENTS];
682   double y_scale;
683
684   SvcInternal *const si = get_svc_internal(svc_ctx);
685   if (svc_ctx == NULL || si == NULL) return NULL;
686
687   svc_log_reset(svc_ctx);
688
689   encode_frame_count = si->encode_frame_count;
690   if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
691
692   svc_log(svc_ctx, SVC_LOG_INFO, "\n");
693   for (i = 0; i < si->layers; ++i) {
694     number_of_frames = encode_frame_count;
695
696     svc_log(svc_ctx, SVC_LOG_INFO,
697             "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
698             i, (double)si->psnr_sum[i][0] / number_of_frames,
699             (double)si->psnr_sum[i][1] / number_of_frames,
700             (double)si->psnr_sum[i][2] / number_of_frames,
701             (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
702     // the following psnr calculation is deduced from ffmpeg.c#print_report
703     y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
704     scale[1] = y_scale;
705     scale[2] = scale[3] = y_scale / 4;  // U or V
706     scale[0] = y_scale * 1.5;           // total
707
708     for (j = 0; j < COMPONENTS; j++) {
709       psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
710       mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
711     }
712     svc_log(svc_ctx, SVC_LOG_INFO,
713             "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
714             psnr[1], psnr[2], psnr[3]);
715     svc_log(svc_ctx, SVC_LOG_INFO,
716             "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
717             mse[1], mse[2], mse[3]);
718
719     bytes_total += si->bytes_sum[i];
720     // clear sums for next time
721     si->bytes_sum[i] = 0;
722     for (j = 0; j < COMPONENTS; ++j) {
723       si->psnr_sum[i][j] = 0;
724       si->sse_sum[i][j] = 0;
725     }
726   }
727
728   // only display statistics once
729   si->encode_frame_count = 0;
730
731   svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
732   return vpx_svc_get_message(svc_ctx);
733 }
734
735 void vpx_svc_release(SvcContext *svc_ctx) {
736   SvcInternal *si;
737   if (svc_ctx == NULL) return;
738   // do not use get_svc_internal as it will unnecessarily allocate an
739   // SvcInternal if it was not already allocated
740   si = (SvcInternal *)svc_ctx->internal;
741   if (si != NULL) {
742     free(si);
743     svc_ctx->internal = NULL;
744   }
745 }
746