Index: source/libvpx/test/svc_test.cc |
=================================================================== |
--- source/libvpx/test/svc_test.cc (revision 291857) |
+++ source/libvpx/test/svc_test.cc (working copy) |
@@ -60,7 +60,7 @@ |
codec_enc_.kf_min_dist = 100; |
codec_enc_.kf_max_dist = 100; |
- vpx_codec_dec_cfg_t dec_cfg = {0}; |
+ vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); |
VP9CodecFactory codec_factory; |
decoder_ = codec_factory.CreateDecoder(dec_cfg, 0); |
} |
@@ -112,7 +112,7 @@ |
video.Next(); |
} |
- // Flush encoder and test EOS packet |
+ // 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_); |
@@ -135,7 +135,7 @@ |
EXPECT_EQ(1, vpx_svc_is_keyframe(&svc_)); |
} |
- outputs[*frame_received].buf = malloc(frame_size); |
+ outputs[*frame_received].buf = malloc(frame_size + 16); |
ASSERT_TRUE(outputs[*frame_received].buf != NULL); |
memcpy(outputs[*frame_received].buf, vpx_svc_get_buffer(&svc_), |
frame_size); |
@@ -176,13 +176,13 @@ |
video.Next(); |
} |
- // Flush Encoder |
+ // 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); |
+ EXPECT_EQ(frame_received, static_cast<size_t>(n)); |
ReleaseEncoder(); |
} |
@@ -204,7 +204,7 @@ |
++decoded_frames; |
DxDataIterator dec_iter = decoder_->GetDxData(); |
- while (dec_iter.Next()) { |
+ while (dec_iter.Next() != NULL) { |
++received_frames; |
} |
} |
@@ -212,12 +212,13 @@ |
EXPECT_EQ(received_frames, n); |
} |
- void DropEnhancementLayers(struct vpx_fixed_buf *const inputs, |
- const int num_super_frames, |
- const int remained_layers) { |
+ void DropLayersAndMakeItVP9Comaptible(struct vpx_fixed_buf *const inputs, |
+ const int num_super_frames, |
+ const int remained_spatial_layers, |
+ const bool is_multiple_frame_contexts) { |
ASSERT_TRUE(inputs != NULL); |
ASSERT_GT(num_super_frames, 0); |
- ASSERT_GT(remained_layers, 0); |
+ ASSERT_GT(remained_spatial_layers, 0); |
for (int i = 0; i < num_super_frames; ++i) { |
uint32_t frame_sizes[8] = {0}; |
@@ -233,34 +234,112 @@ |
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; |
+ if (frame_count == 0) { |
+ // There's no super frame but only a single frame. |
+ ASSERT_EQ(1, remained_spatial_layers); |
+ if (is_multiple_frame_contexts) { |
+ // Make a new super frame. |
+ uint8_t marker = 0xc1; |
+ unsigned int mask; |
+ int mag; |
+ |
+ // Choose the magnitude. |
+ for (mag = 0, mask = 0xff; mag < 4; ++mag) { |
+ if (inputs[i].sz < mask) |
+ break; |
+ mask <<= 8; |
+ mask |= 0xff; |
+ } |
+ marker |= mag << 3; |
+ int index_sz = 2 + (mag + 1) * 2; |
+ |
+ inputs[i].buf = realloc(inputs[i].buf, inputs[i].sz + index_sz + 16); |
+ ASSERT_TRUE(inputs[i].buf != NULL); |
+ uint8_t *frame_data = static_cast<uint8_t*>(inputs[i].buf); |
+ frame_data[0] &= ~2; // Set the show_frame flag to 0. |
+ frame_data += inputs[i].sz; |
+ // Add an one byte frame with show_existing_frame. |
+ *frame_data++ = 0x88; |
+ |
+ // Write the super frame index. |
+ *frame_data++ = marker; |
+ |
+ frame_sizes[0] = inputs[i].sz; |
+ frame_sizes[1] = 1; |
+ for (int j = 0; j < 2; ++j) { |
+ unsigned int this_sz = frame_sizes[j]; |
+ for (int k = 0; k <= mag; k++) { |
+ *frame_data++ = this_sz & 0xff; |
+ this_sz >>= 8; |
+ } |
+ } |
+ *frame_data++ = marker; |
+ inputs[i].sz += index_sz + 1; |
} |
+ } else { |
+ // Found a super frame. |
+ 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_spatial_layers) |
+ break; |
+ } |
+ frame_data += frame_sizes[frame]; |
+ } |
+ ASSERT_LT(frame, frame_count) << "Couldn't find a visible frame. " |
+ << "remained_spatial_layers: " << remained_spatial_layers |
+ << " super_frame: " << i |
+ << " is_multiple_frame_context: " << is_multiple_frame_contexts; |
+ if (frame == frame_count - 1 && !is_multiple_frame_contexts) |
+ continue; |
+ |
frame_data += frame_sizes[frame]; |
+ |
+ // We need to add one more frame for multiple frame contexts. |
+ if (is_multiple_frame_contexts) |
+ ++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; |
+ |
+ // Copy existing frame sizes. |
+ memmove(frame_data + (is_multiple_frame_contexts ? 2 : 1), |
+ frame_start + inputs[i].sz - index_sz + 1, new_index_sz - 2); |
+ if (is_multiple_frame_contexts) { |
+ // Add a one byte frame with flag show_existing_frame. |
+ *frame_data++ = 0x88 | (remained_spatial_layers - 1); |
+ } |
+ // New marker. |
+ frame_data[0] = marker; |
+ frame_data += (mag * (frame + 1) + 1); |
+ |
+ if (is_multiple_frame_contexts) { |
+ // Write the frame size for the one byte frame. |
+ frame_data -= mag; |
+ *frame_data++ = 1; |
+ for (uint32_t j = 1; j < mag; ++j) { |
+ *frame_data++ = 0; |
+ } |
+ } |
+ |
+ *frame_data++ = marker; |
+ inputs[i].sz = frame_data - frame_start; |
+ |
+ if (is_multiple_frame_contexts) { |
+ // Change the show frame flag to 0 for all frames. |
+ for (int j = 0; j < frame; ++j) { |
+ frame_start[0] &= ~2; |
+ frame_start += frame_sizes[j]; |
+ } |
+ } |
} |
- 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; |
} |
} |
@@ -326,7 +405,7 @@ |
} |
TEST_F(SvcTest, SetLayersOption) { |
- vpx_codec_err_t res = vpx_svc_set_options(&svc_, "layers=3"); |
+ vpx_codec_err_t res = vpx_svc_set_options(&svc_, "spatial-layers=3"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
InitializeEncoder(); |
EXPECT_EQ(3, svc_.spatial_layers); |
@@ -334,7 +413,7 @@ |
TEST_F(SvcTest, SetMultipleOptions) { |
vpx_codec_err_t res = |
- vpx_svc_set_options(&svc_, "layers=2 scale-factors=1/3,2/3"); |
+ vpx_svc_set_options(&svc_, "spatial-layers=2 scale-factors=1/3,2/3"); |
EXPECT_EQ(VPX_CODEC_OK, res); |
InitializeEncoder(); |
EXPECT_EQ(2, svc_.spatial_layers); |
@@ -496,7 +575,7 @@ |
FreeBitstreamBuffers(&outputs[0], 20); |
} |
-TEST_F(SvcTest, TwoPassEncode2LayersDecodeBaseLayerOnly) { |
+TEST_F(SvcTest, TwoPassEncode2SpatialLayersDecodeBaseLayerOnly) { |
// First pass encode |
std::string stats_buf; |
Pass1EncodeNFrames(10, 2, &stats_buf); |
@@ -507,12 +586,12 @@ |
vpx_fixed_buf outputs[10]; |
memset(&outputs[0], 0, sizeof(outputs)); |
Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
- DropEnhancementLayers(&outputs[0], 10, 1); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false); |
DecodeNFrames(&outputs[0], 10); |
FreeBitstreamBuffers(&outputs[0], 10); |
} |
-TEST_F(SvcTest, TwoPassEncode5LayersDecode54321Layers) { |
+TEST_F(SvcTest, TwoPassEncode5SpatialLayersDecode54321Layers) { |
// First pass encode |
std::string stats_buf; |
Pass1EncodeNFrames(10, 5, &stats_buf); |
@@ -525,13 +604,13 @@ |
Pass2EncodeNFrames(&stats_buf, 10, 5, &outputs[0]); |
DecodeNFrames(&outputs[0], 10); |
- DropEnhancementLayers(&outputs[0], 10, 4); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 4, false); |
DecodeNFrames(&outputs[0], 10); |
- DropEnhancementLayers(&outputs[0], 10, 3); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 3, false); |
DecodeNFrames(&outputs[0], 10); |
- DropEnhancementLayers(&outputs[0], 10, 2); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, false); |
DecodeNFrames(&outputs[0], 10); |
- DropEnhancementLayers(&outputs[0], 10, 1); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, false); |
DecodeNFrames(&outputs[0], 10); |
FreeBitstreamBuffers(&outputs[0], 10); |
@@ -568,12 +647,212 @@ |
memset(&outputs[0], 0, sizeof(outputs)); |
Pass2EncodeNFrames(&stats_buf, 20, 3, &outputs[0]); |
DecodeNFrames(&outputs[0], 20); |
- DropEnhancementLayers(&outputs[0], 20, 2); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 2, false); |
DecodeNFrames(&outputs[0], 20); |
- DropEnhancementLayers(&outputs[0], 20, 1); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 20, 1, false); |
DecodeNFrames(&outputs[0], 20); |
FreeBitstreamBuffers(&outputs[0], 20); |
} |
+TEST_F(SvcTest, SetMultipleFrameContextsOption) { |
+ svc_.spatial_layers = 5; |
+ vpx_codec_err_t res = |
+ vpx_svc_set_options(&svc_, "multi-frame-contexts=1"); |
+ 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_options(&svc_, "multi-frame-contexts=1"); |
+ InitializeEncoder(); |
+} |
+ |
+TEST_F(SvcTest, TwoPassEncode2SpatialLayersWithMultipleFrameContexts) { |
+ // First pass encode |
+ std::string stats_buf; |
+ Pass1EncodeNFrames(10, 2, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, |
+ TwoPassEncode2SpatialLayersWithMultipleFrameContextsDecodeBaselayer) { |
+ // First pass encode |
+ std::string stats_buf; |
+ Pass1EncodeNFrames(10, 2, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, TwoPassEncode2SNRLayersWithMultipleFrameContexts) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1"); |
+ Pass1EncodeNFrames(10, 2, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1 scale-factors=1/1,1/1 " |
+ "multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 2, &outputs[0]); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 2, true); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, |
+ TwoPassEncode3SNRLayersWithMultipleFrameContextsDecode321Layer) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1,1/1,1/1"); |
+ Pass1EncodeNFrames(10, 3, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1,1,1 scale-factors=1/1,1/1,1/1 " |
+ "multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 3, &outputs[0]); |
+ |
+ vpx_fixed_buf outputs_new[10]; |
+ for (int i = 0; i < 10; ++i) { |
+ outputs_new[i].buf = malloc(outputs[i].sz + 16); |
+ ASSERT_TRUE(outputs_new[i].buf != NULL); |
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz); |
+ outputs_new[i].sz = outputs[i].sz; |
+ } |
+ DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 3, true); |
+ DecodeNFrames(&outputs_new[0], 10); |
+ |
+ for (int i = 0; i < 10; ++i) { |
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz); |
+ outputs_new[i].sz = outputs[i].sz; |
+ } |
+ DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 2, true); |
+ DecodeNFrames(&outputs_new[0], 10); |
+ |
+ for (int i = 0; i < 10; ++i) { |
+ memcpy(outputs_new[i].buf, outputs[i].buf, outputs[i].sz); |
+ outputs_new[i].sz = outputs[i].sz; |
+ } |
+ DropLayersAndMakeItVP9Comaptible(&outputs_new[0], 10, 1, true); |
+ DecodeNFrames(&outputs_new[0], 10); |
+ |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs_new[0], 10); |
+} |
+ |
+TEST_F(SvcTest, TwoPassEncode2TemporalLayers) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1"); |
+ svc_.temporal_layers = 2; |
+ Pass1EncodeNFrames(10, 1, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ svc_.temporal_layers = 2; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, TwoPassEncode2TemporalLayersWithMultipleFrameContexts) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1"); |
+ svc_.temporal_layers = 2; |
+ Pass1EncodeNFrames(10, 1, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ svc_.temporal_layers = 2; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 " |
+ "multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true); |
+ DecodeNFrames(&outputs[0], 10); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, TwoPassEncode2TemporalLayersDecodeBaseLayer) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1"); |
+ svc_.temporal_layers = 2; |
+ Pass1EncodeNFrames(10, 1, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ svc_.temporal_layers = 2; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); |
+ |
+ vpx_fixed_buf base_layer[5]; |
+ for (int i = 0; i < 5; ++i) |
+ base_layer[i] = outputs[i * 2]; |
+ |
+ DecodeNFrames(&base_layer[0], 5); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
+TEST_F(SvcTest, |
+ TwoPassEncode2TemporalLayersWithMultipleFrameContextsDecodeBaseLayer) { |
+ // First pass encode |
+ std::string stats_buf; |
+ vpx_svc_set_options(&svc_, "scale-factors=1/1"); |
+ svc_.temporal_layers = 2; |
+ Pass1EncodeNFrames(10, 1, &stats_buf); |
+ |
+ // Second pass encode |
+ codec_enc_.g_pass = VPX_RC_LAST_PASS; |
+ svc_.temporal_layers = 2; |
+ codec_enc_.g_error_resilient = 0; |
+ vpx_svc_set_options(&svc_, "auto-alt-refs=1 scale-factors=1/1 " |
+ "multi-frame-contexts=1"); |
+ vpx_fixed_buf outputs[10]; |
+ memset(&outputs[0], 0, sizeof(outputs)); |
+ Pass2EncodeNFrames(&stats_buf, 10, 1, &outputs[0]); |
+ DropLayersAndMakeItVP9Comaptible(&outputs[0], 10, 1, true); |
+ |
+ vpx_fixed_buf base_layer[5]; |
+ for (int i = 0; i < 5; ++i) |
+ base_layer[i] = outputs[i * 2]; |
+ |
+ DecodeNFrames(&base_layer[0], 5); |
+ FreeBitstreamBuffers(&outputs[0], 10); |
+} |
+ |
} // namespace |