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