1233d2500723e5594f3e7c70896ffeeef32b9c950ywan/*
2233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3233d2500723e5594f3e7c70896ffeeef32b9c950ywan *
4233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  Use of this source code is governed by a BSD-style license
5233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  that can be found in the LICENSE file in the root of the source
6233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  tree. An additional intellectual property rights grant can be found
7233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  in the file PATENTS.  All contributing project authors may
8233d2500723e5594f3e7c70896ffeeef32b9c950ywan *  be found in the AUTHORS file in the root of the source tree.
9233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
10233d2500723e5594f3e7c70896ffeeef32b9c950ywan
11233d2500723e5594f3e7c70896ffeeef32b9c950ywan/**
12233d2500723e5594f3e7c70896ffeeef32b9c950ywan * @file
13233d2500723e5594f3e7c70896ffeeef32b9c950ywan * VP9 SVC encoding support via libvpx
14233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
15233d2500723e5594f3e7c70896ffeeef32b9c950ywan
16233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <assert.h>
17233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <math.h>
18233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdarg.h>
19233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdio.h>
20233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <stdlib.h>
21233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include <string.h>
22233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define VPX_DISABLE_CTRL_TYPECHECKS 1
23233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define VPX_CODEC_DISABLE_COMPAT 1
24233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx/svc_context.h"
25233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx/vp8cx.h"
26233d2500723e5594f3e7c70896ffeeef32b9c950ywan#include "vpx/vpx_encoder.h"
27233d2500723e5594f3e7c70896ffeeef32b9c950ywan
28233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef __MINGW32__
29233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define strtok_r strtok_s
30233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifndef MINGW_HAS_SECURE_API
31233d2500723e5594f3e7c70896ffeeef32b9c950ywan// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
32233d2500723e5594f3e7c70896ffeeef32b9c950ywan_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
33233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif  /* MINGW_HAS_SECURE_API */
34233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif  /* __MINGW32__ */
35233d2500723e5594f3e7c70896ffeeef32b9c950ywan
36233d2500723e5594f3e7c70896ffeeef32b9c950ywan#ifdef _MSC_VER
37233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define strdup _strdup
38233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define strtok_r strtok_s
39233d2500723e5594f3e7c70896ffeeef32b9c950ywan#endif
40233d2500723e5594f3e7c70896ffeeef32b9c950ywan
41233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define SVC_REFERENCE_FRAMES 8
42233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define SUPERFRAME_SLOTS (8)
43233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
44233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define OPTION_BUFFER_SIZE 256
45233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define COMPONENTS 4  // psnr & sse statistics maintained for total, y, u, v
46233d2500723e5594f3e7c70896ffeeef32b9c950ywan
47233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27";
48233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16";
49233d2500723e5594f3e7c70896ffeeef32b9c950ywan
50233d2500723e5594f3e7c70896ffeeef32b9c950ywantypedef struct SvcInternal {
51233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char options[OPTION_BUFFER_SIZE];        // set by vpx_svc_set_options
52233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char quantizers[OPTION_BUFFER_SIZE];     // set by vpx_svc_set_quantizers
53233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char quantizers_keyframe[OPTION_BUFFER_SIZE];  // set by
54233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                 // vpx_svc_set_quantizers
55233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char scale_factors[OPTION_BUFFER_SIZE];  // set by vpx_svc_set_scale_factors
56233d2500723e5594f3e7c70896ffeeef32b9c950ywan
57233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // values extracted from option, quantizers
58233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int scaling_factor_num[VPX_SS_MAX_LAYERS];
59233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int scaling_factor_den[VPX_SS_MAX_LAYERS];
60233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int quantizer_keyframe[VPX_SS_MAX_LAYERS];
61233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int quantizer[VPX_SS_MAX_LAYERS];
62233d2500723e5594f3e7c70896ffeeef32b9c950ywan
63233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // accumulated statistics
64233d2500723e5594f3e7c70896ffeeef32b9c950ywan  double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS];   // total/Y/U/V
65233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS];
66233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint32_t bytes_sum[VPX_SS_MAX_LAYERS];
67233d2500723e5594f3e7c70896ffeeef32b9c950ywan
68233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // codec encoding values
69233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int width;    // width of highest layer
70233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int height;   // height of highest layer
71233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int kf_dist;  // distance between keyframes
72233d2500723e5594f3e7c70896ffeeef32b9c950ywan
73233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // state variables
74233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int encode_frame_count;
75233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int frame_within_gop;
76233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_enc_frame_flags_t enc_frame_flags;
77233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int layers;
78233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int layer;
79233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int is_keyframe;
80233d2500723e5594f3e7c70896ffeeef32b9c950ywan
81233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t frame_size;
82233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t buffer_size;
83233d2500723e5594f3e7c70896ffeeef32b9c950ywan  void *buffer;
84233d2500723e5594f3e7c70896ffeeef32b9c950ywan
85233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *rc_stats_buf;
86233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t rc_stats_buf_size;
87233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t rc_stats_buf_used;
88233d2500723e5594f3e7c70896ffeeef32b9c950ywan
89233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char message_buffer[2048];
90233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_ctx_t *codec_ctx;
91233d2500723e5594f3e7c70896ffeeef32b9c950ywan} SvcInternal;
92233d2500723e5594f3e7c70896ffeeef32b9c950ywan
93233d2500723e5594f3e7c70896ffeeef32b9c950ywan// Superframe is used to generate an index of individual frames (i.e., layers)
94233d2500723e5594f3e7c70896ffeeef32b9c950ywanstruct Superframe {
95233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int count;
96233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint32_t sizes[SUPERFRAME_SLOTS];
97233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint32_t magnitude;
98233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint8_t buffer[SUPERFRAME_BUFFER_SIZE];
99233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t index_size;
100233d2500723e5594f3e7c70896ffeeef32b9c950ywan};
101233d2500723e5594f3e7c70896ffeeef32b9c950ywan
102233d2500723e5594f3e7c70896ffeeef32b9c950ywan// One encoded frame layer
103233d2500723e5594f3e7c70896ffeeef32b9c950ywanstruct LayerData {
104233d2500723e5594f3e7c70896ffeeef32b9c950ywan  void *buf;    // compressed data buffer
105233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t size;  // length of compressed data
106233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *next;
107233d2500723e5594f3e7c70896ffeeef32b9c950ywan};
108233d2500723e5594f3e7c70896ffeeef32b9c950ywan
109233d2500723e5594f3e7c70896ffeeef32b9c950ywan// create LayerData from encoder output
110233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic struct LayerData *ld_create(void *buf, size_t size) {
111233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *const layer_data =
112233d2500723e5594f3e7c70896ffeeef32b9c950ywan      (struct LayerData *)malloc(sizeof(*layer_data));
113233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (layer_data == NULL) {
114233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return NULL;
115233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
116233d2500723e5594f3e7c70896ffeeef32b9c950ywan  layer_data->buf = malloc(size);
117233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (layer_data->buf == NULL) {
118233d2500723e5594f3e7c70896ffeeef32b9c950ywan    free(layer_data);
119233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return NULL;
120233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
121233d2500723e5594f3e7c70896ffeeef32b9c950ywan  memcpy(layer_data->buf, buf, size);
122233d2500723e5594f3e7c70896ffeeef32b9c950ywan  layer_data->size = size;
123233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return layer_data;
124233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
125233d2500723e5594f3e7c70896ffeeef32b9c950ywan
126233d2500723e5594f3e7c70896ffeeef32b9c950ywan// free LayerData
127233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void ld_free(struct LayerData *layer_data) {
128233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (layer_data) {
129233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (layer_data->buf) {
130233d2500723e5594f3e7c70896ffeeef32b9c950ywan      free(layer_data->buf);
131233d2500723e5594f3e7c70896ffeeef32b9c950ywan      layer_data->buf = NULL;
132233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
133233d2500723e5594f3e7c70896ffeeef32b9c950ywan    free(layer_data);
134233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
135233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
136233d2500723e5594f3e7c70896ffeeef32b9c950ywan
137233d2500723e5594f3e7c70896ffeeef32b9c950ywan// add layer data to list
138233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void ld_list_add(struct LayerData **list, struct LayerData *layer_data) {
139233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData **p = list;
140233d2500723e5594f3e7c70896ffeeef32b9c950ywan
141233d2500723e5594f3e7c70896ffeeef32b9c950ywan  while (*p != NULL) p = &(*p)->next;
142233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *p = layer_data;
143233d2500723e5594f3e7c70896ffeeef32b9c950ywan  layer_data->next = NULL;
144233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
145233d2500723e5594f3e7c70896ffeeef32b9c950ywan
146233d2500723e5594f3e7c70896ffeeef32b9c950ywan// get accumulated size of layer data
147233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic size_t ld_list_get_buffer_size(struct LayerData *list) {
148233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *p;
149233d2500723e5594f3e7c70896ffeeef32b9c950ywan  size_t size = 0;
150233d2500723e5594f3e7c70896ffeeef32b9c950ywan
151233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (p = list; p != NULL; p = p->next) {
152233d2500723e5594f3e7c70896ffeeef32b9c950ywan    size += p->size;
153233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
154233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return size;
155233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
156233d2500723e5594f3e7c70896ffeeef32b9c950ywan
157233d2500723e5594f3e7c70896ffeeef32b9c950ywan// copy layer data to buffer
158233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) {
159233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *p;
160233d2500723e5594f3e7c70896ffeeef32b9c950ywan
161233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (p = list; p != NULL; p = p->next) {
162233d2500723e5594f3e7c70896ffeeef32b9c950ywan    buffer[0] = 1;
163233d2500723e5594f3e7c70896ffeeef32b9c950ywan    memcpy(buffer, p->buf, p->size);
164233d2500723e5594f3e7c70896ffeeef32b9c950ywan    buffer += p->size;
165233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
166233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
167233d2500723e5594f3e7c70896ffeeef32b9c950ywan
168233d2500723e5594f3e7c70896ffeeef32b9c950ywan// free layer data list
169233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void ld_list_free(struct LayerData *list) {
170233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *p = list;
171233d2500723e5594f3e7c70896ffeeef32b9c950ywan
172233d2500723e5594f3e7c70896ffeeef32b9c950ywan  while (p) {
173233d2500723e5594f3e7c70896ffeeef32b9c950ywan    list = list->next;
174233d2500723e5594f3e7c70896ffeeef32b9c950ywan    ld_free(p);
175233d2500723e5594f3e7c70896ffeeef32b9c950ywan    p = list;
176233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
177233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
178233d2500723e5594f3e7c70896ffeeef32b9c950ywan
179233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void sf_create_index(struct Superframe *sf) {
180233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint8_t marker = 0xc0;
181233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int i;
182233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint32_t mag, mask;
183233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint8_t *bufp;
184233d2500723e5594f3e7c70896ffeeef32b9c950ywan
185233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (sf->count == 0 || sf->count >= 8) return;
186233d2500723e5594f3e7c70896ffeeef32b9c950ywan
187233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Add the number of frames to the marker byte
188233d2500723e5594f3e7c70896ffeeef32b9c950ywan  marker |= sf->count - 1;
189233d2500723e5594f3e7c70896ffeeef32b9c950ywan
190233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Choose the magnitude
191233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (mag = 0, mask = 0xff; mag < 4; ++mag) {
192233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (sf->magnitude < mask) break;
193233d2500723e5594f3e7c70896ffeeef32b9c950ywan    mask <<= 8;
194233d2500723e5594f3e7c70896ffeeef32b9c950ywan    mask |= 0xff;
195233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
196233d2500723e5594f3e7c70896ffeeef32b9c950ywan  marker |= mag << 3;
197233d2500723e5594f3e7c70896ffeeef32b9c950ywan
198233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Write the index
199233d2500723e5594f3e7c70896ffeeef32b9c950ywan  sf->index_size = 2 + (mag + 1) * sf->count;
200233d2500723e5594f3e7c70896ffeeef32b9c950ywan  bufp = sf->buffer;
201233d2500723e5594f3e7c70896ffeeef32b9c950ywan
202233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *bufp++ = marker;
203233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < sf->count; ++i) {
204233d2500723e5594f3e7c70896ffeeef32b9c950ywan    int this_sz = sf->sizes[i];
205233d2500723e5594f3e7c70896ffeeef32b9c950ywan    uint32_t j;
206233d2500723e5594f3e7c70896ffeeef32b9c950ywan
207233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (j = 0; j <= mag; ++j) {
208233d2500723e5594f3e7c70896ffeeef32b9c950ywan      *bufp++ = this_sz & 0xff;
209233d2500723e5594f3e7c70896ffeeef32b9c950ywan      this_sz >>= 8;
210233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
211233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
212233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *bufp++ = marker;
213233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
214233d2500723e5594f3e7c70896ffeeef32b9c950ywan
215233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic SvcInternal *get_svc_internal(SvcContext *svc_ctx) {
216233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL) return NULL;
217233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->internal == NULL) {
218233d2500723e5594f3e7c70896ffeeef32b9c950ywan    SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si));
219233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (si != NULL) {
220233d2500723e5594f3e7c70896ffeeef32b9c950ywan      memset(si, 0, sizeof(*si));
221233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
222233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->internal = si;
223233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
224233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return (SvcInternal *)svc_ctx->internal;
225233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
226233d2500723e5594f3e7c70896ffeeef32b9c950ywan
227233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) {
228233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL) return NULL;
229233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return (const SvcInternal *)svc_ctx->internal;
230233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
231233d2500723e5594f3e7c70896ffeeef32b9c950ywan
232233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void svc_log_reset(SvcContext *svc_ctx) {
233233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = (SvcInternal *)svc_ctx->internal;
234233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->message_buffer[0] = '\0';
235233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
236233d2500723e5594f3e7c70896ffeeef32b9c950ywan
237233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int svc_log(SvcContext *svc_ctx, int level, const char *fmt, ...) {
238233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char buf[512];
239233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int retval = 0;
240233d2500723e5594f3e7c70896ffeeef32b9c950ywan  va_list ap;
241233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
242233d2500723e5594f3e7c70896ffeeef32b9c950ywan
243233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (level > svc_ctx->log_level) {
244233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return retval;
245233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
246233d2500723e5594f3e7c70896ffeeef32b9c950ywan
247233d2500723e5594f3e7c70896ffeeef32b9c950ywan  va_start(ap, fmt);
248233d2500723e5594f3e7c70896ffeeef32b9c950ywan  retval = vsnprintf(buf, sizeof(buf), fmt, ap);
249233d2500723e5594f3e7c70896ffeeef32b9c950ywan  va_end(ap);
250233d2500723e5594f3e7c70896ffeeef32b9c950ywan
251233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->log_print) {
252233d2500723e5594f3e7c70896ffeeef32b9c950ywan    printf("%s", buf);
253233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
254233d2500723e5594f3e7c70896ffeeef32b9c950ywan    strncat(si->message_buffer, buf,
255233d2500723e5594f3e7c70896ffeeef32b9c950ywan            sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
256233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
257233d2500723e5594f3e7c70896ffeeef32b9c950ywan
258233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (level == SVC_LOG_ERROR) {
259233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->codec_ctx->err_detail = si->message_buffer;
260233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
261233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return retval;
262233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
263233d2500723e5594f3e7c70896ffeeef32b9c950ywan
264233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx,
265233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                const char *value_str) {
266233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (strcmp(value_str, "i") == 0) {
267233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I;
268233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else if (strcmp(value_str, "alt-ip") == 0) {
269233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP;
270233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else if (strcmp(value_str, "ip") == 0) {
271233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP;
272233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else if (strcmp(value_str, "gf") == 0) {
273233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->encoding_mode = USE_GOLDEN_FRAME;
274233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
275233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str);
276233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
277233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
278233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
279233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
280233d2500723e5594f3e7c70896ffeeef32b9c950ywan
281233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx,
282233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                              const char *quantizer_values,
283233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                              const int is_keyframe) {
284233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *input_string;
285233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *token;
286233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const char *delim = ",";
287233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *save_ptr;
288233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int found = 0;
289233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int i, q;
290233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res = VPX_CODEC_OK;
291233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
292233d2500723e5594f3e7c70896ffeeef32b9c950ywan
293233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (quantizer_values == NULL || strlen(quantizer_values) == 0) {
294233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (is_keyframe) {
295233d2500723e5594f3e7c70896ffeeef32b9c950ywan      // If there non settings for key frame, we will apply settings from
296233d2500723e5594f3e7c70896ffeeef32b9c950ywan      // non key frame. So just simply return here.
297233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return VPX_CODEC_INVALID_PARAM;
298233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
299233d2500723e5594f3e7c70896ffeeef32b9c950ywan    input_string = strdup(DEFAULT_QUANTIZER_VALUES);
300233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
301233d2500723e5594f3e7c70896ffeeef32b9c950ywan    input_string = strdup(quantizer_values);
302233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
303233d2500723e5594f3e7c70896ffeeef32b9c950ywan
304233d2500723e5594f3e7c70896ffeeef32b9c950ywan  token = strtok_r(input_string, delim, &save_ptr);
305233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
306233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (token != NULL) {
307233d2500723e5594f3e7c70896ffeeef32b9c950ywan      q = atoi(token);
308233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (q <= 0 || q > 100) {
309233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_log(svc_ctx, SVC_LOG_ERROR,
310233d2500723e5594f3e7c70896ffeeef32b9c950ywan                "svc-quantizer-values: invalid value %s\n", token);
311233d2500723e5594f3e7c70896ffeeef32b9c950ywan        res = VPX_CODEC_INVALID_PARAM;
312233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
313233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
314233d2500723e5594f3e7c70896ffeeef32b9c950ywan      token = strtok_r(NULL, delim, &save_ptr);
315233d2500723e5594f3e7c70896ffeeef32b9c950ywan      found = i + 1;
316233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else {
317233d2500723e5594f3e7c70896ffeeef32b9c950ywan      q = 0;
318233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
319233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (is_keyframe) {
320233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers]
321233d2500723e5594f3e7c70896ffeeef32b9c950ywan      = q;
322233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else {
323233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q;
324233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
325233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
326233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
327233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR,
328233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "svc: quantizers: %d values required, but only %d specified\n",
329233d2500723e5594f3e7c70896ffeeef32b9c950ywan            svc_ctx->spatial_layers, found);
330233d2500723e5594f3e7c70896ffeeef32b9c950ywan    res = VPX_CODEC_INVALID_PARAM;
331233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
332233d2500723e5594f3e7c70896ffeeef32b9c950ywan  free(input_string);
333233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return res;
334233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
335233d2500723e5594f3e7c70896ffeeef32b9c950ywan
336233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) {
337233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n",
338233d2500723e5594f3e7c70896ffeeef32b9c950ywan          value);
339233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
340233d2500723e5594f3e7c70896ffeeef32b9c950ywan
341233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx,
342233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                           const char *scale_factors) {
343233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *input_string;
344233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *token;
345233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const char *delim = ",";
346233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *save_ptr;
347233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int found = 0;
348233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int i;
349233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int64_t num, den;
350233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res = VPX_CODEC_OK;
351233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
352233d2500723e5594f3e7c70896ffeeef32b9c950ywan
353233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (scale_factors == NULL || strlen(scale_factors) == 0) {
354233d2500723e5594f3e7c70896ffeeef32b9c950ywan    input_string = strdup(DEFAULT_SCALE_FACTORS);
355233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
356233d2500723e5594f3e7c70896ffeeef32b9c950ywan    input_string = strdup(scale_factors);
357233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
358233d2500723e5594f3e7c70896ffeeef32b9c950ywan  token = strtok_r(input_string, delim, &save_ptr);
359233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < svc_ctx->spatial_layers; ++i) {
360233d2500723e5594f3e7c70896ffeeef32b9c950ywan    num = den = 0;
361233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (token != NULL) {
362233d2500723e5594f3e7c70896ffeeef32b9c950ywan      num = strtol(token, &token, 10);
363233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (num <= 0) {
364233d2500723e5594f3e7c70896ffeeef32b9c950ywan        log_invalid_scale_factor(svc_ctx, token);
365233d2500723e5594f3e7c70896ffeeef32b9c950ywan        res = VPX_CODEC_INVALID_PARAM;
366233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
367233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
368233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (*token++ != '/') {
369233d2500723e5594f3e7c70896ffeeef32b9c950ywan        log_invalid_scale_factor(svc_ctx, token);
370233d2500723e5594f3e7c70896ffeeef32b9c950ywan        res = VPX_CODEC_INVALID_PARAM;
371233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
372233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
373233d2500723e5594f3e7c70896ffeeef32b9c950ywan      den = strtol(token, &token, 10);
374233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (den <= 0) {
375233d2500723e5594f3e7c70896ffeeef32b9c950ywan        log_invalid_scale_factor(svc_ctx, token);
376233d2500723e5594f3e7c70896ffeeef32b9c950ywan        res = VPX_CODEC_INVALID_PARAM;
377233d2500723e5594f3e7c70896ffeeef32b9c950ywan        break;
378233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
379233d2500723e5594f3e7c70896ffeeef32b9c950ywan      token = strtok_r(NULL, delim, &save_ptr);
380233d2500723e5594f3e7c70896ffeeef32b9c950ywan      found = i + 1;
381233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
382233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
383233d2500723e5594f3e7c70896ffeeef32b9c950ywan        (int)num;
384233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] =
385233d2500723e5594f3e7c70896ffeeef32b9c950ywan        (int)den;
386233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
387233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) {
388233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR,
389233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "svc: scale-factors: %d values required, but only %d specified\n",
390233d2500723e5594f3e7c70896ffeeef32b9c950ywan            svc_ctx->spatial_layers, found);
391233d2500723e5594f3e7c70896ffeeef32b9c950ywan    res = VPX_CODEC_INVALID_PARAM;
392233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
393233d2500723e5594f3e7c70896ffeeef32b9c950ywan  free(input_string);
394233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return res;
395233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
396233d2500723e5594f3e7c70896ffeeef32b9c950ywan
397233d2500723e5594f3e7c70896ffeeef32b9c950ywan/**
398233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Parse SVC encoding options
399233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Format: encoding-mode=<svc_mode>,layers=<layer_count>
400233d2500723e5594f3e7c70896ffeeef32b9c950ywan *         scale-factors=<n1>/<d1>,<n2>/<d2>,...
401233d2500723e5594f3e7c70896ffeeef32b9c950ywan *         quantizers=<q1>,<q2>,...
402233d2500723e5594f3e7c70896ffeeef32b9c950ywan * svc_mode = [i|ip|alt_ip|gf]
403233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
404233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
405233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *input_string;
406233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *option_name;
407233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *option_value;
408233d2500723e5594f3e7c70896ffeeef32b9c950ywan  char *input_ptr;
409233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int is_keyframe_qaunt_set = 0;
410233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res = VPX_CODEC_OK;
411233d2500723e5594f3e7c70896ffeeef32b9c950ywan
412233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (options == NULL) return VPX_CODEC_OK;
413233d2500723e5594f3e7c70896ffeeef32b9c950ywan  input_string = strdup(options);
414233d2500723e5594f3e7c70896ffeeef32b9c950ywan
415233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // parse option name
416233d2500723e5594f3e7c70896ffeeef32b9c950ywan  option_name = strtok_r(input_string, "=", &input_ptr);
417233d2500723e5594f3e7c70896ffeeef32b9c950ywan  while (option_name != NULL) {
418233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // parse option value
419233d2500723e5594f3e7c70896ffeeef32b9c950ywan    option_value = strtok_r(NULL, " ", &input_ptr);
420233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (option_value == NULL) {
421233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
422233d2500723e5594f3e7c70896ffeeef32b9c950ywan              option_name);
423233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = VPX_CODEC_INVALID_PARAM;
424233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
425233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
426233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (strcmp("encoding-mode", option_name) == 0) {
427233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = set_option_encoding_mode(svc_ctx, option_value);
428233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (res != VPX_CODEC_OK) break;
429233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else if (strcmp("layers", option_name) == 0) {
430233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_ctx->spatial_layers = atoi(option_value);
431233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else if (strcmp("scale-factors", option_name) == 0) {
432233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = parse_scale_factors(svc_ctx, option_value);
433233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (res != VPX_CODEC_OK) break;
434233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else if (strcmp("quantizers", option_name) == 0) {
435233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = parse_quantizer_values(svc_ctx, option_value, 0);
436233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (res != VPX_CODEC_OK) break;
437233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (!is_keyframe_qaunt_set) {
438233d2500723e5594f3e7c70896ffeeef32b9c950ywan        SvcInternal *const si = get_svc_internal(svc_ctx);
439233d2500723e5594f3e7c70896ffeeef32b9c950ywan        memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer,
440233d2500723e5594f3e7c70896ffeeef32b9c950ywan               sizeof(si->quantizer));
441233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
442233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else if (strcmp("quantizers-keyframe", option_name) == 0) {
443233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = parse_quantizer_values(svc_ctx, option_value, 1);
444233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (res != VPX_CODEC_OK) break;
445233d2500723e5594f3e7c70896ffeeef32b9c950ywan      is_keyframe_qaunt_set = 1;
446233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else {
447233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
448233d2500723e5594f3e7c70896ffeeef32b9c950ywan      res = VPX_CODEC_INVALID_PARAM;
449233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
450233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
451233d2500723e5594f3e7c70896ffeeef32b9c950ywan    option_name = strtok_r(NULL, "=", &input_ptr);
452233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
453233d2500723e5594f3e7c70896ffeeef32b9c950ywan  free(input_string);
454233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return res;
455233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
456233d2500723e5594f3e7c70896ffeeef32b9c950ywan
457233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
458233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
459233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || options == NULL || si == NULL) {
460233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
461233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
462233d2500723e5594f3e7c70896ffeeef32b9c950ywan  strncpy(si->options, options, sizeof(si->options));
463233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->options[sizeof(si->options) - 1] = '\0';
464233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
465233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
466233d2500723e5594f3e7c70896ffeeef32b9c950ywan
467233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
468233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                       const char *quantizers,
469233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                       const int is_for_keyframe) {
470233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
471233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
472233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
473233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
474233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (is_for_keyframe) {
475233d2500723e5594f3e7c70896ffeeef32b9c950ywan    strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers));
476233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0';
477233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
478233d2500723e5594f3e7c70896ffeeef32b9c950ywan    strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
479233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->quantizers[sizeof(si->quantizers) - 1] = '\0';
480233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
481233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
482233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
483233d2500723e5594f3e7c70896ffeeef32b9c950ywan
484233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
485233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                          const char *scale_factors) {
486233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
487233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || scale_factors == NULL || si == NULL) {
488233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
489233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
490233d2500723e5594f3e7c70896ffeeef32b9c950ywan  strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors));
491233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->scale_factors[sizeof(si->scale_factors) - 1] = '\0';
492233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
493233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
494233d2500723e5594f3e7c70896ffeeef32b9c950ywan
495233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
496233d2500723e5594f3e7c70896ffeeef32b9c950ywan                             vpx_codec_iface_t *iface,
497233d2500723e5594f3e7c70896ffeeef32b9c950ywan                             vpx_codec_enc_cfg_t *enc_cfg) {
498233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int max_intra_size_pct;
499233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res;
500233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
501233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
502233d2500723e5594f3e7c70896ffeeef32b9c950ywan      enc_cfg == NULL) {
503233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
504233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
505233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si == NULL) return VPX_CODEC_MEM_ERROR;
506233d2500723e5594f3e7c70896ffeeef32b9c950ywan
507233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->codec_ctx = codec_ctx;
508233d2500723e5594f3e7c70896ffeeef32b9c950ywan
509233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->width = enc_cfg->g_w;
510233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->height = enc_cfg->g_h;
511233d2500723e5594f3e7c70896ffeeef32b9c950ywan
512233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (enc_cfg->kf_max_dist < 2) {
513233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
514233d2500723e5594f3e7c70896ffeeef32b9c950ywan            enc_cfg->kf_max_dist);
515233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
516233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
517233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->kf_dist = enc_cfg->kf_max_dist;
518233d2500723e5594f3e7c70896ffeeef32b9c950ywan
519233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->spatial_layers == 0)
520233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
521233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->spatial_layers < 1 ||
522233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
523233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
524233d2500723e5594f3e7c70896ffeeef32b9c950ywan            svc_ctx->spatial_layers);
525233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
526233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
527233d2500723e5594f3e7c70896ffeeef32b9c950ywan
528233d2500723e5594f3e7c70896ffeeef32b9c950ywan  res = parse_quantizer_values(svc_ctx, si->quantizers, 0);
529233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res != VPX_CODEC_OK) return res;
530233d2500723e5594f3e7c70896ffeeef32b9c950ywan
531233d2500723e5594f3e7c70896ffeeef32b9c950ywan  res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1);
532233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res != VPX_CODEC_OK)
533233d2500723e5594f3e7c70896ffeeef32b9c950ywan    memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer));
534233d2500723e5594f3e7c70896ffeeef32b9c950ywan
535233d2500723e5594f3e7c70896ffeeef32b9c950ywan  res = parse_scale_factors(svc_ctx, si->scale_factors);
536233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res != VPX_CODEC_OK) return res;
537233d2500723e5594f3e7c70896ffeeef32b9c950ywan
538233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Parse aggregate command line options. Options must start with
539233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // "layers=xx" then followed by other options
540233d2500723e5594f3e7c70896ffeeef32b9c950ywan  res = parse_options(svc_ctx, si->options);
541233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res != VPX_CODEC_OK) return res;
542233d2500723e5594f3e7c70896ffeeef32b9c950ywan
543233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->layers = svc_ctx->spatial_layers;
544233d2500723e5594f3e7c70896ffeeef32b9c950ywan
545233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Assign target bitrate for each layer. We calculate the ratio
546233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // from the resolution for now.
547233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // TODO(Minghai): Optimize the mechanism of allocating bits after
548233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // implementing svc two pass rate control.
549233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si->layers > 1) {
550233d2500723e5594f3e7c70896ffeeef32b9c950ywan    int i;
551233d2500723e5594f3e7c70896ffeeef32b9c950ywan    float total = 0;
552233d2500723e5594f3e7c70896ffeeef32b9c950ywan    float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
553233d2500723e5594f3e7c70896ffeeef32b9c950ywan
554233d2500723e5594f3e7c70896ffeeef32b9c950ywan    assert(si->layers <= VPX_SS_MAX_LAYERS);
555233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (i = 0; i < si->layers; ++i) {
556233d2500723e5594f3e7c70896ffeeef32b9c950ywan      int pos = i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers;
557233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (pos < VPX_SS_MAX_LAYERS && si->scaling_factor_den[pos] > 0) {
558233d2500723e5594f3e7c70896ffeeef32b9c950ywan        alloc_ratio[i] = (float)(si->scaling_factor_num[pos] * 1.0 /
559233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->scaling_factor_den[pos]);
560233d2500723e5594f3e7c70896ffeeef32b9c950ywan
561233d2500723e5594f3e7c70896ffeeef32b9c950ywan        alloc_ratio[i] *= alloc_ratio[i];
562233d2500723e5594f3e7c70896ffeeef32b9c950ywan        total += alloc_ratio[i];
563233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
564233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
565233d2500723e5594f3e7c70896ffeeef32b9c950ywan
566233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (i = 0; i < si->layers; ++i) {
567233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (total > 0) {
568233d2500723e5594f3e7c70896ffeeef32b9c950ywan        enc_cfg->ss_target_bitrate[i] = (unsigned int)
569233d2500723e5594f3e7c70896ffeeef32b9c950ywan            (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total);
570233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
571233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
572233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
573233d2500723e5594f3e7c70896ffeeef32b9c950ywan
574233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // modify encoder configuration
575233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->ss_number_layers = si->layers;
576233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->ts_number_layers = 1;  // Temporal layers not used in this encoder.
577233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->kf_mode = VPX_KF_DISABLED;
578233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Lag in frames not currently supported
579233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->g_lag_in_frames = 0;
580233d2500723e5594f3e7c70896ffeeef32b9c950ywan
581233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // TODO(ivanmaltz): determine if these values need to be set explicitly for
582233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // svc, or if the normal default/override mechanism can be used
583233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_dropframe_thresh = 0;
584233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_end_usage = VPX_CBR;
585233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_resize_allowed = 0;
586233d2500723e5594f3e7c70896ffeeef32b9c950ywan
587233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (enc_cfg->g_pass == VPX_RC_ONE_PASS) {
588233d2500723e5594f3e7c70896ffeeef32b9c950ywan    enc_cfg->rc_min_quantizer = 33;
589233d2500723e5594f3e7c70896ffeeef32b9c950ywan    enc_cfg->rc_max_quantizer = 33;
590233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
591233d2500723e5594f3e7c70896ffeeef32b9c950ywan
592233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_undershoot_pct = 100;
593233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_overshoot_pct = 15;
594233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_buf_initial_sz = 500;
595233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_buf_optimal_sz = 600;
596233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->rc_buf_sz = 1000;
597233d2500723e5594f3e7c70896ffeeef32b9c950ywan  enc_cfg->g_error_resilient = 1;
598233d2500723e5594f3e7c70896ffeeef32b9c950ywan
599233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Initialize codec
600233d2500723e5594f3e7c70896ffeeef32b9c950ywan  res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
601233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (res != VPX_CODEC_OK) {
602233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
603233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return res;
604233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
605233d2500723e5594f3e7c70896ffeeef32b9c950ywan
606233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
607233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP8E_SET_CPUUSED, 1);
608233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP8E_SET_STATIC_THRESHOLD, 1);
609233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP8E_SET_NOISE_SENSITIVITY, 1);
610233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1);
611233d2500723e5594f3e7c70896ffeeef32b9c950ywan
612233d2500723e5594f3e7c70896ffeeef32b9c950ywan  max_intra_size_pct =
613233d2500723e5594f3e7c70896ffeeef32b9c950ywan      (int)(((double)enc_cfg->rc_buf_optimal_sz * 0.5) *
614233d2500723e5594f3e7c70896ffeeef32b9c950ywan            ((double)enc_cfg->g_timebase.den / enc_cfg->g_timebase.num) / 10.0);
615233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT,
616233d2500723e5594f3e7c70896ffeeef32b9c950ywan                    max_intra_size_pct);
617233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
618233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
619233d2500723e5594f3e7c70896ffeeef32b9c950ywan
620233d2500723e5594f3e7c70896ffeeef32b9c950ywan// SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h
621233d2500723e5594f3e7c70896ffeeef32b9c950ywan
622233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should reference the last frame
623233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define USE_LAST (1 << 0)
624233d2500723e5594f3e7c70896ffeeef32b9c950ywan
625233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should reference the alt ref frame
626233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define USE_ARF (1 << 1)
627233d2500723e5594f3e7c70896ffeeef32b9c950ywan
628233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should reference the golden frame
629233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define USE_GF (1 << 2)
630233d2500723e5594f3e7c70896ffeeef32b9c950ywan
631233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should copy current frame to the last frame buffer
632233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define UPDATE_LAST (1 << 3)
633233d2500723e5594f3e7c70896ffeeef32b9c950ywan
634233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should copy current frame to the alt ref frame buffer
635233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define UPDATE_ARF (1 << 4)
636233d2500723e5594f3e7c70896ffeeef32b9c950ywan
637233d2500723e5594f3e7c70896ffeeef32b9c950ywan// encoder should copy current frame to the golden frame
638233d2500723e5594f3e7c70896ffeeef32b9c950ywan#define UPDATE_GF (1 << 5)
639233d2500723e5594f3e7c70896ffeeef32b9c950ywan
640233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic int map_vp8_flags(int svc_flags) {
641233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int flags = 0;
642233d2500723e5594f3e7c70896ffeeef32b9c950ywan
643233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!(svc_flags & USE_LAST)) flags |= VP8_EFLAG_NO_REF_LAST;
644233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!(svc_flags & USE_ARF)) flags |= VP8_EFLAG_NO_REF_ARF;
645233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (!(svc_flags & USE_GF)) flags |= VP8_EFLAG_NO_REF_GF;
646233d2500723e5594f3e7c70896ffeeef32b9c950ywan
647233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_flags & UPDATE_LAST) {
648233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // last is updated automatically
649233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
650233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= VP8_EFLAG_NO_UPD_LAST;
651233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
652233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_flags & UPDATE_ARF) {
653233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= VP8_EFLAG_FORCE_ARF;
654233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
655233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= VP8_EFLAG_NO_UPD_ARF;
656233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
657233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_flags & UPDATE_GF) {
658233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= VP8_EFLAG_FORCE_GF;
659233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
660233d2500723e5594f3e7c70896ffeeef32b9c950ywan    flags |= VP8_EFLAG_NO_UPD_GF;
661233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
662233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return flags;
663233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
664233d2500723e5594f3e7c70896ffeeef32b9c950ywan
665233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void calculate_enc_frame_flags(SvcContext *svc_ctx) {
666233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF;
667233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
668233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const int is_keyframe = (si->frame_within_gop == 0);
669233d2500723e5594f3e7c70896ffeeef32b9c950ywan
670233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // keyframe layer zero is identical for all modes
671233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (is_keyframe && si->layer == 0) {
672233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->enc_frame_flags = VPX_EFLAG_FORCE_KF;
673233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return;
674233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
675233d2500723e5594f3e7c70896ffeeef32b9c950ywan
676233d2500723e5594f3e7c70896ffeeef32b9c950ywan  switch (svc_ctx->encoding_mode) {
677233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case ALT_INTER_LAYER_PREDICTION_IP:
678233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (si->layer == 0) {
679233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
680233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else if (is_keyframe) {
681233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (si->layer == si->layers - 1) {
682233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
683233d2500723e5594f3e7c70896ffeeef32b9c950ywan        } else {
684233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
685233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
686233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else {
687233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
688233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
689233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
690233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case INTER_LAYER_PREDICTION_I:
691233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (si->layer == 0) {
692233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
693233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else if (is_keyframe) {
694233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
695233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else {
696233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
697233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
698233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
699233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case INTER_LAYER_PREDICTION_IP:
700233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (si->layer == 0) {
701233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
702233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else if (is_keyframe) {
703233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
704233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else {
705233d2500723e5594f3e7c70896ffeeef32b9c950ywan        flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST);
706233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
707233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
708233d2500723e5594f3e7c70896ffeeef32b9c950ywan    case USE_GOLDEN_FRAME:
709233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) {
710233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (si->layer == 0) {
711233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST);
712233d2500723e5594f3e7c70896ffeeef32b9c950ywan        } else if (is_keyframe) {
713233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF);
714233d2500723e5594f3e7c70896ffeeef32b9c950ywan        } else {
715233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST);
716233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
717233d2500723e5594f3e7c70896ffeeef32b9c950ywan      } else {
718233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (si->layer == 0) {
719233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
720233d2500723e5594f3e7c70896ffeeef32b9c950ywan        } else if (is_keyframe) {
721233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_ARF | UPDATE_LAST);
722233d2500723e5594f3e7c70896ffeeef32b9c950ywan        } else {
723233d2500723e5594f3e7c70896ffeeef32b9c950ywan          flags = map_vp8_flags(USE_LAST | UPDATE_LAST);
724233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
725233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
726233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
727233d2500723e5594f3e7c70896ffeeef32b9c950ywan    default:
728233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n",
729233d2500723e5594f3e7c70896ffeeef32b9c950ywan              svc_ctx->encoding_mode);
730233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
731233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
732233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->enc_frame_flags = flags;
733233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
734233d2500723e5594f3e7c70896ffeeef32b9c950ywan
735233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
736233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                             int layer,
737233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                             unsigned int *width,
738233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                             unsigned int *height) {
739233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int w, h, index, num, den;
740233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
741233d2500723e5594f3e7c70896ffeeef32b9c950ywan
742233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) {
743233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
744233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
745233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM;
746233d2500723e5594f3e7c70896ffeeef32b9c950ywan
747233d2500723e5594f3e7c70896ffeeef32b9c950ywan  index = layer + VPX_SS_MAX_LAYERS - si->layers;
748233d2500723e5594f3e7c70896ffeeef32b9c950ywan  num = si->scaling_factor_num[index];
749233d2500723e5594f3e7c70896ffeeef32b9c950ywan  den = si->scaling_factor_den[index];
750233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM;
751233d2500723e5594f3e7c70896ffeeef32b9c950ywan
752233d2500723e5594f3e7c70896ffeeef32b9c950ywan  w = si->width * num / den;
753233d2500723e5594f3e7c70896ffeeef32b9c950ywan  h = si->height * num / den;
754233d2500723e5594f3e7c70896ffeeef32b9c950ywan
755233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // make height and width even to make chrome player happy
756233d2500723e5594f3e7c70896ffeeef32b9c950ywan  w += w % 2;
757233d2500723e5594f3e7c70896ffeeef32b9c950ywan  h += h % 2;
758233d2500723e5594f3e7c70896ffeeef32b9c950ywan
759233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *width = w;
760233d2500723e5594f3e7c70896ffeeef32b9c950ywan  *height = h;
761233d2500723e5594f3e7c70896ffeeef32b9c950ywan
762233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
763233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
764233d2500723e5594f3e7c70896ffeeef32b9c950ywan
765233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic void set_svc_parameters(SvcContext *svc_ctx,
766233d2500723e5594f3e7c70896ffeeef32b9c950ywan                               vpx_codec_ctx_t *codec_ctx) {
767233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int layer, layer_index;
768233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_svc_parameters_t svc_params;
769233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
770233d2500723e5594f3e7c70896ffeeef32b9c950ywan
771233d2500723e5594f3e7c70896ffeeef32b9c950ywan  memset(&svc_params, 0, sizeof(svc_params));
772233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_params.temporal_layer = 0;
773233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_params.spatial_layer = si->layer;
774233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_params.flags = si->enc_frame_flags;
775233d2500723e5594f3e7c70896ffeeef32b9c950ywan
776233d2500723e5594f3e7c70896ffeeef32b9c950ywan  layer = si->layer;
777233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
778233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->frame_within_gop == 0) {
779233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // layers 1 & 3 don't exist in this mode, use the higher one
780233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (layer == 0 || layer == 2) {
781233d2500723e5594f3e7c70896ffeeef32b9c950ywan      layer += 1;
782233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
783233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
784233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
785233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                   &svc_params.width,
786233d2500723e5594f3e7c70896ffeeef32b9c950ywan                                                   &svc_params.height)) {
787233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
788233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
789233d2500723e5594f3e7c70896ffeeef32b9c950ywan  layer_index = layer + VPX_SS_MAX_LAYERS - si->layers;
790233d2500723e5594f3e7c70896ffeeef32b9c950ywan
791233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) {
792233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (vpx_svc_is_keyframe(svc_ctx)) {
793233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.min_quantizer = si->quantizer_keyframe[layer_index];
794233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.max_quantizer = si->quantizer_keyframe[layer_index];
795233d2500723e5594f3e7c70896ffeeef32b9c950ywan    } else {
796233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.min_quantizer = si->quantizer[layer_index];
797233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.max_quantizer = si->quantizer[layer_index];
798233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
799233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
800233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
801233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
802233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
803233d2500723e5594f3e7c70896ffeeef32b9c950ywan
804233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_params.distance_from_i_frame = si->frame_within_gop;
805233d2500723e5594f3e7c70896ffeeef32b9c950ywan
806233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Use buffer i for layer i LST
807233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_params.lst_fb_idx = si->layer;
808233d2500723e5594f3e7c70896ffeeef32b9c950ywan
809233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // Use buffer i-1 for layer i Alt (Inter-layer prediction)
810233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si->layer != 0) {
811233d2500723e5594f3e7c70896ffeeef32b9c950ywan    const int use_higher_layer =
812233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
813233d2500723e5594f3e7c70896ffeeef32b9c950ywan        si->frame_within_gop == 0;
814233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1;
815233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
816233d2500723e5594f3e7c70896ffeeef32b9c950ywan
817233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) {
818233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_params.gld_fb_idx = si->layer + 1;
819233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
820233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES)
821233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.gld_fb_idx = svc_params.lst_fb_idx;
822233d2500723e5594f3e7c70896ffeeef32b9c950ywan    else
823233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer;
824233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
825233d2500723e5594f3e7c70896ffeeef32b9c950ywan
826233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n",
827233d2500723e5594f3e7c70896ffeeef32b9c950ywan          si->encode_frame_count, si->layer, svc_params.width,
828233d2500723e5594f3e7c70896ffeeef32b9c950ywan          svc_params.height, svc_params.min_quantizer);
829233d2500723e5594f3e7c70896ffeeef32b9c950ywan
830233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_params.flags == VPX_EFLAG_FORCE_KF) {
831233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n");
832233d2500723e5594f3e7c70896ffeeef32b9c950ywan  } else {
833233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(
834233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_ctx, SVC_LOG_DEBUG, "Using:    LST/GLD/ALT [%2d|%2d|%2d]\n",
835233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx,
836233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx,
837233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx);
838233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(
839233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n",
840233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx,
841233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx,
842233d2500723e5594f3e7c70896ffeeef32b9c950ywan        svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx);
843233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
844233d2500723e5594f3e7c70896ffeeef32b9c950ywan
845233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
846233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
847233d2500723e5594f3e7c70896ffeeef32b9c950ywan
848233d2500723e5594f3e7c70896ffeeef32b9c950ywan/**
849233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Encode a frame into multiple layers
850233d2500723e5594f3e7c70896ffeeef32b9c950ywan * Create a superframe containing the individual layers
851233d2500723e5594f3e7c70896ffeeef32b9c950ywan */
852233d2500723e5594f3e7c70896ffeeef32b9c950ywanvpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
853233d2500723e5594f3e7c70896ffeeef32b9c950ywan                               struct vpx_image *rawimg, vpx_codec_pts_t pts,
854233d2500723e5594f3e7c70896ffeeef32b9c950ywan                               int64_t duration, int deadline) {
855233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_err_t res;
856233d2500723e5594f3e7c70896ffeeef32b9c950ywan  vpx_codec_iter_t iter;
857233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const vpx_codec_cx_pkt_t *cx_pkt;
858233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *cx_layer_list = NULL;
859233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct LayerData *layer_data;
860233d2500723e5594f3e7c70896ffeeef32b9c950ywan  struct Superframe superframe;
861233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
862233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
863233d2500723e5594f3e7c70896ffeeef32b9c950ywan    return VPX_CODEC_INVALID_PARAM;
864233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
865233d2500723e5594f3e7c70896ffeeef32b9c950ywan
866233d2500723e5594f3e7c70896ffeeef32b9c950ywan  memset(&superframe, 0, sizeof(superframe));
867233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log_reset(svc_ctx);
868233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->rc_stats_buf_used = 0;
869233d2500723e5594f3e7c70896ffeeef32b9c950ywan
870233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->layers = svc_ctx->spatial_layers;
871233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si->frame_within_gop >= si->kf_dist ||
872233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->encode_frame_count == 0) {
873233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->frame_within_gop = 0;
874233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
875233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->is_keyframe = (si->frame_within_gop == 0);
876233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->frame_size = 0;
877233d2500723e5594f3e7c70896ffeeef32b9c950ywan
878233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (rawimg != NULL) {
879233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_DEBUG,
880233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "vpx_svc_encode  layers: %d, frame_count: %d, "
881233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "frame_within_gop: %d\n", si->layers, si->encode_frame_count,
882233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->frame_within_gop);
883233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
884233d2500723e5594f3e7c70896ffeeef32b9c950ywan
885233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // encode each layer
886233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (si->layer = 0; si->layer < si->layers; ++si->layer) {
887233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
888233d2500723e5594f3e7c70896ffeeef32b9c950ywan        si->is_keyframe && (si->layer == 1 || si->layer == 3)) {
889233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer);
890233d2500723e5594f3e7c70896ffeeef32b9c950ywan      continue;
891233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
892233d2500723e5594f3e7c70896ffeeef32b9c950ywan
893233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawimg != NULL) {
894233d2500723e5594f3e7c70896ffeeef32b9c950ywan      calculate_enc_frame_flags(svc_ctx);
895233d2500723e5594f3e7c70896ffeeef32b9c950ywan      set_svc_parameters(svc_ctx, codec_ctx);
896233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
897233d2500723e5594f3e7c70896ffeeef32b9c950ywan
898233d2500723e5594f3e7c70896ffeeef32b9c950ywan    res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration,
899233d2500723e5594f3e7c70896ffeeef32b9c950ywan                           si->enc_frame_flags, deadline);
900233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (res != VPX_CODEC_OK) {
901233d2500723e5594f3e7c70896ffeeef32b9c950ywan      return res;
902233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
903233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // save compressed data
904233d2500723e5594f3e7c70896ffeeef32b9c950ywan    iter = NULL;
905233d2500723e5594f3e7c70896ffeeef32b9c950ywan    while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
906233d2500723e5594f3e7c70896ffeeef32b9c950ywan      switch (cx_pkt->kind) {
907233d2500723e5594f3e7c70896ffeeef32b9c950ywan        case VPX_CODEC_CX_FRAME_PKT: {
908233d2500723e5594f3e7c70896ffeeef32b9c950ywan          const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz);
909233d2500723e5594f3e7c70896ffeeef32b9c950ywan          si->bytes_sum[si->layer] += frame_pkt_size;
910233d2500723e5594f3e7c70896ffeeef32b9c950ywan          svc_log(svc_ctx, SVC_LOG_DEBUG,
911233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  "SVC frame: %d, layer: %d, size: %u\n",
912233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  si->encode_frame_count, si->layer, frame_pkt_size);
913233d2500723e5594f3e7c70896ffeeef32b9c950ywan          layer_data =
914233d2500723e5594f3e7c70896ffeeef32b9c950ywan              ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size);
915233d2500723e5594f3e7c70896ffeeef32b9c950ywan          if (layer_data == NULL) {
916233d2500723e5594f3e7c70896ffeeef32b9c950ywan            svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n");
917233d2500723e5594f3e7c70896ffeeef32b9c950ywan            return VPX_CODEC_OK;
918233d2500723e5594f3e7c70896ffeeef32b9c950ywan          }
919233d2500723e5594f3e7c70896ffeeef32b9c950ywan          ld_list_add(&cx_layer_list, layer_data);
920233d2500723e5594f3e7c70896ffeeef32b9c950ywan
921233d2500723e5594f3e7c70896ffeeef32b9c950ywan          // save layer size in superframe index
922233d2500723e5594f3e7c70896ffeeef32b9c950ywan          superframe.sizes[superframe.count++] = frame_pkt_size;
923233d2500723e5594f3e7c70896ffeeef32b9c950ywan          superframe.magnitude |= frame_pkt_size;
924233d2500723e5594f3e7c70896ffeeef32b9c950ywan          break;
925233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
926233d2500723e5594f3e7c70896ffeeef32b9c950ywan        case VPX_CODEC_PSNR_PKT: {
927233d2500723e5594f3e7c70896ffeeef32b9c950ywan          int i;
928233d2500723e5594f3e7c70896ffeeef32b9c950ywan          svc_log(svc_ctx, SVC_LOG_DEBUG,
929233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
930233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
931233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  si->encode_frame_count, si->layer,
932233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1],
933233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]);
934233d2500723e5594f3e7c70896ffeeef32b9c950ywan          svc_log(svc_ctx, SVC_LOG_DEBUG,
935233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): "
936233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  "%2.3f  %2.3f  %2.3f  %2.3f \n",
937233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  si->encode_frame_count, si->layer,
938233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1],
939233d2500723e5594f3e7c70896ffeeef32b9c950ywan                  cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]);
940233d2500723e5594f3e7c70896ffeeef32b9c950ywan          for (i = 0; i < COMPONENTS; i++) {
941233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->psnr_sum[si->layer][i] += cx_pkt->data.psnr.psnr[i];
942233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->sse_sum[si->layer][i] += cx_pkt->data.psnr.sse[i];
943233d2500723e5594f3e7c70896ffeeef32b9c950ywan          }
944233d2500723e5594f3e7c70896ffeeef32b9c950ywan          break;
945233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
946233d2500723e5594f3e7c70896ffeeef32b9c950ywan        case VPX_CODEC_STATS_PKT: {
947233d2500723e5594f3e7c70896ffeeef32b9c950ywan          size_t new_size = si->rc_stats_buf_used +
948233d2500723e5594f3e7c70896ffeeef32b9c950ywan              cx_pkt->data.twopass_stats.sz;
949233d2500723e5594f3e7c70896ffeeef32b9c950ywan
950233d2500723e5594f3e7c70896ffeeef32b9c950ywan          if (new_size > si->rc_stats_buf_size) {
951233d2500723e5594f3e7c70896ffeeef32b9c950ywan            char *p = (char*)realloc(si->rc_stats_buf, new_size);
952233d2500723e5594f3e7c70896ffeeef32b9c950ywan            if (p == NULL) {
953233d2500723e5594f3e7c70896ffeeef32b9c950ywan              svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n");
954233d2500723e5594f3e7c70896ffeeef32b9c950ywan              break;
955233d2500723e5594f3e7c70896ffeeef32b9c950ywan            }
956233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->rc_stats_buf = p;
957233d2500723e5594f3e7c70896ffeeef32b9c950ywan            si->rc_stats_buf_size = new_size;
958233d2500723e5594f3e7c70896ffeeef32b9c950ywan          }
959233d2500723e5594f3e7c70896ffeeef32b9c950ywan
960233d2500723e5594f3e7c70896ffeeef32b9c950ywan          memcpy(si->rc_stats_buf + si->rc_stats_buf_used,
961233d2500723e5594f3e7c70896ffeeef32b9c950ywan                 cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz);
962233d2500723e5594f3e7c70896ffeeef32b9c950ywan          si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz;
963233d2500723e5594f3e7c70896ffeeef32b9c950ywan          break;
964233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
965233d2500723e5594f3e7c70896ffeeef32b9c950ywan        default: {
966233d2500723e5594f3e7c70896ffeeef32b9c950ywan          break;
967233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
968233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
969233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
970233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (rawimg == NULL) {
971233d2500723e5594f3e7c70896ffeeef32b9c950ywan      break;
972233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
973233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
974233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (codec_ctx->config.enc->g_pass != VPX_RC_FIRST_PASS) {
975233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // add superframe index to layer data list
976233d2500723e5594f3e7c70896ffeeef32b9c950ywan    sf_create_index(&superframe);
977233d2500723e5594f3e7c70896ffeeef32b9c950ywan    layer_data = ld_create(superframe.buffer, superframe.index_size);
978233d2500723e5594f3e7c70896ffeeef32b9c950ywan    ld_list_add(&cx_layer_list, layer_data);
979233d2500723e5594f3e7c70896ffeeef32b9c950ywan
980233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // get accumulated size of layer data
981233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->frame_size = ld_list_get_buffer_size(cx_layer_list);
982233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (si->frame_size > 0) {
983233d2500723e5594f3e7c70896ffeeef32b9c950ywan      // all layers encoded, create single buffer with concatenated layers
984233d2500723e5594f3e7c70896ffeeef32b9c950ywan      if (si->frame_size > si->buffer_size) {
985233d2500723e5594f3e7c70896ffeeef32b9c950ywan        free(si->buffer);
986233d2500723e5594f3e7c70896ffeeef32b9c950ywan        si->buffer = malloc(si->frame_size);
987233d2500723e5594f3e7c70896ffeeef32b9c950ywan        if (si->buffer == NULL) {
988233d2500723e5594f3e7c70896ffeeef32b9c950ywan          ld_list_free(cx_layer_list);
989233d2500723e5594f3e7c70896ffeeef32b9c950ywan          return VPX_CODEC_MEM_ERROR;
990233d2500723e5594f3e7c70896ffeeef32b9c950ywan        }
991233d2500723e5594f3e7c70896ffeeef32b9c950ywan        si->buffer_size = si->frame_size;
992233d2500723e5594f3e7c70896ffeeef32b9c950ywan      }
993233d2500723e5594f3e7c70896ffeeef32b9c950ywan      // copy layer data into packet
994233d2500723e5594f3e7c70896ffeeef32b9c950ywan      ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)si->buffer);
995233d2500723e5594f3e7c70896ffeeef32b9c950ywan
996233d2500723e5594f3e7c70896ffeeef32b9c950ywan      ld_list_free(cx_layer_list);
997233d2500723e5594f3e7c70896ffeeef32b9c950ywan
998233d2500723e5594f3e7c70896ffeeef32b9c950ywan      svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, "
999233d2500723e5594f3e7c70896ffeeef32b9c950ywan              "pts: %d\n", si->encode_frame_count, si->is_keyframe,
1000233d2500723e5594f3e7c70896ffeeef32b9c950ywan              (int)si->frame_size, (int)pts);
1001233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
1002233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
1003233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ++si->frame_within_gop;
1004233d2500723e5594f3e7c70896ffeeef32b9c950ywan  ++si->encode_frame_count;
1005233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1006233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return VPX_CODEC_OK;
1007233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1008233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1009233d2500723e5594f3e7c70896ffeeef32b9c950ywanconst char *vpx_svc_get_message(const SvcContext *svc_ctx) {
1010233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1011233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return NULL;
1012233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->message_buffer;
1013233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1014233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1015233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid *vpx_svc_get_buffer(const SvcContext *svc_ctx) {
1016233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1017233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return NULL;
1018233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->buffer;
1019233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1020233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1021233d2500723e5594f3e7c70896ffeeef32b9c950ywansize_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) {
1022233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1023233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return 0;
1024233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->frame_size;
1025233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1026233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1027233d2500723e5594f3e7c70896ffeeef32b9c950ywanint vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) {
1028233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1029233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return 0;
1030233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->encode_frame_count;
1031233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1032233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1033233d2500723e5594f3e7c70896ffeeef32b9c950ywanint vpx_svc_is_keyframe(const SvcContext *svc_ctx) {
1034233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1035233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return 0;
1036233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->is_keyframe;
1037233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1038233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1039233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid vpx_svc_set_keyframe(SvcContext *svc_ctx) {
1040233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
1041233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return;
1042233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->frame_within_gop = 0;
1043233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1044233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1045233d2500723e5594f3e7c70896ffeeef32b9c950ywanstatic double calc_psnr(double d) {
1046233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (d == 0) return 100;
1047233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return -10.0 * log(d) / log(10.0);
1048233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1049233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1050233d2500723e5594f3e7c70896ffeeef32b9c950ywan// dump accumulated statistics and reset accumulated values
1051233d2500723e5594f3e7c70896ffeeef32b9c950ywanconst char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
1052233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int number_of_frames, number_of_keyframes, encode_frame_count;
1053233d2500723e5594f3e7c70896ffeeef32b9c950ywan  int i, j;
1054233d2500723e5594f3e7c70896ffeeef32b9c950ywan  uint32_t bytes_total = 0;
1055233d2500723e5594f3e7c70896ffeeef32b9c950ywan  double scale[COMPONENTS];
1056233d2500723e5594f3e7c70896ffeeef32b9c950ywan  double psnr[COMPONENTS];
1057233d2500723e5594f3e7c70896ffeeef32b9c950ywan  double mse[COMPONENTS];
1058233d2500723e5594f3e7c70896ffeeef32b9c950ywan  double y_scale;
1059233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1060233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *const si = get_svc_internal(svc_ctx);
1061233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return NULL;
1062233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1063233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log_reset(svc_ctx);
1064233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1065233d2500723e5594f3e7c70896ffeeef32b9c950ywan  encode_frame_count = si->encode_frame_count;
1066233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx);
1067233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1068233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log(svc_ctx, SVC_LOG_INFO, "\n");
1069233d2500723e5594f3e7c70896ffeeef32b9c950ywan  number_of_keyframes = encode_frame_count / si->kf_dist + 1;
1070233d2500723e5594f3e7c70896ffeeef32b9c950ywan  for (i = 0; i < si->layers; ++i) {
1071233d2500723e5594f3e7c70896ffeeef32b9c950ywan    number_of_frames = encode_frame_count;
1072233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1073233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP &&
1074233d2500723e5594f3e7c70896ffeeef32b9c950ywan        (i == 1 || i == 3)) {
1075233d2500723e5594f3e7c70896ffeeef32b9c950ywan      number_of_frames -= number_of_keyframes;
1076233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
1077233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_INFO,
1078233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
1079233d2500723e5594f3e7c70896ffeeef32b9c950ywan            i, (double)si->psnr_sum[i][0] / number_of_frames,
1080233d2500723e5594f3e7c70896ffeeef32b9c950ywan            (double)si->psnr_sum[i][1] / number_of_frames,
1081233d2500723e5594f3e7c70896ffeeef32b9c950ywan            (double)si->psnr_sum[i][2] / number_of_frames,
1082233d2500723e5594f3e7c70896ffeeef32b9c950ywan            (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
1083233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // the following psnr calculation is deduced from ffmpeg.c#print_report
1084233d2500723e5594f3e7c70896ffeeef32b9c950ywan    y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
1085233d2500723e5594f3e7c70896ffeeef32b9c950ywan    scale[1] = y_scale;
1086233d2500723e5594f3e7c70896ffeeef32b9c950ywan    scale[2] = scale[3] = y_scale / 4;  // U or V
1087233d2500723e5594f3e7c70896ffeeef32b9c950ywan    scale[0] = y_scale * 1.5;           // total
1088233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1089233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (j = 0; j < COMPONENTS; j++) {
1090233d2500723e5594f3e7c70896ffeeef32b9c950ywan      psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
1091233d2500723e5594f3e7c70896ffeeef32b9c950ywan      mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
1092233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
1093233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_INFO,
1094233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
1095233d2500723e5594f3e7c70896ffeeef32b9c950ywan            psnr[1], psnr[2], psnr[3]);
1096233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_log(svc_ctx, SVC_LOG_INFO,
1097233d2500723e5594f3e7c70896ffeeef32b9c950ywan            "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
1098233d2500723e5594f3e7c70896ffeeef32b9c950ywan            mse[1], mse[2], mse[3]);
1099233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1100233d2500723e5594f3e7c70896ffeeef32b9c950ywan    bytes_total += si->bytes_sum[i];
1101233d2500723e5594f3e7c70896ffeeef32b9c950ywan    // clear sums for next time
1102233d2500723e5594f3e7c70896ffeeef32b9c950ywan    si->bytes_sum[i] = 0;
1103233d2500723e5594f3e7c70896ffeeef32b9c950ywan    for (j = 0; j < COMPONENTS; ++j) {
1104233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->psnr_sum[i][j] = 0;
1105233d2500723e5594f3e7c70896ffeeef32b9c950ywan      si->sse_sum[i][j] = 0;
1106233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
1107233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
1108233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1109233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // only display statistics once
1110233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si->encode_frame_count = 0;
1111233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1112233d2500723e5594f3e7c70896ffeeef32b9c950ywan  svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
1113233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return vpx_svc_get_message(svc_ctx);
1114233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1115233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1116233d2500723e5594f3e7c70896ffeeef32b9c950ywanvoid vpx_svc_release(SvcContext *svc_ctx) {
1117233d2500723e5594f3e7c70896ffeeef32b9c950ywan  SvcInternal *si;
1118233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL) return;
1119233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // do not use get_svc_internal as it will unnecessarily allocate an
1120233d2500723e5594f3e7c70896ffeeef32b9c950ywan  // SvcInternal if it was not already allocated
1121233d2500723e5594f3e7c70896ffeeef32b9c950ywan  si = (SvcInternal *)svc_ctx->internal;
1122233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (si != NULL) {
1123233d2500723e5594f3e7c70896ffeeef32b9c950ywan    free(si->buffer);
1124233d2500723e5594f3e7c70896ffeeef32b9c950ywan    if (si->rc_stats_buf) {
1125233d2500723e5594f3e7c70896ffeeef32b9c950ywan      free(si->rc_stats_buf);
1126233d2500723e5594f3e7c70896ffeeef32b9c950ywan    }
1127233d2500723e5594f3e7c70896ffeeef32b9c950ywan    free(si);
1128233d2500723e5594f3e7c70896ffeeef32b9c950ywan    svc_ctx->internal = NULL;
1129233d2500723e5594f3e7c70896ffeeef32b9c950ywan  }
1130233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1131233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1132233d2500723e5594f3e7c70896ffeeef32b9c950ywansize_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) {
1133233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1134233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return 0;
1135233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->rc_stats_buf_used;
1136233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1137233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1138233d2500723e5594f3e7c70896ffeeef32b9c950ywanchar *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) {
1139233d2500723e5594f3e7c70896ffeeef32b9c950ywan  const SvcInternal *const si = get_const_svc_internal(svc_ctx);
1140233d2500723e5594f3e7c70896ffeeef32b9c950ywan  if (svc_ctx == NULL || si == NULL) return NULL;
1141233d2500723e5594f3e7c70896ffeeef32b9c950ywan  return si->rc_stats_buf;
1142233d2500723e5594f3e7c70896ffeeef32b9c950ywan}
1143233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1144233d2500723e5594f3e7c70896ffeeef32b9c950ywan
1145