svc: Remove non working svc code tests and examples.

This code is calling unimplemented code in av1, remove.   If necessary
we can port from vp9 when implemented in av1.

Change-Id: I49a12820201eda9c7ccd46224fda26a75288b85d
This commit is contained in:
Jim Bankoski 2016-05-18 09:54:54 -07:00
Родитель c0bf1dd1b2
Коммит 2c82d97b5c
7 изменённых файлов: 0 добавлений и 2631 удалений

Просмотреть файл

@ -1,651 +0,0 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
/**
* @file
* AV1 SVC encoding support via libaom
*/
#include <assert.h>
#include <math.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define AOM_DISABLE_CTRL_TYPECHECKS 1
#include "./aom_config.h"
#include "aom/svc_context.h"
#include "aom/aomcx.h"
#include "aom/aom_encoder.h"
#include "aom_mem/aom_mem.h"
#include "av1/common/onyxc_int.h"
#ifdef __MINGW32__
#define strtok_r strtok_s
#ifndef MINGW_HAS_SECURE_API
// proto from /usr/x86_64-w64-mingw32/include/sec_api/string_s.h
_CRTIMP char *__cdecl strtok_s(char *str, const char *delim, char **context);
#endif /* MINGW_HAS_SECURE_API */
#endif /* __MINGW32__ */
#ifdef _MSC_VER
#define strdup _strdup
#define strtok_r strtok_s
#endif
#define SVC_REFERENCE_FRAMES 8
#define SUPERFRAME_SLOTS (8)
#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
#define MAX_QUANTIZER 63
static const int DEFAULT_SCALE_FACTORS_NUM[AOM_SS_MAX_LAYERS] = { 4, 5, 7, 11,
16 };
static const int DEFAULT_SCALE_FACTORS_DEN[AOM_SS_MAX_LAYERS] = { 16, 16, 16,
16, 16 };
typedef enum {
QUANTIZER = 0,
BITRATE,
SCALE_FACTOR,
AUTO_ALT_REF,
ALL_OPTION_TYPES
} LAYER_OPTION_TYPE;
static const int option_max_values[ALL_OPTION_TYPES] = { 63, INT_MAX, INT_MAX,
1 };
static const int option_min_values[ALL_OPTION_TYPES] = { 0, 0, 1, 0 };
// One encoded frame
typedef struct FrameData {
void *buf; // compressed data buffer
size_t size; // length of compressed data
aom_codec_frame_flags_t flags; /**< flags for this frame */
struct FrameData *next;
} FrameData;
static SvcInternal_t *get_svc_internal(SvcContext *svc_ctx) {
if (svc_ctx == NULL) return NULL;
if (svc_ctx->internal == NULL) {
SvcInternal_t *const si = (SvcInternal_t *)malloc(sizeof(*si));
if (si != NULL) {
memset(si, 0, sizeof(*si));
}
svc_ctx->internal = si;
}
return (SvcInternal_t *)svc_ctx->internal;
}
static const SvcInternal_t *get_const_svc_internal(const SvcContext *svc_ctx) {
if (svc_ctx == NULL) return NULL;
return (const SvcInternal_t *)svc_ctx->internal;
}
static void svc_log_reset(SvcContext *svc_ctx) {
SvcInternal_t *const si = (SvcInternal_t *)svc_ctx->internal;
si->message_buffer[0] = '\0';
}
static int svc_log(SvcContext *svc_ctx, SVC_LOG_LEVEL level, const char *fmt,
...) {
char buf[512];
int retval = 0;
va_list ap;
SvcInternal_t *const si = get_svc_internal(svc_ctx);
if (level > svc_ctx->log_level) {
return retval;
}
va_start(ap, fmt);
retval = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (svc_ctx->log_print) {
printf("%s", buf);
} else {
strncat(si->message_buffer, buf,
sizeof(si->message_buffer) - strlen(si->message_buffer) - 1);
}
if (level == SVC_LOG_ERROR) {
si->codec_ctx->err_detail = si->message_buffer;
}
return retval;
}
static aom_codec_err_t extract_option(LAYER_OPTION_TYPE type, char *input,
int *value0, int *value1) {
if (type == SCALE_FACTOR) {
*value0 = strtol(input, &input, 10);
if (*input++ != '/') return AOM_CODEC_INVALID_PARAM;
*value1 = strtol(input, &input, 10);
if (*value0 < option_min_values[SCALE_FACTOR] ||
*value1 < option_min_values[SCALE_FACTOR] ||
*value0 > option_max_values[SCALE_FACTOR] ||
*value1 > option_max_values[SCALE_FACTOR] ||
*value0 > *value1) // num shouldn't be greater than den
return AOM_CODEC_INVALID_PARAM;
} else {
*value0 = atoi(input);
if (*value0 < option_min_values[type] || *value0 > option_max_values[type])
return AOM_CODEC_INVALID_PARAM;
}
return AOM_CODEC_OK;
}
static aom_codec_err_t parse_layer_options_from_string(SvcContext *svc_ctx,
LAYER_OPTION_TYPE type,
const char *input,
int *option0,
int *option1) {
int i;
aom_codec_err_t res = AOM_CODEC_OK;
char *input_string;
char *token;
const char *delim = ",";
char *save_ptr;
if (input == NULL || option0 == NULL ||
(option1 == NULL && type == SCALE_FACTOR))
return AOM_CODEC_INVALID_PARAM;
input_string = strdup(input);
token = strtok_r(input_string, delim, &save_ptr);
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
if (token != NULL) {
res = extract_option(type, token, option0 + i, option1 + i);
if (res != AOM_CODEC_OK) break;
token = strtok_r(NULL, delim, &save_ptr);
} else {
break;
}
}
if (res == AOM_CODEC_OK && i != svc_ctx->spatial_layers) {
svc_log(svc_ctx, SVC_LOG_ERROR,
"svc: layer params type: %d %d values required, "
"but only %d specified\n",
type, svc_ctx->spatial_layers, i);
res = AOM_CODEC_INVALID_PARAM;
}
free(input_string);
return res;
}
/**
* Parse SVC encoding options
* Format: encoding-mode=<svc_mode>,layers=<layer_count>
* scale-factors=<n1>/<d1>,<n2>/<d2>,...
* quantizers=<q1>,<q2>,...
* svc_mode = [i|ip|alt_ip|gf]
*/
static aom_codec_err_t parse_options(SvcContext *svc_ctx, const char *options) {
char *input_string;
char *option_name;
char *option_value;
char *input_ptr;
SvcInternal_t *const si = get_svc_internal(svc_ctx);
aom_codec_err_t res = AOM_CODEC_OK;
int i, alt_ref_enabled = 0;
if (options == NULL) return AOM_CODEC_OK;
input_string = strdup(options);
// parse option name
option_name = strtok_r(input_string, "=", &input_ptr);
while (option_name != NULL) {
// parse option value
option_value = strtok_r(NULL, " ", &input_ptr);
if (option_value == NULL) {
svc_log(svc_ctx, SVC_LOG_ERROR, "option missing value: %s\n",
option_name);
res = AOM_CODEC_INVALID_PARAM;
break;
}
if (strcmp("spatial-layers", option_name) == 0) {
svc_ctx->spatial_layers = atoi(option_value);
} else if (strcmp("temporal-layers", option_name) == 0) {
svc_ctx->temporal_layers = atoi(option_value);
} else if (strcmp("scale-factors", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
si->svc_params.scaling_factor_num,
si->svc_params.scaling_factor_den);
if (res != AOM_CODEC_OK) break;
} else if (strcmp("max-quantizers", option_name) == 0) {
res =
parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
si->svc_params.max_quantizers, NULL);
if (res != AOM_CODEC_OK) break;
} else if (strcmp("min-quantizers", option_name) == 0) {
res =
parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
si->svc_params.min_quantizers, NULL);
if (res != AOM_CODEC_OK) break;
} else if (strcmp("auto-alt-refs", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
si->enable_auto_alt_ref, NULL);
if (res != AOM_CODEC_OK) break;
} else if (strcmp("bitrates", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, BITRATE, option_value,
si->bitrates, NULL);
if (res != AOM_CODEC_OK) break;
} else if (strcmp("multi-frame-contexts", option_name) == 0) {
si->use_multiple_frame_contexts = atoi(option_value);
} else {
svc_log(svc_ctx, SVC_LOG_ERROR, "invalid option: %s\n", option_name);
res = AOM_CODEC_INVALID_PARAM;
break;
}
option_name = strtok_r(NULL, "=", &input_ptr);
}
free(input_string);
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER ||
si->svc_params.max_quantizers[i] < 0 ||
si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] ||
si->svc_params.min_quantizers[i] < 0)
res = AOM_CODEC_INVALID_PARAM;
}
if (si->use_multiple_frame_contexts &&
(svc_ctx->spatial_layers > 3 ||
svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
res = AOM_CODEC_INVALID_PARAM;
for (i = 0; i < svc_ctx->spatial_layers; ++i)
alt_ref_enabled += si->enable_auto_alt_ref[i];
if (alt_ref_enabled > REF_FRAMES - svc_ctx->spatial_layers) {
svc_log(svc_ctx, SVC_LOG_ERROR,
"svc: auto alt ref: Maxinum %d(REF_FRAMES - layers) layers could"
"enabled auto alt reference frame, but % layers are enabled\n",
REF_FRAMES - svc_ctx->spatial_layers, alt_ref_enabled);
res = AOM_CODEC_INVALID_PARAM;
}
return res;
}
aom_codec_err_t aom_svc_set_options(SvcContext *svc_ctx, const char *options) {
SvcInternal_t *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || options == NULL || si == NULL) {
return AOM_CODEC_INVALID_PARAM;
}
strncpy(si->options, options, sizeof(si->options));
si->options[sizeof(si->options) - 1] = '\0';
return AOM_CODEC_OK;
}
void assign_layer_bitrates(const SvcContext *svc_ctx,
aom_codec_enc_cfg_t *const enc_cfg) {
int i;
const SvcInternal_t *const si = get_const_svc_internal(svc_ctx);
int sl, tl, spatial_layer_target;
if (svc_ctx->temporal_layering_mode != 0) {
if (si->bitrates[0] != 0) {
enc_cfg->rc_target_bitrate = 0;
for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
enc_cfg->ss_target_bitrate[sl * svc_ctx->temporal_layers] = 0;
for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
enc_cfg->ss_target_bitrate[sl * svc_ctx->temporal_layers] +=
(unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl];
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + tl] =
si->bitrates[sl * svc_ctx->temporal_layers + tl];
}
}
} else {
float total = 0;
float alloc_ratio[AOM_MAX_LAYERS] = { 0 };
for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
if (si->svc_params.scaling_factor_den[sl] > 0) {
alloc_ratio[sl] =
(float)(si->svc_params.scaling_factor_num[sl] * 1.0 /
si->svc_params.scaling_factor_den[sl]);
total += alloc_ratio[sl];
}
}
for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
enc_cfg->ss_target_bitrate[sl] = spatial_layer_target =
(unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[sl] /
total);
if (svc_ctx->temporal_layering_mode == 3) {
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
spatial_layer_target >> 1;
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
(spatial_layer_target >> 1) + (spatial_layer_target >> 2);
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 2] =
spatial_layer_target;
} else if (svc_ctx->temporal_layering_mode == 2 ||
svc_ctx->temporal_layering_mode == 1) {
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers] =
spatial_layer_target * 2 / 3;
enc_cfg->layer_target_bitrate[sl * svc_ctx->temporal_layers + 1] =
spatial_layer_target;
} else {
// User should explicitly assign bitrates in this case.
assert(0);
}
}
}
} else {
if (si->bitrates[0] != 0) {
enc_cfg->rc_target_bitrate = 0;
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i];
enc_cfg->rc_target_bitrate += si->bitrates[i];
}
} else {
float total = 0;
float alloc_ratio[AOM_MAX_LAYERS] = { 0 };
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
if (si->svc_params.scaling_factor_den[i] > 0) {
alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
si->svc_params.scaling_factor_den[i]);
alloc_ratio[i] *= alloc_ratio[i];
total += alloc_ratio[i];
}
}
for (i = 0; i < AOM_SS_MAX_LAYERS; ++i) {
if (total > 0) {
enc_cfg->layer_target_bitrate[i] =
(unsigned int)(enc_cfg->rc_target_bitrate * alloc_ratio[i] /
total);
}
}
}
}
}
aom_codec_err_t aom_svc_init(SvcContext *svc_ctx, aom_codec_ctx_t *codec_ctx,
aom_codec_iface_t *iface,
aom_codec_enc_cfg_t *enc_cfg) {
aom_codec_err_t res;
int i, sl, tl;
SvcInternal_t *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || codec_ctx == NULL || iface == NULL ||
enc_cfg == NULL) {
return AOM_CODEC_INVALID_PARAM;
}
if (si == NULL) return AOM_CODEC_MEM_ERROR;
si->codec_ctx = codec_ctx;
si->width = enc_cfg->g_w;
si->height = enc_cfg->g_h;
if (enc_cfg->kf_max_dist < 2) {
svc_log(svc_ctx, SVC_LOG_ERROR, "key frame distance too small: %d\n",
enc_cfg->kf_max_dist);
return AOM_CODEC_INVALID_PARAM;
}
si->kf_dist = enc_cfg->kf_max_dist;
if (svc_ctx->spatial_layers == 0)
svc_ctx->spatial_layers = AOM_SS_DEFAULT_LAYERS;
if (svc_ctx->spatial_layers < 1 ||
svc_ctx->spatial_layers > AOM_SS_MAX_LAYERS) {
svc_log(svc_ctx, SVC_LOG_ERROR, "spatial layers: invalid value: %d\n",
svc_ctx->spatial_layers);
return AOM_CODEC_INVALID_PARAM;
}
// Note: temporal_layering_mode only applies to one-pass CBR
// si->svc_params.temporal_layering_mode = svc_ctx->temporal_layering_mode;
if (svc_ctx->temporal_layering_mode == 3) {
svc_ctx->temporal_layers = 3;
} else if (svc_ctx->temporal_layering_mode == 2 ||
svc_ctx->temporal_layering_mode == 1) {
svc_ctx->temporal_layers = 2;
}
for (sl = 0; sl < AOM_SS_MAX_LAYERS; ++sl) {
si->svc_params.scaling_factor_num[sl] = DEFAULT_SCALE_FACTORS_NUM[sl];
si->svc_params.scaling_factor_den[sl] = DEFAULT_SCALE_FACTORS_DEN[sl];
}
for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
i = sl * svc_ctx->temporal_layers + tl;
si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
si->svc_params.min_quantizers[i] = 0;
}
}
// Parse aggregate command line options. Options must start with
// "layers=xx" then followed by other options
res = parse_options(svc_ctx, si->options);
if (res != AOM_CODEC_OK) return res;
if (svc_ctx->spatial_layers < 1) svc_ctx->spatial_layers = 1;
if (svc_ctx->spatial_layers > AOM_SS_MAX_LAYERS)
svc_ctx->spatial_layers = AOM_SS_MAX_LAYERS;
if (svc_ctx->temporal_layers < 1) svc_ctx->temporal_layers = 1;
if (svc_ctx->temporal_layers > AOM_TS_MAX_LAYERS)
svc_ctx->temporal_layers = AOM_TS_MAX_LAYERS;
if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > AOM_MAX_LAYERS) {
svc_log(svc_ctx, SVC_LOG_ERROR,
"spatial layers * temporal layers exceeds the maximum number of "
"allowed layers of %d\n",
svc_ctx->spatial_layers * svc_ctx->temporal_layers,
(int)AOM_MAX_LAYERS);
return AOM_CODEC_INVALID_PARAM;
}
assign_layer_bitrates(svc_ctx, enc_cfg);
#if CONFIG_SPATIAL_SVC
for (i = 0; i < svc_ctx->spatial_layers; ++i)
enc_cfg->ss_enable_auto_alt_ref[i] = si->enable_auto_alt_ref[i];
#endif
if (svc_ctx->temporal_layers > 1) {
int i;
for (i = 0; i < svc_ctx->temporal_layers; ++i) {
enc_cfg->ts_target_bitrate[i] =
enc_cfg->rc_target_bitrate / svc_ctx->temporal_layers;
enc_cfg->ts_rate_decimator[i] = 1 << (svc_ctx->temporal_layers - 1 - i);
}
}
if (svc_ctx->threads) enc_cfg->g_threads = svc_ctx->threads;
// Modify encoder configuration
enc_cfg->ss_number_layers = svc_ctx->spatial_layers;
enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
if (enc_cfg->rc_end_usage == AOM_CBR) {
enc_cfg->rc_resize_allowed = 0;
enc_cfg->rc_min_quantizer = 2;
enc_cfg->rc_max_quantizer = 56;
enc_cfg->rc_undershoot_pct = 50;
enc_cfg->rc_overshoot_pct = 50;
enc_cfg->rc_buf_initial_sz = 500;
enc_cfg->rc_buf_optimal_sz = 600;
enc_cfg->rc_buf_sz = 1000;
enc_cfg->rc_dropframe_thresh = 0;
}
if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
enc_cfg->g_error_resilient = 1;
// Initialize codec
res = aom_codec_enc_init(codec_ctx, iface, enc_cfg, AOM_CODEC_USE_PSNR);
if (res != AOM_CODEC_OK) {
svc_log(svc_ctx, SVC_LOG_ERROR, "svc_enc_init error\n");
return res;
}
if (svc_ctx->spatial_layers > 1 || svc_ctx->temporal_layers > 1) {
aom_codec_control(codec_ctx, AV1E_SET_SVC, 1);
aom_codec_control(codec_ctx, AV1E_SET_SVC_PARAMETERS, &si->svc_params);
}
return AOM_CODEC_OK;
}
/**
* Encode a frame into multiple layers
* Create a superframe containing the individual layers
*/
aom_codec_err_t aom_svc_encode(SvcContext *svc_ctx, aom_codec_ctx_t *codec_ctx,
struct aom_image *rawimg, aom_codec_pts_t pts,
int64_t duration, int deadline) {
aom_codec_err_t res;
aom_codec_iter_t iter;
const aom_codec_cx_pkt_t *cx_pkt;
SvcInternal_t *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || codec_ctx == NULL || si == NULL) {
return AOM_CODEC_INVALID_PARAM;
}
svc_log_reset(svc_ctx);
res =
aom_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0, deadline);
if (res != AOM_CODEC_OK) {
return res;
}
// save compressed data
iter = NULL;
while ((cx_pkt = aom_codec_get_cx_data(codec_ctx, &iter))) {
switch (cx_pkt->kind) {
#if AOM_ENCODER_ABI_VERSION > (5 + AOM_CODEC_ABI_VERSION)
#if CONFIG_SPATIAL_SVC
case AOM_CODEC_SPATIAL_SVC_LAYER_PSNR: {
int i;
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
int j;
svc_log(svc_ctx, SVC_LOG_DEBUG,
"SVC frame: %d, layer: %d, PSNR(Total/Y/U/V): "
"%2.3f %2.3f %2.3f %2.3f \n",
si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].psnr[0],
cx_pkt->data.layer_psnr[i].psnr[1],
cx_pkt->data.layer_psnr[i].psnr[2],
cx_pkt->data.layer_psnr[i].psnr[3]);
svc_log(svc_ctx, SVC_LOG_DEBUG,
"SVC frame: %d, layer: %d, SSE(Total/Y/U/V): "
"%2.3f %2.3f %2.3f %2.3f \n",
si->psnr_pkt_received, i, cx_pkt->data.layer_psnr[i].sse[0],
cx_pkt->data.layer_psnr[i].sse[1],
cx_pkt->data.layer_psnr[i].sse[2],
cx_pkt->data.layer_psnr[i].sse[3]);
for (j = 0; j < COMPONENTS; ++j) {
si->psnr_sum[i][j] += cx_pkt->data.layer_psnr[i].psnr[j];
si->sse_sum[i][j] += cx_pkt->data.layer_psnr[i].sse[j];
}
}
++si->psnr_pkt_received;
break;
}
case AOM_CODEC_SPATIAL_SVC_LAYER_SIZES: {
int i;
for (i = 0; i < svc_ctx->spatial_layers; ++i)
si->bytes_sum[i] += cx_pkt->data.layer_sizes[i];
break;
}
#endif
#endif
default: { break; }
}
}
return AOM_CODEC_OK;
}
const char *aom_svc_get_message(const SvcContext *svc_ctx) {
const SvcInternal_t *const si = get_const_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL) return NULL;
return si->message_buffer;
}
static double calc_psnr(double d) {
if (d == 0) return 100;
return -10.0 * log(d) / log(10.0);
}
// dump accumulated statistics and reset accumulated values
const char *aom_svc_dump_statistics(SvcContext *svc_ctx) {
int number_of_frames;
int i, j;
uint32_t bytes_total = 0;
double scale[COMPONENTS];
double psnr[COMPONENTS];
double mse[COMPONENTS];
double y_scale;
SvcInternal_t *const si = get_svc_internal(svc_ctx);
if (svc_ctx == NULL || si == NULL) return NULL;
svc_log_reset(svc_ctx);
number_of_frames = si->psnr_pkt_received;
if (number_of_frames <= 0) return aom_svc_get_message(svc_ctx);
svc_log(svc_ctx, SVC_LOG_INFO, "\n");
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
svc_log(svc_ctx, SVC_LOG_INFO,
"Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n",
i, (double)si->psnr_sum[i][0] / number_of_frames,
(double)si->psnr_sum[i][1] / number_of_frames,
(double)si->psnr_sum[i][2] / number_of_frames,
(double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]);
// the following psnr calculation is deduced from ffmpeg.c#print_report
y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames;
scale[1] = y_scale;
scale[2] = scale[3] = y_scale / 4; // U or V
scale[0] = y_scale * 1.5; // total
for (j = 0; j < COMPONENTS; j++) {
psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]);
mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j];
}
svc_log(svc_ctx, SVC_LOG_INFO,
"Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0],
psnr[1], psnr[2], psnr[3]);
svc_log(svc_ctx, SVC_LOG_INFO,
"Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0],
mse[1], mse[2], mse[3]);
bytes_total += si->bytes_sum[i];
// Clear sums for next time.
si->bytes_sum[i] = 0;
for (j = 0; j < COMPONENTS; ++j) {
si->psnr_sum[i][j] = 0;
si->sse_sum[i][j] = 0;
}
}
// only display statistics once
si->psnr_pkt_received = 0;
svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total);
return aom_svc_get_message(svc_ctx);
}
void aom_svc_release(SvcContext *svc_ctx) {
SvcInternal_t *si;
if (svc_ctx == NULL) return;
// do not use get_svc_internal as it will unnecessarily allocate an
// SvcInternal_t if it was not already allocated
si = (SvcInternal_t *)svc_ctx->internal;
if (si != NULL) {
free(si);
svc_ctx->internal = NULL;
}
}

