summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/make/obj_int_extract.c12
-rw-r--r--examples/vpx_temporal_scalable_patterns.c37
-rw-r--r--test/external_frame_buffer_test.cc4
-rw-r--r--test/svc_test.cc29
-rw-r--r--test/test-data.sha11
-rw-r--r--test/test.mk1
-rw-r--r--test/test_vector_test.cc8
-rw-r--r--test/test_vectors.cc8
-rw-r--r--test/test_vectors.h9
-rw-r--r--vp9/encoder/vp9_aq_cyclicrefresh.c116
-rw-r--r--vp9/encoder/vp9_encodeframe.c13
-rw-r--r--vp9/encoder/vp9_onyx_if.c202
-rw-r--r--vp9/encoder/vp9_onyx_int.h14
-rw-r--r--vp9/encoder/vp9_pickmode.c2
-rw-r--r--vp9/encoder/vp9_rdopt.c13
-rw-r--r--vp9/encoder/vp9_svc_layercontext.h1
-rw-r--r--vp9/vp9_cx_iface.c48
17 files changed, 332 insertions, 186 deletions
diff --git a/build/make/obj_int_extract.c b/build/make/obj_int_extract.c
index 819ce9d58..2e50f387f 100644
--- a/build/make/obj_int_extract.c
+++ b/build/make/obj_int_extract.c
@@ -34,6 +34,18 @@ int log_msg(const char *fmt, ...) {
}
#if defined(__GNUC__) && __GNUC__
+
+#if defined(FORCE_PARSE_ELF)
+
+#if defined(__MACH__)
+#undef __MACH__
+#endif
+
+#if !defined(__ELF__)
+#define __ELF__
+#endif
+#endif
+
#if defined(__MACH__)
#include <mach-o/loader.h>
diff --git a/examples/vpx_temporal_scalable_patterns.c b/examples/vpx_temporal_scalable_patterns.c
index b25953f35..3a4f05b92 100644
--- a/examples/vpx_temporal_scalable_patterns.c
+++ b/examples/vpx_temporal_scalable_patterns.c
@@ -437,6 +437,7 @@ int main(int argc, char **argv) {
vpx_codec_err_t res;
unsigned int width;
unsigned int height;
+ int speed;
int frame_avail;
int got_data;
int flags = 0;
@@ -457,7 +458,7 @@ int main(int argc, char **argv) {
// Check usage and arguments.
if (argc < 11) {
die("Usage: %s <infile> <outfile> <codec_type(vp8/vp9)> <width> <height> "
- "<rate_num> <rate_den> <frame_drop_threshold> <mode> "
+ "<rate_num> <rate_den> <speed> <frame_drop_threshold> <mode> "
"<Rate_0> ... <Rate_nlayers-1> \n", argv[0]);
}
@@ -473,12 +474,12 @@ int main(int argc, char **argv) {
die("Invalid resolution: %d x %d", width, height);
}
- layering_mode = strtol(argv[9], NULL, 0);
+ layering_mode = strtol(argv[10], NULL, 0);
if (layering_mode < 0 || layering_mode > 12) {
- die("Invalid mode (0..12) %s", argv[9]);
+ die("Invalid layering mode (0..12) %s", argv[10]);
}
- if (argc != 10 + mode_to_num_layers[layering_mode]) {
+ if (argc != 11 + mode_to_num_layers[layering_mode]) {
die("Invalid number of arguments");
}
@@ -501,12 +502,17 @@ int main(int argc, char **argv) {
cfg.g_timebase.num = strtol(argv[6], NULL, 0);
cfg.g_timebase.den = strtol(argv[7], NULL, 0);
- for (i = 10; (int)i < 10 + mode_to_num_layers[layering_mode]; ++i) {
- cfg.ts_target_bitrate[i - 10] = strtol(argv[i], NULL, 0);
+ speed = strtol(argv[8], NULL, 0);
+ if (speed < 0) {
+ die("Invalid speed setting: must be positive");
+ }
+
+ for (i = 11; (int)i < 11 + mode_to_num_layers[layering_mode]; ++i) {
+ cfg.ts_target_bitrate[i - 11] = strtol(argv[i], NULL, 0);
}
// Real time parameters.
- cfg.rc_dropframe_thresh = strtol(argv[8], NULL, 0);
+ cfg.rc_dropframe_thresh = strtol(argv[9], NULL, 0);
cfg.rc_end_usage = VPX_CBR;
cfg.rc_resize_allowed = 0;
cfg.rc_min_quantizer = 2;
@@ -563,14 +569,15 @@ int main(int argc, char **argv) {
if (vpx_codec_enc_init(&codec, encoder->interface(), &cfg, 0))
die_codec(&codec, "Failed to initialize encoder");
- vpx_codec_control(&codec, VP8E_SET_CPUUSED, -6);
- vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
- if (strncmp(encoder->name, "vp9", 3) == 0) {
- vpx_codec_control(&codec, VP8E_SET_CPUUSED, 5);
- vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
- vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0);
- if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
- die_codec(&codec, "Failed to set SVC");
+ if (strncmp(encoder->name, "vp8", 3) == 0) {
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, -speed);
+ vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 1);
+ } else if (strncmp(encoder->name, "vp9", 3) == 0) {
+ vpx_codec_control(&codec, VP8E_SET_CPUUSED, speed);
+ vpx_codec_control(&codec, VP9E_SET_AQ_MODE, 3);
+ vpx_codec_control(&codec, VP8E_SET_NOISE_SENSITIVITY, 0);
+ if (vpx_codec_control(&codec, VP9E_SET_SVC, 1)) {
+ die_codec(&codec, "Failed to set SVC");
}
}
vpx_codec_control(&codec, VP8E_SET_STATIC_THRESHOLD, 1);
diff --git a/test/external_frame_buffer_test.cc b/test/external_frame_buffer_test.cc
index 6e8ab2422..54c79e903 100644
--- a/test/external_frame_buffer_test.cc
+++ b/test/external_frame_buffer_test.cc
@@ -462,5 +462,7 @@ TEST_F(ExternalFrameBufferTest, SetAfterDecode) {
}
VP9_INSTANTIATE_TEST_CASE(ExternalFrameBufferMD5Test,
- ::testing::ValuesIn(libvpx_test::kVP9TestVectors));
+ ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
+ libvpx_test::kVP9TestVectors +
+ libvpx_test::kNumVP9TestVectors));
} // namespace
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<size_t>(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/test/test_vector_test.cc b/test/test_vector_test.cc
index 53b7636b6..9ba18daef 100644
--- a/test/test_vector_test.cc
+++ b/test/test_vector_test.cc
@@ -89,8 +89,12 @@ TEST_P(TestVectorTest, MD5Match) {
}
VP8_INSTANTIATE_TEST_CASE(TestVectorTest,
- ::testing::ValuesIn(libvpx_test::kVP8TestVectors));
+ ::testing::ValuesIn(libvpx_test::kVP8TestVectors,
+ libvpx_test::kVP8TestVectors +
+ libvpx_test::kNumVP8TestVectors));
VP9_INSTANTIATE_TEST_CASE(TestVectorTest,
- ::testing::ValuesIn(libvpx_test::kVP9TestVectors));
+ ::testing::ValuesIn(libvpx_test::kVP9TestVectors,
+ libvpx_test::kVP9TestVectors +
+ libvpx_test::kNumVP9TestVectors));
} // namespace
diff --git a/test/test_vectors.cc b/test/test_vectors.cc
index c7a0c71fc..175151eaf 100644
--- a/test/test_vectors.cc
+++ b/test/test_vectors.cc
@@ -12,8 +12,10 @@
namespace libvpx_test {
+#define NELEMENTS(x) static_cast<int>(sizeof(x) / sizeof(x[0]))
+
#if CONFIG_VP8_DECODER
-const char *kVP8TestVectors[kNumVP8TestVectors] = {
+const char *const kVP8TestVectors[] = {
"vp80-00-comprehensive-001.ivf",
"vp80-00-comprehensive-002.ivf", "vp80-00-comprehensive-003.ivf",
"vp80-00-comprehensive-004.ivf", "vp80-00-comprehensive-005.ivf",
@@ -47,9 +49,10 @@ const char *kVP8TestVectors[kNumVP8TestVectors] = {
"vp80-05-sharpness-1440.ivf", "vp80-05-sharpness-1443.ivf",
"vp80-06-smallsize.ivf"
};
+const int kNumVP8TestVectors = NELEMENTS(kVP8TestVectors);
#endif // CONFIG_VP8_DECODER
#if CONFIG_VP9_DECODER
-const char *kVP9TestVectors[kNumVP9TestVectors] = {
+const char *const kVP9TestVectors[] = {
"vp90-2-00-quantizer-00.webm", "vp90-2-00-quantizer-01.webm",
"vp90-2-00-quantizer-02.webm", "vp90-2-00-quantizer-03.webm",
"vp90-2-00-quantizer-04.webm", "vp90-2-00-quantizer-05.webm",
@@ -163,6 +166,7 @@ const char *kVP9TestVectors[kNumVP9TestVectors] = {
"vp90-2-12-droppable_2.ivf", "vp90-2-12-droppable_3.ivf",
"vp91-2-04-yv444.webm"
};
+const int kNumVP9TestVectors = NELEMENTS(kVP9TestVectors);
#endif // CONFIG_VP9_DECODER
} // namespace libvpx_test
diff --git a/test/test_vectors.h b/test/test_vectors.h
index de961deea..8e1aabb32 100644
--- a/test/test_vectors.h
+++ b/test/test_vectors.h
@@ -16,14 +16,13 @@
namespace libvpx_test {
#if CONFIG_VP8_DECODER
-const int kNumVP8TestVectors = 62;
-extern const char *kVP8TestVectors[kNumVP8TestVectors];
+extern const int kNumVP8TestVectors;
+extern const char *const kVP8TestVectors[];
#endif
#if CONFIG_VP9_DECODER
-const int kNumVP9TestVectors = 223;
-
-extern const char *kVP9TestVectors[kNumVP9TestVectors];
+extern const int kNumVP9TestVectors;
+extern const char *const kVP9TestVectors[];
#endif // CONFIG_VP9_DECODER
} // namespace libvpx_test
diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c
index 7442d0178..1d272e1d9 100644
--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -20,17 +20,18 @@
#include "vp9/encoder/vp9_segmentation.h"
struct CYCLIC_REFRESH {
- // Target percentage of blocks per frame that are cyclicly refreshed.
- int max_mbs_perframe;
+ // Percentage of super-blocks per frame that are targeted as candidates
+ // for cyclic refresh.
+ int max_sbs_perframe;
// Maximum q-delta as percentage of base q.
int max_qdelta_perc;
// Block size below which we don't apply cyclic refresh.
BLOCK_SIZE min_block_size;
- // Macroblock starting index (unit of 8x8) for cycling through the frame.
- int mb_index;
+ // Superblock starting index for cycling through the frame.
+ int sb_index;
// Controls how long a block will need to wait to be refreshed again.
int time_for_refresh;
- // Actual number of blocks that were applied delta-q (segment 1).
+ // Actual number of (8x8) blocks that were applied delta-q (segment 1).
int num_seg_blocks;
// Actual encoding bits for segment 1.
int actual_seg_bits;
@@ -77,7 +78,13 @@ static int apply_cyclic_refresh_bitrate(const VP9_COMMON *cm,
const int number_blocks = cm->mi_rows * cm->mi_cols;
// The condition below corresponds to turning off at target bitrates:
// ~24kbps for CIF, 72kbps for VGA (at 30fps).
- return rc->av_per_frame_bandwidth >= factor * number_blocks;
+ // Also turn off at very small frame sizes, to avoid too large fraction of
+ // superblocks to be refreshed per frame. Threshold below is less than QCIF.
+ if (rc->av_per_frame_bandwidth < factor * number_blocks ||
+ number_blocks / 64 < 5)
+ return 0;
+ else
+ return 1;
}
// Check if this coding block, of size bsize, should be considered for refresh
@@ -184,19 +191,18 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
vpx_memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
vp9_disable_segmentation(&cm->seg);
if (cm->frame_type == KEY_FRAME)
- cr->mb_index = 0;
+ cr->sb_index = 0;
return;
} else {
- const int mbs_in_frame = cm->mi_rows * cm->mi_cols;
int qindex_delta = 0;
- int i, x, y, block_count;
- int mi_row, mi_col, qindex2;
+ int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
+ int xmis, ymis, x, y, qindex2;
// Rate target ratio to set q delta.
const float rate_ratio_qdelta = 2.0;
vp9_clear_system_state();
// Some of these parameters may be set via codec-control function later.
- cr->max_mbs_perframe = 10;
+ cr->max_sbs_perframe = 10;
cr->max_qdelta_perc = 50;
cr->min_block_size = BLOCK_16X16;
cr->time_for_refresh = 1;
@@ -248,52 +254,62 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) {
cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);
vp9_set_segdata(seg, 1, SEG_LVL_ALT_Q, qindex_delta);
- // Number of target macroblocks to get the q delta (segment 1).
- block_count = cr->max_mbs_perframe * mbs_in_frame / 100;
- // Set the segmentation map: cycle through the macroblocks, starting at
+
+ sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+ sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+ sbs_in_frame = sb_cols * sb_rows;
+ // Number of target superblocks to get the q delta (segment 1).
+ block_count = cr->max_sbs_perframe * sbs_in_frame / 100;
+ // Set the segmentation map: cycle through the superblocks, starting at
// cr->mb_index, and stopping when either block_count blocks have been found
// to be refreshed, or we have passed through whole frame.
- // Note the setting of seg_map below is done in two steps (one over 8x8)
- // and then another over SB, in order to keep the value constant over SB.
- // TODO(marpan): Do this in one pass in SB order.
- assert(cr->mb_index < mbs_in_frame);
- i = cr->mb_index;
+ assert(cr->sb_index < sbs_in_frame);
+ i = cr->sb_index;
do {
- // If the macroblock is as a candidate for clean up then mark it
- // for possible boost/refresh (segment 1). The segment id may get reset to
- // 0 later if the macroblock gets coded anything other than ZEROMV.
- if (cr->map[i] == 0) {
- seg_map[i] = 1;
- block_count--;
- } else if (cr->map[i] < 0) {
- cr->map[i]++;
- }
- i++;
- if (i == mbs_in_frame) {
- i = 0;
+ int sum_map = 0;
+ // Get the mi_row/mi_col corresponding to superblock index i.
+ int sb_row_index = (i / sb_cols);
+ int sb_col_index = i - sb_row_index * sb_cols;
+ int mi_row = sb_row_index * MI_BLOCK_SIZE;
+ int mi_col = sb_col_index * MI_BLOCK_SIZE;
+ assert(mi_row >= 0 && mi_row < cm->mi_rows);
+ assert(mi_col >= 0 && mi_col < cm->mi_cols);
+ bl_index = mi_row * cm->mi_cols + mi_col;
+ // Loop through all 8x8 blocks in superblock and update map.
+ xmis = MIN(cm->mi_cols - mi_col,
+ num_8x8_blocks_wide_lookup[BLOCK_64X64]);
+ ymis = MIN(cm->mi_rows - mi_row,
+ num_8x8_blocks_high_lookup[BLOCK_64X64]);
+ for (y = 0; y < ymis; y++) {
+ for (x = 0; x < xmis; x++) {
+ const int bl_index2 = bl_index + y * cm->mi_cols + x;
+ // If the block is as a candidate for clean up then mark it
+ // for possible boost/refresh (segment 1). The segment id may get
+ // reset to 0 later if block gets coded anything other than ZEROMV.
+ if (cr->map[bl_index2] == 0) {
+ seg_map[bl_index2] = 1;
+ sum_map++;
+ } else if (cr->map[bl_index2] < 0) {
+ cr->map[bl_index2]++;
+ }
+ }
}
- } while (block_count && i != cr->mb_index);
- cr->mb_index = i;
- // Enforce constant segment map over superblock.
- for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE)
- for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) {
- const int bl_index = mi_row * cm->mi_cols + mi_col;
- const int xmis = MIN(cm->mi_cols - mi_col,
- num_8x8_blocks_wide_lookup[BLOCK_64X64]);
- const int ymis = MIN(cm->mi_rows - mi_row,
- num_8x8_blocks_high_lookup[BLOCK_64X64]);
- int sum_map = 0;
+ // Enforce constant segment over superblock.
+ // If segment is partial over superblock, reset to either all 1 or 0.
+ if (sum_map > 0 && sum_map < xmis * ymis) {
+ const int new_value = (sum_map >= xmis * ymis / 2);
for (y = 0; y < ymis; y++)
for (x = 0; x < xmis; x++)
- sum_map += seg_map[bl_index + y * cm->mi_cols + x];
- // If segment is partial over superblock, reset.
- if (sum_map > 0 && sum_map < xmis * ymis) {
- const int new_value = (sum_map >= xmis * ymis / 2);
- for (y = 0; y < ymis; y++)
- for (x = 0; x < xmis; x++)
- seg_map[bl_index + y * cm->mi_cols + x] = new_value;
- }
+ seg_map[bl_index + y * cm->mi_cols + x] = new_value;
}
+ i++;
+ if (i == sbs_in_frame) {
+ i = 0;
+ }
+ if (sum_map >= xmis * ymis /2)
+ block_count--;
+ } while (block_count && i != cr->sb_index);
+ cr->sb_index = i;
}
}
diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index 7c23973b8..1e5890cda 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1405,7 +1405,7 @@ static int sb_has_motion(const VP9_COMMON *cm, MODE_INFO **prev_mi_8x8) {
return 0;
}
-static void update_state_rt(VP9_COMP *cpi, const PICK_MODE_CONTEXT *ctx,
+static void update_state_rt(VP9_COMP *cpi, PICK_MODE_CONTEXT *ctx,
int mi_row, int mi_col, int bsize) {
VP9_COMMON *const cm = &cpi->common;
MACROBLOCK *const x = &cpi->mb;
@@ -1413,15 +1413,11 @@ static void update_state_rt(VP9_COMP *cpi, const PICK_MODE_CONTEXT *ctx,
MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
const struct segmentation *const seg = &cm->seg;
- // TODO(jingning) We might need PICK_MODE_CONTEXT to buffer coding modes
- // associated with variable block sizes. Otherwise, remove this ctx
- // from argument list.
- (void)ctx;
-
*(xd->mi_8x8[0]) = ctx->mic;
- // Check for reseting segment_id and update cyclic map.
- if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && seg->enabled) {
+ // For in frame adaptive Q, check for reseting the segment_id and updating
+ // the cyclic refresh map.
+ if ((cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) && seg->enabled) {
vp9_cyclic_refresh_update_segment(cpi, &xd->mi_8x8[0]->mbmi,
mi_row, mi_col, bsize, 1);
vp9_init_plane_quantizers(cpi, x);
@@ -1448,6 +1444,7 @@ static void encode_b_rt(VP9_COMP *cpi, const TileInfo *const tile,
if (x->ab_index > 0)
return;
}
+
set_offsets(cpi, tile, mi_row, mi_col, bsize);
update_state_rt(cpi, get_block_context(x, bsize), mi_row, mi_col, bsize);
diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c
index 207ce28fe..122477906 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
@@ -425,120 +433,118 @@ static int is_slowest_mode(int mode) {
}
static void set_rd_speed_thresholds(VP9_COMP *cpi) {
- SPEED_FEATURES *sf = &cpi->sf;
int i;
// Set baseline threshold values
for (i = 0; i < MAX_MODES; ++i)
- sf->thresh_mult[i] = is_slowest_mode(cpi->oxcf.mode) ? -500 : 0;
-
- sf->thresh_mult[THR_NEARESTMV] = 0;
- sf->thresh_mult[THR_NEARESTG] = 0;
- sf->thresh_mult[THR_NEARESTA] = 0;
-
- sf->thresh_mult[THR_DC] += 1000;
-
- sf->thresh_mult[THR_NEWMV] += 1000;
- sf->thresh_mult[THR_NEWA] += 1000;
- sf->thresh_mult[THR_NEWG] += 1000;
-
- sf->thresh_mult[THR_NEARMV] += 1000;
- sf->thresh_mult[THR_NEARA] += 1000;
- sf->thresh_mult[THR_COMP_NEARESTLA] += 1000;
- sf->thresh_mult[THR_COMP_NEARESTGA] += 1000;
-
- sf->thresh_mult[THR_TM] += 1000;
-
- sf->thresh_mult[THR_COMP_NEARLA] += 1500;
- sf->thresh_mult[THR_COMP_NEWLA] += 2000;
- sf->thresh_mult[THR_NEARG] += 1000;
- sf->thresh_mult[THR_COMP_NEARGA] += 1500;
- sf->thresh_mult[THR_COMP_NEWGA] += 2000;
-
- sf->thresh_mult[THR_ZEROMV] += 2000;
- sf->thresh_mult[THR_ZEROG] += 2000;
- sf->thresh_mult[THR_ZEROA] += 2000;
- sf->thresh_mult[THR_COMP_ZEROLA] += 2500;
- sf->thresh_mult[THR_COMP_ZEROGA] += 2500;
-
- sf->thresh_mult[THR_H_PRED] += 2000;
- sf->thresh_mult[THR_V_PRED] += 2000;
- sf->thresh_mult[THR_D45_PRED ] += 2500;
- sf->thresh_mult[THR_D135_PRED] += 2500;
- sf->thresh_mult[THR_D117_PRED] += 2500;
- sf->thresh_mult[THR_D153_PRED] += 2500;
- sf->thresh_mult[THR_D207_PRED] += 2500;
- sf->thresh_mult[THR_D63_PRED] += 2500;
+ cpi->rd_thresh_mult[i] = is_slowest_mode(cpi->oxcf.mode) ? -500 : 0;
+
+ cpi->rd_thresh_mult[THR_NEARESTMV] = 0;
+ cpi->rd_thresh_mult[THR_NEARESTG] = 0;
+ cpi->rd_thresh_mult[THR_NEARESTA] = 0;
+
+ cpi->rd_thresh_mult[THR_DC] += 1000;
+
+ cpi->rd_thresh_mult[THR_NEWMV] += 1000;
+ cpi->rd_thresh_mult[THR_NEWA] += 1000;
+ cpi->rd_thresh_mult[THR_NEWG] += 1000;
+
+ cpi->rd_thresh_mult[THR_NEARMV] += 1000;
+ cpi->rd_thresh_mult[THR_NEARA] += 1000;
+ cpi->rd_thresh_mult[THR_COMP_NEARESTLA] += 1000;
+ cpi->rd_thresh_mult[THR_COMP_NEARESTGA] += 1000;
+
+ cpi->rd_thresh_mult[THR_TM] += 1000;
+
+ cpi->rd_thresh_mult[THR_COMP_NEARLA] += 1500;
+ cpi->rd_thresh_mult[THR_COMP_NEWLA] += 2000;
+ cpi->rd_thresh_mult[THR_NEARG] += 1000;
+ cpi->rd_thresh_mult[THR_COMP_NEARGA] += 1500;
+ cpi->rd_thresh_mult[THR_COMP_NEWGA] += 2000;
+
+ cpi->rd_thresh_mult[THR_ZEROMV] += 2000;
+ cpi->rd_thresh_mult[THR_ZEROG] += 2000;
+ cpi->rd_thresh_mult[THR_ZEROA] += 2000;
+ cpi->rd_thresh_mult[THR_COMP_ZEROLA] += 2500;
+ cpi->rd_thresh_mult[THR_COMP_ZEROGA] += 2500;
+
+ cpi->rd_thresh_mult[THR_H_PRED] += 2000;
+ cpi->rd_thresh_mult[THR_V_PRED] += 2000;
+ cpi->rd_thresh_mult[THR_D45_PRED ] += 2500;
+ cpi->rd_thresh_mult[THR_D135_PRED] += 2500;
+ cpi->rd_thresh_mult[THR_D117_PRED] += 2500;
+ cpi->rd_thresh_mult[THR_D153_PRED] += 2500;
+ cpi->rd_thresh_mult[THR_D207_PRED] += 2500;
+ cpi->rd_thresh_mult[THR_D63_PRED] += 2500;
/* disable frame modes if flags not set */
if (!(cpi->ref_frame_flags & VP9_LAST_FLAG)) {
- sf->thresh_mult[THR_NEWMV ] = INT_MAX;
- sf->thresh_mult[THR_NEARESTMV] = INT_MAX;
- sf->thresh_mult[THR_ZEROMV ] = INT_MAX;
- sf->thresh_mult[THR_NEARMV ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEWMV ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARESTMV] = INT_MAX;
+ cpi->rd_thresh_mult[THR_ZEROMV ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARMV ] = INT_MAX;
}
if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG)) {
- sf->thresh_mult[THR_NEARESTG ] = INT_MAX;
- sf->thresh_mult[THR_ZEROG ] = INT_MAX;
- sf->thresh_mult[THR_NEARG ] = INT_MAX;
- sf->thresh_mult[THR_NEWG ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARESTG ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_ZEROG ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARG ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEWG ] = INT_MAX;
}
if (!(cpi->ref_frame_flags & VP9_ALT_FLAG)) {
- sf->thresh_mult[THR_NEARESTA ] = INT_MAX;
- sf->thresh_mult[THR_ZEROA ] = INT_MAX;
- sf->thresh_mult[THR_NEARA ] = INT_MAX;
- sf->thresh_mult[THR_NEWA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARESTA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_ZEROA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEARA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_NEWA ] = INT_MAX;
}
if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
(VP9_LAST_FLAG | VP9_ALT_FLAG)) {
- sf->thresh_mult[THR_COMP_ZEROLA ] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEARESTLA] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEARLA ] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEWLA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_ZEROLA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEARESTLA] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEARLA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEWLA ] = INT_MAX;
}
if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
(VP9_GOLD_FLAG | VP9_ALT_FLAG)) {
- sf->thresh_mult[THR_COMP_ZEROGA ] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEARESTGA] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEARGA ] = INT_MAX;
- sf->thresh_mult[THR_COMP_NEWGA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_ZEROGA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEARESTGA] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEARGA ] = INT_MAX;
+ cpi->rd_thresh_mult[THR_COMP_NEWGA ] = INT_MAX;
}
}
static void set_rd_speed_thresholds_sub8x8(VP9_COMP *cpi) {
- SPEED_FEATURES *sf = &cpi->sf;
+ const SPEED_FEATURES *const sf = &cpi->sf;
int i;
for (i = 0; i < MAX_REFS; ++i)
- sf->thresh_mult_sub8x8[i] = is_slowest_mode(cpi->oxcf.mode) ? -500 : 0;
+ cpi->rd_thresh_mult_sub8x8[i] = is_slowest_mode(cpi->oxcf.mode) ? -500 : 0;
- sf->thresh_mult_sub8x8[THR_LAST] += 2500;
- sf->thresh_mult_sub8x8[THR_GOLD] += 2500;
- sf->thresh_mult_sub8x8[THR_ALTR] += 2500;
- sf->thresh_mult_sub8x8[THR_INTRA] += 2500;
- sf->thresh_mult_sub8x8[THR_COMP_LA] += 4500;
- sf->thresh_mult_sub8x8[THR_COMP_GA] += 4500;
+ cpi->rd_thresh_mult_sub8x8[THR_LAST] += 2500;
+ cpi->rd_thresh_mult_sub8x8[THR_GOLD] += 2500;
+ cpi->rd_thresh_mult_sub8x8[THR_ALTR] += 2500;
+ cpi->rd_thresh_mult_sub8x8[THR_INTRA] += 2500;
+ cpi->rd_thresh_mult_sub8x8[THR_COMP_LA] += 4500;
+ cpi->rd_thresh_mult_sub8x8[THR_COMP_GA] += 4500;
// Check for masked out split cases.
- for (i = 0; i < MAX_REFS; i++) {
+ for (i = 0; i < MAX_REFS; i++)
if (sf->disable_split_mask & (1 << i))
- sf->thresh_mult_sub8x8[i] = INT_MAX;
- }
+ cpi->rd_thresh_mult_sub8x8[i] = INT_MAX;
// disable mode test if frame flag is not set
if (!(cpi->ref_frame_flags & VP9_LAST_FLAG))
- sf->thresh_mult_sub8x8[THR_LAST] = INT_MAX;
+ cpi->rd_thresh_mult_sub8x8[THR_LAST] = INT_MAX;
if (!(cpi->ref_frame_flags & VP9_GOLD_FLAG))
- sf->thresh_mult_sub8x8[THR_GOLD] = INT_MAX;
+ cpi->rd_thresh_mult_sub8x8[THR_GOLD] = INT_MAX;
if (!(cpi->ref_frame_flags & VP9_ALT_FLAG))
- sf->thresh_mult_sub8x8[THR_ALTR] = INT_MAX;
+ cpi->rd_thresh_mult_sub8x8[THR_ALTR] = INT_MAX;
if ((cpi->ref_frame_flags & (VP9_LAST_FLAG | VP9_ALT_FLAG)) !=
(VP9_LAST_FLAG | VP9_ALT_FLAG))
- sf->thresh_mult_sub8x8[THR_COMP_LA] = INT_MAX;
+ cpi->rd_thresh_mult_sub8x8[THR_COMP_LA] = INT_MAX;
if ((cpi->ref_frame_flags & (VP9_GOLD_FLAG | VP9_ALT_FLAG)) !=
(VP9_GOLD_FLAG | VP9_ALT_FLAG))
- sf->thresh_mult_sub8x8[THR_COMP_GA] = INT_MAX;
+ cpi->rd_thresh_mult_sub8x8[THR_COMP_GA] = INT_MAX;
}
// Intra only frames, golden frames (except alt ref overlays) and
@@ -1686,9 +1692,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_onyx_int.h b/vp9/encoder/vp9_onyx_int.h
index b62fa718a..582fa0ea3 100644
--- a/vp9/encoder/vp9_onyx_int.h
+++ b/vp9/encoder/vp9_onyx_int.h
@@ -240,13 +240,6 @@ typedef struct {
// Control when to stop subpel search
int subpel_force_stop;
- // Thresh_mult is used to set a threshold for the rd score. A higher value
- // means that we will accept the best mode so far more often. This number
- // is used in combination with the current block size, and thresh_freq_fact
- // to pick a threshold.
- int thresh_mult[MAX_MODES];
- int thresh_mult_sub8x8[MAX_REFS];
-
// This parameter controls the number of steps we'll do in a diamond
// search.
int max_step_search_steps;
@@ -649,6 +642,13 @@ typedef struct VP9_COMP {
// Ambient reconstruction err target for force key frames
int ambient_err;
+ // Thresh_mult is used to set a threshold for the rd score. A higher value
+ // means that we will accept the best mode so far more often. This number
+ // is used in combination with the current block size, and thresh_freq_fact
+ // to pick a threshold.
+ int rd_thresh_mult[MAX_MODES];
+ int rd_thresh_mult_sub8x8[MAX_REFS];
+
int rd_threshes[MAX_SEGMENTS][BLOCK_SIZES][MAX_MODES];
int rd_thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
int rd_thresh_sub8x8[MAX_SEGMENTS][BLOCK_SIZES][MAX_REFS];
diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c
index bd3be907b..c500a0163 100644
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -255,7 +255,7 @@ int64_t vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x,
mbmi->interp_filter = cpi->common.interp_filter == SWITCHABLE ?
EIGHTTAP : cpi->common.interp_filter;
mbmi->skip = 0;
- mbmi->segment_id = 0;
+ mbmi->segment_id = segment_id;
xd->interp_kernel = vp9_get_interp_kernel(mbmi->interp_filter);
for (ref_frame = LAST_FRAME; ref_frame <= LAST_FRAME ; ++ref_frame) {
diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c
index 4c389092f..ba7d4db12 100644
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -244,7 +244,6 @@ void vp9_initialize_me_consts(VP9_COMP *cpi, int qindex) {
static void set_block_thresholds(VP9_COMP *cpi) {
const VP9_COMMON *const cm = &cpi->common;
- const SPEED_FEATURES *const sf = &cpi->sf;
int i, bsize, segment_id;
for (segment_id = 0; segment_id < MAX_SEGMENTS; ++segment_id) {
@@ -261,13 +260,13 @@ static void set_block_thresholds(VP9_COMP *cpi) {
for (i = 0; i < MAX_MODES; ++i)
cpi->rd_threshes[segment_id][bsize][i] =
- sf->thresh_mult[i] < thresh_max ? sf->thresh_mult[i] * t / 4
+ cpi->rd_thresh_mult[i] < thresh_max ? cpi->rd_thresh_mult[i] * t / 4
: INT_MAX;
for (i = 0; i < MAX_REFS; ++i) {
cpi->rd_thresh_sub8x8[segment_id][bsize][i] =
- sf->thresh_mult_sub8x8[i] < thresh_max
- ? sf->thresh_mult_sub8x8[i] * t / 4
+ cpi->rd_thresh_mult_sub8x8[i] < thresh_max
+ ? cpi->rd_thresh_mult_sub8x8[i] * t / 4
: INT_MAX;
}
}
@@ -3130,7 +3129,6 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = &xd->mi_8x8[0]->mbmi;
const struct segmentation *const seg = &cm->seg;
- const BLOCK_SIZE block_size = get_plane_block_size(bsize, &xd->plane[0]);
MB_PREDICTION_MODE this_mode;
MV_REFERENCE_FRAME ref_frame, second_ref_frame;
unsigned char segment_id = mbmi->segment_id;
@@ -3196,7 +3194,7 @@ int64_t vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, MACROBLOCK *x,
x->pred_mv_sad[ref_frame] = INT_MAX;
if (cpi->ref_frame_flags & flag_list[ref_frame]) {
vp9_setup_buffer_inter(cpi, x, tile,
- ref_frame, block_size, mi_row, mi_col,
+ ref_frame, bsize, mi_row, mi_col,
frame_mv[NEARESTMV], frame_mv[NEARMV], yv12_mb);
}
frame_mv[NEWMV][ref_frame].as_int = INVALID_MV;
@@ -3763,7 +3761,6 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
MACROBLOCKD *xd = &x->e_mbd;
MB_MODE_INFO *mbmi = &xd->mi_8x8[0]->mbmi;
const struct segmentation *seg = &cm->seg;
- const BLOCK_SIZE block_size = get_plane_block_size(bsize, &xd->plane[0]);
MV_REFERENCE_FRAME ref_frame, second_ref_frame;
unsigned char segment_id = mbmi->segment_id;
int comp_pred, i;
@@ -3823,7 +3820,7 @@ int64_t vp9_rd_pick_inter_mode_sub8x8(VP9_COMP *cpi, MACROBLOCK *x,
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ref_frame++) {
if (cpi->ref_frame_flags & flag_list[ref_frame]) {
vp9_setup_buffer_inter(cpi, x, tile,
- ref_frame, block_size, mi_row, mi_col,
+ ref_frame, bsize, mi_row, mi_col,
frame_mv[NEARESTMV], frame_mv[NEARMV],
yv12_mb);
}
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 = 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];
+ }
+ }
+
+ 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 - 1;
+ stats = (const FIRSTPASS_STATS *)cfg->rc_twopass_stats_in.buf +
+ n_packets - cfg->ss_number_layers + i;
+ layer_id = stats->spatial_layer_id;
- if ((int)(stats->count + 0.5) != n_packets - 1)
- ERROR("rc_twopass_stats_in missing EOS stats packet");
+ 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;