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