Vidyo patch: Rate control for SVC, 1 pass CBR mode.

-Make Rate control work for SVC 1 pass CBR mode.
-Added temporal layering mode.
-Fixed bug in non-rd variance partition.
-Modified/updated the sample encoders (vp9_spatial_svc_encoder, vpx_temporal_svc_encoder).
-Added datarate unittest(s) for 1 pass CBR SVC.

Change-Id: Ie94b1b68a56ea1267b5087c625e5df04def2ee48
This commit is contained in:
Marco 2015-05-21 16:15:37 -07:00 коммит произвёл Marco
Родитель ebf7466cd8
Коммит c139b81a13
17 изменённых файлов: 1279 добавлений и 269 удалений

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

@ -14,11 +14,13 @@
* that benefit from a scalable bitstream. * that benefit from a scalable bitstream.
*/ */
#include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include "../args.h" #include "../args.h"
#include "../tools_common.h" #include "../tools_common.h"
#include "../video_writer.h" #include "../video_writer.h"
@ -27,11 +29,18 @@
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx/vpx_encoder.h" #include "vpx/vpx_encoder.h"
#include "../vpxstats.h" #include "../vpxstats.h"
#define OUTPUT_RC_STATS 1
static const arg_def_t skip_frames_arg = static const arg_def_t skip_frames_arg =
ARG_DEF("s", "skip-frames", 1, "input frames to skip"); ARG_DEF("s", "skip-frames", 1, "input frames to skip");
static const arg_def_t frames_arg = static const arg_def_t frames_arg =
ARG_DEF("f", "frames", 1, "number of frames to encode"); ARG_DEF("f", "frames", 1, "number of frames to encode");
static const arg_def_t threads_arg =
ARG_DEF("th", "threads", 1, "number of threads to use");
#if OUTPUT_RC_STATS
static const arg_def_t output_rc_stats_arg =
ARG_DEF("rcstat", "output_rc_stats", 1, "output rc stats");
#endif
static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width"); static const arg_def_t width_arg = ARG_DEF("w", "width", 1, "source width");
static const arg_def_t height_arg = ARG_DEF("h", "height", 1, "source height"); static const arg_def_t height_arg = ARG_DEF("h", "height", 1, "source height");
static const arg_def_t timebase_arg = static const arg_def_t timebase_arg =
@ -42,6 +51,9 @@ static const arg_def_t spatial_layers_arg =
ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers"); ARG_DEF("sl", "spatial-layers", 1, "number of spatial SVC layers");
static const arg_def_t temporal_layers_arg = static const arg_def_t temporal_layers_arg =
ARG_DEF("tl", "temporal-layers", 1, "number of temporal SVC layers"); ARG_DEF("tl", "temporal-layers", 1, "number of temporal SVC layers");
static const arg_def_t temporal_layering_mode_arg =
ARG_DEF("tlm", "temporal-layering-mode", 1, "temporal layering scheme."
"VP9E_TEMPORAL_LAYERING_MODE");
static const arg_def_t kf_dist_arg = static const arg_def_t kf_dist_arg =
ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes"); ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
static const arg_def_t scale_factors_arg = static const arg_def_t scale_factors_arg =
@ -65,6 +77,8 @@ static const arg_def_t lag_in_frame_arg =
"generating any outputs"); "generating any outputs");
static const arg_def_t rc_end_usage_arg = static const arg_def_t rc_end_usage_arg =
ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q"); ARG_DEF(NULL, "rc-end-usage", 1, "0 - 3: VBR, CBR, CQ, Q");
static const arg_def_t speed_arg =
ARG_DEF("sp", "speed", 1, "speed configuration");
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
static const struct arg_enum_list bitdepth_enum[] = { static const struct arg_enum_list bitdepth_enum[] = {
@ -85,10 +99,16 @@ static const arg_def_t *svc_args[] = {
&timebase_arg, &bitrate_arg, &skip_frames_arg, &spatial_layers_arg, &timebase_arg, &bitrate_arg, &skip_frames_arg, &spatial_layers_arg,
&kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg, &kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg,
&fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg, &fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg,
&max_bitrate_arg, &temporal_layers_arg, &lag_in_frame_arg, &max_bitrate_arg, &temporal_layers_arg, &temporal_layering_mode_arg,
&lag_in_frame_arg, &threads_arg,
#if OUTPUT_RC_STATS
&output_rc_stats_arg,
#endif
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
&bitdepth_arg, &bitdepth_arg,
#endif #endif
&speed_arg,
&rc_end_usage_arg, NULL &rc_end_usage_arg, NULL
}; };
@ -102,6 +122,10 @@ static const uint32_t default_bitrate = 1000;
static const uint32_t default_spatial_layers = 5; static const uint32_t default_spatial_layers = 5;
static const uint32_t default_temporal_layers = 1; static const uint32_t default_temporal_layers = 1;
static const uint32_t default_kf_dist = 100; static const uint32_t default_kf_dist = 100;
static const uint32_t default_temporal_layering_mode = 0;
static const uint32_t default_output_rc_stats = 0;
static const int32_t default_speed = -1; // -1 means use library default.
static const uint32_t default_threads = 0; // zero means use library default.
typedef struct { typedef struct {
const char *input_filename; const char *input_filename;
@ -143,6 +167,12 @@ static void parse_command_line(int argc, const char **argv_,
svc_ctx->log_level = SVC_LOG_DEBUG; svc_ctx->log_level = SVC_LOG_DEBUG;
svc_ctx->spatial_layers = default_spatial_layers; svc_ctx->spatial_layers = default_spatial_layers;
svc_ctx->temporal_layers = default_temporal_layers; svc_ctx->temporal_layers = default_temporal_layers;
svc_ctx->temporal_layering_mode = default_temporal_layering_mode;
#if OUTPUT_RC_STATS
svc_ctx->output_rc_stat = default_output_rc_stats;
#endif
svc_ctx->speed = default_speed;
svc_ctx->threads = default_threads;
// start with default encoder configuration // start with default encoder configuration
res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0); res = vpx_codec_enc_config_default(vpx_codec_vp9_cx(), enc_cfg, 0);
@ -184,6 +214,20 @@ static void parse_command_line(int argc, const char **argv_,
svc_ctx->spatial_layers = arg_parse_uint(&arg); svc_ctx->spatial_layers = arg_parse_uint(&arg);
} else if (arg_match(&arg, &temporal_layers_arg, argi)) { } else if (arg_match(&arg, &temporal_layers_arg, argi)) {
svc_ctx->temporal_layers = arg_parse_uint(&arg); svc_ctx->temporal_layers = arg_parse_uint(&arg);
#if OUTPUT_RC_STATS
} else if (arg_match(&arg, &output_rc_stats_arg, argi)) {
svc_ctx->output_rc_stat = arg_parse_uint(&arg);
#endif
} else if (arg_match(&arg, &speed_arg, argi)) {
svc_ctx->speed = arg_parse_uint(&arg);
} else if (arg_match(&arg, &threads_arg, argi)) {
svc_ctx->threads = arg_parse_uint(&arg);
} else if (arg_match(&arg, &temporal_layering_mode_arg, argi)) {
svc_ctx->temporal_layering_mode =
enc_cfg->temporal_layering_mode = arg_parse_int(&arg);
if (svc_ctx->temporal_layering_mode) {
enc_cfg->g_error_resilient = 1;
}
} else if (arg_match(&arg, &kf_dist_arg, argi)) { } else if (arg_match(&arg, &kf_dist_arg, argi)) {
enc_cfg->kf_min_dist = arg_parse_uint(&arg); enc_cfg->kf_min_dist = arg_parse_uint(&arg);
enc_cfg->kf_max_dist = enc_cfg->kf_min_dist; enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
@ -316,6 +360,185 @@ static void parse_command_line(int argc, const char **argv_,
enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist); enc_cfg->rc_target_bitrate, enc_cfg->kf_max_dist);
} }
#if OUTPUT_RC_STATS
// For rate control encoding stats.
struct RateControlStats {
// Number of input frames per layer.
int layer_input_frames[VPX_MAX_LAYERS];
// Total (cumulative) number of encoded frames per layer.
int layer_tot_enc_frames[VPX_MAX_LAYERS];
// Number of encoded non-key frames per layer.
int layer_enc_frames[VPX_MAX_LAYERS];
// Framerate per layer (cumulative).
double layer_framerate[VPX_MAX_LAYERS];
// Target average frame size per layer (per-frame-bandwidth per layer).
double layer_pfb[VPX_MAX_LAYERS];
// Actual average frame size per layer.
double layer_avg_frame_size[VPX_MAX_LAYERS];
// Average rate mismatch per layer (|target - actual| / target).
double layer_avg_rate_mismatch[VPX_MAX_LAYERS];
// Actual encoding bitrate per layer (cumulative).
double layer_encoding_bitrate[VPX_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-time encoding bitrate.
int window_size;
// Number of window measurements.
int window_count;
};
// Note: these rate control stats assume only 1 key frame in the
// sequence (i.e., first frame only).
static void set_rate_control_stats(struct RateControlStats *rc,
vpx_codec_enc_cfg_t *cfg) {
unsigned int sl, tl;
// 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;
for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
const int layer = sl * cfg->ts_number_layers + tl;
const int tlayer0 = sl * cfg->ts_number_layers;
rc->layer_framerate[layer] =
framerate / cfg->ts_rate_decimator[tl];
if (tl > 0) {
rc->layer_pfb[layer] = 1000.0 *
(cfg->layer_target_bitrate[layer] -
cfg->layer_target_bitrate[layer - 1]) /
(rc->layer_framerate[layer] -
rc->layer_framerate[layer - 1]);
} else {
rc->layer_pfb[tlayer0] = 1000.0 *
cfg->layer_target_bitrate[tlayer0] /
rc->layer_framerate[tlayer0];
}
rc->layer_input_frames[layer] = 0;
rc->layer_enc_frames[layer] = 0;
rc->layer_tot_enc_frames[layer] = 0;
rc->layer_encoding_bitrate[layer] = 0.0;
rc->layer_avg_frame_size[layer] = 0.0;
rc->layer_avg_rate_mismatch[layer] = 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 RateControlStats *rc,
vpx_codec_enc_cfg_t *cfg,
int frame_cnt) {
unsigned int sl, tl;
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 sl%d tl%d layer(s):\n\n",
cfg->ss_number_layers, cfg->ts_number_layers);
for (sl = 0; sl < cfg->ss_number_layers; ++sl) {
for (tl = 0; tl < cfg->ts_number_layers; ++tl) {
const int layer = sl * cfg->ts_number_layers + tl;
const int num_dropped = (tl > 0) ?
(rc->layer_input_frames[layer] - rc->layer_enc_frames[layer]) :
(rc->layer_input_frames[layer] - rc->layer_enc_frames[layer] - 1);
if (!sl)
tot_num_frames += rc->layer_input_frames[layer];
rc->layer_encoding_bitrate[layer] = 0.001 * rc->layer_framerate[layer] *
rc->layer_encoding_bitrate[layer] / tot_num_frames;
rc->layer_avg_frame_size[layer] = rc->layer_avg_frame_size[layer] /
rc->layer_enc_frames[layer];
rc->layer_avg_rate_mismatch[layer] =
100.0 * rc->layer_avg_rate_mismatch[layer] /
rc->layer_enc_frames[layer];
printf("For layer#: sl%d tl%d \n", sl, tl);
printf("Bitrate (target vs actual): %d %f.0 kbps\n",
cfg->layer_target_bitrate[layer],
rc->layer_encoding_bitrate[layer]);
printf("Average frame size (target vs actual): %f %f bits\n",
rc->layer_pfb[layer], rc->layer_avg_frame_size[layer]);
printf("Average rate_mismatch: %f\n",
rc->layer_avg_rate_mismatch[layer]);
printf("Number of input frames, encoded (non-key) frames, "
"and percent dropped frames: %d %d %f.0 \n",
rc->layer_input_frames[layer], rc->layer_enc_frames[layer],
100.0 * num_dropped / rc->layer_input_frames[layer]);
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 != tot_num_frames)
die("Error: Number of input frames not equal to output encoded frames != "
"%d tot_num_frames = %d\n", frame_cnt, tot_num_frames);
}
vpx_codec_err_t parse_superframe_index(const uint8_t *data,
size_t data_sz,
uint32_t sizes[8], int *count) {
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
// it is a super frame index. If the last byte of real video compression
// data is 0xc0 the encoder must add a 0 byte. If we have the marker but
// not the associated matching marker byte at the front of the index we have
// an invalid bitstream and need to return an error.
uint8_t marker;
marker = *(data + data_sz - 1);
*count = 0;
if ((marker & 0xe0) == 0xc0) {
const uint32_t frames = (marker & 0x7) + 1;
const uint32_t mag = ((marker >> 3) & 0x3) + 1;
const size_t index_sz = 2 + mag * frames;
// This chunk is marked as having a superframe index but doesn't have
// enough data for it, thus it's an invalid superframe index.
if (data_sz < index_sz)
return VPX_CODEC_CORRUPT_FRAME;
{
const uint8_t marker2 = *(data + data_sz - index_sz);
// This chunk is marked as having a superframe index but doesn't have
// the matching marker byte at the front of the index therefore it's an
// invalid chunk.
if (marker != marker2)
return VPX_CODEC_CORRUPT_FRAME;
}
{
// Found a valid superframe index.
uint32_t i, j;
const uint8_t *x = &data[data_sz - index_sz + 1];
for (i = 0; i < frames; ++i) {
uint32_t this_sz = 0;
for (j = 0; j < mag; ++j)
this_sz |= (*x++) << (j * 8);
sizes[i] = this_sz;
}
*count = frames;
}
}
return VPX_CODEC_OK;
}
#endif
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
AppInput app_input = {0}; AppInput app_input = {0};
VpxVideoWriter *writer = NULL; VpxVideoWriter *writer = NULL;
@ -332,7 +555,15 @@ int main(int argc, const char **argv) {
FILE *infile = NULL; FILE *infile = NULL;
int end_of_stream = 0; int end_of_stream = 0;
int frames_received = 0; int frames_received = 0;
#if OUTPUT_RC_STATS
VpxVideoWriter *outfile[VPX_TS_MAX_LAYERS] = {NULL};
struct RateControlStats rc;
vpx_svc_layer_id_t layer_id;
int sl, tl;
double sum_bitrate = 0.0;
double sum_bitrate2 = 0.0;
double framerate = 30.0;
#endif
memset(&svc_ctx, 0, sizeof(svc_ctx)); memset(&svc_ctx, 0, sizeof(svc_ctx));
svc_ctx.log_print = 1; svc_ctx.log_print = 1;
exec_name = argv[0]; exec_name = argv[0];
@ -359,6 +590,13 @@ int main(int argc, const char **argv) {
VPX_CODEC_OK) VPX_CODEC_OK)
die("Failed to initialize encoder\n"); die("Failed to initialize encoder\n");
#if OUTPUT_RC_STATS
if (svc_ctx.output_rc_stat) {
set_rate_control_stats(&rc, &enc_cfg);
framerate = enc_cfg.g_timebase.den / enc_cfg.g_timebase.num;
}
#endif
info.codec_fourcc = VP9_FOURCC; info.codec_fourcc = VP9_FOURCC;
info.time_base.numerator = enc_cfg.g_timebase.num; info.time_base.numerator = enc_cfg.g_timebase.num;
info.time_base.denominator = enc_cfg.g_timebase.den; info.time_base.denominator = enc_cfg.g_timebase.den;
@ -370,11 +608,30 @@ int main(int argc, const char **argv) {
if (!writer) if (!writer)
die("Failed to open %s for writing\n", app_input.output_filename); die("Failed to open %s for writing\n", app_input.output_filename);
} }
#if OUTPUT_RC_STATS
// For now, just write temporal layer streams.
// TODO(wonkap): do spatial by re-writing superframe.
if (svc_ctx.output_rc_stat) {
for (tl = 0; tl < enc_cfg.ts_number_layers; ++tl) {
char file_name[PATH_MAX];
snprintf(file_name, sizeof(file_name), "%s_t%d.ivf",
app_input.output_filename, tl);
outfile[tl] = vpx_video_writer_open(file_name, kContainerIVF, &info);
if (!outfile[tl])
die("Failed to open %s for writing", file_name);
}
}
#endif
// skip initial frames // skip initial frames
for (i = 0; i < app_input.frames_to_skip; ++i) for (i = 0; i < app_input.frames_to_skip; ++i)
vpx_img_read(&raw, infile); vpx_img_read(&raw, infile);
if (svc_ctx.speed != -1)
vpx_codec_control(&codec, VP8E_SET_CPUUSED, svc_ctx.speed);
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, 0);
// Encode frames // Encode frames
while (!end_of_stream) { while (!end_of_stream) {
vpx_codec_iter_t iter = NULL; vpx_codec_iter_t iter = NULL;
@ -386,7 +643,9 @@ int main(int argc, const char **argv) {
} }
res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw), res = vpx_svc_encode(&svc_ctx, &codec, (end_of_stream ? NULL : &raw),
pts, frame_duration, VPX_DL_GOOD_QUALITY); pts, frame_duration, svc_ctx.speed >= 5 ?
VPX_DL_REALTIME : VPX_DL_GOOD_QUALITY);
printf("%s", vpx_svc_get_message(&svc_ctx)); printf("%s", vpx_svc_get_message(&svc_ctx));
if (res != VPX_CODEC_OK) { if (res != VPX_CODEC_OK) {
die_codec(&codec, "Failed to encode frame"); die_codec(&codec, "Failed to encode frame");
@ -395,11 +654,90 @@ int main(int argc, const char **argv) {
while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) { while ((cx_pkt = vpx_codec_get_cx_data(&codec, &iter)) != NULL) {
switch (cx_pkt->kind) { switch (cx_pkt->kind) {
case VPX_CODEC_CX_FRAME_PKT: { case VPX_CODEC_CX_FRAME_PKT: {
if (cx_pkt->data.frame.sz > 0) if (cx_pkt->data.frame.sz > 0) {
#if OUTPUT_RC_STATS
uint32_t sizes[8];
int count = 0;
#endif
vpx_video_writer_write_frame(writer, vpx_video_writer_write_frame(writer,
cx_pkt->data.frame.buf, cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz, cx_pkt->data.frame.sz,
cx_pkt->data.frame.pts); cx_pkt->data.frame.pts);
#if OUTPUT_RC_STATS
// TODO(marpan/wonkap): Put this (to line728) in separate function.
if (svc_ctx.output_rc_stat) {
vpx_codec_control(&codec, VP9E_GET_SVC_LAYER_ID, &layer_id);
parse_superframe_index(cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz, sizes, &count);
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
++rc.layer_input_frames[sl * enc_cfg.ts_number_layers +
layer_id.temporal_layer_id];
}
for (tl = layer_id.temporal_layer_id;
tl < enc_cfg.ts_number_layers; ++tl) {
vpx_video_writer_write_frame(outfile[tl],
cx_pkt->data.frame.buf,
cx_pkt->data.frame.sz,
cx_pkt->data.frame.pts);
}
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
for (tl = layer_id.temporal_layer_id;
tl < enc_cfg.ts_number_layers; ++tl) {
const int layer = sl * enc_cfg.ts_number_layers + tl;
++rc.layer_tot_enc_frames[layer];
rc.layer_encoding_bitrate[layer] += 8.0 * sizes[sl];
// Keep count of rate control stats per layer, for non-key
// frames.
if (tl == layer_id.temporal_layer_id &&
!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY)) {
rc.layer_avg_frame_size[layer] += 8.0 * sizes[sl];
rc.layer_avg_rate_mismatch[layer] +=
fabs(8.0 * sizes[sl] - rc.layer_pfb[layer]) /
rc.layer_pfb[layer];
++rc.layer_enc_frames[layer];
}
}
}
// 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) {
tl = layer_id.temporal_layer_id;
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
sum_bitrate += 0.001 * 8.0 * sizes[sl] * 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) {
tl = layer_id.temporal_layer_id;
for (sl = 0; sl < enc_cfg.ss_number_layers; ++sl) {
sum_bitrate2 += 0.001 * 8.0 * sizes[sl] * 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;
}
}
}
#endif
}
printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received, printf("SVC frame: %d, kf: %d, size: %d, pts: %d\n", frames_received,
!!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY), !!(cx_pkt->data.frame.flags & VPX_FRAME_IS_KEY),
@ -424,25 +762,30 @@ int main(int argc, const char **argv) {
pts += frame_duration; pts += frame_duration;
} }
} }
printf("Processed %d frames\n", frame_cnt); printf("Processed %d frames\n", frame_cnt);
fclose(infile); fclose(infile);
#if OUTPUT_RC_STATS
if (svc_ctx.output_rc_stat) {
printout_rate_control_summary(&rc, &enc_cfg, frame_cnt);
printf("\n");
}
#endif
if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec"); if (vpx_codec_destroy(&codec)) die_codec(&codec, "Failed to destroy codec");
if (app_input.passes == 2) if (app_input.passes == 2)
stats_close(&app_input.rc_stats, 1); stats_close(&app_input.rc_stats, 1);
if (writer) { if (writer) {
vpx_video_writer_close(writer); vpx_video_writer_close(writer);
} }
#if OUTPUT_RC_STATS
if (svc_ctx.output_rc_stat) {
for (tl = 0; tl < enc_cfg.ts_number_layers; ++tl) {
vpx_video_writer_close(outfile[tl]);
}
}
#endif
vpx_img_free(&raw); vpx_img_free(&raw);
// display average size, psnr // display average size, psnr
printf("%s", vpx_svc_dump_statistics(&svc_ctx)); printf("%s", vpx_svc_dump_statistics(&svc_ctx));
vpx_svc_release(&svc_ctx); vpx_svc_release(&svc_ctx);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

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

@ -85,13 +85,13 @@ static void set_rate_control_metrics(struct RateControlMetrics *rc,
// per-frame-bandwidth, for the rate control encoding stats below. // per-frame-bandwidth, for the rate control encoding stats below.
const double framerate = cfg->g_timebase.den / cfg->g_timebase.num; const double framerate = cfg->g_timebase.den / cfg->g_timebase.num;
rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0]; rc->layer_framerate[0] = framerate / cfg->ts_rate_decimator[0];
rc->layer_pfb[0] = 1000.0 * cfg->ts_target_bitrate[0] / rc->layer_pfb[0] = 1000.0 * cfg->layer_target_bitrate[0] /
rc->layer_framerate[0]; rc->layer_framerate[0];
for (i = 0; i < cfg->ts_number_layers; ++i) { for (i = 0; i < cfg->ts_number_layers; ++i) {
if (i > 0) { if (i > 0) {
rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i]; rc->layer_framerate[i] = framerate / cfg->ts_rate_decimator[i];
rc->layer_pfb[i] = 1000.0 * rc->layer_pfb[i] = 1000.0 *
(cfg->ts_target_bitrate[i] - cfg->ts_target_bitrate[i - 1]) / (cfg->layer_target_bitrate[i] - cfg->layer_target_bitrate[i - 1]) /
(rc->layer_framerate[i] - rc->layer_framerate[i - 1]); (rc->layer_framerate[i] - rc->layer_framerate[i - 1]);
} }
rc->layer_input_frames[i] = 0; rc->layer_input_frames[i] = 0;
@ -128,7 +128,7 @@ static void printout_rate_control_summary(struct RateControlMetrics *rc,
rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] / rc->layer_avg_rate_mismatch[i] = 100.0 * rc->layer_avg_rate_mismatch[i] /
rc->layer_enc_frames[i]; rc->layer_enc_frames[i];
printf("For layer#: %d \n", i); printf("For layer#: %d \n", i);
printf("Bitrate (target vs actual): %d %f \n", cfg->ts_target_bitrate[i], printf("Bitrate (target vs actual): %d %f \n", cfg->layer_target_bitrate[i],
rc->layer_encoding_bitrate[i]); rc->layer_encoding_bitrate[i]);
printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i], printf("Average frame size (target vs actual): %f %f \n", rc->layer_pfb[i],
rc->layer_avg_frame_size[i]); rc->layer_avg_frame_size[i]);
@ -597,7 +597,7 @@ int main(int argc, char **argv) {
for (i = min_args_base; for (i = min_args_base;
(int)i < min_args_base + mode_to_num_layers[layering_mode]; (int)i < min_args_base + mode_to_num_layers[layering_mode];
++i) { ++i) {
cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0); cfg.layer_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
} }
// Real time parameters. // Real time parameters.
@ -625,6 +625,8 @@ int main(int argc, char **argv) {
// Disable automatic keyframe placement. // Disable automatic keyframe placement.
cfg.kf_min_dist = cfg.kf_max_dist = 3000; cfg.kf_min_dist = cfg.kf_max_dist = 3000;
cfg.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
set_temporal_layer_pattern(layering_mode, set_temporal_layer_pattern(layering_mode,
&cfg, &cfg,
layer_flags, layer_flags,
@ -633,8 +635,8 @@ int main(int argc, char **argv) {
set_rate_control_metrics(&rc, &cfg); set_rate_control_metrics(&rc, &cfg);
// Target bandwidth for the whole stream. // Target bandwidth for the whole stream.
// Set to ts_target_bitrate for highest layer (total bitrate). // Set to layer_target_bitrate for highest layer (total bitrate).
cfg.rc_target_bitrate = cfg.ts_target_bitrate[cfg.ts_number_layers - 1]; cfg.rc_target_bitrate = cfg.layer_target_bitrate[cfg.ts_number_layers - 1];
// Open input file. // Open input file.
if (!(infile = fopen(argv[1], "rb"))) { if (!(infile = fopen(argv[1], "rb"))) {
@ -677,6 +679,9 @@ int main(int argc, char **argv) {
vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff); vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, kDenoiserOff);
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0); vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 0);
} else if (strncmp(encoder->name, "vp9", 3) == 0) { } else if (strncmp(encoder->name, "vp9", 3) == 0) {
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
vpx_svc_extra_cfg_t svc_params;
#endif
vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed); vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3); vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0); vpx_codec_control(&codec, VP9E_SET_FRAME_PERIODIC_BOOST, 0);
@ -685,6 +690,15 @@ int main(int argc, char **argv) {
vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1)); vpx_codec_control(&codec, VP9E_SET_TILE_COLUMNS, (cfg.g_threads >> 1));
if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) { if (vpx_codec_control(&codec, VP9E_SET_SVC, layering_mode > 0 ? 1: 0)) {
die_codec(&codec, "Failed to set SVC"); die_codec(&codec, "Failed to set SVC");
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
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;
vpx_codec_control(&codec, VP9E_SET_SVC_PARAMETERS, &svc_params);
#endif
} }
} }
if (strncmp(encoder->name, "vp8", 3) == 0) { if (strncmp(encoder->name, "vp8", 3) == 0) {

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

@ -14,6 +14,7 @@
#include "test/i420_video_source.h" #include "test/i420_video_source.h"
#include "test/util.h" #include "test/util.h"
#include "test/y4m_video_source.h" #include "test/y4m_video_source.h"
#include "vpx/vpx_codec.h"
namespace { namespace {
@ -565,6 +566,8 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
cfg_.ts_rate_decimator[0] = 2; cfg_.ts_rate_decimator[0] = 2;
cfg_.ts_rate_decimator[1] = 1; cfg_.ts_rate_decimator[1] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
if (deadline_ == VPX_DL_REALTIME) if (deadline_ == VPX_DL_REALTIME)
cfg_.g_error_resilient = 1; cfg_.g_error_resilient = 1;
@ -574,14 +577,14 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting2TemporalLayers) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
// 60-40 bitrate allocation for 2 temporal layers. // 60-40 bitrate allocation for 2 temporal layers.
cfg_.ts_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100; cfg_.layer_target_bitrate[0] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = cfg_.rc_target_bitrate; cfg_.layer_target_bitrate[1] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85) ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15) ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
} }
@ -606,25 +609,27 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayers) {
cfg_.ts_rate_decimator[1] = 2; cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1; cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200); 30, 1, 0, 200);
for (int i = 200; i <= 800; i += 200) { for (int i = 200; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i; cfg_.rc_target_bitrate = i;
ResetModel(); ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers. // 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate; cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
// TODO(yaowu): Work out more stable rc control strategy and // TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than .75. // Adjust the thresholds to be tighter than .75.
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.75) ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.75)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
// TODO(yaowu): Work out more stable rc control strategy and // TODO(yaowu): Work out more stable rc control strategy and
// Adjust the thresholds to be tighter than 1.25. // Adjust the thresholds to be tighter than 1.25.
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.25) ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.25)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
} }
@ -652,20 +657,22 @@ TEST_P(DatarateTestVP9Large, BasicRateTargeting3TemporalLayersFrameDropping) {
cfg_.ts_rate_decimator[1] = 2; cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1; cfg_.ts_rate_decimator[2] = 1;
cfg_.temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288, ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200); 30, 1, 0, 200);
cfg_.rc_target_bitrate = 200; cfg_.rc_target_bitrate = 200;
ResetModel(); ResetModel();
// 40-20-40 bitrate allocation for 3 temporal layers. // 40-20-40 bitrate allocation for 3 temporal layers.
cfg_.ts_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100; cfg_.layer_target_bitrate[0] = 40 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100; cfg_.layer_target_bitrate[1] = 60 * cfg_.rc_target_bitrate / 100;
cfg_.ts_target_bitrate[2] = cfg_.rc_target_bitrate; cfg_.layer_target_bitrate[2] = cfg_.rc_target_bitrate;
ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) { for (int j = 0; j < static_cast<int>(cfg_.ts_number_layers); ++j) {
ASSERT_GE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 0.85) ASSERT_GE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 0.85)
<< " The datarate for the file is lower than target by too much, " << " The datarate for the file is lower than target by too much, "
"for layer: " << j; "for layer: " << j;
ASSERT_LE(effective_datarate_[j], cfg_.ts_target_bitrate[j] * 1.15) ASSERT_LE(effective_datarate_[j], cfg_.layer_target_bitrate[j] * 1.15)
<< " The datarate for the file is greater than target by too much, " << " The datarate for the file is greater than target by too much, "
"for layer: " << j; "for layer: " << j;
// Expect some frame drops in this test: for this 200 frames test, // Expect some frame drops in this test: for this 200 frames test,
@ -737,9 +744,180 @@ TEST_P(DatarateTestVP9Large, DenoiserOffOn) {
} }
#endif // CONFIG_VP9_TEMPORAL_DENOISING #endif // CONFIG_VP9_TEMPORAL_DENOISING
class DatarateOnePassCbrSvc : public ::libvpx_test::EncoderTest,
public ::libvpx_test::CodecTestWith2Params<libvpx_test::TestMode, int> {
public:
DatarateOnePassCbrSvc() : EncoderTest(GET_PARAM(0)) {}
virtual ~DatarateOnePassCbrSvc() {}
protected:
virtual void SetUp() {
InitializeConfig();
SetMode(GET_PARAM(1));
speed_setting_ = GET_PARAM(2);
ResetModel();
}
virtual void ResetModel() {
last_pts_ = 0;
bits_in_buffer_model_ = cfg_.rc_target_bitrate * cfg_.rc_buf_initial_sz;
frame_number_ = 0;
first_drop_ = 0;
bits_total_ = 0;
duration_ = 0.0;
}
virtual void BeginPassHook(unsigned int /*pass*/) {
}
virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
::libvpx_test::Encoder *encoder) {
if (video->frame() == 0) {
int i;
for (i = 0; i < 2; ++i) {
svc_params_.max_quantizers[i] = 63;
svc_params_.min_quantizers[i] = 0;
}
svc_params_.scaling_factor_num[0] = 144;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
encoder->Control(VP9E_SET_SVC, 1);
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
encoder->Control(VP9E_SET_SVC_PARAMETERS, &svc_params_);
#endif
encoder->Control(VP8E_SET_CPUUSED, speed_setting_);
encoder->Control(VP9E_SET_TILE_COLUMNS, 0);
encoder->Control(VP8E_SET_MAX_INTRA_BITRATE_PCT, 300);
}
const vpx_rational_t tb = video->timebase();
timebase_ = static_cast<double>(tb.num) / tb.den;
duration_ = 0;
}
virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) {
vpx_codec_pts_t duration = pkt->data.frame.pts - last_pts_;
if (last_pts_ == 0)
duration = 1;
bits_in_buffer_model_ += static_cast<int64_t>(
duration * timebase_ * cfg_.rc_target_bitrate * 1000);
const bool key_frame = (pkt->data.frame.flags & VPX_FRAME_IS_KEY)
? true: false;
if (!key_frame) {
ASSERT_GE(bits_in_buffer_model_, 0) << "Buffer Underrun at frame "
<< pkt->data.frame.pts;
}
const size_t frame_size_in_bits = pkt->data.frame.sz * 8;
bits_in_buffer_model_ -= frame_size_in_bits;
bits_total_ += frame_size_in_bits;
if (!first_drop_ && duration > 1)
first_drop_ = last_pts_ + 1;
last_pts_ = pkt->data.frame.pts;
bits_in_last_frame_ = frame_size_in_bits;
++frame_number_;
}
virtual void EndPassHook(void) {
if (bits_total_) {
const double file_size_in_kb = bits_total_ / 1000.; // bits per kilobit
duration_ = (last_pts_ + 1) * timebase_;
effective_datarate_ = (bits_total_ - bits_in_last_frame_) / 1000.0
/ (cfg_.rc_buf_initial_sz / 1000.0 + duration_);
file_datarate_ = file_size_in_kb / duration_;
}
}
vpx_codec_pts_t last_pts_;
int64_t bits_in_buffer_model_;
double timebase_;
int frame_number_;
vpx_codec_pts_t first_drop_;
int64_t bits_total_;
double duration_;
double file_datarate_;
double effective_datarate_;
size_t bits_in_last_frame_;
vpx_svc_extra_cfg_t svc_params_;
int speed_setting_;
};
static void assign_layer_bitrates(vpx_codec_enc_cfg_t *const enc_cfg,
const vpx_svc_extra_cfg_t *svc_params,
int spatial_layers,
int temporal_layers,
int temporal_layering_mode,
unsigned int total_rate) {
int sl, spatial_layer_target;
float total = 0;
float alloc_ratio[VPX_MAX_LAYERS] = {0};
for (sl = 0; sl < spatial_layers; ++sl) {
if (svc_params->scaling_factor_den[sl] > 0) {
alloc_ratio[sl] = (float)(svc_params->scaling_factor_num[sl] *
1.0 / svc_params->scaling_factor_den[sl]);
total += alloc_ratio[sl];
}
}
for (sl = 0; sl < spatial_layers; ++sl) {
enc_cfg->ss_target_bitrate[sl] = spatial_layer_target =
(unsigned int)(enc_cfg->rc_target_bitrate *
alloc_ratio[sl] / total);
const int index = sl * temporal_layers;
if (temporal_layering_mode == 3) {
enc_cfg->layer_target_bitrate[index] =
spatial_layer_target >> 1;
enc_cfg->layer_target_bitrate[index + 1] =
(spatial_layer_target >> 1) + (spatial_layer_target >> 2);
enc_cfg->layer_target_bitrate[index + 2] =
spatial_layer_target;
} else if (temporal_layering_mode == 2) {
enc_cfg->layer_target_bitrate[index] =
spatial_layer_target * 2 / 3;
enc_cfg->layer_target_bitrate[index + 1] =
spatial_layer_target;
}
}
}
#if VPX_ENCODER_ABI_VERSION > (4 + VPX_CODEC_ABI_VERSION)
// Check basic rate targeting for 1 pass CBR SVC: 2 spatial layers and
// 3 temporal layers.
TEST_P(DatarateOnePassCbrSvc, OnePassCbrSvc) {
cfg_.rc_buf_initial_sz = 500;
cfg_.rc_buf_optimal_sz = 500;
cfg_.rc_buf_sz = 1000;
cfg_.rc_min_quantizer = 0;
cfg_.rc_max_quantizer = 63;
cfg_.rc_end_usage = VPX_CBR;
cfg_.g_lag_in_frames = 0;
cfg_.ss_number_layers = 2;
cfg_.ts_number_layers = 3;
cfg_.ts_rate_decimator[0] = 4;
cfg_.ts_rate_decimator[1] = 2;
cfg_.ts_rate_decimator[2] = 1;
cfg_.g_error_resilient = 1;
cfg_.temporal_layering_mode = 3;
svc_params_.scaling_factor_num[0] = 144;
svc_params_.scaling_factor_den[0] = 288;
svc_params_.scaling_factor_num[1] = 288;
svc_params_.scaling_factor_den[1] = 288;
// TODO(wonkap/marpan): No frame drop for now, we need to implement correct
// frame dropping for SVC.
cfg_.rc_dropframe_thresh = 0;
::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
30, 1, 0, 200);
// TODO(wonkap/marpan): Check that effective_datarate for each layer hits the
// layer target_bitrate. Also check if test can pass at lower bitrate (~200k).
for (int i = 400; i <= 800; i += 200) {
cfg_.rc_target_bitrate = i;
ResetModel();
assign_layer_bitrates(&cfg_, &svc_params_, cfg_.ss_number_layers,
cfg_.ts_number_layers, cfg_.temporal_layering_mode,
cfg_.rc_target_bitrate);
ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
ASSERT_GE(cfg_.rc_target_bitrate, effective_datarate_ * 0.85)
<< " The datarate for the file exceeds the target by too much!";
ASSERT_LE(cfg_.rc_target_bitrate, file_datarate_ * 1.15)
<< " The datarate for the file is lower than the target by too much!";
}
}
#endif
VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES); VP8_INSTANTIATE_TEST_CASE(DatarateTestLarge, ALL_TEST_MODES);
VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large, VP9_INSTANTIATE_TEST_CASE(DatarateTestVP9Large,
::testing::Values(::libvpx_test::kOnePassGood, ::testing::Values(::libvpx_test::kOnePassGood,
::libvpx_test::kRealTime), ::libvpx_test::kRealTime),
::testing::Range(2, 7)); ::testing::Range(2, 7));
VP9_INSTANTIATE_TEST_CASE(DatarateOnePassCbrSvc,
::testing::Values(::libvpx_test::kRealTime),
::testing::Range(5, 8));
} // namespace } // namespace

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

