diff --git a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index d9871873b8..23728d3f54 100644 --- a/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/webrtc/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -35,9 +35,8 @@ void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) { *stride_uv = 16 * ((width + 31) / 32); } -enum { kMaxWaitEncTimeMs = 100 }; -enum { kMaxWaitDecTimeMs = 25 }; - +constexpr int64_t kMaxWaitEncTimeMs = 100; +constexpr int64_t kMaxWaitDecTimeMs = 25; constexpr uint32_t kTestTimestamp = 123; constexpr int64_t kTestNtpTimeMs = 456; constexpr uint32_t kTimestampIncrementPerFrame = 3000; @@ -45,25 +44,29 @@ constexpr int kNumCores = 1; constexpr size_t kMaxPayloadSize = 1440; constexpr int kMinPixelsPerFrame = 12345; constexpr int kDefaultMinPixelsPerFrame = 320 * 180; - +constexpr int kWidth = 172; +constexpr int kHeight = 144; } // namespace -// TODO(mikhal): Replace these with mocks. class Vp8UnitTestEncodeCompleteCallback : public webrtc::EncodedImageCallback { public: Vp8UnitTestEncodeCompleteCallback(EncodedImage* frame, - CodecSpecificInfo* codec_specific_info, - unsigned int decoderSpecificSize, - void* decoderSpecificInfo) + CodecSpecificInfo* codec_specific_info) : encoded_frame_(frame), codec_specific_info_(codec_specific_info), encode_complete_(false) {} - Result OnEncodedImage(const EncodedImage& encoded_frame_, + Result OnEncodedImage(const EncodedImage& encoded_frame, const CodecSpecificInfo* codec_specific_info, const RTPFragmentationHeader* fragmentation) override; bool EncodeComplete(); + void VerifyQpParser(const EncodedImage& encoded_frame) const { + int qp; + ASSERT_TRUE(vp8::GetQp(encoded_frame._buffer, encoded_frame._length, &qp)); + EXPECT_EQ(encoded_frame.qp_, qp) << "Encoder QP != parsed bitstream QP."; + } + private: EncodedImage* const encoded_frame_; CodecSpecificInfo* const codec_specific_info_; @@ -76,23 +79,19 @@ Vp8UnitTestEncodeCompleteCallback::OnEncodedImage( const EncodedImage& encoded_frame, const CodecSpecificInfo* codec_specific_info, const RTPFragmentationHeader* fragmentation) { - if (encoded_frame_->_size < encoded_frame._length) { + EXPECT_GT(encoded_frame._length, 0u); + VerifyQpParser(encoded_frame); + + if (encoded_frame_->_size != encoded_frame._size) { delete[] encoded_frame_->_buffer; - frame_buffer_.reset(new uint8_t[encoded_frame._length]); - encoded_frame_->_buffer = frame_buffer_.get(); - encoded_frame_->_size = encoded_frame._length; + frame_buffer_.reset(new uint8_t[encoded_frame._size]); } - memcpy(encoded_frame_->_buffer, encoded_frame._buffer, encoded_frame._length); - encoded_frame_->_length = encoded_frame._length; - encoded_frame_->_encodedWidth = encoded_frame._encodedWidth; - encoded_frame_->_encodedHeight = encoded_frame._encodedHeight; - encoded_frame_->_timeStamp = encoded_frame._timeStamp; - encoded_frame_->_frameType = encoded_frame._frameType; - encoded_frame_->_completeFrame = encoded_frame._completeFrame; - encoded_frame_->rotation_ = encoded_frame.rotation_; - encoded_frame_->qp_ = encoded_frame.qp_; - codec_specific_info_->codecType = codec_specific_info->codecType; + memcpy(frame_buffer_.get(), encoded_frame._buffer, encoded_frame._length); + *encoded_frame_ = encoded_frame; + encoded_frame_->_buffer = frame_buffer_.get(); + // Skip |codec_name|, to avoid allocating. + codec_specific_info_->codecType = codec_specific_info->codecType; codec_specific_info_->codecSpecific = codec_specific_info->codecSpecific; encode_complete_ = true; return Result(Result::OK, 0); @@ -110,7 +109,7 @@ class Vp8UnitTestDecodeCompleteCallback : public webrtc::DecodedImageCallback { public: explicit Vp8UnitTestDecodeCompleteCallback(rtc::Optional* frame, rtc::Optional* qp) - : decoded_frame_(frame), decoded_qp_(qp), decode_complete(false) {} + : decoded_frame_(frame), decoded_qp_(qp), decode_complete_(false) {} int32_t Decoded(VideoFrame& frame) override { RTC_NOTREACHED(); return -1; @@ -127,12 +126,12 @@ class Vp8UnitTestDecodeCompleteCallback : public webrtc::DecodedImageCallback { private: rtc::Optional* decoded_frame_; rtc::Optional* decoded_qp_; - bool decode_complete; + bool decode_complete_; }; bool Vp8UnitTestDecodeCompleteCallback::DecodeComplete() { - if (decode_complete) { - decode_complete = false; + if (decode_complete_) { + decode_complete_ = false; return true; } return false; @@ -142,9 +141,11 @@ void Vp8UnitTestDecodeCompleteCallback::Decoded( VideoFrame& frame, rtc::Optional decode_time_ms, rtc::Optional qp) { + EXPECT_GT(frame.width(), 0); + EXPECT_GT(frame.height(), 0); *decoded_frame_ = rtc::Optional(frame); *decoded_qp_ = qp; - decode_complete = true; + decode_complete_ = true; } class TestVp8Impl : public ::testing::Test { @@ -156,28 +157,26 @@ class TestVp8Impl : public ::testing::Test { virtual void SetUp() { encoder_.reset(VP8Encoder::Create()); decoder_.reset(VP8Decoder::Create()); - memset(&codec_settings_, 0, sizeof(codec_settings_)); encode_complete_callback_.reset(new Vp8UnitTestEncodeCompleteCallback( - &encoded_frame_, &codec_specific_info_, 0, nullptr)); + &encoded_frame_, &codec_specific_info_)); decode_complete_callback_.reset( new Vp8UnitTestDecodeCompleteCallback(&decoded_frame_, &decoded_qp_)); encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); + + SetupCodecSettings(); + // Using a QCIF image (aligned stride (u,v planes) > width). // Processing only one frame. - source_file_ = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb"); - ASSERT_TRUE(source_file_ != nullptr); + FILE* file = fopen(test::ResourcePath("paris_qcif", "yuv").c_str(), "rb"); + ASSERT_TRUE(file != nullptr); rtc::scoped_refptr compact_buffer( - test::ReadI420Buffer(kWidth, kHeight, source_file_)); + test::ReadI420Buffer(kWidth, kHeight, file)); ASSERT_TRUE(compact_buffer); - codec_settings_.width = kWidth; - codec_settings_.height = kHeight; - const int kFramerate = 30; - codec_settings_.maxFramerate = kFramerate; // Setting aligned stride values. int stride_uv; int stride_y; - Calc16ByteAlignedStride(codec_settings_.width, &stride_y, &stride_uv); + Calc16ByteAlignedStride(kWidth, &stride_y, &stride_uv); EXPECT_EQ(stride_y, 176); EXPECT_EQ(stride_uv, 96); @@ -187,19 +186,24 @@ class TestVp8Impl : public ::testing::Test { // No scaling in our case, just a copy, to add stride to the image. stride_buffer->ScaleFrom(*compact_buffer); - input_frame_.reset( - new VideoFrame(stride_buffer, kVideoRotation_0, 0)); + input_frame_.reset(new VideoFrame(stride_buffer, kVideoRotation_0, 0)); input_frame_->set_timestamp(kTestTimestamp); + fclose(file); + } + + void SetupCodecSettings() { + webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_); + codec_settings_.maxBitrate = 4000; + codec_settings_.width = kWidth; + codec_settings_.height = kHeight; + codec_settings_.VP8()->denoisingOn = true; + codec_settings_.VP8()->frameDroppingOn = false; + codec_settings_.VP8()->automaticResizeOn = false; + codec_settings_.VP8()->complexity = kComplexityNormal; + codec_settings_.VP8()->tl_factory = &tl_factory_; } void SetUpEncodeDecode() { - codec_settings_.startBitrate = 300; - codec_settings_.maxBitrate = 4000; - codec_settings_.qpMax = 56; - codec_settings_.VP8()->denoisingOn = true; - codec_settings_.VP8()->tl_factory = &tl_factory_; - codec_settings_.VP8()->numberOfTemporalLayers = 1; - EXPECT_EQ( WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); @@ -207,44 +211,38 @@ class TestVp8Impl : public ::testing::Test { decoder_->InitDecode(&codec_settings_, kNumCores)); } - size_t WaitForEncodedFrame() const { - int64_t startTime = rtc::TimeMillis(); - while (rtc::TimeMillis() - startTime < kMaxWaitEncTimeMs) { + void WaitForEncodedFrame() const { + int64_t start_ms = rtc::TimeMillis(); + while (rtc::TimeMillis() - start_ms < kMaxWaitEncTimeMs) { if (encode_complete_callback_->EncodeComplete()) { - return encoded_frame_._length; + return; } } - return 0; + ASSERT_TRUE(false); } - size_t WaitForDecodedFrame() const { - int64_t startTime = rtc::TimeMillis(); - while (rtc::TimeMillis() - startTime < kMaxWaitDecTimeMs) { + void WaitForDecodedFrame() const { + int64_t start_ms = rtc::TimeMillis(); + while (rtc::TimeMillis() - start_ms < kMaxWaitDecTimeMs) { if (decode_complete_callback_->DecodeComplete()) { - return CalcBufferSize(VideoType::kI420, decoded_frame_->width(), - decoded_frame_->height()); + return; } } - return 0; + ASSERT_TRUE(false); } void ExpectFrameWith(int16_t picture_id, int tl0_pic_idx, uint8_t temporal_idx) { - ASSERT_TRUE(WaitForEncodedFrame()); + WaitForEncodedFrame(); EXPECT_EQ(picture_id, codec_specific_info_.codecSpecific.VP8.pictureId); EXPECT_EQ(tl0_pic_idx, codec_specific_info_.codecSpecific.VP8.tl0PicIdx); EXPECT_EQ(temporal_idx, codec_specific_info_.codecSpecific.VP8.temporalIdx); } - const int kWidth = 172; - const int kHeight = 144; - test::ScopedFieldTrials override_field_trials_; std::unique_ptr encode_complete_callback_; std::unique_ptr decode_complete_callback_; - std::unique_ptr source_buffer_; - FILE* source_file_; std::unique_ptr input_frame_; std::unique_ptr encoder_; std::unique_ptr decoder_; @@ -256,24 +254,23 @@ class TestVp8Impl : public ::testing::Test { TemporalLayersFactory tl_factory_; }; +TEST_F(TestVp8Impl, EncodeFrame) { + SetUpEncodeDecode(); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*input_frame_, nullptr, nullptr)); + WaitForEncodedFrame(); +} + TEST_F(TestVp8Impl, EncoderParameterTest) { - strncpy(codec_settings_.plName, "VP8", 31); - codec_settings_.plType = 126; codec_settings_.maxBitrate = 0; - codec_settings_.minBitrate = 0; codec_settings_.width = 1440; codec_settings_.height = 1080; - codec_settings_.maxFramerate = 30; - codec_settings_.startBitrate = 300; - codec_settings_.qpMax = 56; - codec_settings_.VP8()->complexity = kComplexityNormal; - codec_settings_.VP8()->numberOfTemporalLayers = 1; - codec_settings_.VP8()->tl_factory = &tl_factory_; + // Calls before InitEncode(). EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Release()); - int bit_rate = 300; + const int kBitrateKbps = 300; BitrateAllocation bitrate_allocation; - bitrate_allocation.SetBitrate(0, 0, bit_rate * 1000); + bitrate_allocation.SetBitrate(0, 0, kBitrateKbps * 1000); EXPECT_EQ(WEBRTC_VIDEO_CODEC_UNINITIALIZED, encoder_->SetRateAllocation(bitrate_allocation, codec_settings_.maxFramerate)); @@ -311,30 +308,18 @@ TEST_F(TestVp8Impl, EncodedRotationEqualsInputRotation) { TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) { SetUpEncodeDecode(); encoder_->Encode(*input_frame_, nullptr, nullptr); - EXPECT_GT(WaitForEncodedFrame(), 0u); + WaitForEncodedFrame(); // First frame should be a key frame. encoded_frame_._frameType = kVideoFrameKey; EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encoded_frame_, false, nullptr)); - EXPECT_GT(WaitForDecodedFrame(), 0u); + WaitForDecodedFrame(); ASSERT_TRUE(decoded_frame_); EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); ASSERT_TRUE(decoded_qp_); EXPECT_EQ(encoded_frame_.qp_, *decoded_qp_); } -TEST_F(TestVp8Impl, ParserQpEqualsEncodedQp) { - SetUpEncodeDecode(); - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, - encoder_->Encode(*input_frame_, nullptr, nullptr)); - EXPECT_GT(WaitForEncodedFrame(), 0u); - - int qp = 0; - ASSERT_TRUE(vp8::GetQp(encoded_frame_._buffer, encoded_frame_._length, &qp)); - - EXPECT_EQ(encoded_frame_.qp_, qp); -} - #if defined(WEBRTC_ANDROID) #define MAYBE_AlignedStrideEncodeDecode DISABLED_AlignedStrideEncodeDecode #else @@ -343,13 +328,13 @@ TEST_F(TestVp8Impl, ParserQpEqualsEncodedQp) { TEST_F(TestVp8Impl, MAYBE_AlignedStrideEncodeDecode) { SetUpEncodeDecode(); encoder_->Encode(*input_frame_, nullptr, nullptr); - EXPECT_GT(WaitForEncodedFrame(), 0u); + WaitForEncodedFrame(); // First frame should be a key frame. encoded_frame_._frameType = kVideoFrameKey; encoded_frame_.ntp_time_ms_ = kTestNtpTimeMs; EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encoded_frame_, false, nullptr)); - EXPECT_GT(WaitForDecodedFrame(), 0u); + WaitForDecodedFrame(); ASSERT_TRUE(decoded_frame_); // Compute PSNR on all planes (faster than SSIM). EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); @@ -365,7 +350,7 @@ TEST_F(TestVp8Impl, MAYBE_AlignedStrideEncodeDecode) { TEST_F(TestVp8Impl, MAYBE_DecodeWithACompleteKeyFrame) { SetUpEncodeDecode(); encoder_->Encode(*input_frame_, nullptr, nullptr); - EXPECT_GT(WaitForEncodedFrame(), 0u); + WaitForEncodedFrame(); // Setting complete to false -> should return an error. encoded_frame_._completeFrame = false; EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, @@ -393,7 +378,7 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { // Temporal layer 0. EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*input_frame_, nullptr, nullptr)); - ASSERT_TRUE(WaitForEncodedFrame()); + WaitForEncodedFrame(); EXPECT_EQ(0, codec_specific_info_.codecSpecific.VP8.temporalIdx); int16_t picture_id = codec_specific_info_.codecSpecific.VP8.pictureId; int tl0_pic_idx = codec_specific_info_.codecSpecific.VP8.tl0PicIdx; @@ -460,23 +445,21 @@ TEST_F(TestVp8Impl, EncoderRetainsRtpStateAfterRelease) { } TEST_F(TestVp8Impl, ScalingDisabledIfAutomaticResizeOff) { - webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_); - codec_settings_.VP8()->tl_factory = &tl_factory_; + codec_settings_.VP8()->frameDroppingOn = true; codec_settings_.VP8()->automaticResizeOn = false; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); + VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings(); EXPECT_FALSE(settings.enabled); } TEST_F(TestVp8Impl, ScalingEnabledIfAutomaticResizeOn) { - webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_); - codec_settings_.VP8()->tl_factory = &tl_factory_; + codec_settings_.VP8()->frameDroppingOn = true; codec_settings_.VP8()->automaticResizeOn = true; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); + VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings(); EXPECT_TRUE(settings.enabled); EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame); @@ -490,12 +473,11 @@ class TestVp8ImplWithForcedFallbackEnabled : public TestVp8Impl { }; TEST_F(TestVp8ImplWithForcedFallbackEnabled, MinPixelsPerFrameConfigured) { - webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings_); - codec_settings_.VP8()->tl_factory = &tl_factory_; + codec_settings_.VP8()->frameDroppingOn = true; codec_settings_.VP8()->automaticResizeOn = true; - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_settings_, kNumCores, kMaxPayloadSize)); + VideoEncoder::ScalingSettings settings = encoder_->GetScalingSettings(); EXPECT_TRUE(settings.enabled); EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame);