Revert 4597 "Don't force key frame when decoding with errors"
> Don't force key frame when decoding with errors
>
> BUG=2241
> R=stefan@webrtc.org
>
> Review URL: https://webrtc-codereview.appspot.com/2036004
TBR=mikhal@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2093004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@4600 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/video_coding/codecs/test_framework/test.cc b/modules/video_coding/codecs/test_framework/test.cc
index a66b539..2d55f02 100644
--- a/modules/video_coding/codecs/test_framework/test.cc
+++ b/modules/video_coding/codecs/test_framework/test.cc
@@ -150,8 +150,8 @@
image._buffer = videoBuffer.Buffer();
image._length = videoBuffer.Length();
image._size = videoBuffer.Size();
- // image._frameType = static_cast<VideoFrameType>
- // (videoBuffer.GetFrameType());
+ //image._frameType = static_cast<VideoFrameType>
+ // (videoBuffer.GetFrameType());
image._timeStamp = videoBuffer.TimeStamp();
image._encodedWidth = videoBuffer.Width();
image._encodedHeight = videoBuffer.Height();
diff --git a/modules/video_coding/codecs/test_framework/unit_test.cc b/modules/video_coding/codecs/test_framework/unit_test.cc
index 3b034e0..0fdd447 100644
--- a/modules/video_coding/codecs/test_framework/unit_test.cc
+++ b/modules/video_coding/codecs/test_framework/unit_test.cc
@@ -32,7 +32,6 @@
_refDecFrame(NULL),
_refEncFrameLength(0),
_sourceFile(NULL),
-is_key_frame_(false),
_encodeCompleteCallback(NULL),
_decodeCompleteCallback(NULL)
{
@@ -49,7 +48,6 @@
_refDecFrame(NULL),
_refEncFrameLength(0),
_sourceFile(NULL),
-is_key_frame_(false),
_encodeCompleteCallback(NULL),
_decodeCompleteCallback(NULL)
{
@@ -256,27 +254,23 @@
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);
@@ -338,10 +332,6 @@
{
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
@@ -536,10 +526,6 @@
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)
@@ -557,8 +543,6 @@
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);
@@ -702,10 +686,6 @@
encTimeStamp = _encodedVideoBuffer.TimeStamp();
EXPECT_TRUE(_inputVideoBuffer.timestamp() ==
static_cast<unsigned>(encTimeStamp));
- if (frames == 0) {
- // First frame is always a key frame.
- is_key_frame_ = true;
- }
frameLength = Decode();
if (frameLength == 0)
diff --git a/modules/video_coding/codecs/test_framework/unit_test.h b/modules/video_coding/codecs/test_framework/unit_test.h
index 4e2fea0..34d4878 100644
--- a/modules/video_coding/codecs/test_framework/unit_test.h
+++ b/modules/video_coding/codecs/test_framework/unit_test.h
@@ -63,7 +63,6 @@
unsigned char* _refDecFrame;
unsigned int _refEncFrameLength;
FILE* _sourceFile;
- bool is_key_frame_;
UnitTestEncodeCompleteCallback* _encodeCompleteCallback;
UnitTestDecodeCompleteCallback* _decodeCompleteCallback;
diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
index 4f7b276..4a1a2ca 100644
--- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
+++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc
@@ -106,43 +106,6 @@
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 {
@@ -180,7 +143,6 @@
scoped_ptr<Vp8UnitTestDecodeCompleteCallback> decode_complete_callback_;
scoped_array<uint8_t> source_buffer_;
FILE* source_file_;
- I420VideoFrame input_frame_;
scoped_ptr<VideoEncoder> encoder_;
scoped_ptr<VideoDecoder> decoder_;
VideoFrame encoded_video_frame_;
@@ -228,38 +190,49 @@
}
TEST_F(TestVp8Impl, DISABLED_ON_ANDROID(AlignedStrideEncodeDecode)) {
- SetUpEncodeDecode();
- encoder_->Encode(input_frame_, NULL, NULL);
+ // 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);
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);
-}
-
-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);
+ EXPECT_GT(I420PSNR(&input_frame, &decoded_video_frame_), 36);
}
} // namespace webrtc
diff --git a/modules/video_coding/codecs/vp8/vp8_impl.cc b/modules/video_coding/codecs/vp8/vp8_impl.cc
index c988498..488d951 100644
--- a/modules/video_coding/codecs/vp8/vp8_impl.cc
+++ b/modules/video_coding/codecs/vp8/vp8_impl.cc
@@ -502,8 +502,8 @@
image_format_(VPX_IMG_FMT_NONE),
ref_frame_(NULL),
propagation_cnt_(-1),
- mfqe_enabled_(false),
- key_frame_required_(true) {
+ latest_keyframe_complete_(false),
+ mfqe_enabled_(false) {
memset(&codec_, 0, sizeof(codec_));
}
@@ -518,6 +518,7 @@
}
InitDecode(&codec_, 1);
propagation_cnt_ = -1;
+ latest_keyframe_complete_ = false;
mfqe_enabled_ = false;
return WEBRTC_VIDEO_CODEC_OK;
}
@@ -570,12 +571,9 @@
}
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;
}
@@ -617,18 +615,6 @@
}
#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.
@@ -722,7 +708,9 @@
// 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 && !input_image._completeFrame)
+ if (input_image._frameType == kKeyFrame)
+ latest_keyframe_complete_ = input_image._completeFrame;
+ if (!latest_keyframe_complete_)
return WEBRTC_VIDEO_CODEC_ERROR;
// Check for reference updates and last reference buffer corruption and
diff --git a/modules/video_coding/codecs/vp8/vp8_impl.h b/modules/video_coding/codecs/vp8/vp8_impl.h
index 26dd52e..d420ba0 100644
--- a/modules/video_coding/codecs/vp8/vp8_impl.h
+++ b/modules/video_coding/codecs/vp8/vp8_impl.h
@@ -226,8 +226,8 @@
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/modules/video_coding/main/source/codec_database.cc b/modules/video_coding/main/source/codec_database.cc
index e41c6b4..6f50ddd 100644
--- a/modules/video_coding/main/source/codec_database.cc
+++ b/modules/video_coding/main/source/codec_database.cc
@@ -597,7 +597,8 @@
}
if (ptr_decoder->InitDecode(decoder_item->settings.get(),
- decoder_item->number_of_cores) < 0) {
+ decoder_item->number_of_cores,
+ decoder_item->require_key_frame) < 0) {
ReleaseDecoder(ptr_decoder);
return NULL;
}
diff --git a/modules/video_coding/main/source/generic_decoder.cc b/modules/video_coding/main/source/generic_decoder.cc
index 50b1eda..12464d1 100644
--- a/modules/video_coding/main/source/generic_decoder.cc
+++ b/modules/video_coding/main/source/generic_decoder.cc
@@ -133,7 +133,9 @@
_nextFrameInfoIdx(0),
_decoder(decoder),
_codecType(kVideoCodecUnknown),
-_isExternal(isExternal)
+_isExternal(isExternal),
+_requireKeyFrame(false),
+_keyFrameDecoded(false)
{
}
@@ -142,8 +144,11 @@
}
int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings,
- int32_t numberOfCores)
+ int32_t numberOfCores,
+ bool requireKeyFrame)
{
+ _requireKeyFrame = requireKeyFrame;
+ _keyFrameDecoded = false;
_codecType = settings->codecType;
return _decoder.InitDecode(settings, numberOfCores);
@@ -152,6 +157,15 @@
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]);
@@ -180,17 +194,22 @@
// 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/modules/video_coding/main/source/generic_decoder.h b/modules/video_coding/main/source/generic_decoder.h
index e1993fb..7144a09 100644
--- a/modules/video_coding/main/source/generic_decoder.h
+++ b/modules/video_coding/main/source/generic_decoder.h
@@ -70,7 +70,8 @@
* Initialize the decoder with the information from the VideoCodec
*/
int32_t InitDecode(const VideoCodec* settings,
- int32_t numberOfCores);
+ int32_t numberOfCores,
+ bool requireKeyFrame);
/**
* Decode to a raw I420 frame,
@@ -114,6 +115,7 @@
VideoDecoder& _decoder;
VideoCodecType _codecType;
bool _isExternal;
+ bool _requireKeyFrame;
bool _keyFrameDecoded;
};
diff --git a/modules/video_coding/main/source/jitter_buffer.cc b/modules/video_coding/main/source/jitter_buffer.cc
index fbfe852..4953b28 100644
--- a/modules/video_coding/main/source/jitter_buffer.cc
+++ b/modules/video_coding/main/source/jitter_buffer.cc
@@ -508,13 +508,19 @@
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 previous
+ // complete. We know decodable_frames_ is not empty due to the prevoius
// 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/video_engine/test/libvietest/testbed/tb_I420_codec.cc b/video_engine/test/libvietest/testbed/tb_I420_codec.cc
index 5ed5e46..bf81ebb 100644
--- a/video_engine/test/libvietest/testbed/tb_I420_codec.cc
+++ b/video_engine/test/libvietest/testbed/tb_I420_codec.cc
@@ -260,19 +260,12 @@
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
- // Only send complete frames.
- if (static_cast<int>(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);