Просмотреть файл

@ -100,14 +100,6 @@ endif
aomenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
aomenc.DESCRIPTION = Full featured encoder
EXAMPLES-$(CONFIG_ENCODERS) += aom_temporal_svc_encoder.c
aom_temporal_svc_encoder.SRCS += ivfenc.c ivfenc.h
aom_temporal_svc_encoder.SRCS += tools_common.c tools_common.h
aom_temporal_svc_encoder.SRCS += video_common.h
aom_temporal_svc_encoder.SRCS += video_writer.h video_writer.c
aom_temporal_svc_encoder.SRCS += aom_ports/msvc.h
aom_temporal_svc_encoder.GUID = B18C08F2-A439-4502-A78E-849BE3D60947
aom_temporal_svc_encoder.DESCRIPTION = Temporal SVC Encoder
EXAMPLES-$(CONFIG_DECODERS) += simple_decoder.c
simple_decoder.GUID = D3BBF1E9-2427-450D-BBFF-B2843C1D44CC
simple_decoder.SRCS += ivfdec.h ivfdec.c

Просмотреть файл

@ -1,816 +0,0 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
// This is an example demonstrating how to implement a multi-layer AVx
// encoding scheme based on temporal scalability for video applications
// that benefit from a scalable bitstream.
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "./aom_config.h"
#include "../aom_ports/aom_timer.h"
#include "aom/aomcx.h"
#include "aom/aom_encoder.h"
#include "../tools_common.h"
#include "../video_writer.h"
static const char *exec_name;
void usage_exit(void) { exit(EXIT_FAILURE); }
// Denoiser states, for temporal denoising.
enum denoiserState {
kDenoiserOff,
kDenoiserOnYOnly,
kDenoiserOnYUV,
kDenoiserOnYUVAggressive,
kDenoiserOnAdaptive
};
static int mode_to_num_layers[12] = { 1, 2, 2, 3, 3, 3, 3, 5, 2, 3, 3, 3 };
// For rate control encoding stats.
struct RateControlMetrics {
// Number of input frames per layer.
int layer_input_frames[AOM_TS_MAX_LAYERS];
// Total (cumulative) number of encoded frames per layer.
int layer_tot_enc_frames[AOM_TS_MAX_LAYERS];
// Number of encoded non-key frames per layer.
int layer_enc_frames[AOM_TS_MAX_LAYERS];
// Framerate per layer layer (cumulative).
double layer_framerate[AOM_TS_MAX_LAYERS];
// Target average frame size per layer (per-frame-bandwidth per layer).
double layer_pfb[AOM_TS_MAX_LAYERS];
// Actual average frame size per layer.
double layer_avg_frame_size[AOM_TS_MAX_LAYERS];
// Average rate mismatch per layer (|target - actual| / target).
double layer_avg_rate_mismatch[AOM_TS_MAX_LAYERS];
// Actual encoding bitrate per layer (cumulative).
double layer_encoding_bitrate[AOM_TS_MAX_LAYERS];
// Average of the short-time encoder actual bitrate.
// TODO(marpan): Should we add these short-time stats for each layer?
double avg_st_encoding_bitrate;
// Variance of the short-time encoder actual bitrate.
double variance_st_encoding_bitrate;
// Window (number of frames) for computing short-timee encoding bitrate.
int window_size;
// Number of window measurements.
int window_count;
int layer_target_bitrate[AOM_MAX_LAYERS];
};
// Note: these rate control metrics assume only 1 key frame in the
// sequence (i.e., first frame only). So for temporal pattern# 7
// (which has key frame for every frame on base layer), the metrics
// computation will be off/wrong.
// TODO(marpan): Update these metrics to account for multiple key frames
// in the stream.
static void set_rate_control_metrics(struct RateControlMetrics *rc,
aom_codec_enc_cfg_t *cfg) {
unsigned int i = 0;
// Set the layer (cumulative) framerate and the target layer (non-cumulative)
// per-frame-bandwidth, for the rate control encoding stats below.
const double framerate = cfg->g_timebase.den / cfg->g_timebase.num;
rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0];
rc->layer_pfb[0] =
1000.0 * rc->layer_target_bitrate[0] / rc->layer_framerate[0];
for (i = 0; i < cfg->ts_number_layers; ++i) {
if (i > 0) {
rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i];
rc->layer_pfb[i] = 1000.0 * (rc->layer_target_bitrate[i] -
rc->layer_target_bitrate[i - 1]) /
(rc->layer_framerate[i] - rc->layer_framerate[i - 1]);
}
rc->layer_input_frames[i] = 0;
rc->layer_enc_frames[i] = 0;
rc->layer_tot_enc_frames[i] = 0;
rc->layer_encoding_bitrate[i] = 0.0;
rc->layer_avg_frame_size[i] = 0.0;
rc->layer_avg_rate_mismatch[i] = 0.0;
}
rc->window_count = 0;
rc->window_size = 15;
rc->avg_st_encoding_bitrate = 0.0;
rc->variance_st_encoding_bitrate = 0.0;
}
static void printout_rate_control_summary(struct RateControlMetrics *rc,
aom_codec_enc_cfg_t *cfg,
int frame_cnt) {
unsigned int i = 0;
int tot_num_frames = 0;
double perc_fluctuation = 0.0;
printf("Total number of processed frames: %d\n\n", frame_cnt - 1);
printf("Rate control layer stats for %d layer(s):\n\n",
cfg->ts_number_layers);
for (i = 0; i < cfg->ts_number_layers; ++i) {
const int num_dropped =
(i > 0) ? (rc->layer_input_frames[i] - rc->layer_enc_frames[i])
: (rc->layer_input_frames[i] - rc->layer_enc_frames[i] - 1);
tot_num_frames += rc->layer_input_frames[i];
rc->layer_encoding_bitrate[i] = 0.001 * rc->layer_framerate[i] *
rc->layer_encoding_bitrate[i] /
tot_num_frames;
rc->layer_avg_frame_size[i] =
rc->layer_avg_frame_size[i] / rc->layer_enc_frames[i];
rc->layer_avg_rate_mismatch[i] =
100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_enc_frames[i];
printf("For layer#: %d \n", i);
printf("Bitrate (target vs actual): %d %f \n", rc->layer_target_bitrate[i],
rc->layer_encoding_bitrate[i]);
printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i],
rc->layer_avg_frame_size[i]);
printf("Average rate_mismatch: %f \n", rc->layer_avg_rate_mismatch[i]);
printf(
"Number of input frames, encoded (non-key) frames, "
"and perc dropped frames: %d %d %f \n",
rc->layer_input_frames[i], rc->layer_enc_frames[i],
100.0 * num_dropped / rc->layer_input_frames[i]);
printf("\n");
}
rc->avg_st_encoding_bitrate = rc->avg_st_encoding_bitrate / rc->window_count;
rc->variance_st_encoding_bitrate =
rc->variance_st_encoding_bitrate / rc->window_count -
(rc->avg_st_encoding_bitrate * rc->avg_st_encoding_bitrate);
perc_fluctuation = 100.0 * sqrt(rc->variance_st_encoding_bitrate) /
rc->avg_st_encoding_bitrate;
printf("Short-time stats, for window of %d frames: \n", rc->window_size);
printf("Average, rms-variance, and percent-fluct: %f %f %f \n",
rc->avg_st_encoding_bitrate, sqrt(rc->variance_st_encoding_bitrate),
perc_fluctuation);
if ((frame_cnt - 1) != tot_num_frames)
die("Error: Number of input frames not equal to output! \n");
}
// Temporal scaling parameters:
// NOTE: The 3 prediction frames cannot be used interchangeably due to
// differences in the way they are handled throughout the code. The
// frames should be allocated to layers in the order LAST, GF, ARF.
// Other combinations work, but may produce slightly inferior results.
static void set_temporal_layer_pattern(int layering_mode,
aom_codec_enc_cfg_t *cfg,
int *layer_flags,
int *flag_periodicity) {
switch (layering_mode) {
case 0: {
// 1-layer.
int ids[1] = { 0 };
cfg->ts_periodicity = 1;
*flag_periodicity = 1;
cfg->ts_number_layers = 1;
cfg->ts_rate_decimator[0] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// Update L only.
layer_flags[0] =
AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
break;
}
case 1: {
// 2-layers, 2-frame period.
int ids[2] = { 0, 1 };
cfg->ts_periodicity = 2;
*flag_periodicity = 2;
cfg->ts_number_layers = 2;
cfg->ts_rate_decimator[0] = 2;
cfg->ts_rate_decimator[1] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
#if 1
// 0=L, 1=GF, Intra-layer prediction enabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF;
layer_flags[1] =
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_REF_ARF;
#else
// 0=L, 1=GF, Intra-layer prediction disabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF;
layer_flags[1] = AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_LAST;
#endif
break;
}
case 2: {
// 2-layers, 3-frame period.
int ids[3] = { 0, 1, 1 };
cfg->ts_periodicity = 3;
*flag_periodicity = 3;
cfg->ts_number_layers = 2;
cfg->ts_rate_decimator[0] = 3;
cfg->ts_rate_decimator[1] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, Intra-layer prediction enabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[1] = layer_flags[2] =
AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_ARF |
AOM_EFLAG_NO_UPD_LAST;
break;
}
case 3: {
// 3-layers, 6-frame period.
int ids[6] = { 0, 2, 2, 1, 2, 2 };
cfg->ts_periodicity = 6;
*flag_periodicity = 6;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 6;
cfg->ts_rate_decimator[1] = 3;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[3] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST;
layer_flags[1] = layer_flags[2] = layer_flags[4] = layer_flags[5] =
AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_LAST;
break;
}
case 4: {
// 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 4;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction disabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[2] = AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST;
layer_flags[1] = layer_flags[3] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
break;
}
case 5: {
// 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 4;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled in layer 1, disabled
// in layer 2.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[2] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ARF;
layer_flags[1] = layer_flags[3] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
break;
}
case 6: {
// 3-layers, 4-frame period.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 4;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF, Intra-layer prediction enabled.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[2] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ARF;
layer_flags[1] = layer_flags[3] =
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF;
break;
}
case 7: {
// NOTE: Probably of academic interest only.
// 5-layers, 16-frame period.
int ids[16] = { 0, 4, 3, 4, 2, 4, 3, 4, 1, 4, 3, 4, 2, 4, 3, 4 };
cfg->ts_periodicity = 16;
*flag_periodicity = 16;
cfg->ts_number_layers = 5;
cfg->ts_rate_decimator[0] = 16;
cfg->ts_rate_decimator[1] = 8;
cfg->ts_rate_decimator[2] = 4;
cfg->ts_rate_decimator[3] = 2;
cfg->ts_rate_decimator[4] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
layer_flags[0] = AOM_EFLAG_FORCE_KF;
layer_flags[1] = layer_flags[3] = layer_flags[5] = layer_flags[7] =
layer_flags[9] = layer_flags[11] = layer_flags[13] = layer_flags[15] =
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[2] = layer_flags[6] = layer_flags[10] = layer_flags[14] =
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_GF;
layer_flags[4] = layer_flags[12] =
AOM_EFLAG_NO_REF_LAST | AOM_EFLAG_NO_UPD_ARF;
layer_flags[8] = AOM_EFLAG_NO_REF_LAST | AOM_EFLAG_NO_REF_GF;
break;
}
case 8: {
// 2-layers, with sync point at first frame of layer 1.
int ids[2] = { 0, 1 };
cfg->ts_periodicity = 2;
*flag_periodicity = 8;
cfg->ts_number_layers = 2;
cfg->ts_rate_decimator[0] = 2;
cfg->ts_rate_decimator[1] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF.
// ARF is used as predictor for all frames, and is only updated on
// key frame. Sync point every 8 frames.
// Layer 0: predict from L and ARF, update L and G.
layer_flags[0] =
AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_UPD_ARF;
// Layer 1: sync point: predict from L and ARF, and update G.
layer_flags[1] =
AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ARF;
// Layer 0, predict from L and ARF, update L.
layer_flags[2] =
AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
// Layer 1: predict from L, G and ARF, and update G.
layer_flags[3] = AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST |
AOM_EFLAG_NO_UPD_ENTROPY;
// Layer 0.
layer_flags[4] = layer_flags[2];
// Layer 1.
layer_flags[5] = layer_flags[3];
// Layer 0.
layer_flags[6] = layer_flags[4];
// Layer 1.
layer_flags[7] = layer_flags[5];
break;
}
case 9: {
// 3-layers: Sync points for layer 1 and 2 every 8 frames.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 8;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF.
layer_flags[0] = AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_REF_GF |
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF;
layer_flags[1] = AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF;
layer_flags[2] = AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ARF;
layer_flags[3] = layer_flags[5] =
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF;
layer_flags[4] = AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
layer_flags[6] =
AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ARF;
layer_flags[7] = AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY;
break;
}
case 10: {
// 3-layers structure where ARF is used as predictor for all frames,
// and is only updated on key frame.
// Sync points for layer 1 and 2 every 8 frames.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 8;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF.
// Layer 0: predict from L and ARF; update L and G.
layer_flags[0] =
AOM_EFLAG_FORCE_KF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
// Layer 2: sync point: predict from L and ARF; update none.
layer_flags[1] = AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_UPD_GF |
AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST |
AOM_EFLAG_NO_UPD_ENTROPY;
// Layer 1: sync point: predict from L and ARF; update G.
layer_flags[2] =
AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST;
// Layer 2: predict from L, G, ARF; update none.
layer_flags[3] = AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ENTROPY;
// Layer 0: predict from L and ARF; update L.
layer_flags[4] =
AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
// Layer 2: predict from L, G, ARF; update none.
layer_flags[5] = layer_flags[3];
// Layer 1: predict from L, G, ARF; update G.
layer_flags[6] = AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST;
// Layer 2: predict from L, G, ARF; update none.
layer_flags[7] = layer_flags[3];
break;
}
case 11:
default: {
// 3-layers structure as in case 10, but no sync/refresh points for
// layer 1 and 2.
int ids[4] = { 0, 2, 1, 2 };
cfg->ts_periodicity = 4;
*flag_periodicity = 8;
cfg->ts_number_layers = 3;
cfg->ts_rate_decimator[0] = 4;
cfg->ts_rate_decimator[1] = 2;
cfg->ts_rate_decimator[2] = 1;
memcpy(cfg->ts_layer_id, ids, sizeof(ids));
// 0=L, 1=GF, 2=ARF.
// Layer 0: predict from L and ARF; update L.
layer_flags[0] =
AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
layer_flags[4] = layer_flags[0];
// Layer 1: predict from L, G, ARF; update G.
layer_flags[2] = AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_LAST;
layer_flags[6] = layer_flags[2];
// Layer 2: predict from L, G, ARF; update none.
layer_flags[1] = AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_ENTROPY;
layer_flags[3] = layer_flags[1];
layer_flags[5] = layer_flags[1];
layer_flags[7] = layer_flags[1];
break;
}
}
}
int main(int argc, char **argv) {
AvxVideoWriter *outfile[AOM_TS_MAX_LAYERS] = { NULL };
aom_codec_ctx_t codec;
aom_codec_enc_cfg_t cfg;
int frame_cnt = 0;
aom_image_t raw;
aom_codec_err_t res;
unsigned int width;
unsigned int height;
int speed;
int frame_avail;
int got_data;
int flags = 0;
unsigned int i;
int pts = 0; // PTS starts at 0.
int frame_duration = 1; // 1 timebase tick per frame.
int layering_mode = 0;
int layer_flags[AOM_TS_MAX_PERIODICITY] = { 0 };
int flag_periodicity = 1;
#if AOM_ENCODER_ABI_VERSION > (4 + AOM_CODEC_ABI_VERSION)
aom_svc_layer_id_t layer_id = { 0, 0 };
#else
aom_svc_layer_id_t layer_id = { 0 };
#endif
const AvxInterface *encoder = NULL;
FILE *infile = NULL;
struct RateControlMetrics rc;
int64_t cx_time = 0;
const int min_args_base = 11;
#if CONFIG_AOM_HIGHBITDEPTH
aom_bit_depth_t bit_depth = AOM_BITS_8;
int input_bit_depth = 8;
const int min_args = min_args_base + 1;
#else
const int min_args = min_args_base;
#endif // CONFIG_AOM_HIGHBITDEPTH
double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0;
double framerate = 30.0;
exec_name = argv[0];
// Check usage and arguments.
if (argc < min_args) {
#if CONFIG_AOM_HIGHBITDEPTH
die(
"Usage: %s <infile> <outfile> <codec_type(aom/av1)> <width> <height> "
"<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<Rate_0> ... <Rate_nlayers-1> <bit-depth> \n",
argv[0]);
#else
die(
"Usage: %s <infile> <outfile> <codec_type(aom/av1)> <width> <height> "
"<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<Rate_0> ... <Rate_nlayers-1> \n",
argv[0]);
#endif // CONFIG_AOM_HIGHBITDEPTH
}
encoder = get_aom_encoder_by_name(argv[3]);
if (!encoder) die("Unsupported codec.");
printf("Using %s\n", aom_codec_iface_name(encoder->codec_interface()));
width = strtol(argv[4], NULL, 0);
height = strtol(argv[5], NULL, 0);
if (width < 16 || width % 2 || height < 16 || height % 2) {
die("Invalid resolution: %d x %d", width, height);
}
layering_mode = strtol(argv[10], NULL, 0);
if (layering_mode < 0 || layering_mode > 12) {
die("Invalid layering mode (0..12) %s", argv[10]);
}
if (argc != min_args + mode_to_num_layers[layering_mode]) {
die("Invalid number of arguments");
}
#if CONFIG_AOM_HIGHBITDEPTH
switch (strtol(argv[argc - 1], NULL, 0)) {
case 8:
bit_depth = AOM_BITS_8;
input_bit_depth = 8;
break;
case 10:
bit_depth = AOM_BITS_10;
input_bit_depth = 10;
break;
case 12:
bit_depth = AOM_BITS_12;
input_bit_depth = 12;
break;
default: die("Invalid bit depth (8, 10, 12) %s", argv[argc - 1]);
}
if (!aom_img_alloc(
&raw, bit_depth == AOM_BITS_8 ? AOM_IMG_FMT_I420 : AOM_IMG_FMT_I42016,
width, height, 32)) {
die("Failed to allocate image", width, height);
}
#else
if (!aom_img_alloc(&raw, AOM_IMG_FMT_I420, width, height, 32)) {
die("Failed to allocate image", width, height);
}
#endif // CONFIG_AOM_HIGHBITDEPTH
// Populate encoder configuration.
res = aom_codec_enc_config_default(encoder->codec_interface(), &cfg, 0);
if (res) {
printf("Failed to get config: %s\n", aom_codec_err_to_string(res));
return EXIT_FAILURE;
}
// Update the default configuration with our settings.
cfg.g_w = width;
cfg.g_h = height;
#if CONFIG_AOM_HIGHBITDEPTH
if (bit_depth != AOM_BITS_8) {
cfg.g_bit_depth = bit_depth;
cfg.g_input_bit_depth = input_bit_depth;
cfg.g_profile = 2;
}
#endif // CONFIG_AOM_HIGHBITDEPTH
// Timebase format e.g. 30fps: numerator=1, demoninator = 30.
cfg.g_timebase.num = strtol(argv[6], NULL, 0);
cfg.g_timebase.den = strtol(argv[7], NULL, 0);
speed = strtol(argv[8], NULL, 0);
if (speed < 0) {
die("Invalid speed setting: must be positive");
}
for (i = min_args_base;
(int)i < min_args_base + mode_to_num_layers[layering_mode]; ++i) {
rc.layer_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
if (strncmp(encoder->name, "aom", 3) == 0)
cfg.ts_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11];
else if (strncmp(encoder->name, "av1", 3) == 0)
cfg.layer_target_bitrate[i - 11] = rc.layer_target_bitrate[i - 11];
}
// Real time parameters.
cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0);
cfg.rc_end_usage = AOM_CBR;
cfg.rc_min_quantizer = 2;
cfg.rc_max_quantizer = 56;
if (strncmp(encoder->name, "av1", 3) == 0) cfg.rc_max_quantizer = 52;
cfg.rc_undershoot_pct = 50;
cfg.rc_overshoot_pct = 50;
cfg.rc_buf_initial_sz = 500;
cfg.rc_buf_optimal_sz = 600;
cfg.rc_buf_sz = 1000;
// Disable dynamic resizing by default.
cfg.rc_resize_allowed = 0;
// Use 1 thread as default.
cfg.g_threads = 1;
// Enable error resilient mode.
cfg.g_error_resilient = 1;
cfg.g_lag_in_frames = 0;
cfg.kf_mode = AOM_KF_AUTO;
// Disable automatic keyframe placement.
cfg.kf_min_dist = cfg.kf_max_dist = 3000;
cfg.temporal_layering_mode = AV1E_TEMPORAL_LAYERING_MODE_BYPASS;
set_temporal_layer_pattern(layering_mode, &cfg, layer_flags,
&flag_periodicity);
set_rate_control_metrics(&rc, &cfg);
// Target bandwidth for the whole stream.
// Set to layer_target_bitrate for highest layer (total bitrate).
cfg.rc_target_bitrate = rc.layer_target_bitrate[cfg.ts_number_layers - 1];
// Open input file.
if (!(infile = fopen(argv[1], "rb"))) {
die("Failed to open %s for reading", argv[1]);
}
framerate = cfg.g_timebase.den / cfg.g_timebase.num;
// Open an output file for each stream.
for (i = 0; i < cfg.ts_number_layers; ++i) {
char file_name[PATH_MAX];
AvxVideoInfo info;
info.codec_fourcc = encoder->fourcc;
info.frame_width = cfg.g_w;
info.frame_height = cfg.g_h;
info.time_base.numerator = cfg.g_timebase.num;
info.time_base.denominator = cfg.g_timebase.den;
snprintf(file_name, sizeof(file_name), "%s_%d.ivf", argv[2], i);
outfile[i] = aom_video_writer_open(file_name, kContainerIVF, &info);
if (!outfile[i]) die("Failed to open %s for writing", file_name);
assert(outfile[i] != NULL);
}
// No spatial layers in this encoder.
cfg.ss_number_layers = 1;
// Initialize codec.
#if CONFIG_AOM_HIGHBITDEPTH
if (aom_codec_enc_init(
&codec, encoder->codec_interface(), &cfg,
bit_depth == AOM_BITS_8 ? 0 : AOM_CODEC_USE_HIGHBITDEPTH))
#else
if (aom_codec_enc_init(&codec, encoder->codec_interface(), &cfg, 0))
#endif // CONFIG_AOM_HIGHBITDEPTH
die_codec(&codec, "Failed to initialize encoder");
if (strncmp(encoder->name, "aom", 3) == 0) {
aom_codec_control(&codec, AOME_SET_CPUUSED, -speed);
aom_codec_control(&codec, AOME_SET_NOISE_SENSITIVITY, kDenoiserOff);
aom_codec_control(&codec, AOME_SET_STATIC_THRESHOLD, 1);
} else if (strncmp(encoder->name, "av1", 3) == 0) {
aom_svc_extra_cfg_t svc_params;
aom_codec_control(&codec, AOME_SET_CPUUSED, speed);
aom_codec_control(&codec, AV1E_SET_AQ_MODE, 3);
aom_codec_control(&codec, AV1E_SET_FRAME_PERIODIC_BOOST, 0);
aom_codec_control(&codec, AV1E_SET_NOISE_SENSITIVITY, 0);
aom_codec_control(&codec, AOME_SET_STATIC_THRESHOLD, 1);
aom_codec_control(&codec, AV1E_SET_TUNE_CONTENT, 0);
aom_codec_control(&codec, AV1E_SET_TILE_COLUMNS, (cfg.g_threads >> 1));
if (aom_codec_control(&codec, AV1E_SET_SVC, layering_mode > 0 ? 1 : 0))
die_codec(&codec, "Failed to set SVC");
for (i = 0; i < cfg.ts_number_layers; ++i) {
svc_params.max_quantizers[i] = cfg.rc_max_quantizer;
svc_params.min_quantizers[i] = cfg.rc_min_quantizer;
}
svc_params.scaling_factor_num[0] = cfg.g_h;
svc_params.scaling_factor_den[0] = cfg.g_h;
aom_codec_control(&codec, AV1E_SET_SVC_PARAMETERS, &svc_params);
}
if (strncmp(encoder->name, "aom", 3) == 0) {
aom_codec_control(&codec, AOME_SET_SCREEN_CONTENT_MODE, 0);
}
aom_codec_control(&codec, AOME_SET_TOKEN_PARTITIONS, 1);
// This controls the maximum target size of the key frame.
// For generating smaller key frames, use a smaller max_intra_size_pct
// value, like 100 or 200.
{
const int max_intra_size_pct = 900;
aom_codec_control(&codec, AOME_SET_MAX_INTRA_BITRATE_PCT,
max_intra_size_pct);
}
frame_avail = 1;
while (frame_avail || got_data) {
struct aom_usec_timer timer;
aom_codec_iter_t iter = NULL;
const aom_codec_cx_pkt_t *pkt;
#if AOM_ENCODER_ABI_VERSION > (4 + AOM_CODEC_ABI_VERSION)
// Update the temporal layer_id. No spatial layers in this test.
layer_id.spatial_layer_id = 0;
#endif
layer_id.temporal_layer_id =
cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
if (strncmp(encoder->name, "av1", 3) == 0) {
aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
} else if (strncmp(encoder->name, "aom", 3) == 0) {
aom_codec_control(&codec, AOME_SET_TEMPORAL_LAYER_ID,
layer_id.temporal_layer_id);
}
flags = layer_flags[frame_cnt % flag_periodicity];
if (layering_mode == 0) flags = 0;
frame_avail = aom_img_read(&raw, infile);
if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id];
aom_usec_timer_start(&timer);
if (aom_codec_encode(&codec, frame_avail ? &raw : NULL, pts, 1, flags,
AOM_DL_REALTIME)) {
die_codec(&codec, "Failed to encode frame");
}
aom_usec_timer_mark(&timer);
cx_time += aom_usec_timer_elapsed(&timer);
// Reset KF flag.
if (layering_mode != 7) {
layer_flags[0] &= ~AOM_EFLAG_FORCE_KF;
}
got_data = 0;
while ((pkt = aom_codec_get_cx_data(&codec, &iter))) {
got_data = 1;
switch (pkt->kind) {
case AOM_CODEC_CX_FRAME_PKT:
for (i = cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity];
i < cfg.ts_number_layers; ++i) {
aom_video_writer_write_frame(outfile[i], pkt->data.frame.buf,
pkt->data.frame.sz, pts);
++rc.layer_tot_enc_frames[i];
rc.layer_encoding_bitrate[i] += 8.0 * pkt->data.frame.sz;
// Keep count of rate control stats per layer (for non-key frames).
if (i == cfg.ts_layer_id[frame_cnt % cfg.ts_periodicity] &&
!(pkt->data.frame.flags & AOM_FRAME_IS_KEY)) {
rc.layer_avg_frame_size[i] += 8.0 * pkt->data.frame.sz;
rc.layer_avg_rate_mismatch[i] +=
fabs(8.0 * pkt->data.frame.sz - rc.layer_pfb[i]) /
rc.layer_pfb[i];
++rc.layer_enc_frames[i];
}
}
// Update for short-time encoding bitrate states, for moving window
// of size rc->window, shifted by rc->window / 2.
// Ignore first window segment, due to key frame.
if (frame_cnt > rc.window_size) {
sum_bitrate += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
if (frame_cnt % rc.window_size == 0) {
rc.window_count += 1;
rc.avg_st_encoding_bitrate += sum_bitrate / rc.window_size;
rc.variance_st_encoding_bitrate +=
(sum_bitrate / rc.window_size) *
(sum_bitrate / rc.window_size);
sum_bitrate = 0.0;
}
}
// Second shifted window.
if (frame_cnt > rc.window_size + rc.window_size / 2) {
sum_bitrate2 += 0.001 * 8.0 * pkt->data.frame.sz * framerate;
if (frame_cnt > 2 * rc.window_size &&
frame_cnt % rc.window_size == 0) {
rc.window_count += 1;
rc.avg_st_encoding_bitrate += sum_bitrate2 / rc.window_size;
rc.variance_st_encoding_bitrate +=
(sum_bitrate2 / rc.window_size) *
(sum_bitrate2 / rc.window_size);
sum_bitrate2 = 0.0;
}
}
break;
default: break;
}
}
++frame_cnt;
pts += frame_duration;
}
fclose(infile);
printout_rate_control_summary(&rc, &cfg, frame_cnt);
printf("\n");
printf("Frame cnt and encoding time/FPS stats for encoding: %d %f %f \n",
frame_cnt, 1000 * (float)cx_time / (double)(frame_cnt * 1000000),
1000000 * (double)frame_cnt / (double)cx_time);
if (aom_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
// Try to rewrite the output file headers with the actual frame count.
for (i = 0; i < cfg.ts_number_layers; ++i) aom_video_writer_close(outfile[i]);
aom_img_free(&raw);
return EXIT_SUCCESS;
}

