diff --git a/webrtc/modules/video_coding/codecs/test_framework/test.cc b/webrtc/modules/video_coding/codecs/test_framework/test.cc index 2d55f02c8..a66b53946 100644 --- a/webrtc/modules/video_coding/codecs/test_framework/test.cc +++ b/webrtc/modules/video_coding/codecs/test_framework/test.cc @@ -150,8 +150,8 @@ CodecTest::VideoEncodedBufferToEncodedImage(VideoFrame& videoBuffer, image._buffer = videoBuffer.Buffer(); image._length = videoBuffer.Length(); image._size = videoBuffer.Size(); - //image._frameType = static_cast - // (videoBuffer.GetFrameType()); + // image._frameType = static_cast + // (videoBuffer.GetFrameType()); image._timeStamp = videoBuffer.TimeStamp(); image._encodedWidth = videoBuffer.Width(); image._encodedHeight = videoBuffer.Height(); diff --git a/webrtc/modules/video_coding/codecs/test_framework/unit_test.cc b/webrtc/modules/video_coding/codecs/test_framework/unit_test.cc index 0fdd447b2..3b034e01c 100644 --- a/webrtc/modules/video_coding/codecs/test_framework/unit_test.cc +++ b/webrtc/modules/video_coding/codecs/test_framework/unit_test.cc @@ -32,6 +32,7 @@ _refEncFrame(NULL), _refDecFrame(NULL), _refEncFrameLength(0), _sourceFile(NULL), +is_key_frame_(false), _encodeCompleteCallback(NULL), _decodeCompleteCallback(NULL) { @@ -48,6 +49,7 @@ _refEncFrame(NULL), _refDecFrame(NULL), _refEncFrameLength(0), _sourceFile(NULL), +is_key_frame_(false), _encodeCompleteCallback(NULL), _decodeCompleteCallback(NULL) { @@ -254,23 +256,27 @@ UnitTest::Setup() ASSERT_FALSE(SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK); unsigned int frameLength = 0; - int i=0; + int i = 0; _inputVideoBuffer.CreateEmptyFrame(_inst.width, _inst.height, _inst.width, (_inst.width + 1) / 2, (_inst.width + 1) / 2); while (frameLength == 0) { + EncodedImage encodedImage; if (i > 0) { - // Insert yet another frame + // Insert yet another frame. ASSERT_TRUE(fread(_refFrame, 1, _lengthSourceFrame, _sourceFile) == _lengthSourceFrame); EXPECT_EQ(0, ConvertToI420(kI420, _refFrame, 0, 0, _width, _height, 0, kRotateNone, &_inputVideoBuffer)); _encoder->Encode(_inputVideoBuffer, NULL, NULL); ASSERT_TRUE(WaitForEncodedFrame() > 0); + } else { + // The first frame is always a key frame. + encodedImage._frameType = kKeyFrame; } - EncodedImage encodedImage; + VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); ASSERT_TRUE(_decoder->Decode(encodedImage, 0, NULL) == WEBRTC_VIDEO_CODEC_OK); @@ -332,6 +338,10 @@ UnitTest::Decode() { return WEBRTC_VIDEO_CODEC_OK; } + if (is_key_frame_) { + encodedImage._frameType = kKeyFrame; + } + int ret = _decoder->Decode(encodedImage, 0, NULL); unsigned int frameLength = WaitForDecodedFrame(); assert(ret == WEBRTC_VIDEO_CODEC_OK && (frameLength == 0 || frameLength @@ -526,6 +536,10 @@ UnitTest::Perform() memset(tmpBuf, 0, _refEncFrameLength); _encodedVideoBuffer.CopyFrame(_refEncFrameLength, tmpBuf); VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); + if (i == 0) { + // First frame is a key frame. + is_key_frame_ = true; + } ret = _decoder->Decode(encodedImage, false, NULL); EXPECT_TRUE(ret <= 0); if (ret == 0) @@ -543,6 +557,8 @@ UnitTest::Perform() ASSERT_FALSE(SetCodecSpecificParameters() != WEBRTC_VIDEO_CODEC_OK); frameLength = 0; VideoEncodedBufferToEncodedImage(_encodedVideoBuffer, encodedImage); + // first frame is a key frame. + encodedImage._frameType = kKeyFrame; while (frameLength == 0) { _decoder->Decode(encodedImage, false, NULL); @@ -686,6 +702,10 @@ UnitTest::Perform() encTimeStamp = _encodedVideoBuffer.TimeStamp(); EXPECT_TRUE(_inputVideoBuffer.timestamp() == static_cast(encTimeStamp)); + if (frames == 0) { + // First frame is always a key frame. + is_key_frame_ = true; + } frameLength = Decode(); if (frameLength == 0) diff --git a/webrtc/modules/video_coding/codecs/test_framework/unit_test.h b/webrtc/modules/video_coding/codecs/test_framework/unit_test.h index 34d487853..4e2fea0e7 100644 --- a/webrtc/modules/video_coding/codecs/test_framework/unit_test.h +++ b/webrtc/modules/video_coding/codecs/test_framework/unit_test.h @@ -63,6 +63,7 @@ protected: unsigned char* _refDecFrame; unsigned int _refEncFrameLength; FILE* _sourceFile; + bool is_key_frame_; UnitTestEncodeCompleteCallback* _encodeCompleteCallback; UnitTestDecodeCompleteCallback* _decodeCompleteCallback; 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 4a1a2ca27..4f7b27600 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 @@ -106,6 +106,43 @@ class TestVp8Impl : public ::testing::Test { Vp8UnitTestDecodeCompleteCallback(&decoded_video_frame_)); encoder_->RegisterEncodeCompleteCallback(encode_complete_callback_.get()); decoder_->RegisterDecodeCompleteCallback(decode_complete_callback_.get()); + // Using a QCIF image (aligned stride (u,v planes) > width). + // Processing only one frame. + const VideoSource source(test::ResourcePath("paris_qcif", "yuv"), kQCIF); + length_source_frame_ = source.GetFrameLength(); + source_buffer_.reset(new uint8_t[length_source_frame_]); + source_file_ = fopen(source.GetFileName().c_str(), "rb"); + ASSERT_TRUE(source_file_ != NULL); + // Set input frame. + ASSERT_EQ(fread(source_buffer_.get(), 1, length_source_frame_, + source_file_), length_source_frame_); + codec_inst_.width = source.GetWidth(); + codec_inst_.height = source.GetHeight(); + codec_inst_.maxFramerate = source.GetFrameRate(); + // Setting aligned stride values. + int stride_uv = 0; + int stride_y = 0; + Calc16ByteAlignedStride(codec_inst_.width, &stride_y, &stride_uv); + EXPECT_EQ(stride_y, 176); + EXPECT_EQ(stride_uv, 96); + + input_frame_.CreateEmptyFrame(codec_inst_.width, codec_inst_.height, + stride_y, stride_uv, stride_uv); + // Using ConvertToI420 to add stride to the image. + EXPECT_EQ(0, ConvertToI420(kI420, source_buffer_.get(), 0, 0, + codec_inst_.width, codec_inst_.height, + 0, kRotateNone, &input_frame_)); + } + + void SetUpEncodeDecode() { + codec_inst_.startBitrate = 300; + codec_inst_.maxBitrate = 4000; + codec_inst_.qpMax = 56; + codec_inst_.codecSpecific.VP8.denoisingOn = true; + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->InitEncode(&codec_inst_, 1, 1440)); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_inst_, 1)); } int WaitForEncodedFrame() const { @@ -143,6 +180,7 @@ class TestVp8Impl : public ::testing::Test { scoped_ptr decode_complete_callback_; scoped_array source_buffer_; FILE* source_file_; + I420VideoFrame input_frame_; scoped_ptr encoder_; scoped_ptr decoder_; VideoFrame encoded_video_frame_; @@ -190,49 +228,38 @@ TEST_F(TestVp8Impl, EncoderParameterTest) { } TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(AlignedStrideEncodeDecode)) { - // Using a QCIF image (aligned stride (u,v planse) > width). - // Processing only one frame. - const VideoSource source(test::ResourcePath("paris_qcif", "yuv"), kQCIF); - length_source_frame_ = source.GetFrameLength(); - source_buffer_.reset(new uint8_t[length_source_frame_]); - source_file_ = fopen(source.GetFileName().c_str(), "rb"); - ASSERT_TRUE(source_file_ != NULL); - codec_inst_.maxFramerate = source.GetFrameRate(); - codec_inst_.startBitrate = 300; - codec_inst_.maxBitrate = 4000; - codec_inst_.qpMax = 56; - codec_inst_.width = source.GetWidth(); - codec_inst_.height = source.GetHeight(); - codec_inst_.codecSpecific.VP8.denoisingOn = true; - - // Get input frame. - ASSERT_EQ(fread(source_buffer_.get(), 1, length_source_frame_, source_file_), - length_source_frame_); - // Setting aligned stride values. - int stride_uv = 0; - int stride_y = 0; - Calc16ByteAlignedStride(codec_inst_.width, &stride_y, &stride_uv); - EXPECT_EQ(stride_y, 176); - EXPECT_EQ(stride_uv, 96); - - I420VideoFrame input_frame; - input_frame.CreateEmptyFrame(codec_inst_.width, codec_inst_.height, - stride_y, stride_uv, stride_uv); - // Using ConvertToI420 to add stride to the image. - EXPECT_EQ(0, ConvertToI420(kI420, source_buffer_.get(), 0, 0, - codec_inst_.width, codec_inst_.height, - 0, kRotateNone, &input_frame)); - - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->InitEncode(&codec_inst_, 1, 1440)); - encoder_->Encode(input_frame, NULL, NULL); + SetUpEncodeDecode(); + encoder_->Encode(input_frame_, NULL, NULL); EXPECT_GT(WaitForEncodedFrame(), 0); - EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->InitDecode(&codec_inst_, 1)); EncodedImage encodedImage; VideoFrameToEncodedImage(encoded_video_frame_, encodedImage); + // First frame should be a key frame. + encodedImage._frameType = kKeyFrame; EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Decode(encodedImage, false, NULL)); EXPECT_GT(WaitForDecodedFrame(), 0); // Compute PSNR on all planes (faster than SSIM). - EXPECT_GT(I420PSNR(&input_frame, &decoded_video_frame_), 36); + EXPECT_GT(I420PSNR(&input_frame_, &decoded_video_frame_), 36); +} + +TEST_F(TestVp8Impl, DecodeWithACompleteKeyFrame) { + SetUpEncodeDecode(); + encoder_->Encode(input_frame_, NULL, NULL); + EXPECT_GT(WaitForEncodedFrame(), 0); + EncodedImage encodedImage; + VideoFrameToEncodedImage(encoded_video_frame_, encodedImage); + // Setting complete to false -> should return an error. + encodedImage._completeFrame = false; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, + decoder_->Decode(encodedImage, false, NULL)); + // Setting complete back to true. + encodedImage._completeFrame = true; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_ERROR, + decoder_->Decode(encodedImage, false, NULL)); + // Now setting a key frame. + encodedImage._frameType = kKeyFrame; + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + decoder_->Decode(encodedImage, false, NULL)); + EXPECT_GT(I420PSNR(&input_frame_, &decoded_video_frame_), 36); } } // namespace webrtc diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc index 488d951c8..c98849830 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.cc @@ -502,8 +502,8 @@ VP8DecoderImpl::VP8DecoderImpl() image_format_(VPX_IMG_FMT_NONE), ref_frame_(NULL), propagation_cnt_(-1), - latest_keyframe_complete_(false), - mfqe_enabled_(false) { + mfqe_enabled_(false), + key_frame_required_(true) { memset(&codec_, 0, sizeof(codec_)); } @@ -518,7 +518,6 @@ int VP8DecoderImpl::Reset() { } InitDecode(&codec_, 1); propagation_cnt_ = -1; - latest_keyframe_complete_ = false; mfqe_enabled_ = false; return WEBRTC_VIDEO_CODEC_OK; } @@ -571,9 +570,12 @@ int VP8DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) { } propagation_cnt_ = -1; - latest_keyframe_complete_ = false; inited_ = true; + + // Always start with a complete key frame. + key_frame_required_ = true; + return WEBRTC_VIDEO_CODEC_OK; } @@ -615,6 +617,18 @@ int VP8DecoderImpl::Decode(const EncodedImage& input_image, } #endif + + // Always start with a complete key frame. + if (key_frame_required_) { + if (input_image._frameType != kKeyFrame) + return WEBRTC_VIDEO_CODEC_ERROR; + // We have a key frame - is it complete? + if (input_image._completeFrame) { + key_frame_required_ = false; + } else { + return WEBRTC_VIDEO_CODEC_ERROR; + } + } // Restrict error propagation using key frame requests. Disabled when // the feedback mode is enabled (RPS). // Reset on a key frame refresh. @@ -708,9 +722,7 @@ int VP8DecoderImpl::Decode(const EncodedImage& input_image, // Whenever we receive an incomplete key frame all reference buffers will // be corrupt. If that happens we must request new key frames until we // decode a complete. - if (input_image._frameType == kKeyFrame) - latest_keyframe_complete_ = input_image._completeFrame; - if (!latest_keyframe_complete_) + if (input_image._frameType == kKeyFrame && !input_image._completeFrame) return WEBRTC_VIDEO_CODEC_ERROR; // Check for reference updates and last reference buffer corruption and diff --git a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h index d420ba024..26dd52e6a 100644 --- a/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h +++ b/webrtc/modules/video_coding/codecs/vp8/vp8_impl.h @@ -226,8 +226,8 @@ class VP8DecoderImpl : public VP8Decoder { int image_format_; vpx_ref_frame_t* ref_frame_; int propagation_cnt_; - bool latest_keyframe_complete_; bool mfqe_enabled_; + bool key_frame_required_; }; // end of VP8Decoder class } // namespace webrtc diff --git a/webrtc/modules/video_coding/main/source/codec_database.cc b/webrtc/modules/video_coding/main/source/codec_database.cc index 6f50ddddc..e41c6b425 100644 --- a/webrtc/modules/video_coding/main/source/codec_database.cc +++ b/webrtc/modules/video_coding/main/source/codec_database.cc @@ -597,8 +597,7 @@ VCMGenericDecoder* VCMCodecDataBase::CreateAndInitDecoder( } if (ptr_decoder->InitDecode(decoder_item->settings.get(), - decoder_item->number_of_cores, - decoder_item->require_key_frame) < 0) { + decoder_item->number_of_cores) < 0) { ReleaseDecoder(ptr_decoder); return NULL; } diff --git a/webrtc/modules/video_coding/main/source/generic_decoder.cc b/webrtc/modules/video_coding/main/source/generic_decoder.cc index 12464d18d..50b1eda70 100644 --- a/webrtc/modules/video_coding/main/source/generic_decoder.cc +++ b/webrtc/modules/video_coding/main/source/generic_decoder.cc @@ -133,9 +133,7 @@ _frameInfos(), _nextFrameInfoIdx(0), _decoder(decoder), _codecType(kVideoCodecUnknown), -_isExternal(isExternal), -_requireKeyFrame(false), -_keyFrameDecoded(false) +_isExternal(isExternal) { } @@ -144,11 +142,8 @@ VCMGenericDecoder::~VCMGenericDecoder() } int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings, - int32_t numberOfCores, - bool requireKeyFrame) + int32_t numberOfCores) { - _requireKeyFrame = requireKeyFrame; - _keyFrameDecoded = false; _codecType = settings->codecType; return _decoder.InitDecode(settings, numberOfCores); @@ -157,15 +152,6 @@ int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings, int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame, int64_t nowMs) { - if (_requireKeyFrame && - !_keyFrameDecoded && - frame.FrameType() != kVideoFrameKey && - frame.FrameType() != kVideoFrameGolden) - { - // Require key frame is enabled, meaning that one key frame must be decoded - // before we can decode delta frames. - return VCM_CODEC_ERROR; - } _frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = nowMs; _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs(); _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]); @@ -194,22 +180,17 @@ int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame, // No output _callback->Pop(frame.TimeStamp()); } - // Update the key frame decoded variable so that we know whether or not we've decoded a key frame since reset. - _keyFrameDecoded = (_keyFrameDecoded || - frame.FrameType() == kVideoFrameKey); return ret; } int32_t VCMGenericDecoder::Release() { - _keyFrameDecoded = false; return _decoder.Release(); } int32_t VCMGenericDecoder::Reset() { - _keyFrameDecoded = false; return _decoder.Reset(); } diff --git a/webrtc/modules/video_coding/main/source/generic_decoder.h b/webrtc/modules/video_coding/main/source/generic_decoder.h index 7144a099f..e1993fbb9 100644 --- a/webrtc/modules/video_coding/main/source/generic_decoder.h +++ b/webrtc/modules/video_coding/main/source/generic_decoder.h @@ -70,8 +70,7 @@ public: * Initialize the decoder with the information from the VideoCodec */ int32_t InitDecode(const VideoCodec* settings, - int32_t numberOfCores, - bool requireKeyFrame); + int32_t numberOfCores); /** * Decode to a raw I420 frame, @@ -115,7 +114,6 @@ protected: VideoDecoder& _decoder; VideoCodecType _codecType; bool _isExternal; - bool _requireKeyFrame; bool _keyFrameDecoded; }; diff --git a/webrtc/modules/video_coding/main/source/jitter_buffer.cc b/webrtc/modules/video_coding/main/source/jitter_buffer.cc index 4953b2898..fbfe852ca 100644 --- a/webrtc/modules/video_coding/main/source/jitter_buffer.cc +++ b/webrtc/modules/video_coding/main/source/jitter_buffer.cc @@ -508,19 +508,13 @@ bool VCMJitterBuffer::NextMaybeIncompleteTimestamp(uint32_t* timestamp) { return false; } VCMFrameBuffer* oldest_frame = decodable_frames_.Front(); - // If we have exactly one frame in the buffer, release it only if it is - // complete. We know decodable_frames_ is not empty due to the prevoius + // complete. We know decodable_frames_ is not empty due to the previous // check. if (decodable_frames_.size() == 1 && incomplete_frames_.empty() && oldest_frame->GetState() != kStateComplete) { return false; } - // Always start with a complete key frame. - if (last_decoded_state_.in_initial_state() && - oldest_frame->FrameType() != kVideoFrameKey) { - return false; - } *timestamp = oldest_frame->TimeStamp(); return true; diff --git a/webrtc/video_engine/test/libvietest/testbed/tb_I420_codec.cc b/webrtc/video_engine/test/libvietest/testbed/tb_I420_codec.cc index bf81ebb86..5ed5e46c9 100644 --- a/webrtc/video_engine/test/libvietest/testbed/tb_I420_codec.cc +++ b/webrtc/video_engine/test/libvietest/testbed/tb_I420_codec.cc @@ -260,12 +260,19 @@ int32_t TbI420Decoder::Decode( return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } + // Only send complete frames. + if (static_cast(inputImage._length) != + webrtc::CalcBufferSize(webrtc::kI420,_width,_height)) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + int ret = ConvertToI420(webrtc::kI420, inputImage._buffer, 0, 0, _width, _height, 0, webrtc::kRotateNone, &_decodedImage); if (ret < 0) return WEBRTC_VIDEO_CODEC_ERROR; + _decodedImage.set_timestamp(inputImage._timeStamp); _decodeCompleteCallback->Decoded(_decodedImage);