1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker * Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker *
4*fb1b10abSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker */
10*fb1b10abSAndroid Build Coastguard Worker
11*fb1b10abSAndroid Build Coastguard Worker /**
12*fb1b10abSAndroid Build Coastguard Worker * @file
13*fb1b10abSAndroid Build Coastguard Worker * VP9 SVC encoding support via libvpx
14*fb1b10abSAndroid Build Coastguard Worker */
15*fb1b10abSAndroid Build Coastguard Worker
16*fb1b10abSAndroid Build Coastguard Worker #include <assert.h>
17*fb1b10abSAndroid Build Coastguard Worker #include <math.h>
18*fb1b10abSAndroid Build Coastguard Worker #include <limits.h>
19*fb1b10abSAndroid Build Coastguard Worker #include <stdarg.h>
20*fb1b10abSAndroid Build Coastguard Worker #include <stdio.h>
21*fb1b10abSAndroid Build Coastguard Worker #include <stdlib.h>
22*fb1b10abSAndroid Build Coastguard Worker #include <string.h>
23*fb1b10abSAndroid Build Coastguard Worker #define VPX_DISABLE_CTRL_TYPECHECKS 1
24*fb1b10abSAndroid Build Coastguard Worker #include "../tools_common.h"
25*fb1b10abSAndroid Build Coastguard Worker #include "./vpx_config.h"
26*fb1b10abSAndroid Build Coastguard Worker #include "./svc_context.h"
27*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vp8cx.h"
28*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_encoder.h"
29*fb1b10abSAndroid Build Coastguard Worker #include "vpx_mem/vpx_mem.h"
30*fb1b10abSAndroid Build Coastguard Worker #include "vp9/common/vp9_onyxc_int.h"
31*fb1b10abSAndroid Build Coastguard Worker
32*fb1b10abSAndroid Build Coastguard Worker #ifdef __MINGW32__
33*fb1b10abSAndroid Build Coastguard Worker #define strtok_r strtok_s
34*fb1b10abSAndroid Build Coastguard Worker #ifndef MINGW_HAS_SECURE_API
35*fb1b10abSAndroid Build Coastguard Worker // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
36*fb1b10abSAndroid Build Coastguard Worker _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
37*fb1b10abSAndroid Build Coastguard Worker #endif /* MINGW_HAS_SECURE_API */
38*fb1b10abSAndroid Build Coastguard Worker #endif /* __MINGW32__ */
39*fb1b10abSAndroid Build Coastguard Worker
40*fb1b10abSAndroid Build Coastguard Worker #ifdef _MSC_VER
41*fb1b10abSAndroid Build Coastguard Worker #define strdup _strdup
42*fb1b10abSAndroid Build Coastguard Worker #define strtok_r strtok_s
43*fb1b10abSAndroid Build Coastguard Worker #endif
44*fb1b10abSAndroid Build Coastguard Worker
45*fb1b10abSAndroid Build Coastguard Worker #define SVC_REFERENCE_FRAMES 8
46*fb1b10abSAndroid Build Coastguard Worker #define SUPERFRAME_SLOTS (8)
47*fb1b10abSAndroid Build Coastguard Worker #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
48*fb1b10abSAndroid Build Coastguard Worker
49*fb1b10abSAndroid Build Coastguard Worker #define MAX_QUANTIZER 63
50*fb1b10abSAndroid Build Coastguard Worker
51*fb1b10abSAndroid Build Coastguard Worker static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = { 4, 5, 7, 11,
52*fb1b10abSAndroid Build Coastguard Worker 16 };
53*fb1b10abSAndroid Build Coastguard Worker
54*fb1b10abSAndroid Build Coastguard Worker static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = { 16, 16, 16,
55*fb1b10abSAndroid Build Coastguard Worker 16, 16 };
56*fb1b10abSAndroid Build Coastguard Worker
57*fb1b10abSAndroid Build Coastguard Worker static const int DEFAULT_SCALE_FACTORS_NUM_2x[VPX_SS_MAX_LAYERS] = { 1, 2, 4 };
58*fb1b10abSAndroid Build Coastguard Worker
59*fb1b10abSAndroid Build Coastguard Worker static const int DEFAULT_SCALE_FACTORS_DEN_2x[VPX_SS_MAX_LAYERS] = { 4, 4, 4 };
60*fb1b10abSAndroid Build Coastguard Worker
61*fb1b10abSAndroid Build Coastguard Worker typedef enum {
62*fb1b10abSAndroid Build Coastguard Worker QUANTIZER = 0,
63*fb1b10abSAndroid Build Coastguard Worker BITRATE,
64*fb1b10abSAndroid Build Coastguard Worker SCALE_FACTOR,
65*fb1b10abSAndroid Build Coastguard Worker AUTO_ALT_REF,
66*fb1b10abSAndroid Build Coastguard Worker ALL_OPTION_TYPES
67*fb1b10abSAndroid Build Coastguard Worker } LAYER_OPTION_TYPE;
68*fb1b10abSAndroid Build Coastguard Worker
69*fb1b10abSAndroid Build Coastguard Worker static const int option_max_values[ALL_OPTION_TYPES] = { 63, INT_MAX, INT_MAX,
70*fb1b10abSAndroid Build Coastguard Worker 1 };
71*fb1b10abSAndroid Build Coastguard Worker
72*fb1b10abSAndroid Build Coastguard Worker static const int option_min_values[ALL_OPTION_TYPES] = { 0, 0, 1, 0 };
73*fb1b10abSAndroid Build Coastguard Worker
74*fb1b10abSAndroid Build Coastguard Worker // One encoded frame
75*fb1b10abSAndroid Build Coastguard Worker typedef struct FrameData {
76*fb1b10abSAndroid Build Coastguard Worker void *buf; // compressed data buffer
77*fb1b10abSAndroid Build Coastguard Worker size_t size; // length of compressed data
78*fb1b10abSAndroid Build Coastguard Worker vpx_codec_frame_flags_t flags; /**< flags for this frame */
79*fb1b10abSAndroid Build Coastguard Worker struct FrameData *next;
80*fb1b10abSAndroid Build Coastguard Worker } FrameData;
81*fb1b10abSAndroid Build Coastguard Worker
get_svc_internal(SvcContext * svc_ctx)82*fb1b10abSAndroid Build Coastguard Worker static SvcInternal_t *get_svc_internal(SvcContext *svc_ctx) {
83*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL) return NULL;
84*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->internal == NULL) {
85*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = (SvcInternal_t *)malloc(sizeof(*si));
86*fb1b10abSAndroid Build Coastguard Worker if (si != NULL) {
87*fb1b10abSAndroid Build Coastguard Worker memset(si, 0, sizeof(*si));
88*fb1b10abSAndroid Build Coastguard Worker }
89*fb1b10abSAndroid Build Coastguard Worker svc_ctx->internal = si;
90*fb1b10abSAndroid Build Coastguard Worker }
91*fb1b10abSAndroid Build Coastguard Worker return (SvcInternal_t *)svc_ctx->internal;
92*fb1b10abSAndroid Build Coastguard Worker }
93*fb1b10abSAndroid Build Coastguard Worker
get_const_svc_internal(const SvcContext * svc_ctx)94*fb1b10abSAndroid Build Coastguard Worker static const SvcInternal_t *get_const_svc_internal(const SvcContext *svc_ctx) {
95*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL) return NULL;
96*fb1b10abSAndroid Build Coastguard Worker return (const SvcInternal_t *)svc_ctx->internal;
97*fb1b10abSAndroid Build Coastguard Worker }
98*fb1b10abSAndroid Build Coastguard Worker
svc_log(SvcContext * svc_ctx,SVC_LOG_LEVEL level,const char * fmt,...)99*fb1b10abSAndroid Build Coastguard Worker static VPX_TOOLS_FORMAT_PRINTF(3, 4) int svc_log(SvcContext *svc_ctx,
100*fb1b10abSAndroid Build Coastguard Worker SVC_LOG_LEVEL level,
101*fb1b10abSAndroid Build Coastguard Worker const char *fmt, ...) {
102*fb1b10abSAndroid Build Coastguard Worker char buf[512];
103*fb1b10abSAndroid Build Coastguard Worker int retval = 0;
104*fb1b10abSAndroid Build Coastguard Worker va_list ap;
105*fb1b10abSAndroid Build Coastguard Worker
106*fb1b10abSAndroid Build Coastguard Worker if (level > svc_ctx->log_level) {
107*fb1b10abSAndroid Build Coastguard Worker return retval;
108*fb1b10abSAndroid Build Coastguard Worker }
109*fb1b10abSAndroid Build Coastguard Worker
110*fb1b10abSAndroid Build Coastguard Worker va_start(ap, fmt);
111*fb1b10abSAndroid Build Coastguard Worker retval = vsnprintf(buf, sizeof(buf), fmt, ap);
112*fb1b10abSAndroid Build Coastguard Worker va_end(ap);
113*fb1b10abSAndroid Build Coastguard Worker
114*fb1b10abSAndroid Build Coastguard Worker printf("%s", buf);
115*fb1b10abSAndroid Build Coastguard Worker
116*fb1b10abSAndroid Build Coastguard Worker return retval;
117*fb1b10abSAndroid Build Coastguard Worker }
118*fb1b10abSAndroid Build Coastguard Worker
extract_option(LAYER_OPTION_TYPE type,char * input,int * value0,int * value1)119*fb1b10abSAndroid Build Coastguard Worker static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type, char *input,
120*fb1b10abSAndroid Build Coastguard Worker int *value0, int *value1) {
121*fb1b10abSAndroid Build Coastguard Worker if (type == SCALE_FACTOR) {
122*fb1b10abSAndroid Build Coastguard Worker *value0 = (int)strtol(input, &input, 10);
123*fb1b10abSAndroid Build Coastguard Worker if (*input++ != '/') return VPX_CODEC_INVALID_PARAM;
124*fb1b10abSAndroid Build Coastguard Worker *value1 = (int)strtol(input, &input, 10);
125*fb1b10abSAndroid Build Coastguard Worker
126*fb1b10abSAndroid Build Coastguard Worker if (*value0 < option_min_values[SCALE_FACTOR] ||
127*fb1b10abSAndroid Build Coastguard Worker *value1 < option_min_values[SCALE_FACTOR] ||
128*fb1b10abSAndroid Build Coastguard Worker *value0 > option_max_values[SCALE_FACTOR] ||
129*fb1b10abSAndroid Build Coastguard Worker *value1 > option_max_values[SCALE_FACTOR] ||
130*fb1b10abSAndroid Build Coastguard Worker *value0 > *value1) // num shouldn't be greater than den
131*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
132*fb1b10abSAndroid Build Coastguard Worker } else {
133*fb1b10abSAndroid Build Coastguard Worker *value0 = atoi(input);
134*fb1b10abSAndroid Build Coastguard Worker if (*value0 < option_min_values[type] || *value0 > option_max_values[type])
135*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
136*fb1b10abSAndroid Build Coastguard Worker }
137*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_OK;
138*fb1b10abSAndroid Build Coastguard Worker }
139*fb1b10abSAndroid Build Coastguard Worker
parse_layer_options_from_string(SvcContext * svc_ctx,LAYER_OPTION_TYPE type,const char * input,int * option0,int * option1)140*fb1b10abSAndroid Build Coastguard Worker static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
141*fb1b10abSAndroid Build Coastguard Worker LAYER_OPTION_TYPE type,
142*fb1b10abSAndroid Build Coastguard Worker const char *input,
143*fb1b10abSAndroid Build Coastguard Worker int *option0,
144*fb1b10abSAndroid Build Coastguard Worker int *option1) {
145*fb1b10abSAndroid Build Coastguard Worker int i;
146*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t res = VPX_CODEC_OK;
147*fb1b10abSAndroid Build Coastguard Worker char *input_string;
148*fb1b10abSAndroid Build Coastguard Worker char *token;
149*fb1b10abSAndroid Build Coastguard Worker const char *delim = ",";
150*fb1b10abSAndroid Build Coastguard Worker char *save_ptr;
151*fb1b10abSAndroid Build Coastguard Worker int num_layers = svc_ctx->spatial_layers;
152*fb1b10abSAndroid Build Coastguard Worker if (type == BITRATE)
153*fb1b10abSAndroid Build Coastguard Worker num_layers = svc_ctx->spatial_layers * svc_ctx->temporal_layers;
154*fb1b10abSAndroid Build Coastguard Worker
155*fb1b10abSAndroid Build Coastguard Worker if (input == NULL || option0 == NULL ||
156*fb1b10abSAndroid Build Coastguard Worker (option1 == NULL && type == SCALE_FACTOR))
157*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
158*fb1b10abSAndroid Build Coastguard Worker
159*fb1b10abSAndroid Build Coastguard Worker input_string = strdup(input);
160*fb1b10abSAndroid Build Coastguard Worker if (input_string == NULL) return VPX_CODEC_MEM_ERROR;
161*fb1b10abSAndroid Build Coastguard Worker token = strtok_r(input_string, delim, &save_ptr);
162*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < num_layers; ++i) {
163*fb1b10abSAndroid Build Coastguard Worker if (token != NULL) {
164*fb1b10abSAndroid Build Coastguard Worker res = extract_option(type, token, option0 + i, option1 + i);
165*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
166*fb1b10abSAndroid Build Coastguard Worker token = strtok_r(NULL, delim, &save_ptr);
167*fb1b10abSAndroid Build Coastguard Worker } else {
168*fb1b10abSAndroid Build Coastguard Worker break;
169*fb1b10abSAndroid Build Coastguard Worker }
170*fb1b10abSAndroid Build Coastguard Worker }
171*fb1b10abSAndroid Build Coastguard Worker if (res == VPX_CODEC_OK && i != num_layers) {
172*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR,
173*fb1b10abSAndroid Build Coastguard Worker "svc: layer params type: %d %d values required, "
174*fb1b10abSAndroid Build Coastguard Worker "but only %d specified\n",
175*fb1b10abSAndroid Build Coastguard Worker type, num_layers, i);
176*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
177*fb1b10abSAndroid Build Coastguard Worker }
178*fb1b10abSAndroid Build Coastguard Worker free(input_string);
179*fb1b10abSAndroid Build Coastguard Worker return res;
180*fb1b10abSAndroid Build Coastguard Worker }
181*fb1b10abSAndroid Build Coastguard Worker
182*fb1b10abSAndroid Build Coastguard Worker /**
183*fb1b10abSAndroid Build Coastguard Worker * Parse SVC encoding options
184*fb1b10abSAndroid Build Coastguard Worker * Format: encoding-mode=<svc_mode>,layers=<layer_count>
185*fb1b10abSAndroid Build Coastguard Worker * scale-factors=<n1>/<d1>,<n2>/<d2>,...
186*fb1b10abSAndroid Build Coastguard Worker * quantizers=<q1>,<q2>,...
187*fb1b10abSAndroid Build Coastguard Worker * svc_mode = [i|ip|alt_ip|gf]
188*fb1b10abSAndroid Build Coastguard Worker */
parse_options(SvcContext * svc_ctx,const char * options)189*fb1b10abSAndroid Build Coastguard Worker static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
190*fb1b10abSAndroid Build Coastguard Worker char *input_string;
191*fb1b10abSAndroid Build Coastguard Worker char *option_name;
192*fb1b10abSAndroid Build Coastguard Worker char *option_value;
193*fb1b10abSAndroid Build Coastguard Worker char *input_ptr = NULL;
194*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = get_svc_internal(svc_ctx);
195*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t res = VPX_CODEC_OK;
196*fb1b10abSAndroid Build Coastguard Worker int i, alt_ref_enabled = 0;
197*fb1b10abSAndroid Build Coastguard Worker
198*fb1b10abSAndroid Build Coastguard Worker if (options == NULL) return VPX_CODEC_OK;
199*fb1b10abSAndroid Build Coastguard Worker input_string = strdup(options);
200*fb1b10abSAndroid Build Coastguard Worker if (input_string == NULL) return VPX_CODEC_MEM_ERROR;
201*fb1b10abSAndroid Build Coastguard Worker
202*fb1b10abSAndroid Build Coastguard Worker // parse option name
203*fb1b10abSAndroid Build Coastguard Worker option_name = strtok_r(input_string, "=", &input_ptr);
204*fb1b10abSAndroid Build Coastguard Worker while (option_name != NULL) {
205*fb1b10abSAndroid Build Coastguard Worker // parse option value
206*fb1b10abSAndroid Build Coastguard Worker option_value = strtok_r(NULL, " ", &input_ptr);
207*fb1b10abSAndroid Build Coastguard Worker if (option_value == NULL) {
208*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
209*fb1b10abSAndroid Build Coastguard Worker option_name);
210*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
211*fb1b10abSAndroid Build Coastguard Worker break;
212*fb1b10abSAndroid Build Coastguard Worker }
213*fb1b10abSAndroid Build Coastguard Worker if (strcmp("spatial-layers", option_name) == 0) {
214*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers = atoi(option_value);
215*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("temporal-layers", option_name) == 0) {
216*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layers = atoi(option_value);
217*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("scale-factors", option_name) == 0) {
218*fb1b10abSAndroid Build Coastguard Worker res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
219*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_num,
220*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_den);
221*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
222*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("max-quantizers", option_name) == 0) {
223*fb1b10abSAndroid Build Coastguard Worker res =
224*fb1b10abSAndroid Build Coastguard Worker parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
225*fb1b10abSAndroid Build Coastguard Worker si->svc_params.max_quantizers, NULL);
226*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
227*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("min-quantizers", option_name) == 0) {
228*fb1b10abSAndroid Build Coastguard Worker res =
229*fb1b10abSAndroid Build Coastguard Worker parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
230*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers, NULL);
231*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
232*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("auto-alt-refs", option_name) == 0) {
233*fb1b10abSAndroid Build Coastguard Worker res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
234*fb1b10abSAndroid Build Coastguard Worker si->enable_auto_alt_ref, NULL);
235*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
236*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("bitrates", option_name) == 0) {
237*fb1b10abSAndroid Build Coastguard Worker res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value,
238*fb1b10abSAndroid Build Coastguard Worker si->bitrates, NULL);
239*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) break;
240*fb1b10abSAndroid Build Coastguard Worker } else if (strcmp("multi-frame-contexts", option_name) == 0) {
241*fb1b10abSAndroid Build Coastguard Worker si->use_multiple_frame_contexts = atoi(option_value);
242*fb1b10abSAndroid Build Coastguard Worker } else {
243*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
244*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
245*fb1b10abSAndroid Build Coastguard Worker break;
246*fb1b10abSAndroid Build Coastguard Worker }
247*fb1b10abSAndroid Build Coastguard Worker option_name = strtok_r(NULL, "=", &input_ptr);
248*fb1b10abSAndroid Build Coastguard Worker }
249*fb1b10abSAndroid Build Coastguard Worker free(input_string);
250*fb1b10abSAndroid Build Coastguard Worker
251*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->spatial_layers; ++i) {
252*fb1b10abSAndroid Build Coastguard Worker if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER ||
253*fb1b10abSAndroid Build Coastguard Worker si->svc_params.max_quantizers[i] < 0 ||
254*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] ||
255*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers[i] < 0)
256*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
257*fb1b10abSAndroid Build Coastguard Worker }
258*fb1b10abSAndroid Build Coastguard Worker
259*fb1b10abSAndroid Build Coastguard Worker if (si->use_multiple_frame_contexts &&
260*fb1b10abSAndroid Build Coastguard Worker (svc_ctx->spatial_layers > 3 ||
261*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
262*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
263*fb1b10abSAndroid Build Coastguard Worker
264*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->spatial_layers; ++i)
265*fb1b10abSAndroid Build Coastguard Worker alt_ref_enabled += si->enable_auto_alt_ref[i];
266*fb1b10abSAndroid Build Coastguard Worker if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) {
267*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR,
268*fb1b10abSAndroid Build Coastguard Worker "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
269*fb1b10abSAndroid Build Coastguard Worker "enabled auto alt reference frame, but %d layers are enabled\n",
270*fb1b10abSAndroid Build Coastguard Worker REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled);
271*fb1b10abSAndroid Build Coastguard Worker res = VPX_CODEC_INVALID_PARAM;
272*fb1b10abSAndroid Build Coastguard Worker }
273*fb1b10abSAndroid Build Coastguard Worker
274*fb1b10abSAndroid Build Coastguard Worker return res;
275*fb1b10abSAndroid Build Coastguard Worker }
276*fb1b10abSAndroid Build Coastguard Worker
vpx_svc_set_options(SvcContext * svc_ctx,const char * options)277*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) {
278*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = get_svc_internal(svc_ctx);
279*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL || options == NULL || si == NULL) {
280*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
281*fb1b10abSAndroid Build Coastguard Worker }
282*fb1b10abSAndroid Build Coastguard Worker strncpy(si->options, options, sizeof(si->options) - 1);
283*fb1b10abSAndroid Build Coastguard Worker si->options[sizeof(si->options) - 1] = '\0';
284*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_OK;
285*fb1b10abSAndroid Build Coastguard Worker }
286*fb1b10abSAndroid Build Coastguard Worker
assign_layer_bitrates(const SvcContext * svc_ctx,vpx_codec_enc_cfg_t * const enc_cfg)287*fb1b10abSAndroid Build Coastguard Worker static vpx_codec_err_t assign_layer_bitrates(
288*fb1b10abSAndroid Build Coastguard Worker const SvcContext *svc_ctx, vpx_codec_enc_cfg_t *const enc_cfg) {
289*fb1b10abSAndroid Build Coastguard Worker int i;
290*fb1b10abSAndroid Build Coastguard Worker const SvcInternal_t *const si = get_const_svc_internal(svc_ctx);
291*fb1b10abSAndroid Build Coastguard Worker int sl, tl, spatial_layer_target;
292*fb1b10abSAndroid Build Coastguard Worker
293*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layering_mode != 0) {
294*fb1b10abSAndroid Build Coastguard Worker if (si->bitrates[0] != 0) {
295*fb1b10abSAndroid Build Coastguard Worker unsigned int total_bitrate = 0;
296*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
297*fb1b10abSAndroid Build Coastguard Worker total_bitrate += si->bitrates[sl * svc_ctx->temporal_layers +
298*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layers - 1];
299*fb1b10abSAndroid Build Coastguard Worker for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
300*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ss_target_bitrate[sl * svc_ctx->temporal_layers] +=
301*fb1b10abSAndroid Build Coastguard Worker (unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl];
302*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + tl] =
303*fb1b10abSAndroid Build Coastguard Worker si->bitrates[sl * svc_ctx->temporal_layers + tl];
304*fb1b10abSAndroid Build Coastguard Worker if (tl > 0 && (si->bitrates[sl * svc_ctx->temporal_layers + tl] <=
305*fb1b10abSAndroid Build Coastguard Worker si->bitrates[sl * svc_ctx->temporal_layers + tl - 1]))
306*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
307*fb1b10abSAndroid Build Coastguard Worker }
308*fb1b10abSAndroid Build Coastguard Worker }
309*fb1b10abSAndroid Build Coastguard Worker if (total_bitrate != enc_cfg->rc_target_bitrate)
310*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
311*fb1b10abSAndroid Build Coastguard Worker } else {
312*fb1b10abSAndroid Build Coastguard Worker float total = 0;
313*fb1b10abSAndroid Build Coastguard Worker float alloc_ratio[VPX_MAX_LAYERS] = { 0 };
314*fb1b10abSAndroid Build Coastguard Worker
315*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
316*fb1b10abSAndroid Build Coastguard Worker if (si->svc_params.scaling_factor_den[sl] > 0) {
317*fb1b10abSAndroid Build Coastguard Worker alloc_ratio[sl] = (float)(pow(2, sl));
318*fb1b10abSAndroid Build Coastguard Worker total += alloc_ratio[sl];
319*fb1b10abSAndroid Build Coastguard Worker }
320*fb1b10abSAndroid Build Coastguard Worker }
321*fb1b10abSAndroid Build Coastguard Worker
322*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
323*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ss_target_bitrate[sl] = spatial_layer_target =
324*fb1b10abSAndroid Build Coastguard Worker (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[sl] /
325*fb1b10abSAndroid Build Coastguard Worker total);
326*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layering_mode == 3) {
327*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
328*fb1b10abSAndroid Build Coastguard Worker (spatial_layer_target * 6) / 10; // 60%
329*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
330*fb1b10abSAndroid Build Coastguard Worker (spatial_layer_target * 8) / 10; // 80%
331*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] =
332*fb1b10abSAndroid Build Coastguard Worker spatial_layer_target;
333*fb1b10abSAndroid Build Coastguard Worker } else if (svc_ctx->temporal_layering_mode == 2 ||
334*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layering_mode == 1) {
335*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
336*fb1b10abSAndroid Build Coastguard Worker spatial_layer_target * 2 / 3;
337*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
338*fb1b10abSAndroid Build Coastguard Worker spatial_layer_target;
339*fb1b10abSAndroid Build Coastguard Worker } else {
340*fb1b10abSAndroid Build Coastguard Worker // User should explicitly assign bitrates in this case.
341*fb1b10abSAndroid Build Coastguard Worker assert(0);
342*fb1b10abSAndroid Build Coastguard Worker }
343*fb1b10abSAndroid Build Coastguard Worker }
344*fb1b10abSAndroid Build Coastguard Worker }
345*fb1b10abSAndroid Build Coastguard Worker } else {
346*fb1b10abSAndroid Build Coastguard Worker if (si->bitrates[0] != 0) {
347*fb1b10abSAndroid Build Coastguard Worker unsigned int total_bitrate = 0;
348*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->spatial_layers; ++i) {
349*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i];
350*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[i] = (unsigned int)si->bitrates[i];
351*fb1b10abSAndroid Build Coastguard Worker total_bitrate += si->bitrates[i];
352*fb1b10abSAndroid Build Coastguard Worker }
353*fb1b10abSAndroid Build Coastguard Worker if (total_bitrate != enc_cfg->rc_target_bitrate)
354*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
355*fb1b10abSAndroid Build Coastguard Worker } else {
356*fb1b10abSAndroid Build Coastguard Worker float total = 0;
357*fb1b10abSAndroid Build Coastguard Worker float alloc_ratio[VPX_MAX_LAYERS] = { 0 };
358*fb1b10abSAndroid Build Coastguard Worker
359*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->spatial_layers; ++i) {
360*fb1b10abSAndroid Build Coastguard Worker if (si->svc_params.scaling_factor_den[i] > 0) {
361*fb1b10abSAndroid Build Coastguard Worker alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
362*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_den[i]);
363*fb1b10abSAndroid Build Coastguard Worker
364*fb1b10abSAndroid Build Coastguard Worker alloc_ratio[i] *= alloc_ratio[i];
365*fb1b10abSAndroid Build Coastguard Worker total += alloc_ratio[i];
366*fb1b10abSAndroid Build Coastguard Worker }
367*fb1b10abSAndroid Build Coastguard Worker }
368*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
369*fb1b10abSAndroid Build Coastguard Worker if (total > 0) {
370*fb1b10abSAndroid Build Coastguard Worker enc_cfg->layer_target_bitrate[i] =
371*fb1b10abSAndroid Build Coastguard Worker (unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[i] /
372*fb1b10abSAndroid Build Coastguard Worker total);
373*fb1b10abSAndroid Build Coastguard Worker }
374*fb1b10abSAndroid Build Coastguard Worker }
375*fb1b10abSAndroid Build Coastguard Worker }
376*fb1b10abSAndroid Build Coastguard Worker }
377*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_OK;
378*fb1b10abSAndroid Build Coastguard Worker }
379*fb1b10abSAndroid Build Coastguard Worker
vpx_svc_init(SvcContext * svc_ctx,vpx_codec_ctx_t * codec_ctx,vpx_codec_iface_t * iface,vpx_codec_enc_cfg_t * enc_cfg)380*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
381*fb1b10abSAndroid Build Coastguard Worker vpx_codec_iface_t *iface,
382*fb1b10abSAndroid Build Coastguard Worker vpx_codec_enc_cfg_t *enc_cfg) {
383*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t res;
384*fb1b10abSAndroid Build Coastguard Worker int sl, tl;
385*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = get_svc_internal(svc_ctx);
386*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
387*fb1b10abSAndroid Build Coastguard Worker enc_cfg == NULL) {
388*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
389*fb1b10abSAndroid Build Coastguard Worker }
390*fb1b10abSAndroid Build Coastguard Worker if (si == NULL) return VPX_CODEC_MEM_ERROR;
391*fb1b10abSAndroid Build Coastguard Worker
392*fb1b10abSAndroid Build Coastguard Worker si->codec_ctx = codec_ctx;
393*fb1b10abSAndroid Build Coastguard Worker
394*fb1b10abSAndroid Build Coastguard Worker si->width = enc_cfg->g_w;
395*fb1b10abSAndroid Build Coastguard Worker si->height = enc_cfg->g_h;
396*fb1b10abSAndroid Build Coastguard Worker
397*fb1b10abSAndroid Build Coastguard Worker si->kf_dist = enc_cfg->kf_max_dist;
398*fb1b10abSAndroid Build Coastguard Worker
399*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers == 0)
400*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS;
401*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers < 1 ||
402*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) {
403*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
404*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers);
405*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
406*fb1b10abSAndroid Build Coastguard Worker }
407*fb1b10abSAndroid Build Coastguard Worker
408*fb1b10abSAndroid Build Coastguard Worker // Note: temporal_layering_mode only applies to one-pass CBR
409*fb1b10abSAndroid Build Coastguard Worker // si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode;
410*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layering_mode == 3) {
411*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layers = 3;
412*fb1b10abSAndroid Build Coastguard Worker } else if (svc_ctx->temporal_layering_mode == 2 ||
413*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layering_mode == 1) {
414*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layers = 2;
415*fb1b10abSAndroid Build Coastguard Worker }
416*fb1b10abSAndroid Build Coastguard Worker
417*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < VPX_SS_MAX_LAYERS; ++sl) {
418*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl];
419*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl];
420*fb1b10abSAndroid Build Coastguard Worker si->svc_params.speed_per_layer[sl] = svc_ctx->speed;
421*fb1b10abSAndroid Build Coastguard Worker }
422*fb1b10abSAndroid Build Coastguard Worker if (enc_cfg->rc_end_usage == VPX_CBR && enc_cfg->g_pass == VPX_RC_ONE_PASS &&
423*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers <= 3) {
424*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
425*fb1b10abSAndroid Build Coastguard Worker int sl2 = (svc_ctx->spatial_layers == 2) ? sl + 1 : sl;
426*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM_2x[sl2];
427*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN_2x[sl2];
428*fb1b10abSAndroid Build Coastguard Worker }
429*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers == 1) {
430*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_num[0] = 1;
431*fb1b10abSAndroid Build Coastguard Worker si->svc_params.scaling_factor_den[0] = 1;
432*fb1b10abSAndroid Build Coastguard Worker }
433*fb1b10abSAndroid Build Coastguard Worker }
434*fb1b10abSAndroid Build Coastguard Worker for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
435*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
436*fb1b10abSAndroid Build Coastguard Worker const int i = sl * svc_ctx->temporal_layers + tl;
437*fb1b10abSAndroid Build Coastguard Worker si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
438*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers[i] = 0;
439*fb1b10abSAndroid Build Coastguard Worker if (enc_cfg->rc_end_usage == VPX_CBR &&
440*fb1b10abSAndroid Build Coastguard Worker enc_cfg->g_pass == VPX_RC_ONE_PASS) {
441*fb1b10abSAndroid Build Coastguard Worker si->svc_params.max_quantizers[i] = 56;
442*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers[i] = 2;
443*fb1b10abSAndroid Build Coastguard Worker }
444*fb1b10abSAndroid Build Coastguard Worker }
445*fb1b10abSAndroid Build Coastguard Worker }
446*fb1b10abSAndroid Build Coastguard Worker
447*fb1b10abSAndroid Build Coastguard Worker // Parse aggregate command line options. Options must start with
448*fb1b10abSAndroid Build Coastguard Worker // "layers=xx" then followed by other options
449*fb1b10abSAndroid Build Coastguard Worker res = parse_options(svc_ctx, si->options);
450*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) return res;
451*fb1b10abSAndroid Build Coastguard Worker
452*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers < 1) svc_ctx->spatial_layers = 1;
453*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS)
454*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS;
455*fb1b10abSAndroid Build Coastguard Worker
456*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layers < 1) svc_ctx->temporal_layers = 1;
457*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS)
458*fb1b10abSAndroid Build Coastguard Worker svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS;
459*fb1b10abSAndroid Build Coastguard Worker
460*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_MAX_LAYERS) {
461*fb1b10abSAndroid Build Coastguard Worker svc_log(
462*fb1b10abSAndroid Build Coastguard Worker svc_ctx, SVC_LOG_ERROR,
463*fb1b10abSAndroid Build Coastguard Worker "spatial layers * temporal layers (%d) exceeds the maximum number of "
464*fb1b10abSAndroid Build Coastguard Worker "allowed layers of %d\n",
465*fb1b10abSAndroid Build Coastguard Worker svc_ctx->spatial_layers * svc_ctx->temporal_layers, VPX_MAX_LAYERS);
466*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
467*fb1b10abSAndroid Build Coastguard Worker }
468*fb1b10abSAndroid Build Coastguard Worker res = assign_layer_bitrates(svc_ctx, enc_cfg);
469*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) {
470*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR,
471*fb1b10abSAndroid Build Coastguard Worker "layer bitrates incorrect: \n"
472*fb1b10abSAndroid Build Coastguard Worker "1) spatial layer bitrates should sum up to target \n"
473*fb1b10abSAndroid Build Coastguard Worker "2) temporal layer bitrates should be increasing within \n"
474*fb1b10abSAndroid Build Coastguard Worker "a spatial layer \n");
475*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
476*fb1b10abSAndroid Build Coastguard Worker }
477*fb1b10abSAndroid Build Coastguard Worker
478*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->temporal_layers > 1) {
479*fb1b10abSAndroid Build Coastguard Worker int i;
480*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->temporal_layers; ++i) {
481*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ts_target_bitrate[i] =
482*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_target_bitrate / svc_ctx->temporal_layers;
483*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i);
484*fb1b10abSAndroid Build Coastguard Worker }
485*fb1b10abSAndroid Build Coastguard Worker }
486*fb1b10abSAndroid Build Coastguard Worker
487*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->threads) enc_cfg->g_threads = svc_ctx->threads;
488*fb1b10abSAndroid Build Coastguard Worker
489*fb1b10abSAndroid Build Coastguard Worker // Modify encoder configuration
490*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ss_number_layers = svc_ctx->spatial_layers;
491*fb1b10abSAndroid Build Coastguard Worker enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
492*fb1b10abSAndroid Build Coastguard Worker
493*fb1b10abSAndroid Build Coastguard Worker if (enc_cfg->rc_end_usage == VPX_CBR) {
494*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_resize_allowed = 0;
495*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_min_quantizer = 2;
496*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_max_quantizer = 56;
497*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_undershoot_pct = 50;
498*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_overshoot_pct = 50;
499*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_buf_initial_sz = 500;
500*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_buf_optimal_sz = 600;
501*fb1b10abSAndroid Build Coastguard Worker enc_cfg->rc_buf_sz = 1000;
502*fb1b10abSAndroid Build Coastguard Worker }
503*fb1b10abSAndroid Build Coastguard Worker
504*fb1b10abSAndroid Build Coastguard Worker for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
505*fb1b10abSAndroid Build Coastguard Worker for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
506*fb1b10abSAndroid Build Coastguard Worker const int i = sl * svc_ctx->temporal_layers + tl;
507*fb1b10abSAndroid Build Coastguard Worker if (enc_cfg->rc_end_usage == VPX_CBR &&
508*fb1b10abSAndroid Build Coastguard Worker enc_cfg->g_pass == VPX_RC_ONE_PASS) {
509*fb1b10abSAndroid Build Coastguard Worker si->svc_params.max_quantizers[i] = enc_cfg->rc_max_quantizer;
510*fb1b10abSAndroid Build Coastguard Worker si->svc_params.min_quantizers[i] = enc_cfg->rc_min_quantizer;
511*fb1b10abSAndroid Build Coastguard Worker }
512*fb1b10abSAndroid Build Coastguard Worker }
513*fb1b10abSAndroid Build Coastguard Worker }
514*fb1b10abSAndroid Build Coastguard Worker
515*fb1b10abSAndroid Build Coastguard Worker if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
516*fb1b10abSAndroid Build Coastguard Worker enc_cfg->g_error_resilient = 1;
517*fb1b10abSAndroid Build Coastguard Worker
518*fb1b10abSAndroid Build Coastguard Worker // Initialize codec
519*fb1b10abSAndroid Build Coastguard Worker res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR);
520*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) {
521*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
522*fb1b10abSAndroid Build Coastguard Worker return res;
523*fb1b10abSAndroid Build Coastguard Worker }
524*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) {
525*fb1b10abSAndroid Build Coastguard Worker vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
526*fb1b10abSAndroid Build Coastguard Worker vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params);
527*fb1b10abSAndroid Build Coastguard Worker }
528*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_OK;
529*fb1b10abSAndroid Build Coastguard Worker }
530*fb1b10abSAndroid Build Coastguard Worker
531*fb1b10abSAndroid Build Coastguard Worker /**
532*fb1b10abSAndroid Build Coastguard Worker * Encode a frame into multiple layers
533*fb1b10abSAndroid Build Coastguard Worker * Create a superframe containing the individual layers
534*fb1b10abSAndroid Build Coastguard Worker */
vpx_svc_encode(SvcContext * svc_ctx,vpx_codec_ctx_t * codec_ctx,struct vpx_image * rawimg,vpx_codec_pts_t pts,int64_t duration,int deadline)535*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
536*fb1b10abSAndroid Build Coastguard Worker struct vpx_image *rawimg, vpx_codec_pts_t pts,
537*fb1b10abSAndroid Build Coastguard Worker int64_t duration, int deadline) {
538*fb1b10abSAndroid Build Coastguard Worker vpx_codec_err_t res;
539*fb1b10abSAndroid Build Coastguard Worker vpx_codec_iter_t iter;
540*fb1b10abSAndroid Build Coastguard Worker const vpx_codec_cx_pkt_t *cx_pkt;
541*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = get_svc_internal(svc_ctx);
542*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
543*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_INVALID_PARAM;
544*fb1b10abSAndroid Build Coastguard Worker }
545*fb1b10abSAndroid Build Coastguard Worker
546*fb1b10abSAndroid Build Coastguard Worker res =
547*fb1b10abSAndroid Build Coastguard Worker vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline);
548*fb1b10abSAndroid Build Coastguard Worker if (res != VPX_CODEC_OK) {
549*fb1b10abSAndroid Build Coastguard Worker return res;
550*fb1b10abSAndroid Build Coastguard Worker }
551*fb1b10abSAndroid Build Coastguard Worker // save compressed data
552*fb1b10abSAndroid Build Coastguard Worker iter = NULL;
553*fb1b10abSAndroid Build Coastguard Worker while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) {
554*fb1b10abSAndroid Build Coastguard Worker switch (cx_pkt->kind) {
555*fb1b10abSAndroid Build Coastguard Worker case VPX_CODEC_PSNR_PKT: ++si->psnr_pkt_received; break;
556*fb1b10abSAndroid Build Coastguard Worker default: break;
557*fb1b10abSAndroid Build Coastguard Worker }
558*fb1b10abSAndroid Build Coastguard Worker }
559*fb1b10abSAndroid Build Coastguard Worker
560*fb1b10abSAndroid Build Coastguard Worker return VPX_CODEC_OK;
561*fb1b10abSAndroid Build Coastguard Worker }
562*fb1b10abSAndroid Build Coastguard Worker
calc_psnr(double d)563*fb1b10abSAndroid Build Coastguard Worker static double calc_psnr(double d) {
564*fb1b10abSAndroid Build Coastguard Worker if (d == 0) return 100;
565*fb1b10abSAndroid Build Coastguard Worker return -10.0 * log(d) / log(10.0);
566*fb1b10abSAndroid Build Coastguard Worker }
567*fb1b10abSAndroid Build Coastguard Worker
568*fb1b10abSAndroid Build Coastguard Worker // dump accumulated statistics and reset accumulated values
vpx_svc_dump_statistics(SvcContext * svc_ctx)569*fb1b10abSAndroid Build Coastguard Worker void vpx_svc_dump_statistics(SvcContext *svc_ctx) {
570*fb1b10abSAndroid Build Coastguard Worker int number_of_frames;
571*fb1b10abSAndroid Build Coastguard Worker int i, j;
572*fb1b10abSAndroid Build Coastguard Worker uint32_t bytes_total = 0;
573*fb1b10abSAndroid Build Coastguard Worker double scale[COMPONENTS];
574*fb1b10abSAndroid Build Coastguard Worker double psnr[COMPONENTS];
575*fb1b10abSAndroid Build Coastguard Worker double mse[COMPONENTS];
576*fb1b10abSAndroid Build Coastguard Worker double y_scale;
577*fb1b10abSAndroid Build Coastguard Worker
578*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *const si = get_svc_internal(svc_ctx);
579*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL || si == NULL) return;
580*fb1b10abSAndroid Build Coastguard Worker
581*fb1b10abSAndroid Build Coastguard Worker number_of_frames = si->psnr_pkt_received;
582*fb1b10abSAndroid Build Coastguard Worker if (number_of_frames <= 0) return;
583*fb1b10abSAndroid Build Coastguard Worker
584*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_INFO, "\n");
585*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < svc_ctx->spatial_layers; ++i) {
586*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_INFO,
587*fb1b10abSAndroid Build Coastguard Worker "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
588*fb1b10abSAndroid Build Coastguard Worker i, si->psnr_sum[i][0] / number_of_frames,
589*fb1b10abSAndroid Build Coastguard Worker si->psnr_sum[i][1] / number_of_frames,
590*fb1b10abSAndroid Build Coastguard Worker si->psnr_sum[i][2] / number_of_frames,
591*fb1b10abSAndroid Build Coastguard Worker si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
592*fb1b10abSAndroid Build Coastguard Worker // the following psnr calculation is deduced from ffmpeg.c#print_report
593*fb1b10abSAndroid Build Coastguard Worker y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
594*fb1b10abSAndroid Build Coastguard Worker scale[1] = y_scale;
595*fb1b10abSAndroid Build Coastguard Worker scale[2] = scale[3] = y_scale / 4; // U or V
596*fb1b10abSAndroid Build Coastguard Worker scale[0] = y_scale * 1.5; // total
597*fb1b10abSAndroid Build Coastguard Worker
598*fb1b10abSAndroid Build Coastguard Worker for (j = 0; j < COMPONENTS; j++) {
599*fb1b10abSAndroid Build Coastguard Worker psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
600*fb1b10abSAndroid Build Coastguard Worker mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
601*fb1b10abSAndroid Build Coastguard Worker }
602*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_INFO,
603*fb1b10abSAndroid Build Coastguard Worker "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
604*fb1b10abSAndroid Build Coastguard Worker psnr[1], psnr[2], psnr[3]);
605*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_INFO,
606*fb1b10abSAndroid Build Coastguard Worker "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
607*fb1b10abSAndroid Build Coastguard Worker mse[1], mse[2], mse[3]);
608*fb1b10abSAndroid Build Coastguard Worker
609*fb1b10abSAndroid Build Coastguard Worker bytes_total += si->bytes_sum[i];
610*fb1b10abSAndroid Build Coastguard Worker // Clear sums for next time.
611*fb1b10abSAndroid Build Coastguard Worker si->bytes_sum[i] = 0;
612*fb1b10abSAndroid Build Coastguard Worker for (j = 0; j < COMPONENTS; ++j) {
613*fb1b10abSAndroid Build Coastguard Worker si->psnr_sum[i][j] = 0;
614*fb1b10abSAndroid Build Coastguard Worker si->sse_sum[i][j] = 0;
615*fb1b10abSAndroid Build Coastguard Worker }
616*fb1b10abSAndroid Build Coastguard Worker }
617*fb1b10abSAndroid Build Coastguard Worker
618*fb1b10abSAndroid Build Coastguard Worker // only display statistics once
619*fb1b10abSAndroid Build Coastguard Worker si->psnr_pkt_received = 0;
620*fb1b10abSAndroid Build Coastguard Worker
621*fb1b10abSAndroid Build Coastguard Worker svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
622*fb1b10abSAndroid Build Coastguard Worker }
623*fb1b10abSAndroid Build Coastguard Worker
vpx_svc_release(SvcContext * svc_ctx)624*fb1b10abSAndroid Build Coastguard Worker void vpx_svc_release(SvcContext *svc_ctx) {
625*fb1b10abSAndroid Build Coastguard Worker SvcInternal_t *si;
626*fb1b10abSAndroid Build Coastguard Worker if (svc_ctx == NULL) return;
627*fb1b10abSAndroid Build Coastguard Worker // do not use get_svc_internal as it will unnecessarily allocate an
628*fb1b10abSAndroid Build Coastguard Worker // SvcInternal_t if it was not already allocated
629*fb1b10abSAndroid Build Coastguard Worker si = (SvcInternal_t *)svc_ctx->internal;
630*fb1b10abSAndroid Build Coastguard Worker if (si != NULL) {
631*fb1b10abSAndroid Build Coastguard Worker free(si);
632*fb1b10abSAndroid Build Coastguard Worker svc_ctx->internal = NULL;
633*fb1b10abSAndroid Build Coastguard Worker }
634*fb1b10abSAndroid Build Coastguard Worker }
635