Просмотреть файл

@ -1,290 +0,0 @@
#!/bin/sh
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
##
## This source code is subject to the terms of the BSD 2 Clause License and
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
## was not distributed with this source code in the LICENSE file, you can
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
## Media Patent License 1.0 was not distributed with this source code in the
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
##
## This file tests the libaom aom_temporal_svc_encoder example. To add new
## tests to this file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to aom_tsvc_encoder_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
aom_tsvc_encoder_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libaom test data must exist in LIBAOM_TEST_DATA_PATH."
return 1
fi
if [ "$(aom_config_option_enabled CONFIG_TEMPORAL_DENOISING)" != "yes" ]; then
elog "Warning: Temporal denoising is disabled! Spatial denoising will be " \
"used instead, which is probably not what you want for this test."
fi
}
# Runs aom_temporal_svc_encoder using the codec specified by $1 and output file
# name by $2. Additional positional parameters are passed directly to
# aom_temporal_svc_encoder.
aom_tsvc_encoder() {
local encoder="${LIBAOM_BIN_PATH}/aom_temporal_svc_encoder"
encoder="${encoder}${AOM_TEST_EXE_SUFFIX}"
local codec="$1"
local output_file_base="$2"
local output_file="${AOM_TEST_OUTPUT_DIR}/${output_file_base}"
local timebase_num="1"
local timebase_den="1000"
local speed="6"
local frame_drop_thresh="30"
shift 2
if [ ! -x "${encoder}" ]; then
elog "${encoder} does not exist or is not executable."
return 1
fi
eval "${AOM_TEST_PREFIX}" "${encoder}" "${YUV_RAW_INPUT}" "${output_file}" \
"${codec}" "${YUV_RAW_INPUT_WIDTH}" "${YUV_RAW_INPUT_HEIGHT}" \
"${timebase_num}" "${timebase_den}" "${speed}" "${frame_drop_thresh}" \
"$@" \
${devnull}
}
# Confirms that all expected output files exist given the output file name
# passed to aom_temporal_svc_encoder.
# The file name passed to aom_temporal_svc_encoder is joined with the stream
# number and the extension .ivf to produce per stream output files. Here $1 is
# file name, and $2 is expected number of files.
files_exist() {
local file_name="${AOM_TEST_OUTPUT_DIR}/$1"
local num_files="$(($2 - 1))"
for stream_num in $(seq 0 ${num_files}); do
[ -e "${file_name}_${stream_num}.ivf" ] || return 1
done
}
# Run aom_temporal_svc_encoder in all supported modes for aom and av1.
aom_tsvc_encoder_aom_mode_0() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 0 200 || return 1
# Mode 0 produces 1 stream
files_exist "${FUNCNAME}" 1 || return 1
fi
}
aom_tsvc_encoder_aom_mode_1() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 1 200 400 || return 1
# Mode 1 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_aom_mode_2() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 2 200 400 || return 1
# Mode 2 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_aom_mode_3() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 3 200 400 600 || return 1
# Mode 3 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_4() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 4 200 400 600 || return 1
# Mode 4 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_5() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 5 200 400 600 || return 1
# Mode 5 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_6() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 6 200 400 600 || return 1
# Mode 6 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_7() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 7 200 400 600 800 1000 || return 1
# Mode 7 produces 5 streams
files_exist "${FUNCNAME}" 5 || return 1
fi
}
aom_tsvc_encoder_aom_mode_8() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 8 200 400 || return 1
# Mode 8 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_aom_mode_9() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 9 200 400 600 || return 1
# Mode 9 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_10() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 10 200 400 600 || return 1
# Mode 10 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_aom_mode_11() {
if [ "$(aom_encode_available)" = "yes" ]; then
aom_tsvc_encoder aom "${FUNCNAME}" 11 200 400 600 || return 1
# Mode 11 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_0() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 0 200 || return 1
# Mode 0 produces 1 stream
files_exist "${FUNCNAME}" 1 || return 1
fi
}
aom_tsvc_encoder_av1_mode_1() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 1 200 400 || return 1
# Mode 1 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_av1_mode_2() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 2 200 400 || return 1
# Mode 2 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_av1_mode_3() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 3 200 400 600 || return 1
# Mode 3 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_4() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 4 200 400 600 || return 1
# Mode 4 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_5() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 5 200 400 600 || return 1
# Mode 5 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_6() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 6 200 400 600 || return 1
# Mode 6 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_7() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 7 200 400 600 800 1000 || return 1
# Mode 7 produces 5 streams
files_exist "${FUNCNAME}" 5 || return 1
fi
}
aom_tsvc_encoder_av1_mode_8() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 8 200 400 || return 1
# Mode 8 produces 2 streams
files_exist "${FUNCNAME}" 2 || return 1
fi
}
aom_tsvc_encoder_av1_mode_9() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 9 200 400 600 || return 1
# Mode 9 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_10() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 10 200 400 600 || return 1
# Mode 10 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_av1_mode_11() {
if [ "$(av1_encode_available)" = "yes" ]; then
aom_tsvc_encoder av1 "${FUNCNAME}" 11 200 400 600 || return 1
# Mode 11 produces 3 streams
files_exist "${FUNCNAME}" 3 || return 1
fi
}
aom_tsvc_encoder_tests="aom_tsvc_encoder_aom_mode_0
aom_tsvc_encoder_aom_mode_1
aom_tsvc_encoder_aom_mode_2
aom_tsvc_encoder_aom_mode_3
aom_tsvc_encoder_aom_mode_4
aom_tsvc_encoder_aom_mode_5
aom_tsvc_encoder_aom_mode_6
aom_tsvc_encoder_aom_mode_7
aom_tsvc_encoder_aom_mode_8
aom_tsvc_encoder_aom_mode_9
aom_tsvc_encoder_aom_mode_10
aom_tsvc_encoder_aom_mode_11
aom_tsvc_encoder_av1_mode_0
aom_tsvc_encoder_av1_mode_1
aom_tsvc_encoder_av1_mode_2
aom_tsvc_encoder_av1_mode_3
aom_tsvc_encoder_av1_mode_4
aom_tsvc_encoder_av1_mode_5
aom_tsvc_encoder_av1_mode_6
aom_tsvc_encoder_av1_mode_7
aom_tsvc_encoder_av1_mode_8
aom_tsvc_encoder_av1_mode_9
aom_tsvc_encoder_av1_mode_10
aom_tsvc_encoder_av1_mode_11"
run_tests aom_tsvc_encoder_verify_environment "${aom_tsvc_encoder_tests}"

