ARG_DEF("k", "kf-dist", 1, "number of frames between keyframes");
static const arg_def_t scale_factors_arg =
ARG_DEF("r", "scale-factors", 1, "scale factors (lowest to highest layer)");
-static const arg_def_t quantizers_arg =
- ARG_DEF("q", "quantizers", 1, "quantizers for non key frames, also will "
- "be applied to key frames if -qn is not specified (lowest to "
- "highest layer)");
static const arg_def_t passes_arg =
ARG_DEF("p", "passes", 1, "Number of passes (1/2)");
static const arg_def_t pass_arg =
static const arg_def_t *svc_args[] = {
&frames_arg, &width_arg, &height_arg,
&timebase_arg, &bitrate_arg, &skip_frames_arg, &spatial_layers_arg,
- &kf_dist_arg, &scale_factors_arg, &quantizers_arg, &passes_arg,
- &pass_arg, &fpf_name_arg, &min_q_arg, &max_q_arg,
- &min_bitrate_arg, &max_bitrate_arg, &temporal_layers_arg,
- NULL
+ &kf_dist_arg, &scale_factors_arg, &passes_arg, &pass_arg,
+ &fpf_name_arg, &min_q_arg, &max_q_arg, &min_bitrate_arg,
+ &max_bitrate_arg, &temporal_layers_arg, NULL
};
static const uint32_t default_frames_to_skip = 0;
const char *fpf_file_name = NULL;
unsigned int min_bitrate = 0;
unsigned int max_bitrate = 0;
+ char string_options[1024] = {0};
// initialize SvcContext with parameters that will be passed to vpx_svc_init
svc_ctx->log_level = SVC_LOG_DEBUG;
enc_cfg->kf_min_dist = arg_parse_uint(&arg);
enc_cfg->kf_max_dist = enc_cfg->kf_min_dist;
} else if (arg_match(&arg, &scale_factors_arg, argi)) {
- vpx_svc_set_scale_factors(svc_ctx, arg.val);
- } else if (arg_match(&arg, &quantizers_arg, argi)) {
- vpx_svc_set_quantizers(svc_ctx, arg.val);
+ snprintf(string_options, 1024, "%s scale-factors=%s",
+ string_options, arg.val);
} else if (arg_match(&arg, &passes_arg, argi)) {
passes = arg_parse_uint(&arg);
if (passes < 1 || passes > 2) {
} else if (arg_match(&arg, &fpf_name_arg, argi)) {
fpf_file_name = arg.val;
} else if (arg_match(&arg, &min_q_arg, argi)) {
- enc_cfg->rc_min_quantizer = arg_parse_uint(&arg);
+ snprintf(string_options, 1024, "%s min-quantizers=%s",
+ string_options, arg.val);
} else if (arg_match(&arg, &max_q_arg, argi)) {
- enc_cfg->rc_max_quantizer = arg_parse_uint(&arg);
+ snprintf(string_options, 1024, "%s max-quantizers=%s",
+ string_options, arg.val);
} else if (arg_match(&arg, &min_bitrate_arg, argi)) {
min_bitrate = arg_parse_uint(&arg);
} else if (arg_match(&arg, &max_bitrate_arg, argi)) {
}
}
+ // There will be a space in front of the string options
+ if (strlen(string_options) > 0)
+ vpx_svc_set_options(svc_ctx, string_options + 1);
+
if (passes == 0 || passes == 1) {
if (pass) {
fprintf(stderr, "pass is ignored since there's only one pass\n");
info.codec_fourcc = VP9_FOURCC;
info.time_base.numerator = enc_cfg.g_timebase.num;
info.time_base.denominator = enc_cfg.g_timebase.den;
- if (vpx_svc_get_layer_resolution(&svc_ctx, svc_ctx.spatial_layers - 1,
- (unsigned int *)&info.frame_width,
- (unsigned int *)&info.frame_height) !=
- VPX_CODEC_OK) {
- die("Failed to get output resolution");
- }
if (!(app_input.passes == 2 && app_input.pass == 1)) {
// We don't save the bitstream for the 1st pass on two pass rate control
namespace {
-static const int kMaxDimension = 64;
+static const unsigned int kMaxDimension = 64;
typedef void (*ConvolveFunc)(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
TEST_F(SvcTest, InitTwoLayers) {
svc_.spatial_layers = 2;
- vpx_svc_set_scale_factors(&svc_, "4/16,16*16"); // invalid scale values
- vpx_codec_err_t res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_);
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); // valid scale values
InitializeEncoder();
}
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
+ res = vpx_svc_set_options(&svc_, "scale-factors=1/3, 3*3");
EXPECT_EQ(VPX_CODEC_OK, res);
- InitializeEncoder();
-}
+ res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
+ EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-TEST_F(SvcTest, SetQuantizersOption) {
- svc_.spatial_layers = 2;
- vpx_codec_err_t res = vpx_svc_set_options(&svc_, "quantizers=not-quantizers");
+ res = vpx_svc_set_options(&svc_, "scale-factors=1/3");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- vpx_svc_set_options(&svc_, "quantizers=40,45");
+ res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3");
+ EXPECT_EQ(VPX_CODEC_OK, res);
InitializeEncoder();
}
-TEST_F(SvcTest, SetAutoAltRefOption) {
- svc_.spatial_layers = 5;
- vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none");
+TEST_F(SvcTest, SetQuantizersOption) {
+ svc_.spatial_layers = 2;
+ vpx_codec_err_t res = vpx_svc_set_options(&svc_, "max-quantizers=nothing");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
+ res = vpx_svc_set_options(&svc_, "min-quantizers=nothing");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
- InitializeEncoder();
-}
-
-TEST_F(SvcTest, SetQuantizers) {
- vpx_codec_err_t res = vpx_svc_set_quantizers(NULL, "40,30");
+ res = vpx_svc_set_options(&svc_, "max-quantizers=40");
+ EXPECT_EQ(VPX_CODEC_OK, res);
+ res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- res = vpx_svc_set_quantizers(&svc_, NULL);
+ res = vpx_svc_set_options(&svc_, "min-quantizers=40");
+ EXPECT_EQ(VPX_CODEC_OK, res);
+ res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- svc_.spatial_layers = 2;
- res = vpx_svc_set_quantizers(&svc_, "40");
+ res = vpx_svc_set_options(&svc_, "max-quantizers=30,30 min-quantizers=40,40");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- res = vpx_svc_set_quantizers(&svc_, "40,30");
- EXPECT_EQ(VPX_CODEC_OK, res);
+ res = vpx_svc_set_options(&svc_, "max-quantizers=40,40 min-quantizers=30,30");
InitializeEncoder();
}
-TEST_F(SvcTest, SetScaleFactors) {
- vpx_codec_err_t res = vpx_svc_set_scale_factors(NULL, "4/16,16/16");
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- res = vpx_svc_set_scale_factors(&svc_, NULL);
+TEST_F(SvcTest, SetAutoAltRefOption) {
+ svc_.spatial_layers = 5;
+ vpx_codec_err_t res = vpx_svc_set_options(&svc_, "auto-alt-refs=none");
+ EXPECT_EQ(VPX_CODEC_OK, res);
+ res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- svc_.spatial_layers = 2;
- res = vpx_svc_set_scale_factors(&svc_, "4/16");
+ res = vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1,1,0");
EXPECT_EQ(VPX_CODEC_OK, res);
res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_);
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
- res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16");
- EXPECT_EQ(VPX_CODEC_OK, res);
+ vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0");
InitializeEncoder();
}
FreeBitstreamBuffers(&outputs[0], 3);
}
-TEST_F(SvcTest, GetLayerResolution) {
- svc_.spatial_layers = 2;
- vpx_svc_set_scale_factors(&svc_, "4/16,8/16");
- vpx_svc_set_quantizers(&svc_, "40,30");
-
- InitializeEncoder();
-
- // ensure that requested layer is a valid layer
- uint32_t layer_width, layer_height;
- vpx_codec_err_t res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers,
- &layer_width, &layer_height);
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- res = vpx_svc_get_layer_resolution(NULL, 0, &layer_width, &layer_height);
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- res = vpx_svc_get_layer_resolution(&svc_, 0, NULL, &layer_height);
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, NULL);
- EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res);
-
- res = vpx_svc_get_layer_resolution(&svc_, 0, &layer_width, &layer_height);
- EXPECT_EQ(VPX_CODEC_OK, res);
- EXPECT_EQ(kWidth * 4 / 16, layer_width);
- EXPECT_EQ(kHeight * 4 / 16, layer_height);
-
- res = vpx_svc_get_layer_resolution(&svc_, 1, &layer_width, &layer_height);
- EXPECT_EQ(VPX_CODEC_OK, res);
- EXPECT_EQ(kWidth * 8 / 16, layer_width);
- EXPECT_EQ(kHeight * 8 / 16, layer_height);
-}
-
TEST_F(SvcTest, TwoPassEncode10Frames) {
// First pass encode
std::string stats_buf;
LIBVPX_TEST_SRCS-$(CONFIG_VP8_ENCODER) += keyframe_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += external_frame_buffer_test.cc
+LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += invalid_file_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_DECODER) += user_priv_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += active_map_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_VP9_ENCODER) += borders_test.cc
endif
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += decode_api_test.cc
-LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += invalid_file_test.cc
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += test_vector_test.cc
# Currently we only support decoder perf tests for vp9. Also they read from WebM
// Default rd threshold factors for mode selection
for (i = 0; i < BLOCK_SIZES; ++i) {
- for (j = 0; j < MAX_MODES; ++j)
+ for (j = 0; j < MAX_MODES; ++j) {
cpi->rd.thresh_freq_fact[i][j] = 32;
+ cpi->rd.mode_map[i][j] = j;
+ }
}
#define BFP(BT, SDF, SDAF, VF, SVF, SVAF, SDX3F, SDX8F, SDX4DF)\
vpx_usec_timer_start(&timer);
-#if CONFIG_SPATIAL_SVC
- if (is_two_pass_svc(cpi))
- res = vp9_svc_lookahead_push(cpi, cpi->lookahead, sd, time_stamp, end_time,
- frame_flags);
- else
-#endif
- res = vp9_lookahead_push(cpi->lookahead,
- sd, time_stamp, end_time, frame_flags);
- if (res)
+ if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags))
res = -1;
vpx_usec_timer_mark(&timer);
cpi->time_receive_data += vpx_usec_timer_elapsed(&timer);
MV_REFERENCE_FRAME ref_frame;
int arf_src_index;
- if (is_two_pass_svc(cpi) && oxcf->pass == 2) {
+ if (is_two_pass_svc(cpi)) {
#if CONFIG_SPATIAL_SVC
- vp9_svc_lookahead_peek(cpi, cpi->lookahead, 0, 1);
+ vp9_svc_start_frame(cpi);
#endif
- vp9_restore_layer_context(cpi);
+ if (oxcf->pass == 2)
+ vp9_restore_layer_context(cpi);
}
vpx_usec_timer_start(&cmptimer);
if (arf_src_index) {
assert(arf_src_index <= rc->frames_to_key);
-#if CONFIG_SPATIAL_SVC
- if (is_two_pass_svc(cpi))
- source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, arf_src_index, 0);
- else
-#endif
- source = vp9_lookahead_peek(cpi->lookahead, arf_src_index);
- if (source != NULL) {
+ if ((source = vp9_lookahead_peek(cpi->lookahead, arf_src_index)) != NULL) {
cpi->alt_ref_source = source;
#if CONFIG_SPATIAL_SVC
if (!source) {
// Get last frame source.
if (cm->current_video_frame > 0) {
-#if CONFIG_SPATIAL_SVC
- if (is_two_pass_svc(cpi))
- last_source = vp9_svc_lookahead_peek(cpi, cpi->lookahead, -1, 0);
- else
-#endif
- last_source = vp9_lookahead_peek(cpi->lookahead, -1);
- if (last_source == NULL)
+ if ((last_source = vp9_lookahead_peek(cpi->lookahead, -1)) == NULL)
return -1;
}
}
#endif
+
+ if (is_two_pass_svc(cpi) && 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;
}
int64_t ts_start;
int64_t ts_end;
unsigned int flags;
-
-#if CONFIG_SPATIAL_SVC
- vpx_svc_parameters_t svc_params[VPX_SS_MAX_LAYERS];
-#endif
};
// The max of past frames we want to keep in the queue.
THR_NEARMV,
THR_NEARA,
+ THR_NEARG,
+
+ THR_ZEROMV,
+ THR_ZEROG,
+ THR_ZEROA,
+
THR_COMP_NEARESTLA,
THR_COMP_NEARESTGA,
THR_COMP_NEARLA,
THR_COMP_NEWLA,
- THR_NEARG,
THR_COMP_NEARGA,
THR_COMP_NEWGA,
- THR_ZEROMV,
- THR_ZEROG,
- THR_ZEROA,
THR_COMP_ZEROLA,
THR_COMP_ZEROGA,
int threshes[MAX_SEGMENTS][BLOCK_SIZES][MAX_MODES];
int thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
+ int mode_map[BLOCK_SIZES][MAX_MODES];
+
int64_t comp_pred_diff[REFERENCE_MODES];
int64_t prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
int64_t tx_select_diff[TX_MODES];
{NEARMV, {LAST_FRAME, NONE}},
{NEARMV, {ALTREF_FRAME, NONE}},
+ {NEARMV, {GOLDEN_FRAME, NONE}},
+
+ {ZEROMV, {LAST_FRAME, NONE}},
+ {ZEROMV, {GOLDEN_FRAME, NONE}},
+ {ZEROMV, {ALTREF_FRAME, NONE}},
+
{NEARESTMV, {LAST_FRAME, ALTREF_FRAME}},
{NEARESTMV, {GOLDEN_FRAME, ALTREF_FRAME}},
{NEARMV, {LAST_FRAME, ALTREF_FRAME}},
{NEWMV, {LAST_FRAME, ALTREF_FRAME}},
- {NEARMV, {GOLDEN_FRAME, NONE}},
{NEARMV, {GOLDEN_FRAME, ALTREF_FRAME}},
{NEWMV, {GOLDEN_FRAME, ALTREF_FRAME}},
- {ZEROMV, {LAST_FRAME, NONE}},
- {ZEROMV, {GOLDEN_FRAME, NONE}},
- {ZEROMV, {ALTREF_FRAME, NONE}},
{ZEROMV, {LAST_FRAME, ALTREF_FRAME}},
{ZEROMV, {GOLDEN_FRAME, ALTREF_FRAME}},
int64_t best_filter_diff[SWITCHABLE_FILTER_CONTEXTS];
MB_MODE_INFO best_mbmode;
int best_mode_skippable = 0;
- int mode_index, best_mode_index = -1;
+ int midx, best_mode_index = -1;
unsigned int ref_costs_single[MAX_REF_FRAMES], ref_costs_comp[MAX_REF_FRAMES];
vp9_prob comp_mode_p;
int64_t best_intra_rd = INT64_MAX;
int mode_skip_start = cpi->sf.mode_skip_start + 1;
const int *const rd_threshes = rd_opt->threshes[segment_id][bsize];
const int *const rd_thresh_freq_fact = rd_opt->thresh_freq_fact[bsize];
+ int mode_threshold[MAX_MODES];
+ int *mode_map = rd_opt->mode_map[bsize];
const int mode_search_skip_flags = cpi->sf.mode_search_skip_flags;
vp9_zero(best_mbmode);
+
x->skip_encode = cpi->sf.skip_encode_frame && x->q_index < QIDX_SKIP_THRESH;
estimate_ref_frame_costs(cm, xd, segment_id, ref_costs_single, ref_costs_comp,
mode_skip_mask[INTRA_FRAME] |=
~(cpi->sf.intra_y_mode_mask[max_txsize_lookup[bsize]]);
- for (mode_index = 0; mode_index < MAX_MODES; ++mode_index) {
+ for (i = 0; i < MAX_MODES; ++i)
+ mode_threshold[i] = ((int64_t)rd_threshes[i] * rd_thresh_freq_fact[i]) >> 5;
+
+ midx = cpi->sf.schedule_mode_search ? mode_skip_start : 0;
+ while (midx > 4) {
+ uint8_t end_pos = 0;
+ for (i = 5; i < midx; ++i) {
+ if (mode_threshold[mode_map[i - 1]] > mode_threshold[mode_map[i]]) {
+ uint8_t tmp = mode_map[i];
+ mode_map[i] = mode_map[i - 1];
+ mode_map[i - 1] = tmp;
+ end_pos = i;
+ }
+ }
+ midx = end_pos;
+ }
+
+ for (midx = 0; midx < MAX_MODES; ++midx) {
+ int mode_index = mode_map[midx];
int mode_excluded = 0;
int64_t this_rd = INT64_MAX;
int disable_skip = 0;
int64_t distortion2 = 0, distortion_y = 0, distortion_uv = 0;
int skippable = 0;
int64_t tx_cache[TX_MODES];
- int i;
int this_skip2 = 0;
int64_t total_sse = INT64_MAX;
int early_term = 0;
// Look at the reference frame of the best mode so far and set the
// skip mask to look at a subset of the remaining modes.
- if (mode_index == mode_skip_start && best_mode_index >= 0) {
+ if (midx == mode_skip_start && best_mode_index >= 0) {
switch (best_mbmode.ref_frame[0]) {
case INTRA_FRAME:
break;
continue;
// Test best rd so far against threshold for trying this mode.
- if (rd_less_than_thresh(best_rd, rd_threshes[mode_index],
- rd_thresh_freq_fact[mode_index]))
+ if (best_mode_skippable && cpi->sf.schedule_mode_search)
+ mode_threshold[mode_index] <<= 1;
+
+ if (best_rd < mode_threshold[mode_index])
continue;
if (cpi->sf.motion_field_mode_search) {
(cm->interp_filter == best_mbmode.interp_filter) ||
!is_inter_block(&best_mbmode));
- update_rd_thresh_fact(cpi, bsize, best_mode_index);
+ if (!cpi->rc.is_src_frame_alt_ref)
+ update_rd_thresh_fact(cpi, bsize, best_mode_index);
// macroblock modes
*mbmi = best_mbmode;
: USE_LARGESTALL;
if (MIN(cm->width, cm->height) >= 720) {
sf->disable_split_mask = DISABLE_ALL_SPLIT;
+ sf->schedule_mode_search = cm->base_qindex < 220 ? 1 : 0;
} else {
sf->max_intra_bsize = BLOCK_32X32;
sf->disable_split_mask = DISABLE_ALL_INTER_SPLIT;
+ sf->schedule_mode_search = cm->base_qindex < 175 ? 1 : 0;
}
sf->adaptive_pred_interp_filter = 0;
sf->adaptive_mode_search = 1;
sf->use_fast_coef_updates = TWO_LOOP;
sf->use_fast_coef_costing = 0;
sf->mode_skip_start = MAX_MODES; // Mode index at which mode skip mask set
+ sf->schedule_mode_search = 0;
sf->use_nonrd_pick_mode = 0;
for (i = 0; i < BLOCK_SIZES; ++i)
sf->inter_mode_mask[i] = INTER_ALL;
// point for this motion search and limits the search range around it.
int adaptive_motion_search;
+ int schedule_mode_search;
+
// Allows sub 8x8 modes to use the prediction filter that was determined
// best for 8x8 mode. If set to 0 we always re check all the filters for
// sizes less than 8x8, 1 means we check all filter modes if no 8x8 filter
}
#if CONFIG_SPATIAL_SVC
-int vp9_svc_lookahead_push(const VP9_COMP *const cpi, struct lookahead_ctx *ctx,
- YV12_BUFFER_CONFIG *src, int64_t ts_start,
- int64_t ts_end, unsigned int flags) {
- struct lookahead_entry *buf;
- int i, index;
+static void get_layer_resolution(const int width_org, const int height_org,
+ const int num, const int den,
+ int *width_out, int *height_out) {
+ int w, h;
- if (vp9_lookahead_push(ctx, src, ts_start, ts_end, flags))
- return 1;
+ if (width_out == NULL || height_out == NULL || den == 0)
+ return;
- index = ctx->write_idx - 1;
- if (index < 0)
- index += ctx->max_sz;
+ w = width_org * num / den;
+ h = height_org * num / den;
- buf = ctx->buf + index;
+ // make height and width even to make chrome player happy
+ w += w % 2;
+ h += h % 2;
- if (buf == NULL)
- return 1;
-
- // Store svc parameters for each layer
- for (i = 0; i < cpi->svc.number_spatial_layers; ++i)
- buf->svc_params[i] = cpi->svc.layer_context[i].svc_params_received;
-
- return 0;
+ *width_out = w;
+ *height_out = h;
}
-static int copy_svc_params(VP9_COMP *const cpi, struct lookahead_entry *buf) {
- int layer_id;
- vpx_svc_parameters_t *layer_param;
+int vp9_svc_start_frame(VP9_COMP *const cpi) {
+ int width = 0, height = 0;
LAYER_CONTEXT *lc;
int count = 1 << (cpi->svc.number_temporal_layers - 1);
- // Find the next layer to be encoded
- for (layer_id = 0; layer_id < cpi->svc.number_spatial_layers; ++layer_id) {
- if (buf->svc_params[layer_id].spatial_layer >=0)
- break;
- }
-
- if (layer_id == cpi->svc.number_spatial_layers)
- return 1;
-
- layer_param = &buf->svc_params[layer_id];
- cpi->svc.spatial_layer_id = layer_param->spatial_layer;
- cpi->svc.temporal_layer_id = layer_param->temporal_layer;
- cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
-
+ cpi->svc.spatial_layer_id = cpi->svc.spatial_layer_to_encode;
lc = &cpi->svc.layer_context[cpi->svc.spatial_layer_id];
cpi->svc.temporal_layer_id = 0;
count >>= 1;
}
+ cpi->ref_frame_flags = VP9_ALT_FLAG | VP9_GOLD_FLAG | VP9_LAST_FLAG;
+
cpi->lst_fb_idx = cpi->svc.spatial_layer_id;
if (cpi->svc.spatial_layer_id == 0)
}
}
- if (vp9_set_size_literal(cpi, layer_param->width, layer_param->height) != 0)
+ 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;
- cpi->oxcf.worst_allowed_q =
- vp9_quantizer_to_qindex(layer_param->max_quantizer);
- cpi->oxcf.best_allowed_q =
- vp9_quantizer_to_qindex(layer_param->min_quantizer);
+ cpi->oxcf.worst_allowed_q = vp9_quantizer_to_qindex(lc->max_q);
+ cpi->oxcf.best_allowed_q = vp9_quantizer_to_qindex(lc->min_q);
vp9_change_config(cpi, &cpi->oxcf);
return 0;
}
-struct lookahead_entry *vp9_svc_lookahead_peek(VP9_COMP *const cpi,
- struct lookahead_ctx *ctx,
- int index, int copy_params) {
- struct lookahead_entry *buf = vp9_lookahead_peek(ctx, index);
-
- if (buf != NULL && copy_params != 0) {
- if (copy_svc_params(cpi, buf) != 0)
- return NULL;
- }
- return buf;
-}
-
struct lookahead_entry *vp9_svc_lookahead_pop(VP9_COMP *const cpi,
struct lookahead_ctx *ctx,
int drain) {
struct lookahead_entry *buf = NULL;
if (ctx->sz && (drain || ctx->sz == ctx->max_sz - MAX_PRE_FRAMES)) {
- buf = vp9_svc_lookahead_peek(cpi, ctx, 0, 1);
+ buf = vp9_lookahead_peek(ctx, 0);
if (buf != NULL) {
- // Only remove the buffer when pop the highest layer. Simply set the
- // spatial_layer to -1 for lower layers.
- buf->svc_params[cpi->svc.spatial_layer_id].spatial_layer = -1;
+ // Only remove the buffer when pop the highest layer.
if (cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) {
vp9_lookahead_pop(ctx, drain);
}
int target_bandwidth;
double framerate;
int avg_frame_size;
+ int max_q;
+ int min_q;
+ int scaling_factor_num;
+ int scaling_factor_den;
TWO_PASS twopass;
vpx_fixed_buf_t rc_twopass_stats_in;
unsigned int current_video_frame_in_layer;
int is_key_frame;
int frames_from_key_frame;
FRAME_TYPE last_frame_type;
- vpx_svc_parameters_t svc_params_received;
struct lookahead_entry *alt_ref_source;
int alt_ref_idx;
int gold_ref_idx;
int number_spatial_layers;
int number_temporal_layers;
+ int spatial_layer_to_encode;
+
// Store scaled source frames to be used for temporal filter to generate
// a alt ref frame.
YV12_BUFFER_CONFIG scaled_frames[MAX_LAG_BUFFERS];
// Check if current layer is key frame in spatial upper layer
int vp9_is_upper_layer_key_frame(const struct VP9_COMP *const cpi);
-// Copy the source image, flags and svc parameters into a new framebuffer
-// with the expected stride/border
-int vp9_svc_lookahead_push(const struct VP9_COMP *const cpi,
- struct lookahead_ctx *ctx, YV12_BUFFER_CONFIG *src,
- int64_t ts_start, int64_t ts_end,
- unsigned int flags);
-
// Get the next source buffer to encode
struct lookahead_entry *vp9_svc_lookahead_pop(struct VP9_COMP *const cpi,
struct lookahead_ctx *ctx,
int drain);
-// Get a future source buffer to encode
-struct lookahead_entry *vp9_svc_lookahead_peek(struct VP9_COMP *const cpi,
- struct lookahead_ctx *ctx,
- int index, int copy_params);
+// Start a frame and initialize svc parameters
+int vp9_svc_start_frame(struct VP9_COMP *const cpi);
#ifdef __cplusplus
} // extern "C"
static vpx_codec_err_t ctrl_set_svc_parameters(vpx_codec_alg_priv_t *ctx,
va_list args) {
VP9_COMP *const cpi = ctx->cpi;
- vpx_svc_parameters_t *const params = va_arg(args, vpx_svc_parameters_t *);
+ vpx_svc_extra_cfg_t *const params = va_arg(args, vpx_svc_extra_cfg_t *);
+ int i;
- if (params == NULL || params->spatial_layer < 0 ||
- params->spatial_layer >= cpi->svc.number_spatial_layers)
- return VPX_CODEC_INVALID_PARAM;
+ for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
+ LAYER_CONTEXT *lc = &cpi->svc.layer_context[i];
- if (params->spatial_layer == 0) {
- int i;
- for (i = 0; i < cpi->svc.number_spatial_layers; ++i) {
- cpi->svc.layer_context[i].svc_params_received.spatial_layer = -1;
- }
+ lc->max_q = params->max_quantizers[i];
+ lc->min_q = params->min_quantizers[i];
+ lc->scaling_factor_num = params->scaling_factor_num[i];
+ lc->scaling_factor_den = params->scaling_factor_den[i];
}
- cpi->svc.layer_context[params->spatial_layer].svc_params_received =
- *params;
-
return VPX_CODEC_OK;
}
text vpx_svc_init
text vpx_svc_release
text vpx_svc_set_options
-text vpx_svc_set_quantizers
-text vpx_svc_set_scale_factors
-text vpx_svc_get_layer_resolution
#define SVC_REFERENCE_FRAMES 8
#define SUPERFRAME_SLOTS (8)
#define SUPERFRAME_BUFFER_SIZE (SUPERFRAME_SLOTS * sizeof(uint32_t) + 2)
-#define OPTION_BUFFER_SIZE 256
+#define OPTION_BUFFER_SIZE 1024
#define COMPONENTS 4 // psnr & sse statistics maintained for total, y, u, v
-static const int DEFAULT_QUANTIZER_VALUES[VPX_SS_MAX_LAYERS] = {
- 60, 53, 39, 33, 27
-};
+#define MAX_QUANTIZER 63
static const int DEFAULT_SCALE_FACTORS_NUM[VPX_SS_MAX_LAYERS] = {
4, 5, 7, 11, 16
typedef struct SvcInternal {
char options[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_options
- char quantizers[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_quantizers
- char scale_factors[OPTION_BUFFER_SIZE]; // set by vpx_svc_set_scale_factors
// values extracted from option, quantizers
- int scaling_factor_num[VPX_SS_MAX_LAYERS];
- int scaling_factor_den[VPX_SS_MAX_LAYERS];
- int quantizer[VPX_SS_MAX_LAYERS];
+ vpx_svc_extra_cfg_t svc_params;
int enable_auto_alt_ref[VPX_SS_MAX_LAYERS];
int bitrates[VPX_SS_MAX_LAYERS];
if (*value0 < option_min_values[SCALE_FACTOR] ||
*value1 < option_min_values[SCALE_FACTOR] ||
*value0 > option_max_values[SCALE_FACTOR] ||
- *value1 > option_max_values[SCALE_FACTOR])
+ *value1 > option_max_values[SCALE_FACTOR] ||
+ *value0 > *value1) // num shouldn't be greater than den
return VPX_CODEC_INVALID_PARAM;
} else {
*value0 = atoi(input);
svc_ctx->temporal_layers = atoi(option_value);
} else if (strcmp("scale-factors", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR, option_value,
- si->scaling_factor_num,
- si->scaling_factor_den);
+ si->svc_params.scaling_factor_num,
+ si->svc_params.scaling_factor_den);
+ if (res != VPX_CODEC_OK) break;
+ } else if (strcmp("max-quantizers", option_name) == 0) {
+ res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
+ si->svc_params.max_quantizers,
+ NULL);
if (res != VPX_CODEC_OK) break;
- } else if (strcmp("quantizers", option_name) == 0) {
+ } else if (strcmp("min-quantizers", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, QUANTIZER, option_value,
- si->quantizer, NULL);
+ si->svc_params.min_quantizers,
+ NULL);
if (res != VPX_CODEC_OK) break;
} else if (strcmp("auto-alt-refs", option_name) == 0) {
res = parse_layer_options_from_string(svc_ctx, AUTO_ALT_REF, option_value,
}
free(input_string);
+ for (i = 0; i < svc_ctx->spatial_layers; ++i) {
+ if (si->svc_params.max_quantizers[i] > MAX_QUANTIZER ||
+ si->svc_params.max_quantizers[i] < 0 ||
+ si->svc_params.min_quantizers[i] > si->svc_params.max_quantizers[i] ||
+ si->svc_params.min_quantizers[i] < 0)
+ res = VPX_CODEC_INVALID_PARAM;
+ }
+
if (si->use_multiple_frame_contexts &&
(svc_ctx->spatial_layers > 3 ||
svc_ctx->spatial_layers * svc_ctx->temporal_layers > 4))
return VPX_CODEC_OK;
}
-vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
- const char *quantizers) {
- SvcInternal *const si = get_svc_internal(svc_ctx);
- if (svc_ctx == NULL || quantizers == NULL || si == NULL) {
- return VPX_CODEC_INVALID_PARAM;
- }
- strncpy(si->quantizers, quantizers, sizeof(si->quantizers));
- si->quantizers[sizeof(si->quantizers) - 1] = '\0';
- return VPX_CODEC_OK;
-}
-
-vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
- const char *scale_factors) {
- SvcInternal *const si = get_svc_internal(svc_ctx);
- if (svc_ctx == NULL || scale_factors == NULL || si == NULL) {
- return VPX_CODEC_INVALID_PARAM;
- }
- strncpy(si->scale_factors, scale_factors, sizeof(si->scale_factors));
- si->scale_factors[sizeof(si->scale_factors) - 1] = '\0';
- return VPX_CODEC_OK;
-}
-
void assign_layer_bitrates(const SvcContext *svc_ctx,
vpx_codec_enc_cfg_t *const enc_cfg) {
int i;
float alloc_ratio[VPX_SS_MAX_LAYERS] = {0};
for (i = 0; i < svc_ctx->spatial_layers; ++i) {
- if (si->scaling_factor_den[i] > 0) {
- alloc_ratio[i] = (float)(si->scaling_factor_num[i] * 1.0 /
- si->scaling_factor_den[i]);
+ if (si->svc_params.scaling_factor_den[i] > 0) {
+ alloc_ratio[i] = (float)(si->svc_params.scaling_factor_num[i] * 1.0 /
+ si->svc_params.scaling_factor_den[i]);
alloc_ratio[i] *= alloc_ratio[i];
total += alloc_ratio[i];
}
for (i = 0; i < VPX_SS_MAX_LAYERS; ++i) {
- si->quantizer[i] = DEFAULT_QUANTIZER_VALUES[i];
- si->scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i];
- si->scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i];
- }
-
- if (strlen(si->quantizers) > 0) {
- res = parse_layer_options_from_string(svc_ctx, QUANTIZER, si->quantizers,
- si->quantizer, NULL);
- if (res != VPX_CODEC_OK)
- return res;
- }
-
- if (strlen(si->scale_factors) > 0) {
- res = parse_layer_options_from_string(svc_ctx, SCALE_FACTOR,
- si->scale_factors,
- si->scaling_factor_num,
- si->scaling_factor_den);
- if (res != VPX_CODEC_OK)
- return res;
+ si->svc_params.max_quantizers[i] = MAX_QUANTIZER;
+ si->svc_params.min_quantizers[i] = 0;
+ si->svc_params.scaling_factor_num[i] = DEFAULT_SCALE_FACTORS_NUM[i];
+ si->svc_params.scaling_factor_den[i] = DEFAULT_SCALE_FACTORS_DEN[i];
}
// Parse aggregate command line options. Options must start with
}
vpx_codec_control(codec_ctx, VP9E_SET_SVC, 1);
+ vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &si->svc_params);
return VPX_CODEC_OK;
}
-vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
- int layer,
- unsigned int *width,
- unsigned int *height) {
- int w, h, num, den;
- const SvcInternal *const si = get_const_svc_internal(svc_ctx);
-
- if (svc_ctx == NULL || si == NULL || width == NULL || height == NULL)
- return VPX_CODEC_INVALID_PARAM;
- if (layer < 0 || layer >= svc_ctx->spatial_layers)
- return VPX_CODEC_INVALID_PARAM;
-
- num = si->scaling_factor_num[layer];
- den = si->scaling_factor_den[layer];
- if (num == 0 || den == 0) return VPX_CODEC_INVALID_PARAM;
-
- w = si->width * num / den;
- h = si->height * num / den;
-
- // make height and width even to make chrome player happy
- w += w % 2;
- h += h % 2;
-
- *width = w;
- *height = h;
-
- return VPX_CODEC_OK;
-}
-
-static void set_svc_parameters(SvcContext *svc_ctx,
- vpx_codec_ctx_t *codec_ctx) {
- int layer;
- vpx_svc_parameters_t svc_params;
- SvcInternal *const si = get_svc_internal(svc_ctx);
-
- memset(&svc_params, 0, sizeof(svc_params));
- svc_params.temporal_layer = 0;
- svc_params.spatial_layer = si->layer;
-
- layer = si->layer;
- if (VPX_CODEC_OK != vpx_svc_get_layer_resolution(svc_ctx, layer,
- &svc_params.width,
- &svc_params.height)) {
- svc_log(svc_ctx, SVC_LOG_ERROR, "vpx_svc_get_layer_resolution failed\n");
- }
-
- if (codec_ctx->config.enc->g_pass == VPX_RC_ONE_PASS) {
- svc_params.min_quantizer = si->quantizer[layer];
- svc_params.max_quantizer = si->quantizer[layer];
- } else {
- svc_params.min_quantizer = codec_ctx->config.enc->rc_min_quantizer;
- svc_params.max_quantizer = codec_ctx->config.enc->rc_max_quantizer;
- }
-
- vpx_codec_control(codec_ctx, VP9E_SET_SVC_PARAMETERS, &svc_params);
-}
-
/**
* Encode a frame into multiple layers
* Create a superframe containing the individual layers
svc_log_reset(svc_ctx);
- if (rawimg != NULL) {
- // encode each layer
- for (si->layer = 0; si->layer < svc_ctx->spatial_layers; ++si->layer) {
- set_svc_parameters(svc_ctx, codec_ctx);
- }
- }
-
res = vpx_codec_encode(codec_ctx, rawimg, pts, (uint32_t)duration, 0,
deadline);
if (res != VPX_CODEC_OK) {
vpx_codec_err_t vpx_svc_set_options(SvcContext *svc_ctx, const char *options);
/**
- * Set SVC quantizer values
- * values comma separated, ordered from lowest resolution to highest
- * e.g., "60,53,39,33,27"
- */
-vpx_codec_err_t vpx_svc_set_quantizers(SvcContext *svc_ctx,
- const char *quantizer_values);
-
-/**
- * Set SVC scale factors
- * values comma separated, ordered from lowest resolution to highest
- * e.g., "4/16,5/16,7/16,11/16,16/16"
- */
-vpx_codec_err_t vpx_svc_set_scale_factors(SvcContext *svc_ctx,
- const char *scale_factors);
-
-/**
* initialize SVC encoding
*/
vpx_codec_err_t vpx_svc_init(SvcContext *svc_ctx, vpx_codec_ctx_t *codec_ctx,
*/
const char *vpx_svc_get_message(const SvcContext *svc_ctx);
-/**
- * return spatial resolution of the specified layer
- */
-vpx_codec_err_t vpx_svc_get_layer_resolution(const SvcContext *svc_ctx,
- int layer,
- unsigned int *width,
- unsigned int *height);
-
#ifdef __cplusplus
} // extern "C"
#endif
VP8_TUNE_SSIM
} vp8e_tuning;
-/*!\brief vp9 svc parameters
- *
- * This defines parameters for svc encoding.
- *
- */
-typedef struct vpx_svc_parameters {
- unsigned int width; /**< width of current spatial layer */
- unsigned int height; /**< height of current spatial layer */
- int spatial_layer; /**< current spatial layer number - 0 = base */
- int temporal_layer; /**< current temporal layer number - 0 = base */
- int max_quantizer; /**< max quantizer for current layer */
- int min_quantizer; /**< min quantizer for current layer */
- int lst_fb_idx; /**< last frame frame buffer index */
- int gld_fb_idx; /**< golden frame frame buffer index */
- int alt_fb_idx; /**< alt reference frame frame buffer index */
-} vpx_svc_parameters_t;
-
/*!\brief vp9 svc layer parameters
*
* This defines the spatial and temporal layer id numbers for svc encoding.
VPX_CTRL_USE_TYPE(VP8E_SET_SCALEMODE, vpx_scaling_mode_t *)
VPX_CTRL_USE_TYPE(VP9E_SET_SVC, int)
-VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, vpx_svc_parameters_t *)
+VPX_CTRL_USE_TYPE(VP9E_SET_SVC_PARAMETERS, void *)
VPX_CTRL_USE_TYPE(VP9E_SET_SVC_LAYER_ID, vpx_svc_layer_id_t *)
VPX_CTRL_USE_TYPE(VP8E_SET_CPUUSED, int)
unsigned int ts_layer_id[VPX_TS_MAX_PERIODICITY];
} vpx_codec_enc_cfg_t; /**< alias for struct vpx_codec_enc_cfg */
+ /*!\brief vp9 svc extra configure parameters
+ *
+ * This defines max/min quantizers and scale factors for each layer
+ *
+ */
+ typedef struct vpx_svc_parameters {
+ int max_quantizers[VPX_SS_MAX_LAYERS];
+ int min_quantizers[VPX_SS_MAX_LAYERS];
+ int scaling_factor_num[VPX_SS_MAX_LAYERS];
+ int scaling_factor_den[VPX_SS_MAX_LAYERS];
+ } vpx_svc_extra_cfg_t;
+
/*!\brief Initialize an encoder instance
*