Chromium Code Reviews| Index: content/renderer/media/rtc_video_decoder_bridge_tv_unittest.cc |
| diff --git a/content/renderer/media/rtc_video_decoder_bridge_tv_unittest.cc b/content/renderer/media/rtc_video_decoder_bridge_tv_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1a78a8c48d0fa03c6db619346b36f5345ca229e8 |
| --- /dev/null |
| +++ b/content/renderer/media/rtc_video_decoder_bridge_tv_unittest.cc |
| @@ -0,0 +1,342 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/synchronization/waitable_event.h" |
| +#include "base/task_runner_util.h" |
| +#include "content/renderer/media/mock_media_stream_dependency_factory.h" |
| +#include "content/renderer/media/rtc_video_decoder_bridge_tv.h" |
| +#include "media/base/decoder_buffer.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "third_party/webrtc/modules/video_coding/codecs/interface/mock/mock_video_codec_interface.h" |
| + |
| +using ::testing::_; |
| +using ::testing::Return; |
| + |
| +namespace content { |
| + |
| +class RTCVideoDecoderBridgeTvTest : public ::testing::Test { |
| + public: |
| + RTCVideoDecoderBridgeTvTest() |
| + : bridge_(RTCVideoDecoderBridgeTv::Get()), |
| + demuxer_(NULL), |
| + video_stream_(NULL), |
| + size_(1280, 720), |
| + input_image_(&data_, sizeof(data_), sizeof(data_)), |
| + data_('a'), |
| + read_event_(false, false), |
| + decoder_thread_("Test decoeder thread"), |
| + decoder_thread_event_(false, false) {} |
| + |
| + void ReadCallback(media::DemuxerStream::Status status, |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
intentionally ignoring |status|?
wonsik
2013/05/14 12:53:57
Added some sanity checks.
|
| + const scoped_refptr<media::DecoderBuffer>& decoder_buffer) { |
| + last_decoder_buffer_ = decoder_buffer; |
| + read_event_.Signal(); |
| + } |
| + |
| + void ExpectEqualsAndSignal(int32_t expected_result, int32_t actual_result) { |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
s/_result//g
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
s/_t//g
wonsik
2013/05/14 12:53:57
Done.
wonsik
2013/05/14 12:53:57
Well they are from the definition of webrtc::Video
|
| + EXPECT_EQ(expected_result, actual_result); |
| + decoder_thread_event_.Signal(); |
| + } |
| + |
| + void ExpectNotEqualsAndSignal(int32_t unexpected_result, |
| + int32_t actual_result) { |
| + EXPECT_NE(unexpected_result, actual_result); |
| + decoder_thread_event_.Signal(); |
| + } |
| + |
| + protected: |
| + virtual void SetUp() OVERRIDE { |
| + memset(&codec_, 0, sizeof(codec_)); |
| + message_loop_proxy_ = base::MessageLoopProxy::current(); |
| + input_image_._frameType = webrtc::kKeyFrame; |
| + input_image_._encodedWidth = size_.width(); |
| + input_image_._encodedHeight = size_.height(); |
| + input_image_._completeFrame = true; |
| + decoder_thread_.Start(); |
| + } |
| + |
| + virtual void TearDown() OVERRIDE { |
| + if (demuxer_) { |
| + bridge_->ReleaseOwnership(&owner_factory_); |
| + bridge_->DestroyDemuxer(demuxer_); |
| + } |
| + decoder_thread_.Stop(); |
| + } |
| + |
| + base::Callback<void(int32_t)> BindExpectEquals( |
| + int32_t expected_result) { |
| + return base::Bind(&RTCVideoDecoderBridgeTvTest::ExpectEqualsAndSignal, |
| + base::Unretained(this), |
| + expected_result); |
| + } |
| + |
| + base::Callback<void(int32_t)> BindExpectNotEquals( |
| + int32_t unexpected_result) { |
| + return base::Bind(&RTCVideoDecoderBridgeTvTest::ExpectNotEqualsAndSignal, |
| + base::Unretained(this), |
| + unexpected_result); |
| + } |
| + |
| + base::Callback<int32_t(void)> BindInitDecode( |
| + const webrtc::VideoCodec* codec, |
| + int32_t num_cores) { |
| + return base::Bind(&RTCVideoDecoderBridgeTv::InitDecode, |
| + base::Unretained(bridge_), |
| + codec, |
| + num_cores); |
| + } |
| + |
| + base::Callback<int32_t(void)> BindDecode( |
| + const webrtc::EncodedImage& input_image, |
| + bool missing_frames, |
| + const webrtc::RTPFragmentationHeader* fragmentation, |
| + const webrtc::CodecSpecificInfo* info = NULL, |
| + int64_t render_time_ms = -1) { |
| + return base::Bind(&RTCVideoDecoderBridgeTv::Decode, |
| + base::Unretained(bridge_), |
| + input_image, |
| + missing_frames, |
| + fragmentation, |
| + info, |
| + render_time_ms); |
| + } |
| + |
| + void AcquireOwnershipAndCreateDemuxer() { |
| + bridge_->AcquireOwnership(&owner_factory_); |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
What if this fails?
(I'd say CHECK the return valu
wonsik
2013/05/14 12:53:57
Done.
|
| + demuxer_ = bridge_->CreateDemuxer(&owner_factory_, message_loop_proxy_); |
| + } |
| + |
| + void InitDecode() { |
| + codec_.codecType = webrtc::kVideoCodecVP8; |
| + codec_.width = size_.width(); |
| + codec_.height = size_.height(); |
| + base::PostTaskAndReplyWithResult( |
| + decoder_thread_.message_loop_proxy(), |
| + FROM_HERE, |
| + BindInitDecode(&codec_, 1), |
| + BindExpectEquals(WEBRTC_VIDEO_CODEC_OK)); |
| + decoder_thread_event_.Wait(); |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
here and elsewhere, if expectations have already f
wonsik
2013/05/14 12:53:57
Done.
|
| + base::PostTaskAndReplyWithResult( |
| + decoder_thread_.message_loop_proxy(), |
| + FROM_HERE, |
| + base::Bind(&RTCVideoDecoderBridgeTv::RegisterDecodeCompleteCallback, |
| + base::Unretained(bridge_), |
| + &decode_complete_callback_), |
| + BindExpectEquals(WEBRTC_VIDEO_CODEC_OK)); |
| + decoder_thread_event_.Wait(); |
| + } |
| + |
| + void GetVideoStream() { |
| + video_stream_ = demuxer_->GetStream(media::DemuxerStream::VIDEO); |
| + EXPECT_NE(static_cast<media::DemuxerStream*>(NULL), video_stream_); |
| + EXPECT_EQ(media::kCodecVP8, video_stream_->video_decoder_config().codec()); |
| + EXPECT_EQ(size_, video_stream_->video_decoder_config().coded_size()); |
| + EXPECT_EQ(gfx::Rect(size_), |
| + video_stream_->video_decoder_config().visible_rect()); |
| + EXPECT_EQ(size_, video_stream_->video_decoder_config().natural_size()); |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
This would be a fantastic place to test support fo
|
| + } |
| + |
| + void PostDecodeAndWait(int32_t expected_result, |
| + const webrtc::EncodedImage& input_image, |
| + bool missing_frames, |
| + const webrtc::RTPFragmentationHeader* fragmentation, |
| + const webrtc::CodecSpecificInfo* info = NULL, |
| + int64_t render_time_ms = -1) { |
| + base::PostTaskAndReplyWithResult( |
| + decoder_thread_.message_loop_proxy(), |
| + FROM_HERE, |
| + BindDecode( |
| + input_image, missing_frames, fragmentation, info, render_time_ms), |
| + BindExpectEquals(expected_result)); |
| + decoder_thread_event_.Wait(); |
| + } |
| + |
| + RTCVideoDecoderBridgeTv* bridge_; |
| + MockMediaStreamDependencyFactory owner_factory_; |
| + MockMediaStreamDependencyFactory non_owner_factory_; |
| + base::MessageLoopProxy* message_loop_proxy_; |
| + media::Demuxer* demuxer_; |
| + media::DemuxerStream* video_stream_; |
| + webrtc::VideoCodec codec_; |
| + gfx::Size size_; |
| + webrtc::EncodedImage input_image_; |
| + unsigned char data_; |
| + webrtc::MockDecodedImageCallback decode_complete_callback_; |
| + base::WaitableEvent read_event_; |
| + base::Thread decoder_thread_; |
| + base::WaitableEvent decoder_thread_event_; |
| + scoped_refptr<media::DecoderBuffer> last_decoder_buffer_; |
| +}; |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, AcquireAndReleaseOwnership) { |
| + EXPECT_TRUE(bridge_->AcquireOwnership(&owner_factory_)); |
| + EXPECT_FALSE(bridge_->AcquireOwnership(&non_owner_factory_)); |
| + bridge_->ReleaseOwnership(&owner_factory_); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, CreateDemuxerAfterAcquireOwnership) { |
| + EXPECT_TRUE(bridge_->AcquireOwnership(&owner_factory_)); |
| + EXPECT_EQ(static_cast<media::Demuxer*>(NULL), |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
FWIW, here and elsewhere, instead of static_cast<L
wonsik
2013/05/14 12:53:57
Done.
|
| + bridge_->CreateDemuxer(&non_owner_factory_, message_loop_proxy_)); |
| + demuxer_ = bridge_->CreateDemuxer(&owner_factory_, message_loop_proxy_); |
| + EXPECT_NE(static_cast<media::Demuxer*>(NULL), demuxer_); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, CreateDemuxerBeforeAcquireOwnership) { |
| + RTCVideoDecoderBridgeTv* bridge_ = RTCVideoDecoderBridgeTv::Get(); |
| + demuxer_ = bridge_->CreateDemuxer(&owner_factory_, message_loop_proxy_); |
| + EXPECT_NE(static_cast<media::Demuxer*>(NULL), demuxer_); |
| + EXPECT_EQ(static_cast<media::Demuxer*>(NULL), |
| + bridge_->CreateDemuxer(&non_owner_factory_, message_loop_proxy_)); |
| + EXPECT_FALSE(bridge_->AcquireOwnership(&non_owner_factory_)); |
| + EXPECT_TRUE(bridge_->AcquireOwnership(&owner_factory_)); |
|
Ami GONE FROM CHROMIUM
2013/05/08 20:26:44
here and elsewhere, always release.
Since you're u
wonsik
2013/05/14 12:53:57
Done --- we're no longer using a singleton, and Te
|
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, InitDecodeReturnsErrorOnNonVP8Codec) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + codec_.codecType = webrtc::kVideoCodecI420; |
| + base::PostTaskAndReplyWithResult( |
| + decoder_thread_.message_loop_proxy(), |
| + FROM_HERE, |
| + BindInitDecode(&codec_, 1), |
| + BindExpectNotEquals(WEBRTC_VIDEO_CODEC_OK)); |
| + decoder_thread_event_.Wait(); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, InitDecodeReturnsErrorOnFeedbackMode) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + codec_.codecType = webrtc::kVideoCodecVP8; |
| + codec_.codecSpecific.VP8.feedbackModeOn = true; |
| + base::PostTaskAndReplyWithResult( |
| + decoder_thread_.message_loop_proxy(), |
| + FROM_HERE, |
| + BindInitDecode(&codec_, 1), |
| + BindExpectNotEquals(WEBRTC_VIDEO_CODEC_OK)); |
| + decoder_thread_event_.Wait(); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeReturnsErrorBeforeInitDecode) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_UNINITIALIZED, input_image_, false, NULL, NULL, 0); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeReturnsErrorOnDamagedBitstream) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + input_image_._completeFrame = false; |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_ERROR, input_image_, false, NULL, NULL, 0); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeReturnsErrorOnMissingFrames) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_ERROR, input_image_, true, NULL, NULL, 0); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, GetNonVideoStreamFails) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + EXPECT_EQ(static_cast<media::DemuxerStream*>(NULL), |
| + demuxer_->GetStream(media::DemuxerStream::AUDIO)); |
| + EXPECT_EQ(static_cast<media::DemuxerStream*>(NULL), |
| + demuxer_->GetStream(media::DemuxerStream::UNKNOWN)); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, GetVideoStreamSucceeds) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeReturnsErrorOnNonKeyFrameAtFirst) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| + input_image_._frameType = webrtc::kDeltaFrame; |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_ERROR, input_image_, false, NULL, NULL, 0); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeUpdatesVideoSizeOnKeyFrame) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| + gfx::Size new_size(320, 240); |
| + input_image_._encodedWidth = new_size.width(); |
| + input_image_._encodedHeight = new_size.height(); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); |
| + EXPECT_EQ(new_size, video_stream_->video_decoder_config().coded_size()); |
| + EXPECT_EQ(gfx::Rect(new_size), |
| + video_stream_->video_decoder_config().visible_rect()); |
| + EXPECT_EQ(new_size, video_stream_->video_decoder_config().natural_size()); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodeAdjustsTimestampFromZero) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 10000); |
| + video_stream_->Read(base::Bind(&RTCVideoDecoderBridgeTvTest::ReadCallback, |
| + base::Unretained(this))); |
| + read_event_.Wait(); |
| + EXPECT_EQ(base::TimeDelta::FromMilliseconds(0), |
| + last_decoder_buffer_->GetTimestamp()); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 10033); |
| + video_stream_->Read(base::Bind(&RTCVideoDecoderBridgeTvTest::ReadCallback, |
| + base::Unretained(this))); |
| + read_event_.Wait(); |
| + EXPECT_EQ(base::TimeDelta::FromMilliseconds(33), |
| + last_decoder_buffer_->GetTimestamp()); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, DecodePassesDataCorrectly) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| + video_stream_->Read(base::Bind(&RTCVideoDecoderBridgeTvTest::ReadCallback, |
| + base::Unretained(this))); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); |
| + read_event_.Wait(); |
| + EXPECT_EQ(static_cast<int>(sizeof(data_)), |
| + last_decoder_buffer_->GetDataSize()); |
| + EXPECT_EQ(data_, last_decoder_buffer_->GetData()[0]); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, NextReadTriggersDecodeCompleteCallback) { |
| + EXPECT_CALL(decode_complete_callback_, Decoded(_)) |
| + .WillOnce(Return(WEBRTC_VIDEO_CODEC_OK)); |
| + |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + GetVideoStream(); |
| + video_stream_->Read(base::Bind(&RTCVideoDecoderBridgeTvTest::ReadCallback, |
| + base::Unretained(this))); |
| + PostDecodeAndWait( |
| + WEBRTC_VIDEO_CODEC_OK, input_image_, false, NULL, NULL, 0); |
| + read_event_.Wait(); |
| + video_stream_->Read(base::Bind(&RTCVideoDecoderBridgeTvTest::ReadCallback, |
| + base::Unretained(this))); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, ResetReturnsOk) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, bridge_->Reset()); |
| +} |
| + |
| +TEST_F(RTCVideoDecoderBridgeTvTest, ReleaseReturnsOk) { |
| + AcquireOwnershipAndCreateDemuxer(); |
| + InitDecode(); |
| + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, bridge_->Release()); |
| +} |
| + |
| +} // content |