1// Copyright (c) 2012 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 "base/basictypes.h"
6#include "base/bind.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/message_loop/message_loop.h"
9#include "media/base/decoder_buffer.h"
10#include "media/base/demuxer_stream.h"
11#include "media/filters/fake_demuxer_stream.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace media {
15
16const int kNumBuffersInOneConfig = 9;
17const int kNumBuffersToReadFirst = 5;
18const int kNumConfigs = 3;
19COMPILE_ASSERT(kNumBuffersToReadFirst < kNumBuffersInOneConfig,
20               do_not_read_too_many_buffers);
21COMPILE_ASSERT(kNumConfigs > 0, need_multiple_configs_to_trigger_config_change);
22
23class FakeDemuxerStreamTest : public testing::Test {
24 public:
25  FakeDemuxerStreamTest()
26      : status_(DemuxerStream::kAborted),
27        read_pending_(false),
28        num_buffers_received_(0) {}
29  virtual ~FakeDemuxerStreamTest() {}
30
31  void BufferReady(DemuxerStream::Status status,
32                   const scoped_refptr<DecoderBuffer>& buffer) {
33    DCHECK(read_pending_);
34    read_pending_ = false;
35    status_ = status;
36    buffer_ = buffer;
37    if (status == DemuxerStream::kOk && !buffer->end_of_stream())
38      num_buffers_received_++;
39  }
40
41  enum ReadResult {
42    OK,
43    ABORTED,
44    CONFIG_CHANGED,
45    EOS,
46    PENDING
47  };
48
49  void EnterNormalReadState() {
50    stream_.reset(
51        new FakeDemuxerStream(kNumConfigs, kNumBuffersInOneConfig, false));
52    for (int i = 0; i < kNumBuffersToReadFirst; ++i)
53      ReadAndExpect(OK);
54    DCHECK_EQ(kNumBuffersToReadFirst, num_buffers_received_);
55  }
56
57  void EnterBeforeEOSState() {
58    stream_.reset(new FakeDemuxerStream(1, kNumBuffersInOneConfig, false));
59    for (int i = 0; i < kNumBuffersInOneConfig; ++i)
60      ReadAndExpect(OK);
61    DCHECK_EQ(kNumBuffersInOneConfig, num_buffers_received_);
62  }
63
64  void ExpectReadResult(ReadResult result) {
65    switch (result) {
66      case OK:
67        EXPECT_FALSE(read_pending_);
68        EXPECT_EQ(DemuxerStream::kOk, status_);
69        ASSERT_TRUE(buffer_.get());
70        EXPECT_FALSE(buffer_->end_of_stream());
71        break;
72
73      case ABORTED:
74        EXPECT_FALSE(read_pending_);
75        EXPECT_EQ(DemuxerStream::kAborted, status_);
76        EXPECT_FALSE(buffer_.get());
77        break;
78
79      case CONFIG_CHANGED:
80        EXPECT_TRUE(stream_->SupportsConfigChanges());
81        EXPECT_FALSE(read_pending_);
82        EXPECT_EQ(DemuxerStream::kConfigChanged, status_);
83        EXPECT_FALSE(buffer_.get());
84        break;
85
86      case EOS:
87        EXPECT_FALSE(read_pending_);
88        EXPECT_EQ(DemuxerStream::kOk, status_);
89        ASSERT_TRUE(buffer_.get());
90        EXPECT_TRUE(buffer_->end_of_stream());
91        break;
92
93      case PENDING:
94        EXPECT_TRUE(read_pending_);
95        break;
96    }
97  }
98
99  void ReadAndExpect(ReadResult result) {
100    EXPECT_FALSE(read_pending_);
101    read_pending_ = true;
102    stream_->Read(base::Bind(&FakeDemuxerStreamTest::BufferReady,
103                             base::Unretained(this)));
104    message_loop_.RunUntilIdle();
105    ExpectReadResult(result);
106  }
107
108  void ReadUntilPending() {
109    while (1) {
110      read_pending_ = true;
111      stream_->Read(base::Bind(&FakeDemuxerStreamTest::BufferReady,
112                               base::Unretained(this)));
113      message_loop_.RunUntilIdle();
114      if (read_pending_)
115        break;
116    }
117  }
118
119  void SatisfyReadAndExpect(ReadResult result) {
120    EXPECT_TRUE(read_pending_);
121    stream_->SatisfyRead();
122    message_loop_.RunUntilIdle();
123    ExpectReadResult(result);
124  }
125
126  void Reset() {
127    bool had_read_pending = read_pending_;
128    stream_->Reset();
129    message_loop_.RunUntilIdle();
130
131    EXPECT_FALSE(read_pending_);
132    if (had_read_pending)
133      ExpectReadResult(ABORTED);
134  }
135
136  void ReadAllBuffers(int num_configs, int num_buffers_in_one_config) {
137    DCHECK_EQ(0, num_buffers_received_);
138    for (int i = 0; i < num_configs; ++i) {
139      for (int j = 0; j < num_buffers_in_one_config; ++j) {
140        ReadAndExpect(OK);
141        EXPECT_EQ(num_buffers_received_, stream_->num_buffers_returned());
142      }
143
144      if (i == num_configs - 1)
145        ReadAndExpect(EOS);
146      else
147        ReadAndExpect(CONFIG_CHANGED);
148    }
149
150    // Will always get EOS after we hit EOS.
151    ReadAndExpect(EOS);
152
153    EXPECT_EQ(num_configs * num_buffers_in_one_config, num_buffers_received_);
154  }
155
156  void TestRead(int num_configs,
157                int num_buffers_in_one_config,
158                bool is_encrypted) {
159    stream_.reset(new FakeDemuxerStream(
160        num_configs, num_buffers_in_one_config, is_encrypted));
161
162    const VideoDecoderConfig& config = stream_->video_decoder_config();
163    EXPECT_TRUE(config.IsValidConfig());
164    EXPECT_EQ(is_encrypted, config.is_encrypted());
165
166    ReadAllBuffers(num_configs, num_buffers_in_one_config);
167  }
168
169  base::MessageLoop message_loop_;
170  scoped_ptr<FakeDemuxerStream> stream_;
171
172  DemuxerStream::Status status_;
173  scoped_refptr<DecoderBuffer> buffer_;
174  bool read_pending_;
175  int num_buffers_received_;
176
177 private:
178  DISALLOW_COPY_AND_ASSIGN(FakeDemuxerStreamTest);
179};
180
181TEST_F(FakeDemuxerStreamTest, Read_OneConfig) {
182  TestRead(1, 5, false);
183}
184
185TEST_F(FakeDemuxerStreamTest, Read_MultipleConfigs) {
186  TestRead(3, 5, false);
187}
188
189TEST_F(FakeDemuxerStreamTest, Read_OneBufferPerConfig) {
190  TestRead(3, 1, false);
191}
192
193TEST_F(FakeDemuxerStreamTest, Read_Encrypted) {
194  TestRead(6, 3, true);
195}
196
197TEST_F(FakeDemuxerStreamTest, HoldRead_Normal) {
198  EnterNormalReadState();
199  stream_->HoldNextRead();
200  ReadAndExpect(PENDING);
201  SatisfyReadAndExpect(OK);
202}
203
204TEST_F(FakeDemuxerStreamTest, HoldRead_BeforeConfigChanged) {
205  EnterNormalReadState();
206  stream_->HoldNextConfigChangeRead();
207  ReadUntilPending();
208  SatisfyReadAndExpect(CONFIG_CHANGED);
209}
210
211TEST_F(FakeDemuxerStreamTest, HoldRead_BeforeEOS) {
212  EnterBeforeEOSState();
213  stream_->HoldNextRead();
214  ReadAndExpect(PENDING);
215  SatisfyReadAndExpect(EOS);
216}
217
218TEST_F(FakeDemuxerStreamTest, Reset_Normal) {
219  EnterNormalReadState();
220  Reset();
221  ReadAndExpect(OK);
222}
223
224TEST_F(FakeDemuxerStreamTest, Reset_AfterHoldRead) {
225  EnterNormalReadState();
226  stream_->HoldNextRead();
227  Reset();
228  ReadAndExpect(OK);
229}
230
231TEST_F(FakeDemuxerStreamTest, Reset_DuringPendingRead) {
232  EnterNormalReadState();
233  stream_->HoldNextRead();
234  ReadAndExpect(PENDING);
235  Reset();
236  ReadAndExpect(OK);
237}
238
239TEST_F(FakeDemuxerStreamTest, Reset_BeforeConfigChanged) {
240  EnterNormalReadState();
241  stream_->HoldNextConfigChangeRead();
242  ReadUntilPending();
243  Reset();
244  ReadAndExpect(CONFIG_CHANGED);
245}
246
247TEST_F(FakeDemuxerStreamTest, Reset_BeforeEOS) {
248  EnterBeforeEOSState();
249  stream_->HoldNextRead();
250  ReadAndExpect(PENDING);
251  Reset();
252  ReadAndExpect(EOS);
253}
254
255TEST_F(FakeDemuxerStreamTest, NoConfigChanges) {
256  stream_.reset(
257      new FakeDemuxerStream(1, kNumBuffersInOneConfig, false));
258  EXPECT_FALSE(stream_->SupportsConfigChanges());
259  for (int i = 0; i < kNumBuffersInOneConfig; ++i)
260    ReadAndExpect(OK);
261  ReadAndExpect(EOS);
262}
263
264TEST_F(FakeDemuxerStreamTest, SeekToStart_Normal) {
265  EnterNormalReadState();
266  stream_->SeekToStart();
267  num_buffers_received_ = 0;
268  ReadAllBuffers(kNumConfigs, kNumBuffersInOneConfig);
269}
270
271TEST_F(FakeDemuxerStreamTest, SeekToStart_BeforeEOS) {
272  EnterBeforeEOSState();
273  stream_->SeekToStart();
274  num_buffers_received_ = 0;
275  ReadAllBuffers(1, kNumBuffersInOneConfig);
276}
277
278TEST_F(FakeDemuxerStreamTest, SeekToStart_AfterEOS) {
279  TestRead(3, 5, false);
280  stream_->SeekToStart();
281  num_buffers_received_ = 0;
282  ReadAllBuffers(3, 5);
283}
284
285}  // namespace media
286