| 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 <stdarg.h> | 18 #include <stdarg.h> |
| 19 #include <stdio.h> | 19 #include <stdio.h> |
| 20 #include <stdlib.h> | 20 #include <stdlib.h> |
| 21 #include <string.h> | 21 #include <string.h> |
| 22 #define VPX_DISABLE_CTRL_TYPECHECKS 1 | 22 #define VPX_DISABLE_CTRL_TYPECHECKS 1 |
| 23 #define VPX_CODEC_DISABLE_COMPAT 1 | 23 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 24 #include "vpx/svc_context.h" | 24 #include "vpx/svc_context.h" |
| 25 #include "vpx/vp8cx.h" | 25 #include "vpx/vp8cx.h" |
| 26 #include "vpx/vpx_encoder.h" | 26 #include "vpx/vpx_encoder.h" |
| 27 #include "vpx_mem/vpx_mem.h" |
| 27 | 28 |
| 28 #ifdef __MINGW32__ | 29 #ifdef __MINGW32__ |
| 29 #define strtok_r strtok_s | 30 #define strtok_r strtok_s |
| 30 #ifndef MINGW_HAS_SECURE_API | 31 #ifndef MINGW_HAS_SECURE_API |
| 31 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h | 32 // proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h |
| 32 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); | 33 _CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); |
| 33 #endif /* MINGW_HAS_SECURE_API */ | 34 #endif /* MINGW_HAS_SECURE_API */ |
| 34 #endif /* __MINGW32__ */ | 35 #endif /* __MINGW32__ */ |
| 35 | 36 |
| 36 #ifdef _MSC_VER | 37 #ifdef _MSC_VER |
| 37 #define strdup _strdup | 38 #define strdup _strdup |
| 38 #define strtok_r strtok_s | 39 #define strtok_r strtok_s |
| 39 #endif | 40 #endif |
| 40 | 41 |
| 41 #define SVC_REFERENCE_FRAMES 8 | 42 #define SVC_REFERENCE_FRAMES 8 |
| 42 #define SUPERFRAME_SLOTS (8) | 43 #define SUPERFRAME_SLOTS (8) |
| 43 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) | 44 #define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) |
| 44 #define OPTION_BUFFER_SIZE 256 | 45 #define OPTION_BUFFER_SIZE 256 |
| 45 #define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v | 46 #define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v |
| 46 | 47 |
| 47 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; | 48 static const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; |
| 48 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; | 49 static const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; |
| 49 | 50 |
| 51 // One encoded frame |
| 52 typedef struct FrameData { |
| 53 void *buf; // compressed data buffer |
| 54 size_t size; // length of compressed data |
| 55 vpx_codec_frame_flags_t flags; /**< flags for this frame */ |
| 56 struct FrameData *next; |
| 57 } FrameData; |
| 58 |
| 50 typedef struct SvcInternal { | 59 typedef struct SvcInternal { |
| 51 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options | 60 char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options |
| 52 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers | 61 char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers |
| 53 char quantizers_keyframe[OPTION_BUFFER_SIZE]; // set by | |
| 54 // vpx_svc_set_quantizers | |
| 55 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors | 62 char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors |
| 56 | 63 |
| 57 // values extracted from option, quantizers | 64 // values extracted from option, quantizers |
| 58 int scaling_factor_num[VPX_SS_MAX_LAYERS]; | 65 int scaling_factor_num[VPX_SS_MAX_LAYERS]; |
| 59 int scaling_factor_den[VPX_SS_MAX_LAYERS]; | 66 int scaling_factor_den[VPX_SS_MAX_LAYERS]; |
| 60 int quantizer_keyframe[VPX_SS_MAX_LAYERS]; | |
| 61 int quantizer[VPX_SS_MAX_LAYERS]; | 67 int quantizer[VPX_SS_MAX_LAYERS]; |
| 62 | 68 |
| 63 // accumulated statistics | 69 // accumulated statistics |
| 64 double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V | 70 double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V |
| 65 uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; | 71 uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; |
| 66 uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; | 72 uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; |
| 67 | 73 |
| 68 // codec encoding values | 74 // codec encoding values |
| 69 int width; // width of highest layer | 75 int width; // width of highest layer |
| 70 int height; // height of highest layer | 76 int height; // height of highest layer |
| 71 int kf_dist; // distance between keyframes | 77 int kf_dist; // distance between keyframes |
| 72 | 78 |
| 73 // state variables | 79 // state variables |
| 74 int encode_frame_count; | 80 int encode_frame_count; |
| 81 int frame_received; |
| 75 int frame_within_gop; | 82 int frame_within_gop; |
| 76 vpx_enc_frame_flags_t enc_frame_flags; | 83 vpx_enc_frame_flags_t enc_frame_flags; |
| 77 int layers; | 84 int layers; |
| 78 int layer; | 85 int layer; |
| 79 int is_keyframe; | 86 int is_keyframe; |
| 80 | 87 |
| 81 size_t frame_size; | 88 FrameData *frame_list; |
| 82 size_t buffer_size; | 89 FrameData *frame_temp; |
| 83 void *buffer; | |
| 84 | 90 |
| 85 char *rc_stats_buf; | 91 char *rc_stats_buf; |
| 86 size_t rc_stats_buf_size; | 92 size_t rc_stats_buf_size; |
| 87 size_t rc_stats_buf_used; | 93 size_t rc_stats_buf_used; |
| 88 | 94 |
| 89 char message_buffer[2048]; | 95 char message_buffer[2048]; |
| 90 vpx_codec_ctx_t *codec_ctx; | 96 vpx_codec_ctx_t *codec_ctx; |
| 91 } SvcInternal; | 97 } SvcInternal; |
| 92 | 98 |
| 93 // Superframe is used to generate an index of individual frames (i.e., layers) | 99 // create FrameData from encoder output |
| 94 struct Superframe { | 100 static struct FrameData *fd_create(void *buf, size_t size, |
| 95 int count; | 101 vpx_codec_frame_flags_t flags) { |
| 96 uint32_t sizes[SUPERFRAME_SLOTS]; | 102 struct FrameData *const frame_data = |
| 97 uint32_t magnitude; | 103 (struct FrameData *)vpx_malloc(sizeof(*frame_data)); |
| 98 uint8_t buffer[SUPERFRAME_BUFFER_SIZE]; | 104 if (frame_data == NULL) { |
| 99 size_t index_size; | |
| 100 }; | |
| 101 | |
| 102 // One encoded frame layer | |
| 103 struct LayerData { | |
| 104 void *buf; // compressed data buffer | |
| 105 size_t size; // length of compressed data | |
| 106 struct LayerData *next; | |
| 107 }; | |
| 108 | |
| 109 // create LayerData from encoder output | |
| 110 static struct LayerData *ld_create(void *buf, size_t size) { | |
| 111 struct LayerData *const layer_data = | |
| 112 (struct LayerData *)malloc(sizeof(*layer_data)); | |
| 113 if (layer_data == NULL) { | |
| 114 return NULL; | 105 return NULL; |
| 115 } | 106 } |
| 116 layer_data->buf = malloc(size); | 107 frame_data->buf = vpx_malloc(size); |
| 117 if (layer_data->buf == NULL) { | 108 if (frame_data->buf == NULL) { |
| 118 free(layer_data); | 109 vpx_free(frame_data); |
| 119 return NULL; | 110 return NULL; |
| 120 } | 111 } |
| 121 memcpy(layer_data->buf, buf, size); | 112 vpx_memcpy(frame_data->buf, buf, size); |
| 122 layer_data->size = size; | 113 frame_data->size = size; |
| 123 return layer_data; | 114 frame_data->flags = flags; |
| 115 return frame_data; |
| 124 } | 116 } |
| 125 | 117 |
| 126 // free LayerData | 118 // free FrameData |
| 127 static void ld_free(struct LayerData *layer_data) { | 119 static void fd_free(struct FrameData *p) { |
| 128 if (layer_data) { | 120 if (p) { |
| 129 if (layer_data->buf) { | 121 if (p->buf) |
| 130 free(layer_data->buf); | 122 vpx_free(p->buf); |
| 131 layer_data->buf = NULL; | 123 vpx_free(p); |
| 132 } | |
| 133 free(layer_data); | |
| 134 } | 124 } |
| 135 } | 125 } |
| 136 | 126 |
| 137 // add layer data to list | 127 // add FrameData to list |
| 138 static void ld_list_add(struct LayerData **list, struct LayerData *layer_data) { | 128 static void fd_list_add(struct FrameData **list, struct FrameData *layer_data) { |
| 139 struct LayerData **p = list; | 129 struct FrameData **p = list; |
| 140 | 130 |
| 141 while (*p != NULL) p = &(*p)->next; | 131 while (*p != NULL) p = &(*p)->next; |
| 142 *p = layer_data; | 132 *p = layer_data; |
| 143 layer_data->next = NULL; | 133 layer_data->next = NULL; |
| 144 } | 134 } |
| 145 | 135 |
| 146 // get accumulated size of layer data | 136 // free FrameData list |
| 147 static size_t ld_list_get_buffer_size(struct LayerData *list) { | 137 static void fd_free_list(struct FrameData *list) { |
| 148 struct LayerData *p; | 138 struct FrameData *p = list; |
| 149 size_t size = 0; | |
| 150 | |
| 151 for (p = list; p != NULL; p = p->next) { | |
| 152 size += p->size; | |
| 153 } | |
| 154 return size; | |
| 155 } | |
| 156 | |
| 157 // copy layer data to buffer | |
| 158 static void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) { | |
| 159 struct LayerData *p; | |
| 160 | |
| 161 for (p = list; p != NULL; p = p->next) { | |
| 162 buffer[0] = 1; | |
| 163 memcpy(buffer, p->buf, p->size); | |
| 164 buffer += p->size; | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 // free layer data list | |
| 169 static void ld_list_free(struct LayerData *list) { | |
| 170 struct LayerData *p = list; | |
| 171 | 139 |
| 172 while (p) { | 140 while (p) { |
| 173 list = list->next; | 141 list = list->next; |
| 174 ld_free(p); | 142 fd_free(p); |
| 175 p = list; | 143 p = list; |
| 176 } | 144 } |
| 177 } | 145 } |
| 178 | 146 |
| 179 static void sf_create_index(struct Superframe *sf) { | |
| 180 uint8_t marker = 0xc0; | |
| 181 int i; | |
| 182 uint32_t mag, mask; | |
| 183 uint8_t *bufp; | |
| 184 | |
| 185 if (sf->count == 0 || sf->count >= 8) return; | |
| 186 | |
| 187 // Add the number of frames to the marker byte | |
| 188 marker |= sf->count - 1; | |
| 189 | |
| 190 // Choose the magnitude | |
| 191 for (mag = 0, mask = 0xff; mag < 4; ++mag) { | |
| 192 if (sf->magnitude < mask) break; | |
| 193 mask <<= 8; | |
| 194 mask |= 0xff; | |
| 195 } | |
| 196 marker |= mag << 3; | |
| 197 | |
| 198 // Write the index | |
| 199 sf->index_size = 2 + (mag + 1) * sf->count; | |
| 200 bufp = sf->buffer; | |
| 201 | |
| 202 *bufp++ = marker; | |
| 203 for (i = 0; i < sf->count; ++i) { | |
| 204 int this_sz = sf->sizes[i]; | |
| 205 uint32_t j; | |
| 206 | |
| 207 for (j = 0; j <= mag; ++j) { | |
| 208 *bufp++ = this_sz & 0xff; | |
| 209 this_sz >>= 8; | |
| 210 } | |
| 211 } | |
| 212 *bufp++ = marker; | |
| 213 } | |
| 214 | |
| 215 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) { | 147 static SvcInternal *get_svc_internal(SvcContext *svc_ctx) { |
| 216 if (svc_ctx == NULL) return NULL; | 148 if (svc_ctx == NULL) return NULL; |
| 217 if (svc_ctx->internal == NULL) { | 149 if (svc_ctx->internal == NULL) { |
| 218 SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si)); | 150 SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si)); |
| 219 if (si != NULL) { | 151 if (si != NULL) { |
| 220 memset(si, 0, sizeof(*si)); | 152 memset(si, 0, sizeof(*si)); |
| 221 } | 153 } |
| 222 svc_ctx->internal = si; | 154 svc_ctx->internal = si; |
| 223 } | 155 } |
| 224 return (SvcInternal *)svc_ctx->internal; | 156 return (SvcInternal *)svc_ctx->internal; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 255 strncat(si->message_buffer, buf, | 187 strncat(si->message_buffer, buf, |
| 256 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); | 188 sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); |
| 257 } | 189 } |
| 258 | 190 |
| 259 if (level == SVC_LOG_ERROR) { | 191 if (level == SVC_LOG_ERROR) { |
| 260 si->codec_ctx->err_detail = si->message_buffer; | 192 si->codec_ctx->err_detail = si->message_buffer; |
| 261 } | 193 } |
| 262 return retval; | 194 return retval; |
| 263 } | 195 } |
| 264 | 196 |
| 265 static vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx, | |
| 266 const char *value_str) { | |
| 267 if (strcmp(value_str, "i") == 0) { | |
| 268 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I; | |
| 269 } else if (strcmp(value_str, "alt-ip") == 0) { | |
| 270 svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP; | |
| 271 } else if (strcmp(value_str, "ip") == 0) { | |
| 272 svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP; | |
| 273 } else if (strcmp(value_str, "gf") == 0) { | |
| 274 svc_ctx->encoding_mode = USE_GOLDEN_FRAME; | |
| 275 } else { | |
| 276 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str); | |
| 277 return VPX_CODEC_INVALID_PARAM; | |
| 278 } | |
| 279 return VPX_CODEC_OK; | |
| 280 } | |
| 281 | |
| 282 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, | 197 static vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, |
| 283 const char *quantizer_values, | 198 const char *quantizer_values) { |
| 284 const int is_keyframe) { | |
| 285 char *input_string; | 199 char *input_string; |
| 286 char *token; | 200 char *token; |
| 287 const char *delim = ","; | 201 const char *delim = ","; |
| 288 char *save_ptr; | 202 char *save_ptr; |
| 289 int found = 0; | 203 int found = 0; |
| 290 int i, q; | 204 int i, q; |
| 291 vpx_codec_err_t res = VPX_CODEC_OK; | 205 vpx_codec_err_t res = VPX_CODEC_OK; |
| 292 SvcInternal *const si = get_svc_internal(svc_ctx); | 206 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 293 | 207 |
| 294 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { | 208 if (quantizer_values == NULL || strlen(quantizer_values) == 0) { |
| 295 if (is_keyframe) { | |
| 296 // If there non settings for key frame, we will apply settings from | |
| 297 // non key frame. So just simply return here. | |
| 298 return VPX_CODEC_INVALID_PARAM; | |
| 299 } | |
| 300 input_string = strdup(DEFAULT_QUANTIZER_VALUES); | 209 input_string = strdup(DEFAULT_QUANTIZER_VALUES); |
| 301 } else { | 210 } else { |
| 302 input_string = strdup(quantizer_values); | 211 input_string = strdup(quantizer_values); |
| 303 } | 212 } |
| 304 | 213 |
| 305 token = strtok_r(input_string, delim, &save_ptr); | 214 token = strtok_r(input_string, delim, &save_ptr); |
| 306 for (i = 0; i < svc_ctx->spatial_layers; ++i) { | 215 for (i = 0; i < svc_ctx->spatial_layers; ++i) { |
| 307 if (token != NULL) { | 216 if (token != NULL) { |
| 308 q = atoi(token); | 217 q = atoi(token); |
| 309 if (q <= 0 || q > 100) { | 218 if (q <= 0 || q > 100) { |
| 310 svc_log(svc_ctx, SVC_LOG_ERROR, | 219 svc_log(svc_ctx, SVC_LOG_ERROR, |
| 311 "svc-quantizer-values: invalid value %s\n", token); | 220 "svc-quantizer-values: invalid value %s\n", token); |
| 312 res = VPX_CODEC_INVALID_PARAM; | 221 res = VPX_CODEC_INVALID_PARAM; |
| 313 break; | 222 break; |
| 314 } | 223 } |
| 315 token = strtok_r(NULL, delim, &save_ptr); | 224 token = strtok_r(NULL, delim, &save_ptr); |
| 316 found = i + 1; | 225 found = i + 1; |
| 317 } else { | 226 } else { |
| 318 q = 0; | 227 q = 0; |
| 319 } | 228 } |
| 320 if (is_keyframe) { | 229 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; |
| 321 si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] | |
| 322 = q; | |
| 323 } else { | |
| 324 si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; | |
| 325 } | |
| 326 } | 230 } |
| 327 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { | 231 if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { |
| 328 svc_log(svc_ctx, SVC_LOG_ERROR, | 232 svc_log(svc_ctx, SVC_LOG_ERROR, |
| 329 "svc: quantizers: %d values required, but only %d specified\n", | 233 "svc: quantizers: %d values required, but only %d specified\n", |
| 330 svc_ctx->spatial_layers, found); | 234 svc_ctx->spatial_layers, found); |
| 331 res = VPX_CODEC_INVALID_PARAM; | 235 res = VPX_CODEC_INVALID_PARAM; |
| 332 } | 236 } |
| 333 free(input_string); | 237 free(input_string); |
| 334 return res; | 238 return res; |
| 335 } | 239 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 * Format: encoding-mode=<svc_mode>,layers=<layer_count> | 304 * Format: encoding-mode=<svc_mode>,layers=<layer_count> |
| 401 * scale-factors=<n1>/<d1>,<n2>/<d2>,... | 305 * scale-factors=<n1>/<d1>,<n2>/<d2>,... |
| 402 * quantizers=<q1>,<q2>,... | 306 * quantizers=<q1>,<q2>,... |
| 403 * svc_mode = [i|ip|alt_ip|gf] | 307 * svc_mode = [i|ip|alt_ip|gf] |
| 404 */ | 308 */ |
| 405 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { | 309 static vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { |
| 406 char *input_string; | 310 char *input_string; |
| 407 char *option_name; | 311 char *option_name; |
| 408 char *option_value; | 312 char *option_value; |
| 409 char *input_ptr; | 313 char *input_ptr; |
| 410 int is_keyframe_qaunt_set = 0; | |
| 411 vpx_codec_err_t res = VPX_CODEC_OK; | 314 vpx_codec_err_t res = VPX_CODEC_OK; |
| 412 | 315 |
| 413 if (options == NULL) return VPX_CODEC_OK; | 316 if (options == NULL) return VPX_CODEC_OK; |
| 414 input_string = strdup(options); | 317 input_string = strdup(options); |
| 415 | 318 |
| 416 // parse option name | 319 // parse option name |
| 417 option_name = strtok_r(input_string, "=", &input_ptr); | 320 option_name = strtok_r(input_string, "=", &input_ptr); |
| 418 while (option_name != NULL) { | 321 while (option_name != NULL) { |
| 419 // parse option value | 322 // parse option value |
| 420 option_value = strtok_r(NULL, " ", &input_ptr); | 323 option_value = strtok_r(NULL, " ", &input_ptr); |
| 421 if (option_value == NULL) { | 324 if (option_value == NULL) { |
| 422 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", | 325 svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", |
| 423 option_name); | 326 option_name); |
| 424 res = VPX_CODEC_INVALID_PARAM; | 327 res = VPX_CODEC_INVALID_PARAM; |
| 425 break; | 328 break; |
| 426 } | 329 } |
| 427 if (strcmp("encoding-mode", option_name) == 0) { | 330 if (strcmp("layers", option_name) == 0) { |
| 428 res = set_option_encoding_mode(svc_ctx, option_value); | |
| 429 if (res != VPX_CODEC_OK) break; | |
| 430 } else if (strcmp("layers", option_name) == 0) { | |
| 431 svc_ctx->spatial_layers = atoi(option_value); | 331 svc_ctx->spatial_layers = atoi(option_value); |
| 432 } else if (strcmp("scale-factors", option_name) == 0) { | 332 } else if (strcmp("scale-factors", option_name) == 0) { |
| 433 res = parse_scale_factors(svc_ctx, option_value); | 333 res = parse_scale_factors(svc_ctx, option_value); |
| 434 if (res != VPX_CODEC_OK) break; | 334 if (res != VPX_CODEC_OK) break; |
| 435 } else if (strcmp("quantizers", option_name) == 0) { | 335 } else if (strcmp("quantizers", option_name) == 0) { |
| 436 res = parse_quantizer_values(svc_ctx, option_value, 0); | 336 res = parse_quantizer_values(svc_ctx, option_value); |
| 437 if (res != VPX_CODEC_OK) break; | 337 if (res != VPX_CODEC_OK) break; |
| 438 if (!is_keyframe_qaunt_set) { | |
| 439 SvcInternal *const si = get_svc_internal(svc_ctx); | |
| 440 memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer, | |
| 441 sizeof(si->quantizer)); | |
| 442 } | |
| 443 } else if (strcmp("quantizers-keyframe", option_name) == 0) { | |
| 444 res = parse_quantizer_values(svc_ctx, option_value, 1); | |
| 445 if (res != VPX_CODEC_OK) break; | |
| 446 is_keyframe_qaunt_set = 1; | |
| 447 } else { | 338 } else { |
| 448 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); | 339 svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); |
| 449 res = VPX_CODEC_INVALID_PARAM; | 340 res = VPX_CODEC_INVALID_PARAM; |
| 450 break; | 341 break; |
| 451 } | 342 } |
| 452 option_name = strtok_r(NULL, "=", &input_ptr); | 343 option_name = strtok_r(NULL, "=", &input_ptr); |
| 453 } | 344 } |
| 454 free(input_string); | 345 free(input_string); |
| 455 return res; | 346 return res; |
| 456 } | 347 } |
| 457 | 348 |
| 458 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { | 349 vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { |
| 459 SvcInternal *const si = get_svc_internal(svc_ctx); | 350 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 460 if (svc_ctx == NULL || options == NULL || si == NULL) { | 351 if (svc_ctx == NULL || options == NULL || si == NULL) { |
| 461 return VPX_CODEC_INVALID_PARAM; | 352 return VPX_CODEC_INVALID_PARAM; |
| 462 } | 353 } |
| 463 strncpy(si->options, options, sizeof(si->options)); | 354 strncpy(si->options, options, sizeof(si->options)); |
| 464 si->options[sizeof(si->options) - 1] = '\0'; | 355 si->options[sizeof(si->options) - 1] = '\0'; |
| 465 return VPX_CODEC_OK; | 356 return VPX_CODEC_OK; |
| 466 } | 357 } |
| 467 | 358 |
| 468 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, | 359 vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, |
| 469 const char *quantizers, | 360 const char *quantizers) { |
| 470 const int is_for_keyframe) { | |
| 471 SvcInternal *const si = get_svc_internal(svc_ctx); | 361 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 472 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { | 362 if (svc_ctx == NULL || quantizers == NULL || si == NULL) { |
| 473 return VPX_CODEC_INVALID_PARAM; | 363 return VPX_CODEC_INVALID_PARAM; |
| 474 } | 364 } |
| 475 if (is_for_keyframe) { | 365 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); |
| 476 strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers)); | 366 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; |
| 477 si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0'; | |
| 478 } else { | |
| 479 strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); | |
| 480 si->quantizers[sizeof(si->quantizers) - 1] = '\0'; | |
| 481 } | |
| 482 return VPX_CODEC_OK; | 367 return VPX_CODEC_OK; |
| 483 } | 368 } |
| 484 | 369 |
| 485 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, | 370 vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, |
| 486 const char *scale_factors) { | 371 const char *scale_factors) { |
| 487 SvcInternal *const si = get_svc_internal(svc_ctx); | 372 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 488 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { | 373 if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { |
| 489 return VPX_CODEC_INVALID_PARAM; | 374 return VPX_CODEC_INVALID_PARAM; |
| 490 } | 375 } |
| 491 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); | 376 strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 518 | 403 |
| 519 if (svc_ctx->spatial_layers == 0) | 404 if (svc_ctx->spatial_layers == 0) |
| 520 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; | 405 svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; |
| 521 if (svc_ctx->spatial_layers < 1 || | 406 if (svc_ctx->spatial_layers < 1 || |
| 522 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { | 407 svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { |
| 523 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", | 408 svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", |
| 524 svc_ctx->spatial_layers); | 409 svc_ctx->spatial_layers); |
| 525 return VPX_CODEC_INVALID_PARAM; | 410 return VPX_CODEC_INVALID_PARAM; |
| 526 } | 411 } |
| 527 | 412 |
| 528 res = parse_quantizer_values(svc_ctx, si->quantizers, 0); | 413 res = parse_quantizer_values(svc_ctx, si->quantizers); |
| 529 if (res != VPX_CODEC_OK) return res; | 414 if (res != VPX_CODEC_OK) return res; |
| 530 | 415 |
| 531 res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1); | |
| 532 if (res != VPX_CODEC_OK) | |
| 533 memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer)); | |
| 534 | |
| 535 res = parse_scale_factors(svc_ctx, si->scale_factors); | 416 res = parse_scale_factors(svc_ctx, si->scale_factors); |
| 536 if (res != VPX_CODEC_OK) return res; | 417 if (res != VPX_CODEC_OK) return res; |
| 537 | 418 |
| 538 // Parse aggregate command line options. Options must start with | 419 // Parse aggregate command line options. Options must start with |
| 539 // "layers=xx" then followed by other options | 420 // "layers=xx" then followed by other options |
| 540 res = parse_options(svc_ctx, si->options); | 421 res = parse_options(svc_ctx, si->options); |
| 541 if (res != VPX_CODEC_OK) return res; | 422 if (res != VPX_CODEC_OK) return res; |
| 542 | 423 |
| 543 si->layers = svc_ctx->spatial_layers; | 424 si->layers = svc_ctx->spatial_layers; |
| 544 | 425 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 567 if (total > 0) { | 448 if (total > 0) { |
| 568 enc_cfg->ss_target_bitrate[i] = (unsigned int) | 449 enc_cfg->ss_target_bitrate[i] = (unsigned int) |
| 569 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); | 450 (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); |
| 570 } | 451 } |
| 571 } | 452 } |
| 572 } | 453 } |
| 573 | 454 |
| 574 // modify encoder configuration | 455 // modify encoder configuration |
| 575 enc_cfg->ss_number_layers = si->layers; | 456 enc_cfg->ss_number_layers = si->layers; |
| 576 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. | 457 enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. |
| 577 // Lag in frames not currently supported | |
| 578 enc_cfg->g_lag_in_frames = 0; | |
| 579 | 458 |
| 580 // TODO(ivanmaltz): determine if these values need to be set explicitly for | 459 // TODO(ivanmaltz): determine if these values need to be set explicitly for |
| 581 // svc, or if the normal default/override mechanism can be used | 460 // svc, or if the normal default/override mechanism can be used |
| 582 enc_cfg->rc_dropframe_thresh = 0; | 461 enc_cfg->rc_dropframe_thresh = 0; |
| 583 enc_cfg->rc_resize_allowed = 0; | 462 enc_cfg->rc_resize_allowed = 0; |
| 584 | 463 |
| 585 if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { | 464 if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { |
| 586 enc_cfg->rc_min_quantizer = 33; | 465 enc_cfg->rc_min_quantizer = 33; |
| 587 enc_cfg->rc_max_quantizer = 33; | 466 enc_cfg->rc_max_quantizer = 33; |
| 588 } | 467 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 601 return res; | 480 return res; |
| 602 } | 481 } |
| 603 | 482 |
| 604 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); | 483 vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); |
| 605 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); | 484 vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); |
| 606 vpx_codec_control(codec_ctx, VP8E_SET_ENABLEAUTOALTREF, 0); | 485 vpx_codec_control(codec_ctx, VP8E_SET_ENABLEAUTOALTREF, 0); |
| 607 | 486 |
| 608 return VPX_CODEC_OK; | 487 return VPX_CODEC_OK; |
| 609 } | 488 } |
| 610 | 489 |
| 490 static void accumulate_frame_size_for_each_layer(SvcInternal *const si, |
| 491 const uint8_t *const buf, |
| 492 const size_t size) { |
| 493 uint8_t marker = buf[size - 1]; |
| 494 if ((marker & 0xe0) == 0xc0) { |
| 495 const uint32_t frames = (marker & 0x7) + 1; |
| 496 const uint32_t mag = ((marker >> 3) & 0x3) + 1; |
| 497 const size_t index_sz = 2 + mag * frames; |
| 498 |
| 499 uint8_t marker2 = buf[size - index_sz]; |
| 500 |
| 501 if (size >= index_sz && marker2 == marker) { |
| 502 // found a valid superframe index |
| 503 uint32_t i, j; |
| 504 const uint8_t *x = &buf[size - index_sz + 1]; |
| 505 |
| 506 // frames has a maximum of 8 and mag has a maximum of 4. |
| 507 for (i = 0; i < frames; i++) { |
| 508 uint32_t this_sz = 0; |
| 509 |
| 510 for (j = 0; j < mag; j++) |
| 511 this_sz |= (*x++) << (j * 8); |
| 512 si->bytes_sum[i] += this_sz; |
| 513 } |
| 514 } |
| 515 } |
| 516 } |
| 517 |
| 611 // SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h | 518 // SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h |
| 612 | 519 |
| 613 // encoder should reference the last frame | 520 // encoder should reference the last frame |
| 614 #define USE_LAST (1 << 0) | 521 #define USE_LAST (1 << 0) |
| 615 | 522 |
| 616 // encoder should reference the alt ref frame | 523 // encoder should reference the alt ref frame |
| 617 #define USE_ARF (1 << 1) | 524 #define USE_ARF (1 << 1) |
| 618 | 525 |
| 619 // encoder should reference the golden frame | 526 // encoder should reference the golden frame |
| 620 #define USE_GF (1 << 2) | 527 #define USE_GF (1 << 2) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF; | 564 vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF; |
| 658 SvcInternal *const si = get_svc_internal(svc_ctx); | 565 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 659 const int is_keyframe = (si->frame_within_gop == 0); | 566 const int is_keyframe = (si->frame_within_gop == 0); |
| 660 | 567 |
| 661 // keyframe layer zero is identical for all modes | 568 // keyframe layer zero is identical for all modes |
| 662 if (is_keyframe && si->layer == 0) { | 569 if (is_keyframe && si->layer == 0) { |
| 663 si->enc_frame_flags = VPX_EFLAG_FORCE_KF; | 570 si->enc_frame_flags = VPX_EFLAG_FORCE_KF; |
| 664 return; | 571 return; |
| 665 } | 572 } |
| 666 | 573 |
| 667 switch (svc_ctx->encoding_mode) { | 574 if (si->layer == 0) { |
| 668 case ALT_INTER_LAYER_PREDICTION_IP: | 575 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); |
| 669 if (si->layer == 0) { | 576 } else if (is_keyframe) { |
| 670 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | 577 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); |
| 671 } else if (is_keyframe) { | 578 } else { |
| 672 if (si->layer == si->layers - 1) { | 579 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); |
| 673 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); | |
| 674 } else { | |
| 675 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); | |
| 676 } | |
| 677 } else { | |
| 678 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); | |
| 679 } | |
| 680 break; | |
| 681 case INTER_LAYER_PREDICTION_I: | |
| 682 if (si->layer == 0) { | |
| 683 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | |
| 684 } else if (is_keyframe) { | |
| 685 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); | |
| 686 } else { | |
| 687 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | |
| 688 } | |
| 689 break; | |
| 690 case INTER_LAYER_PREDICTION_IP: | |
| 691 if (si->layer == 0) { | |
| 692 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | |
| 693 } else if (is_keyframe) { | |
| 694 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); | |
| 695 } else { | |
| 696 flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); | |
| 697 } | |
| 698 break; | |
| 699 case USE_GOLDEN_FRAME: | |
| 700 if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) { | |
| 701 if (si->layer == 0) { | |
| 702 flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST); | |
| 703 } else if (is_keyframe) { | |
| 704 flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); | |
| 705 } else { | |
| 706 flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST); | |
| 707 } | |
| 708 } else { | |
| 709 if (si->layer == 0) { | |
| 710 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | |
| 711 } else if (is_keyframe) { | |
| 712 flags = map_vp8_flags(USE_ARF | UPDATE_LAST); | |
| 713 } else { | |
| 714 flags = map_vp8_flags(USE_LAST | UPDATE_LAST); | |
| 715 } | |
| 716 } | |
| 717 break; | |
| 718 default: | |
| 719 svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n", | |
| 720 svc_ctx->encoding_mode); | |
| 721 break; | |
| 722 } | 580 } |
| 581 |
| 723 si->enc_frame_flags = flags; | 582 si->enc_frame_flags = flags; |
| 724 } | 583 } |
| 725 | 584 |
| 726 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx, | 585 vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx, |
| 727 int layer, | 586 int layer, |
| 728 unsigned int *width, | 587 unsigned int *width, |
| 729 unsigned int *height) { | 588 unsigned int *height) { |
| 730 int w, h, index, num, den; | 589 int w, h, index, num, den; |
| 731 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 590 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 732 | 591 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 758 int layer, layer_index; | 617 int layer, layer_index; |
| 759 vpx_svc_parameters_t svc_params; | 618 vpx_svc_parameters_t svc_params; |
| 760 SvcInternal *const si = get_svc_internal(svc_ctx); | 619 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 761 | 620 |
| 762 memset(&svc_params, 0, sizeof(svc_params)); | 621 memset(&svc_params, 0, sizeof(svc_params)); |
| 763 svc_params.temporal_layer = 0; | 622 svc_params.temporal_layer = 0; |
| 764 svc_params.spatial_layer = si->layer; | 623 svc_params.spatial_layer = si->layer; |
| 765 svc_params.flags = si->enc_frame_flags; | 624 svc_params.flags = si->enc_frame_flags; |
| 766 | 625 |
| 767 layer = si->layer; | 626 layer = si->layer; |
| 768 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | |
| 769 si->frame_within_gop == 0) { | |
| 770 // layers 1 & 3 don't exist in this mode, use the higher one | |
| 771 if (layer == 0 || layer == 2) { | |
| 772 layer += 1; | |
| 773 } | |
| 774 } | |
| 775 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, | 627 if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, |
| 776 &svc_params.width, | 628 &svc_params.width, |
| 777 &svc_params.height)) { | 629 &svc_params.height)) { |
| 778 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); | 630 svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); |
| 779 } | 631 } |
| 780 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; | 632 layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; |
| 781 | 633 |
| 782 if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) { | 634 if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) { |
| 783 if (vpx_svc_is_keyframe(svc_ctx)) { | 635 svc_params.min_quantizer = si->quantizer[layer_index]; |
| 784 svc_params.min_quantizer = si->quantizer_keyframe[layer_index]; | 636 svc_params.max_quantizer = si->quantizer[layer_index]; |
| 785 svc_params.max_quantizer = si->quantizer_keyframe[layer_index]; | |
| 786 } else { | |
| 787 svc_params.min_quantizer = si->quantizer[layer_index]; | |
| 788 svc_params.max_quantizer = si->quantizer[layer_index]; | |
| 789 } | |
| 790 } else { | 637 } else { |
| 791 svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer; | 638 svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer; |
| 792 svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer; | 639 svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer; |
| 793 } | 640 } |
| 794 | 641 |
| 795 svc_params.distance_from_i_frame = si->frame_within_gop; | 642 svc_params.distance_from_i_frame = si->frame_within_gop; |
| 796 | 643 |
| 797 // Use buffer i for layer i LST | 644 // Use buffer i for layer i LST |
| 798 svc_params.lst_fb_idx = si->layer; | 645 svc_params.lst_fb_idx = si->layer; |
| 799 | 646 |
| 800 // Use buffer i-1 for layer i Alt (Inter-layer prediction) | 647 // Use buffer i-1 for layer i Alt (Inter-layer prediction) |
| 801 if (si->layer != 0) { | 648 svc_params.alt_fb_idx = (si->layer > 0) ? si->layer - 1 : 0; |
| 802 const int use_higher_layer = | 649 svc_params.gld_fb_idx = svc_params.lst_fb_idx; |
| 803 svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | |
| 804 si->frame_within_gop == 0; | |
| 805 svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1; | |
| 806 } | |
| 807 | |
| 808 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) { | |
| 809 svc_params.gld_fb_idx = si->layer + 1; | |
| 810 } else { | |
| 811 if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES) | |
| 812 svc_params.gld_fb_idx = svc_params.lst_fb_idx; | |
| 813 else | |
| 814 svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer; | |
| 815 } | |
| 816 | 650 |
| 817 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n", | 651 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n", |
| 818 si->encode_frame_count, si->layer, svc_params.width, | 652 si->encode_frame_count, si->layer, svc_params.width, |
| 819 svc_params.height, svc_params.min_quantizer); | 653 svc_params.height, svc_params.min_quantizer); |
| 820 | 654 |
| 821 if (svc_params.flags == VPX_EFLAG_FORCE_KF) { | 655 if (svc_params.flags == VPX_EFLAG_FORCE_KF) { |
| 822 svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n"); | 656 svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n"); |
| 823 } else { | 657 } else { |
| 824 svc_log( | 658 svc_log( |
| 825 svc_ctx, SVC_LOG_DEBUG, "Using: LST/GLD/ALT [%2d|%2d|%2d]\n", | 659 svc_ctx, SVC_LOG_DEBUG, "Using: LST/GLD/ALT [%2d|%2d|%2d]\n", |
| (...skipping 13 matching lines...) Expand all Loading... |
| 839 /** | 673 /** |
| 840 * Encode a frame into multiple layers | 674 * Encode a frame into multiple layers |
| 841 * Create a superframe containing the individual layers | 675 * Create a superframe containing the individual layers |
| 842 */ | 676 */ |
| 843 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, | 677 vpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, |
| 844 struct vpx_image *rawimg, vpx_codec_pts_t pts, | 678 struct vpx_image *rawimg, vpx_codec_pts_t pts, |
| 845 int64_t duration, int deadline) { | 679 int64_t duration, int deadline) { |
| 846 vpx_codec_err_t res; | 680 vpx_codec_err_t res; |
| 847 vpx_codec_iter_t iter; | 681 vpx_codec_iter_t iter; |
| 848 const vpx_codec_cx_pkt_t *cx_pkt; | 682 const vpx_codec_cx_pkt_t *cx_pkt; |
| 849 struct LayerData *cx_layer_list = NULL; | 683 int layer_for_psnr = 0; |
| 850 struct LayerData *layer_data; | |
| 851 struct Superframe superframe; | |
| 852 SvcInternal *const si = get_svc_internal(svc_ctx); | 684 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 853 if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { | 685 if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { |
| 854 return VPX_CODEC_INVALID_PARAM; | 686 return VPX_CODEC_INVALID_PARAM; |
| 855 } | 687 } |
| 856 | 688 |
| 857 memset(&superframe, 0, sizeof(superframe)); | |
| 858 svc_log_reset(svc_ctx); | 689 svc_log_reset(svc_ctx); |
| 859 si->rc_stats_buf_used = 0; | 690 si->rc_stats_buf_used = 0; |
| 860 | 691 |
| 861 si->layers = svc_ctx->spatial_layers; | 692 si->layers = svc_ctx->spatial_layers; |
| 862 if (si->encode_frame_count == 0) { | 693 if (si->encode_frame_count == 0) { |
| 863 si->frame_within_gop = 0; | 694 si->frame_within_gop = 0; |
| 864 } | 695 } |
| 865 si->is_keyframe = (si->frame_within_gop == 0); | 696 si->is_keyframe = (si->frame_within_gop == 0); |
| 866 si->frame_size = 0; | |
| 867 | 697 |
| 868 if (rawimg != NULL) { | 698 if (rawimg != NULL) { |
| 869 svc_log(svc_ctx, SVC_LOG_DEBUG, | 699 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 870 "vpx_svc_encode layers: %d, frame_count: %d, " | 700 "vpx_svc_encode layers: %d, frame_count: %d, " |
| 871 "frame_within_gop: %d\n", si->layers, si->encode_frame_count, | 701 "frame_within_gop: %d\n", si->layers, si->encode_frame_count, |
| 872 si->frame_within_gop); | 702 si->frame_within_gop); |
| 873 } | 703 } |
| 874 | 704 |
| 875 // encode each layer | 705 if (rawimg != NULL) { |
| 876 for (si->layer = 0; si->layer < si->layers; ++si->layer) { | 706 // encode each layer |
| 877 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | 707 for (si->layer = 0; si->layer < si->layers; ++si->layer) { |
| 878 si->is_keyframe && (si->layer == 1 || si->layer == 3)) { | |
| 879 svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer); | |
| 880 continue; | |
| 881 } | |
| 882 | |
| 883 if (rawimg != NULL) { | |
| 884 calculate_enc_frame_flags(svc_ctx); | 708 calculate_enc_frame_flags(svc_ctx); |
| 885 set_svc_parameters(svc_ctx, codec_ctx); | 709 set_svc_parameters(svc_ctx, codec_ctx); |
| 886 } | 710 } |
| 711 } |
| 887 | 712 |
| 888 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, | 713 res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, |
| 889 si->enc_frame_flags, deadline); | 714 deadline); |
| 890 if (res != VPX_CODEC_OK) { | 715 if (res != VPX_CODEC_OK) { |
| 891 return res; | 716 return res; |
| 892 } | 717 } |
| 893 // save compressed data | 718 // save compressed data |
| 894 iter = NULL; | 719 iter = NULL; |
| 895 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { | 720 while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { |
| 896 switch (cx_pkt->kind) { | 721 switch (cx_pkt->kind) { |
| 897 case VPX_CODEC_CX_FRAME_PKT: { | 722 case VPX_CODEC_CX_FRAME_PKT: { |
| 898 const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz); | 723 fd_list_add(&si->frame_list, fd_create(cx_pkt->data.frame.buf, |
| 899 si->bytes_sum[si->layer] += frame_pkt_size; | 724 cx_pkt->data.frame.sz, |
| 900 svc_log(svc_ctx, SVC_LOG_DEBUG, | 725 cx_pkt->data.frame.flags)); |
| 901 "SVC frame: %d, layer: %d, size: %u\n", | 726 accumulate_frame_size_for_each_layer(si, cx_pkt->data.frame.buf, |
| 902 si->encode_frame_count, si->layer, frame_pkt_size); | 727 cx_pkt->data.frame.sz); |
| 903 layer_data = | 728 |
| 904 ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size); | 729 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, " |
| 905 if (layer_data == NULL) { | 730 "pts: %d\n", si->frame_received, |
| 906 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n"); | 731 (cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY) ? 1 : 0, |
| 907 return VPX_CODEC_OK; | 732 (int)cx_pkt->data.frame.sz, (int)cx_pkt->data.frame.pts); |
| 733 |
| 734 ++si->frame_received; |
| 735 layer_for_psnr = 0; |
| 736 break; |
| 737 } |
| 738 case VPX_CODEC_PSNR_PKT: { |
| 739 int i; |
| 740 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 741 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " |
| 742 "%2.3f %2.3f %2.3f %2.3f \n", |
| 743 si->frame_received, layer_for_psnr, |
| 744 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], |
| 745 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); |
| 746 svc_log(svc_ctx, SVC_LOG_DEBUG, |
| 747 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " |
| 748 "%2.3f %2.3f %2.3f %2.3f \n", |
| 749 si->frame_received, layer_for_psnr, |
| 750 cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1], |
| 751 cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]); |
| 752 for (i = 0; i < COMPONENTS; i++) { |
| 753 si->psnr_sum[layer_for_psnr][i] += cx_pkt->data.psnr.psnr[i]; |
| 754 si->sse_sum[layer_for_psnr][i] += cx_pkt->data.psnr.sse[i]; |
| 755 } |
| 756 ++layer_for_psnr; |
| 757 break; |
| 758 } |
| 759 case VPX_CODEC_STATS_PKT: { |
| 760 size_t new_size = si->rc_stats_buf_used + |
| 761 cx_pkt->data.twopass_stats.sz; |
| 762 |
| 763 if (new_size > si->rc_stats_buf_size) { |
| 764 char *p = (char*)realloc(si->rc_stats_buf, new_size); |
| 765 if (p == NULL) { |
| 766 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n"); |
| 767 return VPX_CODEC_MEM_ERROR; |
| 908 } | 768 } |
| 909 ld_list_add(&cx_layer_list, layer_data); | 769 si->rc_stats_buf = p; |
| 770 si->rc_stats_buf_size = new_size; |
| 771 } |
| 910 | 772 |
| 911 // save layer size in superframe index | 773 memcpy(si->rc_stats_buf + si->rc_stats_buf_used, |
| 912 superframe.sizes[superframe.count++] = frame_pkt_size; | 774 cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); |
| 913 superframe.magnitude |= frame_pkt_size; | 775 si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz; |
| 914 break; | 776 break; |
| 915 } | 777 } |
| 916 case VPX_CODEC_PSNR_PKT: { | 778 default: { |
| 917 int i; | 779 break; |
| 918 svc_log(svc_ctx, SVC_LOG_DEBUG, | |
| 919 "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " | |
| 920 "%2.3f %2.3f %2.3f %2.3f \n", | |
| 921 si->encode_frame_count, si->layer, | |
| 922 cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], | |
| 923 cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); | |
| 924 svc_log(svc_ctx, SVC_LOG_DEBUG, | |
| 925 "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " | |
| 926 "%2.3f %2.3f %2.3f %2.3f \n", | |
| 927 si->encode_frame_count, si->layer, | |
| 928 cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1], | |
| 929 cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]); | |
| 930 for (i = 0; i < COMPONENTS; i++) { | |
| 931 si->psnr_sum[si->layer][i] += cx_pkt->data.psnr.psnr[i]; | |
| 932 si->sse_sum[si->layer][i] += cx_pkt->data.psnr.sse[i]; | |
| 933 } | |
| 934 break; | |
| 935 } | |
| 936 case VPX_CODEC_STATS_PKT: { | |
| 937 size_t new_size = si->rc_stats_buf_used + | |
| 938 cx_pkt->data.twopass_stats.sz; | |
| 939 | |
| 940 if (new_size > si->rc_stats_buf_size) { | |
| 941 char *p = (char*)realloc(si->rc_stats_buf, new_size); | |
| 942 if (p == NULL) { | |
| 943 svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n"); | |
| 944 break; | |
| 945 } | |
| 946 si->rc_stats_buf = p; | |
| 947 si->rc_stats_buf_size = new_size; | |
| 948 } | |
| 949 | |
| 950 memcpy(si->rc_stats_buf + si->rc_stats_buf_used, | |
| 951 cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); | |
| 952 si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz; | |
| 953 break; | |
| 954 } | |
| 955 default: { | |
| 956 break; | |
| 957 } | |
| 958 } | 780 } |
| 959 } | 781 } |
| 960 if (rawimg == NULL) { | |
| 961 break; | |
| 962 } | |
| 963 } | 782 } |
| 964 if (codec_ctx->config.enc->g_pass != VPX_RC_FIRST_PASS) { | |
| 965 // add superframe index to layer data list | |
| 966 sf_create_index(&superframe); | |
| 967 layer_data = ld_create(superframe.buffer, superframe.index_size); | |
| 968 ld_list_add(&cx_layer_list, layer_data); | |
| 969 | 783 |
| 970 // get accumulated size of layer data | |
| 971 si->frame_size = ld_list_get_buffer_size(cx_layer_list); | |
| 972 if (si->frame_size > 0) { | |
| 973 // all layers encoded, create single buffer with concatenated layers | |
| 974 if (si->frame_size > si->buffer_size) { | |
| 975 free(si->buffer); | |
| 976 si->buffer = malloc(si->frame_size); | |
| 977 if (si->buffer == NULL) { | |
| 978 ld_list_free(cx_layer_list); | |
| 979 return VPX_CODEC_MEM_ERROR; | |
| 980 } | |
| 981 si->buffer_size = si->frame_size; | |
| 982 } | |
| 983 // copy layer data into packet | |
| 984 ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)si->buffer); | |
| 985 | |
| 986 ld_list_free(cx_layer_list); | |
| 987 | |
| 988 svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, " | |
| 989 "pts: %d\n", si->encode_frame_count, si->is_keyframe, | |
| 990 (int)si->frame_size, (int)pts); | |
| 991 } | |
| 992 } | |
| 993 if (rawimg != NULL) { | 784 if (rawimg != NULL) { |
| 994 ++si->frame_within_gop; | 785 ++si->frame_within_gop; |
| 995 ++si->encode_frame_count; | 786 ++si->encode_frame_count; |
| 996 } | 787 } |
| 997 | 788 |
| 998 return VPX_CODEC_OK; | 789 return VPX_CODEC_OK; |
| 999 } | 790 } |
| 1000 | 791 |
| 1001 const char *vpx_svc_get_message(const SvcContext *svc_ctx) { | 792 const char *vpx_svc_get_message(const SvcContext *svc_ctx) { |
| 1002 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 793 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1003 if (svc_ctx == NULL || si == NULL) return NULL; | 794 if (svc_ctx == NULL || si == NULL) return NULL; |
| 1004 return si->message_buffer; | 795 return si->message_buffer; |
| 1005 } | 796 } |
| 1006 | 797 |
| 1007 void *vpx_svc_get_buffer(const SvcContext *svc_ctx) { | 798 // We will maintain a list of output frame buffers since with lag_in_frame |
| 1008 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 799 // we need to output all frame buffers at the end. vpx_svc_get_buffer() will |
| 1009 if (svc_ctx == NULL || si == NULL) return NULL; | 800 // remove a frame buffer from the list the put it to a temporal pointer, which |
| 1010 return si->buffer; | 801 // will be removed at the next vpx_svc_get_buffer() or when closing encoder. |
| 802 void *vpx_svc_get_buffer(SvcContext *svc_ctx) { |
| 803 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 804 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return NULL; |
| 805 |
| 806 if (si->frame_temp) |
| 807 fd_free(si->frame_temp); |
| 808 |
| 809 si->frame_temp = si->frame_list; |
| 810 si->frame_list = si->frame_list->next; |
| 811 |
| 812 return si->frame_temp->buf; |
| 1011 } | 813 } |
| 1012 | 814 |
| 1013 size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) { | 815 size_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) { |
| 1014 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 816 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1015 if (svc_ctx == NULL || si == NULL) return 0; | 817 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0; |
| 1016 return si->frame_size; | 818 return si->frame_list->size; |
| 1017 } | 819 } |
| 1018 | 820 |
| 1019 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) { | 821 int vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) { |
| 1020 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 822 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1021 if (svc_ctx == NULL || si == NULL) return 0; | 823 if (svc_ctx == NULL || si == NULL) return 0; |
| 1022 return si->encode_frame_count; | 824 return si->encode_frame_count; |
| 1023 } | 825 } |
| 1024 | 826 |
| 1025 int vpx_svc_is_keyframe(const SvcContext *svc_ctx) { | 827 int vpx_svc_is_keyframe(const SvcContext *svc_ctx) { |
| 1026 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 828 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1027 if (svc_ctx == NULL || si == NULL) return 0; | 829 if (svc_ctx == NULL || si == NULL || si->frame_list == NULL) return 0; |
| 1028 return si->is_keyframe; | 830 return (si->frame_list->flags & VPX_FRAME_IS_KEY) != 0; |
| 1029 } | 831 } |
| 1030 | 832 |
| 1031 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { | 833 void vpx_svc_set_keyframe(SvcContext *svc_ctx) { |
| 1032 SvcInternal *const si = get_svc_internal(svc_ctx); | 834 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 1033 if (svc_ctx == NULL || si == NULL) return; | 835 if (svc_ctx == NULL || si == NULL) return; |
| 1034 si->frame_within_gop = 0; | 836 si->frame_within_gop = 0; |
| 1035 } | 837 } |
| 1036 | 838 |
| 1037 static double calc_psnr(double d) { | 839 static double calc_psnr(double d) { |
| 1038 if (d == 0) return 100; | 840 if (d == 0) return 100; |
| 1039 return -10.0 * log(d) / log(10.0); | 841 return -10.0 * log(d) / log(10.0); |
| 1040 } | 842 } |
| 1041 | 843 |
| 1042 // dump accumulated statistics and reset accumulated values | 844 // dump accumulated statistics and reset accumulated values |
| 1043 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { | 845 const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { |
| 1044 int number_of_frames, number_of_keyframes, encode_frame_count; | 846 int number_of_frames, encode_frame_count; |
| 1045 int i, j; | 847 int i, j; |
| 1046 uint32_t bytes_total = 0; | 848 uint32_t bytes_total = 0; |
| 1047 double scale[COMPONENTS]; | 849 double scale[COMPONENTS]; |
| 1048 double psnr[COMPONENTS]; | 850 double psnr[COMPONENTS]; |
| 1049 double mse[COMPONENTS]; | 851 double mse[COMPONENTS]; |
| 1050 double y_scale; | 852 double y_scale; |
| 1051 | 853 |
| 1052 SvcInternal *const si = get_svc_internal(svc_ctx); | 854 SvcInternal *const si = get_svc_internal(svc_ctx); |
| 1053 if (svc_ctx == NULL || si == NULL) return NULL; | 855 if (svc_ctx == NULL || si == NULL) return NULL; |
| 1054 | 856 |
| 1055 svc_log_reset(svc_ctx); | 857 svc_log_reset(svc_ctx); |
| 1056 | 858 |
| 1057 encode_frame_count = si->encode_frame_count; | 859 encode_frame_count = si->encode_frame_count; |
| 1058 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); | 860 if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); |
| 1059 | 861 |
| 1060 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); | 862 svc_log(svc_ctx, SVC_LOG_INFO, "\n"); |
| 1061 number_of_keyframes = encode_frame_count / si->kf_dist + 1; | |
| 1062 for (i = 0; i < si->layers; ++i) { | 863 for (i = 0; i < si->layers; ++i) { |
| 1063 number_of_frames = encode_frame_count; | 864 number_of_frames = encode_frame_count; |
| 1064 | 865 |
| 1065 if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && | |
| 1066 (i == 1 || i == 3)) { | |
| 1067 number_of_frames -= number_of_keyframes; | |
| 1068 } | |
| 1069 svc_log(svc_ctx, SVC_LOG_INFO, | 866 svc_log(svc_ctx, SVC_LOG_INFO, |
| 1070 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", | 867 "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", |
| 1071 i, (double)si->psnr_sum[i][0] / number_of_frames, | 868 i, (double)si->psnr_sum[i][0] / number_of_frames, |
| 1072 (double)si->psnr_sum[i][1] / number_of_frames, | 869 (double)si->psnr_sum[i][1] / number_of_frames, |
| 1073 (double)si->psnr_sum[i][2] / number_of_frames, | 870 (double)si->psnr_sum[i][2] / number_of_frames, |
| 1074 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); | 871 (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); |
| 1075 // the following psnr calculation is deduced from ffmpeg.c#print_report | 872 // the following psnr calculation is deduced from ffmpeg.c#print_report |
| 1076 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; | 873 y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; |
| 1077 scale[1] = y_scale; | 874 scale[1] = y_scale; |
| 1078 scale[2] = scale[3] = y_scale / 4; // U or V | 875 scale[2] = scale[3] = y_scale / 4; // U or V |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1105 return vpx_svc_get_message(svc_ctx); | 902 return vpx_svc_get_message(svc_ctx); |
| 1106 } | 903 } |
| 1107 | 904 |
| 1108 void vpx_svc_release(SvcContext *svc_ctx) { | 905 void vpx_svc_release(SvcContext *svc_ctx) { |
| 1109 SvcInternal *si; | 906 SvcInternal *si; |
| 1110 if (svc_ctx == NULL) return; | 907 if (svc_ctx == NULL) return; |
| 1111 // do not use get_svc_internal as it will unnecessarily allocate an | 908 // do not use get_svc_internal as it will unnecessarily allocate an |
| 1112 // SvcInternal if it was not already allocated | 909 // SvcInternal if it was not already allocated |
| 1113 si = (SvcInternal *)svc_ctx->internal; | 910 si = (SvcInternal *)svc_ctx->internal; |
| 1114 if (si != NULL) { | 911 if (si != NULL) { |
| 1115 free(si->buffer); | 912 fd_free(si->frame_temp); |
| 913 fd_free_list(si->frame_list); |
| 1116 if (si->rc_stats_buf) { | 914 if (si->rc_stats_buf) { |
| 1117 free(si->rc_stats_buf); | 915 free(si->rc_stats_buf); |
| 1118 } | 916 } |
| 1119 free(si); | 917 free(si); |
| 1120 svc_ctx->internal = NULL; | 918 svc_ctx->internal = NULL; |
| 1121 } | 919 } |
| 1122 } | 920 } |
| 1123 | 921 |
| 1124 size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) { | 922 size_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) { |
| 1125 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 923 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1126 if (svc_ctx == NULL || si == NULL) return 0; | 924 if (svc_ctx == NULL || si == NULL) return 0; |
| 1127 return si->rc_stats_buf_used; | 925 return si->rc_stats_buf_used; |
| 1128 } | 926 } |
| 1129 | 927 |
| 1130 char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { | 928 char *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { |
| 1131 const SvcInternal *const si = get_const_svc_internal(svc_ctx); | 929 const SvcInternal *const si = get_const_svc_internal(svc_ctx); |
| 1132 if (svc_ctx == NULL || si == NULL) return NULL; | 930 if (svc_ctx == NULL || si == NULL) return NULL; |
| 1133 return si->rc_stats_buf; | 931 return si->rc_stats_buf; |
| 1134 } | 932 } |
| 1135 | 933 |
| 1136 | 934 |
| OLD | NEW |