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.
5 #include "media/filters/pipeline_integration_test_base.h"
8 #include "media/base/test_data_util.h"
9 #include "media/filters/chunk_demuxer_client.h"
13 // Key ID of the video track in test file "bear-320x240-encrypted.webm".
14 static const unsigned char kKeyId
[] =
15 "\x11\xa5\x18\x37\xc4\x73\x84\x03\xe5\xe6\x57\xed\x8e\x06\xd9\x7c";
17 static const char* kSourceId
= "SourceId";
19 // Helper class that emulates calls made on the ChunkDemuxer by the
21 class MockMediaSource
: public ChunkDemuxerClient
{
23 MockMediaSource(const std::string
& filename
, int initial_append_size
)
24 : url_(GetTestDataURL(filename
)),
26 initial_append_size_(initial_append_size
) {
27 ReadTestDataFile(filename
, &file_data_
, &file_data_size_
);
29 DCHECK_GT(initial_append_size_
, 0);
30 DCHECK_LE(initial_append_size_
, file_data_size_
);
33 virtual ~MockMediaSource() {}
35 void set_decryptor(AesDecryptor
* decryptor
) {
36 decryptor_
= decryptor
;
38 AesDecryptor
* decryptor() const {
42 const std::string
& url() const { return url_
; }
44 void Seek(int new_position
, int seek_append_size
) {
45 chunk_demuxer_
->FlushData();
47 DCHECK_GE(new_position
, 0);
48 DCHECK_LT(new_position
, file_data_size_
);
49 current_position_
= new_position
;
51 AppendData(seek_append_size
);
54 void AppendData(int size
) {
55 DCHECK(chunk_demuxer_
.get());
56 DCHECK_LT(current_position_
, file_data_size_
);
57 DCHECK_LE(current_position_
+ size
, file_data_size_
);
58 CHECK(chunk_demuxer_
->AppendData(kSourceId
,
59 file_data_
.get() + current_position_
,
61 current_position_
+= size
;
65 chunk_demuxer_
->EndOfStream(PIPELINE_OK
);
69 if (!chunk_demuxer_
.get())
71 chunk_demuxer_
->Shutdown();
74 // ChunkDemuxerClient methods.
75 virtual void DemuxerOpened(ChunkDemuxer
* demuxer
) {
76 chunk_demuxer_
= demuxer
;
78 std::vector
<std::string
> codecs(2);
81 chunk_demuxer_
->AddId(kSourceId
, "video/webm", codecs
);
82 AppendData(initial_append_size_
);
85 virtual void DemuxerClosed() {
86 chunk_demuxer_
= NULL
;
89 virtual void KeyNeeded(scoped_array
<uint8
> init_data
, int init_data_size
) {
90 DCHECK(init_data
.get());
91 DCHECK_EQ(init_data_size
, 16);
93 // In test file bear-320x240-encrypted.webm, the decryption key is equal to
95 decryptor()->AddKey(init_data
.get(), init_data_size
,
96 init_data
.get(), init_data_size
);
101 scoped_array
<uint8
> file_data_
;
103 int current_position_
;
104 int initial_append_size_
;
105 scoped_refptr
<ChunkDemuxer
> chunk_demuxer_
;
106 AesDecryptor
* decryptor_
;
109 class PipelineIntegrationTest
110 : public testing::Test
,
111 public PipelineIntegrationTestBase
{
113 void StartPipelineWithMediaSource(MockMediaSource
& source
) {
115 CreateFilterCollection(&source
),
116 base::Bind(&PipelineIntegrationTest::OnEnded
, base::Unretained(this)),
117 base::Bind(&PipelineIntegrationTest::OnError
, base::Unretained(this)),
118 NetworkEventCB(), QuitOnStatusCB(PIPELINE_OK
));
120 ASSERT_TRUE(decoder_
.get());
121 source
.set_decryptor(decoder_
->decryptor());
126 // Verifies that seeking works properly for ChunkDemuxer when the
127 // seek happens while there is a pending read on the ChunkDemuxer
128 // and no data is available.
129 bool TestSeekDuringRead(const std::string
& filename
,
130 int initial_append_size
,
131 base::TimeDelta start_seek_time
,
132 base::TimeDelta seek_time
,
133 int seek_file_position
,
134 int seek_append_size
) {
135 MockMediaSource
source(filename
, initial_append_size
);
136 StartPipelineWithMediaSource(source
);
138 if (pipeline_status_
!= PIPELINE_OK
)
142 if (!WaitUntilCurrentTimeIsAfter(start_seek_time
))
145 source
.Seek(seek_file_position
, seek_append_size
);
146 if (!Seek(seek_time
))
149 source
.EndOfStream();
158 TEST_F(PipelineIntegrationTest
, BasicPlayback
) {
159 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK
));
163 ASSERT_TRUE(WaitUntilOnEnded());
165 ASSERT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
168 TEST_F(PipelineIntegrationTest
, EncryptedPlayback
) {
169 MockMediaSource
source("bear-320x240-encrypted.webm", 219726);
170 StartPipelineWithMediaSource(source
);
172 source
.EndOfStream();
173 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
177 ASSERT_TRUE(WaitUntilOnEnded());
182 // TODO(acolwell): Fix flakiness http://crbug.com/117921
183 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePaused
) {
184 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK
));
186 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
187 base::TimeDelta
start_seek_time(duration
/ 4);
188 base::TimeDelta
seek_time(duration
* 3 / 4);
191 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
193 ASSERT_TRUE(Seek(seek_time
));
194 EXPECT_EQ(pipeline_
->GetCurrentTime(), seek_time
);
196 ASSERT_TRUE(WaitUntilOnEnded());
198 // Make sure seeking after reaching the end works as expected.
200 ASSERT_TRUE(Seek(seek_time
));
201 EXPECT_EQ(pipeline_
->GetCurrentTime(), seek_time
);
203 ASSERT_TRUE(WaitUntilOnEnded());
206 // TODO(acolwell): Fix flakiness http://crbug.com/117921
207 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePlaying
) {
208 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK
));
210 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
211 base::TimeDelta
start_seek_time(duration
/ 4);
212 base::TimeDelta
seek_time(duration
* 3 / 4);
215 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
216 ASSERT_TRUE(Seek(seek_time
));
217 EXPECT_GE(pipeline_
->GetCurrentTime(), seek_time
);
218 ASSERT_TRUE(WaitUntilOnEnded());
220 // Make sure seeking after reaching the end works as expected.
221 ASSERT_TRUE(Seek(seek_time
));
222 EXPECT_GE(pipeline_
->GetCurrentTime(), seek_time
);
223 ASSERT_TRUE(WaitUntilOnEnded());
226 // Verify audio decoder & renderer can handle aborted demuxer reads.
227 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_AudioOnly
) {
228 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192,
229 base::TimeDelta::FromMilliseconds(464),
230 base::TimeDelta::FromMilliseconds(617),
234 // Verify video decoder & renderer can handle aborted demuxer reads.
235 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_VideoOnly
) {
236 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768,
237 base::TimeDelta::FromMilliseconds(200),
238 base::TimeDelta::FromMilliseconds(1668),