| 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,
|
| + 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) {
|
| + 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_);
|
| + 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();
|
| + 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());
|
| + }
|
| +
|
| + 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),
|
| + 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_));
|
| +}
|
| +
|
| +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
|
|
|