demuxer_stream_adapter_unittest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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.
4
5#include <list>
6
7#include "base/basictypes.h"
8#include "base/bind.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"
21
22namespace chromecast {
23namespace media {
24
25namespace {
26
27class DummyDemuxerStream : public ::media::DemuxerStream {
28 public:
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|
33  //   instantly,
34  // - then provides |delayed_frame_count| frames with a delay,
35  // - ... and so on.
36  // Special cases:
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();
45
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;
53
54  bool has_pending_read() const {
55    return has_pending_read_;
56  }
57
58 private:
59  void DoRead(const ReadCB& read_cb);
60
61  // Demuxer configuration.
62  const int cycle_count_;
63  const int delayed_frame_count_;
64  std::list<int> config_idx_;
65
66  // Number of frames sent so far.
67  int frame_count_;
68
69  bool has_pending_read_;
70
71  DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream);
72};
73
74DummyDemuxerStream::DummyDemuxerStream(
75    int cycle_count,
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),
81    frame_count_(0),
82    has_pending_read_(false) {
83  DCHECK_LE(delayed_frame_count, cycle_count);
84}
85
86DummyDemuxerStream::~DummyDemuxerStream() {
87}
88
89void 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>());
96    return;
97  }
98
99  if ((frame_count_ % cycle_count_) < delayed_frame_count_) {
100    base::MessageLoopProxy::current()->PostDelayedTask(
101        FROM_HERE,
102        base::Bind(&DummyDemuxerStream::DoRead, base::Unretained(this),
103                   read_cb),
104        base::TimeDelta::FromMilliseconds(20));
105    return;
106  }
107  DoRead(read_cb);
108}
109
110::media::AudioDecoderConfig DummyDemuxerStream::audio_decoder_config() {
111  LOG(FATAL) << "DummyDemuxerStream is a video DemuxerStream";
112  return ::media::AudioDecoderConfig();
113}
114
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(
120      ::media::kCodecH264,
121      ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
122      ::media::VideoFrame::YV12,
123      coded_size,
124      visible_rect,
125      natural_size,
126      NULL, 0,
127      false);
128}
129
130::media::DemuxerStream::Type DummyDemuxerStream::type() {
131  return VIDEO;
132}
133
134bool DummyDemuxerStream::SupportsConfigChanges() {
135  return true;
136}
137
138::media::VideoRotation DummyDemuxerStream::video_rotation() {
139  return ::media::VIDEO_ROTATION_0;
140}
141
142void 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));
147  frame_count_++;
148  read_cb.Run(kOk, buffer);
149}
150
151}  // namespace
152
153class DemuxerStreamAdapterTest : public testing::Test {
154 public:
155  DemuxerStreamAdapterTest();
156  virtual ~DemuxerStreamAdapterTest();
157
158  void Initialize(::media::DemuxerStream* demuxer_stream);
159  void Start();
160
161 protected:
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();
167
168  // Total number of frames to request.
169  int total_frames_;
170
171  // Number of demuxer read before issuing an early flush.
172  int early_flush_idx_;
173  bool use_post_task_for_flush_;
174
175  // Number of expected read frames.
176  int total_expected_frames_;
177
178  // Number of frames actually read so far.
179  int frame_received_count_;
180
181  // List of expected frame indices with decoder config changes.
182  std::list<int> config_idx_;
183
184  scoped_ptr<DummyDemuxerStream> demuxer_stream_;
185
186  scoped_ptr<CodedFrameProvider> coded_frame_provider_;
187
188  DISALLOW_COPY_AND_ASSIGN(DemuxerStreamAdapterTest);
189};
190
191DemuxerStreamAdapterTest::DemuxerStreamAdapterTest()
192    : use_post_task_for_flush_(false) {
193}
194
195DemuxerStreamAdapterTest::~DemuxerStreamAdapterTest() {
196}
197
198void DemuxerStreamAdapterTest::Initialize(
199    ::media::DemuxerStream* demuxer_stream) {
200  coded_frame_provider_.reset(
201      new DemuxerStreamAdapter(
202          base::MessageLoopProxy::current(),
203          scoped_refptr<BalancedMediaTaskRunnerFactory>(),
204          demuxer_stream));
205}
206
207void DemuxerStreamAdapterTest::Start() {
208  frame_received_count_ = 0;
209
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(
214      FROM_HERE,
215      base::Bind(&DemuxerStreamAdapterTest::OnTestTimeout,
216                 base::Unretained(this)),
217      base::TimeDelta::FromSeconds(5));
218
219  coded_frame_provider_->Read(
220      base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
221                 base::Unretained(this)));
222}
223
224void DemuxerStreamAdapterTest::OnTestTimeout() {
225  ADD_FAILURE() << "Test timed out";
226  if (base::MessageLoop::current())
227    base::MessageLoop::current()->QuitWhenIdle();
228}
229
230void 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();
238  }
239
240  ASSERT_TRUE(buffer.get() != NULL);
241  ASSERT_EQ(buffer->timestamp(),
242            frame_received_count_ * base::TimeDelta::FromMilliseconds(40));
243  frame_received_count_++;
244
245  if (frame_received_count_ >= total_frames_) {
246    coded_frame_provider_->Flush(
247        base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted,
248                   base::Unretained(this)));
249    return;
250  }
251
252  coded_frame_provider_->Read(
253      base::Bind(&DemuxerStreamAdapterTest::OnNewFrame,
254                 base::Unretained(this)));
255
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(
263          FROM_HERE,
264          base::Bind(&CodedFrameProvider::Flush,
265                     base::Unretained(coded_frame_provider_.get()),
266                     flush_cb));
267    } else {
268      coded_frame_provider_->Flush(flush_cb);
269    }
270    return;
271  }
272}
273
274void DemuxerStreamAdapterTest::OnFlushCompleted() {
275  ASSERT_EQ(frame_received_count_, total_expected_frames_);
276  ASSERT_FALSE(demuxer_stream_->has_pending_read());
277  base::MessageLoop::current()->QuitWhenIdle();
278}
279
280TEST_F(DemuxerStreamAdapterTest, NoDelay) {
281  total_frames_ = 10;
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);
286
287  int cycle_count = 1;
288  int delayed_frame_count = 0;
289  demuxer_stream_.reset(
290      new DummyDemuxerStream(
291          cycle_count, delayed_frame_count, config_idx_));
292
293  scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
294  Initialize(demuxer_stream_.get());
295  message_loop->PostTask(
296      FROM_HERE,
297      base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
298  message_loop->Run();
299}
300
301TEST_F(DemuxerStreamAdapterTest, AllDelayed) {
302  total_frames_ = 10;
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);
307
308  int cycle_count = 1;
309  int delayed_frame_count = 1;
310  demuxer_stream_.reset(
311      new DummyDemuxerStream(
312          cycle_count, delayed_frame_count, config_idx_));
313
314  scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
315  Initialize(demuxer_stream_.get());
316  message_loop->PostTask(
317      FROM_HERE,
318      base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
319  message_loop->Run();
320}
321
322TEST_F(DemuxerStreamAdapterTest, AllDelayedEarlyFlush) {
323  total_frames_ = 10;
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);
329
330  int cycle_count = 1;
331  int delayed_frame_count = 1;
332  demuxer_stream_.reset(
333      new DummyDemuxerStream(
334          cycle_count, delayed_frame_count, config_idx_));
335
336  scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop());
337  Initialize(demuxer_stream_.get());
338  message_loop->PostTask(
339      FROM_HERE,
340      base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this)));
341  message_loop->Run();
342}
343
344}  // namespace media
345}  // namespace chromecast
346