diff options
author | wuchengli@chromium.org <wuchengli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 09:58:40 +0000 |
---|---|---|
committer | wuchengli@chromium.org <wuchengli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 09:58:40 +0000 |
commit | 851d703c85c373b5150d3af2e65135229711e021 (patch) | |
tree | 7947450e65c4548ee44b8cc7c2e0753f25a81426 /content/renderer/media | |
parent | 16e52fe481c589061231eefa859bd5daddfd46a0 (diff) | |
download | chromium_src-851d703c85c373b5150d3af2e65135229711e021.zip chromium_src-851d703c85c373b5150d3af2e65135229711e021.tar.gz chromium_src-851d703c85c373b5150d3af2e65135229711e021.tar.bz2 |
Make sure the first VP8 frame for VDA is key frame.
Sometimes WebRTC gives video decoder an old frame after Reset.
VDA will fail if the first frame is not a key frame.
RTCVideoDecoder should return error and skip the frame when
this happens.
BUG=170345
TEST=Try http://apprtc.appspot.com/?debug=loopback on Chromebook Daisy.
Review URL: https://chromiumcodereview.appspot.com/23034002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217985 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/renderer/media')
-rw-r--r-- | content/renderer/media/rtc_video_decoder.cc | 17 | ||||
-rw-r--r-- | content/renderer/media/rtc_video_decoder.h | 5 | ||||
-rw-r--r-- | content/renderer/media/rtc_video_decoder_unittest.cc | 24 |
3 files changed, 45 insertions, 1 deletions
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc index 27030f6..c048b6b 100644 --- a/content/renderer/media/rtc_video_decoder.cc +++ b/content/renderer/media/rtc_video_decoder.cc @@ -195,8 +195,17 @@ int32_t RTCVideoDecoder::Decode( // Return an error to request a key frame. return WEBRTC_VIDEO_CODEC_ERROR; } - if (inputImage._frameType == webrtc::kKeyFrame) + if (inputImage._frameType == webrtc::kKeyFrame) { + DVLOG(2) << "Got key frame. size=" << inputImage._encodedWidth << "x" + << inputImage._encodedHeight; frame_size_.SetSize(inputImage._encodedWidth, inputImage._encodedHeight); + } else if (IsFirstBufferAfterReset(next_bitstream_buffer_id_, + reset_bitstream_buffer_id_)) { + // TODO(wuchengli): VDA should handle it. Remove this when + // http://crosbug.com/p/21913 is fixed. + DVLOG(1) << "The first frame should be a key frame. Drop this."; + return WEBRTC_VIDEO_CODEC_ERROR; + } // Create buffer metadata. BufferData buffer_data(next_bitstream_buffer_id_, @@ -526,6 +535,12 @@ bool RTCVideoDecoder::IsBufferAfterReset(int32 id_buffer, int32 id_reset) { return diff < ID_HALF; } +bool RTCVideoDecoder::IsFirstBufferAfterReset(int32 id_buffer, int32 id_reset) { + if (id_reset == ID_INVALID) + return id_buffer == 0; + return id_buffer == ((id_reset + 1) & ID_LAST); +} + void RTCVideoDecoder::SaveToDecodeBuffers_Locked( const webrtc::EncodedImage& input_image, scoped_ptr<SHMBuffer> shm_buffer, diff --git a/content/renderer/media/rtc_video_decoder.h b/content/renderer/media/rtc_video_decoder.h index 7a2686e..13adf37 100644 --- a/content/renderer/media/rtc_video_decoder.h +++ b/content/renderer/media/rtc_video_decoder.h @@ -110,6 +110,7 @@ class CONTENT_EXPORT RTCVideoDecoder }; FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, IsBufferAfterReset); + FRIEND_TEST_ALL_PREFIXES(RTCVideoDecoderTest, IsFirstBufferAfterReset); // The meessage loop of |factories| will be saved to |vda_loop_proxy_|. RTCVideoDecoder( @@ -126,6 +127,10 @@ class CONTENT_EXPORT RTCVideoDecoder // This handles the wraparound. bool IsBufferAfterReset(int32 id_buffer, int32 id_reset); + // Returns true if bitstream buffer |id_buffer| is the first buffer after + // |id_reset|. + bool IsFirstBufferAfterReset(int32 id_buffer, int32 id_reset); + // Saves a WebRTC buffer in |decode_buffers_| for decode. void SaveToDecodeBuffers_Locked(const webrtc::EncodedImage& input_image, scoped_ptr<SHMBuffer> shm_buffer, diff --git a/content/renderer/media/rtc_video_decoder_unittest.cc b/content/renderer/media/rtc_video_decoder_unittest.cc index 3355b6a..ba27a5767 100644 --- a/content/renderer/media/rtc_video_decoder_unittest.cc +++ b/content/renderer/media/rtc_video_decoder_unittest.cc @@ -192,4 +192,28 @@ TEST_F(RTCVideoDecoderTest, IsBufferAfterReset) { RTCVideoDecoder::ID_LAST)); } +TEST_F(RTCVideoDecoderTest, IsFirstBufferAfterReset) { + EXPECT_TRUE( + rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_INVALID)); + EXPECT_FALSE( + rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_INVALID)); + EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(0, 0)); + EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset(1, 0)); + EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(2, 0)); + + EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_HALF, + RTCVideoDecoder::ID_HALF)); + EXPECT_TRUE(rtc_decoder_->IsFirstBufferAfterReset( + RTCVideoDecoder::ID_HALF + 1, RTCVideoDecoder::ID_HALF)); + EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset( + RTCVideoDecoder::ID_HALF + 2, RTCVideoDecoder::ID_HALF)); + + EXPECT_FALSE(rtc_decoder_->IsFirstBufferAfterReset(RTCVideoDecoder::ID_LAST, + RTCVideoDecoder::ID_LAST)); + EXPECT_TRUE( + rtc_decoder_->IsFirstBufferAfterReset(0, RTCVideoDecoder::ID_LAST)); + EXPECT_FALSE( + rtc_decoder_->IsFirstBufferAfterReset(1, RTCVideoDecoder::ID_LAST)); +} + } // content |