@ -133,6 +133,10 @@ class Encoder {
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError(); ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
} }
void Control(int ctrl_id, struct vpx_svc_parameters *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);
ASSERT_EQ(VPX_CODEC_OK, res) << EncoderError();
}
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER
void Control(int ctrl_id, vpx_active_map_t *arg) { void Control(int ctrl_id, vpx_active_map_t *arg) {
const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg); const vpx_codec_err_t res = vpx_codec_control_(&encoder_, ctrl_id, arg);

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

@ -453,6 +453,7 @@ TEST_F(SvcTest, OnePassEncodeOneFrame) {
TEST_F(SvcTest, OnePassEncodeThreeFrames) { TEST_F(SvcTest, OnePassEncodeThreeFrames) {
codec_enc_.g_pass = VPX_RC_ONE_PASS; codec_enc_.g_pass = VPX_RC_ONE_PASS;
codec_enc_.g_lag_in_frames = 0;
vpx_fixed_buf outputs[3]; vpx_fixed_buf outputs[3];
memset(&outputs[0], 0, sizeof(outputs)); memset(&outputs[0], 0, sizeof(outputs));
Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]); Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]);

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

@ -687,17 +687,28 @@ static int choose_partitioning(VP9_COMP *cpi,
s = x->plane[0].src.buf; s = x->plane[0].src.buf;
sp = x->plane[0].src.stride; sp = x->plane[0].src.stride;
if (!is_key_frame) { if (!is_key_frame && !(is_one_pass_cbr_svc(cpi) &&
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) {
// In the case of spatial/temporal scalable coding, the assumption here is
// that the temporal reference frame will always be of type LAST_FRAME.
// TODO(marpan): If that assumption is broken, we need to revisit this code.
MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi;
unsigned int uv_sad; unsigned int uv_sad;
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME); const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
const YV12_BUFFER_CONFIG *yv12_g = get_ref_frame_buffer(cpi, GOLDEN_FRAME); const YV12_BUFFER_CONFIG *yv12_g = NULL;
unsigned int y_sad, y_sad_g; unsigned int y_sad, y_sad_g;
const BLOCK_SIZE bsize = BLOCK_32X32 const BLOCK_SIZE bsize = BLOCK_32X32
+ (mi_col + 4 < cm->mi_cols) * 2 + (mi_row + 4 < cm->mi_rows); + (mi_col + 4 < cm->mi_cols) * 2 + (mi_row + 4 < cm->mi_rows);
assert(yv12 != NULL); assert(yv12 != NULL);
if (!(is_one_pass_cbr_svc(cpi) && cpi->svc.spatial_layer_id)) {
// For now, GOLDEN will not be used for non-zero spatial layers, since
// it may not be a temporal reference.
yv12_g = get_ref_frame_buffer(cpi, GOLDEN_FRAME);
}
if (yv12_g && yv12_g != yv12) { if (yv12_g && yv12_g != yv12) {
vp9_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col, vp9_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col,
&cm->frame_refs[GOLDEN_FRAME - 1].sf); &cm->frame_refs[GOLDEN_FRAME - 1].sf);

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

@ -756,6 +756,8 @@ static void init_config(struct VP9_COMP *cpi, VP9EncoderConfig *oxcf) {
cm->height = oxcf->height; cm->height = oxcf->height;
vp9_alloc_compressor_data(cpi); vp9_alloc_compressor_data(cpi);
cpi->svc.temporal_layering_mode = oxcf->temporal_layering_mode;
// Single thread case: use counts in common. // Single thread case: use counts in common.
cpi->td.counts = &cm->counts; cpi->td.counts = &cm->counts;
@ -2265,8 +2267,9 @@ static void generate_psnr_packet(VP9_COMP *cpi) {
pkt.data.psnr.psnr[i] = psnr.psnr[i]; pkt.data.psnr.psnr[i] = psnr.psnr[i];
} }
pkt.kind = VPX_CODEC_PSNR_PKT; pkt.kind = VPX_CODEC_PSNR_PKT;
if (is_two_pass_svc(cpi)) if (cpi->use_svc)
cpi->svc.layer_context[cpi->svc.spatial_layer_id].psnr_pkt = pkt.data.psnr; cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].psnr_pkt = pkt.data.psnr;
else else
vpx_codec_pkt_list_add(cpi->output_pkt_list, &pkt); vpx_codec_pkt_list_add(cpi->output_pkt_list, &pkt);
} }
@ -3667,9 +3670,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
} }
cm->prev_frame = cm->cur_frame; cm->prev_frame = cm->cur_frame;
if (is_two_pass_svc(cpi)) if (cpi->use_svc)
cpi->svc.layer_context[cpi->svc.spatial_layer_id].last_frame_type = cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cm->frame_type; cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id].last_frame_type =
cm->frame_type;
} }
static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest, static void SvcEncode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
@ -3930,6 +3935,8 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
#endif #endif
if (oxcf->pass == 2) if (oxcf->pass == 2)
vp9_restore_layer_context(cpi); vp9_restore_layer_context(cpi);
} else if (is_one_pass_cbr_svc(cpi)) {
vp9_one_pass_cbr_svc_start_layer(cpi);
} }
vpx_usec_timer_start(&cmptimer); vpx_usec_timer_start(&cmptimer);
@ -3948,9 +3955,11 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
// Normal defaults // Normal defaults
cm->reset_frame_context = 0; cm->reset_frame_context = 0;
cm->refresh_frame_context = 1; cm->refresh_frame_context = 1;
cpi->refresh_last_frame = 1; if (!is_one_pass_cbr_svc(cpi)) {
cpi->refresh_golden_frame = 0; cpi->refresh_last_frame = 1;
cpi->refresh_alt_ref_frame = 0; cpi->refresh_golden_frame = 0;
cpi->refresh_alt_ref_frame = 0;
}
// Should we encode an arf frame. // Should we encode an arf frame.
arf_src_index = get_arf_src_index(cpi); arf_src_index = get_arf_src_index(cpi);
@ -4006,12 +4015,11 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
} }
// Read in the source frame. // Read in the source frame.
#if CONFIG_SPATIAL_SVC if (cpi->use_svc)
if (is_two_pass_svc(cpi))
source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush); source = vp9_svc_lookahead_pop(cpi, cpi->lookahead, flush);
else else
#endif
source = vp9_lookahead_pop(cpi->lookahead, flush); source = vp9_lookahead_pop(cpi->lookahead, flush);
if (source != NULL) { if (source != NULL) {
cm->show_frame = 1; cm->show_frame = 1;
cm->intra_only = 0; cm->intra_only = 0;
@ -4060,8 +4068,7 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
adjust_frame_rate(cpi, source); adjust_frame_rate(cpi, source);
} }
if (cpi->svc.number_temporal_layers > 1 && if (is_one_pass_cbr_svc(cpi)) {
oxcf->rc_mode == VPX_CBR) {
vp9_update_temporal_layer_framerate(cpi); vp9_update_temporal_layer_framerate(cpi);
vp9_restore_layer_context(cpi); vp9_restore_layer_context(cpi);
} }
@ -4143,11 +4150,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
} }
// Save layer specific state. // Save layer specific state.
if ((cpi->svc.number_temporal_layers > 1 && if (is_one_pass_cbr_svc(cpi) ||
oxcf->rc_mode == VPX_CBR) || ((cpi->svc.number_temporal_layers > 1 ||
((cpi->svc.number_temporal_layers > 1 || cpi->svc.number_spatial_layers > 1) &&
cpi->svc.number_spatial_layers > 1) && oxcf->pass == 2)) {
oxcf->pass == 2)) {
vp9_save_layer_context(cpi); vp9_save_layer_context(cpi);
} }
@ -4343,6 +4349,12 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
// May need the empty frame after an visible frame. // May need the empty frame after an visible frame.
cpi->svc.encode_empty_frame_state = NEED_TO_ENCODE; cpi->svc.encode_empty_frame_state = NEED_TO_ENCODE;
} }
} else if (is_one_pass_cbr_svc(cpi)) {
if (cm->show_frame) {
++cpi->svc.spatial_layer_to_encode;
if (cpi->svc.spatial_layer_to_encode >= cpi->svc.number_spatial_layers)
cpi->svc.spatial_layer_to_encode = 0;
}
} }
return 0; return 0;
} }

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

