summaryrefslogtreecommitdiffstats
path: root/content/renderer/media
diff options
context:
space:
mode:
authorwuchengli@chromium.org <wuchengli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 09:58:40 +0000
committerwuchengli@chromium.org <wuchengli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-16 09:58:40 +0000
commit851d703c85c373b5150d3af2e65135229711e021 (patch)
tree7947450e65c4548ee44b8cc7c2e0753f25a81426 /content/renderer/media
parent16e52fe481c589061231eefa859bd5daddfd46a0 (diff)
downloadchromium_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.cc17
-rw-r--r--content/renderer/media/rtc_video_decoder.h5
-rw-r--r--content/renderer/media/rtc_video_decoder_unittest.cc24
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