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 "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 #include "media/filters/renderer_impl.h"
21 #include "testing/gmock/include/gmock/gmock.h"
24 using testing::AnyNumber
;
25 using testing::AtLeast
;
26 using testing::AtMost
;
27 using testing::SaveArg
;
31 const char kSourceId
[] = "SourceId";
32 const uint8 kInitData
[] = { 0x69, 0x6e, 0x69, 0x74 };
34 const char kWebM
[] = "video/webm; codecs=\"vp8,vorbis\"";
35 const char kWebMVP9
[] = "video/webm; codecs=\"vp9\"";
36 const char kAudioOnlyWebM
[] = "video/webm; codecs=\"vorbis\"";
37 const char kOpusAudioOnlyWebM
[] = "video/webm; codecs=\"opus\"";
38 const char kVideoOnlyWebM
[] = "video/webm; codecs=\"vp8\"";
39 const char kMP4VideoType
[] = "video/mp4";
40 const char kMP4AudioType
[] = "audio/mp4";
41 #if defined(USE_PROPRIETARY_CODECS)
42 const char kADTS
[] = "audio/aac";
43 const char kMP4
[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
44 const char kMP4Video
[] = "video/mp4; codecs=\"avc1.4D4041\"";
45 const char kMP4VideoAVC3
[] = "video/mp4; codecs=\"avc3.64001f\"";
46 const char kMP4Audio
[] = "audio/mp4; codecs=\"mp4a.40.2\"";
47 const char kMP3
[] = "audio/mpeg";
48 #endif // defined(USE_PROPRIETARY_CODECS)
50 // Key used to encrypt test files.
51 const uint8 kSecretKey
[] = {
52 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
53 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
56 // The key ID for all encrypted files.
57 const uint8 kKeyId
[] = {
58 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
59 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
62 const int kAppendWholeFile
= -1;
64 // Constants for the Media Source config change tests.
65 const int kAppendTimeSec
= 1;
66 const int kAppendTimeMs
= kAppendTimeSec
* 1000;
67 const int k320WebMFileDurationMs
= 2736;
68 const int k640WebMFileDurationMs
= 2749;
69 const int kOpusEndTrimmingWebMFileDurationMs
= 2741;
70 const int kVP9WebMFileDurationMs
= 2736;
71 const int kVP8AWebMFileDurationMs
= 2733;
73 #if defined(USE_PROPRIETARY_CODECS)
74 const int k640IsoFileDurationMs
= 2737;
75 const int k640IsoCencFileDurationMs
= 2736;
76 const int k1280IsoFileDurationMs
= 2736;
77 const int k1280IsoAVC3FileDurationMs
= 2736;
78 #endif // defined(USE_PROPRIETARY_CODECS)
80 // Return a timeline offset for bear-320x240-live.webm.
81 static base::Time
kLiveTimelineOffset() {
82 // The file contians the following UTC timeline offset:
83 // 2012-11-10 12:34:56.789123456
84 // Since base::Time only has a resolution of microseconds,
85 // construct a base::Time for 2012-11-10 12:34:56.789123.
86 base::Time::Exploded exploded_time
;
87 exploded_time
.year
= 2012;
88 exploded_time
.month
= 11;
89 exploded_time
.day_of_month
= 10;
90 exploded_time
.hour
= 12;
91 exploded_time
.minute
= 34;
92 exploded_time
.second
= 56;
93 exploded_time
.millisecond
= 789;
94 base::Time timeline_offset
= base::Time::FromUTCExploded(exploded_time
);
96 timeline_offset
+= base::TimeDelta::FromMicroseconds(123);
98 return timeline_offset
;
101 // FFmpeg only supports time a resolution of seconds so this
102 // helper function truncates a base::Time to seconds resolution.
103 static base::Time
TruncateToFFmpegTimeResolution(base::Time t
) {
104 base::Time::Exploded exploded_time
;
105 t
.UTCExplode(&exploded_time
);
106 exploded_time
.millisecond
= 0;
108 return base::Time::FromUTCExploded(exploded_time
);
111 // Note: Tests using this class only exercise the DecryptingDemuxerStream path.
112 // They do not exercise the Decrypting{Audio|Video}Decoder path.
113 class FakeEncryptedMedia
{
115 // Defines the behavior of the "app" that responds to EME events.
118 virtual ~AppBase() {}
120 virtual void OnSessionMessage(const std::string
& web_session_id
,
121 const std::vector
<uint8
>& message
,
122 const GURL
& destination_url
) = 0;
124 virtual void OnSessionReady(const std::string
& web_session_id
) = 0;
126 virtual void OnSessionClosed(const std::string
& web_session_id
) = 0;
128 // Errors are not expected unless overridden.
129 virtual void OnSessionError(const std::string
& web_session_id
,
130 const std::string
& error_name
,
132 const std::string
& error_message
) {
133 FAIL() << "Unexpected Key Error";
136 virtual void NeedKey(const std::string
& type
,
137 const std::vector
<uint8
>& init_data
,
138 AesDecryptor
* decryptor
) = 0;
141 FakeEncryptedMedia(AppBase
* app
)
142 : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionMessage
,
143 base::Unretained(this)),
144 base::Bind(&FakeEncryptedMedia::OnSessionClosed
,
145 base::Unretained(this))),
148 AesDecryptor
* decryptor() {
152 // Callbacks for firing session events. Delegate to |app_|.
153 void OnSessionMessage(const std::string
& web_session_id
,
154 const std::vector
<uint8
>& message
,
155 const GURL
& destination_url
) {
156 app_
->OnSessionMessage(web_session_id
, message
, destination_url
);
159 void OnSessionReady(const std::string
& web_session_id
) {
160 app_
->OnSessionReady(web_session_id
);
163 void OnSessionClosed(const std::string
& web_session_id
) {
164 app_
->OnSessionClosed(web_session_id
);
167 void OnSessionError(const std::string
& web_session_id
,
168 const std::string
& error_name
,
170 const std::string
& error_message
) {
171 app_
->OnSessionError(
172 web_session_id
, error_name
, system_code
, error_message
);
175 void NeedKey(const std::string
& type
,
176 const std::vector
<uint8
>& init_data
) {
177 app_
->NeedKey(type
, init_data
, &decryptor_
);
181 AesDecryptor decryptor_
;
182 scoped_ptr
<AppBase
> app_
;
185 enum PromiseResult
{ RESOLVED
, REJECTED
};
187 // Provides |kSecretKey| in response to needkey.
188 class KeyProvidingApp
: public FakeEncryptedMedia::AppBase
{
192 void OnResolveWithSession(PromiseResult expected
,
193 const std::string
& web_session_id
) {
194 EXPECT_EQ(expected
, RESOLVED
);
195 EXPECT_GT(web_session_id
.length(), 0ul);
196 current_session_id_
= web_session_id
;
199 void OnResolve(PromiseResult expected
) {
200 EXPECT_EQ(expected
, RESOLVED
);
203 void OnReject(PromiseResult expected
,
204 media::MediaKeys::Exception exception_code
,
206 const std::string
& error_message
) {
207 EXPECT_EQ(expected
, REJECTED
);
210 scoped_ptr
<SimpleCdmPromise
> CreatePromise(PromiseResult expected
) {
211 scoped_ptr
<media::SimpleCdmPromise
> promise(new media::SimpleCdmPromise(
213 &KeyProvidingApp::OnResolve
, base::Unretained(this), expected
),
215 &KeyProvidingApp::OnReject
, base::Unretained(this), expected
)));
216 return promise
.Pass();
219 scoped_ptr
<NewSessionCdmPromise
> CreateSessionPromise(
220 PromiseResult expected
) {
221 scoped_ptr
<media::NewSessionCdmPromise
> promise(
222 new media::NewSessionCdmPromise(
223 base::Bind(&KeyProvidingApp::OnResolveWithSession
,
224 base::Unretained(this),
227 &KeyProvidingApp::OnReject
, base::Unretained(this), expected
)));
228 return promise
.Pass();
231 virtual void OnSessionMessage(const std::string
& web_session_id
,
232 const std::vector
<uint8
>& message
,
233 const GURL
& destination_url
) OVERRIDE
{
234 EXPECT_FALSE(web_session_id
.empty());
235 EXPECT_FALSE(message
.empty());
236 EXPECT_EQ(current_session_id_
, web_session_id
);
239 virtual void OnSessionReady(const std::string
& web_session_id
) OVERRIDE
{
240 EXPECT_EQ(current_session_id_
, web_session_id
);
243 virtual void OnSessionClosed(const std::string
& web_session_id
) OVERRIDE
{
244 EXPECT_EQ(current_session_id_
, web_session_id
);
247 virtual void NeedKey(const std::string
& type
,
248 const std::vector
<uint8
>& init_data
,
249 AesDecryptor
* decryptor
) OVERRIDE
{
250 if (current_session_id_
.empty()) {
251 decryptor
->CreateSession(type
,
253 arraysize(kInitData
),
254 MediaKeys::TEMPORARY_SESSION
,
255 CreateSessionPromise(RESOLVED
));
256 EXPECT_FALSE(current_session_id_
.empty());
259 // Clear Key really needs the key ID in |init_data|. For WebM, they are the
260 // same, but this is not the case for ISO CENC. Therefore, provide the
262 const uint8
* key_id
= init_data
.empty() ? NULL
: &init_data
[0];
263 size_t key_id_length
= init_data
.size();
264 if (type
== kMP4AudioType
|| type
== kMP4VideoType
) {
266 key_id_length
= arraysize(kKeyId
);
269 // Convert key into a JSON structure and then add it.
270 std::string jwk
= GenerateJWKSet(
271 kSecretKey
, arraysize(kSecretKey
), key_id
, key_id_length
);
272 decryptor
->UpdateSession(current_session_id_
,
273 reinterpret_cast<const uint8
*>(jwk
.data()),
275 CreatePromise(RESOLVED
));
278 std::string current_session_id_
;
281 class RotatingKeyProvidingApp
: public KeyProvidingApp
{
283 RotatingKeyProvidingApp() : num_distint_need_key_calls_(0) {}
284 virtual ~RotatingKeyProvidingApp() {
285 // Expect that NeedKey is fired multiple times with different |init_data|.
286 EXPECT_GT(num_distint_need_key_calls_
, 1u);
289 virtual void NeedKey(const std::string
& type
,
290 const std::vector
<uint8
>& init_data
,
291 AesDecryptor
* decryptor
) OVERRIDE
{
292 // Skip the request if the |init_data| has been seen.
293 if (init_data
== prev_init_data_
)
295 prev_init_data_
= init_data
;
296 ++num_distint_need_key_calls_
;
298 decryptor
->CreateSession(type
,
299 vector_as_array(&init_data
),
301 MediaKeys::TEMPORARY_SESSION
,
302 CreateSessionPromise(RESOLVED
));
304 std::vector
<uint8
> key_id
;
305 std::vector
<uint8
> key
;
306 EXPECT_TRUE(GetKeyAndKeyId(init_data
, &key
, &key_id
));
308 // Convert key into a JSON structure and then add it.
309 std::string jwk
= GenerateJWKSet(vector_as_array(&key
),
311 vector_as_array(&key_id
),
313 decryptor
->UpdateSession(current_session_id_
,
314 reinterpret_cast<const uint8
*>(jwk
.data()),
316 CreatePromise(RESOLVED
));
320 bool GetKeyAndKeyId(std::vector
<uint8
> init_data
,
321 std::vector
<uint8
>* key
,
322 std::vector
<uint8
>* key_id
) {
323 // For WebM, init_data is key_id; for ISO CENC, init_data should contain
324 // the key_id. We assume key_id is in the end of init_data here (that is
325 // only a reasonable assumption for WebM and clear key ISO CENC).
326 DCHECK_GE(init_data
.size(), arraysize(kKeyId
));
327 std::vector
<uint8
> key_id_from_init_data(
328 init_data
.end() - arraysize(kKeyId
), init_data
.end());
330 key
->assign(kSecretKey
, kSecretKey
+ arraysize(kSecretKey
));
331 key_id
->assign(kKeyId
, kKeyId
+ arraysize(kKeyId
));
333 // The Key and KeyId for this testing key provider are created by left
334 // rotating kSecretKey and kKeyId. Note that this implementation is only
335 // intended for testing purpose. The actual key rotation algorithm can be
336 // much more complicated.
337 // Find out the rotating position from |key_id_from_init_data| and apply on
339 for (size_t pos
= 0; pos
< arraysize(kKeyId
); ++pos
) {
340 std::rotate(key_id
->begin(), key_id
->begin() + pos
, key_id
->end());
341 if (*key_id
== key_id_from_init_data
) {
342 std::rotate(key
->begin(), key
->begin() + pos
, key
->end());
349 std::vector
<uint8
> prev_init_data_
;
350 uint32 num_distint_need_key_calls_
;
353 // Ignores needkey and does not perform a license request
354 class NoResponseApp
: public FakeEncryptedMedia::AppBase
{
356 virtual void OnSessionMessage(const std::string
& web_session_id
,
357 const std::vector
<uint8
>& message
,
358 const GURL
& default_url
) OVERRIDE
{
359 EXPECT_FALSE(web_session_id
.empty());
360 EXPECT_FALSE(message
.empty());
361 FAIL() << "Unexpected Message";
364 virtual void OnSessionReady(const std::string
& web_session_id
) OVERRIDE
{
365 EXPECT_FALSE(web_session_id
.empty());
366 FAIL() << "Unexpected Ready";
369 virtual void OnSessionClosed(const std::string
& web_session_id
) OVERRIDE
{
370 EXPECT_FALSE(web_session_id
.empty());
371 FAIL() << "Unexpected Closed";
374 virtual void NeedKey(const std::string
& type
,
375 const std::vector
<uint8
>& init_data
,
376 AesDecryptor
* decryptor
) OVERRIDE
{
380 // Helper class that emulates calls made on the ChunkDemuxer by the
382 class MockMediaSource
{
384 MockMediaSource(const std::string
& filename
,
385 const std::string
& mimetype
,
386 int initial_append_size
)
387 : file_path_(GetTestDataFilePath(filename
)),
388 current_position_(0),
389 initial_append_size_(initial_append_size
),
391 chunk_demuxer_(new ChunkDemuxer(
392 base::Bind(&MockMediaSource::DemuxerOpened
, base::Unretained(this)),
393 base::Bind(&MockMediaSource::DemuxerNeedKey
,
394 base::Unretained(this)),
397 owned_chunk_demuxer_(chunk_demuxer_
) {
399 file_data_
= ReadTestDataFile(filename
);
401 if (initial_append_size_
== kAppendWholeFile
)
402 initial_append_size_
= file_data_
->data_size();
404 DCHECK_GT(initial_append_size_
, 0);
405 DCHECK_LE(initial_append_size_
, file_data_
->data_size());
408 virtual ~MockMediaSource() {}
410 scoped_ptr
<Demuxer
> GetDemuxer() { return owned_chunk_demuxer_
.Pass(); }
412 void set_need_key_cb(const Demuxer::NeedKeyCB
& need_key_cb
) {
413 need_key_cb_
= need_key_cb
;
416 void Seek(base::TimeDelta seek_time
, int new_position
, int seek_append_size
) {
417 chunk_demuxer_
->StartWaitingForSeek(seek_time
);
419 chunk_demuxer_
->Abort(
421 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_
);
423 DCHECK_GE(new_position
, 0);
424 DCHECK_LT(new_position
, file_data_
->data_size());
425 current_position_
= new_position
;
427 AppendData(seek_append_size
);
430 void AppendData(int size
) {
431 DCHECK(chunk_demuxer_
);
432 DCHECK_LT(current_position_
, file_data_
->data_size());
433 DCHECK_LE(current_position_
+ size
, file_data_
->data_size());
435 chunk_demuxer_
->AppendData(
436 kSourceId
, file_data_
->data() + current_position_
, size
,
437 base::TimeDelta(), kInfiniteDuration(), &last_timestamp_offset_
,
438 base::Bind(&MockMediaSource::InitSegmentReceived
,
439 base::Unretained(this)));
440 current_position_
+= size
;
443 void AppendAtTime(base::TimeDelta timestamp_offset
,
446 CHECK(!chunk_demuxer_
->IsParsingMediaSegment(kSourceId
));
447 chunk_demuxer_
->AppendData(kSourceId
, pData
, size
,
448 base::TimeDelta(), kInfiniteDuration(),
450 base::Bind(&MockMediaSource::InitSegmentReceived
,
451 base::Unretained(this)));
452 last_timestamp_offset_
= timestamp_offset
;
455 void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset
,
456 base::TimeDelta append_window_start
,
457 base::TimeDelta append_window_end
,
460 CHECK(!chunk_demuxer_
->IsParsingMediaSegment(kSourceId
));
461 chunk_demuxer_
->AppendData(kSourceId
,
467 base::Bind(&MockMediaSource::InitSegmentReceived
,
468 base::Unretained(this)));
469 last_timestamp_offset_
= timestamp_offset
;
473 chunk_demuxer_
->MarkEndOfStream(PIPELINE_OK
);
479 chunk_demuxer_
->Shutdown();
480 chunk_demuxer_
= NULL
;
483 void DemuxerOpened() {
484 base::MessageLoop::current()->PostTask(
485 FROM_HERE
, base::Bind(&MockMediaSource::DemuxerOpenedTask
,
486 base::Unretained(this)));
489 void DemuxerOpenedTask() {
490 // This code assumes that |mimetype_| is one of the following forms.
492 // 2. video/webm;codec="vorbis,vp8".
493 size_t semicolon
= mimetype_
.find(";");
494 std::string type
= mimetype_
;
495 std::vector
<std::string
> codecs
;
496 if (semicolon
!= std::string::npos
) {
497 type
= mimetype_
.substr(0, semicolon
);
498 size_t codecs_param_start
= mimetype_
.find("codecs=\"", semicolon
);
500 CHECK_NE(codecs_param_start
, std::string::npos
);
502 codecs_param_start
+= 8; // Skip over the codecs=".
504 size_t codecs_param_end
= mimetype_
.find("\"", codecs_param_start
);
506 CHECK_NE(codecs_param_end
, std::string::npos
);
508 std::string codecs_param
=
509 mimetype_
.substr(codecs_param_start
,
510 codecs_param_end
- codecs_param_start
);
511 Tokenize(codecs_param
, ",", &codecs
);
514 CHECK_EQ(chunk_demuxer_
->AddId(kSourceId
, type
, codecs
), ChunkDemuxer::kOk
);
516 AppendData(initial_append_size_
);
519 void DemuxerNeedKey(const std::string
& type
,
520 const std::vector
<uint8
>& init_data
) {
521 DCHECK(!init_data
.empty());
522 CHECK(!need_key_cb_
.is_null());
523 need_key_cb_
.Run(type
, init_data
);
526 base::TimeDelta
last_timestamp_offset() const {
527 return last_timestamp_offset_
;
530 MOCK_METHOD0(InitSegmentReceived
, void(void));
533 base::FilePath file_path_
;
534 scoped_refptr
<DecoderBuffer
> file_data_
;
535 int current_position_
;
536 int initial_append_size_
;
537 std::string mimetype_
;
538 ChunkDemuxer
* chunk_demuxer_
;
539 scoped_ptr
<Demuxer
> owned_chunk_demuxer_
;
540 Demuxer::NeedKeyCB need_key_cb_
;
541 base::TimeDelta last_timestamp_offset_
;
544 class PipelineIntegrationTest
545 : public testing::Test
,
546 public PipelineIntegrationTestBase
{
548 void StartPipelineWithMediaSource(MockMediaSource
* source
) {
549 EXPECT_CALL(*source
, InitSegmentReceived()).Times(AtLeast(1));
550 EXPECT_CALL(*this, OnMetadata(_
))
552 .WillRepeatedly(SaveArg
<0>(&metadata_
));
553 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH
))
555 demuxer_
= source
->GetDemuxer().Pass();
558 CreateRenderer(NULL
),
559 base::Bind(&PipelineIntegrationTest::OnEnded
, base::Unretained(this)),
560 base::Bind(&PipelineIntegrationTest::OnError
, base::Unretained(this)),
561 QuitOnStatusCB(PIPELINE_OK
),
562 base::Bind(&PipelineIntegrationTest::OnMetadata
,
563 base::Unretained(this)),
564 base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged
,
565 base::Unretained(this)),
567 base::Bind(&PipelineIntegrationTest::OnAddTextTrack
,
568 base::Unretained(this)));
572 void StartHashedPipelineWithMediaSource(MockMediaSource
* source
) {
573 hashing_enabled_
= true;
574 StartPipelineWithMediaSource(source
);
577 void StartPipelineWithEncryptedMedia(
578 MockMediaSource
* source
,
579 FakeEncryptedMedia
* encrypted_media
) {
580 EXPECT_CALL(*this, OnMetadata(_
))
582 .WillRepeatedly(SaveArg
<0>(&metadata_
));
583 EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH
))
585 demuxer_
= source
->GetDemuxer().Pass();
588 CreateRenderer(encrypted_media
->decryptor()),
589 base::Bind(&PipelineIntegrationTest::OnEnded
, base::Unretained(this)),
590 base::Bind(&PipelineIntegrationTest::OnError
, base::Unretained(this)),
591 QuitOnStatusCB(PIPELINE_OK
),
592 base::Bind(&PipelineIntegrationTest::OnMetadata
,
593 base::Unretained(this)),
594 base::Bind(&PipelineIntegrationTest::OnBufferingStateChanged
,
595 base::Unretained(this)),
597 base::Bind(&PipelineIntegrationTest::OnAddTextTrack
,
598 base::Unretained(this)));
600 source
->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey
,
601 base::Unretained(encrypted_media
)));
606 // Verifies that seeking works properly for ChunkDemuxer when the
607 // seek happens while there is a pending read on the ChunkDemuxer
608 // and no data is available.
609 bool TestSeekDuringRead(const std::string
& filename
,
610 const std::string
& mimetype
,
611 int initial_append_size
,
612 base::TimeDelta start_seek_time
,
613 base::TimeDelta seek_time
,
614 int seek_file_position
,
615 int seek_append_size
) {
616 MockMediaSource
source(filename
, mimetype
, initial_append_size
);
617 StartPipelineWithMediaSource(&source
);
619 if (pipeline_status_
!= PIPELINE_OK
)
623 if (!WaitUntilCurrentTimeIsAfter(start_seek_time
))
626 source
.Seek(seek_time
, seek_file_position
, seek_append_size
);
627 if (!Seek(seek_time
))
630 source
.EndOfStream();
638 TEST_F(PipelineIntegrationTest
, BasicPlayback
) {
639 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
643 ASSERT_TRUE(WaitUntilOnEnded());
646 TEST_F(PipelineIntegrationTest
, BasicPlaybackOpusOgg
) {
647 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus.ogg"), PIPELINE_OK
));
651 ASSERT_TRUE(WaitUntilOnEnded());
654 TEST_F(PipelineIntegrationTest
, BasicPlaybackHashed
) {
656 GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
, kHashed
));
660 ASSERT_TRUE(WaitUntilOnEnded());
662 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
663 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
664 EXPECT_TRUE(demuxer_
->GetTimelineOffset().is_null());
667 TEST_F(PipelineIntegrationTest
, BasicPlaybackLive
) {
669 GetTestDataFilePath("bear-320x240-live.webm"), PIPELINE_OK
, kHashed
));
673 ASSERT_TRUE(WaitUntilOnEnded());
675 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
676 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
678 // TODO: Fix FFmpeg code to return higher resolution time values so
679 // we don't have to truncate our expectations here.
680 EXPECT_EQ(TruncateToFFmpegTimeResolution(kLiveTimelineOffset()),
681 demuxer_
->GetTimelineOffset());
684 TEST_F(PipelineIntegrationTest
, F32PlaybackHashed
) {
686 Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK
, kHashed
));
688 ASSERT_TRUE(WaitUntilOnEnded());
689 EXPECT_EQ(std::string(kNullVideoHash
), GetVideoHash());
690 EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash());
693 TEST_F(PipelineIntegrationTest
, BasicPlaybackEncrypted
) {
694 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
695 set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey
,
696 base::Unretained(&encrypted_media
)));
698 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"),
699 encrypted_media
.decryptor()));
703 ASSERT_TRUE(WaitUntilOnEnded());
707 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource
) {
708 MockMediaSource
source("bear-320x240.webm", kWebM
, 219229);
709 StartPipelineWithMediaSource(&source
);
710 source
.EndOfStream();
712 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
713 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
714 EXPECT_EQ(k320WebMFileDurationMs
,
715 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
719 ASSERT_TRUE(WaitUntilOnEnded());
721 EXPECT_TRUE(demuxer_
->GetTimelineOffset().is_null());
726 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_Live
) {
727 MockMediaSource
source("bear-320x240-live.webm", kWebM
, 219221);
728 StartPipelineWithMediaSource(&source
);
729 source
.EndOfStream();
731 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
732 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
733 EXPECT_EQ(k320WebMFileDurationMs
,
734 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
738 ASSERT_TRUE(WaitUntilOnEnded());
740 EXPECT_EQ(kLiveTimelineOffset(),
741 demuxer_
->GetTimelineOffset());
746 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_VP9_WebM
) {
747 MockMediaSource
source("bear-vp9.webm", kWebMVP9
, 67504);
748 StartPipelineWithMediaSource(&source
);
749 source
.EndOfStream();
751 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
752 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
753 EXPECT_EQ(kVP9WebMFileDurationMs
,
754 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
758 ASSERT_TRUE(WaitUntilOnEnded());
763 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_VP8A_WebM
) {
764 MockMediaSource
source("bear-vp8a.webm", kVideoOnlyWebM
, kAppendWholeFile
);
765 StartPipelineWithMediaSource(&source
);
766 source
.EndOfStream();
768 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
769 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
770 EXPECT_EQ(kVP8AWebMFileDurationMs
,
771 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
775 ASSERT_TRUE(WaitUntilOnEnded());
780 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_Opus_WebM
) {
781 MockMediaSource
source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM
,
783 StartPipelineWithMediaSource(&source
);
784 source
.EndOfStream();
786 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
787 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
788 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs
,
789 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
792 ASSERT_TRUE(WaitUntilOnEnded());
797 // Flaky. http://crbug.com/304776
798 TEST_F(PipelineIntegrationTest
, DISABLED_MediaSource_Opus_Seeking_WebM
) {
799 MockMediaSource
source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM
,
801 StartHashedPipelineWithMediaSource(&source
);
803 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
804 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
805 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs
,
806 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
808 base::TimeDelta start_seek_time
= base::TimeDelta::FromMilliseconds(1000);
809 base::TimeDelta seek_time
= base::TimeDelta::FromMilliseconds(2000);
812 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
813 source
.Seek(seek_time
, 0x1D5, 34017);
814 source
.EndOfStream();
815 ASSERT_TRUE(Seek(seek_time
));
817 ASSERT_TRUE(WaitUntilOnEnded());
819 EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash());
825 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_WebM
) {
826 MockMediaSource
source("bear-320x240-16x9-aspect.webm", kWebM
,
828 StartPipelineWithMediaSource(&source
);
830 scoped_refptr
<DecoderBuffer
> second_file
=
831 ReadTestDataFile("bear-640x360.webm");
833 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
834 second_file
->data(), second_file
->data_size());
836 source
.EndOfStream();
838 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
839 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
840 EXPECT_EQ(kAppendTimeMs
+ k640WebMFileDurationMs
,
841 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
845 EXPECT_TRUE(WaitUntilOnEnded());
850 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_Encrypted_WebM
) {
851 MockMediaSource
source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM
,
853 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
854 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
856 scoped_refptr
<DecoderBuffer
> second_file
=
857 ReadTestDataFile("bear-640x360-av_enc-av.webm");
859 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
860 second_file
->data(), second_file
->data_size());
862 source
.EndOfStream();
864 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
865 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
866 EXPECT_EQ(kAppendTimeMs
+ k640WebMFileDurationMs
,
867 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
871 EXPECT_TRUE(WaitUntilOnEnded());
876 // Config changes from encrypted to clear are not currently supported.
877 TEST_F(PipelineIntegrationTest
,
878 MediaSource_ConfigChange_ClearThenEncrypted_WebM
) {
879 MockMediaSource
source("bear-320x240-16x9-aspect.webm", kWebM
,
881 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
882 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
884 scoped_refptr
<DecoderBuffer
> second_file
=
885 ReadTestDataFile("bear-640x360-av_enc-av.webm");
887 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
888 second_file
->data(), second_file
->data_size());
890 source
.EndOfStream();
893 EXPECT_EQ(PIPELINE_ERROR_DECODE
, pipeline_status_
);
895 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
896 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
897 // The second video was not added, so its time has not been added.
898 EXPECT_EQ(k320WebMFileDurationMs
,
899 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
903 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
907 // Config changes from clear to encrypted are not currently supported.
908 TEST_F(PipelineIntegrationTest
,
909 MediaSource_ConfigChange_EncryptedThenClear_WebM
) {
910 MockMediaSource
source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM
,
912 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
913 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
915 scoped_refptr
<DecoderBuffer
> second_file
=
916 ReadTestDataFile("bear-640x360.webm");
918 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
919 second_file
->data(), second_file
->data_size());
921 source
.EndOfStream();
923 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
924 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
925 // The second video was not added, so its time has not been added.
926 EXPECT_EQ(k320WebMFileDurationMs
,
927 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
931 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
935 #if defined(USE_PROPRIETARY_CODECS)
936 TEST_F(PipelineIntegrationTest
, MediaSource_ADTS
) {
937 MockMediaSource
source("sfx.adts", kADTS
, kAppendWholeFile
);
938 StartPipelineWithMediaSource(&source
);
939 source
.EndOfStream();
941 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
942 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
943 EXPECT_EQ(325, pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
947 EXPECT_TRUE(WaitUntilOnEnded());
950 TEST_F(PipelineIntegrationTest
, MediaSource_ADTS_TimestampOffset
) {
951 MockMediaSource
source("sfx.adts", kADTS
, kAppendWholeFile
);
952 StartHashedPipelineWithMediaSource(&source
);
953 EXPECT_EQ(325, source
.last_timestamp_offset().InMilliseconds());
955 // Trim off multiple frames off the beginning of the segment which will cause
956 // the first decoded frame to be incorrect if preroll isn't implemented.
957 const base::TimeDelta adts_preroll_duration
=
958 base::TimeDelta::FromSecondsD(2.5 * 1024 / 44100);
959 const base::TimeDelta append_time
=
960 source
.last_timestamp_offset() - adts_preroll_duration
;
962 scoped_refptr
<DecoderBuffer
> second_file
= ReadTestDataFile("sfx.adts");
963 source
.AppendAtTimeWithWindow(append_time
,
964 append_time
+ adts_preroll_duration
,
967 second_file
->data_size());
968 source
.EndOfStream();
970 EXPECT_EQ(592, source
.last_timestamp_offset().InMilliseconds());
971 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
972 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
973 EXPECT_EQ(592, pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
977 EXPECT_TRUE(WaitUntilOnEnded());
979 // Verify preroll is stripped.
980 EXPECT_EQ("-0.06,0.97,-0.90,-0.70,-0.53,-0.34,", GetAudioHash());
983 TEST_F(PipelineIntegrationTest
, BasicPlaybackHashed_MP3
) {
984 ASSERT_TRUE(Start(GetTestDataFilePath("sfx.mp3"), PIPELINE_OK
, kHashed
));
988 ASSERT_TRUE(WaitUntilOnEnded());
990 // Verify codec delay and preroll are stripped.
991 EXPECT_EQ("3.05,2.87,3.00,3.32,3.58,4.08,", GetAudioHash());
994 TEST_F(PipelineIntegrationTest
, MediaSource_MP3
) {
995 MockMediaSource
source("sfx.mp3", kMP3
, kAppendWholeFile
);
996 StartHashedPipelineWithMediaSource(&source
);
997 source
.EndOfStream();
999 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1000 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1001 EXPECT_EQ(313, pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1005 EXPECT_TRUE(WaitUntilOnEnded());
1007 // Verify that codec delay was stripped.
1008 EXPECT_EQ("1.01,2.71,4.18,4.32,3.04,1.12,", GetAudioHash());
1011 TEST_F(PipelineIntegrationTest
, MediaSource_MP3_TimestampOffset
) {
1012 MockMediaSource
source("sfx.mp3", kMP3
, kAppendWholeFile
);
1013 StartPipelineWithMediaSource(&source
);
1014 EXPECT_EQ(313, source
.last_timestamp_offset().InMilliseconds());
1016 // There are 576 silent frames at the start of this mp3. The second append
1017 // should trim them off.
1018 const base::TimeDelta mp3_preroll_duration
=
1019 base::TimeDelta::FromSecondsD(576.0 / 44100);
1020 const base::TimeDelta append_time
=
1021 source
.last_timestamp_offset() - mp3_preroll_duration
;
1023 scoped_refptr
<DecoderBuffer
> second_file
= ReadTestDataFile("sfx.mp3");
1024 source
.AppendAtTimeWithWindow(append_time
,
1025 append_time
+ mp3_preroll_duration
,
1026 kInfiniteDuration(),
1027 second_file
->data(),
1028 second_file
->data_size());
1029 source
.EndOfStream();
1031 EXPECT_EQ(613, source
.last_timestamp_offset().InMilliseconds());
1032 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1033 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1034 EXPECT_EQ(613, pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1038 EXPECT_TRUE(WaitUntilOnEnded());
1041 TEST_F(PipelineIntegrationTest
, MediaSource_MP3_Icecast
) {
1042 MockMediaSource
source("icy_sfx.mp3", kMP3
, kAppendWholeFile
);
1043 StartPipelineWithMediaSource(&source
);
1044 source
.EndOfStream();
1048 EXPECT_TRUE(WaitUntilOnEnded());
1051 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_MP4
) {
1052 MockMediaSource
source("bear-640x360-av_frag.mp4", kMP4
, kAppendWholeFile
);
1053 StartPipelineWithMediaSource(&source
);
1055 scoped_refptr
<DecoderBuffer
> second_file
=
1056 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1058 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
1059 second_file
->data(), second_file
->data_size());
1061 source
.EndOfStream();
1063 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1064 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1065 EXPECT_EQ(kAppendTimeMs
+ k1280IsoFileDurationMs
,
1066 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1070 EXPECT_TRUE(WaitUntilOnEnded());
1075 TEST_F(PipelineIntegrationTest
,
1076 MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly
) {
1077 MockMediaSource
source("bear-640x360-v_frag-cenc.mp4", kMP4Video
,
1079 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1080 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1082 scoped_refptr
<DecoderBuffer
> second_file
=
1083 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1085 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
1086 second_file
->data(), second_file
->data_size());
1088 source
.EndOfStream();
1090 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1091 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1092 EXPECT_EQ(kAppendTimeMs
+ k1280IsoFileDurationMs
,
1093 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1097 EXPECT_TRUE(WaitUntilOnEnded());
1102 TEST_F(PipelineIntegrationTest
,
1103 MediaSource_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly
) {
1104 MockMediaSource
source("bear-640x360-v_frag-cenc-key_rotation.mp4", kMP4Video
,
1106 FakeEncryptedMedia
encrypted_media(new RotatingKeyProvidingApp());
1107 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1109 scoped_refptr
<DecoderBuffer
> second_file
=
1110 ReadTestDataFile("bear-1280x720-v_frag-cenc-key_rotation.mp4");
1112 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
1113 second_file
->data(), second_file
->data_size());
1115 source
.EndOfStream();
1117 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1118 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1119 EXPECT_EQ(kAppendTimeMs
+ k1280IsoFileDurationMs
,
1120 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1124 EXPECT_TRUE(WaitUntilOnEnded());
1129 // Config changes from clear to encrypted are not currently supported.
1130 // TODO(ddorwin): Figure out why this CHECKs in AppendAtTime().
1131 TEST_F(PipelineIntegrationTest
,
1132 DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC
) {
1133 MockMediaSource
source("bear-640x360-av_frag.mp4", kMP4Video
,
1135 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1136 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1138 scoped_refptr
<DecoderBuffer
> second_file
=
1139 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
1141 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
1142 second_file
->data(), second_file
->data_size());
1144 source
.EndOfStream();
1146 message_loop_
.Run();
1147 EXPECT_EQ(PIPELINE_ERROR_DECODE
, pipeline_status_
);
1149 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1150 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1151 // The second video was not added, so its time has not been added.
1152 EXPECT_EQ(k640IsoFileDurationMs
,
1153 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1157 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
1161 // Config changes from encrypted to clear are not currently supported.
1162 TEST_F(PipelineIntegrationTest
,
1163 MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC
) {
1164 MockMediaSource
source("bear-640x360-v_frag-cenc.mp4", kMP4Video
,
1166 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1167 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1169 scoped_refptr
<DecoderBuffer
> second_file
=
1170 ReadTestDataFile("bear-1280x720-av_frag.mp4");
1172 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
1173 second_file
->data(), second_file
->data_size());
1175 source
.EndOfStream();
1177 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1178 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1179 // The second video was not added, so its time has not been added.
1180 EXPECT_EQ(k640IsoCencFileDurationMs
,
1181 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1185 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
1189 // Verify files which change configuration midstream fail gracefully.
1190 TEST_F(PipelineIntegrationTest
, MidStreamConfigChangesFail
) {
1192 GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK
));
1194 ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE
);
1199 TEST_F(PipelineIntegrationTest
, BasicPlayback_16x9AspectRatio
) {
1200 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"),
1203 ASSERT_TRUE(WaitUntilOnEnded());
1206 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_WebM
) {
1207 MockMediaSource
source("bear-320x240-av_enc-av.webm", kWebM
, 219816);
1208 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1209 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1211 source
.EndOfStream();
1212 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1216 ASSERT_TRUE(WaitUntilOnEnded());
1221 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_ClearStart_WebM
) {
1222 MockMediaSource
source("bear-320x240-av_enc-av_clear-1s.webm", kWebM
,
1224 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1225 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1227 source
.EndOfStream();
1228 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1232 ASSERT_TRUE(WaitUntilOnEnded());
1237 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_NoEncryptedFrames_WebM
) {
1238 MockMediaSource
source("bear-320x240-av_enc-av_clear-all.webm", kWebM
,
1240 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
1241 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1243 source
.EndOfStream();
1244 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1248 ASSERT_TRUE(WaitUntilOnEnded());
1253 #if defined(USE_PROPRIETARY_CODECS)
1254 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_VideoOnly
) {
1255 MockMediaSource
source("bear-1280x720-v_frag-cenc.mp4", kMP4Video
,
1257 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1258 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1260 source
.EndOfStream();
1261 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1265 ASSERT_TRUE(WaitUntilOnEnded());
1270 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_AudioOnly
) {
1271 MockMediaSource
source("bear-1280x720-a_frag-cenc.mp4", kMP4Audio
,
1273 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
1274 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1276 source
.EndOfStream();
1277 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1281 ASSERT_TRUE(WaitUntilOnEnded());
1286 TEST_F(PipelineIntegrationTest
,
1287 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly
) {
1288 MockMediaSource
source("bear-1280x720-v_frag-cenc_clear-all.mp4", kMP4Video
,
1290 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
1291 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1293 source
.EndOfStream();
1294 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1298 ASSERT_TRUE(WaitUntilOnEnded());
1303 TEST_F(PipelineIntegrationTest
,
1304 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly
) {
1305 MockMediaSource
source("bear-1280x720-a_frag-cenc_clear-all.mp4", kMP4Audio
,
1307 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
1308 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1310 source
.EndOfStream();
1311 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1315 ASSERT_TRUE(WaitUntilOnEnded());
1320 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3
) {
1321 MockMediaSource
source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3
,
1323 StartPipelineWithMediaSource(&source
);
1324 source
.EndOfStream();
1326 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1327 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1328 EXPECT_EQ(k1280IsoAVC3FileDurationMs
,
1329 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1333 ASSERT_TRUE(WaitUntilOnEnded());
1338 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_KeyRotation_Video
) {
1339 MockMediaSource
source("bear-1280x720-v_frag-cenc-key_rotation.mp4",
1340 kMP4Video
, kAppendWholeFile
);
1341 FakeEncryptedMedia
encrypted_media(new RotatingKeyProvidingApp());
1342 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1344 source
.EndOfStream();
1345 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1349 ASSERT_TRUE(WaitUntilOnEnded());
1354 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_KeyRotation_Audio
) {
1355 MockMediaSource
source("bear-1280x720-a_frag-cenc-key_rotation.mp4",
1356 kMP4Audio
, kAppendWholeFile
);
1357 FakeEncryptedMedia
encrypted_media(new RotatingKeyProvidingApp());
1358 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
1360 source
.EndOfStream();
1361 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
1365 ASSERT_TRUE(WaitUntilOnEnded());
1371 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1372 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePaused
) {
1373 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
1375 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
1376 base::TimeDelta
start_seek_time(duration
/ 4);
1377 base::TimeDelta
seek_time(duration
* 3 / 4);
1380 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
1382 ASSERT_TRUE(Seek(seek_time
));
1383 EXPECT_EQ(pipeline_
->GetMediaTime(), seek_time
);
1385 ASSERT_TRUE(WaitUntilOnEnded());
1387 // Make sure seeking after reaching the end works as expected.
1389 ASSERT_TRUE(Seek(seek_time
));
1390 EXPECT_EQ(pipeline_
->GetMediaTime(), seek_time
);
1392 ASSERT_TRUE(WaitUntilOnEnded());
1395 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1396 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePlaying
) {
1397 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
1399 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
1400 base::TimeDelta
start_seek_time(duration
/ 4);
1401 base::TimeDelta
seek_time(duration
* 3 / 4);
1404 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
1405 ASSERT_TRUE(Seek(seek_time
));
1406 EXPECT_GE(pipeline_
->GetMediaTime(), seek_time
);
1407 ASSERT_TRUE(WaitUntilOnEnded());
1409 // Make sure seeking after reaching the end works as expected.
1410 ASSERT_TRUE(Seek(seek_time
));
1411 EXPECT_GE(pipeline_
->GetMediaTime(), seek_time
);
1412 ASSERT_TRUE(WaitUntilOnEnded());
1415 #if defined(USE_PROPRIETARY_CODECS)
1416 TEST_F(PipelineIntegrationTest
, Rotated_Metadata_0
) {
1417 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_0.mp4"), PIPELINE_OK
));
1418 ASSERT_EQ(VIDEO_ROTATION_0
, metadata_
.video_rotation
);
1421 TEST_F(PipelineIntegrationTest
, Rotated_Metadata_90
) {
1422 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_90.mp4"), PIPELINE_OK
));
1423 ASSERT_EQ(VIDEO_ROTATION_90
, metadata_
.video_rotation
);
1426 TEST_F(PipelineIntegrationTest
, Rotated_Metadata_180
) {
1427 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_180.mp4"), PIPELINE_OK
));
1428 ASSERT_EQ(VIDEO_ROTATION_180
, metadata_
.video_rotation
);
1431 TEST_F(PipelineIntegrationTest
, Rotated_Metadata_270
) {
1432 ASSERT_TRUE(Start(GetTestDataFilePath("bear_rotate_270.mp4"), PIPELINE_OK
));
1433 ASSERT_EQ(VIDEO_ROTATION_270
, metadata_
.video_rotation
);
1437 // Verify audio decoder & renderer can handle aborted demuxer reads.
1438 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_AudioOnly
) {
1439 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM
,
1441 base::TimeDelta::FromMilliseconds(464),
1442 base::TimeDelta::FromMilliseconds(617),
1446 // Verify video decoder & renderer can handle aborted demuxer reads.
1447 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_VideoOnly
) {
1448 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM
,
1450 base::TimeDelta::FromMilliseconds(167),
1451 base::TimeDelta::FromMilliseconds(1668),
1455 // Verify that Opus audio in WebM containers can be played back.
1456 TEST_F(PipelineIntegrationTest
, BasicPlayback_AudioOnly_Opus_WebM
) {
1457 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"),
1460 ASSERT_TRUE(WaitUntilOnEnded());
1463 // Verify that VP9 video in WebM containers can be played back.
1464 TEST_F(PipelineIntegrationTest
, BasicPlayback_VideoOnly_VP9_WebM
) {
1465 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"),
1468 ASSERT_TRUE(WaitUntilOnEnded());
1471 // Verify that VP9 video and Opus audio in the same WebM container can be played
1473 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP9_Opus_WebM
) {
1474 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"),
1477 ASSERT_TRUE(WaitUntilOnEnded());
1480 // Verify that VP8 video with alpha channel can be played back.
1481 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP8A_WebM
) {
1482 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"),
1485 ASSERT_TRUE(WaitUntilOnEnded());
1486 EXPECT_EQ(last_video_frame_format_
, VideoFrame::YV12A
);
1489 // Verify that VP8A video with odd width/height can be played back.
1490 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP8A_Odd_WebM
) {
1491 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"),
1494 ASSERT_TRUE(WaitUntilOnEnded());
1495 EXPECT_EQ(last_video_frame_format_
, VideoFrame::YV12A
);
1498 // Verify that VP9 video with odd width/height can be played back.
1499 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP9_Odd_WebM
) {
1500 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-odd-dimensions.webm"),
1503 ASSERT_TRUE(WaitUntilOnEnded());
1506 // Verify that VP8 video with inband text track can be played back.
1507 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP8_WebVTT_WebM
) {
1508 EXPECT_CALL(*this, OnAddTextTrack(_
, _
));
1509 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"),
1512 ASSERT_TRUE(WaitUntilOnEnded());
1515 // Verify that VP9 video with 4:4:4 subsampling can be played back.
1516 TEST_F(PipelineIntegrationTest
, P444_VP9_WebM
) {
1517 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-P444.webm"),
1520 ASSERT_TRUE(WaitUntilOnEnded());
1521 EXPECT_EQ(last_video_frame_format_
, VideoFrame::YV24
);
1524 // Verify that videos with an odd frame size playback successfully.
1525 TEST_F(PipelineIntegrationTest
, BasicPlayback_OddVideoSize
) {
1526 ASSERT_TRUE(Start(GetTestDataFilePath("butterfly-853x480.webm"),
1529 ASSERT_TRUE(WaitUntilOnEnded());
1532 // Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays
1533 // correctly at 48kHz
1534 TEST_F(PipelineIntegrationTest
, BasicPlayback_Opus441kHz
) {
1535 ASSERT_TRUE(Start(GetTestDataFilePath("sfx-opus-441.webm"), PIPELINE_OK
));
1537 ASSERT_TRUE(WaitUntilOnEnded());
1539 demuxer_
->GetStream(DemuxerStream::AUDIO
)
1540 ->audio_decoder_config()
1541 .samples_per_second());
1544 // Same as above but using MediaSource.
1545 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_Opus441kHz
) {
1546 MockMediaSource
source(
1547 "sfx-opus-441.webm", kOpusAudioOnlyWebM
, kAppendWholeFile
);
1548 StartPipelineWithMediaSource(&source
);
1549 source
.EndOfStream();
1551 ASSERT_TRUE(WaitUntilOnEnded());
1555 demuxer_
->GetStream(DemuxerStream::AUDIO
)
1556 ->audio_decoder_config()
1557 .samples_per_second());
1560 // Ensures audio-only playback with missing or negative timestamps works. Tests
1561 // the common live-streaming case for chained ogg. See http://crbug.com/396864.
1562 TEST_F(PipelineIntegrationTest
, BasicPlaybackChainedOgg
) {
1563 ASSERT_TRUE(Start(GetTestDataFilePath("double-sfx.ogg"), PIPELINE_OK
));
1565 ASSERT_TRUE(WaitUntilOnEnded());
1566 ASSERT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
1569 // Ensures audio-video playback with missing or negative timestamps fails softly
1570 // instead of crashing. See http://crbug.com/396864.
1571 TEST_F(PipelineIntegrationTest
, BasicPlaybackChainedOggVideo
) {
1572 ASSERT_TRUE(Start(GetTestDataFilePath("double-bear.ogv"), PIPELINE_OK
));
1574 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
1575 ASSERT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
1578 // Tests that we signal ended even when audio runs longer than video track.
1579 TEST_F(PipelineIntegrationTest
, BasicPlaybackAudioLongerThanVideo
) {
1580 ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_longer_than_video.ogv"),
1582 // Audio track is 2000ms. Video track is 1001ms. Duration should be higher
1584 EXPECT_EQ(2000, pipeline_
->GetMediaDuration().InMilliseconds());
1586 ASSERT_TRUE(WaitUntilOnEnded());
1589 // Tests that we signal ended even when audio runs shorter than video track.
1590 TEST_F(PipelineIntegrationTest
, BasicPlaybackAudioShorterThanVideo
) {
1591 ASSERT_TRUE(Start(GetTestDataFilePath("bear_audio_shorter_than_video.ogv"),
1593 // Audio track is 500ms. Video track is 1001ms. Duration should be higher of
1595 EXPECT_EQ(1001, pipeline_
->GetMediaDuration().InMilliseconds());
1597 ASSERT_TRUE(WaitUntilOnEnded());
1600 TEST_F(PipelineIntegrationTest
, BasicPlaybackPositiveStartTime
) {
1602 Start(GetTestDataFilePath("nonzero-start-time.webm"), PIPELINE_OK
));
1604 ASSERT_TRUE(WaitUntilOnEnded());
1605 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000),
1606 demuxer_
->GetStartTime());
1609 } // namespace media