Index: source/libvpx/test/svc_test.cc |
=================================================================== |
--- source/libvpx/test/svc_test.cc (revision 291087) |
+++ source/libvpx/test/svc_test.cc (working copy) |
@@ -13,6 +13,9 @@ |
#include "test/codec_factory.h" |
#include "test/decode_test_driver.h" |
#include "test/i420_video_source.h" |
+ |
+#include "vp9/decoder/vp9_decoder.h" |
+ |
#include "vpx/svc_context.h" |
#include "vpx/vp8cx.h" |
#include "vpx/vpx_encoder.h" |
@@ -21,6 +24,7 @@ |
using libvpx_test::CodecFactory; |
using libvpx_test::Decoder; |
+using libvpx_test::DxDataIterator; |
using libvpx_test::VP9CodecFactory; |
class SvcTest : public ::testing::Test { |
@@ -62,11 +66,215 @@ |
} |
virtual void TearDown() { |
+ ReleaseEncoder(); |
+ delete(decoder_); |
+ } |
+ |
+ void InitializeEncoder() { |
+ const vpx_codec_err_t res = |
+ vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
+ EXPECT_EQ(VPX_CODEC_OK, res); |
+ codec_initialized_ = true; |
+ } |
+ |
+ void ReleaseEncoder() { |
vpx_svc_release(&svc_); |
- delete(decoder_); |
if (codec_initialized_) vpx_codec_destroy(&codec_); |
+ codec_initialized_ = false; |
} |
+ void Pass1EncodeNFrames(const int n, const int layers, |
+ std::string *const stats_buf) { |
+ vpx_codec_err_t res; |
+ size_t stats_size = 0; |
+ const char *stats_data = NULL; |
+ |
+ ASSERT_GT(n, 0); |
+ ASSERT_GT(layers, 0); |
+ svc_.spatial_layers = layers; |
+ codec_enc_.g_pass = VPX_RC_FIRST_PASS; |
+ InitializeEncoder(); |
+ |
+ libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, |
+ codec_enc_.g_timebase.den, |
+ codec_enc_.g_timebase.num, 0, 30); |
+ video.Begin(); |
+ |
+ for (int i = 0; i < n; ++i) { |
+ res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
+ video.duration(), VPX_DL_GOOD_QUALITY); |
+ ASSERT_EQ(VPX_CODEC_OK, res); |
+ stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_); |
+ EXPECT_GT(stats_size, 0U); |
+ stats_data = vpx_svc_get_rc_stats_buffer(&svc_); |
+ ASSERT_TRUE(stats_data != NULL); |
+ stats_buf->append(stats_data, stats_size); |
+ video.Next(); |
+ } |
+ |
+ // Flush encoder and test EOS packet |
+ res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(), |
+ video.duration(), VPX_DL_GOOD_QUALITY); |
+ stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_); |
+ EXPECT_GT(stats_size, 0U); |
+ stats_data = vpx_svc_get_rc_stats_buffer(&svc_); |
+ ASSERT_TRUE(stats_data != NULL); |
+ stats_buf->append(stats_data, stats_size); |
+ |
+ ReleaseEncoder(); |
+ } |
+ |
+ void StoreFrames(const size_t max_frame_received, |
+ struct vpx_fixed_buf *const outputs, |
+ size_t *const frame_received) { |
+ size_t frame_size; |
+ while ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
+ ASSERT_LT(*frame_received, max_frame_received); |
+ |
+ if (*frame_received == 0) { |
+ EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_)); |
+ } |
+ |
+ outputs[*frame_received].buf = malloc(frame_size); |
+ ASSERT_TRUE(outputs[*frame_received].buf != NULL); |
+ memcpy(outputs[*frame_received].buf, vpx_svc_get_buffer(&svc_), |
+ frame_size); |
+ outputs[*frame_received].sz = frame_size; |
+ ++(*frame_received); |
+ } |
+ } |
+ |
+ void Pass2EncodeNFrames(std::string *const stats_buf, |
+ const int n, const int layers, |
+ struct vpx_fixed_buf *const outputs) { |
+ vpx_codec_err_t res; |
+ size_t frame_received = 0; |
+ |
+ ASSERT_TRUE(outputs != NULL); |
+ ASSERT_GT(n, 0); |
+ ASSERT_GT(layers, 0); |
+ svc_.spatial_layers = layers; |
+ codec_enc_.rc_target_bitrate = 500; |
+ if (codec_enc_.g_pass == VPX_RC_LAST_PASS) { |
+ ASSERT_TRUE(stats_buf != NULL); |
+ ASSERT_GT(stats_buf->size(), 0U); |
+ codec_enc_.rc_twopass_stats_in.buf = &(*stats_buf)[0]; |
+ codec_enc_.rc_twopass_stats_in.sz = stats_buf->size(); |
+ } |
+ InitializeEncoder(); |
+ |
+ libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, |
+ codec_enc_.g_timebase.den, |
+ codec_enc_.g_timebase.num, 0, 30); |
+ video.Begin(); |
+ |
+ for (int i = 0; i < n; ++i) { |
+ res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
+ video.duration(), VPX_DL_GOOD_QUALITY); |
+ ASSERT_EQ(VPX_CODEC_OK, res); |
+ StoreFrames(n, outputs, &frame_received); |
+ video.Next(); |
+ } |
+ |
+ // Flush Encoder |
+ res = vpx_svc_encode(&svc_, &codec_, NULL, 0, |
+ video.duration(), VPX_DL_GOOD_QUALITY); |
+ EXPECT_EQ(VPX_CODEC_OK, res); |
+ StoreFrames(n, outputs, &frame_received); |
+ |
+ EXPECT_EQ(frame_received, (size_t)n); |
+ |
+ ReleaseEncoder(); |
+ } |
+ |
+ void DecodeNFrames(const struct vpx_fixed_buf *const inputs, const int n) { |
+ int decoded_frames = 0; |
+ int received_frames = 0; |
+ |
+ ASSERT_TRUE(inputs != NULL); |
+ ASSERT_GT(n, 0); |
+ |
+ for (int i = 0; i < n; ++i) { |
+ ASSERT_TRUE(inputs[i].buf != NULL); |
+ ASSERT_GT(inputs[i].sz, 0U); |
+ const vpx_codec_err_t res_dec = |
+ decoder_->DecodeFrame(static_cast<const uint8_t *>(inputs[i].buf), |
+ inputs[i].sz); |
+ ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
+ ++decoded_frames; |
+ |
+ DxDataIterator dec_iter = decoder_->GetDxData(); |
+ while (dec_iter.Next()) { |
+ ++received_frames; |
+ } |
+ } |
+ EXPECT_EQ(decoded_frames, n); |
+ EXPECT_EQ(received_frames, n); |
+ } |
+ |
+ void DropEnhancementLayers(struct vpx_fixed_buf *const inputs, |
+ const int num_super_frames, |
+ const int remained_layers) { |
+ ASSERT_TRUE(inputs != NULL); |
+ ASSERT_GT(num_super_frames, 0); |
+ ASSERT_GT(remained_layers, 0); |
+ |
+ for (int i = 0; i < num_super_frames; ++i) { |
+ uint32_t frame_sizes[8] = {0}; |
+ int frame_count = 0; |
+ int frames_found = 0; |
+ int frame; |
+ ASSERT_TRUE(inputs[i].buf != NULL); |
+ ASSERT_GT(inputs[i].sz, 0U); |
+ |
+ vpx_codec_err_t res = |
+ vp9_parse_superframe_index(static_cast<const uint8_t*>(inputs[i].buf), |
+ inputs[i].sz, frame_sizes, &frame_count, |
+ NULL, NULL); |
+ ASSERT_EQ(VPX_CODEC_OK, res); |
+ |
+ uint8_t *frame_data = static_cast<uint8_t *>(inputs[i].buf); |
+ uint8_t *frame_start = frame_data; |
+ for (frame = 0; frame < frame_count; ++frame) { |
+ // Looking for a visible frame |
+ if (frame_data[0] & 0x02) { |
+ ++frames_found; |
+ if (frames_found == remained_layers) |
+ break; |
+ } |
+ frame_data += frame_sizes[frame]; |
+ } |
+ ASSERT_LT(frame, frame_count); |
+ if (frame == frame_count - 1) |
+ continue; |
+ |
+ frame_data += frame_sizes[frame]; |
+ uint8_t marker = |
+ static_cast<const uint8_t *>(inputs[i].buf)[inputs[i].sz - 1]; |
+ const uint32_t mag = ((marker >> 3) & 0x3) + 1; |
+ const size_t index_sz = 2 + mag * frame_count; |
+ const size_t new_index_sz = 2 + mag * (frame + 1); |
+ marker &= 0x0f8; |
+ marker |= frame; |
+ frame_data[0] = marker; |
+ memcpy(frame_data + 1, frame_start + inputs[i].sz - index_sz + 1, |
+ new_index_sz - 2); |
+ frame_data[new_index_sz - 1] = marker; |
+ inputs[i].sz = frame_data - frame_start + new_index_sz; |
+ } |
+ } |
+ |
+ void FreeBitstreamBuffers(struct vpx_fixed_buf *const inputs, const int n) { |
+ ASSERT_TRUE(inputs != NULL); |
+ ASSERT_GT(n, 0); |
+ |
+ for (int i = 0; i < n; ++i) { |
+ free(inputs[i].buf); |
+ inputs[i].buf = NULL; |
+ inputs[i].sz = 0; |
+ } |
+ } |
+ |
SvcContext svc_; |
vpx_codec_ctx_t codec_; |
struct vpx_codec_enc_cfg codec_enc_; |
@@ -93,9 +301,7 @@ |
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); |
svc_.spatial_layers = 0; // use default layers |
- res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
EXPECT_EQ(VPX_SS_DEFAULT_LAYERS, svc_.spatial_layers); |
} |
@@ -106,9 +312,7 @@ |
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); |
vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); // valid scale values |
- res = vpx_svc_init(&svc_, &codec_, codec_iface_, &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
TEST_F(SvcTest, InvalidOptions) { |
@@ -124,18 +328,15 @@ |
TEST_F(SvcTest, SetLayersOption) { |
vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=3"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
EXPECT_EQ(3, svc_.spatial_layers); |
} |
TEST_F(SvcTest, SetMultipleOptions) { |
vpx_codec_err_t res = |
vpx_svc_set_options(&svc_, "layers=2 scale-factors=1/3,2/3"); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
EXPECT_EQ(2, svc_.spatial_layers); |
} |
@@ -149,9 +350,7 @@ |
res = vpx_svc_set_options(&svc_, "scale-factors=1/3,2/3"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
TEST_F(SvcTest, SetQuantizersOption) { |
@@ -162,9 +361,7 @@ |
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); |
vpx_svc_set_options(&svc_, "quantizers=40,45"); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
TEST_F(SvcTest, SetAutoAltRefOption) { |
@@ -180,9 +377,7 @@ |
EXPECT_EQ(VPX_CODEC_INVALID_PARAM, res); |
vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0"); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
TEST_F(SvcTest, SetQuantizers) { |
@@ -200,9 +395,7 @@ |
res = vpx_svc_set_quantizers(&svc_, "40,30"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
TEST_F(SvcTest, SetScaleFactors) { |
@@ -220,121 +413,25 @@ |
res = vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
} |
// Test that decoder can handle an SVC frame as the first frame in a sequence. |
-TEST_F(SvcTest, FirstFrameHasLayers) { |
- svc_.spatial_layers = 2; |
- vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); |
- vpx_svc_set_quantizers(&svc_, "40,30"); |
- |
- vpx_codec_err_t res = |
- vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
- |
- libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, |
- codec_enc_.g_timebase.den, |
- codec_enc_.g_timebase.num, 0, 30); |
- video.Begin(); |
- |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- |
- if (vpx_svc_get_frame_size(&svc_) == 0) { |
- // Flush encoder |
- res = vpx_svc_encode(&svc_, &codec_, NULL, 0, |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- } |
- |
- int frame_size = vpx_svc_get_frame_size(&svc_); |
- EXPECT_GT(frame_size, 0); |
- const vpx_codec_err_t res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- |
- // this test fails with a decoder error |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
+TEST_F(SvcTest, OnePassEncodeOneFrame) { |
+ codec_enc_.g_pass = VPX_RC_ONE_PASS; |
+ vpx_fixed_buf output = {0}; |
+ Pass2EncodeNFrames(NULL, 1, 2, &output); |
+ DecodeNFrames(&output, 1); |
+ FreeBitstreamBuffers(&output, 1); |
} |
-TEST_F(SvcTest, EncodeThreeFrames) { |
- svc_.spatial_layers = 2; |
- vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); |
- vpx_svc_set_quantizers(&svc_, "40,30"); |
- int decoded_frames = 0; |
- vpx_codec_err_t res_dec; |
- int frame_size; |
- |
- vpx_codec_err_t res = |
- vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
- |
- libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, |
- codec_enc_.g_timebase.den, |
- codec_enc_.g_timebase.num, 0, 30); |
- // FRAME 0 |
- video.Begin(); |
- // This frame is a keyframe. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
- |
- // FRAME 1 |
- video.Next(); |
- // This is a P-frame. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
- |
- // FRAME 2 |
- video.Next(); |
- // This is a P-frame. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
- |
- // Flush encoder |
- res = vpx_svc_encode(&svc_, &codec_, NULL, 0, |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- |
- while ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
- |
- EXPECT_EQ(decoded_frames, 3); |
+TEST_F(SvcTest, OnePassEncodeThreeFrames) { |
+ codec_enc_.g_pass = VPX_RC_ONE_PASS; |
+ vpx_fixed_buf outputs[3]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(NULL, 3, 2, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 3); |
+ FreeBitstreamBuffers(&outputs[0], 3); |
} |
TEST_F(SvcTest, GetLayerResolution) { |
@@ -342,14 +439,11 @@ |
vpx_svc_set_scale_factors(&svc_, "4/16,8/16"); |
vpx_svc_set_quantizers(&svc_, "40,30"); |
- vpx_codec_err_t res = |
- vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ InitializeEncoder(); |
// ensure that requested layer is a valid layer |
uint32_t layer_width, layer_height; |
- res = vpx_svc_get_layer_resolution(&svc_, svc_.spatial_layers, |
+ 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); |
@@ -373,131 +467,113 @@ |
EXPECT_EQ(kHeight * 8 / 16, layer_height); |
} |
-TEST_F(SvcTest, TwoPassEncode) { |
+TEST_F(SvcTest, TwoPassEncode10Frames) { |
// First pass encode |
std::string stats_buf; |
- svc_.spatial_layers = 2; |
- codec_enc_.g_pass = VPX_RC_FIRST_PASS; |
- vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); |
- vpx_svc_set_quantizers(&svc_, "40,30"); |
- vpx_svc_set_options(&svc_, "auto-alt-refs=1,1"); |
+ Pass1EncodeNFrames(10, 2, &stats_buf); |
- vpx_codec_err_t res = |
- vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
- libvpx_test::I420VideoSource video(test_file_name_, kWidth, kHeight, |
- codec_enc_.g_timebase.den, |
- codec_enc_.g_timebase.num, 0, 30); |
- // FRAME 0 |
- video.Begin(); |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- size_t stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_); |
- EXPECT_GT(stats_size, 0U); |
- const char *stats_data = vpx_svc_get_rc_stats_buffer(&svc_); |
- ASSERT_TRUE(stats_data != NULL); |
- stats_buf.append(stats_data, stats_size); |
+TEST_F(SvcTest, TwoPassEncode20FramesWithAltRef) { |
+ // First pass encode |
+ std::string stats_buf; |
+ Pass1EncodeNFrames(20, 2, &stats_buf); |
- // FRAME 1 |
- video.Next(); |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_); |
- EXPECT_GT(stats_size, 0U); |
- stats_data = vpx_svc_get_rc_stats_buffer(&svc_); |
- ASSERT_TRUE(stats_data != NULL); |
- stats_buf.append(stats_data, stats_size); |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1"); |
+ vpx_fixed_buf outputs[20]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 20); |
+ FreeBitstreamBuffers(&outputs[0], 20); |
+} |
- // Flush encoder and test EOS packet |
- res = vpx_svc_encode(&svc_, &codec_, NULL, video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- stats_size = vpx_svc_get_rc_stats_buffer_size(&svc_); |
- EXPECT_GT(stats_size, 0U); |
- stats_data = vpx_svc_get_rc_stats_buffer(&svc_); |
- ASSERT_TRUE(stats_data != NULL); |
- stats_buf.append(stats_data, stats_size); |
+TEST_F(SvcTest, TwoPassEncode2LayersDecodeBaseLayerOnly) { |
+ // First pass encode |
+ std::string stats_buf; |
+ Pass1EncodeNFrames(10, 2, &stats_buf); |
- // Tear down encoder |
- vpx_svc_release(&svc_); |
- vpx_codec_destroy(&codec_); |
- |
// Second pass encode |
- int decoded_frames = 0; |
- vpx_codec_err_t res_dec; |
- int frame_size; |
codec_enc_.g_pass = VPX_RC_LAST_PASS; |
- vpx_svc_set_scale_factors(&svc_, "4/16,16/16"); |
- vpx_svc_set_quantizers(&svc_, "40,30"); |
vpx_svc_set_options(&svc_, "auto-alt-refs=1,1"); |
- codec_enc_.rc_twopass_stats_in.buf = &stats_buf[0]; |
- codec_enc_.rc_twopass_stats_in.sz = stats_buf.size(); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
+ DropEnhancementLayers(&outputs[0], 10, 1); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
- res = vpx_svc_init(&svc_, &codec_, vpx_codec_vp9_cx(), &codec_enc_); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
- codec_initialized_ = true; |
+TEST_F(SvcTest, TwoPassEncode5LayersDecode54321Layers) { |
+ // First pass encode |
+ std::string stats_buf; |
+ Pass1EncodeNFrames(10, 5, &stats_buf); |
- // FRAME 0 |
- video.Begin(); |
- // This frame is a keyframe. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=0,1,1,1,0"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]); |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
+ DecodeNFrames(&outputs[0], 10); |
+ DropEnhancementLayers(&outputs[0], 10, 4); |
+ DecodeNFrames(&outputs[0], 10); |
+ DropEnhancementLayers(&outputs[0], 10, 3); |
+ DecodeNFrames(&outputs[0], 10); |
+ DropEnhancementLayers(&outputs[0], 10, 2); |
+ DecodeNFrames(&outputs[0], 10); |
+ DropEnhancementLayers(&outputs[0], 10, 1); |
+ DecodeNFrames(&outputs[0], 10); |
- // FRAME 1 |
- video.Next(); |
- // This is a P-frame. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
+TEST_F(SvcTest, TwoPassEncode2SNRLayers) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1"); |
+ Pass1EncodeNFrames(20, 2, &stats_buf); |
- // FRAME 2 |
- video.Next(); |
- // This is a P-frame. |
- res = vpx_svc_encode(&svc_, &codec_, video.img(), video.pts(), |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- ASSERT_EQ(VPX_CODEC_OK, res); |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ vpx_svc_set_options(&svc_, |
+ "auto-alt-refs=1,1 scale-factors=1/1,1/1"); |
+ vpx_fixed_buf outputs[20]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 20, 2, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 20); |
+ FreeBitstreamBuffers(&outputs[0], 20); |
+} |
- if ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
+TEST_F(SvcTest, TwoPassEncode3SNRLayersDecode321Layers) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1"); |
+ Pass1EncodeNFrames(20, 3, &stats_buf); |
- // Flush encoder |
- res = vpx_svc_encode(&svc_, &codec_, NULL, 0, |
- video.duration(), VPX_DL_GOOD_QUALITY); |
- EXPECT_EQ(VPX_CODEC_OK, res); |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ vpx_svc_set_options(&svc_, |
+ "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1"); |
+ vpx_fixed_buf outputs[20]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 20); |
+ DropEnhancementLayers(&outputs[0], 20, 2); |
+ DecodeNFrames(&outputs[0], 20); |
+ DropEnhancementLayers(&outputs[0], 20, 1); |
+ DecodeNFrames(&outputs[0], 20); |
- while ((frame_size = vpx_svc_get_frame_size(&svc_)) > 0) { |
- EXPECT_EQ((decoded_frames == 0), vpx_svc_is_keyframe(&svc_)); |
- res_dec = decoder_->DecodeFrame( |
- static_cast<const uint8_t *>(vpx_svc_get_buffer(&svc_)), frame_size); |
- ASSERT_EQ(VPX_CODEC_OK, res_dec) << decoder_->DecodeError(); |
- ++decoded_frames; |
- } |
- |
- EXPECT_EQ(decoded_frames, 3); |
+ FreeBitstreamBuffers(&outputs[0], 20); |
} |
} // namespace |