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 "media/filters/pipeline_integration_test_base.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/string_util.h"
11 #include "build/build_config.h"
12 #include "media/base/cdm_promise.h"
13 #include "media/base/decoder_buffer.h"
14 #include "media/base/media_keys.h"
15 #include "media/base/media_switches.h"
16 #include "media/base/test_data_util.h"
17 #include "media/cdm/aes_decryptor.h"
18 #include "media/cdm/json_web_key.h"
19 #include "media/filters/chunk_demuxer.h"
20
21 using testing::_;
22 using testing::AnyNumber;
23 using testing::AtMost;
24 using testing::SaveArg;
25
26 namespace media {
27
28 const char kSourceId[] = "SourceId";
29 const uint8 kInitData[] = { 0x69, 0x6e, 0x69, 0x74 };
30
31 const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\"";
32 const char kWebMVP9[] = "video/webm; codecs=\"vp9\"";
33 const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\"";
34 const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\"";
35 const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\"";
36 const char kMP4VideoType[] = "video/mp4";
37 const char kMP4AudioType[] = "audio/mp4";
38 #if defined(USE_PROPRIETARY_CODECS)
39 const char kADTS[] = "audio/aac";
40 const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
41 const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\"";
42 const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\"";
43 const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\"";
44 const char kMP3[] = "audio/mpeg";
45 #endif // defined(USE_PROPRIETARY_CODECS)
46
47 // Key used to encrypt test files.
48 const uint8 kSecretKey[] = {
49 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
50 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
51 };
52
53 // The key ID for all encrypted files.
54 const uint8 kKeyId[] = {
55 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
56 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
57 };
58
59 const int kAppendWholeFile = -1;
60
61 // Constants for the Media Source config change tests.
62 const int kAppendTimeSec = 1;
63 const int kAppendTimeMs = kAppendTimeSec * 1000;
64 const int k320WebMFileDurationMs = 2736;
65 const int k640WebMFileDurationMs = 2749;
66 const int kOpusEndTrimmingWebMFileDurationMs = 2741;
67 const int kVP9WebMFileDurationMs = 2736;
68 const int kVP8AWebMFileDurationMs = 2733;
69
70 #if defined(USE_PROPRIETARY_CODECS)
71 const int k640IsoFileDurationMs = 2737;
72 const int k640IsoCencFileDurationMs = 2736;
73 const int k1280IsoFileDurationMs = 2736;
74 const int k1280IsoAVC3FileDurationMs = 2736;
75 #endif // defined(USE_PROPRIETARY_CODECS)
76
77 // Return a timeline offset for bear-320x240-live.webm.
kLiveTimelineOffset()78 static base::Time kLiveTimelineOffset() {
79 // The file contians the following UTC timeline offset:
80 // 2012-11-10 12:34:56.789123456
81 // Since base::Time only has a resolution of microseconds,
82 // construct a base::Time for 2012-11-10 12:34:56.789123.
83 base::Time::Exploded exploded_time;
84 exploded_time.year = 2012;
85 exploded_time.month = 11;
86 exploded_time.day_of_month = 10;
87 exploded_time.hour = 12;
88 exploded_time.minute = 34;
89 exploded_time.second = 56;
90 exploded_time.millisecond = 789;
91 base::Time timeline_offset = base::Time::FromUTCExploded(exploded_time);
92
93 timeline_offset += base::TimeDelta::FromMicroseconds(123);
94
95 return timeline_offset;
96 }
97
98 // FFmpeg only supports time a resolution of seconds so this
99 // helper function truncates a base::Time to seconds resolution.
TruncateToFFmpegTimeResolution(base::Time t)100 static base::Time TruncateToFFmpegTimeResolution(base::Time t) {
101 base::Time::Exploded exploded_time;
102 t.UTCExplode(&exploded_time);
103 exploded_time.millisecond = 0;
104
105 return base::Time::FromUTCExploded(exploded_time);
106 }
107
108 // Note: Tests using this class only exercise the DecryptingDemuxerStream path.
109 // They do not exercise the Decrypting{Audio|Video}Decoder path.
110 class FakeEncryptedMedia {
111 public:
112 // Defines the behavior of the "app" that responds to EME events.
113 class AppBase {
114 public:
~AppBase()115 virtual ~AppBase() {}
116
117 virtual void OnSessionMessage(const std::string& web_session_id,
118 const std::vector<uint8>& message,
119 const GURL& destination_url) = 0;
120
121 virtual void OnSessionReady(const std::string& web_session_id) = 0;
122
123 virtual void OnSessionClosed(const std::string& web_session_id) = 0;
124
125 // Errors are not expected unless overridden.
OnSessionError(const std::string & web_session_id,const std::string & error_name,uint32 system_code,const std::string & error_message)126 virtual void OnSessionError(const std::string& web_session_id,
127 const std::string& error_name,
128 uint32 system_code,
129 const std::string& error_message) {
130 FAIL() << "Unexpected Key Error";
131 }
132
133 virtual void NeedKey(const std::string& type,
134 const std::vector<uint8>& init_data,
135 AesDecryptor* decryptor) = 0;
136 };
137
FakeEncryptedMedia(AppBase * app)138 FakeEncryptedMedia(AppBase* app)
139 : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage,
140 base::Unretained(this)),
141 base::Bind(&FakeEncryptedMedia::OnSessionClosed,
142 base::Unretained(this))),
143 app_(app) {}
144
decryptor()145 AesDecryptor* decryptor() {
146 return &decryptor_;
147 }
148
149 // Callbacks for firing session events. Delegate to |app_|.
OnSessionMessage(const std::string & web_session_id,const std::vector<uint8> & message,const GURL & destination_url)150 void OnSessionMessage(const std::string& web_session_id,
151 const std::vector<uint8>& message,
152 const GURL& destination_url) {
153 app_->OnSessionMessage(web_session_id, message, destination_url);
154 }
155
OnSessionReady(const std::string & web_session_id)156 void OnSessionReady(const std::string& web_session_id) {
157 app_->OnSessionReady(web_session_id);
158 }
159
OnSessionClosed(const std::string & web_session_id)160 void OnSessionClosed(const std::string& web_session_id) {
161 app_->OnSessionClosed(web_session_id);
162 }
163
OnSessionError(const std::string & web_session_id,const std::string & error_name,uint32 system_code,const std::string & error_message)164 void OnSessionError(const std::string& web_session_id,
165 const std::string& error_name,
166 uint32 system_code,
167 const std::string& error_message) {
168 app_->OnSessionError(
169 web_session_id, error_name, system_code, error_message);
170 }
171
NeedKey(const std::string & type,const std::vector<uint8> & init_data)172 void NeedKey(const std::string& type,
173 const std::vector<uint8>& init_data) {
174 app_->NeedKey(type, init_data, &decryptor_);
175 }
176
177 private:
178 AesDecryptor decryptor_;
179 scoped_ptr<AppBase> app_;
180 };
181
182 enum PromiseResult { RESOLVED, REJECTED };
183
184 // Provides |kSecretKey| in response to needkey.
185 class KeyProvidingApp : public FakeEncryptedMedia::AppBase {
186 public:
KeyProvidingApp()187 KeyProvidingApp() {}
188
OnResolveWithSession(PromiseResult expected,const std::string & web_session_id)189 void OnResolveWithSession(PromiseResult expected,
190 const std::string& web_session_id) {
191 EXPECT_EQ(expected, RESOLVED);
192 EXPECT_GT(web_session_id.length(), 0ul);
193 current_session_id_ = web_session_id;
194 }
195
OnResolve(PromiseResult expected)196 void OnResolve(PromiseResult expected) {
197 EXPECT_EQ(expected, RESOLVED);
198 }
199
OnReject(PromiseResult expected,media::MediaKeys::Exception exception_code,uint32 system_code,const std::string & error_message)200 void OnReject(PromiseResult expected,
201 media::MediaKeys::Exception exception_code,
202 uint32 system_code,
203 const std::string& error_message) {
204 EXPECT_EQ(expected, REJECTED);
205 }
206
CreatePromise(PromiseResult expected)207 scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {
208 scoped_ptr<media::SimpleCdmPromise> promise(new media::SimpleCdmPromise(
209 base::Bind(
210 &KeyProvidingApp::OnResolve, base::Unretained(this), expected),
211 base::Bind(
212 &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
213 return promise.Pass();
214 }
215
CreateSessionPromise(PromiseResult expected)216 scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
217 PromiseResult expected) {
218 scoped_ptr<media::NewSessionCdmPromise> promise(
219 new media::NewSessionCdmPromise(
220 base::Bind(&KeyProvidingApp::OnResolveWithSession,
221 base::Unretained(this),
222 expected),
223 base::Bind(
224 &KeyProvidingApp::OnReject, base::Unretained(this), expected)));
225 return promise.Pass();
226 }
227
OnSessionMessage(const std::string & web_session_id,const std::vector<uint8> & message,const GURL & destination_url)228 virtual void OnSessionMessage(const std::string& web_session_id,
229 const std::vector<uint8>& message,
230 const GURL& destination_url) OVERRIDE {
231 EXPECT_FALSE(web_session_id.empty());
232 EXPECT_FALSE(message.empty());
233 EXPECT_EQ(current_session_id_, web_session_id);
234 }
235
OnSessionReady(const std::string & web_session_id)236 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
237 EXPECT_EQ(current_session_id_, web_session_id);
238 }
239
OnSessionClosed(const std::string & web_session_id)240 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
241 EXPECT_EQ(current_session_id_, web_session_id);
242 }
243
NeedKey(const std::string & type,const std::vector<uint8> & init_data,AesDecryptor * decryptor)244 virtual void NeedKey(const std::string& type,
245 const std::vector<uint8>& init_data,
246 AesDecryptor* decryptor) OVERRIDE {
247 if (current_session_id_.empty()) {
248 decryptor->CreateSession(type,
249 kInitData,
250 arraysize(kInitData),
251 MediaKeys::TEMPORARY_SESSION,
252 CreateSessionPromise(RESOLVED));
253 EXPECT_FALSE(current_session_id_.empty());
254 }
255
256 // Clear Key really needs the key ID in |init_data|. For WebM, they are the
257 // same, but this is not the case for ISO CENC. Therefore, provide the
258 // correct key ID.
259 const uint8* key_id = init_data.empty() ? NULL : &init_data[0];
260 size_t key_id_length = init_data.size();
261 if (type == kMP4AudioType || type == kMP4VideoType) {
262 key_id = kKeyId;
263 key_id_length = arraysize(kKeyId);
264 }
265
266 // Convert key into a JSON structure and then add it.
267 std::string jwk = GenerateJWKSet(
268 kSecretKey, arraysize(kSecretKey), key_id, key_id_length);
269 decryptor->UpdateSession(current_session_id_,
270 reinterpret_cast<const uint8*>(jwk.data()),
271 jwk.size(),
272 CreatePromise(RESOLVED));
273 }
274
275 std::string current_session_id_;
276 };
277
278 class RotatingKeyProvidingApp : public KeyProvidingApp {
279 public:
RotatingKeyProvidingApp()280 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {}
~RotatingKeyProvidingApp()281 virtual ~RotatingKeyProvidingApp() {
282 // Expect that NeedKey is fired multiple times with different |init_data|.
283 EXPECT_GT(num_distint_need_key_calls_, 1u);
284 }
285
NeedKey(const std::string & type,const std::vector<uint8> & init_data,AesDecryptor * decryptor)286 virtual void NeedKey(const std::string& type,
287 const std::vector<uint8>& init_data,
288 AesDecryptor* decryptor) OVERRIDE {
289 // Skip the request if the |init_data| has been seen.
290 if (init_data == prev_init_data_)
291 return;
292 prev_init_data_ = init_data;
293 ++num_distint_need_key_calls_;
294
295 decryptor->CreateSession(type,
296 vector_as_array(&init_data),
297 init_data.size(),
298 MediaKeys::TEMPORARY_SESSION,
299 CreateSessionPromise(RESOLVED));
300
301 std::vector<uint8> key_id;
302 std::vector<uint8> key;
303 EXPECT_TRUE(GetKeyAndKeyId(init_data, &key, &key_id));
304
305 // Convert key into a JSON structure and then add it.
306 std::string jwk = GenerateJWKSet(vector_as_array(&key),
307 key.size(),
308 vector_as_array(&key_id),
309 key_id.size());
310 decryptor->UpdateSession(current_session_id_,
311 reinterpret_cast<const uint8*>(jwk.data()),
312 jwk.size(),
313 CreatePromise(RESOLVED));
314 }
315
316 private:
GetKeyAndKeyId(std::vector<uint8> init_data,std::vector<uint8> * key,std::vector<uint8> * key_id)317 bool GetKeyAndKeyId(std::vector<uint8> init_data,
318 std::vector<uint8>* key,
319 std::vector<uint8>* key_id) {
320 // For WebM, init_data is key_id; for ISO CENC, init_data should contain
321 // the key_id. We assume key_id is in the end of init_data here (that is
322 // only a reasonable assumption for WebM and clear key ISO CENC).
323 DCHECK_GE(init_data.size(), arraysize(kKeyId));
324 std::vector<uint8> key_id_from_init_data(
325 init_data.end() - arraysize(kKeyId), init_data.end());
326
327 key->assign(kSecretKey, kSecretKey + arraysize(kSecretKey));
328 key_id->assign(kKeyId, kKeyId + arraysize(kKeyId));
329
330 // The Key and KeyId for this testing key provider are created by left
331 // rotating kSecretKey and kKeyId. Note that this implementation is only
332 // intended for testing purpose. The actual key rotation algorithm can be
333 // much more complicated.
334 // Find out the rotating position from |key_id_from_init_data| and apply on
335 // |key|.
336 for (size_t pos = 0; pos < arraysize(kKeyId); ++pos) {
337 std::rotate(key_id->begin(), key_id->begin() + pos, key_id->end());
338 if (*key_id == key_id_from_init_data) {
339 std::rotate(key->begin(), key->begin() + pos, key->end());
340 return true;
341 }
342 }
343 return false;
344 }
345
346 std::vector<uint8> prev_init_data_;
347 uint32 num_distint_need_key_calls_;
348 };
349
350 // Ignores needkey and does not perform a license request
351 class NoResponseApp : public FakeEncryptedMedia::AppBase {
352 public:
OnSessionMessage(const std::string & web_session_id,const std::vector<uint8> & message,const GURL & default_url)353 virtual void OnSessionMessage(const std::string& web_session_id,
354 const std::vector<uint8>& message,
355 const GURL& default_url) OVERRIDE {
356 EXPECT_FALSE(web_session_id.empty());
357 EXPECT_FALSE(message.empty());
358 FAIL() << "Unexpected Message";
359 }
360
OnSessionReady(const std::string & web_session_id)361 virtual void OnSessionReady(const std::string& web_session_id) OVERRIDE {
362 EXPECT_FALSE(web_session_id.empty());
363 FAIL() << "Unexpected Ready";
364 }
365
OnSessionClosed(const std::string & web_session_id)366 virtual void OnSessionClosed(const std::string& web_session_id) OVERRIDE {
367 EXPECT_FALSE(web_session_id.empty());
368 FAIL() << "Unexpected Closed";
369 }
370
NeedKey(const std::string & type,const std::vector<uint8> & init_data,AesDecryptor * decryptor)371 virtual void NeedKey(const std::string& type,
372 const std::vector<uint8>& init_data,
373 AesDecryptor* decryptor) OVERRIDE {
374 }
375 };
376
377 // Helper class that emulates calls made on the ChunkDemuxer by the
378 // Media Source API.
379 class MockMediaSource {
380 public:
MockMediaSource(const std::string & filename,const std::string & mimetype,int initial_append_size)381 MockMediaSource(const std::string& filename,
382 const std::string& mimetype,
383 int initial_append_size)
384 : file_path_(GetTestDataFilePath(filename)),
385 current_position_(0),
386 initial_append_size_(initial_append_size),
387 mimetype_(mimetype),
388 chunk_demuxer_(new ChunkDemuxer(
389 base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)),
390 base::Bind(&MockMediaSource::DemuxerNeedKey,
391 base::Unretained(this)),
392 LogCB(),
393 true)),
394 owned_chunk_demuxer_(chunk_demuxer_) {
395
396 file_data_ = ReadTestDataFile(filename);
397
398 if (initial_append_size_ == kAppendWholeFile)
399 initial_append_size_ = file_data_->data_size();
400
401 DCHECK_GT(initial_append_size_, 0);
402 DCHECK_LE(initial_append_size_, file_data_->data_size());
403 }
404
~MockMediaSource()405 virtual ~MockMediaSource() {}
406
GetDemuxer()407 scoped_ptr<Demuxer> GetDemuxer() { return owned_chunk_demuxer_.Pass(); }
408
set_need_key_cb(const Demuxer::NeedKeyCB & need_key_cb)409 void set_need_key_cb(const Demuxer::NeedKeyCB& need_key_cb) {
410 need_key_cb_ = need_key_cb;
411 }
412
Seek(base::TimeDelta seek_time,int new_position,int seek_append_size)413 void Seek(base::TimeDelta seek_time, int new_position, int seek_append_size) {
414 chunk_demuxer_->StartWaitingForSeek(seek_time);
415
416 chunk_demuxer_->Abort(
417 kSourceId,
418 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
419
420 DCHECK_GE(new_position, 0);
421 DCHECK_LT(new_position, file_data_->data_size());
422 current_position_ = new_position;
423
424 AppendData(seek_append_size);
425 }
426
AppendData(int size)427 void AppendData(int size) {
428 DCHECK(chunk_demuxer_);
429 DCHECK_LT(current_position_, file_data_->data_size());
430 DCHECK_LE(current_position_ + size, file_data_->data_size());
431
432 chunk_demuxer_->AppendData(
433 kSourceId, file_data_->data() + current_position_, size,
434 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_);
435 current_position_ += size;
436 }
437
AppendAtTime(base::TimeDelta timestamp_offset,const uint8 * pData,int size)438 void AppendAtTime(base::TimeDelta timestamp_offset,
439 const uint8* pData,
440 int size) {
441 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
442 chunk_demuxer_->AppendData(kSourceId, pData, size,
443 base::TimeDelta(), kInfiniteDuration(),
444 ×tamp_offset);
445 last_timestamp_offset_ = timestamp_offset;
446 }
447
AppendAtTimeWithWindow(base::TimeDelta timestamp_offset,base::TimeDelta append_window_start,base::TimeDelta append_window_end,const uint8 * pData,int size)448 void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset,
449 base::TimeDelta append_window_start,
450 base::TimeDelta append_window_end,
451 const uint8* pData,
452 int size) {
453 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
454 chunk_demuxer_->AppendData(kSourceId,
455 pData,
456 size,
457 append_window_start,
458 append_window_end,
459 ×tamp_offset);
460 last_timestamp_offset_ = timestamp_offset;
461 }
462
EndOfStream()463 void EndOfStream() {
464 chunk_demuxer_->MarkEndOfStream(PIPELINE_OK);
465 }
466
Abort()467 void Abort() {
468 if (!chunk_demuxer_)
469 return;
470 chunk_demuxer_->Shutdown();
471 chunk_demuxer_ = NULL;
472 }
473
DemuxerOpened()474 void DemuxerOpened() {
475 base::MessageLoop::current()->PostTask(
476 FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask,
477 base::Unretained(this)));
478 }
479
DemuxerOpenedTask()480 void DemuxerOpenedTask() {
481 // This code assumes that |mimetype_| is one of the following forms.
482 // 1. audio/mpeg
483 // 2. video/webm;codec="vorbis,vp8".
484 size_t semicolon = mimetype_.find(";");
485 std::string type = mimetype_;
486 std::vector<std::string> codecs;
487 if (semicolon != std::string::npos) {
488 type = mimetype_.substr(0, semicolon);
489 size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon);
490
491 CHECK_NE(codecs_param_start, std::string::npos);
492
493 codecs_param_start += 8; // Skip over the codecs=".
494
495 size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);
496
497 CHECK_NE(codecs_param_end, std::string::npos);
498
499 std::string codecs_param =
500 mimetype_.substr(codecs_param_start,
501 codecs_param_end - codecs_param_start);
502 Tokenize(codecs_param, ",", &codecs);
503 }
504
505 CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
506
507 AppendData(initial_append_size_);
508 }
509
DemuxerNeedKey(const std::string & type,const std::vector<uint8> & init_data)510 void DemuxerNeedKey(const std::string& type,
511 const std::vector<uint8>& init_data) {
512 DCHECK(!init_data.empty());
513 CHECK(!need_key_cb_.is_null());
514 need_key_cb_.Run(type, init_data);
515 }
516
last_timestamp_offset() const517 base::TimeDelta last_timestamp_offset() const {
518 return last_timestamp_offset_;
519 }
520
521 private:
522 base::FilePath file_path_;
523 scoped_refptr<DecoderBuffer> file_data_;
524 int current_position_;
525 int initial_append_size_;
526 std::string mimetype_;
527 ChunkDemuxer* chunk_demuxer_;
528 scoped_ptr<Demuxer> owned_chunk_demuxer_;
529 Demuxer::NeedKeyCB need_key_cb_;
530 base::TimeDelta last_timestamp_offset_;
531 };
532
533 class PipelineIntegrationTest
534 : public testing::Test,
535 public PipelineIntegrationTestBase {
536 public:
StartPipelineWithMediaSource(MockMediaSource * source)537 void StartPipelineWithMediaSource(MockMediaSource* source) {
538 EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1))
539 .WillRepeatedly(SaveArg<0>(&metadata_));
540 EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1));
541 pipeline_->Start(
542 CreateFilterCollection(source->GetDemuxer(), NULL),
543 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
544 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
545 QuitOnStatusCB(PIPELINE_OK),
546 base::Bind(&PipelineIntegrationTest::OnMetadata,
547 base::Unretained(this)),
548 base::Bind(&PipelineIntegrationTest::OnPrerollCompleted,
549 base::Unretained(this)),
550 base::Closure());
551
552 message_loop_.Run();
553 }
554
StartHashedPipelineWithMediaSource(MockMediaSource * source)555 void StartHashedPipelineWithMediaSource(MockMediaSource* source) {
556 hashing_enabled_ = true;
557 StartPipelineWithMediaSource(source);
558 }
559
StartPipelineWithEncryptedMedia(MockMediaSource * source,FakeEncryptedMedia * encrypted_media)560 void StartPipelineWithEncryptedMedia(
561 MockMediaSource* source,
562 FakeEncryptedMedia* encrypted_media) {
563 EXPECT_CALL(*this, OnMetadata(_)).Times(AtMost(1))
564 .WillRepeatedly(SaveArg<0>(&metadata_));
565 EXPECT_CALL(*this, OnPrerollCompleted()).Times(AtMost(1));
566 pipeline_->Start(
567 CreateFilterCollection(source->GetDemuxer(),
568 encrypted_media->decryptor()),
569 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)),
570 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)),
571 QuitOnStatusCB(PIPELINE_OK),
572 base::Bind(&PipelineIntegrationTest::OnMetadata,
573 base::Unretained(this)),
574 base::Bind(&PipelineIntegrationTest::OnPrerollCompleted,
575 base::Unretained(this)),
576 base::Closure());
577
578 source->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
579 base::Unretained(encrypted_media)));
580
581 message_loop_.Run();
582 }
583
584 // Verifies that seeking works properly for ChunkDemuxer when the
585 // seek happens while there is a pending read on the ChunkDemuxer
586 // and no data is available.
TestSeekDuringRead(const std::string & filename,const std::string & mimetype,int initial_append_size,base::TimeDelta start_seek_time,base::TimeDelta seek_time,int seek_file_position,int seek_append_size)587 bool TestSeekDuringRead(const std::string& filename,
588 const std::string& mimetype,
589 int initial_append_size,
590 base::TimeDelta start_seek_time,
591 base::TimeDelta seek_time,
592 int seek_file_position,
593 int seek_append_size) {
594 MockMediaSource source(filename, mimetype, initial_append_size);
595 StartPipelineWithMediaSource(&source);
596
597 if (pipeline_status_ != PIPELINE_OK)
598 return false;
599
600 Play();
601 if (!WaitUntilCurrentTimeIsAfter(start_seek_time))
602 return false;
603
604 source.Seek(seek_time, seek_file_position, seek_append_size);
605 if (!Seek(seek_time))
606 return false;
607
608 source.EndOfStream();
609
610 source.Abort();
611 Stop();
612 return true;
613 }
614 };
615
TEST_F(PipelineIntegrationTest,BasicPlayback)616 TEST_F(PipelineIntegrationTest, BasicPlayback) {
617 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
618
619 Play();
620
621 ASSERT_TRUE(WaitUntilOnEnded());
622 }
623
TEST_F(PipelineIntegrationTest,BasicPlaybackOpusOgg)624 TEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) {
625 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK));
626
627 Play();
628
629 ASSERT_TRUE(WaitUntilOnEnded());
630 }
631
TEST_F(PipelineIntegrationTest,BasicPlaybackHashed)632 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
633 ASSERT_TRUE(Start(
634 GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK, kHashed));
635
636 Play();
637
638 ASSERT_TRUE(WaitUntilOnEnded());
639
640 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
641 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
642 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
643 }
644
TEST_F(PipelineIntegrationTest,BasicPlaybackLive)645 TEST_F(PipelineIntegrationTest, BasicPlaybackLive) {
646 ASSERT_TRUE(Start(
647 GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK, kHashed));
648
649 Play();
650
651 ASSERT_TRUE(WaitUntilOnEnded());
652
653 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
654 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
655
656 // TODO: Fix FFmpeg code to return higher resolution time values so
657 // we don't have to truncate our expectations here.
658 EXPECT_EQ(TruncateToFFmpegTimeResolution(kLiveTimelineOffset()),
659 demuxer_->GetTimelineOffset());
660 }
661
TEST_F(PipelineIntegrationTest,F32PlaybackHashed)662 TEST_F(PipelineIntegrationTest, F32PlaybackHashed) {
663 ASSERT_TRUE(
664 Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK, kHashed));
665 Play();
666 ASSERT_TRUE(WaitUntilOnEnded());
667 EXPECT_EQ(std::string(kNullVideoHash), GetVideoHash());
668 EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash());
669 }
670
TEST_F(PipelineIntegrationTest,BasicPlaybackEncrypted)671 TEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {
672 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
673 set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey,
674 base::Unretained(&encrypted_media)));
675
676 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"),
677 encrypted_media.decryptor()));
678
679 Play();
680
681 ASSERT_TRUE(WaitUntilOnEnded());
682 Stop();
683 }
684
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource)685 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
686 MockMediaSource source("bear-320x240.webm", kWebM, 219229);
687 StartPipelineWithMediaSource(&source);
688 source.EndOfStream();
689
690 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
691 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
692 EXPECT_EQ(k320WebMFileDurationMs,
693 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
694
695 Play();
696
697 ASSERT_TRUE(WaitUntilOnEnded());
698
699 EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());
700 source.Abort();
701 Stop();
702 }
703
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource_Live)704 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Live) {
705 MockMediaSource source("bear-320x240-live.webm", kWebM, 219221);
706 StartPipelineWithMediaSource(&source);
707 source.EndOfStream();
708
709 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
710 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
711 EXPECT_EQ(k320WebMFileDurationMs,
712 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
713
714 Play();
715
716 ASSERT_TRUE(WaitUntilOnEnded());
717
718 EXPECT_EQ(kLiveTimelineOffset(),
719 demuxer_->GetTimelineOffset());
720 source.Abort();
721 Stop();
722 }
723
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource_VP9_WebM)724 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP9_WebM) {
725 MockMediaSource source("bear-vp9.webm", kWebMVP9, 67504);
726 StartPipelineWithMediaSource(&source);
727 source.EndOfStream();
728
729 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
730 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
731 EXPECT_EQ(kVP9WebMFileDurationMs,
732 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
733
734 Play();
735
736 ASSERT_TRUE(WaitUntilOnEnded());
737 source.Abort();
738 Stop();
739 }
740
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource_VP8A_WebM)741 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VP8A_WebM) {
742 MockMediaSource source("bear-vp8a.webm", kVideoOnlyWebM, kAppendWholeFile);
743 StartPipelineWithMediaSource(&source);
744 source.EndOfStream();
745
746 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
747 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
748 EXPECT_EQ(kVP8AWebMFileDurationMs,
749 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
750
751 Play();
752
753 ASSERT_TRUE(WaitUntilOnEnded());
754 source.Abort();
755 Stop();
756 }
757
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource_Opus_WebM)758 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus_WebM) {
759 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
760 kAppendWholeFile);
761 StartPipelineWithMediaSource(&source);
762 source.EndOfStream();
763
764 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
765 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
766 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
767 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
768 Play();
769
770 ASSERT_TRUE(WaitUntilOnEnded());
771 source.Abort();
772 Stop();
773 }
774
775 // Flaky. http://crbug.com/304776
TEST_F(PipelineIntegrationTest,DISABLED_MediaSource_Opus_Seeking_WebM)776 TEST_F(PipelineIntegrationTest, DISABLED_MediaSource_Opus_Seeking_WebM) {
777 MockMediaSource source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM,
778 kAppendWholeFile);
779 StartHashedPipelineWithMediaSource(&source);
780
781 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
782 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
783 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs,
784 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
785
786 base::TimeDelta start_seek_time = base::TimeDelta::FromMilliseconds(1000);
787 base::TimeDelta seek_time = base::TimeDelta::FromMilliseconds(2000);
788
789 Play();
790 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
791 source.Seek(seek_time, 0x1D5, 34017);
792 source.EndOfStream();
793 ASSERT_TRUE(Seek(seek_time));
794
795 ASSERT_TRUE(WaitUntilOnEnded());
796
797 EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash());
798
799 source.Abort();
800 Stop();
801 }
802
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_WebM)803 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_WebM) {
804 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
805 kAppendWholeFile);
806 StartPipelineWithMediaSource(&source);
807
808 scoped_refptr<DecoderBuffer> second_file =
809 ReadTestDataFile("bear-640x360.webm");
810
811 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
812 second_file->data(), second_file->data_size());
813
814 source.EndOfStream();
815
816 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
817 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
818 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
819 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
820
821 Play();
822
823 EXPECT_TRUE(WaitUntilOnEnded());
824 source.Abort();
825 Stop();
826 }
827
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_Encrypted_WebM)828 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_Encrypted_WebM) {
829 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
830 kAppendWholeFile);
831 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
832 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
833
834 scoped_refptr<DecoderBuffer> second_file =
835 ReadTestDataFile("bear-640x360-av_enc-av.webm");
836
837 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
838 second_file->data(), second_file->data_size());
839
840 source.EndOfStream();
841
842 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
843 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
844 EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,
845 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
846
847 Play();
848
849 EXPECT_TRUE(WaitUntilOnEnded());
850 source.Abort();
851 Stop();
852 }
853
854 // Config changes from encrypted to clear are not currently supported.
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_ClearThenEncrypted_WebM)855 TEST_F(PipelineIntegrationTest,
856 MediaSource_ConfigChange_ClearThenEncrypted_WebM) {
857 MockMediaSource source("bear-320x240-16x9-aspect.webm", kWebM,
858 kAppendWholeFile);
859 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
860 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
861
862 scoped_refptr<DecoderBuffer> second_file =
863 ReadTestDataFile("bear-640x360-av_enc-av.webm");
864
865 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
866 second_file->data(), second_file->data_size());
867
868 source.EndOfStream();
869
870 message_loop_.Run();
871 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
872
873 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
874 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
875 // The second video was not added, so its time has not been added.
876 EXPECT_EQ(k320WebMFileDurationMs,
877 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
878
879 Play();
880
881 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
882 source.Abort();
883 }
884
885 // Config changes from clear to encrypted are not currently supported.
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_EncryptedThenClear_WebM)886 TEST_F(PipelineIntegrationTest,
887 MediaSource_ConfigChange_EncryptedThenClear_WebM) {
888 MockMediaSource source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM,
889 kAppendWholeFile);
890 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
891 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
892
893 scoped_refptr<DecoderBuffer> second_file =
894 ReadTestDataFile("bear-640x360.webm");
895
896 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
897 second_file->data(), second_file->data_size());
898
899 source.EndOfStream();
900
901 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
902 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
903 // The second video was not added, so its time has not been added.
904 EXPECT_EQ(k320WebMFileDurationMs,
905 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
906
907 Play();
908
909 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
910 source.Abort();
911 }
912
913 #if defined(USE_PROPRIETARY_CODECS)
TEST_F(PipelineIntegrationTest,MediaSource_ADTS)914 TEST_F(PipelineIntegrationTest, MediaSource_ADTS) {
915 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
916 StartPipelineWithMediaSource(&source);
917 source.EndOfStream();
918
919 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
920 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
921 EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
922
923 Play();
924
925 EXPECT_TRUE(WaitUntilOnEnded());
926 }
927
TEST_F(PipelineIntegrationTest,MediaSource_ADTS_TimestampOffset)928 TEST_F(PipelineIntegrationTest, MediaSource_ADTS_TimestampOffset) {
929 MockMediaSource source("sfx.adts", kADTS, kAppendWholeFile);
930 StartHashedPipelineWithMediaSource(&source);
931 EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds());
932
933 // Trim off multiple frames off the beginning of the segment which will cause
934 // the first decoded frame to be incorrect if preroll isn't implemented.
935 const base::TimeDelta adts_preroll_duration =
936 base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100);
937 const base::TimeDelta append_time =
938 source.last_timestamp_offset() - adts_preroll_duration;
939
940 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.adts");
941 source.AppendAtTimeWithWindow(append_time,
942 append_time + adts_preroll_duration,
943 kInfiniteDuration(),
944 second_file->data(),
945 second_file->data_size());
946 source.EndOfStream();
947
948 EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());
949 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
950 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
951 EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
952
953 Play();
954
955 EXPECT_TRUE(WaitUntilOnEnded());
956
957 // Verify preroll is stripped.
958 EXPECT_EQ("-0.06,0.97,-0.90,-0.70,-0.53,-0.34,", GetAudioHash());
959 }
960
TEST_F(PipelineIntegrationTest,BasicPlaybackHashed_MP3)961 TEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {
962 ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK, kHashed));
963
964 Play();
965
966 ASSERT_TRUE(WaitUntilOnEnded());
967
968 // Verify codec delay and preroll are stripped.
969 EXPECT_EQ("3.05,2.87,3.00,3.32,3.58,4.08,", GetAudioHash());
970 }
971
TEST_F(PipelineIntegrationTest,MediaSource_MP3)972 TEST_F(PipelineIntegrationTest, MediaSource_MP3) {
973 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
974 StartHashedPipelineWithMediaSource(&source);
975 source.EndOfStream();
976
977 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
978 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
979 EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
980
981 Play();
982
983 EXPECT_TRUE(WaitUntilOnEnded());
984
985 // Verify that codec delay was stripped.
986 EXPECT_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash());
987 }
988
TEST_F(PipelineIntegrationTest,MediaSource_MP3_TimestampOffset)989 TEST_F(PipelineIntegrationTest, MediaSource_MP3_TimestampOffset) {
990 MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
991 StartPipelineWithMediaSource(&source);
992 EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds());
993
994 // There are 576 silent frames at the start of this mp3. The second append
995 // should trim them off.
996 const base::TimeDelta mp3_preroll_duration =
997 base::TimeDelta::FromSecondsD(576.0 / 44100);
998 const base::TimeDelta append_time =
999 source.last_timestamp_offset() - mp3_preroll_duration;
1000
1001 scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile("sfx.mp3");
1002 source.AppendAtTimeWithWindow(append_time,
1003 append_time + mp3_preroll_duration,
1004 kInfiniteDuration(),
1005 second_file->data(),
1006 second_file->data_size());
1007 source.EndOfStream();
1008
1009 EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds());
1010 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1011 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1012 EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1013
1014 Play();
1015
1016 EXPECT_TRUE(WaitUntilOnEnded());
1017 }
1018
TEST_F(PipelineIntegrationTest,MediaSource_MP3_Icecast)1019 TEST_F(PipelineIntegrationTest, MediaSource_MP3_Icecast) {
1020 MockMediaSource source("icy_sfx.mp3", kMP3, kAppendWholeFile);
1021 StartPipelineWithMediaSource(&source);
1022 source.EndOfStream();
1023
1024 Play();
1025
1026 EXPECT_TRUE(WaitUntilOnEnded());
1027 }
1028
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_MP4)1029 TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
1030 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
1031 StartPipelineWithMediaSource(&source);
1032
1033 scoped_refptr<DecoderBuffer> second_file =
1034 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1035
1036 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1037 second_file->data(), second_file->data_size());
1038
1039 source.EndOfStream();
1040
1041 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1042 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1043 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1044 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1045
1046 Play();
1047
1048 EXPECT_TRUE(WaitUntilOnEnded());
1049 source.Abort();
1050 Stop();
1051 }
1052
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly)1053 TEST_F(PipelineIntegrationTest,
1054 MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly) {
1055 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1056 kAppendWholeFile);
1057 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1058 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1059
1060 scoped_refptr<DecoderBuffer> second_file =
1061 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1062
1063 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1064 second_file->data(), second_file->data_size());
1065
1066 source.EndOfStream();
1067
1068 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1069 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1070 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1071 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1072
1073 Play();
1074
1075 EXPECT_TRUE(WaitUntilOnEnded());
1076 source.Abort();
1077 Stop();
1078 }
1079
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly)1080 TEST_F(PipelineIntegrationTest,
1081 MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) {
1082 MockMediaSource source("bear-640x360-v_frag-cenc-key_rotation.mp4", kMP4Video,
1083 kAppendWholeFile);
1084 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1085 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1086
1087 scoped_refptr<DecoderBuffer> second_file =
1088 ReadTestDataFile("bear-1280x720-v_frag-cenc-key_rotation.mp4");
1089
1090 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1091 second_file->data(), second_file->data_size());
1092
1093 source.EndOfStream();
1094
1095 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1096 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1097 EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,
1098 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1099
1100 Play();
1101
1102 EXPECT_TRUE(WaitUntilOnEnded());
1103 source.Abort();
1104 Stop();
1105 }
1106
1107 // Config changes from clear to encrypted are not currently supported.
1108 // TODO(ddorwin): Figure out why this CHECKs in AppendAtTime().
TEST_F(PipelineIntegrationTest,DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC)1109 TEST_F(PipelineIntegrationTest,
1110 DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC) {
1111 MockMediaSource source("bear-640x360-av_frag.mp4", kMP4Video,
1112 kAppendWholeFile);
1113 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1114 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1115
1116 scoped_refptr<DecoderBuffer> second_file =
1117 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1118
1119 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1120 second_file->data(), second_file->data_size());
1121
1122 source.EndOfStream();
1123
1124 message_loop_.Run();
1125 EXPECT_EQ(PIPELINE_ERROR_DECODE, pipeline_status_);
1126
1127 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1128 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1129 // The second video was not added, so its time has not been added.
1130 EXPECT_EQ(k640IsoFileDurationMs,
1131 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1132
1133 Play();
1134
1135 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1136 source.Abort();
1137 }
1138
1139 // Config changes from encrypted to clear are not currently supported.
TEST_F(PipelineIntegrationTest,MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC)1140 TEST_F(PipelineIntegrationTest,
1141 MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC) {
1142 MockMediaSource source("bear-640x360-v_frag-cenc.mp4", kMP4Video,
1143 kAppendWholeFile);
1144 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1145 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1146
1147 scoped_refptr<DecoderBuffer> second_file =
1148 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1149
1150 source.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec),
1151 second_file->data(), second_file->data_size());
1152
1153 source.EndOfStream();
1154
1155 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1156 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1157 // The second video was not added, so its time has not been added.
1158 EXPECT_EQ(k640IsoCencFileDurationMs,
1159 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1160
1161 Play();
1162
1163 EXPECT_EQ(PIPELINE_ERROR_DECODE, WaitUntilEndedOrError());
1164 source.Abort();
1165 }
1166
1167 // Verify files which change configuration midstream fail gracefully.
TEST_F(PipelineIntegrationTest,MidStreamConfigChangesFail)1168 TEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {
1169 ASSERT_TRUE(Start(
1170 GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK));
1171 Play();
1172 ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);
1173 }
1174
1175 #endif
1176
TEST_F(PipelineIntegrationTest,BasicPlayback_16x9AspectRatio)1177 TEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {
1178 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"),
1179 PIPELINE_OK));
1180 Play();
1181 ASSERT_TRUE(WaitUntilOnEnded());
1182 }
1183
TEST_F(PipelineIntegrationTest,EncryptedPlayback_WebM)1184 TEST_F(PipelineIntegrationTest, EncryptedPlayback_WebM) {
1185 MockMediaSource source("bear-320x240-av_enc-av.webm", kWebM, 219816);
1186 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1187 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1188
1189 source.EndOfStream();
1190 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1191
1192 Play();
1193
1194 ASSERT_TRUE(WaitUntilOnEnded());
1195 source.Abort();
1196 Stop();
1197 }
1198
TEST_F(PipelineIntegrationTest,EncryptedPlayback_ClearStart_WebM)1199 TEST_F(PipelineIntegrationTest, EncryptedPlayback_ClearStart_WebM) {
1200 MockMediaSource source("bear-320x240-av_enc-av_clear-1s.webm", kWebM,
1201 kAppendWholeFile);
1202 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1203 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1204
1205 source.EndOfStream();
1206 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1207
1208 Play();
1209
1210 ASSERT_TRUE(WaitUntilOnEnded());
1211 source.Abort();
1212 Stop();
1213 }
1214
TEST_F(PipelineIntegrationTest,EncryptedPlayback_NoEncryptedFrames_WebM)1215 TEST_F(PipelineIntegrationTest, EncryptedPlayback_NoEncryptedFrames_WebM) {
1216 MockMediaSource source("bear-320x240-av_enc-av_clear-all.webm", kWebM,
1217 kAppendWholeFile);
1218 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1219 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1220
1221 source.EndOfStream();
1222 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1223
1224 Play();
1225
1226 ASSERT_TRUE(WaitUntilOnEnded());
1227 source.Abort();
1228 Stop();
1229 }
1230
1231 #if defined(USE_PROPRIETARY_CODECS)
TEST_F(PipelineIntegrationTest,EncryptedPlayback_MP4_CENC_VideoOnly)1232 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_VideoOnly) {
1233 MockMediaSource source("bear-1280x720-v_frag-cenc.mp4", kMP4Video,
1234 kAppendWholeFile);
1235 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1236 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1237
1238 source.EndOfStream();
1239 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1240
1241 Play();
1242
1243 ASSERT_TRUE(WaitUntilOnEnded());
1244 source.Abort();
1245 Stop();
1246 }
1247
TEST_F(PipelineIntegrationTest,EncryptedPlayback_MP4_CENC_AudioOnly)1248 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_AudioOnly) {
1249 MockMediaSource source("bear-1280x720-a_frag-cenc.mp4", kMP4Audio,
1250 kAppendWholeFile);
1251 FakeEncryptedMedia encrypted_media(new KeyProvidingApp());
1252 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1253
1254 source.EndOfStream();
1255 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1256
1257 Play();
1258
1259 ASSERT_TRUE(WaitUntilOnEnded());
1260 source.Abort();
1261 Stop();
1262 }
1263
TEST_F(PipelineIntegrationTest,EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly)1264 TEST_F(PipelineIntegrationTest,
1265 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) {
1266 MockMediaSource source("bear-1280x720-v_frag-cenc_clear-all.mp4", kMP4Video,
1267 kAppendWholeFile);
1268 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1269 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1270
1271 source.EndOfStream();
1272 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1273
1274 Play();
1275
1276 ASSERT_TRUE(WaitUntilOnEnded());
1277 source.Abort();
1278 Stop();
1279 }
1280
TEST_F(PipelineIntegrationTest,EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly)1281 TEST_F(PipelineIntegrationTest,
1282 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) {
1283 MockMediaSource source("bear-1280x720-a_frag-cenc_clear-all.mp4", kMP4Audio,
1284 kAppendWholeFile);
1285 FakeEncryptedMedia encrypted_media(new NoResponseApp());
1286 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1287
1288 source.EndOfStream();
1289 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1290
1291 Play();
1292
1293 ASSERT_TRUE(WaitUntilOnEnded());
1294 source.Abort();
1295 Stop();
1296 }
1297
TEST_F(PipelineIntegrationTest,BasicPlayback_MediaSource_VideoOnly_MP4_AVC3)1298 TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3) {
1299 MockMediaSource source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3,
1300 kAppendWholeFile);
1301 StartPipelineWithMediaSource(&source);
1302 source.EndOfStream();
1303
1304 EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());
1305 EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());
1306 EXPECT_EQ(k1280IsoAVC3FileDurationMs,
1307 pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());
1308
1309 Play();
1310
1311 ASSERT_TRUE(WaitUntilOnEnded());
1312 source.Abort();
1313 Stop();
1314 }
1315
TEST_F(PipelineIntegrationTest,EncryptedPlayback_MP4_CENC_KeyRotation_Video)1316 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Video) {
1317 MockMediaSource source("bear-1280x720-v_frag-cenc-key_rotation.mp4",
1318 kMP4Video, kAppendWholeFile);
1319 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1320 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1321
1322 source.EndOfStream();
1323 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1324
1325 Play();
1326
1327 ASSERT_TRUE(WaitUntilOnEnded());
1328 source.Abort();
1329 Stop();
1330 }
1331
TEST_F(PipelineIntegrationTest,EncryptedPlayback_MP4_CENC_KeyRotation_Audio)1332 TEST_F(PipelineIntegrationTest, EncryptedPlayback_MP4_CENC_KeyRotation_Audio) {
1333 MockMediaSource source("bear-1280x720-a_frag-cenc-key_rotation.mp4",
1334 kMP4Audio, kAppendWholeFile);
1335 FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());
1336 StartPipelineWithEncryptedMedia(&source, &encrypted_media);
1337
1338 source.EndOfStream();
1339 ASSERT_EQ(PIPELINE_OK, pipeline_status_);
1340
1341 Play();
1342
1343 ASSERT_TRUE(WaitUntilOnEnded());
1344 source.Abort();
1345 Stop();
1346 }
1347 #endif
1348
1349 // TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest,DISABLED_SeekWhilePaused)1350 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePaused) {
1351 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1352
1353 base::TimeDelta duration(pipeline_->GetMediaDuration());
1354 base::TimeDelta start_seek_time(duration / 4);
1355 base::TimeDelta seek_time(duration * 3 / 4);
1356
1357 Play();
1358 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1359 Pause();
1360 ASSERT_TRUE(Seek(seek_time));
1361 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1362 Play();
1363 ASSERT_TRUE(WaitUntilOnEnded());
1364
1365 // Make sure seeking after reaching the end works as expected.
1366 Pause();
1367 ASSERT_TRUE(Seek(seek_time));
1368 EXPECT_EQ(pipeline_->GetMediaTime(), seek_time);
1369 Play();
1370 ASSERT_TRUE(WaitUntilOnEnded());
1371 }
1372
1373 // TODO(acolwell): Fix flakiness http://crbug.com/117921
TEST_F(PipelineIntegrationTest,DISABLED_SeekWhilePlaying)1374 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) {
1375 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK));
1376
1377 base::TimeDelta duration(pipeline_->GetMediaDuration());
1378 base::TimeDelta start_seek_time(duration / 4);
1379 base::TimeDelta seek_time(duration * 3 / 4);
1380
1381 Play();
1382 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));
1383 ASSERT_TRUE(Seek(seek_time));
1384 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1385 ASSERT_TRUE(WaitUntilOnEnded());
1386
1387 // Make sure seeking after reaching the end works as expected.
1388 ASSERT_TRUE(Seek(seek_time));
1389 EXPECT_GE(pipeline_->GetMediaTime(), seek_time);
1390 ASSERT_TRUE(WaitUntilOnEnded());
1391 }
1392
1393 // Verify audio decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest,ChunkDemuxerAbortRead_AudioOnly)1394 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
1395 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM,
1396 8192,
1397 base::TimeDelta::FromMilliseconds(464),
1398 base::TimeDelta::FromMilliseconds(617),
1399 0x10CA, 19730));
1400 }
1401
1402 // Verify video decoder & renderer can handle aborted demuxer reads.
TEST_F(PipelineIntegrationTest,ChunkDemuxerAbortRead_VideoOnly)1403 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
1404 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM,
1405 32768,
1406 base::TimeDelta::FromMilliseconds(167),
1407 base::TimeDelta::FromMilliseconds(1668),
1408 0x1C896, 65536));
1409 }
1410
1411 // Verify that Opus audio in WebM containers can be played back.
TEST_F(PipelineIntegrationTest,BasicPlayback_AudioOnly_Opus_WebM)1412 TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) {
1413 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"),
1414 PIPELINE_OK));
1415 Play();
1416 ASSERT_TRUE(WaitUntilOnEnded());
1417 }
1418
1419 // Verify that VP9 video in WebM containers can be played back.
TEST_F(PipelineIntegrationTest,BasicPlayback_VideoOnly_VP9_WebM)1420 TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) {
1421 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"),
1422 PIPELINE_OK));
1423 Play();
1424 ASSERT_TRUE(WaitUntilOnEnded());
1425 }
1426
1427 // Verify that VP9 video and Opus audio in the same WebM container can be played
1428 // back.
TEST_F(PipelineIntegrationTest,BasicPlayback_VP9_Opus_WebM)1429 TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) {
1430 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"),
1431 PIPELINE_OK));
1432 Play();
1433 ASSERT_TRUE(WaitUntilOnEnded());
1434 }
1435
1436 // Verify that VP8 video with alpha channel can be played back.
TEST_F(PipelineIntegrationTest,BasicPlayback_VP8A_WebM)1437 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) {
1438 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"),
1439 PIPELINE_OK));
1440 Play();
1441 ASSERT_TRUE(WaitUntilOnEnded());
1442 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1443 }
1444
1445 // Verify that VP8A video with odd width/height can be played back.
TEST_F(PipelineIntegrationTest,BasicPlayback_VP8A_Odd_WebM)1446 TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) {
1447 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"),
1448 PIPELINE_OK));
1449 Play();
1450 ASSERT_TRUE(WaitUntilOnEnded());
1451 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV12A);
1452 }
1453
1454 // Verify that VP8 video with inband text track can be played back.
TEST_F(PipelineIntegrationTest,BasicPlayback_VP8_WebVTT_WebM)1455 TEST_F(PipelineIntegrationTest,
1456 BasicPlayback_VP8_WebVTT_WebM) {
1457 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"),
1458 PIPELINE_OK));
1459 Play();
1460 ASSERT_TRUE(WaitUntilOnEnded());
1461 }
1462
1463 // Verify that VP9 video with 4:4:4 subsampling can be played back.
TEST_F(PipelineIntegrationTest,P444_VP9_WebM)1464 TEST_F(PipelineIntegrationTest, P444_VP9_WebM) {
1465 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"),
1466 PIPELINE_OK));
1467 Play();
1468 ASSERT_TRUE(WaitUntilOnEnded());
1469 EXPECT_EQ(last_video_frame_format_, VideoFrame::YV24);
1470 }
1471
1472 // Verify that videos with an odd frame size playback successfully.
TEST_F(PipelineIntegrationTest,BasicPlayback_OddVideoSize)1473 TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {
1474 ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"),
1475 PIPELINE_OK));
1476 Play();
1477 ASSERT_TRUE(WaitUntilOnEnded());
1478 }
1479
1480 } // namespace media
1481