Просмотреть файл

@ -1,72 +0,0 @@
#!/bin/sh
## Copyright (c) 2016, Alliance for Open Media. All rights reserved
##
## This source code is subject to the terms of the BSD 2 Clause License and
## the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
## was not distributed with this source code in the LICENSE file, you can
## obtain it at www.aomedia.org/license/software. If the Alliance for Open
## Media Patent License 1.0 was not distributed with this source code in the
## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
##
## This file tests the libaom av1_spatial_svc_encoder example. To add new
## tests to to this file, do the following:
## 1. Write a shell function (this is your test).
## 2. Add the function to av1_spatial_svc_tests (on a new line).
##
. $(dirname $0)/tools_common.sh
# Environment check: $YUV_RAW_INPUT is required.
av1_spatial_svc_encoder_verify_environment() {
if [ ! -e "${YUV_RAW_INPUT}" ]; then
echo "Libaom test data must exist in LIBAOM_TEST_DATA_PATH."
return 1
fi
}
# Runs av1_spatial_svc_encoder. $1 is the test name.
av1_spatial_svc_encoder() {
local readonly \
encoder="${LIBAOM_BIN_PATH}/av1_spatial_svc_encoder${AOM_TEST_EXE_SUFFIX}"
local readonly test_name="$1"
local readonly \
output_file="${AOM_TEST_OUTPUT_DIR}/av1_ssvc_encoder${test_name}.ivf"
local readonly frames_to_encode=10
local readonly max_kf=9999
shift
if [ ! -x "${encoder}" ]; then
elog "${encoder} does not exist or is not executable."
return 1
fi
eval "${AOM_TEST_PREFIX}" "${encoder}" -w "${YUV_RAW_INPUT_WIDTH}" \
-h "${YUV_RAW_INPUT_HEIGHT}" -k "${max_kf}" -f "${frames_to_encode}" \
"$@" "${YUV_RAW_INPUT}" "${output_file}" ${devnull}
[ -e "${output_file}" ] || return 1
}
# Each test is run with layer count 1-$av1_ssvc_test_layers.
av1_ssvc_test_layers=5
av1_spatial_svc() {
if [ "$(av1_encode_available)" = "yes" ]; then
local readonly test_name="av1_spatial_svc"
for layers in $(seq 1 ${av1_ssvc_test_layers}); do
av1_spatial_svc_encoder "${test_name}" -sl ${layers}
done
fi
}
readonly av1_spatial_svc_tests="DISABLED_av1_spatial_svc_mode_i
DISABLED_av1_spatial_svc_mode_altip
DISABLED_av1_spatial_svc_mode_ip
DISABLED_av1_spatial_svc_mode_gf
av1_spatial_svc"
if [ "$(aom_config_option_enabled CONFIG_SPATIAL_SVC)" = "yes" ]; then
run_tests \
av1_spatial_svc_encoder_verify_environment \
"${av1_spatial_svc_tests}"
fi

