From 5fec128de94c0b2d0090de8eac692dce9aa23a80 Mon Sep 17 00:00:00 2001 From: sakal Date: Mon, 20 Feb 2017 06:43:58 -0800 Subject: [PATCH] Add QP for libvpx VP8 decoder. BUG=webrtc:6541, webrtc:7065 TBR=hta@webrtc.org Review-Url: https://codereview.webrtc.org/2656603002 Cr-Commit-Position: refs/heads/master@{#16722} --- .../codecs/vp8/simulcast_unittest.h | 2 +- .../codecs/vp8/test/vp8_impl_unittest.cc | 43 ++++++++++++++----- .../video_coding/codecs/vp8/vp8_impl.cc | 14 +++--- .../video_coding/codecs/vp8/vp8_impl.h | 3 +- webrtc/pc/rtcstats_integrationtest.cc | 12 +++--- 5 files changed, 50 insertions(+), 24 deletions(-) diff --git a/webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h b/webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h index b7e3e7d569..fb59646dcb 100644 --- a/webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h +++ b/webrtc/modules/video_coding/codecs/vp8/simulcast_unittest.h @@ -148,7 +148,7 @@ class Vp8TestDecodedImageCallback : public DecodedImageCallback { void Decoded(VideoFrame& decoded_image, rtc::Optional decode_time_ms, rtc::Optional qp) override { - RTC_NOTREACHED(); + Decoded(decoded_image); } int DecodedFrames() { return decoded_frames_; } 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 a47c209ad4..9a0f3db145 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 @@ -76,6 +76,7 @@ Vp8UnitTestEncodeCompleteCallback::OnEncodedImage( encoded_frame_->_timeStamp = encoded_frame._timeStamp; encoded_frame_->_frameType = encoded_frame._frameType; encoded_frame_->_completeFrame = encoded_frame._completeFrame; + encoded_frame_->qp_ = encoded_frame.qp_; encode_complete_ = true; return Result(Result::OK, 0); } @@ -90,22 +91,25 @@ bool Vp8UnitTestEncodeCompleteCallback::EncodeComplete() { class Vp8UnitTestDecodeCompleteCallback : public webrtc::DecodedImageCallback { public: - explicit Vp8UnitTestDecodeCompleteCallback(rtc::Optional* frame) - : decoded_frame_(frame), decode_complete(false) {} - int32_t Decoded(VideoFrame& frame) override; + explicit Vp8UnitTestDecodeCompleteCallback(rtc::Optional* frame, + rtc::Optional* qp) + : decoded_frame_(frame), decoded_qp_(qp), decode_complete(false) {} + int32_t Decoded(VideoFrame& frame) override { + RTC_NOTREACHED(); + return -1; + } int32_t Decoded(VideoFrame& frame, int64_t decode_time_ms) override { RTC_NOTREACHED(); return -1; } void Decoded(VideoFrame& frame, rtc::Optional decode_time_ms, - rtc::Optional qp) override { - RTC_NOTREACHED(); - } + rtc::Optional qp) override; bool DecodeComplete(); private: rtc::Optional* decoded_frame_; + rtc::Optional* decoded_qp_; bool decode_complete; }; @@ -117,10 +121,13 @@ bool Vp8UnitTestDecodeCompleteCallback::DecodeComplete() { return false; } -int Vp8UnitTestDecodeCompleteCallback::Decoded(VideoFrame& image) { - *decoded_frame_ = rtc::Optional(image); +void Vp8UnitTestDecodeCompleteCallback::Decoded( + VideoFrame& frame, + rtc::Optional decode_time_ms, + rtc::Optional qp) { + *decoded_frame_ = rtc::Optional(frame); + *decoded_qp_ = qp; decode_complete = true; - return 0; } class TestVp8Impl : public ::testing::Test { @@ -132,7 +139,7 @@ class TestVp8Impl : public ::testing::Test { encode_complete_callback_.reset( new Vp8UnitTestEncodeCompleteCallback(&encoded_frame_, 0, NULL)); decode_complete_callback_.reset( - new Vp8UnitTestDecodeCompleteCallback(&decoded_frame_)); + new Vp8UnitTestDecodeCompleteCallback(&decoded_frame_, &decoded_qp_)); encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); // Using a QCIF image (aligned stride (u,v planes) > width). @@ -210,6 +217,7 @@ class TestVp8Impl : public ::testing::Test { std::unique_ptr decoder_; EncodedImage encoded_frame_; rtc::Optional decoded_frame_; + rtc::Optional decoded_qp_; VideoCodec codec_inst_; TemporalLayersFactory tl_factory_; }; @@ -244,6 +252,21 @@ TEST_F(TestVp8Impl, EncoderParameterTest) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_inst_, 1)); } +TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) { + SetUpEncodeDecode(); + encoder_->Encode(*input_frame_, nullptr, nullptr); + EXPECT_GT(WaitForEncodedFrame(), 0u); + // 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); + ASSERT_TRUE(decoded_frame_); + EXPECT_GT(I420PSNR(input_frame_.get(), &*decoded_frame_), 36); + ASSERT_TRUE(decoded_qp_); + EXPECT_EQ(encoded_frame_.qp_, *decoded_qp_); +} + #if defined(WEBRTC_ANDROID) #define MAYBE_AlignedStrideEncodeDecode DISABLED_AlignedStrideEncodeDecode #else diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc index 2fbceb1d79..89752a9b82 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -1145,7 +1145,11 @@ int VP8DecoderImpl::Decode(const EncodedImage& input_image, } img = vpx_codec_get_frame(decoder_, &iter); - ret = ReturnFrame(img, input_image._timeStamp, input_image.ntp_time_ms_); + int qp; + vpx_codec_err_t vpx_ret = + vpx_codec_control(decoder_, VPXD_GET_LAST_QUANTIZER, &qp); + RTC_DCHECK_EQ(vpx_ret, VPX_CODEC_OK); + ret = ReturnFrame(img, input_image._timeStamp, input_image.ntp_time_ms_, qp); if (ret != 0) { // Reset to avoid requesting key frames too often. if (ret < 0 && propagation_cnt_ > 0) @@ -1205,7 +1209,8 @@ int VP8DecoderImpl::Decode(const EncodedImage& input_image, int VP8DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp, - int64_t ntp_time_ms) { + int64_t ntp_time_ms, + int qp) { if (img == NULL) { // Decoder OK and NULL image => No show frame return WEBRTC_VIDEO_CODEC_NO_OUTPUT; @@ -1232,9 +1237,8 @@ int VP8DecoderImpl::ReturnFrame(const vpx_image_t* img, VideoFrame decoded_image(buffer, timestamp, 0, kVideoRotation_0); decoded_image.set_ntp_time_ms(ntp_time_ms); - int ret = decode_complete_callback_->Decoded(decoded_image); - if (ret != 0) - return ret; + decode_complete_callback_->Decoded(decoded_image, rtc::Optional(), + rtc::Optional(qp)); // Remember image format for later image_format_ = img->fmt; diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h index d24dfa36a2..77e1dc459c 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h @@ -149,7 +149,8 @@ class VP8DecoderImpl : public VP8Decoder { int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp, - int64_t ntp_time_ms); + int64_t ntp_time_ms, + int qp); I420BufferPool buffer_pool_; DecodedImageCallback* decode_complete_callback_; diff --git a/webrtc/pc/rtcstats_integrationtest.cc b/webrtc/pc/rtcstats_integrationtest.cc index f27157be46..9e92cdab6d 100644 --- a/webrtc/pc/rtcstats_integrationtest.cc +++ b/webrtc/pc/rtcstats_integrationtest.cc @@ -536,14 +536,12 @@ class RTCStatsReportVerifier { const RTCInboundRTPStreamStats& inbound_stream) { RTCStatsVerifier verifier(report_, &inbound_stream); VerifyRTCRTPStreamStats(inbound_stream, &verifier); - // TODO(hbos): As soon as the decoders provide |qp_sum| values, this - // if-statement needs to be included. https://bugs.webrtc.org/7065 - // if (inbound_stream.media_type.is_defined() && - // *inbound_stream.media_type == "video") { - // verifier.TestMemberIsNonNegative(inbound_stream.qp_sum); - // } else { + if (inbound_stream.media_type.is_defined() && + *inbound_stream.media_type == "video") { + verifier.TestMemberIsNonNegative(inbound_stream.qp_sum); + } else { verifier.TestMemberIsUndefined(inbound_stream.qp_sum); - // } + } verifier.TestMemberIsNonNegative(inbound_stream.packets_received); verifier.TestMemberIsNonNegative(inbound_stream.bytes_received); verifier.TestMemberIsNonNegative(inbound_stream.packets_lost);