OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebM project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 /** | 11 /** |
12 * @file | 12 * @file |
13 * VP9 SVC encoding support via libvpx | 13 * VP9 SVC encoding support via libvpx |
14 */ | 14 */ |
15 | 15 |
16 #include <assert.h> | 16 #include <assert.h> |
17 #include <math.h> | 17 #include <math.h> |
| 18 #include <limits.h> |
18 #include <stdarg.h> | 19 #include <stdarg.h> |
19 #include <stdio.h> | 20 #include <stdio.h> |
20 #include <stdlib.h> | 21 #include <stdlib.h> |
21 #include <string.h> | 22 #include <string.h> |
22 #define VPX_DISABLE_CTRL_TYPECHECKS 1 | 23 #define VPX_DISABLE_CTRL_TYPECHECKS 1 |
23 #define VPX_CODEC_DISABLE_COMPAT 1 | |
24 #include "./vpx_config.h" | 24 #include "./vpx_config.h" |
25 #include "vpx/svc_context.h" | 25 #include "vpx/svc_context.h" |
26 #include "vpx/vp8cx.h" | 26 #include "vpx/vp8cx.h" |
27 #include "vpx/vpx_encoder.h" | 27 #include "vpx/vpx_encoder.h" |
28 #include "vpx_mem/vpx_mem.h" | 28 #include "vpx_mem/vpx_mem.h" |
29 #include "vp9/common/vp9_onyxc_int.h" | 29 #include "vp9/common/vp9_onyxc_int.h" |
30 | 30 |
31 #ifdef __MINGW32__ | 31 #ifdef __MINGW32__ |
32 #define strtok_r strtok_s | 32 #define strtok_r strtok_s |
33 #ifndef MINGW_HAS_SECURE_API | 33 #ifndef MINGW_HAS_SECURE_API |
34 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h | 34 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h |
35 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); | 35 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); |
36 #endif /* MINGW_HAS_SECURE_API */ | 36 #endif /* MINGW_HAS_SECURE_API */ |
37 #endif /* __MINGW32__ */ | 37 #endif /* __MINGW32__ */ |
38 | 38 |
39 #ifdef _MSC_VER | 39 #ifdef _MSC_VER |
40 #define strdup _strdup | 40 #define strdup _strdup |
41 #define strtok_r strtok_s | 41 #define strtok_r strtok_s |
42 #endif | 42 #endif |
43 | 43 |
44 #define SVC_REFERENCE_FRAMES 8 | 44 #define SVC_REFERENCE_FRAMES 8 |
45 #define SUPERFRAME_SLOTS (8) | 45 #define SUPERFRAME_SLOTS (8) |
46 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) | 46 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) |
47 #define OPTION_BUFFER_SIZE 256 | 47 #define OPTION_BUFFER_SIZE 1024 |
48 #define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v | 48 #define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v |
49 | 49 |
50 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; | 50 #define MAX_QUANTIZER 63 |
51 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; | 51 |
| 52 static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = { |
| 53 4, 5, 7, 11, 16 |
| 54 }; |
| 55 |
| 56 static const int DEFAULT_SCALE_FACTORS_DEN[VPX_SS_MAX_LAYERS] = { |
| 57 16, 16, 16, 16, 16 |
| 58 }; |
| 59 |
| 60 typedef enum { |
| 61 QUANTIZER = 0, |
| 62 BITRATE, |
| 63 SCALE_FACTOR, |
| 64 AUTO_ALT_REF, |
| 65 ALL_OPTION_TYPES |
| 66 } LAYER_OPTION_TYPE; |
| 67 |
| 68 static const int option_max_values[ALL_OPTION_TYPES] = { |
| 69 63, INT_MAX, INT_MAX, 1 |
| 70 }; |
| 71 |
| 72 static const int option_min_values[ALL_OPTION_TYPES] = { |
| 73 0, 0, 1, 0 |
| 74 }; |
52 | 75 |
53 // One encoded frame | 76 // One encoded frame |
54 typedef struct FrameData { | 77 typedef struct FrameData { |
55 void *buf; // compressed data buffer | 78 void *buf; // compressed data buffer |
56 size_t size; // length of compressed data | 79 size_t size; // length of compressed data |
57 vpx_codec_frame_flags_t flags; /**< flags for this frame */ | 80 vpx_codec_frame_flags_t flags; /**< flags for this frame */ |
58 struct FrameData *next; | 81 struct FrameData *next; |
59 } FrameData; | 82 } FrameData; |
60 | 83 |
61 typedef struct SvcInternal { | 84 typedef struct SvcInternal { |
62 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options | 85 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options |
63 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers | |
64 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors | |
65 | 86 |
66 // values extracted from option, quantizers | 87 // values extracted from option, quantizers |
67 int scaling_factor_num[VPX_SS_MAX_LAYERS]; | 88 vpx_svc_extra_cfg_t svc_params; |
68 int scaling_factor_den[VPX_SS_MAX_LAYERS]; | |
69 int quantizer[VPX_SS_MAX_LAYERS]; | |
70 int enable_auto_alt_ref[VPX_SS_MAX_LAYERS]; | 89 int enable_auto_alt_ref[VPX_SS_MAX_LAYERS]; |
| 90 int bitrates[VPX_SS_MAX_LAYERS]; |
71 | 91 |
72 // accumulated statistics | 92 // accumulated statistics |
73 double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V | 93 double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V |
74 uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; | 94 uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; |
75 uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; | 95 uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; |
76 | 96 |
77 // codec encoding values | 97 // codec encoding values |
78 int width; // width of highest layer | 98 int width; // width of highest layer |
79 int height; // height of highest layer | 99 int height; // height of highest layer |
80 int kf_dist; // distance between keyframes | 100 int kf_dist; // distance between keyframes |
81 | 101 |
82 // state variables | 102 // state variables |
83 int encode_frame_count; | 103 int psnr_pkt_received; |
84 int frame_received; | |
85 int frame_within_gop; | |
86 int layers; | |
87 int layer; | 104 int layer; |
88 int is_keyframe; | |
89 int use_multiple_frame_contexts; | 105 int use_multiple_frame_contexts; |
90 | 106 |
91 FrameData *frame_list; | |
92 FrameData *frame_temp; | |
93 | |
94 char *rc_stats_buf; | |
95 size_t rc_stats_buf_size; | |
96 size_t rc_stats_buf_used; | |
97 | |
98 char message_buffer[2048]; | 107 char message_buffer[2048]; |
99 vpx_codec_ctx_t *codec_ctx; | 108 vpx_codec_ctx_t *codec_ctx; |
100 } SvcInternal; | 109 } SvcInternal; |
101 | 110 |
102 // create FrameData from encoder output | |
103 static struct FrameData *fd_create(void *buf, size_t size, | |
104 vpx_codec_frame_flags_t flags) { | |
105 struct FrameData *const frame_data = | |
106 (struct FrameData *)vpx_malloc(sizeof(*frame_data)); | |
107 if (frame_data == NULL) { | |
108 return NULL; | |
109 } | |
110 frame_data->buf = vpx_malloc(size); | |
111 if (frame_data->buf == NULL) { | |
112 vpx_free(frame_data); | |
113 return NULL; | |
114 } | |
115 vpx_memcpy(frame_data->buf, buf, size); | |
116 frame_data->size = size; | |
117 frame_data->flags = flags; | |
118 return frame_data; | |
119 } | |
120 | |
121 // free FrameData | |
122 static void fd_free(struct FrameData *p) { | |
123 if (p) { | |
124 if (p->buf) | |
125 vpx_free(p->buf); | |
126 vpx_free(p); | |
127 } | |
128 } | |
129 | |
130 // add FrameData to list | |
131 static void fd_list_add(struct FrameData **list, struct FrameData *layer_data) { | |
132 struct FrameData **p = list; | |
133 | |
134 while (*p != NULL) p = &(*p)->next; | |
135 *p = layer_data; | |
136 layer_data->next = NULL; | |
137 } | |
138 | |
139 // free FrameData list | |
140 static void fd_free_list(struct FrameData *list) { | |
141 struct FrameData *p = list; | |
142 | |
143 while (p) { | |
144 list = list->next; | |
145 fd_free(p); | |
146 p = list; | |
147 } | |
148 } | |
149 | |
150 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) { | 111 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) { |
151 if (svc_ctx == NULL) return NULL; | 112 if (svc_ctx == NULL) return NULL; |
152 if (svc_ctx->internal == NULL) { | 113 if (svc_ctx->internal == NULL) { |
153 SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si)); | 114 SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si)); |
154 if (si != NULL) { | 115 if (si != NULL) { |
155 memset(si, 0, sizeof(*si)); | 116 memset(si, 0, sizeof(*si)); |
156 } | 117 } |
157 svc_ctx->internal = si; | 118 svc_ctx->internal = si; |
158 } | 119 } |
159 return (SvcInternal *)svc_ctx->internal; | 120 return (SvcInternal *)svc_ctx->internal; |
(...skipping 30 matching lines...) Expand all Loading... |
190 strncat(si->message_buffer, buf, | 151 strncat(si->message_buffer, buf, |
191 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); | 152 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); |
192 } | 153 } |
193 | 154 |
194 if (level == SVC_LOG_ERROR) { | 155 if (level == SVC_LOG_ERROR) { |
195 si->codec_ctx->err_detail = si->message_buffer; | 156 si->codec_ctx->err_detail = si->message_buffer; |
196 } | 157 } |
197 return retval; | 158 return retval; |
198 } | 159 } |
199 | 160 |
200 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, | 161 static vpx_codec_err_t extract_option(LAYER_OPTION_TYPE type, |
201 const char *quantizer_values) { | 162 char *input, |
| 163 int *value0, |
| 164 int *value1) { |
| 165 if (type == SCALE_FACTOR) { |
| 166 *value0 = strtol(input, &input, 10); |
| 167 if (*input++ != '/') |
| 168 return VPX_CODEC_INVALID_PARAM; |
| 169 *value1 = strtol(input, &input, 10); |
| 170 |
| 171 if (*value0 < option_min_values[SCALE_FACTOR] || |
| 172 *value1 < option_min_values[SCALE_FACTOR] || |
| 173 *value0 > option_max_values[SCALE_FACTOR] || |
| 174 *value1 > option_max_values[SCALE_FACTOR] || |
| 175 *value0 > *value1) // num shouldn't be greater than den |
| 176 return VPX_CODEC_INVALID_PARAM; |
| 177 } else { |
| 178 *value0 = atoi(input); |
| 179 if (*value0 < option_min_values[type] || |
| 180 *value0 > option_max_values[type]) |
| 181 return VPX_CODEC_INVALID_PARAM; |
| 182 } |
| 183 return VPX_CODEC_OK; |
| 184 } |
| 185 |
| 186 static vpx_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx, |
| 187 LAYER_OPTION_TYPE type, |
| 188 const char *input, |
| 189 int *option0, |
| 190 int *option1) { |
| 191 int i; |
| 192 vpx_codec_err_t res = VPX_CODEC_OK; |
202 char *input_string; | 193 char *input_string; |
203 char *token; | 194 char *token; |
204 const char *delim = ","; | 195 const char *delim = ","; |
205 char *save_ptr; | 196 char *save_ptr; |
206 int found = 0; | |
207 int i, q; | |
208 vpx_codec_err_t res = VPX_CODEC_OK; | |
209 SvcInternal *const si = get_svc_internal(svc_ctx); | |
210 | 197 |
211 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { | 198 if (input == NULL || option0 == NULL || |
212 input_string = strdup(DEFAULT_QUANTIZER_VALUES); | 199 (option1 == NULL && type == SCALE_FACTOR)) |
213 } else { | 200 return VPX_CODEC_INVALID_PARAM; |
214 input_string = strdup(quantizer_values); | |
215 } | |
216 | 201 |
| 202 input_string = strdup(input); |
217 token = strtok_r(input_string, delim, &save_ptr); | 203 token = strtok_r(input_string, delim, &save_ptr); |
218 for (i = 0; i < svc_ctx->spatial_layers; ++i) { | 204 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
219 if (token != NULL) { | 205 if (token != NULL) { |
220 q = atoi(token); | 206 res = extract_option(type, token, option0 + i, option1 + i); |
221 if (q <= 0 || q > 100) { | 207 if (res != VPX_CODEC_OK) |
222 svc_log(svc_ctx, SVC_LOG_ERROR, | |
223 "svc-quantizer-values: invalid value %s\n", token); | |
224 res = VPX_CODEC_INVALID_PARAM; | |
225 break; | 208 break; |
226 } | |
227 token = strtok_r(NULL, delim, &save_ptr); | 209 token = strtok_r(NULL, delim, &save_ptr); |
228 found = i + 1; | |
229 } else { | 210 } else { |
230 q = 0; | 211 break; |
231 } | 212 } |
232 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; | |
233 } | 213 } |
234 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { | 214 if (res == VPX_CODEC_OK && i != svc_ctx->spatial_layers) { |
235 svc_log(svc_ctx, SVC_LOG_ERROR, | 215 svc_log(svc_ctx, SVC_LOG_ERROR, |
236 "svc: quantizers: %d values required, but only %d specified\n", | 216 "svc: layer params type: %d %d values required, " |
237 svc_ctx->spatial_layers, found); | 217 "but only %d specified\n", type, svc_ctx->spatial_layers, i); |
238 res = VPX_CODEC_INVALID_PARAM; | |
239 } | |
240 free(input_string); | |
241 return res; | |
242 } | |
243 | |
244 static vpx_codec_err_t parse_auto_alt_ref(SvcContext *svc_ctx, | |
245 const char *alt_ref_options) { | |
246 char *input_string; | |
247 char *token; | |
248 const char *delim = ","; | |
249 char *save_ptr; | |
250 int found = 0, enabled = 0; | |
251 int i, value; | |
252 vpx_codec_err_t res = VPX_CODEC_OK; | |
253 SvcInternal *const si = get_svc_internal(svc_ctx); | |
254 | |
255 if (alt_ref_options == NULL || strlen(alt_ref_options) == 0) { | |
256 return VPX_CODEC_INVALID_PARAM; | |
257 } else { | |
258 input_string = strdup(alt_ref_options); | |
259 } | |
260 | |
261 token = strtok_r(input_string, delim, &save_ptr); | |
262 for (i = 0; i < svc_ctx->spatial_layers; ++i) { | |
263 if (token != NULL) { | |
264 value = atoi(token); | |
265 if (value < 0 || value > 1) { | |
266 svc_log(svc_ctx, SVC_LOG_ERROR, | |
267 "enable auto alt ref values: invalid value %s\n", token); | |
268 res = VPX_CODEC_INVALID_PARAM; | |
269 break; | |
270 } | |
271 token = strtok_r(NULL, delim, &save_ptr); | |
272 found = i + 1; | |
273 } else { | |
274 value = 0; | |
275 } | |
276 si->enable_auto_alt_ref[i] = value; | |
277 if (value > 0) | |
278 ++enabled; | |
279 } | |
280 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { | |
281 svc_log(svc_ctx, SVC_LOG_ERROR, | |
282 "svc: quantizers: %d values required, but only %d specified\n", | |
283 svc_ctx->spatial_layers, found); | |
284 res = VPX_CODEC_INVALID_PARAM; | |
285 } | |
286 if (enabled > REF_FRAMES - svc_ctx->spatial_layers) { | |
287 svc_log(svc_ctx, SVC_LOG_ERROR, | |
288 "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could" | |
289 "enabled auto alt reference frame, but % layers are enabled\n", | |
290 REF_FRAMES - svc_ctx->spatial_layers, enabled); | |
291 res = VPX_CODEC_INVALID_PARAM; | |
292 } | |
293 free(input_string); | |
294 return res; | |
295 } | |
296 | |
297 static void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) { | |
298 svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n", | |
299 value); | |
300 } | |
301 | |
302 static vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx, | |
303 const char *scale_factors) { | |
304 char *input_string; | |
305 char *token; | |
306 const char *delim = ","; | |
307 char *save_ptr; | |
308 int found = 0; | |
309 int i; | |
310 int64_t num, den; | |
311 vpx_codec_err_t res = VPX_CODEC_OK; | |
312 SvcInternal *const si = get_svc_internal(svc_ctx); | |
313 | |
314 if (scale_factors == NULL || strlen(scale_factors) == 0) { | |
315 input_string = strdup(DEFAULT_SCALE_FACTORS); | |
316 } else { | |
317 input_string = strdup(scale_factors); | |
318 } | |
319 token = strtok_r(input_string, delim, &save_ptr); | |
320 for (i = 0; i < svc_ctx->spatial_layers; ++i) { | |
321 num = den = 0; | |
322 if (token != NULL) { | |
323 num = strtol(token, &token, 10); | |
324 if (num <= 0) { | |
325 log_invalid_scale_factor(svc_ctx, token); | |
326 res = VPX_CODEC_INVALID_PARAM; | |
327 break; | |
328 } | |
329 if (*token++ != '/') { | |
330 log_invalid_scale_factor(svc_ctx, token); | |
331 res = VPX_CODEC_INVALID_PARAM; | |
332 break; | |
333 } | |
334 den = strtol(token, &token, 10); | |
335 if (den <= 0) { | |
336 log_invalid_scale_factor(svc_ctx, token); | |
337 res = VPX_CODEC_INVALID_PARAM; | |
338 break; | |
339 } | |
340 token = strtok_r(NULL, delim, &save_ptr); | |
341 found = i + 1; | |
342 } | |
343 si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = | |
344 (int)num; | |
345 si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = | |
346 (int)den; | |
347 } | |
348 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { | |
349 svc_log(svc_ctx, SVC_LOG_ERROR, | |
350 "svc: scale-factors: %d values required, but only %d specified\n", | |
351 svc_ctx->spatial_layers, found); | |
352 res = VPX_CODEC_INVALID_PARAM; | 218 res = VPX_CODEC_INVALID_PARAM; |
353 } | 219 } |
354 free(input_string); | 220 free(input_string); |
355 return res; | 221 return res; |
356 } | 222 } |
357 | 223 |
358 /** | 224 /** |
359 * Parse SVC encoding options | 225 * Parse SVC encoding options |
360 * Format: encoding-mode=<svc_mode>,layers=<layer_count> | 226 * Format: encoding-mode=<svc_mode>,layers=<layer_count> |
361 * scale-factors=<n1>/<d1>,<n2>/<d2>,... | 227 * scale-factors=<n1>/<d1>,<n2>/<d2>,... |
362 * quantizers=<q1>,<q2>,... | 228 * quantizers=<q1>,<q2>,... |
363 * svc_mode = [i|ip|alt_ip|gf] | 229 * svc_mode = [i|ip|alt_ip|gf] |
364 */ | 230 */ |
365 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { | 231 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { |
366 char *input_string; | 232 char *input_string; |
367 char *option_name; | 233 char *option_name; |
368 char *option_value; | 234 char *option_value; |
369 char *input_ptr; | 235 char *input_ptr; |
370 SvcInternal *const si = get_svc_internal(svc_ctx); | 236 SvcInternal *const si = get_svc_internal(svc_ctx); |
371 vpx_codec_err_t res = VPX_CODEC_OK; | 237 vpx_codec_err_t res = VPX_CODEC_OK; |
| 238 int i, alt_ref_enabled = 0; |
372 | 239 |
373 if (options == NULL) return VPX_CODEC_OK; | 240 if (options == NULL) return VPX_CODEC_OK; |
374 input_string = strdup(options); | 241 input_string = strdup(options); |
375 | 242 |
376 // parse option name | 243 // parse option name |
377 option_name = strtok_r(input_string, "=", &input_ptr); | 244 option_name = strtok_r(input_string, "=", &input_ptr); |
378 while (option_name != NULL) { | 245 while (option_name != NULL) { |
379 // parse option value | 246 // parse option value |
380 option_value = strtok_r(NULL, " ", &input_ptr); | 247 option_value = strtok_r(NULL, " ", &input_ptr); |
381 if (option_value == NULL) { | 248 if (option_value == NULL) { |
382 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", | 249 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", |
383 option_name); | 250 option_name); |
384 res = VPX_CODEC_INVALID_PARAM; | 251 res = VPX_CODEC_INVALID_PARAM; |
385 break; | 252 break; |
386 } | 253 } |
387 if (strcmp("spatial-layers", option_name) == 0) { | 254 if (strcmp("spatial-layers", option_name) == 0) { |
388 svc_ctx->spatial_layers = atoi(option_value); | 255 svc_ctx->spatial_layers = atoi(option_value); |
389 } else if (strcmp("temporal-layers", option_name) == 0) { | 256 } else if (strcmp("temporal-layers", option_name) == 0) { |
390 svc_ctx->temporal_layers = atoi(option_value); | 257 svc_ctx->temporal_layers = atoi(option_value); |
391 } else if (strcmp("scale-factors", option_name) == 0) { | 258 } else if (strcmp("scale-factors", option_name) == 0) { |
392 res = parse_scale_factors(svc_ctx, option_value); | 259 res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value, |
| 260 si->svc_params.scaling_factor_num, |
| 261 si->svc_params.scaling_factor_den); |
393 if (res != VPX_CODEC_OK) break; | 262 if (res != VPX_CODEC_OK) break; |
394 } else if (strcmp("quantizers", option_name) == 0) { | 263 } else if (strcmp("max-quantizers", option_name) == 0) { |
395 res = parse_quantizer_values(svc_ctx, option_value); | 264 res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, |
| 265 si->svc_params.max_quantizers, |
| 266 NULL); |
| 267 if (res != VPX_CODEC_OK) break; |
| 268 } else if (strcmp("min-quantizers", option_name) == 0) { |
| 269 res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value, |
| 270 si->svc_params.min_quantizers, |
| 271 NULL); |
396 if (res != VPX_CODEC_OK) break; | 272 if (res != VPX_CODEC_OK) break; |
397 } else if (strcmp("auto-alt-refs", option_name) == 0) { | 273 } else if (strcmp("auto-alt-refs", option_name) == 0) { |
398 res = parse_auto_alt_ref(svc_ctx, option_value); | 274 res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value, |
| 275 si->enable_auto_alt_ref, NULL); |
| 276 if (res != VPX_CODEC_OK) break; |
| 277 } else if (strcmp("bitrates", option_name) == 0) { |
| 278 res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value, |
| 279 si->bitrates, NULL); |
399 if (res != VPX_CODEC_OK) break; | 280 if (res != VPX_CODEC_OK) break; |
400 } else if (strcmp("multi-frame-contexts", option_name) == 0) { | 281 } else if (strcmp("multi-frame-contexts", option_name) == 0) { |
401 si->use_multiple_frame_contexts = atoi(option_value); | 282 si->use_multiple_frame_contexts = atoi(option_value); |
402 } else { | 283 } else { |
403 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); | 284 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); |
404 res = VPX_CODEC_INVALID_PARAM; | 285 res = VPX_CODEC_INVALID_PARAM; |
405 break; | 286 break; |
406 } | 287 } |
407 option_name = strtok_r(NULL, "=", &input_ptr); | 288 option_name = strtok_r(NULL, "=", &input_ptr); |
408 } | 289 } |
409 free(input_string); | 290 free(input_string); |
410 | 291 |
| 292 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 293 if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER || |
| 294 si->svc_params.max_quantizers[i] < 0 || |
| 295 si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] || |
| 296 si->svc_params.min_quantizers[i] < 0) |
| 297 res = VPX_CODEC_INVALID_PARAM; |
| 298 } |
| 299 |
411 if (si->use_multiple_frame_contexts && | 300 if (si->use_multiple_frame_contexts && |
412 (svc_ctx->spatial_layers > 3 || | 301 (svc_ctx->spatial_layers > 3 || |
413 svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) | 302 svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4)) |
414 res = VPX_CODEC_INVALID_PARAM; | 303 res = VPX_CODEC_INVALID_PARAM; |
415 | 304 |
| 305 for (i = 0; i < svc_ctx->spatial_layers; ++i) |
| 306 alt_ref_enabled += si->enable_auto_alt_ref[i]; |
| 307 if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) { |
| 308 svc_log(svc_ctx, SVC_LOG_ERROR, |
| 309 "svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could" |
| 310 "enabled auto alt reference frame, but % layers are enabled\n", |
| 311 REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled); |
| 312 res = VPX_CODEC_INVALID_PARAM; |
| 313 } |
| 314 |
416 return res; | 315 return res; |
417 } | 316 } |
418 | 317 |
419 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { | 318 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { |
420 SvcInternal *const si = get_svc_internal(svc_ctx); | 319 SvcInternal *const si = get_svc_internal(svc_ctx); |
421 if (svc_ctx == NULL || options == NULL || si == NULL) { | 320 if (svc_ctx == NULL || options == NULL || si == NULL) { |
422 return VPX_CODEC_INVALID_PARAM; | 321 return VPX_CODEC_INVALID_PARAM; |
423 } | 322 } |
424 strncpy(si->options, options, sizeof(si->options)); | 323 strncpy(si->options, options, sizeof(si->options)); |
425 si->options[sizeof(si->options) - 1] = '\0'; | 324 si->options[sizeof(si->options) - 1] = '\0'; |
426 return VPX_CODEC_OK; | 325 return VPX_CODEC_OK; |
427 } | 326 } |
428 | 327 |
429 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, | 328 void assign_layer_bitrates(const SvcContext *svc_ctx, |
430 const char *quantizers) { | 329 vpx_codec_enc_cfg_t *const enc_cfg) { |
431 SvcInternal *const si = get_svc_internal(svc_ctx); | 330 int i; |
432 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { | 331 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
433 return VPX_CODEC_INVALID_PARAM; | 332 |
| 333 if (si->bitrates[0] != 0) { |
| 334 enc_cfg->rc_target_bitrate = 0; |
| 335 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 336 enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i]; |
| 337 enc_cfg->rc_target_bitrate += si->bitrates[i]; |
| 338 } |
| 339 } else { |
| 340 float total = 0; |
| 341 float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; |
| 342 |
| 343 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 344 if (si->svc_params.scaling_factor_den[i] > 0) { |
| 345 alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 / |
| 346 si->svc_params.scaling_factor_den[i]); |
| 347 |
| 348 alloc_ratio[i] *= alloc_ratio[i]; |
| 349 total += alloc_ratio[i]; |
| 350 } |
| 351 } |
| 352 |
| 353 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 354 if (total > 0) { |
| 355 enc_cfg->ss_target_bitrate[i] = (unsigned int) |
| 356 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); |
| 357 } |
| 358 } |
434 } | 359 } |
435 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); | |
436 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; | |
437 return VPX_CODEC_OK; | |
438 } | |
439 | |
440 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, | |
441 const char *scale_factors) { | |
442 SvcInternal *const si = get_svc_internal(svc_ctx); | |
443 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { | |
444 return VPX_CODEC_INVALID_PARAM; | |
445 } | |
446 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); | |
447 si->scale_factors[sizeof(si->scale_factors) - 1] = '\0'; | |
448 return VPX_CODEC_OK; | |
449 } | 360 } |
450 | 361 |
451 vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, | 362 vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, |
452 vpx_codec_iface_t *iface, | 363 vpx_codec_iface_t *iface, |
453 vpx_codec_enc_cfg_t *enc_cfg) { | 364 vpx_codec_enc_cfg_t *enc_cfg) { |
454 vpx_codec_err_t res; | 365 vpx_codec_err_t res; |
455 int i; | 366 int i; |
456 SvcInternal *const si = get_svc_internal(svc_ctx); | 367 SvcInternal *const si = get_svc_internal(svc_ctx); |
457 if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || | 368 if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || |
458 enc_cfg == NULL) { | 369 enc_cfg == NULL) { |
(...skipping 15 matching lines...) Expand all Loading... |
474 | 385 |
475 if (svc_ctx->spatial_layers == 0) | 386 if (svc_ctx->spatial_layers == 0) |
476 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; | 387 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; |
477 if (svc_ctx->spatial_layers < 1 || | 388 if (svc_ctx->spatial_layers < 1 || |
478 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { | 389 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { |
479 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", | 390 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", |
480 svc_ctx->spatial_layers); | 391 svc_ctx->spatial_layers); |
481 return VPX_CODEC_INVALID_PARAM; | 392 return VPX_CODEC_INVALID_PARAM; |
482 } | 393 } |
483 | 394 |
484 res = parse_quantizer_values(svc_ctx, si->quantizers); | 395 for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { |
485 if (res != VPX_CODEC_OK) return res; | 396 si->svc_params.max_quantizers[i] = MAX_QUANTIZER; |
486 | 397 si->svc_params.min_quantizers[i] = 0; |
487 res = parse_scale_factors(svc_ctx, si->scale_factors); | 398 si->svc_params.scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i]; |
488 if (res != VPX_CODEC_OK) return res; | 399 si->svc_params.scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i]; |
| 400 } |
489 | 401 |
490 // Parse aggregate command line options. Options must start with | 402 // Parse aggregate command line options. Options must start with |
491 // "layers=xx" then followed by other options | 403 // "layers=xx" then followed by other options |
492 res = parse_options(svc_ctx, si->options); | 404 res = parse_options(svc_ctx, si->options); |
493 if (res != VPX_CODEC_OK) return res; | 405 if (res != VPX_CODEC_OK) return res; |
494 | 406 |
495 if (svc_ctx->spatial_layers < 1) | 407 if (svc_ctx->spatial_layers < 1) |
496 svc_ctx->spatial_layers = 1; | 408 svc_ctx->spatial_layers = 1; |
497 if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) | 409 if (svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) |
498 svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; | 410 svc_ctx->spatial_layers = VPX_SS_MAX_LAYERS; |
499 | 411 |
500 if (svc_ctx->temporal_layers < 1) | 412 if (svc_ctx->temporal_layers < 1) |
501 svc_ctx->temporal_layers = 1; | 413 svc_ctx->temporal_layers = 1; |
502 if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) | 414 if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) |
503 svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; | 415 svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; |
504 | 416 |
505 si->layers = svc_ctx->spatial_layers; | 417 assign_layer_bitrates(svc_ctx, enc_cfg); |
506 | |
507 // Assign target bitrate for each layer. We calculate the ratio | |
508 // from the resolution for now. | |
509 // TODO(Minghai): Optimize the mechanism of allocating bits after | |
510 // implementing svc two pass rate control. | |
511 if (si->layers > 1) { | |
512 float total = 0; | |
513 float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; | |
514 | |
515 assert(si->layers <= VPX_SS_MAX_LAYERS); | |
516 for (i = 0; i < si->layers; ++i) { | |
517 int pos = i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers; | |
518 if (pos < VPX_SS_MAX_LAYERS && si->scaling_factor_den[pos] > 0) { | |
519 alloc_ratio[i] = (float)(si->scaling_factor_num[pos] * 1.0 / | |
520 si->scaling_factor_den[pos]); | |
521 | |
522 alloc_ratio[i] *= alloc_ratio[i]; | |
523 total += alloc_ratio[i]; | |
524 } | |
525 } | |
526 | |
527 for (i = 0; i < si->layers; ++i) { | |
528 if (total > 0) { | |
529 enc_cfg->ss_target_bitrate[i] = (unsigned int) | |
530 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); | |
531 } | |
532 } | |
533 } | |
534 | 418 |
535 #if CONFIG_SPATIAL_SVC | 419 #if CONFIG_SPATIAL_SVC |
536 for (i = 0; i < si->layers; ++i) | 420 for (i = 0; i < svc_ctx->spatial_layers; ++i) |
537 enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; | 421 enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i]; |
538 #endif | 422 #endif |
539 | 423 |
540 if (svc_ctx->temporal_layers > 1) { | 424 if (svc_ctx->temporal_layers > 1) { |
541 int i; | 425 int i; |
542 for (i = 0; i < svc_ctx->temporal_layers; ++i) { | 426 for (i = 0; i < svc_ctx->temporal_layers; ++i) { |
543 enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate / | 427 enc_cfg->ts_target_bitrate[i] = enc_cfg->rc_target_bitrate / |
544 svc_ctx->temporal_layers; | 428 svc_ctx->temporal_layers; |
545 enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); | 429 enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i); |
546 } | 430 } |
547 } | 431 } |
548 | 432 |
549 // modify encoder configuration | 433 // modify encoder configuration |
550 enc_cfg->ss_number_layers = si->layers; | 434 enc_cfg->ss_number_layers = svc_ctx->spatial_layers; |
551 enc_cfg->ts_number_layers = svc_ctx->temporal_layers; | 435 enc_cfg->ts_number_layers = svc_ctx->temporal_layers; |
552 | 436 |
553 // TODO(ivanmaltz): determine if these values need to be set explicitly for | |
554 // svc, or if the normal default/override mechanism can be used | |
555 enc_cfg->rc_dropframe_thresh = 0; | |
556 enc_cfg->rc_resize_allowed = 0; | |
557 | |
558 if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { | |
559 enc_cfg->rc_min_quantizer = 33; | |
560 enc_cfg->rc_max_quantizer = 33; | |
561 } | |
562 | |
563 enc_cfg->rc_undershoot_pct = 100; | |
564 enc_cfg->rc_overshoot_pct = 15; | |
565 enc_cfg->rc_buf_initial_sz = 500; | |
566 enc_cfg->rc_buf_optimal_sz = 600; | |
567 enc_cfg->rc_buf_sz = 1000; | |
568 if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) | 437 if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) |
569 enc_cfg->g_error_resilient = 1; | 438 enc_cfg->g_error_resilient = 1; |
570 | 439 |
571 // Initialize codec | 440 // Initialize codec |
572 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); | 441 res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); |
573 if (res != VPX_CODEC_OK) { | 442 if (res != VPX_CODEC_OK) { |
574 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); | 443 svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); |
575 return res; | 444 return res; |
576 } | 445 } |
577 | 446 |
578 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); | 447 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); |
579 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); | 448 vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params); |
580 | 449 |
581 return VPX_CODEC_OK; | 450 return VPX_CODEC_OK; |
582 } | 451 } |
583 | 452 |
584 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx, | |
585 int layer, | |
586 unsigned int *width, | |
587 unsigned int *height) { | |
588 int w, h, index, num, den; | |
589 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
590 | |
591 if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) { | |
592 return VPX_CODEC_INVALID_PARAM; | |
593 } | |
594 if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM; | |
595 | |
596 index = layer + VPX_SS_MAX_LAYERS - si->layers; | |
597 num = si->scaling_factor_num[index]; | |
598 den = si->scaling_factor_den[index]; | |
599 if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM; | |
600 | |
601 w = si->width * num / den; | |
602 h = si->height * num / den; | |
603 | |
604 // make height and width even to make chrome player happy | |
605 w += w % 2; | |
606 h += h % 2; | |
607 | |
608 *width = w; | |
609 *height = h; | |
610 | |
611 return VPX_CODEC_OK; | |
612 } | |
613 | |
614 static void set_svc_parameters(SvcContext *svc_ctx, | |
615 vpx_codec_ctx_t *codec_ctx) { | |
616 int layer, layer_index; | |
617 vpx_svc_parameters_t svc_params; | |
618 SvcInternal *const si = get_svc_internal(svc_ctx); | |
619 | |
620 memset(&svc_params, 0, sizeof(svc_params)); | |
621 svc_params.temporal_layer = 0; | |
622 svc_params.spatial_layer = si->layer; | |
623 | |
624 layer = si->layer; | |
625 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, | |
626 &svc_params.width, | |
627 &svc_params.height)) { | |
628 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); | |
629 } | |
630 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; | |
631 | |
632 if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) { | |
633 svc_params.min_quantizer = si->quantizer[layer_index]; | |
634 svc_params.max_quantizer = si->quantizer[layer_index]; | |
635 } else { | |
636 svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer; | |
637 svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer; | |
638 } | |
639 | |
640 svc_params.distance_from_i_frame = si->frame_within_gop; | |
641 vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params); | |
642 } | |
643 | |
644 /** | 453 /** |
645 * Encode a frame into multiple layers | 454 * Encode a frame into multiple layers |
646 * Create a superframe containing the individual layers | 455 * Create a superframe containing the individual layers |
647 */ | 456 */ |
648 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, | 457 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, |
649 struct vpx_image *rawimg, vpx_codec_pts_t pts, | 458 struct vpx_image *rawimg, vpx_codec_pts_t pts, |
650 int64_t duration, int deadline) { | 459 int64_t duration, int deadline) { |
651 vpx_codec_err_t res; | 460 vpx_codec_err_t res; |
652 vpx_codec_iter_t iter; | 461 vpx_codec_iter_t iter; |
653 const vpx_codec_cx_pkt_t *cx_pkt; | 462 const vpx_codec_cx_pkt_t *cx_pkt; |
654 int layer_for_psnr = 0; | |
655 SvcInternal *const si = get_svc_internal(svc_ctx); | 463 SvcInternal *const si = get_svc_internal(svc_ctx); |
656 if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { | 464 if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { |
657 return VPX_CODEC_INVALID_PARAM; | 465 return VPX_CODEC_INVALID_PARAM; |
658 } | 466 } |
659 | 467 |
660 svc_log_reset(svc_ctx); | 468 svc_log_reset(svc_ctx); |
661 si->rc_stats_buf_used = 0; | |
662 | |
663 si->layers = svc_ctx->spatial_layers; | |
664 if (si->encode_frame_count == 0) { | |
665 si->frame_within_gop = 0; | |
666 } | |
667 si->is_keyframe = (si->frame_within_gop == 0); | |
668 | |
669 if (rawimg != NULL) { | |
670 svc_log(svc_ctx, SVC_LOG_DEBUG, | |
671 "vpx_svc_encode layers: %d, frame_count: %d, " | |
672 "frame_within_gop: %d\n", si->layers, si->encode_frame_count, | |
673 si->frame_within_gop); | |
674 } | |
675 | |
676 if (rawimg != NULL) { | |
677 // encode each layer | |
678 for (si->layer = 0; si->layer < si->layers; ++si->layer) { | |
679 set_svc_parameters(svc_ctx, codec_ctx); | |
680 } | |
681 } | |
682 | 469 |
683 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, | 470 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, |
684 deadline); | 471 deadline); |
685 if (res != VPX_CODEC_OK) { | 472 if (res != VPX_CODEC_OK) { |
686 return res; | 473 return res; |
687 } | 474 } |
688 // save compressed data | 475 // save compressed data |
689 iter = NULL; | 476 iter = NULL; |
690 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { | 477 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { |
691 switch (cx_pkt->kind) { | 478 switch (cx_pkt->kind) { |
692 case VPX_CODEC_CX_FRAME_PKT: { | 479 #if CONFIG_SPATIAL_SVC |
693 fd_list_add(&si->frame_list, fd_create(cx_pkt->data.frame.buf, | 480 case VPX_CODEC_SPATIAL_SVC_LAYER_PSNR: { |
694 cx_pkt->data.frame.sz, | 481 int i; |
695 cx_pkt->data.frame.flags)); | 482 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 483 int j; |
| 484 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 485 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " |
| 486 "%2.3f %2.3f %2.3f %2.3f \n", |
| 487 si->psnr_pkt_received, i, |
| 488 cx_pkt->data.layer_psnr[i].psnr[0], |
| 489 cx_pkt->data.layer_psnr[i].psnr[1], |
| 490 cx_pkt->data.layer_psnr[i].psnr[2], |
| 491 cx_pkt->data.layer_psnr[i].psnr[3]); |
| 492 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 493 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " |
| 494 "%2.3f %2.3f %2.3f %2.3f \n", |
| 495 si->psnr_pkt_received, i, |
| 496 cx_pkt->data.layer_psnr[i].sse[0], |
| 497 cx_pkt->data.layer_psnr[i].sse[1], |
| 498 cx_pkt->data.layer_psnr[i].sse[2], |
| 499 cx_pkt->data.layer_psnr[i].sse[3]); |
696 | 500 |
697 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, " | 501 for (j = 0; j < COMPONENTS; ++j) { |
698 "pts: %d\n", si->frame_received, | 502 si->psnr_sum[i][j] += |
699 (cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? 1 : 0, | 503 cx_pkt->data.layer_psnr[i].psnr[j]; |
700 (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts); | 504 si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j]; |
701 | 505 } |
702 ++si->frame_received; | 506 } |
703 layer_for_psnr = 0; | 507 ++si->psnr_pkt_received; |
704 break; | 508 break; |
705 } | 509 } |
706 case VPX_CODEC_PSNR_PKT: { | |
707 int i; | |
708 svc_log(svc_ctx, SVC_LOG_DEBUG, | |
709 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " | |
710 "%2.3f %2.3f %2.3f %2.3f \n", | |
711 si->frame_received, layer_for_psnr, | |
712 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], | |
713 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); | |
714 svc_log(svc_ctx, SVC_LOG_DEBUG, | |
715 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " | |
716 "%2.3f %2.3f %2.3f %2.3f \n", | |
717 si->frame_received, layer_for_psnr, | |
718 cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1], | |
719 cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]); | |
720 for (i = 0; i < COMPONENTS; i++) { | |
721 si->psnr_sum[layer_for_psnr][i] += cx_pkt->data.psnr.psnr[i]; | |
722 si->sse_sum[layer_for_psnr][i] += cx_pkt->data.psnr.sse[i]; | |
723 } | |
724 ++layer_for_psnr; | |
725 break; | |
726 } | |
727 case VPX_CODEC_STATS_PKT: { | |
728 size_t new_size = si->rc_stats_buf_used + | |
729 cx_pkt->data.twopass_stats.sz; | |
730 | |
731 if (new_size > si->rc_stats_buf_size) { | |
732 char *p = (char*)realloc(si->rc_stats_buf, new_size); | |
733 if (p == NULL) { | |
734 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n"); | |
735 return VPX_CODEC_MEM_ERROR; | |
736 } | |
737 si->rc_stats_buf = p; | |
738 si->rc_stats_buf_size = new_size; | |
739 } | |
740 | |
741 memcpy(si->rc_stats_buf + si->rc_stats_buf_used, | |
742 cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); | |
743 si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz; | |
744 break; | |
745 } | |
746 #if CONFIG_SPATIAL_SVC | |
747 case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: { | 510 case VPX_CODEC_SPATIAL_SVC_LAYER_SIZES: { |
748 int i; | 511 int i; |
749 for (i = 0; i < si->layers; ++i) | 512 for (i = 0; i < svc_ctx->spatial_layers; ++i) |
750 si->bytes_sum[i] += cx_pkt->data.layer_sizes[i]; | 513 si->bytes_sum[i] += cx_pkt->data.layer_sizes[i]; |
751 break; | 514 break; |
752 } | 515 } |
753 #endif | 516 #endif |
754 default: { | 517 default: { |
755 break; | 518 break; |
756 } | 519 } |
757 } | 520 } |
758 } | 521 } |
759 | 522 |
760 if (rawimg != NULL) { | |
761 ++si->frame_within_gop; | |
762 ++si->encode_frame_count; | |
763 } | |
764 | |
765 return VPX_CODEC_OK; | 523 return VPX_CODEC_OK; |
766 } | 524 } |
767 | 525 |
768 const char *vpx_svc_get_message(const SvcContext *svc_ctx) { | 526 const char *vpx_svc_get_message(const SvcContext *svc_ctx) { |
769 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 527 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
770 if (svc_ctx == NULL || si == NULL) return NULL; | 528 if (svc_ctx == NULL || si == NULL) return NULL; |
771 return si->message_buffer; | 529 return si->message_buffer; |
772 } | 530 } |
773 | 531 |
774 // We will maintain a list of output frame buffers since with lag_in_frame | |
775 // we need to output all frame buffers at the end. vpx_svc_get_buffer() will | |
776 // remove a frame buffer from the list the put it to a temporal pointer, which | |
777 // will be removed at the next vpx_svc_get_buffer() or when closing encoder. | |
778 void *vpx_svc_get_buffer(SvcContext *svc_ctx) { | |
779 SvcInternal *const si = get_svc_internal(svc_ctx); | |
780 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return NULL; | |
781 | |
782 if (si->frame_temp) | |
783 fd_free(si->frame_temp); | |
784 | |
785 si->frame_temp = si->frame_list; | |
786 si->frame_list = si->frame_list->next; | |
787 | |
788 return si->frame_temp->buf; | |
789 } | |
790 | |
791 size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) { | |
792 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
793 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0; | |
794 return si->frame_list->size; | |
795 } | |
796 | |
797 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) { | |
798 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
799 if (svc_ctx == NULL || si == NULL) return 0; | |
800 return si->encode_frame_count; | |
801 } | |
802 | |
803 int vpx_svc_is_keyframe(const SvcContext *svc_ctx) { | |
804 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
805 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0; | |
806 return (si->frame_list->flags & VPX_FRAME_IS_KEY) != 0; | |
807 } | |
808 | |
809 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { | |
810 SvcInternal *const si = get_svc_internal(svc_ctx); | |
811 if (svc_ctx == NULL || si == NULL) return; | |
812 si->frame_within_gop = 0; | |
813 } | |
814 | |
815 static double calc_psnr(double d) { | 532 static double calc_psnr(double d) { |
816 if (d == 0) return 100; | 533 if (d == 0) return 100; |
817 return -10.0 * log(d) / log(10.0); | 534 return -10.0 * log(d) / log(10.0); |
818 } | 535 } |
819 | 536 |
820 // dump accumulated statistics and reset accumulated values | 537 // dump accumulated statistics and reset accumulated values |
821 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { | 538 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { |
822 int number_of_frames, encode_frame_count; | 539 int number_of_frames; |
823 int i, j; | 540 int i, j; |
824 uint32_t bytes_total = 0; | 541 uint32_t bytes_total = 0; |
825 double scale[COMPONENTS]; | 542 double scale[COMPONENTS]; |
826 double psnr[COMPONENTS]; | 543 double psnr[COMPONENTS]; |
827 double mse[COMPONENTS]; | 544 double mse[COMPONENTS]; |
828 double y_scale; | 545 double y_scale; |
829 | 546 |
830 SvcInternal *const si = get_svc_internal(svc_ctx); | 547 SvcInternal *const si = get_svc_internal(svc_ctx); |
831 if (svc_ctx == NULL || si == NULL) return NULL; | 548 if (svc_ctx == NULL || si == NULL) return NULL; |
832 | 549 |
833 svc_log_reset(svc_ctx); | 550 svc_log_reset(svc_ctx); |
834 | 551 |
835 encode_frame_count = si->encode_frame_count; | 552 number_of_frames = si->psnr_pkt_received; |
836 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); | 553 if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx); |
837 | 554 |
838 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); | 555 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); |
839 for (i = 0; i < si->layers; ++i) { | 556 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
840 number_of_frames = encode_frame_count; | |
841 | 557 |
842 svc_log(svc_ctx, SVC_LOG_INFO, | 558 svc_log(svc_ctx, SVC_LOG_INFO, |
843 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", | 559 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", |
844 i, (double)si->psnr_sum[i][0] / number_of_frames, | 560 i, (double)si->psnr_sum[i][0] / number_of_frames, |
845 (double)si->psnr_sum[i][1] / number_of_frames, | 561 (double)si->psnr_sum[i][1] / number_of_frames, |
846 (double)si->psnr_sum[i][2] / number_of_frames, | 562 (double)si->psnr_sum[i][2] / number_of_frames, |
847 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); | 563 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); |
848 // the following psnr calculation is deduced from ffmpeg.c#print_report | 564 // the following psnr calculation is deduced from ffmpeg.c#print_report |
849 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; | 565 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; |
850 scale[1] = y_scale; | 566 scale[1] = y_scale; |
(...skipping 14 matching lines...) Expand all Loading... |
865 bytes_total += si->bytes_sum[i]; | 581 bytes_total += si->bytes_sum[i]; |
866 // clear sums for next time | 582 // clear sums for next time |
867 si->bytes_sum[i] = 0; | 583 si->bytes_sum[i] = 0; |
868 for (j = 0; j < COMPONENTS; ++j) { | 584 for (j = 0; j < COMPONENTS; ++j) { |
869 si->psnr_sum[i][j] = 0; | 585 si->psnr_sum[i][j] = 0; |
870 si->sse_sum[i][j] = 0; | 586 si->sse_sum[i][j] = 0; |
871 } | 587 } |
872 } | 588 } |
873 | 589 |
874 // only display statistics once | 590 // only display statistics once |
875 si->encode_frame_count = 0; | 591 si->psnr_pkt_received = 0; |
876 | 592 |
877 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); | 593 svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); |
878 return vpx_svc_get_message(svc_ctx); | 594 return vpx_svc_get_message(svc_ctx); |
879 } | 595 } |
880 | 596 |
881 void vpx_svc_release(SvcContext *svc_ctx) { | 597 void vpx_svc_release(SvcContext *svc_ctx) { |
882 SvcInternal *si; | 598 SvcInternal *si; |
883 if (svc_ctx == NULL) return; | 599 if (svc_ctx == NULL) return; |
884 // do not use get_svc_internal as it will unnecessarily allocate an | 600 // do not use get_svc_internal as it will unnecessarily allocate an |
885 // SvcInternal if it was not already allocated | 601 // SvcInternal if it was not already allocated |
886 si = (SvcInternal *)svc_ctx->internal; | 602 si = (SvcInternal *)svc_ctx->internal; |
887 if (si != NULL) { | 603 if (si != NULL) { |
888 fd_free(si->frame_temp); | |
889 fd_free_list(si->frame_list); | |
890 if (si->rc_stats_buf) { | |
891 free(si->rc_stats_buf); | |
892 } | |
893 free(si); | 604 free(si); |
894 svc_ctx->internal = NULL; | 605 svc_ctx->internal = NULL; |
895 } | 606 } |
896 } | 607 } |
897 | 608 |
898 size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) { | |
899 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
900 if (svc_ctx == NULL || si == NULL) return 0; | |
901 return si->rc_stats_buf_used; | |
902 } | |
903 | |
904 char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { | |
905 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | |
906 if (svc_ctx == NULL || si == NULL) return NULL; | |
907 return si->rc_stats_buf; | |
908 } | |
909 | |
910 | |
OLD | NEW |