Просмотреть файл

@ -1,790 +0,0 @@
/*
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 2 Clause License and
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
* was not distributed with this source code in the LICENSE file, you can
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
* Media Patent License 1.0 was not distributed with this source code in the
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
#include <string>
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/i420_video_source.h"
#include "av1/decoder/decoder.h"
#include "aom/svc_context.h"
#include "aom/aomcx.h"
#include "aom/aom_encoder.h"
namespace {
using libaom_test::CodecFactory;
using libaom_test::Decoder;
using libaom_test::DxDataIterator;
using libaom_test::AV1CodecFactory;
class SvcTest : public ::testing::Test {
protected:
static const uint32_t kWidth = 352;
static const uint32_t kHeight = 288;
SvcTest()
: codec_iface_(0), test_file_name_("hantro_collage_w352h288.yuv"),
codec_initialized_(false), decoder_(0) {
memset(&svc_, 0, sizeof(svc_));
memset(&codec_, 0, sizeof(codec_));
memset(&codec_enc_, 0, sizeof(codec_enc_));
}
virtual ~SvcTest() {}
virtual void SetUp() {
svc_.log_level = SVC_LOG_DEBUG;
svc_.log_print = 0;
codec_iface_ = aom_codec_av1_cx();
const aom_codec_err_t res =
aom_codec_enc_config_default(codec_iface_, &codec_enc_, 0);
EXPECT_EQ(AOM_CODEC_OK, res);
codec_enc_.g_w = kWidth;
codec_enc_.g_h = kHeight;
codec_enc_.g_timebase.num = 1;
codec_enc_.g_timebase.den = 60;
codec_enc_.kf_min_dist = 100;
codec_enc_.kf_max_dist = 100;
aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t();
AV1CodecFactory codec_factory;
decoder_ = codec_factory.CreateDecoder(dec_cfg, 0);
tile_columns_ = 0;
tile_rows_ = 0;
}
virtual void TearDown() {
ReleaseEncoder();
delete (decoder_);
}
void InitializeEncoder() {
const aom_codec_err_t res =
aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_OK, res);
aom_codec_control(&codec_, AOME_SET_CPUUSED, 4); // Make the test faster
aom_codec_control(&codec_, AV1E_SET_TILE_COLUMNS, tile_columns_);
aom_codec_control(&codec_, AV1E_SET_TILE_ROWS, tile_rows_);
codec_initialized_ = true;
}
void ReleaseEncoder() {
aom_svc_release(&svc_);
if (codec_initialized_) aom_codec_destroy(&codec_);
codec_initialized_ = false;
}
void GetStatsData(std::string *const stats_buf) {
aom_codec_iter_t iter = NULL;
const aom_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = aom_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == AOM_CODEC_STATS_PKT) {
EXPECT_GT(cx_pkt->data.twopass_stats.sz, 0U);
ASSERT_TRUE(cx_pkt->data.twopass_stats.buf != NULL);
stats_buf->append(static_cast<char *>(cx_pkt->data.twopass_stats.buf),
cx_pkt->data.twopass_stats.sz);
}
}
}
void Pass1EncodeNFrames(const int n, const int layers,
std::string *const stats_buf) {
aom_codec_err_t res;
ASSERT_GT(n, 0);
ASSERT_GT(layers, 0);
svc_.spatial_layers = layers;
codec_enc_.g_pass = AOM_RC_FIRST_PASS;
InitializeEncoder();
libaom_test::I420VideoSource video(
test_file_name_, codec_enc_.g_w, codec_enc_.g_h,
codec_enc_.g_timebase.den, codec_enc_.g_timebase.num, 0, 30);
video.Begin();
for (int i = 0; i < n; ++i) {
res = aom_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), AOM_DL_GOOD_QUALITY);
ASSERT_EQ(AOM_CODEC_OK, res);
GetStatsData(stats_buf);
video.Next();
}
// Flush encoder and test EOS packet.
res = aom_svc_encode(&svc_, &codec_, NULL, video.pts(), video.duration(),
AOM_DL_GOOD_QUALITY);
ASSERT_EQ(AOM_CODEC_OK, res);
GetStatsData(stats_buf);
ReleaseEncoder();
}
void StoreFrames(const size_t max_frame_received,
struct aom_fixed_buf *const outputs,
size_t *const frame_received) {
aom_codec_iter_t iter = NULL;
const aom_codec_cx_pkt_t *cx_pkt;
while ((cx_pkt = aom_codec_get_cx_data(&codec_, &iter)) != NULL) {
if (cx_pkt->kind == AOM_CODEC_CX_FRAME_PKT) {
const size_t frame_size = cx_pkt->data.frame.sz;
EXPECT_GT(frame_size, 0U);
ASSERT_TRUE(cx_pkt->data.frame.buf != NULL);
ASSERT_LT(*frame_received, max_frame_received);
if (*frame_received == 0)
EXPECT_EQ(1, !!(cx_pkt->data.frame.flags & AOM_FRAME_IS_KEY));
outputs[*frame_received].buf = malloc(frame_size + 16);
ASSERT_TRUE(outputs[*frame_received].buf != NULL);
memcpy(outputs[*frame_received].buf, cx_pkt->data.frame.buf,
frame_size);
outputs[*frame_received].sz = frame_size;
++(*frame_received);
}
}
}
void Pass2EncodeNFrames(std::string *const stats_buf, const int n,
const int layers,
struct aom_fixed_buf *const outputs) {
aom_codec_err_t res;
size_t frame_received = 0;
ASSERT_TRUE(outputs != NULL);
ASSERT_GT(n, 0);
ASSERT_GT(layers, 0);
svc_.spatial_layers = layers;
codec_enc_.rc_target_bitrate = 500;
if (codec_enc_.g_pass == AOM_RC_LAST_PASS) {
ASSERT_TRUE(stats_buf != NULL);
ASSERT_GT(stats_buf->size(), 0U);
codec_enc_.rc_twopass_stats_in.buf = &(*stats_buf)[0];
codec_enc_.rc_twopass_stats_in.sz = stats_buf->size();
}
InitializeEncoder();
libaom_test::I420VideoSource video(
test_file_name_, codec_enc_.g_w, codec_enc_.g_h,
codec_enc_.g_timebase.den, codec_enc_.g_timebase.num, 0, 30);
video.Begin();
for (int i = 0; i < n; ++i) {
res = aom_svc_encode(&svc_, &codec_, video.img(), video.pts(),
video.duration(), AOM_DL_GOOD_QUALITY);
ASSERT_EQ(AOM_CODEC_OK, res);
StoreFrames(n, outputs, &frame_received);
video.Next();
}
// Flush encoder.
res = aom_svc_encode(&svc_, &codec_, NULL, 0, video.duration(),
AOM_DL_GOOD_QUALITY);
EXPECT_EQ(AOM_CODEC_OK, res);
StoreFrames(n, outputs, &frame_received);
EXPECT_EQ(frame_received, static_cast<size_t>(n));
ReleaseEncoder();
}
void DecodeNFrames(const struct aom_fixed_buf *const inputs, const int n) {
int decoded_frames = 0;
int received_frames = 0;
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(n, 0);
for (int i = 0; i < n; ++i) {
ASSERT_TRUE(inputs[i].buf != NULL);
ASSERT_GT(inputs[i].sz, 0U);
const aom_codec_err_t res_dec = decoder_->DecodeFrame(
static_cast<const uint8_t *>(inputs[i].buf), inputs[i].sz);
ASSERT_EQ(AOM_CODEC_OK, res_dec) << decoder_->DecodeError();
++decoded_frames;
DxDataIterator dec_iter = decoder_->GetDxData();
while (dec_iter.Next() != NULL) {
++received_frames;
}
}
EXPECT_EQ(decoded_frames, n);
EXPECT_EQ(received_frames, n);
}
void DropEnhancementLayers(struct aom_fixed_buf *const inputs,
const int num_super_frames,
const int remained_spatial_layers) {
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(num_super_frames, 0);
ASSERT_GT(remained_spatial_layers, 0);
for (int i = 0; i < num_super_frames; ++i) {
uint32_t frame_sizes[8] = { 0 };
int frame_count = 0;
int frames_found = 0;
int frame;
ASSERT_TRUE(inputs[i].buf != NULL);
ASSERT_GT(inputs[i].sz, 0U);
aom_codec_err_t res = av1_parse_superframe_index(
static_cast<const uint8_t *>(inputs[i].buf), inputs[i].sz,
frame_sizes, &frame_count, NULL, NULL);
ASSERT_EQ(AOM_CODEC_OK, res);
if (frame_count == 0) {
// There's no super frame but only a single frame.
ASSERT_EQ(1, remained_spatial_layers);
} else {
// Found a super frame.
uint8_t *frame_data = static_cast<uint8_t *>(inputs[i].buf);
uint8_t *frame_start = frame_data;
for (frame = 0; frame < frame_count; ++frame) {
// Looking for a visible frame.
if (frame_data[0] & 0x02) {
++frames_found;
if (frames_found == remained_spatial_layers) break;
}
frame_data += frame_sizes[frame];
}
ASSERT_LT(frame, frame_count)
<< "Couldn't find a visible frame. "
<< "remained_spatial_layers: " << remained_spatial_layers
<< " super_frame: " << i;
if (frame == frame_count - 1) continue;
frame_data += frame_sizes[frame];
// We need to add one more frame for multiple frame contexts.
uint8_t marker =
static_cast<const uint8_t *>(inputs[i].buf)[inputs[i].sz - 1];
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * frame_count;
const size_t new_index_sz = 2 + mag * (frame + 1);
marker &= 0x0f8;
marker |= frame;
// Copy existing frame sizes.
memmove(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1,
new_index_sz - 2);
// New marker.
frame_data[0] = marker;
frame_data += (mag * (frame + 1) + 1);
*frame_data++ = marker;
inputs[i].sz = frame_data - frame_start;
}
}
}
void FreeBitstreamBuffers(struct aom_fixed_buf *const inputs, const int n) {
ASSERT_TRUE(inputs != NULL);
ASSERT_GT(n, 0);
for (int i = 0; i < n; ++i) {
free(inputs[i].buf);
inputs[i].buf = NULL;
inputs[i].sz = 0;
}
}
SvcContext svc_;
aom_codec_ctx_t codec_;
struct aom_codec_enc_cfg codec_enc_;
aom_codec_iface_t *codec_iface_;
std::string test_file_name_;
bool codec_initialized_;
Decoder *decoder_;
int tile_columns_;
int tile_rows_;
};
TEST_F(SvcTest, SvcInit) {
// test missing parameters
aom_codec_err_t res = aom_svc_init(NULL, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_init(&svc_, NULL, codec_iface_, &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_init(&svc_, &codec_, NULL, &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_init(&svc_, &codec_, codec_iface_, NULL);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 6; // too many layers
res = aom_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 0; // use default layers
InitializeEncoder();
EXPECT_EQ(AOM_SS_DEFAULT_LAYERS, svc_.spatial_layers);
}
TEST_F(SvcTest, InitTwoLayers) {
svc_.spatial_layers = 2;
InitializeEncoder();
}
TEST_F(SvcTest, InvalidOptions) {
aom_codec_err_t res = aom_svc_set_options(&svc_, NULL);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "not-an-option=1");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
}
TEST_F(SvcTest, SetLayersOption) {
aom_codec_err_t res = aom_svc_set_options(&svc_, "spatial-layers=3");
EXPECT_EQ(AOM_CODEC_OK, res);
InitializeEncoder();
EXPECT_EQ(3, svc_.spatial_layers);
}
TEST_F(SvcTest, SetMultipleOptions) {
aom_codec_err_t res =
aom_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3");
EXPECT_EQ(AOM_CODEC_OK, res);
InitializeEncoder();
EXPECT_EQ(2, svc_.spatial_layers);
}
TEST_F(SvcTest, SetScaleFactorsOption) {
svc_.spatial_layers = 2;
aom_codec_err_t res =
aom_svc_set_options(&svc_, "scale-factors=not-scale-factors");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "scale-factors=1/3, 3*3");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "scale-factors=1/3");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "scale-factors=1/3,2/3");
EXPECT_EQ(AOM_CODEC_OK, res);
InitializeEncoder();
}
TEST_F(SvcTest, SetQuantizersOption) {
svc_.spatial_layers = 2;
aom_codec_err_t res = aom_svc_set_options(&svc_, "max-quantizers=nothing");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "min-quantizers=nothing");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "max-quantizers=40");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "min-quantizers=40");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "max-quantizers=30,30 min-quantizers=40,40");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "max-quantizers=40,40 min-quantizers=30,30");
InitializeEncoder();
}
TEST_F(SvcTest, SetAutoAltRefOption) {
svc_.spatial_layers = 5;
aom_codec_err_t res = aom_svc_set_options(&svc_, "auto-alt-refs=none");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
res = aom_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
aom_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
InitializeEncoder();
}
// Test that decoder can handle an SVC frame as the first frame in a sequence.
TEST_F(SvcTest, OnePassEncodeOneFrame) {
codec_enc_.g_pass = AOM_RC_ONE_PASS;
aom_fixed_buf output = { 0 };
Pass2EncodeNFrames(NULL, 1, 2, &output);
DecodeNFrames(&output, 1);
FreeBitstreamBuffers(&output, 1);
}
TEST_F(SvcTest, OnePassEncodeThreeFrames) {
codec_enc_.g_pass = AOM_RC_ONE_PASS;
codec_enc_.g_lag_in_frames = 0;
aom_fixed_buf outputs[3];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 3);
FreeBitstreamBuffers(&outputs[0], 3);
}
TEST_F(SvcTest, TwoPassEncode10Frames) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode20FramesWithAltRef) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(20, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1");
aom_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 5, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 4);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 3);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 2);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2SNRLayers) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1,1/1");
Pass1EncodeNFrames(20, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1");
aom_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
Pass1EncodeNFrames(20, 3, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1");
aom_fixed_buf outputs[20];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]);
DecodeNFrames(&outputs[0], 20);
DropEnhancementLayers(&outputs[0], 20, 2);
DecodeNFrames(&outputs[0], 20);
DropEnhancementLayers(&outputs[0], 20, 1);
DecodeNFrames(&outputs[0], 20);
FreeBitstreamBuffers(&outputs[0], 20);
}
TEST_F(SvcTest, SetMultipleFrameContextsOption) {
svc_.spatial_layers = 5;
aom_codec_err_t res = aom_svc_set_options(&svc_, "multi-frame-contexts=1");
EXPECT_EQ(AOM_CODEC_OK, res);
res = aom_svc_init(&svc_, &codec_, aom_codec_av1_cx(), &codec_enc_);
EXPECT_EQ(AOM_CODEC_INVALID_PARAM, res);
svc_.spatial_layers = 2;
res = aom_svc_set_options(&svc_, "multi-frame-contexts=1");
InitializeEncoder();
}
TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) {
// First pass encode
std::string stats_buf;
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1,1/1");
Pass1EncodeNFrames(10, 2, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_,
"auto-alt-refs=1,1 scale-factors=1/1,1/1 "
"multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1");
Pass1EncodeNFrames(10, 3, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_,
"auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 "
"multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 2);
DecodeNFrames(&outputs[0], 10);
DropEnhancementLayers(&outputs[0], 10, 1);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayers) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
aom_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContexts) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_,
"auto-alt-refs=1 scale-factors=1/1 "
"multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersDecodeBaseLayer) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
aom_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
aom_fixed_buf base_layer[5];
for (int i = 0; i < 5; ++i) base_layer[i] = outputs[i * 2];
DecodeNFrames(&base_layer[0], 5);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest,
TwoPassEncode2TemporalLayersWithMultipleFrameContextsDecodeBaseLayer) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
codec_enc_.g_error_resilient = 0;
aom_svc_set_options(&svc_,
"auto-alt-refs=1 scale-factors=1/1 "
"multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
aom_fixed_buf base_layer[5];
for (int i = 0; i < 5; ++i) base_layer[i] = outputs[i * 2];
DecodeNFrames(&base_layer[0], 5);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithTiles) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
aom_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1");
codec_enc_.g_w = 704;
codec_enc_.g_h = 144;
tile_columns_ = 1;
tile_rows_ = 1;
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContextsAndTiles) {
// First pass encode
std::string stats_buf;
aom_svc_set_options(&svc_, "scale-factors=1/1");
svc_.temporal_layers = 2;
Pass1EncodeNFrames(10, 1, &stats_buf);
// Second pass encode
codec_enc_.g_pass = AOM_RC_LAST_PASS;
svc_.temporal_layers = 2;
codec_enc_.g_error_resilient = 0;
codec_enc_.g_w = 704;
codec_enc_.g_h = 144;
tile_columns_ = 1;
tile_rows_ = 1;
aom_svc_set_options(&svc_,
"auto-alt-refs=1 scale-factors=1/1 "
"multi-frame-contexts=1");
aom_fixed_buf outputs[10];
memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]);
DecodeNFrames(&outputs[0], 10);
FreeBitstreamBuffers(&outputs[0], 10);
}
} // namespace

Просмотреть файл

@ -107,10 +107,6 @@ LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += variance_test.cc
LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += quantize_test.cc
LIBAOM_TEST_SRCS-$(CONFIG_AV1_ENCODER) += subtract_test.cc
ifeq ($(CONFIG_AV1_ENCODER),yes)
LIBAOM_TEST_SRCS-$(CONFIG_SPATIAL_SVC) += svc_test.cc
endif
ifeq ($(CONFIG_AV1_ENCODER)$(CONFIG_AV1_TEMPORAL_DENOISING),yesyes)
LIBAOM_TEST_SRCS-$(HAVE_SSE2) += denoiser_sse2_test.cc
endif