1d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org/*
2d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *
4d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  Use of this source code is governed by a BSD-style license
5d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  that can be found in the LICENSE file in the root of the source
6d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  tree. An additional intellectual property rights grant can be found
7d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  in the file PATENTS.  All contributing project authors may
8d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *  be found in the AUTHORS file in the root of the source tree.
9d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org */
10d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
11d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org/**
12d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * @file
13d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * VP9 SVC encoding support via libvpx
14d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org */
15d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
1693a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org#include <assert.h>
17411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#include <math.h>
1887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org#include <limits.h>
19d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include <stdarg.h>
20d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include <stdio.h>
21d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include <stdlib.h>
22d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include <string.h>
23d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define VPX_DISABLE_CTRL_TYPECHECKS 1
24ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org#include "./vpx_config.h"
25d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include "vpx/svc_context.h"
26d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include "vpx/vp8cx.h"
27d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#include "vpx/vpx_encoder.h"
28e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org#include "vpx_mem/vpx_mem.h"
29ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org#include "vp9/common/vp9_onyxc_int.h"
30d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
31411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#ifdef __MINGW32__
32d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define strtok_r strtok_s
33411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#ifndef MINGW_HAS_SECURE_API
34d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
35d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
36411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#endif  /* MINGW_HAS_SECURE_API */
37411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#endif  /* __MINGW32__ */
38d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
39d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#ifdef _MSC_VER
40d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define strdup _strdup
41d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define strtok_r strtok_s
42d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#endif
43d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
44d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define SVC_REFERENCE_FRAMES 8
45d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define SUPERFRAME_SLOTS (8)
46d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
4787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org#define OPTION_BUFFER_SIZE 1024
48411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org#define COMPONENTS 4  // psnr & sse statistics maintained for total, y, u, v
49d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
5087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org#define MAX_QUANTIZER 63
5187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
5287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = {
5387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  4, 5, 7, 11, 16
5487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org};
5587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
5687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = {
5787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  16, 16, 16, 16, 16
5887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org};
5987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
6087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgtypedef enum {
6187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  QUANTIZER = 0,
6287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  BITRATE,
6387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  SCALE_FACTOR,
6487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  AUTO_ALT_REF,
6587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  ALL_OPTION_TYPES
6687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org} LAYER_OPTION_TYPE;
6787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
6887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic const int option_max_values[ALL_OPTION_TYPES] = {
6987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  63, INT_MAX, INT_MAX, 1
7087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org};
7187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
7287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic const int option_min_values[ALL_OPTION_TYPES] = {
7387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  0, 0, 1, 0
7487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org};
75d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
76e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org// One encoded frame
77e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.orgtypedef struct FrameData {
78e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  void                     *buf;    // compressed data buffer
79e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  size_t                    size;  // length of compressed data
80e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  vpx_codec_frame_flags_t   flags;    /**< flags for this frame */
81e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  struct FrameData         *next;
82e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org} FrameData;
83e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org
84d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgtypedef struct SvcInternal {
85d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char options[OPTION_BUFFER_SIZE];        // set by vpx_svc_set_options
86d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
87d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // values extracted from option, quantizers
8887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  vpx_svc_extra_cfg_t svc_params;
89ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  int enable_auto_alt_ref[VPX_SS_MAX_LAYERS];
9087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int bitrates[VPX_SS_MAX_LAYERS];
91d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
92d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // accumulated statistics
93411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS];   // total/Y/U/V
94411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS];
95411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  uint32_t bytes_sum[VPX_SS_MAX_LAYERS];
96d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
97d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // codec encoding values
98d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  int width;    // width of highest layer
99d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  int height;   // height of highest layer
100d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  int kf_dist;  // distance between keyframes
101d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
102d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // state variables
10387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int psnr_pkt_received;
104d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  int layer;
105d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  int use_multiple_frame_contexts;
106d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
107d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char message_buffer[2048];
108d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  vpx_codec_ctx_t *codec_ctx;
109d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org} SvcInternal;
110d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
111d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgstatic SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
112d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL) return NULL;
113d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx->internal == NULL) {
11476e516e2154f353aa02c504bac88afb0f95fefa7johannkoenig@chromium.org    SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si));
115d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    if (si != NULL) {
116d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      memset(si, 0, sizeof(*si));
117d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    }
118d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_ctx->internal = si;
119d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
12076e516e2154f353aa02c504bac88afb0f95fefa7johannkoenig@chromium.org  return (SvcInternal *)svc_ctx->internal;
121d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
122d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
123d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgstatic const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
124d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL) return NULL;
12576e516e2154f353aa02c504bac88afb0f95fefa7johannkoenig@chromium.org  return (const SvcInternal *)svc_ctx->internal;
126d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
127d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
128d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgstatic void svc_log_reset(SvcContext *svc_ctx) {
129d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = (SvcInternal *)svc_ctx->internal;
130d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->message_buffer[0] = '\0';
131d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
132d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
1337765c078fa920ba6c949c15f16b6cc979d8bb95bjohannkoenig@chromium.orgstatic int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level,
1347765c078fa920ba6c949c15f16b6cc979d8bb95bjohannkoenig@chromium.org                   const char *fmt, ...) {
135d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char buf[512];
136d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  int retval = 0;
137d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  va_list ap;
138d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
139d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
140d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (level > svc_ctx->log_level) {
141d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return retval;
142d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
143d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
144d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  va_start(ap, fmt);
145d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  retval = vsnprintf(buf, sizeof(buf), fmt, ap);
146d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  va_end(ap);
147d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
148d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx->log_print) {
149d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    printf("%s", buf);
150d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  } else {
151d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    strncat(si->message_buffer, buf,
152d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org            sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
153d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
154d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
155d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (level == SVC_LOG_ERROR) {
156d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    si->codec_ctx->err_detail = si->message_buffer;
157d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
158d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return retval;
159d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
160d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
16187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type,
16287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                      char *input,
16387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                      int *value0,
16487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                      int *value1) {
16587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (type == SCALE_FACTOR) {
16687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    *value0 = strtol(input, &input, 10);
16787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    if (*input++ != '/')
16887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      return VPX_CODEC_INVALID_PARAM;
16987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    *value1 = strtol(input, &input, 10);
17087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
17187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    if (*value0 < option_min_values[SCALE_FACTOR] ||
17287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        *value1 < option_min_values[SCALE_FACTOR] ||
17387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        *value0 > option_max_values[SCALE_FACTOR] ||
17487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        *value1 > option_max_values[SCALE_FACTOR] ||
17587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        *value0 > *value1)  // num shouldn't be greater than den
17687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      return VPX_CODEC_INVALID_PARAM;
177d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  } else {
17887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    *value0 = atoi(input);
17987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    if (*value0 < option_min_values[type] ||
18087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        *value0 > option_max_values[type])
18187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      return VPX_CODEC_INVALID_PARAM;
182d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
18387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  return VPX_CODEC_OK;
184d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
185d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
18687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgstatic vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
18787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                                       LAYER_OPTION_TYPE type,
18887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                                       const char *input,
18987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                                       int *option0,
19087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                                       int *option1) {
19187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int i;
19287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  vpx_codec_err_t res = VPX_CODEC_OK;
193ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  char *input_string;
194ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  char *token;
195ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  const char *delim = ",";
196ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  char *save_ptr;
197ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org
19887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (input == NULL || option0 == NULL ||
19987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      (option1 == NULL && type == SCALE_FACTOR))
200ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
201ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org
20287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  input_string = strdup(input);
203ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  token = strtok_r(input_string, delim, &save_ptr);
204ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
205ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org    if (token != NULL) {
20687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = extract_option(type, token, option0 + i, option1 + i);
20787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      if (res != VPX_CODEC_OK)
208ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org        break;
209ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org      token = strtok_r(NULL, delim, &save_ptr);
210ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org    } else {
21187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      break;
212d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    }
213d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
21487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (res == VPX_CODEC_OK && i != svc_ctx->spatial_layers) {
215d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_log(svc_ctx, SVC_LOG_ERROR,
21687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            "svc: layer params type: %d    %d values required, "
21787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            "but only %d specified\n", type, svc_ctx->spatial_layers, i);
218d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    res = VPX_CODEC_INVALID_PARAM;
219d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
220d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  free(input_string);
221d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return res;
222d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
223d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
224d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org/**
225d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * Parse SVC encoding options
226d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * Format: encoding-mode=<svc_mode>,layers=<layer_count>
227d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *         scale-factors=<n1>/<d1>,<n2>/<d2>,...
228d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org *         quantizers=<q1>,<q2>,...
229d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * svc_mode = [i|ip|alt_ip|gf]
230d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org */
231d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgstatic vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
232d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char *input_string;
233d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char *option_name;
234d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char *option_value;
235d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  char *input_ptr;
236d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
23776e516e2154f353aa02c504bac88afb0f95fefa7johannkoenig@chromium.org  vpx_codec_err_t res = VPX_CODEC_OK;
23887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int i, alt_ref_enabled = 0;
239d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
240d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (options == NULL) return VPX_CODEC_OK;
241d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  input_string = strdup(options);
242d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
243d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // parse option name
244d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  option_name = strtok_r(input_string, "=", &input_ptr);
245d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  while (option_name != NULL) {
246d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    // parse option value
247d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    option_value = strtok_r(NULL, " ", &input_ptr);
248d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    if (option_value == NULL) {
249d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
250d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org              option_name);
251d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      res = VPX_CODEC_INVALID_PARAM;
252d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      break;
253d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    }
254d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    if (strcmp("spatial-layers", option_name) == 0) {
255d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      svc_ctx->spatial_layers = atoi(option_value);
256d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    } else if (strcmp("temporal-layers", option_name) == 0) {
257d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org      svc_ctx->temporal_layers = atoi(option_value);
258d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    } else if (strcmp("scale-factors", option_name) == 0) {
25987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
26087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->svc_params.scaling_factor_num,
26187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->svc_params.scaling_factor_den);
262d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      if (res != VPX_CODEC_OK) break;
26387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    } else if (strcmp("max-quantizers", option_name) == 0) {
26487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
26587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->svc_params.max_quantizers,
26687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            NULL);
26787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      if (res != VPX_CODEC_OK) break;
26887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    } else if (strcmp("min-quantizers", option_name) == 0) {
26987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
27087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->svc_params.min_quantizers,
27187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            NULL);
272d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      if (res != VPX_CODEC_OK) break;
273ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org    } else if (strcmp("auto-alt-refs", option_name) == 0) {
27487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
27587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->enable_auto_alt_ref, NULL);
27687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      if (res != VPX_CODEC_OK) break;
27787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    } else if (strcmp("bitrates", option_name) == 0) {
27887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value,
27987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                            si->bitrates, NULL);
280ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org      if (res != VPX_CODEC_OK) break;
281d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    } else if (strcmp("multi-frame-contexts", option_name) == 0) {
282d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org      si->use_multiple_frame_contexts = atoi(option_value);
283d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    } else {
284d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
285d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      res = VPX_CODEC_INVALID_PARAM;
286d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      break;
287d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    }
288d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    option_name = strtok_r(NULL, "=", &input_ptr);
289d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
290d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  free(input_string);
291d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org
29287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
29387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER ||
29487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        si->svc_params.max_quantizers[i] < 0 ||
29587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] ||
29687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        si->svc_params.min_quantizers[i] < 0)
29787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      res = VPX_CODEC_INVALID_PARAM;
29887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  }
29987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
300d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (si->use_multiple_frame_contexts &&
301d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org      (svc_ctx->spatial_layers > 3 ||
302d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org       svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
303d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    res = VPX_CODEC_INVALID_PARAM;
304d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org
30587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  for (i = 0; i < svc_ctx->spatial_layers; ++i)
30687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    alt_ref_enabled += si->enable_auto_alt_ref[i];
30787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) {
30887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    svc_log(svc_ctx, SVC_LOG_ERROR,
30987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
31087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            "enabled auto alt reference frame, but % layers are enabled\n",
31187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled);
31287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    res = VPX_CODEC_INVALID_PARAM;
31387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  }
31487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
315d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return res;
316d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
317d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
318d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgvpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
319d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
320d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL || options == NULL || si == NULL) {
321d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
322d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
323d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  strncpy(si->options, options, sizeof(si->options));
324d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->options[sizeof(si->options) - 1] = '\0';
325d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return VPX_CODEC_OK;
326d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
327d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
32887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.orgvoid assign_layer_bitrates(const SvcContext *svc_ctx,
32987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                           vpx_codec_enc_cfg_t *const enc_cfg) {
33087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int i;
33187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
332d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
33387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (si->bitrates[0] != 0) {
33487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    enc_cfg->rc_target_bitrate = 0;
33587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    for (i = 0; i < svc_ctx->spatial_layers; ++i) {
33687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i];
33787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      enc_cfg->rc_target_bitrate += si->bitrates[i];
33887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    }
33987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  } else {
34087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    float total = 0;
34187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
34287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
34387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    for (i = 0; i < svc_ctx->spatial_layers; ++i) {
34487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      if (si->svc_params.scaling_factor_den[i] > 0) {
34587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
34687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                                 si->svc_params.scaling_factor_den[i]);
34787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
34887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        alloc_ratio[i] *= alloc_ratio[i];
34987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        total += alloc_ratio[i];
35087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      }
35187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    }
35287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
35387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    for (i = 0; i < svc_ctx->spatial_layers; ++i) {
35487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      if (total > 0) {
35587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        enc_cfg->ss_target_bitrate[i] = (unsigned int)
35687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total);
35787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      }
35887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    }
359d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
360d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
361d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
362d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgvpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
363d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org                             vpx_codec_iface_t *iface,
364d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org                             vpx_codec_enc_cfg_t *enc_cfg) {
365d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  vpx_codec_err_t res;
366ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org  int i;
367d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
368d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
369d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      enc_cfg == NULL) {
370d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
371d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
372d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (si == NULL) return VPX_CODEC_MEM_ERROR;
373d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
374d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->codec_ctx = codec_ctx;
375d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
376d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->width = enc_cfg->g_w;
377d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->height = enc_cfg->g_h;
378d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
379d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (enc_cfg->kf_max_dist < 2) {
380d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
381d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org            enc_cfg->kf_max_dist);
382d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
383d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
384d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si->kf_dist = enc_cfg->kf_max_dist;
385d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
386d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx->spatial_layers == 0)
387d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
388d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx->spatial_layers < 1 ||
389d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
390d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
391d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org            svc_ctx->spatial_layers);
392d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
393d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
394d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
39587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
39687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
39787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    si->svc_params.min_quantizers[i] = 0;
39887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    si->svc_params.scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i];
39987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org    si->svc_params.scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i];
40087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  }
401d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
40293a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org  // Parse aggregate command line options. Options must start with
40393a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org  // "layers=xx" then followed by other options
404d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  res = parse_options(svc_ctx, si->options);
405d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (res != VPX_CODEC_OK) return res;
406d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
407d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (svc_ctx->spatial_layers < 1)
408d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    svc_ctx->spatial_layers = 1;
409d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS)
410d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS;
411d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org
412d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (svc_ctx->temporal_layers < 1)
413d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    svc_ctx->temporal_layers = 1;
414d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS)
415d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS;
416d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org
41787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  assign_layer_bitrates(svc_ctx, enc_cfg);
418411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org
41941294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#if CONFIG_SPATIAL_SVC
42087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  for (i = 0; i < svc_ctx->spatial_layers; ++i)
421ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org    enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i];
42241294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
423ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org
424d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (svc_ctx->temporal_layers > 1) {
425d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    int i;
426d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    for (i = 0; i < svc_ctx->temporal_layers; ++i) {
427d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org      enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate /
428d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org                                      svc_ctx->temporal_layers;
429d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org      enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i);
430d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    }
431d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  }
432d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org
433d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // modify encoder configuration
43487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  enc_cfg->ss_number_layers = svc_ctx->spatial_layers;
435d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
436d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
437d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org  if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
438d95585fb0ec024f6abd96f7b02e0df58019d46afjohannkoenig@chromium.org    enc_cfg->g_error_resilient = 1;
439d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
440d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // Initialize codec
441d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
442d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (res != VPX_CODEC_OK) {
443d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
444d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return res;
445d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
446d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
447d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
44887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params);
449d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
450d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return VPX_CODEC_OK;
451d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
452d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
453d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org/**
454d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * Encode a frame into multiple layers
455d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org * Create a superframe containing the individual layers
456d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org */
457d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgvpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
458d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org                               struct vpx_image *rawimg, vpx_codec_pts_t pts,
459d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org                               int64_t duration, int deadline) {
460d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  vpx_codec_err_t res;
461d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  vpx_codec_iter_t iter;
462d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  const vpx_codec_cx_pkt_t *cx_pkt;
463d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
46493a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org  if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
465d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    return VPX_CODEC_INVALID_PARAM;
466d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
467d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
468d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  svc_log_reset(svc_ctx);
469d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
470e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0,
471e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org                         deadline);
472e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  if (res != VPX_CODEC_OK) {
473e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org    return res;
474e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  }
475e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  // save compressed data
476e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  iter = NULL;
477e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org  while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
478e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org    switch (cx_pkt->kind) {
47987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org#if CONFIG_SPATIAL_SVC
48087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org      case VPX_CODEC_SPATIAL_SVC_LAYER_PSNR: {
481e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org        int i;
48287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        for (i = 0; i < svc_ctx->spatial_layers; ++i) {
48387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org          int j;
48487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org          svc_log(svc_ctx, SVC_LOG_DEBUG,
48587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
48687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
48787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  si->psnr_pkt_received, i,
48887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].psnr[0],
48987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].psnr[1],
49087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].psnr[2],
49187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].psnr[3]);
49287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org          svc_log(svc_ctx, SVC_LOG_DEBUG,
49387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): "
49487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
49587997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  si->psnr_pkt_received, i,
49687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].sse[0],
49787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].sse[1],
49887997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].sse[2],
49987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                  cx_pkt->data.layer_psnr[i].sse[3]);
50087997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org
50187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org          for (j = 0; j < COMPONENTS; ++j) {
50287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            si->psnr_sum[i][j] +=
50387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org                cx_pkt->data.layer_psnr[i].psnr[j];
50487997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org            si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j];
505411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org          }
506d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org        }
50787997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        ++si->psnr_pkt_received;
508e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org        break;
509d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org      }
510ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org      case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: {
511ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org        int i;
51287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org        for (i = 0; i < svc_ctx->spatial_layers; ++i)
513ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org          si->bytes_sum[i] += cx_pkt->data.layer_sizes[i];
514ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org        break;
515ac4e313c19203132648a2a271703b6ee76fe4284johannkoenig@chromium.org      }
51641294d96d7dbf9bc215b09832a8336c5fb158f0bjohannkoenig@chromium.org#endif
517e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org      default: {
518e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org        break;
51993a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org      }
520d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    }
521d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
522e2064011d36b2008099446503f28e64d445060ecjohannkoenig@chromium.org
523d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return VPX_CODEC_OK;
524d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
525d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
526d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgconst char *vpx_svc_get_message(const SvcContext *svc_ctx) {
527d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
528d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL || si == NULL) return NULL;
529d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return si->message_buffer;
530d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
531d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
532411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.orgstatic double calc_psnr(double d) {
533411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  if (d == 0) return 100;
534411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  return -10.0 * log(d) / log(10.0);
535411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org}
536411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org
537d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org// dump accumulated statistics and reset accumulated values
538d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgconst char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
53987997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  int number_of_frames;
540411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  int i, j;
541d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  uint32_t bytes_total = 0;
542411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  double scale[COMPONENTS];
543411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  double psnr[COMPONENTS];
544411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  double mse[COMPONENTS];
545411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org  double y_scale;
546411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org
547d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *const si = get_svc_internal(svc_ctx);
548d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL || si == NULL) return NULL;
549d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
550d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  svc_log_reset(svc_ctx);
551d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
55287997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  number_of_frames = si->psnr_pkt_received;
55387997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx);
554d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
555d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  svc_log(svc_ctx, SVC_LOG_INFO, "\n");
55687997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
557d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
558411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    svc_log(svc_ctx, SVC_LOG_INFO,
559411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
560411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            i, (double)si->psnr_sum[i][0] / number_of_frames,
561411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            (double)si->psnr_sum[i][1] / number_of_frames,
562411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            (double)si->psnr_sum[i][2] / number_of_frames,
563411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
564411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    // the following psnr calculation is deduced from ffmpeg.c#print_report
565411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
566411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    scale[1] = y_scale;
567411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    scale[2] = scale[3] = y_scale / 4;  // U or V
568411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    scale[0] = y_scale * 1.5;           // total
569411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org
570411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    for (j = 0; j < COMPONENTS; j++) {
571411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org      psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
572411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org      mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
573411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    }
574411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    svc_log(svc_ctx, SVC_LOG_INFO,
575411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
576411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            psnr[1], psnr[2], psnr[3]);
577411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    svc_log(svc_ctx, SVC_LOG_INFO,
578411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
579411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org            mse[1], mse[2], mse[3]);
580411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org
581411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    bytes_total += si->bytes_sum[i];
582411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    // clear sums for next time
583411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    si->bytes_sum[i] = 0;
584411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    for (j = 0; j < COMPONENTS; ++j) {
585411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org      si->psnr_sum[i][j] = 0;
586411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org      si->sse_sum[i][j] = 0;
587411971f94253c85e1866c281860d6344f6aa0c78fgalligan@chromium.org    }
588d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
589d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
590d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // only display statistics once
59187997d490ae52aa962a985c95b3cddf7f8832641johannkoenig@chromium.org  si->psnr_pkt_received = 0;
592d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
593d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
594d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  return vpx_svc_get_message(svc_ctx);
595d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
596d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org
597d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.orgvoid vpx_svc_release(SvcContext *svc_ctx) {
598d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  SvcInternal *si;
599d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (svc_ctx == NULL) return;
600d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // do not use get_svc_internal as it will unnecessarily allocate an
601d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  // SvcInternal if it was not already allocated
602d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  si = (SvcInternal *)svc_ctx->internal;
603d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  if (si != NULL) {
604d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    free(si);
605d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org    svc_ctx->internal = NULL;
606d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org  }
607d851b91d14ef0bd71acdce7b90c9a8f1af1181adjohannkoenig@chromium.org}
60893a74791c8e808ea76001ee07693aa2a5fdd3500johannkoenig@chromium.org
609