From 6b2e4061235f39978ec186afad0534330e049858 Mon Sep 17 00:00:00 2001 From: Minghai Shang Date: Thu, 27 Mar 2014 13:43:20 -0700 Subject: [PATCH] [svc] Verify and store input two pass stats data in 2nd pass rc Change-Id: Ib09eedc17ea0ea2eec75d78112e4786d98f382aa --- test/svc_test.cc | 29 +++++++++++++++++ test/test-data.sha1 | 1 + test/test.mk | 1 + vp9/encoder/vp9_onyx_if.c | 52 ++++++++++++++++++++++++++++-- vp9/encoder/vp9_svc_layercontext.h | 1 + vp9/vp9_cx_iface.c | 48 ++++++++++++++++++++++----- 6 files changed, 121 insertions(+), 11 deletions(-) diff --git a/test/svc_test.cc b/test/svc_test.cc index dff2ec767..30508dfec 100644 --- a/test/svc_test.cc +++ b/test/svc_test.cc @@ -31,6 +31,7 @@ class SvcTest : public ::testing::Test { SvcTest() : codec_iface_(0), test_file_name_("hantro_collage_w352h288.yuv"), + stats_file_name_("hantro_collage_w352h288.stat"), codec_initialized_(false), decoder_(0) { memset(&svc_, 0, sizeof(svc_)); @@ -73,6 +74,7 @@ class SvcTest : public ::testing::Test { struct vpx_codec_enc_cfg codec_enc_; vpx_codec_iface_t *codec_iface_; std::string test_file_name_; + std::string stats_file_name_; bool codec_initialized_; Decoder *decoder_; }; @@ -397,4 +399,31 @@ TEST_F(SvcTest, FirstPassEncode) { EXPECT_GT(vpx_svc_get_rc_stats_buffer_size(&svc_), 0U); } +TEST_F(SvcTest, SecondPassEncode) { + svc_.spatial_layers = 2; + codec_enc_.g_pass = VPX_RC_LAST_PASS; + + FILE *const stats_file = libvpx_test::OpenTestDataFile(stats_file_name_); + ASSERT_TRUE(stats_file != NULL) << "Stats file open failed. Filename: " + << stats_file; + + struct vpx_fixed_buf stats_buf; + fseek(stats_file, 0, SEEK_END); + stats_buf.sz = static_cast(ftell(stats_file)); + fseek(stats_file, 0, SEEK_SET); + + stats_buf.buf = malloc(stats_buf.sz); + ASSERT_TRUE(stats_buf.buf != NULL); + const size_t bytes_read = fread(stats_buf.buf, 1, stats_buf.sz, stats_file); + ASSERT_EQ(bytes_read, stats_buf.sz); + fclose(stats_file); + codec_enc_.rc_twopass_stats_in = stats_buf; + + const vpx_codec_err_t res = + vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); + ASSERT_EQ(VPX_CODEC_OK, res); + + free(stats_buf.buf); +} + } // namespace diff --git a/test/test-data.sha1 b/test/test-data.sha1 index 6f718ef6c..981aa4ff6 100644 --- a/test/test-data.sha1 +++ b/test/test-data.sha1 @@ -1,4 +1,5 @@ d5dfb0151c9051f8c85999255645d7a23916d3c0 hantro_collage_w352h288.yuv +2752863aa6330a93eaeb30f883310f87aa3de87c hantro_collage_w352h288.stat b87815bf86020c592ccc7a846ba2e28ec8043902 hantro_odd.yuv b1f1c3ec79114b9a0651af24ce634afb44a9a419 rush_hour_444.y4m 5184c46ddca8b1fadd16742e8500115bc8f749da vp80-00-comprehensive-001.ivf diff --git a/test/test.mk b/test/test.mk index 175bc520f..31baf059c 100644 --- a/test/test.mk +++ b/test/test.mk @@ -122,6 +122,7 @@ endif # CONFIG_SHARED ## TEST DATA ## LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv +LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.stat LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_odd.yuv LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 444720915..e30f5346a 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -177,6 +177,7 @@ void vp9_initialize_enc() { static void dealloc_compressor_data(VP9_COMP *cpi) { VP9_COMMON *const cm = &cpi->common; + int i; // Delete sementation map vpx_free(cpi->segmentation_map); @@ -210,6 +211,13 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { cpi->mb_activity_map = 0; vpx_free(cpi->mb_norm_activity_map); cpi->mb_norm_activity_map = 0; + + for (i = 0; i < cpi->svc.number_spatial_layers; ++i) { + LAYER_CONTEXT *const lc = &cpi->svc.layer_context[i]; + vpx_free(lc->rc_twopass_stats_in.buf); + lc->rc_twopass_stats_in.buf = NULL; + lc->rc_twopass_stats_in.sz = 0; + } } // Computes a q delta (in "q index" terms) to get from a starting q value @@ -1750,9 +1758,47 @@ VP9_COMP *vp9_create_compressor(VP9_CONFIG *oxcf) { const size_t packet_sz = sizeof(FIRSTPASS_STATS); const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz); - cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf; - cpi->twopass.stats_in = cpi->twopass.stats_in_start; - cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1]; + if (cpi->svc.number_spatial_layers > 1 + && cpi->svc.number_temporal_layers == 1) { + FIRSTPASS_STATS *const stats = oxcf->two_pass_stats_in.buf; + FIRSTPASS_STATS *stats_copy[VPX_SS_MAX_LAYERS] = {0}; + int i; + + for (i = 0; i < oxcf->ss_number_layers; ++i) { + FIRSTPASS_STATS *const last_packet_for_layer = + &stats[packets - oxcf->ss_number_layers + i]; + const int layer_id = last_packet_for_layer->spatial_layer_id; + const int packets_in_layer = (int)last_packet_for_layer->count + 1; + if (layer_id >= 0 && layer_id < oxcf->ss_number_layers) { + LAYER_CONTEXT *const lc = &cpi->svc.layer_context[layer_id]; + + vpx_free(lc->rc_twopass_stats_in.buf); + + lc->rc_twopass_stats_in.sz = packets_in_layer * packet_sz; + CHECK_MEM_ERROR(cm, lc->rc_twopass_stats_in.buf, + vpx_malloc(lc->rc_twopass_stats_in.sz)); + lc->twopass.stats_in_start = lc->rc_twopass_stats_in.buf; + lc->twopass.stats_in = lc->twopass.stats_in_start; + lc->twopass.stats_in_end = lc->twopass.stats_in_start + + packets_in_layer - 1; + stats_copy[layer_id] = lc->rc_twopass_stats_in.buf; + } + } + + for (i = 0; i < packets; ++i) { + const int layer_id = stats[i].spatial_layer_id; + if (layer_id >= 0 && layer_id < oxcf->ss_number_layers + && stats_copy[layer_id] != NULL) { + *stats_copy[layer_id] = stats[i]; + ++stats_copy[layer_id]; + } + } + } else { + cpi->twopass.stats_in_start = oxcf->two_pass_stats_in.buf; + cpi->twopass.stats_in = cpi->twopass.stats_in_start; + cpi->twopass.stats_in_end = &cpi->twopass.stats_in[packets - 1]; + } + vp9_init_second_pass(cpi); } diff --git a/vp9/encoder/vp9_svc_layercontext.h b/vp9/encoder/vp9_svc_layercontext.h index e81b0b7c8..afbbdf086 100644 --- a/vp9/encoder/vp9_svc_layercontext.h +++ b/vp9/encoder/vp9_svc_layercontext.h @@ -28,6 +28,7 @@ typedef struct { double framerate; int avg_frame_size; struct twopass_rc twopass; + struct vpx_fixed_buf rc_twopass_stats_in; } LAYER_CONTEXT; typedef struct { diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 30c2c49e6..84b61eba4 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -221,14 +221,43 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, if (cfg->rc_twopass_stats_in.sz % packet_sz) ERROR("rc_twopass_stats_in.sz indicates truncated packet."); - if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz) - ERROR("rc_twopass_stats_in requires at least two packets."); + if (cfg->ss_number_layers > 1) { + int i; + unsigned int n_packets_per_layer[VPX_SS_MAX_LAYERS] = {0}; - stats = - (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1; + stats = cfg->rc_twopass_stats_in.buf; + for (i = 0; i < n_packets; ++i) { + const int layer_id = stats[i].spatial_layer_id; + if (layer_id >= 0 && layer_id < (int)cfg->ss_number_layers) { + ++n_packets_per_layer[layer_id]; + } + } - if ((int)(stats->count + 0.5) != n_packets - 1) - ERROR("rc_twopass_stats_in missing EOS stats packet"); + for (i = 0; i < (int)cfg->ss_number_layers; ++i) { + unsigned int layer_id; + if (n_packets_per_layer[i] < 2) { + ERROR("rc_twopass_stats_in requires at least two packets for each " + "layer."); + } + + stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + + n_packets - cfg->ss_number_layers + i; + layer_id = stats->spatial_layer_id; + + if (layer_id >= cfg->ss_number_layers + ||(int)(stats->count + 0.5) != n_packets_per_layer[layer_id] - 1) + ERROR("rc_twopass_stats_in missing EOS stats packet"); + } + } else { + if (cfg->rc_twopass_stats_in.sz < 2 * packet_sz) + ERROR("rc_twopass_stats_in requires at least two packets."); + + stats = + (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf + n_packets - 1; + + if ((int)(stats->count + 0.5) != n_packets - 1) + ERROR("rc_twopass_stats_in missing EOS stats packet"); + } } return VPX_CODEC_OK; @@ -990,9 +1019,12 @@ static vpx_codec_err_t vp9e_set_svc(vpx_codec_alg_priv_t *ctx, int ctr_id, va_list args) { int data = va_arg(args, int); vp9_set_svc(ctx->cpi, data); - // CBR mode for SVC with both temporal and spatial layers not yet supported. + // CBR or two pass mode for SVC with both temporal and spatial layers + // not yet supported. if (data == 1 && - ctx->cfg.rc_end_usage == VPX_CBR && + (ctx->cfg.rc_end_usage == VPX_CBR || + ctx->cfg.g_pass == VPX_RC_FIRST_PASS || + ctx->cfg.g_pass == VPX_RC_LAST_PASS) && ctx->cfg.ss_number_layers > 1 && ctx->cfg.ts_number_layers > 1) { return VPX_CODEC_INVALID_PARAM;