@ -194,10 +194,10 @@ typedef struct VP9EncoderConfig {
int ss_number_layers; // Number of spatial layers. int ss_number_layers; // Number of spatial layers.
int ts_number_layers; // Number of temporal layers. int ts_number_layers; // Number of temporal layers.
// Bitrate allocation for spatial layers. // Bitrate allocation for spatial layers.
int layer_target_bitrate[VPX_MAX_LAYERS];
int ss_target_bitrate[VPX_SS_MAX_LAYERS]; int ss_target_bitrate[VPX_SS_MAX_LAYERS];
int ss_enable_auto_arf[VPX_SS_MAX_LAYERS]; int ss_enable_auto_arf[VPX_SS_MAX_LAYERS];
// Bitrate allocation (CBR mode) and framerate factor, for temporal layers. // Bitrate allocation (CBR mode) and framerate factor, for temporal layers.
int ts_target_bitrate[VPX_TS_MAX_LAYERS];
int ts_rate_decimator[VPX_TS_MAX_LAYERS]; int ts_rate_decimator[VPX_TS_MAX_LAYERS];
int enable_auto_arf; int enable_auto_arf;
@ -237,6 +237,7 @@ typedef struct VP9EncoderConfig {
int use_highbitdepth; int use_highbitdepth;
#endif #endif
vpx_color_space_t color_space; vpx_color_space_t color_space;
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
} VP9EncoderConfig; } VP9EncoderConfig;
static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) { static INLINE int is_lossless_requested(const VP9EncoderConfig *cfg) {
@ -611,9 +612,11 @@ YV12_BUFFER_CONFIG *vp9_scale_if_required(VP9_COMMON *cm,
void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags); void vp9_apply_encoding_flags(VP9_COMP *cpi, vpx_enc_frame_flags_t flags);
static INLINE int is_two_pass_svc(const struct VP9_COMP *const cpi) { static INLINE int is_two_pass_svc(const struct VP9_COMP *const cpi) {
return cpi->use_svc && return cpi->use_svc && cpi->oxcf.pass != 0;
((cpi->svc.number_spatial_layers > 1) || }
(cpi->svc.number_temporal_layers > 1 && cpi->oxcf.pass != 0));
static INLINE int is_one_pass_cbr_svc(const struct VP9_COMP *const cpi) {
return (cpi->use_svc && cpi->oxcf.pass == 0);
} }
static INLINE int is_altref_enabled(const VP9_COMP *const cpi) { static INLINE int is_altref_enabled(const VP9_COMP *const cpi) {
@ -642,6 +645,8 @@ static INLINE int *cond_cost_list(const struct VP9_COMP *cpi, int *cost_list) {
void vp9_new_framerate(VP9_COMP *cpi, double framerate); void vp9_new_framerate(VP9_COMP *cpi, double framerate);
#define LAYER_IDS_TO_IDX(sl, tl, num_tl) ((sl) * (num_tl) + (tl))
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

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

@ -234,13 +234,16 @@ int vp9_rc_clamp_iframe_target_size(const VP9_COMP *const cpi, int target) {
return target; return target;
} }
// Update the buffer level for higher layers, given the encoded current layer. // Update the buffer level for higher temporal layers, given the encoded current
// temporal layer.
static void update_layer_buffer_level(SVC *svc, int encoded_frame_size) { static void update_layer_buffer_level(SVC *svc, int encoded_frame_size) {
int temporal_layer = 0; int i = 0;
int current_temporal_layer = svc->temporal_layer_id; int current_temporal_layer = svc->temporal_layer_id;
for (temporal_layer = current_temporal_layer + 1; for (i = current_temporal_layer + 1;
temporal_layer < svc->number_temporal_layers; ++temporal_layer) { i < svc->number_temporal_layers; ++i) {
LAYER_CONTEXT *lc = &svc->layer_context[temporal_layer]; const int layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id, i,
svc->number_temporal_layers);
LAYER_CONTEXT *lc = &svc->layer_context[layer];
RATE_CONTROL *lrc = &lc->rc; RATE_CONTROL *lrc = &lc->rc;
int bits_off_for_this_layer = (int)(lc->target_bandwidth / lc->framerate - int bits_off_for_this_layer = (int)(lc->target_bandwidth / lc->framerate -
encoded_frame_size); encoded_frame_size);
@ -268,7 +271,7 @@ static void update_buffer_level(VP9_COMP *cpi, int encoded_frame_size) {
rc->bits_off_target = MIN(rc->bits_off_target, rc->maximum_buffer_size); rc->bits_off_target = MIN(rc->bits_off_target, rc->maximum_buffer_size);
rc->buffer_level = rc->bits_off_target; rc->buffer_level = rc->bits_off_target;
if (cpi->use_svc && cpi->oxcf.rc_mode == VPX_CBR) { if (is_one_pass_cbr_svc(cpi)) {
update_layer_buffer_level(&cpi->svc, encoded_frame_size); update_layer_buffer_level(&cpi->svc, encoded_frame_size);
} }
} }
@ -1418,13 +1421,14 @@ static int calc_pframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
} else { } else {
target = rc->avg_frame_bandwidth; target = rc->avg_frame_bandwidth;
} }
if (svc->number_temporal_layers > 1 && if (is_one_pass_cbr_svc(cpi)) {
oxcf->rc_mode == VPX_CBR) {
// Note that for layers, avg_frame_bandwidth is the cumulative // Note that for layers, avg_frame_bandwidth is the cumulative
// per-frame-bandwidth. For the target size of this frame, use the // per-frame-bandwidth. For the target size of this frame, use the
// layer average frame size (i.e., non-cumulative per-frame-bw). // layer average frame size (i.e., non-cumulative per-frame-bw).
int current_temporal_layer = svc->temporal_layer_id; int layer =
const LAYER_CONTEXT *lc = &svc->layer_context[current_temporal_layer]; LAYER_IDS_TO_IDX(svc->spatial_layer_id,
svc->temporal_layer_id, svc->number_temporal_layers);
const LAYER_CONTEXT *lc = &svc->layer_context[layer];
target = lc->avg_frame_size; target = lc->avg_frame_size;
min_frame_target = MAX(lc->avg_frame_size >> 4, FRAME_OVERHEAD_BITS); min_frame_target = MAX(lc->avg_frame_size >> 4, FRAME_OVERHEAD_BITS);
} }
@ -1459,7 +1463,9 @@ static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
if (svc->number_temporal_layers > 1 && if (svc->number_temporal_layers > 1 &&
oxcf->rc_mode == VPX_CBR) { oxcf->rc_mode == VPX_CBR) {
// Use the layer framerate for temporal layers CBR mode. // Use the layer framerate for temporal layers CBR mode.
const LAYER_CONTEXT *lc = &svc->layer_context[svc->temporal_layer_id]; const int layer = LAYER_IDS_TO_IDX(svc->spatial_layer_id,
svc->temporal_layer_id, svc->number_temporal_layers);
const LAYER_CONTEXT *lc = &svc->layer_context[layer];
framerate = lc->framerate; framerate = lc->framerate;
} }
kf_boost = MAX(kf_boost, (int)(2 * framerate - 16)); kf_boost = MAX(kf_boost, (int)(2 * framerate - 16));
@ -1472,10 +1478,27 @@ static int calc_iframe_target_size_one_pass_cbr(const VP9_COMP *cpi) {
return vp9_rc_clamp_iframe_target_size(cpi, target); return vp9_rc_clamp_iframe_target_size(cpi, target);
} }
// Reset information needed to set proper reference frames and buffer updates
// for temporal layering. This is called when a key frame is encoded.
static void reset_temporal_layer_to_zero(VP9_COMP *cpi) {
int sl;
LAYER_CONTEXT *lc = NULL;
cpi->svc.temporal_layer_id = 0;
for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
lc = &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers];
lc->current_video_frame_in_layer = 0;
lc->frames_from_key_frame = 0;
}
}
void vp9_rc_get_svc_params(VP9_COMP *cpi) { void vp9_rc_get_svc_params(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common; VP9_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc; RATE_CONTROL *const rc = &cpi->rc;
int target = rc->avg_frame_bandwidth; int target = rc->avg_frame_bandwidth;
const int layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id,
cpi->svc.temporal_layer_id, cpi->svc.number_temporal_layers);
if ((cm->current_video_frame == 0) || if ((cm->current_video_frame == 0) ||
(cpi->frame_flags & FRAMEFLAGS_KEY) || (cpi->frame_flags & FRAMEFLAGS_KEY) ||
(cpi->oxcf.auto_key && (rc->frames_since_key % (cpi->oxcf.auto_key && (rc->frames_since_key %
@ -1484,30 +1507,39 @@ void vp9_rc_get_svc_params(VP9_COMP *cpi) {
rc->source_alt_ref_active = 0; rc->source_alt_ref_active = 0;
if (is_two_pass_svc(cpi)) { if (is_two_pass_svc(cpi)) {
cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame = 1; cpi->svc.layer_context[layer].is_key_frame = 1;
cpi->ref_frame_flags &= cpi->ref_frame_flags &=
(~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG); (~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG);
} } else if (is_one_pass_cbr_svc(cpi)) {
cpi->svc.layer_context[layer].is_key_frame = 1;
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { reset_temporal_layer_to_zero(cpi);
cpi->ref_frame_flags &=
(~VP9_LAST_FLAG & ~VP9_GOLD_FLAG & ~VP9_ALT_FLAG);
// Assumption here is that LAST_FRAME is being updated for a keyframe.
// Thus no change in update flags.
target = calc_iframe_target_size_one_pass_cbr(cpi); target = calc_iframe_target_size_one_pass_cbr(cpi);
} }
} else { } else {
cm->frame_type = INTER_FRAME; cm->frame_type = INTER_FRAME;
if (is_two_pass_svc(cpi)) { if (is_two_pass_svc(cpi)) {
LAYER_CONTEXT *lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id]; LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
if (cpi->svc.spatial_layer_id == 0) { if (cpi->svc.spatial_layer_id == 0) {
lc->is_key_frame = 0; lc->is_key_frame = 0;
} else { } else {
lc->is_key_frame = cpi->svc.layer_context[0].is_key_frame; lc->is_key_frame =
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame;
if (lc->is_key_frame) if (lc->is_key_frame)
cpi->ref_frame_flags &= (~VP9_LAST_FLAG); cpi->ref_frame_flags &= (~VP9_LAST_FLAG);
} }
cpi->ref_frame_flags &= (~VP9_ALT_FLAG); cpi->ref_frame_flags &= (~VP9_ALT_FLAG);
} } else if (is_one_pass_cbr_svc(cpi)) {
LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer];
if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR) { if (cpi->svc.spatial_layer_id == 0) {
lc->is_key_frame = 0;
} else {
lc->is_key_frame =
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame;
}
target = calc_pframe_target_size_one_pass_cbr(cpi); target = calc_pframe_target_size_one_pass_cbr(cpi);
} }
} }

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

@ -21,83 +21,79 @@
void vp9_init_layer_context(VP9_COMP *const cpi) { void vp9_init_layer_context(VP9_COMP *const cpi) {
SVC *const svc = &cpi->svc; SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf; const VP9EncoderConfig *const oxcf = &cpi->oxcf;
int layer; int sl, tl;
int layer_end;
int alt_ref_idx = svc->number_spatial_layers; int alt_ref_idx = svc->number_spatial_layers;
svc->spatial_layer_id = 0; svc->spatial_layer_id = 0;
svc->temporal_layer_id = 0; svc->temporal_layer_id = 0;
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) {
layer_end = svc->number_temporal_layers; if (vp9_realloc_frame_buffer(&cpi->svc.empty_frame.img,
} else { SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT,
layer_end = svc->number_spatial_layers; cpi->common.subsampling_x,
cpi->common.subsampling_y,
if (cpi->oxcf.error_resilient_mode == 0 && cpi->oxcf.pass == 2) {
if (vp9_realloc_frame_buffer(&cpi->svc.empty_frame.img,
SMALL_FRAME_WIDTH, SMALL_FRAME_HEIGHT,
cpi->common.subsampling_x,
cpi->common.subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
cpi->common.use_highbitdepth, cpi->common.use_highbitdepth,
#endif #endif
VP9_ENC_BORDER_IN_PIXELS, VP9_ENC_BORDER_IN_PIXELS,
cpi->common.byte_alignment, cpi->common.byte_alignment,
NULL, NULL, NULL)) NULL, NULL, NULL))
vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR,
"Failed to allocate empty frame for multiple frame " "Failed to allocate empty frame for multiple frame "
"contexts"); "contexts");
memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80, memset(cpi->svc.empty_frame.img.buffer_alloc, 0x80,
cpi->svc.empty_frame.img.buffer_alloc_sz); cpi->svc.empty_frame.img.buffer_alloc_sz);
}
} }
for (layer = 0; layer < layer_end; ++layer) { for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
LAYER_CONTEXT *const lc = &svc->layer_context[layer]; for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
RATE_CONTROL *const lrc = &lc->rc; int layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
int i; LAYER_CONTEXT *const lc = &svc->layer_context[layer];
lc->current_video_frame_in_layer = 0; RATE_CONTROL *const lrc = &lc->rc;
lc->layer_size = 0; int i;
lc->frames_from_key_frame = 0; lc->current_video_frame_in_layer = 0;
lc->last_frame_type = FRAME_TYPES; lc->layer_size = 0;
lrc->ni_av_qi = oxcf->worst_allowed_q; lc->frames_from_key_frame = 0;
lrc->total_actual_bits = 0; lc->last_frame_type = FRAME_TYPES;
lrc->total_target_vs_actual = 0; lrc->ni_av_qi = oxcf->worst_allowed_q;
lrc->ni_tot_qi = 0; lrc->total_actual_bits = 0;
lrc->tot_q = 0.0; lrc->total_target_vs_actual = 0;
lrc->avg_q = 0.0; lrc->ni_tot_qi = 0;
lrc->ni_frames = 0; lrc->tot_q = 0.0;
lrc->decimation_count = 0; lrc->avg_q = 0.0;
lrc->decimation_factor = 0; lrc->ni_frames = 0;
lrc->decimation_count = 0;
lrc->decimation_factor = 0;
for (i = 0; i < RATE_FACTOR_LEVELS; ++i) { for (i = 0; i < RATE_FACTOR_LEVELS; ++i) {
lrc->rate_correction_factors[i] = 1.0; lrc->rate_correction_factors[i] = 1.0;
} }
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { if (cpi->oxcf.rc_mode == VPX_CBR) {
lc->target_bandwidth = oxcf->ts_target_bitrate[layer]; lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q; lrc->last_q[INTER_FRAME] = oxcf->worst_allowed_q;
lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[INTER_FRAME] = oxcf->worst_allowed_q;
lrc->avg_frame_qindex[KEY_FRAME] = oxcf->worst_allowed_q; lrc->avg_frame_qindex[KEY_FRAME] = oxcf->worst_allowed_q;
} else { } else {
lc->target_bandwidth = oxcf->ss_target_bitrate[layer]; lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q; lrc->last_q[KEY_FRAME] = oxcf->best_allowed_q;
lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q; lrc->last_q[INTER_FRAME] = oxcf->best_allowed_q;
lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q + lrc->avg_frame_qindex[KEY_FRAME] = (oxcf->worst_allowed_q +
oxcf->best_allowed_q) / 2;
lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q +
oxcf->best_allowed_q) / 2; oxcf->best_allowed_q) / 2;
if (oxcf->ss_enable_auto_arf[layer]) lrc->avg_frame_qindex[INTER_FRAME] = (oxcf->worst_allowed_q +
lc->alt_ref_idx = alt_ref_idx++; oxcf->best_allowed_q) / 2;
else if (oxcf->ss_enable_auto_arf[sl])
lc->alt_ref_idx = INVALID_IDX; lc->alt_ref_idx = alt_ref_idx++;
lc->gold_ref_idx = INVALID_IDX; else
} lc->alt_ref_idx = INVALID_IDX;
lc->gold_ref_idx = INVALID_IDX;
}
lrc->buffer_level = oxcf->starting_buffer_level_ms * lrc->buffer_level = oxcf->starting_buffer_level_ms *
lc->target_bandwidth / 1000; lc->target_bandwidth / 1000;
lrc->bits_off_target = lrc->buffer_level; lrc->bits_off_target = lrc->buffer_level;
}
} }
// Still have extra buffer for base layer golden frame // Still have extra buffer for base layer golden frame
@ -112,53 +108,100 @@ void vp9_update_layer_context_change_config(VP9_COMP *const cpi,
SVC *const svc = &cpi->svc; SVC *const svc = &cpi->svc;
const VP9EncoderConfig *const oxcf = &cpi->oxcf; const VP9EncoderConfig *const oxcf = &cpi->oxcf;
const RATE_CONTROL *const rc = &cpi->rc; const RATE_CONTROL *const rc = &cpi->rc;
int layer; int sl, tl, layer = 0, spatial_layer_target;
int layer_end;
float bitrate_alloc = 1.0; float bitrate_alloc = 1.0;
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { if (svc->temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) {
layer_end = svc->number_temporal_layers; for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
spatial_layer_target = 0;
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
svc->layer_context[layer].target_bandwidth =
oxcf->layer_target_bitrate[layer];
}
layer = LAYER_IDS_TO_IDX(sl, ((oxcf->ts_number_layers - 1) < 0 ?
0 : (oxcf->ts_number_layers - 1)), oxcf->ts_number_layers);
spatial_layer_target =
svc->layer_context[layer].target_bandwidth =
oxcf->layer_target_bitrate[layer];
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
LAYER_CONTEXT *const lc =
&svc->layer_context[sl * oxcf->ts_number_layers + tl];
RATE_CONTROL *const lrc = &lc->rc;
layer = LAYER_IDS_TO_IDX(sl, tl, oxcf->ts_number_layers);
lc->spatial_layer_target_bandwidth = spatial_layer_target;
bitrate_alloc = (float)lc->target_bandwidth / spatial_layer_target;
lrc->starting_buffer_level =
(int64_t)(rc->starting_buffer_level * bitrate_alloc);
lrc->optimal_buffer_level =
(int64_t)(rc->optimal_buffer_level * bitrate_alloc);
lrc->maximum_buffer_size =
(int64_t)(rc->maximum_buffer_size * bitrate_alloc);
lrc->bits_off_target =
MIN(lrc->bits_off_target, lrc->maximum_buffer_size);
lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size);
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer];
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
}
}
} else { } else {
layer_end = svc->number_spatial_layers; int layer_end;
} float bitrate_alloc = 1.0;
for (layer = 0; layer < layer_end; ++layer) {
LAYER_CONTEXT *const lc = &svc->layer_context[layer];
RATE_CONTROL *const lrc = &lc->rc;
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) {
lc->target_bandwidth = oxcf->ts_target_bitrate[layer]; layer_end = svc->number_temporal_layers;
} else { } else {
lc->target_bandwidth = oxcf->ss_target_bitrate[layer]; layer_end = svc->number_spatial_layers;
} }
bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
// Update buffer-related quantities. for (layer = 0; layer < layer_end; ++layer) {
lrc->starting_buffer_level = LAYER_CONTEXT *const lc = &svc->layer_context[layer];
(int64_t)(rc->starting_buffer_level * bitrate_alloc); RATE_CONTROL *const lrc = &lc->rc;
lrc->optimal_buffer_level =
(int64_t)(rc->optimal_buffer_level * bitrate_alloc); lc->target_bandwidth = oxcf->layer_target_bitrate[layer];
lrc->maximum_buffer_size =
(int64_t)(rc->maximum_buffer_size * bitrate_alloc); bitrate_alloc = (float)lc->target_bandwidth / target_bandwidth;
lrc->bits_off_target = MIN(lrc->bits_off_target, lrc->maximum_buffer_size); // Update buffer-related quantities.
lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size); lrc->starting_buffer_level =
// Update framerate-related quantities. (int64_t)(rc->starting_buffer_level * bitrate_alloc);
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) { lrc->optimal_buffer_level =
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer]; (int64_t)(rc->optimal_buffer_level * bitrate_alloc);
} else { lrc->maximum_buffer_size =
lc->framerate = cpi->framerate; (int64_t)(rc->maximum_buffer_size * bitrate_alloc);
lrc->bits_off_target = MIN(lrc->bits_off_target,
lrc->maximum_buffer_size);
lrc->buffer_level = MIN(lrc->buffer_level, lrc->maximum_buffer_size);
// Update framerate-related quantities.
if (svc->number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) {
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer];
} else {
lc->framerate = cpi->framerate;
}
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
// Update qp-related quantities.
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
} }
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = rc->max_frame_bandwidth;
// Update qp-related quantities.
lrc->worst_quality = rc->worst_quality;
lrc->best_quality = rc->best_quality;
} }
} }
static LAYER_CONTEXT *get_layer_context(VP9_COMP *const cpi) { static LAYER_CONTEXT *get_layer_context(VP9_COMP *const cpi) {
return (cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) ? if (is_one_pass_cbr_svc(cpi))
&cpi->svc.layer_context[cpi->svc.temporal_layer_id] : return &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
&cpi->svc.layer_context[cpi->svc.spatial_layer_id]; cpi->svc.number_temporal_layers + cpi->svc.temporal_layer_id];
else
return (cpi->svc.number_temporal_layers > 1 &&
cpi->oxcf.rc_mode == VPX_CBR) ?
&cpi->svc.layer_context[cpi->svc.temporal_layer_id] :
&cpi->svc.layer_context[cpi->svc.spatial_layer_id];
} }
void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) { void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
@ -166,18 +209,22 @@ void vp9_update_temporal_layer_framerate(VP9_COMP *const cpi) {
const VP9EncoderConfig *const oxcf = &cpi->oxcf; const VP9EncoderConfig *const oxcf = &cpi->oxcf;
LAYER_CONTEXT *const lc = get_layer_context(cpi); LAYER_CONTEXT *const lc = get_layer_context(cpi);
RATE_CONTROL *const lrc = &lc->rc; RATE_CONTROL *const lrc = &lc->rc;
const int layer = svc->temporal_layer_id; // Index into spatial+temporal arrays.
const int st_idx = svc->spatial_layer_id * svc->number_temporal_layers +
svc->temporal_layer_id;
const int tl = svc->temporal_layer_id;
lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[layer]; lc->framerate = cpi->framerate / oxcf->ts_rate_decimator[tl];
lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate); lrc->avg_frame_bandwidth = (int)(lc->target_bandwidth / lc->framerate);
lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth; lrc->max_frame_bandwidth = cpi->rc.max_frame_bandwidth;
// Update the average layer frame size (non-cumulative per-frame-bw). // Update the average layer frame size (non-cumulative per-frame-bw).
if (layer == 0) { if (tl == 0) {
lc->avg_frame_size = lrc->avg_frame_bandwidth; lc->avg_frame_size = lrc->avg_frame_bandwidth;
} else { } else {
const double prev_layer_framerate = const double prev_layer_framerate =
cpi->framerate / oxcf->ts_rate_decimator[layer - 1]; cpi->framerate / oxcf->ts_rate_decimator[tl - 1];
const int prev_layer_target_bandwidth = oxcf->ts_target_bitrate[layer - 1]; const int prev_layer_target_bandwidth =
oxcf->layer_target_bitrate[st_idx - 1];
lc->avg_frame_size = lc->avg_frame_size =
(int)((lc->target_bandwidth - prev_layer_target_bandwidth) / (int)((lc->target_bandwidth - prev_layer_target_bandwidth) /
(lc->framerate - prev_layer_framerate)); (lc->framerate - prev_layer_framerate));
@ -243,9 +290,8 @@ void vp9_init_second_pass_spatial_svc(VP9_COMP *cpi) {
void vp9_inc_frame_in_layer(VP9_COMP *const cpi) { void vp9_inc_frame_in_layer(VP9_COMP *const cpi) {
LAYER_CONTEXT *const lc = LAYER_CONTEXT *const lc =
(cpi->svc.number_temporal_layers > 1 && cpi->oxcf.rc_mode == VPX_CBR) ? &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
&cpi->svc.layer_context[cpi->svc.temporal_layer_id] : cpi->svc.number_temporal_layers];
&cpi->svc.layer_context[cpi->svc.spatial_layer_id];
++lc->current_video_frame_in_layer; ++lc->current_video_frame_in_layer;
++lc->frames_from_key_frame; ++lc->frames_from_key_frame;
} }
@ -253,10 +299,11 @@ void vp9_inc_frame_in_layer(VP9_COMP *const cpi) {
int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) { int vp9_is_upper_layer_key_frame(const VP9_COMP *const cpi) {
return is_two_pass_svc(cpi) && return is_two_pass_svc(cpi) &&
cpi->svc.spatial_layer_id > 0 && cpi->svc.spatial_layer_id > 0 &&
cpi->svc.layer_context[cpi->svc.spatial_layer_id].is_key_frame; cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id].is_key_frame;
} }
#if CONFIG_SPATIAL_SVC
static void get_layer_resolution(const int width_org, const int height_org, static void get_layer_resolution(const int width_org, const int height_org,
const int num, const int den, const int num, const int den,
int *width_out, int *height_out) { int *width_out, int *height_out) {
@ -276,6 +323,201 @@ static void get_layer_resolution(const int width_org, const int height_org,
*height_out = h; *height_out = h;
} }
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 3 - that does 0-2-1-2 temporal layering
// scheme.
static void set_flags_and_fb_idx_for_temporal_mode3(VP9_COMP *const cpi) {
int frame_num_within_temporal_struct = 0;
int spatial_id, temporal_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
frame_num_within_temporal_struct =
cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].current_video_frame_in_layer % 4;
temporal_id = cpi->svc.temporal_layer_id =
(frame_num_within_temporal_struct & 1) ? 2 :
(frame_num_within_temporal_struct >> 1);
cpi->ext_refresh_last_frame = cpi->ext_refresh_golden_frame =
cpi->ext_refresh_alt_ref_frame = 0;
if (!temporal_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else if (temporal_id == 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
if (frame_num_within_temporal_struct == 1) {
// the first tl2 picture
if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (spatial_id < cpi->svc.number_spatial_layers - 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
} else { // Top layer
cpi->ext_refresh_frame_flags_pending = 0;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else {
// The second tl2 picture
if (!spatial_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG;
cpi->ext_refresh_last_frame = 1;
} else if (spatial_id < cpi->svc.number_spatial_layers - 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
cpi->ext_refresh_last_frame = 1;
} else { // top layer
cpi->ext_refresh_frame_flags_pending = 0;
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
}
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
} else if (frame_num_within_temporal_struct == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
} else {
cpi->lst_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = 0;
}
}
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 2 - that does 0-1-0-1 temporal layering
// scheme.
static void set_flags_and_fb_idx_for_temporal_mode2(VP9_COMP *const cpi) {
int spatial_id, temporal_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
temporal_id = cpi->svc.temporal_layer_id =
cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].current_video_frame_in_layer & 1;
cpi->ext_refresh_last_frame = cpi->ext_refresh_golden_frame =
cpi->ext_refresh_alt_ref_frame = 0;
if (!temporal_id) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[temporal_id].is_key_frame) {
// base layer is a key frame.
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
} else if (temporal_id == 1) {
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_alt_ref_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
}
if (temporal_id == 0) {
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
cpi->alt_fb_idx = 0;
} else if (temporal_id == 1) {
cpi->lst_fb_idx = spatial_id;
cpi->gld_fb_idx = cpi->svc.number_spatial_layers + spatial_id - 1;
cpi->alt_fb_idx = cpi->svc.number_spatial_layers + spatial_id;
}
}
// The function sets proper ref_frame_flags, buffer indices, and buffer update
// variables for temporal layering mode 0 - that has no temporal layering.
static void set_flags_and_fb_idx_for_temporal_mode_noLayering(
VP9_COMP *const cpi) {
int spatial_id;
spatial_id = cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
cpi->ext_refresh_last_frame =
cpi->ext_refresh_golden_frame = cpi->ext_refresh_alt_ref_frame = 0;
cpi->ext_refresh_frame_flags_pending = 1;
cpi->ext_refresh_last_frame = 1;
if (!spatial_id) {
cpi->ref_frame_flags = VP9_LAST_FLAG;
} else if (cpi->svc.layer_context[0].is_key_frame) {
cpi->ref_frame_flags = VP9_GOLD_FLAG;
} else {
cpi->ref_frame_flags = VP9_LAST_FLAG | VP9_GOLD_FLAG;
}
cpi->lst_fb_idx = spatial_id;
if (spatial_id)
cpi->gld_fb_idx = spatial_id - 1;
else
cpi->gld_fb_idx = 0;
}
int vp9_one_pass_cbr_svc_start_layer(VP9_COMP *const cpi) {
int width = 0, height = 0;
LAYER_CONTEXT *lc = NULL;
if (cpi->svc.temporal_layering_mode == VP9E_TEMPORAL_LAYERING_MODE_0212) {
set_flags_and_fb_idx_for_temporal_mode3(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING) {
set_flags_and_fb_idx_for_temporal_mode_noLayering(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_0101) {
set_flags_and_fb_idx_for_temporal_mode2(cpi);
} else if (cpi->svc.temporal_layering_mode ==
VP9E_TEMPORAL_LAYERING_MODE_BYPASS) {
// VP9E_TEMPORAL_LAYERING_MODE_BYPASS :
// if the code goes here, it means the encoder will be relying on the
// flags from outside for layering.
// However, since when spatial+temporal layering is used, the buffer indices
// cannot be derived automatically, the bypass mode will only work when the
// number of spatial layers equals 1.
assert(cpi->svc.number_spatial_layers == 1);
}
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers +
cpi->svc.temporal_layer_id];
get_layer_resolution(cpi->oxcf.width, cpi->oxcf.height,
lc->scaling_factor_num, lc->scaling_factor_den,
&width, &height);
if (vp9_set_size_literal(cpi, width, height) != 0)
return VPX_CODEC_INVALID_PARAM;
return 0;
}
#if CONFIG_SPATIAL_SVC
int vp9_svc_start_frame(VP9_COMP *const cpi) { int vp9_svc_start_frame(VP9_COMP *const cpi) {
int width = 0, height = 0; int width = 0, height = 0;
LAYER_CONTEXT *lc; LAYER_CONTEXT *lc;
@ -386,11 +628,12 @@ int vp9_svc_start_frame(VP9_COMP *const cpi) {
return 0; return 0;
} }
#endif
struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi, struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi,
struct lookahead_ctx *ctx, struct lookahead_ctx *ctx,
int drain) { int drain) {
struct lookahead_entry *buf = NULL; struct lookahead_entry *buf = NULL;
if (ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) { if (ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
buf = vp9_lookahead_peek(ctx, 0); buf = vp9_lookahead_peek(ctx, 0);
if (buf != NULL) { if (buf != NULL) {
@ -400,7 +643,5 @@ struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi,
} }
} }
} }
return buf; return buf;
} }
#endif

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

@ -22,6 +22,7 @@ extern "C" {
typedef struct { typedef struct {
RATE_CONTROL rc; RATE_CONTROL rc;
int target_bandwidth; int target_bandwidth;
int spatial_layer_target_bandwidth; // Target for the spatial layer.
double framerate; double framerate;
int avg_frame_size; int avg_frame_size;
int max_q; int max_q;
@ -64,9 +65,11 @@ typedef struct {
YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS]; YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
// Layer context used for rate control in one pass temporal CBR mode or // Layer context used for rate control in one pass temporal CBR mode or
// two pass spatial mode. Defined for temporal or spatial layers for now. // two pass spatial mode.
// Does not support temporal combined with spatial RC. LAYER_CONTEXT layer_context[VPX_MAX_LAYERS];
LAYER_CONTEXT layer_context[MAX(VPX_TS_MAX_LAYERS, VPX_SS_MAX_LAYERS)]; // Indicates what sort of temporal layering is used.
// Currently, this only works for CBR mode.
VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
} SVC; } SVC;
struct VP9_COMP; struct VP9_COMP;
@ -110,6 +113,8 @@ struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
// Start a frame and initialize svc parameters // Start a frame and initialize svc parameters
int vp9_svc_start_frame(struct VP9_COMP *const cpi); int vp9_svc_start_frame(struct VP9_COMP *const cpi);
int vp9_one_pass_cbr_svc_start_layer(struct VP9_COMP *const cpi);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

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

@ -682,7 +682,7 @@ void vp9_temporal_filter(VP9_COMP *cpi, int distance) {
if (frames_to_blur > 0) { if (frames_to_blur > 0) {
// Setup scaling factors. Scaling on each of the arnr frames is not // Setup scaling factors. Scaling on each of the arnr frames is not
// supported. // supported.
if (is_two_pass_svc(cpi)) { if (cpi->use_svc) {
// In spatial svc the scaling factors might be less then 1/2. // In spatial svc the scaling factors might be less then 1/2.
// So we will use non-normative scaling. // So we will use non-normative scaling.
int frame_used = 0; int frame_used = 0;

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

@ -176,15 +176,23 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS); RANGE_CHECK(cfg, ss_number_layers, 1, VPX_SS_MAX_LAYERS);
RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS); RANGE_CHECK(cfg, ts_number_layers, 1, VPX_TS_MAX_LAYERS);
if (cfg->ss_number_layers * cfg->ts_number_layers > VPX_MAX_LAYERS)
ERROR("ss_number_layers * ts_number_layers is out of range");
if (cfg->ts_number_layers > 1) { if (cfg->ts_number_layers > 1) {
unsigned int i; unsigned int sl, tl;
for (i = 1; i < cfg->ts_number_layers; ++i) for (sl = 1; sl < cfg->ss_number_layers; ++sl) {
if (cfg->ts_target_bitrate[i] < cfg->ts_target_bitrate[i - 1]) for (tl = 1; tl < cfg->ts_number_layers; ++tl) {
const int layer =
LAYER_IDS_TO_IDX(sl, tl, cfg->ts_number_layers);
if (cfg->layer_target_bitrate[layer] <
cfg->layer_target_bitrate[layer - 1])
ERROR("ts_target_bitrate entries are not increasing"); ERROR("ts_target_bitrate entries are not increasing");
}
}
RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1); RANGE_CHECK(cfg, ts_rate_decimator[cfg->ts_number_layers - 1], 1, 1);
for (i = cfg->ts_number_layers - 2; i > 0; --i) for (tl = cfg->ts_number_layers - 2; tl > 0; --tl)
if (cfg->ts_rate_decimator[i - 1] != 2 * cfg->ts_rate_decimator[i]) if (cfg->ts_rate_decimator[tl - 1] != 2 * cfg->ts_rate_decimator[tl])
ERROR("ts_rate_decimator factors are not powers of 2"); ERROR("ts_rate_decimator factors are not powers of 2");
} }
@ -360,6 +368,7 @@ static vpx_codec_err_t set_encoder_config(
const vpx_codec_enc_cfg_t *cfg, const vpx_codec_enc_cfg_t *cfg,
const struct vp9_extracfg *extra_cfg) { const struct vp9_extracfg *extra_cfg) {
const int is_vbr = cfg->rc_end_usage == VPX_VBR; const int is_vbr = cfg->rc_end_usage == VPX_VBR;
int sl, tl;
oxcf->profile = cfg->g_profile; oxcf->profile = cfg->g_profile;
oxcf->max_threads = (int)cfg->g_threads; oxcf->max_threads = (int)cfg->g_threads;
oxcf->width = cfg->g_w; oxcf->width = cfg->g_w;
@ -460,35 +469,33 @@ static vpx_codec_err_t set_encoder_config(
oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost; oxcf->frame_periodic_boost = extra_cfg->frame_periodic_boost;
oxcf->ss_number_layers = cfg->ss_number_layers; oxcf->ss_number_layers = cfg->ss_number_layers;
oxcf->ts_number_layers = cfg->ts_number_layers;
oxcf->temporal_layering_mode = (enum vp9e_temporal_layering_mode)
cfg->temporal_layering_mode;
if (oxcf->ss_number_layers > 1) { for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
int i;
for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
oxcf->ss_target_bitrate[i] = 1000 * cfg->ss_target_bitrate[i];
#if CONFIG_SPATIAL_SVC #if CONFIG_SPATIAL_SVC
oxcf->ss_enable_auto_arf[i] = cfg->ss_enable_auto_alt_ref[i]; oxcf->ss_enable_auto_arf[sl] = cfg->ss_enable_auto_alt_ref[sl];
#endif #endif
for (tl = 0; tl < oxcf->ts_number_layers; ++tl) {
oxcf->layer_target_bitrate[sl * oxcf->ts_number_layers + tl] =
1000 * cfg->layer_target_bitrate[sl * oxcf->ts_number_layers + tl];
} }
} else if (oxcf->ss_number_layers == 1) { }
if (oxcf->ss_number_layers == 1 && oxcf->pass != 0) {
oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth; oxcf->ss_target_bitrate[0] = (int)oxcf->target_bandwidth;
#if CONFIG_SPATIAL_SVC #if CONFIG_SPATIAL_SVC
oxcf->ss_enable_auto_arf[0] = extra_cfg->enable_auto_alt_ref; oxcf->ss_enable_auto_arf[0] = extra_cfg->enable_auto_alt_ref;
#endif #endif
} }
oxcf->ts_number_layers = cfg->ts_number_layers;
if (oxcf->ts_number_layers > 1) { if (oxcf->ts_number_layers > 1) {
int i; for (tl = 0; tl < VPX_TS_MAX_LAYERS; ++tl) {
for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) { oxcf->ts_rate_decimator[tl] = cfg->ts_rate_decimator[tl] ?
oxcf->ts_target_bitrate[i] = 1000 * cfg->ts_target_bitrate[i]; cfg->ts_rate_decimator[tl] : 1;
oxcf->ts_rate_decimator[i] = cfg->ts_rate_decimator[i];
} }
} else if (oxcf->ts_number_layers == 1) { } else if (oxcf->ts_number_layers == 1) {
oxcf->ts_target_bitrate[0] = (int)oxcf->target_bandwidth;
oxcf->ts_rate_decimator[0] = 1; oxcf->ts_rate_decimator[0] = 1;
} }
/* /*
printf("Current VP9 Settings: \n"); printf("Current VP9 Settings: \n");
printf("target_bandwidth: %d\n", oxcf->target_bandwidth); printf("target_bandwidth: %d\n", oxcf->target_bandwidth);
@ -902,11 +909,12 @@ static vpx_codec_frame_flags_t get_frame_pkt_flags(const VP9_COMP *cpi,
unsigned int lib_flags) { unsigned int lib_flags) {
vpx_codec_frame_flags_t flags = lib_flags << 16; vpx_codec_frame_flags_t flags = lib_flags << 16;
if (lib_flags & FRAMEFLAGS_KEY if (lib_flags & FRAMEFLAGS_KEY ||
#if CONFIG_SPATIAL_SVC (cpi->use_svc &&
|| (is_two_pass_svc(cpi) && cpi->svc.layer_context[0].is_key_frame) cpi->svc.layer_context[cpi->svc.spatial_layer_id *
#endif cpi->svc.number_temporal_layers +
) cpi->svc.temporal_layer_id].is_key_frame)
)
flags |= VPX_FRAME_IS_KEY; flags |= VPX_FRAME_IS_KEY;
if (cpi->droppable) if (cpi->droppable)
@ -1022,16 +1030,15 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
vpx_codec_cx_pkt_t pkt; vpx_codec_cx_pkt_t pkt;
#if CONFIG_SPATIAL_SVC #if CONFIG_SPATIAL_SVC
if (is_two_pass_svc(cpi)) if (cpi->use_svc)
cpi->svc.layer_context[cpi->svc.spatial_layer_id].layer_size += size; cpi->svc.layer_context[cpi->svc.spatial_layer_id *
cpi->svc.number_temporal_layers].layer_size += size;
#endif #endif
// Pack invisible frames with the next visible frame // Pack invisible frames with the next visible frame
if (!cpi->common.show_frame if (!cpi->common.show_frame ||
#if CONFIG_SPATIAL_SVC (cpi->use_svc &&
|| (is_two_pass_svc(cpi) && cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
#endif
) { ) {
if (ctx->pending_cx_data == 0) if (ctx->pending_cx_data == 0)
ctx->pending_cx_data = cx_data; ctx->pending_cx_data = cx_data;
@ -1089,24 +1096,26 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
pkt.data.frame.partition_id = -1; pkt.data.frame.partition_id = -1;
if(ctx->output_cx_pkt_cb.output_cx_pkt) if(ctx->output_cx_pkt_cb.output_cx_pkt)
ctx->output_cx_pkt_cb.output_cx_pkt(&pkt, ctx->output_cx_pkt_cb.user_priv); ctx->output_cx_pkt_cb.output_cx_pkt(&pkt,
ctx->output_cx_pkt_cb.user_priv);
else else
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt); vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt);
cx_data += size; cx_data += size;
cx_data_sz -= size; cx_data_sz -= size;
#if CONFIG_SPATIAL_SVC #if CONFIG_SPATIAL_SVC
if (is_two_pass_svc(cpi) && !ctx->output_cx_pkt_cb.output_cx_pkt) { if (cpi->use_svc && !ctx->output_cx_pkt_cb.output_cx_pkt) {
vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr; vpx_codec_cx_pkt_t pkt_sizes, pkt_psnr;
int i; int sl;
vp9_zero(pkt_sizes); vp9_zero(pkt_sizes);
vp9_zero(pkt_psnr); vp9_zero(pkt_psnr);
pkt_sizes.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES; pkt_sizes.kind = VPX_CODEC_SPATIAL_SVC_LAYER_SIZES;
pkt_psnr.kind = VPX_CODEC_SPATIAL_SVC_LAYER_PSNR; pkt_psnr.kind = VPX_CODEC_SPATIAL_SVC_LAYER_PSNR;
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
LAYER_CONTEXT *lc = &cpi->svc.layer_context[i]; LAYER_CONTEXT *lc =
pkt_sizes.data.layer_sizes[i] = lc->layer_size; &cpi->svc.layer_context[sl * cpi->svc.number_temporal_layers];
pkt_psnr.data.layer_psnr[i] = lc->psnr_pkt; pkt_sizes.data.layer_sizes[sl] = lc->layer_size;
pkt_psnr.data.layer_psnr[sl] = lc->psnr_pkt;
lc->layer_size = 0; lc->layer_size = 0;
} }
@ -1115,6 +1124,11 @@ static vpx_codec_err_t encoder_encode(vpx_codec_alg_priv_t *ctx,
vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_psnr); vpx_codec_pkt_list_add(&ctx->pkt_list.head, &pkt_psnr);
} }
#endif #endif
if (is_one_pass_cbr_svc(cpi) &&
(cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1)) {
// Encoded all spatial layers; exit loop.
break;
}
} }
} }
} }
@ -1292,16 +1306,20 @@ static vpx_codec_err_t ctrl_set_scale_mode(vpx_codec_alg_priv_t *ctx,
static vpx_codec_err_t ctrl_set_svc(vpx_codec_alg_priv_t *ctx, va_list args) { static vpx_codec_err_t ctrl_set_svc(vpx_codec_alg_priv_t *ctx, va_list args) {
int data = va_arg(args, int); int data = va_arg(args, int);
const vpx_codec_enc_cfg_t *cfg = &ctx->cfg; const vpx_codec_enc_cfg_t *cfg = &ctx->cfg;
// Both one-pass and two-pass RC are supported now.
// User setting this has to make sure of the following.
// In two-pass setting: either (but not both)
// cfg->ss_number_layers > 1, or cfg->ts_number_layers > 1
// In one-pass setting:
// either or both cfg->ss_number_layers > 1, or cfg->ts_number_layers > 1
vp9_set_svc(ctx->cpi, data); vp9_set_svc(ctx->cpi, data);
// CBR or two pass mode for SVC with both temporal and spatial layers
// not yet supported.
if (data == 1 && if (data == 1 &&
(cfg->rc_end_usage == VPX_CBR || (cfg->g_pass == VPX_RC_FIRST_PASS ||
cfg->g_pass == VPX_RC_FIRST_PASS ||
cfg->g_pass == VPX_RC_LAST_PASS) && cfg->g_pass == VPX_RC_LAST_PASS) &&
cfg->ss_number_layers > 1 && cfg->ss_number_layers > 1 &&
cfg->ts_number_layers > 1) { cfg->ts_number_layers > 1) {
return VPX_CODEC_INVALID_PARAM; return VPX_CODEC_INVALID_PARAM;
} }
return VPX_CODEC_OK; return VPX_CODEC_OK;
@ -1347,15 +1365,21 @@ static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
va_list args) { va_list args) {
VP9_COMP *const cpi = ctx->cpi; VP9_COMP *const cpi = ctx->cpi;
vpx_svc_extra_cfg_t *const params = va_arg(args, vpx_svc_extra_cfg_t *); vpx_svc_extra_cfg_t *const params = va_arg(args, vpx_svc_extra_cfg_t *);
int i; int sl, tl;
for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { // Number of temporal layers and number of spatial layers have to be set
LAYER_CONTEXT *lc = &cpi->svc.layer_context[i]; // properly before calling this control function.
for (sl = 0; sl < cpi->svc.number_spatial_layers; ++sl) {
lc->max_q = params->max_quantizers[i]; for (tl = 0; tl < cpi->svc.number_temporal_layers; ++tl) {
lc->min_q = params->min_quantizers[i]; const int layer =
lc->scaling_factor_num = params->scaling_factor_num[i]; LAYER_IDS_TO_IDX(sl, tl, cpi->svc.number_temporal_layers);
lc->scaling_factor_den = params->scaling_factor_den[i]; LAYER_CONTEXT *lc =
&cpi->svc.layer_context[layer];
lc->max_q = params->max_quantizers[sl];
lc->min_q = params->min_quantizers[sl];
lc->scaling_factor_num = params->scaling_factor_num[sl];
lc->scaling_factor_den = params->scaling_factor_den[sl];
}
} }
return VPX_CODEC_OK; return VPX_CODEC_OK;
@ -1495,6 +1519,8 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
{0}, // ts_rate_decimator {0}, // ts_rate_decimator
0, // ts_periodicity 0, // ts_periodicity
{0}, // ts_layer_id {0}, // ts_layer_id
{0}, // layer_taget_bitrate
0 // temporal_layering_mode
} }
}, },
}; };

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

@ -302,31 +302,79 @@ void assign_layer_bitrates(const SvcContext *svc_ctx,
vpx_codec_enc_cfg_t *const enc_cfg) { vpx_codec_enc_cfg_t *const enc_cfg) {
int i; int i;
const SvcInternal_t *const si = get_const_svc_internal(svc_ctx); const SvcInternal_t *const si = get_const_svc_internal(svc_ctx);
int sl, tl, spatial_layer_target;
if (si->bitrates[0] != 0) { if (svc_ctx->temporal_layering_mode != 0) {
enc_cfg->rc_target_bitrate = 0; if (si->bitrates[0] != 0) {
for (i = 0; i < svc_ctx->spatial_layers; ++i) { enc_cfg->rc_target_bitrate = 0;
enc_cfg->ss_target_bitrate[i] = (unsigned int)si->bitrates[i]; for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
enc_cfg->rc_target_bitrate += si->bitrates[i]; enc_cfg->ss_target_bitrate[sl*svc_ctx->temporal_layers] = 0;
} for (tl = 0; tl < svc_ctx->temporal_layers; ++tl) {
} else { enc_cfg->ss_target_bitrate[sl*svc_ctx->temporal_layers]
float total = 0; += (unsigned int)si->bitrates[sl * svc_ctx->temporal_layers + tl];
float alloc_ratio[VPX_SS_MAX_LAYERS] = {0}; 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[VPX_MAX_LAYERS] = {0};
for (i = 0; i < svc_ctx->spatial_layers; ++i) { for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
if (si->svc_params.scaling_factor_den[i] > 0) { if (si->svc_params.scaling_factor_den[sl] > 0) {
alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 / alloc_ratio[sl] = (float)(si->svc_params.scaling_factor_num[sl] *
si->svc_params.scaling_factor_den[i]); 1.0 / si->svc_params.scaling_factor_den[sl]);
total += alloc_ratio[sl];
}
}
alloc_ratio[i] *= alloc_ratio[i]; for (sl = 0; sl < svc_ctx->spatial_layers; ++sl) {
total += alloc_ratio[i]; 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) {
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[VPX_MAX_LAYERS] = {0};
for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { for (i = 0; i < svc_ctx->spatial_layers; ++i) {
if (total > 0) { if (si->svc_params.scaling_factor_den[i] > 0) {
enc_cfg->ss_target_bitrate[i] = (unsigned int) alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
(enc_cfg->rc_target_bitrate * alloc_ratio[i] / total); si->svc_params.scaling_factor_den[i]);
alloc_ratio[i] *= alloc_ratio[i];
total += alloc_ratio[i];
}
}
for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
if (total > 0) {
enc_cfg->layer_target_bitrate[i] = (unsigned int)
(enc_cfg->rc_target_bitrate * alloc_ratio[i] / total);
}
} }
} }
} }
@ -365,6 +413,14 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
return VPX_CODEC_INVALID_PARAM; return VPX_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_layers = 2;
}
for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) { for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
si->svc_params.max_quantizers[i] = MAX_QUANTIZER; si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
si->svc_params.min_quantizers[i] = 0; si->svc_params.min_quantizers[i] = 0;
@ -387,6 +443,14 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS) if (svc_ctx->temporal_layers > VPX_TS_MAX_LAYERS)
svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS; svc_ctx->temporal_layers = VPX_TS_MAX_LAYERS;
if (svc_ctx->temporal_layers * svc_ctx->spatial_layers > VPX_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) VPX_MAX_LAYERS);
return VPX_CODEC_INVALID_PARAM;
}
assign_layer_bitrates(svc_ctx, enc_cfg); assign_layer_bitrates(svc_ctx, enc_cfg);
#if CONFIG_SPATIAL_SVC #if CONFIG_SPATIAL_SVC
@ -403,10 +467,24 @@ vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
} }
} }
// modify encoder configuration 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->ss_number_layers = svc_ctx->spatial_layers;
enc_cfg->ts_number_layers = svc_ctx->temporal_layers; enc_cfg->ts_number_layers = svc_ctx->temporal_layers;
if (enc_cfg->rc_end_usage == VPX_CBR) {
enc_cfg->rc_resize_allowed = 0;
enc_cfg->rc_min_quantizer = 2;
enc_cfg->rc_max_quantizer = 63;
enc_cfg->rc_undershoot_pct = 50;
enc_cfg->rc_overshoot_pct = 50;
enc_cfg->rc_buf_initial_sz = 20;
enc_cfg->rc_buf_optimal_sz = 600;
enc_cfg->rc_buf_sz = 1000;
}
if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0) if (enc_cfg->g_error_resilient == 0 && si->use_multiple_frame_contexts == 0)
enc_cfg->g_error_resilient = 1; enc_cfg->g_error_resilient = 1;
@ -554,7 +632,7 @@ const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) {
mse[1], mse[2], mse[3]); mse[1], mse[2], mse[3]);
bytes_total += si->bytes_sum[i]; bytes_total += si->bytes_sum[i];
// clear sums for next time // Clear sums for next time.
si->bytes_sum[i] = 0; si->bytes_sum[i] = 0;
for (j = 0; j < COMPONENTS; ++j) { for (j = 0; j < COMPONENTS; ++j) {
si->psnr_sum[i][j] = 0; si->psnr_sum[i][j] = 0;

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

@ -33,10 +33,13 @@ typedef struct {
// public interface to svc_command options // public interface to svc_command options
int spatial_layers; // number of spatial layers int spatial_layers; // number of spatial layers
int temporal_layers; // number of temporal layers int temporal_layers; // number of temporal layers
int temporal_layering_mode;
SVC_LOG_LEVEL log_level; // amount of information to display SVC_LOG_LEVEL log_level; // amount of information to display
int log_print; // when set, printf log messages instead of returning the int log_print; // when set, printf log messages instead of returning the
// message with svc_get_message // message with svc_get_message
int output_rc_stat; // for outputting rc stats
int speed; // speed setting for codec
int threads;
// private storage for vpx_svc_encode // private storage for vpx_svc_encode
void *internal; void *internal;
} SvcContext; } SvcContext;

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

@ -511,6 +511,17 @@ enum vp8e_enc_control_id {
*/ */
VP9E_SET_COLOR_SPACE, VP9E_SET_COLOR_SPACE,
/*!\brief Codec control function to set temporal layering mode.
* \note Valid ranges: 0..3, default is "0" (VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING).
* 0 = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING
* 1 = VP9E_TEMPORAL_LAYERING_MODE_BYPASS
* 2 = VP9E_TEMPORAL_LAYERING_MODE_0101
* 3 = VP9E_TEMPORAL_LAYERING_MODE_0212
*
* Supported in codecs: VP9
*/
VP9E_SET_TEMPORAL_LAYERING_MODE,
/*!\brief Codec control function to get an Active map back from the encoder. /*!\brief Codec control function to get an Active map back from the encoder.
* *
* Supported in codecs: VP9 * Supported in codecs: VP9
@ -529,6 +540,32 @@ typedef enum vpx_scaling_mode_1d {
VP8E_ONETWO = 3 VP8E_ONETWO = 3
} VPX_SCALING_MODE; } VPX_SCALING_MODE;
/*!\brief Temporal layering mode enum for VP9 SVC.
*
* This set of macros define the different temporal layering modes.
* Supported codecs: VP9 (in SVC mode)
*
*/
typedef enum vp9e_temporal_layering_mode {
/*!\brief No temporal layering.
* Used when only spatial layering is used.
*/
VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING = 0,
/*!\brief Bypass mode.
* Used when application needs to control temporal layering.
* This will only work when the number of spatial layers equals 1.
*/
VP9E_TEMPORAL_LAYERING_MODE_BYPASS = 1,
/*!\brief 0-1-0-1... temporal layering scheme with two temporal layers.
*/
VP9E_TEMPORAL_LAYERING_MODE_0101 = 2,
/*!\brief 0-2-1-2... temporal layering scheme with three temporal layers.
*/
VP9E_TEMPORAL_LAYERING_MODE_0212 = 3
} VP9E_TEMPORAL_LAYERING_MODE;
/*!\brief vpx region of interest map /*!\brief vpx region of interest map
* *

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

@ -42,8 +42,11 @@ extern "C" {
/*!\deprecated Use #VPX_TS_MAX_PERIODICITY instead. */ /*!\deprecated Use #VPX_TS_MAX_PERIODICITY instead. */
#define MAX_PERIODICITY VPX_TS_MAX_PERIODICITY #define MAX_PERIODICITY VPX_TS_MAX_PERIODICITY
/*!\deprecated Use #VPX_TS_MAX_LAYERS instead. */ /*! Temporal+Spatial Scalability: Maximum number of coding layers */
#define MAX_LAYERS VPX_TS_MAX_LAYERS #define VPX_MAX_LAYERS 12 // 3 temporal + 4 spatial layers are allowed.
/*!\deprecated Use #VPX_MAX_LAYERS instead. */
#define MAX_LAYERS VPX_MAX_LAYERS // 3 temporal + 4 spatial layers allowed.
/*! Spatial Scalability: Maximum number of coding layers */ /*! Spatial Scalability: Maximum number of coding layers */
#define VPX_SS_MAX_LAYERS 5 #define VPX_SS_MAX_LAYERS 5
@ -729,6 +732,22 @@ extern "C" {
* ts_periodicity=8, then ts_layer_id = (0,1,0,1,0,1,0,1). * ts_periodicity=8, then ts_layer_id = (0,1,0,1,0,1,0,1).
*/ */
unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY]; unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY];
/*!\brief Target bitrate for each spatial/temporal layer.
*
* These values specify the target coding bitrate to be used for each
* spatial/temporal layer.
*
*/
unsigned int layer_target_bitrate[VPX_MAX_LAYERS];
/*!\brief Temporal layering mode indicating which temporal layering scheme to use.
*
* The value (refer to VP9E_TEMPORAL_LAYERING_MODE) specifies the
* temporal layering mode to use.
*
*/
int temporal_layering_mode;
} vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */ } vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */
/*!\brief vp9 svc extra configure parameters /*!\brief vp9 svc extra configure parameters
@ -737,10 +756,11 @@ extern "C" {
* *
*/ */
typedef struct vpx_svc_parameters { typedef struct vpx_svc_parameters {
int max_quantizers[VPX_SS_MAX_LAYERS]; /**< Max Q for each layer */ int max_quantizers[VPX_MAX_LAYERS]; /**< Max Q for each layer */
int min_quantizers[VPX_SS_MAX_LAYERS]; /**< Min Q for each layer */ int min_quantizers[VPX_MAX_LAYERS]; /**< Min Q for each layer */
int scaling_factor_num[VPX_SS_MAX_LAYERS]; /**< Scaling factor-numerator*/ int scaling_factor_num[VPX_MAX_LAYERS]; /**< Scaling factor-numerator */
int scaling_factor_den[VPX_SS_MAX_LAYERS]; /**< Scaling factor-denominator*/ int scaling_factor_den[VPX_MAX_LAYERS]; /**< Scaling factor-denominator */
int temporal_layering_mode; /**< Temporal layering mode */
} vpx_svc_extra_cfg_t; } vpx_svc_extra_cfg_t;