1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "base/basictypes.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/threading/thread.h"
12 #include "base/time/time.h"
13 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
14 #include "chromecast/media/cma/base/decoder_buffer_base.h"
15 #include "chromecast/media/cma/filters/demuxer_stream_adapter.h"
16 #include "media/base/audio_decoder_config.h"
17 #include "media/base/decoder_buffer.h"
18 #include "media/base/demuxer_stream.h"
19 #include "media/base/video_decoder_config.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 namespace chromecast {
27 class DummyDemuxerStream : public ::media::DemuxerStream {
29 // Creates a demuxer stream which provides frames either with a delay
30 // or instantly. The scheduling pattern is the following:
31 // - provides |delayed_frame_count| frames with a delay,
32 // - then provides the following |cycle_count| - |delayed_frame_count|
34 // - then provides |delayed_frame_count| frames with a delay,
37 // - all frames are delayed: |delayed_frame_count| = |cycle_count|
38 // - all frames are provided instantly: |delayed_frame_count| = 0
39 // |config_idx| is a list of frame index before which there is
40 // a change of decoder configuration.
41 DummyDemuxerStream(int cycle_count,
42 int delayed_frame_count,
43 const std::list<int>& config_idx);
44 virtual ~DummyDemuxerStream();
46 // ::media::DemuxerStream implementation.
47 virtual void Read(const ReadCB& read_cb) override;
48 virtual ::media::AudioDecoderConfig audio_decoder_config() override;
49 virtual ::media::VideoDecoderConfig video_decoder_config() override;
50 virtual Type type() override;
51 virtual bool SupportsConfigChanges() override;
52 virtual ::media::VideoRotation video_rotation() override;
54 bool has_pending_read() const {
55 return has_pending_read_;
59 void DoRead(const ReadCB& read_cb);
61 // Demuxer configuration.
62 const int cycle_count_;
63 const int delayed_frame_count_;
64 std::list<int> config_idx_;
66 // Number of frames sent so far.
69 bool has_pending_read_;
71 DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
74 DummyDemuxerStream::DummyDemuxerStream(
76 int delayed_frame_count,
77 const std::list<int>& config_idx)
78 : cycle_count_(cycle_count),
79 delayed_frame_count_(delayed_frame_count),
80 config_idx_(config_idx),
82 has_pending_read_(false) {
83 DCHECK_LE(delayed_frame_count, cycle_count);
86 DummyDemuxerStream::~DummyDemuxerStream() {
89 void DummyDemuxerStream::Read(const ReadCB& read_cb) {
90 has_pending_read_ = true;
91 if (!config_idx_.empty() && config_idx_.front() == frame_count_) {
92 config_idx_.pop_front();
93 has_pending_read_ = false;
94 read_cb.Run(kConfigChanged,
95 scoped_refptr< ::media::DecoderBuffer>());
99 if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
100 base::MessageLoopProxy::current()->PostDelayedTask(
102 base::Bind(&DummyDemuxerStream::DoRead, base::Unretained(this),
104 base::TimeDelta::FromMilliseconds(20));
110 ::media::AudioDecoderConfig DummyDemuxerStream::audio_decoder_config() {
111 LOG(FATAL) << "DummyDemuxerStream is a video DemuxerStream";
112 return ::media::AudioDecoderConfig();
115 ::media::VideoDecoderConfig DummyDemuxerStream::video_decoder_config() {
116 gfx::Size coded_size(640, 480);
117 gfx::Rect visible_rect(640, 480);
118 gfx::Size natural_size(640, 480);
119 return ::media::VideoDecoderConfig(
121 ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
122 ::media::VideoFrame::YV12,
130 ::media::DemuxerStream::Type DummyDemuxerStream::type() {
134 bool DummyDemuxerStream::SupportsConfigChanges() {
138 ::media::VideoRotation DummyDemuxerStream::video_rotation() {
139 return ::media::VIDEO_ROTATION_0;
142 void DummyDemuxerStream::DoRead(const ReadCB& read_cb) {
143 has_pending_read_ = false;
144 scoped_refptr< ::media::DecoderBuffer> buffer(
145 new ::media::DecoderBuffer(16));
146 buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(40));
148 read_cb.Run(kOk, buffer);
153 class DemuxerStreamAdapterTest : public testing::Test {
155 DemuxerStreamAdapterTest();
156 virtual ~DemuxerStreamAdapterTest();
158 void Initialize(::media::DemuxerStream* demuxer_stream);
162 void OnTestTimeout();
163 void OnNewFrame(const scoped_refptr<DecoderBufferBase>& buffer,
164 const ::media::AudioDecoderConfig& audio_config,
165 const ::media::VideoDecoderConfig& video_config);
166 void OnFlushCompleted();
168 // Total number of frames to request.
171 // Number of demuxer read before issuing an early flush.
172 int early_flush_idx_;
173 bool use_post_task_for_flush_;
175 // Number of expected read frames.
176 int total_expected_frames_;
178 // Number of frames actually read so far.
179 int frame_received_count_;
181 // List of expected frame indices with decoder config changes.
182 std::list<int> config_idx_;
184 scoped_ptr<DummyDemuxerStream> demuxer_stream_;
186 scoped_ptr<CodedFrameProvider> coded_frame_provider_;
188 DISALLOW_COPY_AND_ASSIGN(DemuxerStreamAdapterTest);
191 DemuxerStreamAdapterTest::DemuxerStreamAdapterTest()
192 : use_post_task_for_flush_(false) {
195 DemuxerStreamAdapterTest::~DemuxerStreamAdapterTest() {
198 void DemuxerStreamAdapterTest::Initialize(
199 ::media::DemuxerStream* demuxer_stream) {
200 coded_frame_provider_.reset(
201 new DemuxerStreamAdapter(
202 base::MessageLoopProxy::current(),
203 scoped_refptr<BalancedMediaTaskRunnerFactory>(),
207 void DemuxerStreamAdapterTest::Start() {
208 frame_received_count_ = 0;
210 // TODO(damienv): currently, test assertions which fail do not trigger the
211 // exit of the unit test, the message loop is still running. Find a different
212 // way to exit the unit test.
213 base::MessageLoop::current()->PostDelayedTask(
215 base::Bind(&DemuxerStreamAdapterTest::OnTestTimeout,
216 base::Unretained(this)),
217 base::TimeDelta::FromSeconds(5));
219 coded_frame_provider_->Read(
220 base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
221 base::Unretained(this)));
224 void DemuxerStreamAdapterTest::OnTestTimeout() {
225 ADD_FAILURE() << "Test timed out";
226 if (base::MessageLoop::current())
227 base::MessageLoop::current()->QuitWhenIdle();
230 void DemuxerStreamAdapterTest::OnNewFrame(
231 const scoped_refptr<DecoderBufferBase>& buffer,
232 const ::media::AudioDecoderConfig& audio_config,
233 const ::media::VideoDecoderConfig& video_config) {
234 if (video_config.IsValidConfig()) {
235 ASSERT_GT(config_idx_.size(), 0);
236 ASSERT_EQ(frame_received_count_, config_idx_.front());
237 config_idx_.pop_front();
240 ASSERT_TRUE(buffer.get() != NULL);
241 ASSERT_EQ(buffer->timestamp(),
242 frame_received_count_ * base::TimeDelta::FromMilliseconds(40));
243 frame_received_count_++;
245 if (frame_received_count_ >= total_frames_) {
246 coded_frame_provider_->Flush(
247 base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted,
248 base::Unretained(this)));
252 coded_frame_provider_->Read(
253 base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
254 base::Unretained(this)));
256 ASSERT_LE(frame_received_count_, early_flush_idx_);
257 if (frame_received_count_ == early_flush_idx_) {
258 base::Closure flush_cb =
259 base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted,
260 base::Unretained(this));
261 if (use_post_task_for_flush_) {
262 base::MessageLoop::current()->PostTask(
264 base::Bind(&CodedFrameProvider::Flush,
265 base::Unretained(coded_frame_provider_.get()),
268 coded_frame_provider_->Flush(flush_cb);
274 void DemuxerStreamAdapterTest::OnFlushCompleted() {
275 ASSERT_EQ(frame_received_count_, total_expected_frames_);
276 ASSERT_FALSE(demuxer_stream_->has_pending_read());
277 base::MessageLoop::current()->QuitWhenIdle();
280 TEST_F(DemuxerStreamAdapterTest, NoDelay) {
282 early_flush_idx_ = total_frames_; // No early flush.
283 total_expected_frames_ = 10;
284 config_idx_.push_back(0);
285 config_idx_.push_back(5);
288 int delayed_frame_count = 0;
289 demuxer_stream_.reset(
290 new DummyDemuxerStream(
291 cycle_count, delayed_frame_count, config_idx_));
293 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
294 Initialize(demuxer_stream_.get());
295 message_loop->PostTask(
297 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
301 TEST_F(DemuxerStreamAdapterTest, AllDelayed) {
303 early_flush_idx_ = total_frames_; // No early flush.
304 total_expected_frames_ = 10;
305 config_idx_.push_back(0);
306 config_idx_.push_back(5);
309 int delayed_frame_count = 1;
310 demuxer_stream_.reset(
311 new DummyDemuxerStream(
312 cycle_count, delayed_frame_count, config_idx_));
314 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
315 Initialize(demuxer_stream_.get());
316 message_loop->PostTask(
318 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
322 TEST_F(DemuxerStreamAdapterTest, AllDelayedEarlyFlush) {
324 early_flush_idx_ = 5;
325 use_post_task_for_flush_ = true;
326 total_expected_frames_ = 5;
327 config_idx_.push_back(0);
328 config_idx_.push_back(3);
331 int delayed_frame_count = 1;
332 demuxer_stream_.reset(
333 new DummyDemuxerStream(
334 cycle_count, delayed_frame_count, config_idx_));
336 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
337 Initialize(demuxer_stream_.get());
338 message_loop->PostTask(
340 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
345 } // namespace chromecast