15ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/* 25ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Copyright (c) 2013 The WebM project authors. All Rights Reserved. 35ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * 45ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Use of this source code is governed by a BSD-style license 55ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * that can be found in the LICENSE file in the root of the source 65ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * tree. An additional intellectual property rights grant can be found 75ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * in the file PATENTS. All contributing project authors may 85ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * be found in the AUTHORS file in the root of the source tree. 95ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */ 105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/** 125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * @file 135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * VP9 SVC encoding support via libvpx 145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */ 155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 16a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian#include <assert.h> 17b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#include <math.h> 185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <stdarg.h> 195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <stdio.h> 205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <stdlib.h> 215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include <string.h> 225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define VPX_DISABLE_CTRL_TYPECHECKS 1 235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define VPX_CODEC_DISABLE_COMPAT 1 245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include "vpx/svc_context.h" 255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include "vpx/vp8cx.h" 265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#include "vpx/vpx_encoder.h" 275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 28b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#ifdef __MINGW32__ 295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define strtok_r strtok_s 30b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#ifndef MINGW_HAS_SECURE_API 315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h 325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context); 33b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#endif /* MINGW_HAS_SECURE_API */ 34b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#endif /* __MINGW32__ */ 355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#ifdef _MSC_VER 375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define strdup _strdup 385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define strtok_r strtok_s 395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#endif 405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define SVC_REFERENCE_FRAMES 8 425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define SUPERFRAME_SLOTS (8) 435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2) 445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define OPTION_BUFFER_SIZE 256 45b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian#define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v 465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic const char *DEFAULT_QUANTIZER_VALUES = "60,53,39,33,27"; 485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic const char *DEFAULT_SCALE_FACTORS = "4/16,5/16,7/16,11/16,16/16"; 495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangtypedef struct SvcInternal { 515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options 525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers 53b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian char quantizers_keyframe[OPTION_BUFFER_SIZE]; // set by 54b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // vpx_svc_set_quantizers 555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors 565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // values extracted from option, quantizers 585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int scaling_factor_num[VPX_SS_MAX_LAYERS]; 595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int scaling_factor_den[VPX_SS_MAX_LAYERS]; 60b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int quantizer_keyframe[VPX_SS_MAX_LAYERS]; 615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int quantizer[VPX_SS_MAX_LAYERS]; 625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // accumulated statistics 64b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian double psnr_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; // total/Y/U/V 65b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian uint64_t sse_sum[VPX_SS_MAX_LAYERS][COMPONENTS]; 66b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian uint32_t bytes_sum[VPX_SS_MAX_LAYERS]; 675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // codec encoding values 695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int width; // width of highest layer 705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int height; // height of highest layer 715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int kf_dist; // distance between keyframes 725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // state variables 745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int encode_frame_count; 755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int frame_within_gop; 765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_enc_frame_flags_t enc_frame_flags; 775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int layers; 785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int layer; 795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int is_keyframe; 805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size_t frame_size; 825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size_t buffer_size; 835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang void *buffer; 845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 85b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian char *rc_stats_buf; 86b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian size_t rc_stats_buf_size; 87b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian size_t rc_stats_buf_used; 88b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char message_buffer[2048]; 905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_ctx_t *codec_ctx; 915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} SvcInternal; 925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// Superframe is used to generate an index of individual frames (i.e., layers) 945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstruct Superframe { 955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int count; 965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint32_t sizes[SUPERFRAME_SLOTS]; 975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint32_t magnitude; 985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint8_t buffer[SUPERFRAME_BUFFER_SIZE]; 995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size_t index_size; 1005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang}; 1015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// One encoded frame layer 1035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstruct LayerData { 1045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang void *buf; // compressed data buffer 1055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size_t size; // length of compressed data 1065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *next; 1075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang}; 1085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// create LayerData from encoder output 1105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic struct LayerData *ld_create(void *buf, size_t size) { 111b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian struct LayerData *const layer_data = 112b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian (struct LayerData *)malloc(sizeof(*layer_data)); 1135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer_data == NULL) { 1145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return NULL; 1155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_data->buf = malloc(size); 1175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer_data->buf == NULL) { 1185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(layer_data); 1195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return NULL; 1205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang memcpy(layer_data->buf, buf, size); 1225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_data->size = size; 1235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return layer_data; 1245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// free LayerData 1275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void ld_free(struct LayerData *layer_data) { 1285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer_data) { 1295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer_data->buf) { 1305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(layer_data->buf); 1315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_data->buf = NULL; 1325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(layer_data); 1345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// add layer data to list 1385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void ld_list_add(struct LayerData **list, struct LayerData *layer_data) { 1395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData **p = list; 1405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang while (*p != NULL) p = &(*p)->next; 1425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *p = layer_data; 1435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_data->next = NULL; 1445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// get accumulated size of layer data 1475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic size_t ld_list_get_buffer_size(struct LayerData *list) { 1485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *p; 1495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size_t size = 0; 1505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (p = list; p != NULL; p = p->next) { 1525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang size += p->size; 1535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return size; 1555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// copy layer data to buffer 1585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void ld_list_copy_to_buffer(struct LayerData *list, uint8_t *buffer) { 1595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *p; 1605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (p = list; p != NULL; p = p->next) { 1625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang buffer[0] = 1; 1635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang memcpy(buffer, p->buf, p->size); 1645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang buffer += p->size; 1655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// free layer data list 1695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void ld_list_free(struct LayerData *list) { 1705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *p = list; 1715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang while (p) { 1735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang list = list->next; 1745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ld_free(p); 1755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang p = list; 1765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void sf_create_index(struct Superframe *sf) { 1805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint8_t marker = 0xc0; 1815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int i; 1825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint32_t mag, mask; 1835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint8_t *bufp; 1845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (sf->count == 0 || sf->count >= 8) return; 1865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Add the number of frames to the marker byte 1885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang marker |= sf->count - 1; 1895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Choose the magnitude 1915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (mag = 0, mask = 0xff; mag < 4; ++mag) { 1925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (sf->magnitude < mask) break; 1935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang mask <<= 8; 1945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang mask |= 0xff; 1955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang marker |= mag << 3; 1975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Write the index 1995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang sf->index_size = 2 + (mag + 1) * sf->count; 2005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang bufp = sf->buffer; 2015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *bufp++ = marker; 2035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (i = 0; i < sf->count; ++i) { 2045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int this_sz = sf->sizes[i]; 2055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint32_t j; 2065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (j = 0; j <= mag; ++j) { 2085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *bufp++ = this_sz & 0xff; 2095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang this_sz >>= 8; 2105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *bufp++ = marker; 2135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic SvcInternal *get_svc_internal(SvcContext *svc_ctx) { 2165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL) return NULL; 2175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->internal == NULL) { 218b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian SvcInternal *const si = (SvcInternal *)malloc(sizeof(*si)); 2195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si != NULL) { 2205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang memset(si, 0, sizeof(*si)); 2215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->internal = si; 2235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 224b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return (SvcInternal *)svc_ctx->internal; 2255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic const SvcInternal *get_const_svc_internal(const SvcContext *svc_ctx) { 2285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL) return NULL; 229b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return (const SvcInternal *)svc_ctx->internal; 2305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void svc_log_reset(SvcContext *svc_ctx) { 2335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = (SvcInternal *)svc_ctx->internal; 2345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->message_buffer[0] = '\0'; 2355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic int svc_log(SvcContext *svc_ctx, int level, const char *fmt, ...) { 2385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char buf[512]; 2395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int retval = 0; 2405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang va_list ap; 2415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 2425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (level > svc_ctx->log_level) { 2445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return retval; 2455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang va_start(ap, fmt); 2485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang retval = vsnprintf(buf, sizeof(buf), fmt, ap); 2495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang va_end(ap); 2505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->log_print) { 2525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang printf("%s", buf); 2535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 2545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang strncat(si->message_buffer, buf, 2555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang sizeof(si->message_buffer) - strlen(si->message_buffer) - 1); 2565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (level == SVC_LOG_ERROR) { 2595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->codec_ctx->err_detail = si->message_buffer; 2605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return retval; 2625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic vpx_codec_err_t set_option_encoding_mode(SvcContext *svc_ctx, 2655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const char *value_str) { 2665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (strcmp(value_str, "i") == 0) { 2675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_I; 2685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp(value_str, "alt-ip") == 0) { 2695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode = ALT_INTER_LAYER_PREDICTION_IP; 2705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp(value_str, "ip") == 0) { 2715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode = INTER_LAYER_PREDICTION_IP; 2725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp(value_str, "gf") == 0) { 2735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode = USE_GOLDEN_FRAME; 2745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 2755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "invalid encoding mode: %s", value_str); 2765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 2775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 2785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 2795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 2805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic vpx_codec_err_t parse_quantizer_values(SvcContext *svc_ctx, 282b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const char *quantizer_values, 283b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const int is_keyframe) { 2845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *input_string; 2855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *token; 2865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const char *delim = ","; 2875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *save_ptr; 2885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int found = 0; 2895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int i, q; 290b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian vpx_codec_err_t res = VPX_CODEC_OK; 2915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 2925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 2935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (quantizer_values == NULL || strlen(quantizer_values) == 0) { 294b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (is_keyframe) { 295b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // If there non settings for key frame, we will apply settings from 296b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // non key frame. So just simply return here. 297b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return VPX_CODEC_INVALID_PARAM; 298b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 2995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang input_string = strdup(DEFAULT_QUANTIZER_VALUES); 3005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 3015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang input_string = strdup(quantizer_values); 3025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 3045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang token = strtok_r(input_string, delim, &save_ptr); 3055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (i = 0; i < svc_ctx->spatial_layers; ++i) { 3065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (token != NULL) { 3075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang q = atoi(token); 3085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (q <= 0 || q > 100) { 3095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, 3105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang "svc-quantizer-values: invalid value %s\n", token); 3115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 3135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang token = strtok_r(NULL, delim, &save_ptr); 3155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang found = i + 1; 3165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 3175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang q = 0; 3185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 319b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (is_keyframe) { 320b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->quantizer_keyframe[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] 321b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian = q; 322b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } else { 323b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->quantizer[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = q; 324b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 3255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { 3275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, 3285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang "svc: quantizers: %d values required, but only %d specified\n", 3295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers, found); 3305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(input_string); 3335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return res; 3345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 3355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 3365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void log_invalid_scale_factor(SvcContext *svc_ctx, const char *value) { 3375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "svc scale-factors: invalid value %s\n", 3385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang value); 3395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 3405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 3415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic vpx_codec_err_t parse_scale_factors(SvcContext *svc_ctx, 3425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const char *scale_factors) { 3435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *input_string; 3445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *token; 3455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const char *delim = ","; 3465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *save_ptr; 3475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int found = 0; 3485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int i; 3495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int64_t num, den; 350b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian vpx_codec_err_t res = VPX_CODEC_OK; 3515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 3525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 3535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (scale_factors == NULL || strlen(scale_factors) == 0) { 3545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang input_string = strdup(DEFAULT_SCALE_FACTORS); 3555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 3565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang input_string = strdup(scale_factors); 3575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang token = strtok_r(input_string, delim, &save_ptr); 3595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (i = 0; i < svc_ctx->spatial_layers; ++i) { 3605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang num = den = 0; 3615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (token != NULL) { 3625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang num = strtol(token, &token, 10); 3635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (num <= 0) { 3645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang log_invalid_scale_factor(svc_ctx, token); 3655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 3675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (*token++ != '/') { 3695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang log_invalid_scale_factor(svc_ctx, token); 3705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 3725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang den = strtol(token, &token, 10); 3745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (den <= 0) { 3755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang log_invalid_scale_factor(svc_ctx, token); 3765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 3785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang token = strtok_r(NULL, delim, &save_ptr); 3805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang found = i + 1; 3815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->scaling_factor_num[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = 3835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang (int)num; 3845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->scaling_factor_den[i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers] = 3855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang (int)den; 3865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res == VPX_CODEC_OK && found != svc_ctx->spatial_layers) { 3885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, 3895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang "svc: scale-factors: %d values required, but only %d specified\n", 3905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers, found); 3915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 3925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 3935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(input_string); 3945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return res; 3955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 3965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 3975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/** 3985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Parse SVC encoding options 3995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Format: encoding-mode=<svc_mode>,layers=<layer_count> 4005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * scale-factors=<n1>/<d1>,<n2>/<d2>,... 4015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * quantizers=<q1>,<q2>,... 4025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * svc_mode = [i|ip|alt_ip|gf] 4035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */ 4045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic vpx_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) { 4055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *input_string; 4065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *option_name; 4075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *option_value; 4085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang char *input_ptr; 409b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int is_keyframe_qaunt_set = 0; 410b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian vpx_codec_err_t res = VPX_CODEC_OK; 4115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (options == NULL) return VPX_CODEC_OK; 4135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang input_string = strdup(options); 4145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // parse option name 4165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang option_name = strtok_r(input_string, "=", &input_ptr); 4175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang while (option_name != NULL) { 4185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // parse option value 4195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang option_value = strtok_r(NULL, " ", &input_ptr); 4205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (option_value == NULL) { 4215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n", 4225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang option_name); 4235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 4245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 4255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 4265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (strcmp("encoding-mode", option_name) == 0) { 4275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = set_option_encoding_mode(svc_ctx, option_value); 4285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) break; 4295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp("layers", option_name) == 0) { 4305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers = atoi(option_value); 4315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp("scale-factors", option_name) == 0) { 4325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = parse_scale_factors(svc_ctx, option_value); 4335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) break; 4345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (strcmp("quantizers", option_name) == 0) { 435b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian res = parse_quantizer_values(svc_ctx, option_value, 0); 436b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (res != VPX_CODEC_OK) break; 437b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (!is_keyframe_qaunt_set) { 438b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian SvcInternal *const si = get_svc_internal(svc_ctx); 439b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian memcpy(get_svc_internal(svc_ctx)->quantizer_keyframe, si->quantizer, 440b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian sizeof(si->quantizer)); 441b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 442b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } else if (strcmp("quantizers-keyframe", option_name) == 0) { 443b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian res = parse_quantizer_values(svc_ctx, option_value, 1); 4445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) break; 445b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian is_keyframe_qaunt_set = 1; 4465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 4475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name); 4485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = VPX_CODEC_INVALID_PARAM; 4495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 4505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 4515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang option_name = strtok_r(NULL, "=", &input_ptr); 4525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 4535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(input_string); 4545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return res; 4555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 4565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options) { 4585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 4595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || options == NULL || si == NULL) { 4605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 4615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 4625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang strncpy(si->options, options, sizeof(si->options)); 4635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->options[sizeof(si->options) - 1] = '\0'; 4645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 4655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 4665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx, 468b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const char *quantizers, 469b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const int is_for_keyframe) { 4705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 4715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || quantizers == NULL || si == NULL) { 4725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 4735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 474b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (is_for_keyframe) { 475b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian strncpy(si->quantizers_keyframe, quantizers, sizeof(si->quantizers)); 476b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->quantizers_keyframe[sizeof(si->quantizers_keyframe) - 1] = '\0'; 477b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } else { 478b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian strncpy(si->quantizers, quantizers, sizeof(si->quantizers)); 479b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->quantizers[sizeof(si->quantizers) - 1] = '\0'; 480b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 4815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 4825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 4835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx, 4855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const char *scale_factors) { 4865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 4875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || scale_factors == NULL || si == NULL) { 4885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 4895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 4905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors)); 4915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->scale_factors[sizeof(si->scale_factors) - 1] = '\0'; 4925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 4935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 4945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 4955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, 4965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_iface_t *iface, 4975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_enc_cfg_t *enc_cfg) { 4985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int max_intra_size_pct; 4995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_err_t res; 5005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 5015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL || 5025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg == NULL) { 5035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 5045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 5055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si == NULL) return VPX_CODEC_MEM_ERROR; 5065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->codec_ctx = codec_ctx; 5085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->width = enc_cfg->g_w; 5105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->height = enc_cfg->g_h; 5115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (enc_cfg->kf_max_dist < 2) { 5135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n", 5145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->kf_max_dist); 5155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 5165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 5175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->kf_dist = enc_cfg->kf_max_dist; 5185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->spatial_layers == 0) 5205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers = VPX_SS_DEFAULT_LAYERS; 5215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->spatial_layers < 1 || 5225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers > VPX_SS_MAX_LAYERS) { 5235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n", 5245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->spatial_layers); 5255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 5265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 5275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 528b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian res = parse_quantizer_values(svc_ctx, si->quantizers, 0); 5295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) return res; 5305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 531b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian res = parse_quantizer_values(svc_ctx, si->quantizers_keyframe, 1); 532b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (res != VPX_CODEC_OK) 533b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian memcpy(si->quantizer_keyframe, si->quantizer, sizeof(si->quantizer)); 534b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 5355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = parse_scale_factors(svc_ctx, si->scale_factors); 5365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) return res; 5375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5386ac915abcdb404a00d927fe6308a47fcf09d9519hkuang // Parse aggregate command line options. Options must start with 5396ac915abcdb404a00d927fe6308a47fcf09d9519hkuang // "layers=xx" then followed by other options 5405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = parse_options(svc_ctx, si->options); 5415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) return res; 5425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5436ac915abcdb404a00d927fe6308a47fcf09d9519hkuang si->layers = svc_ctx->spatial_layers; 5446ac915abcdb404a00d927fe6308a47fcf09d9519hkuang 545b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // Assign target bitrate for each layer. We calculate the ratio 546b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // from the resolution for now. 547b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // TODO(Minghai): Optimize the mechanism of allocating bits after 548b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // implementing svc two pass rate control. 549b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (si->layers > 1) { 550b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int i; 551b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian float total = 0; 552b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; 553b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 554a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian assert(si->layers <= VPX_SS_MAX_LAYERS); 555b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian for (i = 0; i < si->layers; ++i) { 556b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int pos = i + VPX_SS_MAX_LAYERS - svc_ctx->spatial_layers; 557b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (pos < VPX_SS_MAX_LAYERS && si->scaling_factor_den[pos] > 0) { 558b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian alloc_ratio[i] = (float)(si->scaling_factor_num[pos] * 1.0 / 559b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->scaling_factor_den[pos]); 560b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 561b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian alloc_ratio[i] *= alloc_ratio[i]; 562b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian total += alloc_ratio[i]; 563b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 564b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 565b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 566b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian for (i = 0; i < si->layers; ++i) { 567b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (total > 0) { 568b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian enc_cfg->ss_target_bitrate[i] = (unsigned int) 569b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian (enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); 570b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 571b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 572b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 573b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 5745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // modify encoder configuration 5755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->ss_number_layers = si->layers; 576b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian enc_cfg->ts_number_layers = 1; // Temporal layers not used in this encoder. 5775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->kf_mode = VPX_KF_DISABLED; 5785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Lag in frames not currently supported 5795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->g_lag_in_frames = 0; 5805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // TODO(ivanmaltz): determine if these values need to be set explicitly for 5825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // svc, or if the normal default/override mechanism can be used 5835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_dropframe_thresh = 0; 5845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_end_usage = VPX_CBR; 5855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_resize_allowed = 0; 5866ac915abcdb404a00d927fe6308a47fcf09d9519hkuang 5876ac915abcdb404a00d927fe6308a47fcf09d9519hkuang if (enc_cfg->g_pass == VPX_RC_ONE_PASS) { 5886ac915abcdb404a00d927fe6308a47fcf09d9519hkuang enc_cfg->rc_min_quantizer = 33; 5896ac915abcdb404a00d927fe6308a47fcf09d9519hkuang enc_cfg->rc_max_quantizer = 33; 5906ac915abcdb404a00d927fe6308a47fcf09d9519hkuang } 5916ac915abcdb404a00d927fe6308a47fcf09d9519hkuang 5925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_undershoot_pct = 100; 5935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_overshoot_pct = 15; 5945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_buf_initial_sz = 500; 5955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_buf_optimal_sz = 600; 5965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->rc_buf_sz = 1000; 5975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang enc_cfg->g_error_resilient = 1; 5985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 5995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Initialize codec 6005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = vpx_codec_enc_init(codec_ctx, iface, enc_cfg, VPX_CODEC_USE_PSNR); 6015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) { 6025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n"); 6035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return res; 6045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1); 6075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP8E_SET_CPUUSED, 1); 6085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP8E_SET_STATIC_THRESHOLD, 1); 6095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP8E_SET_NOISE_SENSITIVITY, 1); 6105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP8E_SET_TOKEN_PARTITIONS, 1); 6115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang max_intra_size_pct = 6135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang (int)(((double)enc_cfg->rc_buf_optimal_sz * 0.5) * 6145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ((double)enc_cfg->g_timebase.den / enc_cfg->g_timebase.num) / 10.0); 6155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP8E_SET_MAX_INTRA_BITRATE_PCT, 6165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang max_intra_size_pct); 6175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 6185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 6195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// SVC Algorithm flags - these get mapped to VP8_EFLAG_* defined in vp8cx.h 6215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should reference the last frame 6235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define USE_LAST (1 << 0) 6245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should reference the alt ref frame 6265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define USE_ARF (1 << 1) 6275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should reference the golden frame 6295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define USE_GF (1 << 2) 6305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should copy current frame to the last frame buffer 6325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define UPDATE_LAST (1 << 3) 6335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should copy current frame to the alt ref frame buffer 6355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define UPDATE_ARF (1 << 4) 6365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// encoder should copy current frame to the golden frame 6385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang#define UPDATE_GF (1 << 5) 6395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic int map_vp8_flags(int svc_flags) { 6415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int flags = 0; 6425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (!(svc_flags & USE_LAST)) flags |= VP8_EFLAG_NO_REF_LAST; 6445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (!(svc_flags & USE_ARF)) flags |= VP8_EFLAG_NO_REF_ARF; 6455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (!(svc_flags & USE_GF)) flags |= VP8_EFLAG_NO_REF_GF; 6465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_flags & UPDATE_LAST) { 6485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // last is updated automatically 6495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags |= VP8_EFLAG_NO_UPD_LAST; 6515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_flags & UPDATE_ARF) { 6535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags |= VP8_EFLAG_FORCE_ARF; 6545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags |= VP8_EFLAG_NO_UPD_ARF; 6565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_flags & UPDATE_GF) { 6585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags |= VP8_EFLAG_FORCE_GF; 6595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags |= VP8_EFLAG_NO_UPD_GF; 6615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return flags; 6635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 6645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void calculate_enc_frame_flags(SvcContext *svc_ctx) { 6665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_enc_frame_flags_t flags = VPX_EFLAG_FORCE_KF; 6675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 6685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const int is_keyframe = (si->frame_within_gop == 0); 6695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // keyframe layer zero is identical for all modes 671b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (is_keyframe && si->layer == 0) { 6725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->enc_frame_flags = VPX_EFLAG_FORCE_KF; 6735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return; 6745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 6765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang switch (svc_ctx->encoding_mode) { 6775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case ALT_INTER_LAYER_PREDICTION_IP: 6785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == 0) { 6795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 6805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (is_keyframe) { 6815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == si->layers - 1) { 6825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST); 6835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); 6855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); 6885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 6905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case INTER_LAYER_PREDICTION_I: 6915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == 0) { 6925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 6935ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (is_keyframe) { 6945ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST); 6955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 6965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 6975ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 6985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 6995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case INTER_LAYER_PREDICTION_IP: 7005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == 0) { 7015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 7025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (is_keyframe) { 7035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST); 7045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 7055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | USE_ARF | UPDATE_LAST); 7065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 7085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case USE_GOLDEN_FRAME: 7095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (2 * si->layers - SVC_REFERENCE_FRAMES <= si->layer) { 7105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == 0) { 7115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | USE_GF | UPDATE_LAST); 7125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (is_keyframe) { 7135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST | UPDATE_GF); 7145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 7155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | USE_ARF | USE_GF | UPDATE_LAST); 7165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 7185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer == 0) { 7195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 7205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else if (is_keyframe) { 7215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_ARF | UPDATE_LAST); 7225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 7235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang flags = map_vp8_flags(USE_LAST | UPDATE_LAST); 7245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 7275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang default: 7285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "unexpected encoding mode: %d\n", 7295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode); 7305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 7315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->enc_frame_flags = flags; 7335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 7345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx, 7365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int layer, 7375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang unsigned int *width, 7385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang unsigned int *height) { 7395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int w, h, index, num, den; 7405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 7415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL) { 7435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 7445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer < 0 || layer >= si->layers) return VPX_CODEC_INVALID_PARAM; 7465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang index = layer + VPX_SS_MAX_LAYERS - si->layers; 7485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang num = si->scaling_factor_num[index]; 7495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang den = si->scaling_factor_den[index]; 7505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM; 7515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang w = si->width * num / den; 7535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang h = si->height * num / den; 7545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // make height and width even to make chrome player happy 7565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang w += w % 2; 7575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang h += h % 2; 7585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *width = w; 7605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang *height = h; 7615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 7635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 7645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangstatic void set_svc_parameters(SvcContext *svc_ctx, 7665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_ctx_t *codec_ctx) { 7675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int layer, layer_index; 7685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_svc_parameters_t svc_params; 7695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 7705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang memset(&svc_params, 0, sizeof(svc_params)); 772b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_params.temporal_layer = 0; 773b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_params.spatial_layer = si->layer; 7745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags = si->enc_frame_flags; 7755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 7765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer = si->layer; 7775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && 7785ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->frame_within_gop == 0) { 7795ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // layers 1 & 3 don't exist in this mode, use the higher one 7805ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer == 0 || layer == 2) { 7815ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer += 1; 7825ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7835ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer, 7855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang &svc_params.width, 7865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang &svc_params.height)) { 7875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n"); 7885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 7895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_index = layer + VPX_SS_MAX_LAYERS - si->layers; 790b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 7916ac915abcdb404a00d927fe6308a47fcf09d9519hkuang if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) { 7926ac915abcdb404a00d927fe6308a47fcf09d9519hkuang if (vpx_svc_is_keyframe(svc_ctx)) { 7936ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.min_quantizer = si->quantizer_keyframe[layer_index]; 7946ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.max_quantizer = si->quantizer_keyframe[layer_index]; 7956ac915abcdb404a00d927fe6308a47fcf09d9519hkuang } else { 7966ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.min_quantizer = si->quantizer[layer_index]; 7976ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.max_quantizer = si->quantizer[layer_index]; 7986ac915abcdb404a00d927fe6308a47fcf09d9519hkuang } 799b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } else { 8006ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer; 8016ac915abcdb404a00d927fe6308a47fcf09d9519hkuang svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer; 802b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 803b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 8045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.distance_from_i_frame = si->frame_within_gop; 8055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Use buffer i for layer i LST 8075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.lst_fb_idx = si->layer; 8085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // Use buffer i-1 for layer i Alt (Inter-layer prediction) 8105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer != 0) { 8115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const int use_higher_layer = 8125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && 8135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->frame_within_gop == 0; 8145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.alt_fb_idx = use_higher_layer ? si->layer - 2 : si->layer - 1; 8155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP) { 8185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.gld_fb_idx = si->layer + 1; 8195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 8205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->layer < 2 * si->layers - SVC_REFERENCE_FRAMES) 8215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.gld_fb_idx = svc_params.lst_fb_idx; 8225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang else 8235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.gld_fb_idx = 2 * si->layers - 1 - si->layer; 8245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, layer: %d, %dx%d, q: %d\n", 8275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->encode_frame_count, si->layer, svc_params.width, 8285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.height, svc_params.min_quantizer); 8295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_params.flags == VPX_EFLAG_FORCE_KF) { 8315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_DEBUG, "flags == VPX_EFLAG_FORCE_KF\n"); 8325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } else { 8335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log( 8345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx, SVC_LOG_DEBUG, "Using: LST/GLD/ALT [%2d|%2d|%2d]\n", 8355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_REF_LAST ? -1 : svc_params.lst_fb_idx, 8365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_REF_GF ? -1 : svc_params.gld_fb_idx, 8375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_REF_ARF ? -1 : svc_params.alt_fb_idx); 8385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log( 8395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx, SVC_LOG_DEBUG, "Updating: LST/GLD/ALT [%2d|%2d|%2d]\n", 8405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_UPD_LAST ? -1 : svc_params.lst_fb_idx, 8415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_UPD_GF ? -1 : svc_params.gld_fb_idx, 8425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_params.flags & VP8_EFLAG_NO_UPD_ARF ? -1 : svc_params.alt_fb_idx); 8435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8455ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params); 8465ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 8475ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8485ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang/** 8495ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Encode a frame into multiple layers 8505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang * Create a superframe containing the individual layers 8515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang */ 8525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvpx_codec_err_t vpx_svc_encode(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx, 8535ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct vpx_image *rawimg, vpx_codec_pts_t pts, 8545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int64_t duration, int deadline) { 8555ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_err_t res; 8565ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang vpx_codec_iter_t iter; 8575ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const vpx_codec_cx_pkt_t *cx_pkt; 8585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *cx_layer_list = NULL; 8595ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct LayerData *layer_data; 8605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang struct Superframe superframe; 8615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 862a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) { 8635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_INVALID_PARAM; 8645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang memset(&superframe, 0, sizeof(superframe)); 8675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log_reset(svc_ctx); 868b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->rc_stats_buf_used = 0; 8695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 870b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->layers = svc_ctx->spatial_layers; 8715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->frame_within_gop >= si->kf_dist || 872b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->encode_frame_count == 0) { 8735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->frame_within_gop = 0; 8745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->is_keyframe = (si->frame_within_gop == 0); 8765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->frame_size = 0; 8775ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 878a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (rawimg != NULL) { 879a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_DEBUG, 880a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian "vpx_svc_encode layers: %d, frame_count: %d, " 881a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian "frame_within_gop: %d\n", si->layers, si->encode_frame_count, 882a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian si->frame_within_gop); 883a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian } 8845ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 8855ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // encode each layer 8865ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (si->layer = 0; si->layer < si->layers; ++si->layer) { 8875ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && 8885ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->is_keyframe && (si->layer == 1 || si->layer == 3)) { 8895ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_DEBUG, "Skip encoding layer %d\n", si->layer); 8905ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang continue; 8915ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 8925ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 893a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (rawimg != NULL) { 894a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian calculate_enc_frame_flags(svc_ctx); 895a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian set_svc_parameters(svc_ctx, codec_ctx); 896a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian } 897b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 8985ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 8995ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->enc_frame_flags, deadline); 9005ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (res != VPX_CODEC_OK) { 9015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return res; 9025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // save compressed data 9045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang iter = NULL; 9055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang while ((cx_pkt = vpx_codec_get_cx_data(codec_ctx, &iter))) { 9065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang switch (cx_pkt->kind) { 9075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case VPX_CODEC_CX_FRAME_PKT: { 9085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const uint32_t frame_pkt_size = (uint32_t)(cx_pkt->data.frame.sz); 909b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->bytes_sum[si->layer] += frame_pkt_size; 910b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_DEBUG, 911b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "SVC frame: %d, layer: %d, size: %u\n", 912b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->encode_frame_count, si->layer, frame_pkt_size); 9135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang layer_data = 9145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ld_create(cx_pkt->data.frame.buf, (size_t)frame_pkt_size); 9155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (layer_data == NULL) { 9165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating LayerData\n"); 917b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return VPX_CODEC_OK; 9185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ld_list_add(&cx_layer_list, layer_data); 9205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 9215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // save layer size in superframe index 9225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang superframe.sizes[superframe.count++] = frame_pkt_size; 9235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang superframe.magnitude |= frame_pkt_size; 9245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 9255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang case VPX_CODEC_PSNR_PKT: { 927b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int i; 928b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_DEBUG, 929b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): " 930b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "%2.3f %2.3f %2.3f %2.3f \n", 931b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->encode_frame_count, si->layer, 932b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.psnr.psnr[0], cx_pkt->data.psnr.psnr[1], 933b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.psnr.psnr[2], cx_pkt->data.psnr.psnr[3]); 934b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_DEBUG, 935b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "SVC frame: %d, layer: %d, SSE(Total/Y/U/V): " 936b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "%2.3f %2.3f %2.3f %2.3f \n", 937b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->encode_frame_count, si->layer, 938b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.psnr.sse[0], cx_pkt->data.psnr.sse[1], 939b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.psnr.sse[2], cx_pkt->data.psnr.sse[3]); 940b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian for (i = 0; i < COMPONENTS; i++) { 941b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->psnr_sum[si->layer][i] += cx_pkt->data.psnr.psnr[i]; 942b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->sse_sum[si->layer][i] += cx_pkt->data.psnr.sse[i]; 943b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 944b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian break; 945b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 946b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian case VPX_CODEC_STATS_PKT: { 947b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian size_t new_size = si->rc_stats_buf_used + 948b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.twopass_stats.sz; 949b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 950b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (new_size > si->rc_stats_buf_size) { 951b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian char *p = (char*)realloc(si->rc_stats_buf, new_size); 952b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (p == NULL) { 953b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_ERROR, "Error allocating stats buf\n"); 954b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian break; 955b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 956b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->rc_stats_buf = p; 957b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->rc_stats_buf_size = new_size; 9585ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 959b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 960b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian memcpy(si->rc_stats_buf + si->rc_stats_buf_used, 961b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian cx_pkt->data.twopass_stats.buf, cx_pkt->data.twopass_stats.sz); 962b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->rc_stats_buf_used += cx_pkt->data.twopass_stats.sz; 9635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 9645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang default: { 9665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang break; 9675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 9695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 970a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (rawimg == NULL) { 971a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian break; 972a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian } 9735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 974a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (codec_ctx->config.enc->g_pass != VPX_RC_FIRST_PASS) { 975a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian // add superframe index to layer data list 976a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian sf_create_index(&superframe); 977a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian layer_data = ld_create(superframe.buffer, superframe.index_size); 978a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian ld_list_add(&cx_layer_list, layer_data); 979a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian 980a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian // get accumulated size of layer data 981a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian si->frame_size = ld_list_get_buffer_size(cx_layer_list); 982a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (si->frame_size > 0) { 983a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian // all layers encoded, create single buffer with concatenated layers 984a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (si->frame_size > si->buffer_size) { 985a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian free(si->buffer); 986a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian si->buffer = malloc(si->frame_size); 987a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian if (si->buffer == NULL) { 988a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian ld_list_free(cx_layer_list); 989a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian return VPX_CODEC_MEM_ERROR; 990a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian } 991a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian si->buffer_size = si->frame_size; 992a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian } 993a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian // copy layer data into packet 994a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian ld_list_copy_to_buffer(cx_layer_list, (uint8_t *)si->buffer); 9955ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 9965ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ld_list_free(cx_layer_list); 997a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian 998a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_DEBUG, "SVC frame: %d, kf: %d, size: %d, " 999a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian "pts: %d\n", si->encode_frame_count, si->is_keyframe, 1000a72801d7d92ababb50eecf27a36bd222d031d2feVignesh Venkatasubramanian (int)si->frame_size, (int)pts); 10015ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 10025ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 10035ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ++si->frame_within_gop; 10045ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang ++si->encode_frame_count; 10055ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10065ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return VPX_CODEC_OK; 10075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangconst char *vpx_svc_get_message(const SvcContext *svc_ctx) { 10105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 10115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return NULL; 10125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return si->message_buffer; 10135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid *vpx_svc_get_buffer(const SvcContext *svc_ctx) { 10165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 10175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return NULL; 10185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return si->buffer; 10195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangsize_t vpx_svc_get_frame_size(const SvcContext *svc_ctx) { 10225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 10235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return 0; 10245ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return si->frame_size; 10255ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10265ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangint vpx_svc_get_encode_frame_count(const SvcContext *svc_ctx) { 10285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 10295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return 0; 10305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return si->encode_frame_count; 10315ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10325ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10335ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangint vpx_svc_is_keyframe(const SvcContext *svc_ctx) { 10345ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang const SvcInternal *const si = get_const_svc_internal(svc_ctx); 10355ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return 0; 10365ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return si->is_keyframe; 10375ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10385ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid vpx_svc_set_keyframe(SvcContext *svc_ctx) { 10405ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 10415ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return; 10425ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->frame_within_gop = 0; 10435ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 10445ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 1045b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianstatic double calc_psnr(double d) { 1046b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (d == 0) return 100; 1047b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return -10.0 * log(d) / log(10.0); 1048b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian} 1049b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 10505ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang// dump accumulated statistics and reset accumulated values 10515ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangconst char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { 10525ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang int number_of_frames, number_of_keyframes, encode_frame_count; 1053b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian int i, j; 10545ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang uint32_t bytes_total = 0; 1055b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian double scale[COMPONENTS]; 1056b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian double psnr[COMPONENTS]; 1057b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian double mse[COMPONENTS]; 1058b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian double y_scale; 1059b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 10605ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *const si = get_svc_internal(svc_ctx); 10615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL || si == NULL) return NULL; 10625ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10635ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log_reset(svc_ctx); 10645ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10655ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang encode_frame_count = si->encode_frame_count; 10665ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si->encode_frame_count <= 0) return vpx_svc_get_message(svc_ctx); 10675ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10685ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_INFO, "\n"); 10695ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang number_of_keyframes = encode_frame_count / si->kf_dist + 1; 10705ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang for (i = 0; i < si->layers; ++i) { 10715ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang number_of_frames = encode_frame_count; 10725ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 10735ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx->encoding_mode == ALT_INTER_LAYER_PREDICTION_IP && 10745ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang (i == 1 || i == 3)) { 10755ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang number_of_frames -= number_of_keyframes; 10765ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 1077b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_INFO, 1078b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", 1079b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian i, (double)si->psnr_sum[i][0] / number_of_frames, 1080b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian (double)si->psnr_sum[i][1] / number_of_frames, 1081b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian (double)si->psnr_sum[i][2] / number_of_frames, 1082b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); 1083b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // the following psnr calculation is deduced from ffmpeg.c#print_report 1084b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; 1085b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian scale[1] = y_scale; 1086b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian scale[2] = scale[3] = y_scale / 4; // U or V 1087b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian scale[0] = y_scale * 1.5; // total 1088b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1089b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian for (j = 0; j < COMPONENTS; j++) { 1090b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); 1091b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; 1092b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 1093b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_INFO, 1094b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], 1095b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian psnr[1], psnr[2], psnr[3]); 1096b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian svc_log(svc_ctx, SVC_LOG_INFO, 1097b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], 1098b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian mse[1], mse[2], mse[3]); 1099b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1100b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian bytes_total += si->bytes_sum[i]; 1101b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian // clear sums for next time 1102b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->bytes_sum[i] = 0; 1103b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian for (j = 0; j < COMPONENTS; ++j) { 1104b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->psnr_sum[i][j] = 0; 1105b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian si->sse_sum[i][j] = 0; 1106b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 11075ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 11085ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 11095ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // only display statistics once 11105ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si->encode_frame_count = 0; 11115ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 11125ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); 11135ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang return vpx_svc_get_message(svc_ctx); 11145ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 11155ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang 11165ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuangvoid vpx_svc_release(SvcContext *svc_ctx) { 11175ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SvcInternal *si; 11185ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (svc_ctx == NULL) return; 11195ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // do not use get_svc_internal as it will unnecessarily allocate an 11205ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang // SvcInternal if it was not already allocated 11215ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang si = (SvcInternal *)svc_ctx->internal; 11225ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang if (si != NULL) { 11235ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(si->buffer); 1124b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (si->rc_stats_buf) { 1125b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian free(si->rc_stats_buf); 1126b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian } 11275ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang free(si); 11285ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang svc_ctx->internal = NULL; 11295ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang } 11305ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang} 1131b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1132b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramaniansize_t vpx_svc_get_rc_stats_buffer_size(const SvcContext *svc_ctx) { 1133b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const SvcInternal *const si = get_const_svc_internal(svc_ctx); 1134b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (svc_ctx == NULL || si == NULL) return 0; 1135b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return si->rc_stats_buf_used; 1136b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian} 1137b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1138b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanianchar *vpx_svc_get_rc_stats_buffer(const SvcContext *svc_ctx) { 1139b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian const SvcInternal *const si = get_const_svc_internal(svc_ctx); 1140b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian if (svc_ctx == NULL || si == NULL) return NULL; 1141b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian return si->rc_stats_buf; 1142b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian} 1143b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1144b08e2e23eec181e9951df33cd704ac294c5407b6Vignesh Venkatasubramanian 1145