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/decoder_buffer.h"
13 #include "media/base/media_keys.h"
14 #include "media/base/media_switches.h"
15 #include "media/base/test_data_util.h"
16 #include "media/cdm/aes_decryptor.h"
17 #include "media/cdm/json_web_key.h"
18 #include "media/filters/chunk_demuxer.h"
20 using testing::AnyNumber
;
21 using testing::AtMost
;
25 const char kSourceId
[] = "SourceId";
26 const uint8 kInitData
[] = { 0x69, 0x6e, 0x69, 0x74 };
28 const char kWebM
[] = "video/webm; codecs=\"vp8,vorbis\"";
29 const char kWebMVP9
[] = "video/webm; codecs=\"vp9\"";
30 const char kAudioOnlyWebM
[] = "video/webm; codecs=\"vorbis\"";
31 const char kOpusAudioOnlyWebM
[] = "video/webm; codecs=\"opus\"";
32 const char kVideoOnlyWebM
[] = "video/webm; codecs=\"vp8\"";
33 const char kMP4VideoType
[] = "video/mp4";
34 const char kMP4AudioType
[] = "audio/mp4";
35 #if defined(USE_PROPRIETARY_CODECS)
36 const char kMP4
[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\"";
37 const char kMP4Video
[] = "video/mp4; codecs=\"avc1.4D4041\"";
38 const char kMP4VideoAVC3
[] = "video/mp4; codecs=\"avc3.64001f\"";
39 const char kMP4Audio
[] = "audio/mp4; codecs=\"mp4a.40.2\"";
40 const char kMP3
[] = "audio/mpeg";
41 #endif // defined(USE_PROPRIETARY_CODECS)
43 // Key used to encrypt test files.
44 const uint8 kSecretKey
[] = {
45 0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
46 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
49 // The key ID for all encrypted files.
50 const uint8 kKeyId
[] = {
51 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
52 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35
55 const int kAppendWholeFile
= -1;
57 // Constants for the Media Source config change tests.
58 const int kAppendTimeSec
= 1;
59 const int kAppendTimeMs
= kAppendTimeSec
* 1000;
60 const int k320WebMFileDurationMs
= 2737;
61 const int k640WebMFileDurationMs
= 2763;
62 const int kOpusEndTrimmingWebMFileDurationMs
= 2771;
63 const int kVP9WebMFileDurationMs
= 2735;
64 const int kVP8AWebMFileDurationMs
= 2700;
66 #if defined(USE_PROPRIETARY_CODECS)
67 const int k640IsoFileDurationMs
= 2737;
68 const int k640IsoCencFileDurationMs
= 2736;
69 const int k1280IsoFileDurationMs
= 2736;
70 const int k1280IsoAVC3FileDurationMs
= 2735;
71 #endif // defined(USE_PROPRIETARY_CODECS)
73 // Note: Tests using this class only exercise the DecryptingDemuxerStream path.
74 // They do not exercise the Decrypting{Audio|Video}Decoder path.
75 class FakeEncryptedMedia
{
77 // Defines the behavior of the "app" that responds to EME events.
82 virtual void OnSessionCreated(uint32 session_id
,
83 const std::string
& web_session_id
) = 0;
85 virtual void OnSessionMessage(uint32 session_id
,
86 const std::vector
<uint8
>& message
,
87 const std::string
& destination_url
) = 0;
89 virtual void OnSessionReady(uint32 session_id
) = 0;
91 virtual void OnSessionClosed(uint32 session_id
) = 0;
93 // Errors are not expected unless overridden.
94 virtual void OnSessionError(uint32 session_id
,
95 MediaKeys::KeyError error_code
,
97 FAIL() << "Unexpected Key Error";
100 virtual void NeedKey(const std::string
& type
,
101 const std::vector
<uint8
>& init_data
,
102 AesDecryptor
* decryptor
) = 0;
105 FakeEncryptedMedia(AppBase
* app
)
106 : decryptor_(base::Bind(&FakeEncryptedMedia::OnSessionCreated
,
107 base::Unretained(this)),
108 base::Bind(&FakeEncryptedMedia::OnSessionMessage
,
109 base::Unretained(this)),
110 base::Bind(&FakeEncryptedMedia::OnSessionReady
,
111 base::Unretained(this)),
112 base::Bind(&FakeEncryptedMedia::OnSessionClosed
,
113 base::Unretained(this)),
114 base::Bind(&FakeEncryptedMedia::OnSessionError
,
115 base::Unretained(this))),
118 AesDecryptor
* decryptor() {
122 // Callbacks for firing session events. Delegate to |app_|.
123 void OnSessionCreated(uint32 session_id
, const std::string
& web_session_id
) {
124 app_
->OnSessionCreated(session_id
, web_session_id
);
127 void OnSessionMessage(uint32 session_id
,
128 const std::vector
<uint8
>& message
,
129 const std::string
& destination_url
) {
130 app_
->OnSessionMessage(session_id
, message
, destination_url
);
133 void OnSessionReady(uint32 session_id
) {
134 app_
->OnSessionReady(session_id
);
137 void OnSessionClosed(uint32 session_id
) {
138 app_
->OnSessionClosed(session_id
);
141 void OnSessionError(uint32 session_id
,
142 MediaKeys::KeyError error_code
,
143 uint32 system_code
) {
144 app_
->OnSessionError(session_id
, error_code
, system_code
);
147 void NeedKey(const std::string
& type
,
148 const std::vector
<uint8
>& init_data
) {
149 app_
->NeedKey(type
, init_data
, &decryptor_
);
153 AesDecryptor decryptor_
;
154 scoped_ptr
<AppBase
> app_
;
157 // Provides |kSecretKey| in response to needkey.
158 class KeyProvidingApp
: public FakeEncryptedMedia::AppBase
{
160 KeyProvidingApp() : current_session_id_(0) {}
162 virtual void OnSessionCreated(uint32 session_id
,
163 const std::string
& web_session_id
) OVERRIDE
{
164 EXPECT_GT(session_id
, 0u);
165 EXPECT_FALSE(web_session_id
.empty());
168 virtual void OnSessionMessage(uint32 session_id
,
169 const std::vector
<uint8
>& message
,
170 const std::string
& default_url
) OVERRIDE
{
171 EXPECT_GT(session_id
, 0u);
172 EXPECT_FALSE(message
.empty());
174 current_session_id_
= session_id
;
177 virtual void OnSessionReady(uint32 session_id
) OVERRIDE
{
178 EXPECT_GT(session_id
, 0u);
181 virtual void OnSessionClosed(uint32 session_id
) OVERRIDE
{
182 EXPECT_GT(session_id
, 0u);
185 virtual void NeedKey(const std::string
& type
,
186 const std::vector
<uint8
>& init_data
,
187 AesDecryptor
* decryptor
) OVERRIDE
{
188 if (current_session_id_
== 0u) {
190 decryptor
->CreateSession(12, type
, kInitData
, arraysize(kInitData
)));
193 EXPECT_EQ(current_session_id_
, 12u);
195 // Clear Key really needs the key ID in |init_data|. For WebM, they are the
196 // same, but this is not the case for ISO CENC. Therefore, provide the
198 const uint8
* key_id
= init_data
.empty() ? NULL
: &init_data
[0];
199 size_t key_id_length
= init_data
.size();
200 if (type
== kMP4AudioType
|| type
== kMP4VideoType
) {
202 key_id_length
= arraysize(kKeyId
);
205 // Convert key into a JSON structure and then add it.
206 std::string jwk
= GenerateJWKSet(
207 kSecretKey
, arraysize(kSecretKey
), key_id
, key_id_length
);
208 decryptor
->UpdateSession(current_session_id_
,
209 reinterpret_cast<const uint8
*>(jwk
.data()),
213 uint32 current_session_id_
;
216 // Ignores needkey and does not perform a license request
217 class NoResponseApp
: public FakeEncryptedMedia::AppBase
{
219 virtual void OnSessionCreated(uint32 session_id
,
220 const std::string
& web_session_id
) OVERRIDE
{
221 EXPECT_GT(session_id
, 0u);
222 EXPECT_FALSE(web_session_id
.empty());
225 virtual void OnSessionMessage(uint32 session_id
,
226 const std::vector
<uint8
>& message
,
227 const std::string
& default_url
) OVERRIDE
{
228 EXPECT_GT(session_id
, 0u);
229 EXPECT_FALSE(message
.empty());
230 FAIL() << "Unexpected KeyMessage";
233 virtual void OnSessionReady(uint32 session_id
) OVERRIDE
{
234 EXPECT_GT(session_id
, 0u);
235 FAIL() << "Unexpected Ready";
238 virtual void OnSessionClosed(uint32 session_id
) OVERRIDE
{
239 EXPECT_GT(session_id
, 0u);
240 FAIL() << "Unexpected Closed";
243 virtual void NeedKey(const std::string
& type
,
244 const std::vector
<uint8
>& init_data
,
245 AesDecryptor
* decryptor
) OVERRIDE
{
249 // Helper class that emulates calls made on the ChunkDemuxer by the
251 class MockMediaSource
{
253 MockMediaSource(const std::string
& filename
, const std::string
& mimetype
,
254 int initial_append_size
)
255 : file_path_(GetTestDataFilePath(filename
)),
256 current_position_(0),
257 initial_append_size_(initial_append_size
),
259 chunk_demuxer_(new ChunkDemuxer(
260 base::Bind(&MockMediaSource::DemuxerOpened
,
261 base::Unretained(this)),
262 base::Bind(&MockMediaSource::DemuxerNeedKey
,
263 base::Unretained(this)),
265 owned_chunk_demuxer_(chunk_demuxer_
) {
267 file_data_
= ReadTestDataFile(filename
);
269 if (initial_append_size_
== kAppendWholeFile
)
270 initial_append_size_
= file_data_
->data_size();
272 DCHECK_GT(initial_append_size_
, 0);
273 DCHECK_LE(initial_append_size_
, file_data_
->data_size());
276 virtual ~MockMediaSource() {}
278 scoped_ptr
<Demuxer
> GetDemuxer() { return owned_chunk_demuxer_
.Pass(); }
280 void set_need_key_cb(const Demuxer::NeedKeyCB
& need_key_cb
) {
281 need_key_cb_
= need_key_cb
;
284 void Seek(base::TimeDelta seek_time
, int new_position
, int seek_append_size
) {
285 chunk_demuxer_
->StartWaitingForSeek(seek_time
);
287 chunk_demuxer_
->Abort(kSourceId
);
289 DCHECK_GE(new_position
, 0);
290 DCHECK_LT(new_position
, file_data_
->data_size());
291 current_position_
= new_position
;
293 AppendData(seek_append_size
);
296 void AppendData(int size
) {
297 DCHECK(chunk_demuxer_
);
298 DCHECK_LT(current_position_
, file_data_
->data_size());
299 DCHECK_LE(current_position_
+ size
, file_data_
->data_size());
301 // TODO(wolenetz): Test timestamp offset updating once "sequence" append
302 // mode processing is implemented. See http://crbug.com/249422.
303 chunk_demuxer_
->AppendData(
304 kSourceId
, file_data_
->data() + current_position_
, size
, NULL
);
305 current_position_
+= size
;
308 void AppendAtTime(const base::TimeDelta
& timestampOffset
,
309 const uint8
* pData
, int size
) {
310 CHECK(chunk_demuxer_
->SetTimestampOffset(kSourceId
, timestampOffset
));
311 chunk_demuxer_
->AppendData(kSourceId
, pData
, size
, NULL
);
312 CHECK(chunk_demuxer_
->SetTimestampOffset(kSourceId
, base::TimeDelta()));
316 chunk_demuxer_
->MarkEndOfStream(PIPELINE_OK
);
322 chunk_demuxer_
->Shutdown();
323 chunk_demuxer_
= NULL
;
326 void DemuxerOpened() {
327 base::MessageLoop::current()->PostTask(
328 FROM_HERE
, base::Bind(&MockMediaSource::DemuxerOpenedTask
,
329 base::Unretained(this)));
332 void DemuxerOpenedTask() {
333 // This code assumes that |mimetype_| is one of the following forms.
335 // 2. video/webm;codec="vorbis,vp8".
336 size_t semicolon
= mimetype_
.find(";");
337 std::string type
= mimetype_
;
338 std::vector
<std::string
> codecs
;
339 if (semicolon
!= std::string::npos
) {
340 type
= mimetype_
.substr(0, semicolon
);
341 size_t codecs_param_start
= mimetype_
.find("codecs=\"", semicolon
);
343 CHECK_NE(codecs_param_start
, std::string::npos
);
345 codecs_param_start
+= 8; // Skip over the codecs=".
347 size_t codecs_param_end
= mimetype_
.find("\"", codecs_param_start
);
349 CHECK_NE(codecs_param_end
, std::string::npos
);
351 std::string codecs_param
=
352 mimetype_
.substr(codecs_param_start
,
353 codecs_param_end
- codecs_param_start
);
354 Tokenize(codecs_param
, ",", &codecs
);
357 CHECK_EQ(chunk_demuxer_
->AddId(kSourceId
, type
, codecs
), ChunkDemuxer::kOk
);
358 AppendData(initial_append_size_
);
361 void DemuxerNeedKey(const std::string
& type
,
362 const std::vector
<uint8
>& init_data
) {
363 DCHECK(!init_data
.empty());
364 CHECK(!need_key_cb_
.is_null());
365 need_key_cb_
.Run(type
, init_data
);
369 base::FilePath file_path_
;
370 scoped_refptr
<DecoderBuffer
> file_data_
;
371 int current_position_
;
372 int initial_append_size_
;
373 std::string mimetype_
;
374 ChunkDemuxer
* chunk_demuxer_
;
375 scoped_ptr
<Demuxer
> owned_chunk_demuxer_
;
376 Demuxer::NeedKeyCB need_key_cb_
;
379 class PipelineIntegrationTest
380 : public testing::Test
,
381 public PipelineIntegrationTestBase
{
383 void StartPipelineWithMediaSource(MockMediaSource
* source
) {
384 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata
))
386 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted
))
389 CreateFilterCollection(source
->GetDemuxer(), NULL
),
390 base::Bind(&PipelineIntegrationTest::OnEnded
, base::Unretained(this)),
391 base::Bind(&PipelineIntegrationTest::OnError
, base::Unretained(this)),
392 QuitOnStatusCB(PIPELINE_OK
),
393 base::Bind(&PipelineIntegrationTest::OnBufferingState
,
394 base::Unretained(this)),
400 void StartHashedPipelineWithMediaSource(MockMediaSource
* source
) {
401 hashing_enabled_
= true;
402 StartPipelineWithMediaSource(source
);
405 void StartPipelineWithEncryptedMedia(
406 MockMediaSource
* source
,
407 FakeEncryptedMedia
* encrypted_media
) {
408 EXPECT_CALL(*this, OnBufferingState(Pipeline::kHaveMetadata
))
410 EXPECT_CALL(*this, OnBufferingState(Pipeline::kPrerollCompleted
))
413 CreateFilterCollection(source
->GetDemuxer(),
414 encrypted_media
->decryptor()),
415 base::Bind(&PipelineIntegrationTest::OnEnded
, base::Unretained(this)),
416 base::Bind(&PipelineIntegrationTest::OnError
, base::Unretained(this)),
417 QuitOnStatusCB(PIPELINE_OK
),
418 base::Bind(&PipelineIntegrationTest::OnBufferingState
,
419 base::Unretained(this)),
422 source
->set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey
,
423 base::Unretained(encrypted_media
)));
428 // Verifies that seeking works properly for ChunkDemuxer when the
429 // seek happens while there is a pending read on the ChunkDemuxer
430 // and no data is available.
431 bool TestSeekDuringRead(const std::string
& filename
,
432 const std::string
& mimetype
,
433 int initial_append_size
,
434 base::TimeDelta start_seek_time
,
435 base::TimeDelta seek_time
,
436 int seek_file_position
,
437 int seek_append_size
) {
438 MockMediaSource
source(filename
, mimetype
, initial_append_size
);
439 StartPipelineWithMediaSource(&source
);
441 if (pipeline_status_
!= PIPELINE_OK
)
445 if (!WaitUntilCurrentTimeIsAfter(start_seek_time
))
448 source
.Seek(seek_time
, seek_file_position
, seek_append_size
);
449 if (!Seek(seek_time
))
452 source
.EndOfStream();
460 TEST_F(PipelineIntegrationTest
, BasicPlayback
) {
461 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
465 ASSERT_TRUE(WaitUntilOnEnded());
468 TEST_F(PipelineIntegrationTest
, BasicPlaybackHashed
) {
470 GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
, kHashed
));
474 ASSERT_TRUE(WaitUntilOnEnded());
476 EXPECT_EQ("f0be120a90a811506777c99a2cdf7cc1", GetVideoHash());
477 EXPECT_EQ("-3.59,-2.06,-0.43,2.15,0.77,-0.95,", GetAudioHash());
480 TEST_F(PipelineIntegrationTest
, F32PlaybackHashed
) {
482 Start(GetTestDataFilePath("sfx_f32le.wav"), PIPELINE_OK
, kHashed
));
484 ASSERT_TRUE(WaitUntilOnEnded());
485 EXPECT_EQ(std::string(kNullVideoHash
), GetVideoHash());
486 EXPECT_EQ("3.03,2.86,2.99,3.31,3.57,4.06,", GetAudioHash());
489 TEST_F(PipelineIntegrationTest
, BasicPlaybackEncrypted
) {
490 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
491 set_need_key_cb(base::Bind(&FakeEncryptedMedia::NeedKey
,
492 base::Unretained(&encrypted_media
)));
494 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-av_enc-av.webm"),
495 encrypted_media
.decryptor()));
499 ASSERT_TRUE(WaitUntilOnEnded());
503 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource
) {
504 MockMediaSource
source("bear-320x240.webm", kWebM
, 219229);
505 StartPipelineWithMediaSource(&source
);
506 source
.EndOfStream();
508 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
509 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
510 EXPECT_EQ(k320WebMFileDurationMs
,
511 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
515 ASSERT_TRUE(WaitUntilOnEnded());
520 // TODO(fgalligan): Enable after new vp9 files are landed.
521 // http://crbug.com/259116
522 TEST_F(PipelineIntegrationTest
,
523 DISABLED_BasicPlayback_MediaSource_VideoOnly_VP9_WebM
) {
524 MockMediaSource
source("bear-vp9.webm", kWebMVP9
, 32393);
525 StartPipelineWithMediaSource(&source
);
526 source
.EndOfStream();
528 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
529 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
530 EXPECT_EQ(kVP9WebMFileDurationMs
,
531 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
535 ASSERT_TRUE(WaitUntilOnEnded());
540 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_VP8A_WebM
) {
541 EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber());
542 MockMediaSource
source("bear-vp8a.webm", kVideoOnlyWebM
, kAppendWholeFile
);
543 StartPipelineWithMediaSource(&source
);
544 source
.EndOfStream();
546 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
547 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
548 EXPECT_EQ(kVP8AWebMFileDurationMs
,
549 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
553 ASSERT_TRUE(WaitUntilOnEnded());
558 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_Opus_WebM
) {
559 EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber());
560 MockMediaSource
source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM
,
562 StartPipelineWithMediaSource(&source
);
563 source
.EndOfStream();
565 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
566 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
567 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs
,
568 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
571 ASSERT_TRUE(WaitUntilOnEnded());
576 // Flaky. http://crbug.com/304776
577 TEST_F(PipelineIntegrationTest
, DISABLED_MediaSource_Opus_Seeking_WebM
) {
578 EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber());
579 MockMediaSource
source("bear-opus-end-trimming.webm", kOpusAudioOnlyWebM
,
581 StartHashedPipelineWithMediaSource(&source
);
584 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
585 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
586 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs
,
587 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
589 base::TimeDelta start_seek_time
= base::TimeDelta::FromMilliseconds(1000);
590 base::TimeDelta seek_time
= base::TimeDelta::FromMilliseconds(2000);
593 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
594 source
.Seek(seek_time
, 0x1D5, 34017);
595 source
.EndOfStream();
596 ASSERT_TRUE(Seek(seek_time
));
598 ASSERT_TRUE(WaitUntilOnEnded());
600 EXPECT_EQ("0.76,0.20,-0.82,-0.58,-1.29,-0.29,", GetAudioHash());
606 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_WebM
) {
607 MockMediaSource
source("bear-320x240-16x9-aspect.webm", kWebM
,
609 StartPipelineWithMediaSource(&source
);
611 scoped_refptr
<DecoderBuffer
> second_file
=
612 ReadTestDataFile("bear-640x360.webm");
614 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
615 second_file
->data(), second_file
->data_size());
617 source
.EndOfStream();
619 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
620 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
621 EXPECT_EQ(kAppendTimeMs
+ k640WebMFileDurationMs
,
622 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
626 EXPECT_TRUE(WaitUntilOnEnded());
631 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_Encrypted_WebM
) {
632 MockMediaSource
source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM
,
634 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
635 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
637 scoped_refptr
<DecoderBuffer
> second_file
=
638 ReadTestDataFile("bear-640x360-av_enc-av.webm");
640 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
641 second_file
->data(), second_file
->data_size());
643 source
.EndOfStream();
645 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
646 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
647 EXPECT_EQ(kAppendTimeMs
+ k640WebMFileDurationMs
,
648 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
652 EXPECT_TRUE(WaitUntilOnEnded());
657 // Config changes from encrypted to clear are not currently supported.
658 TEST_F(PipelineIntegrationTest
,
659 MediaSource_ConfigChange_ClearThenEncrypted_WebM
) {
660 MockMediaSource
source("bear-320x240-16x9-aspect.webm", kWebM
,
662 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
663 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
665 scoped_refptr
<DecoderBuffer
> second_file
=
666 ReadTestDataFile("bear-640x360-av_enc-av.webm");
668 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
669 second_file
->data(), second_file
->data_size());
671 source
.EndOfStream();
674 EXPECT_EQ(PIPELINE_ERROR_DECODE
, pipeline_status_
);
676 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
677 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
678 // The second video was not added, so its time has not been added.
679 EXPECT_EQ(k320WebMFileDurationMs
,
680 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
684 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
688 // Config changes from clear to encrypted are not currently supported.
689 TEST_F(PipelineIntegrationTest
,
690 MediaSource_ConfigChange_EncryptedThenClear_WebM
) {
691 MockMediaSource
source("bear-320x240-16x9-aspect-av_enc-av.webm", kWebM
,
693 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
694 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
696 scoped_refptr
<DecoderBuffer
> second_file
=
697 ReadTestDataFile("bear-640x360.webm");
699 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
700 second_file
->data(), second_file
->data_size());
702 source
.EndOfStream();
704 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
705 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
706 // The second video was not added, so its time has not been added.
707 EXPECT_EQ(k320WebMFileDurationMs
,
708 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
712 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
716 #if defined(USE_PROPRIETARY_CODECS)
717 TEST_F(PipelineIntegrationTest
, MediaSource_MP3
) {
718 MockMediaSource
source("sfx.mp3", kMP3
, kAppendWholeFile
);
719 StartPipelineWithMediaSource(&source
);
720 source
.EndOfStream();
724 EXPECT_TRUE(WaitUntilOnEnded());
728 TEST_F(PipelineIntegrationTest
, MediaSource_MP3_Icecast
) {
729 MockMediaSource
source("icy_sfx.mp3", kMP3
, kAppendWholeFile
);
730 StartPipelineWithMediaSource(&source
);
731 source
.EndOfStream();
735 EXPECT_TRUE(WaitUntilOnEnded());
738 TEST_F(PipelineIntegrationTest
, MediaSource_ConfigChange_MP4
) {
739 MockMediaSource
source("bear-640x360-av_frag.mp4", kMP4
, kAppendWholeFile
);
740 StartPipelineWithMediaSource(&source
);
742 scoped_refptr
<DecoderBuffer
> second_file
=
743 ReadTestDataFile("bear-1280x720-av_frag.mp4");
745 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
746 second_file
->data(), second_file
->data_size());
748 source
.EndOfStream();
750 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
751 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
752 EXPECT_EQ(kAppendTimeMs
+ k1280IsoFileDurationMs
,
753 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
757 EXPECT_TRUE(WaitUntilOnEnded());
762 TEST_F(PipelineIntegrationTest
,
763 MediaSource_ConfigChange_Encrypted_MP4_CENC_VideoOnly
) {
764 MockMediaSource
source("bear-640x360-v_frag-cenc.mp4",
765 kMP4Video
, kAppendWholeFile
);
766 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
767 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
769 scoped_refptr
<DecoderBuffer
> second_file
=
770 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
772 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
773 second_file
->data(), second_file
->data_size());
775 source
.EndOfStream();
777 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
778 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
779 EXPECT_EQ(kAppendTimeMs
+ k1280IsoFileDurationMs
,
780 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
784 EXPECT_TRUE(WaitUntilOnEnded());
789 // Config changes from clear to encrypted are not currently supported.
790 // TODO(ddorwin): Figure out why this CHECKs in AppendAtTime().
791 TEST_F(PipelineIntegrationTest
,
792 DISABLED_MediaSource_ConfigChange_ClearThenEncrypted_MP4_CENC
) {
793 MockMediaSource
source("bear-640x360-av_frag.mp4", kMP4Video
,
795 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
796 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
798 scoped_refptr
<DecoderBuffer
> second_file
=
799 ReadTestDataFile("bear-1280x720-v_frag-cenc.mp4");
801 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
802 second_file
->data(), second_file
->data_size());
804 source
.EndOfStream();
807 EXPECT_EQ(PIPELINE_ERROR_DECODE
, pipeline_status_
);
809 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
810 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
811 // The second video was not added, so its time has not been added.
812 EXPECT_EQ(k640IsoFileDurationMs
,
813 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
817 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
821 // Config changes from encrypted to clear are not currently supported.
822 TEST_F(PipelineIntegrationTest
,
823 MediaSource_ConfigChange_EncryptedThenClear_MP4_CENC
) {
824 MockMediaSource
source("bear-640x360-v_frag-cenc.mp4",
825 kMP4Video
, kAppendWholeFile
);
826 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
827 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
829 scoped_refptr
<DecoderBuffer
> second_file
=
830 ReadTestDataFile("bear-1280x720-av_frag.mp4");
832 source
.AppendAtTime(base::TimeDelta::FromSeconds(kAppendTimeSec
),
833 second_file
->data(), second_file
->data_size());
835 source
.EndOfStream();
837 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
838 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
839 // The second video was not added, so its time has not been added.
840 EXPECT_EQ(k640IsoCencFileDurationMs
,
841 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
845 EXPECT_EQ(PIPELINE_ERROR_DECODE
, WaitUntilEndedOrError());
849 // Verify files which change configuration midstream fail gracefully.
850 TEST_F(PipelineIntegrationTest
, MidStreamConfigChangesFail
) {
852 GetTestDataFilePath("midstream_config_change.mp3"), PIPELINE_OK
));
854 ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE
);
859 TEST_F(PipelineIntegrationTest
, BasicPlayback_16x9AspectRatio
) {
860 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240-16x9-aspect.webm"),
863 ASSERT_TRUE(WaitUntilOnEnded());
866 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_WebM
) {
867 MockMediaSource
source("bear-320x240-av_enc-av.webm", kWebM
, 219816);
868 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
869 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
871 source
.EndOfStream();
872 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
876 ASSERT_TRUE(WaitUntilOnEnded());
881 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_ClearStart_WebM
) {
882 MockMediaSource
source("bear-320x240-av_enc-av_clear-1s.webm",
883 kWebM
, kAppendWholeFile
);
884 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
885 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
887 source
.EndOfStream();
888 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
892 ASSERT_TRUE(WaitUntilOnEnded());
897 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_NoEncryptedFrames_WebM
) {
898 MockMediaSource
source("bear-320x240-av_enc-av_clear-all.webm",
899 kWebM
, kAppendWholeFile
);
900 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
901 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
903 source
.EndOfStream();
904 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
908 ASSERT_TRUE(WaitUntilOnEnded());
913 #if defined(USE_PROPRIETARY_CODECS)
914 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_VideoOnly
) {
915 MockMediaSource
source("bear-1280x720-v_frag-cenc.mp4",
916 kMP4Video
, kAppendWholeFile
);
917 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
918 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
920 source
.EndOfStream();
921 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
925 ASSERT_TRUE(WaitUntilOnEnded());
930 TEST_F(PipelineIntegrationTest
, EncryptedPlayback_MP4_CENC_AudioOnly
) {
931 MockMediaSource
source("bear-1280x720-a_frag-cenc.mp4",
932 kMP4Audio
, kAppendWholeFile
);
933 FakeEncryptedMedia
encrypted_media(new KeyProvidingApp());
934 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
936 source
.EndOfStream();
937 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
941 ASSERT_TRUE(WaitUntilOnEnded());
946 TEST_F(PipelineIntegrationTest
,
947 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly
) {
948 MockMediaSource
source("bear-1280x720-v_frag-cenc_clear-all.mp4",
949 kMP4Video
, kAppendWholeFile
);
950 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
951 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
953 source
.EndOfStream();
954 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
958 ASSERT_TRUE(WaitUntilOnEnded());
963 TEST_F(PipelineIntegrationTest
,
964 EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly
) {
965 MockMediaSource
source("bear-1280x720-a_frag-cenc_clear-all.mp4",
966 kMP4Audio
, kAppendWholeFile
);
967 FakeEncryptedMedia
encrypted_media(new NoResponseApp());
968 StartPipelineWithEncryptedMedia(&source
, &encrypted_media
);
970 source
.EndOfStream();
971 ASSERT_EQ(PIPELINE_OK
, pipeline_status_
);
975 ASSERT_TRUE(WaitUntilOnEnded());
980 TEST_F(PipelineIntegrationTest
, BasicPlayback_MediaSource_VideoOnly_MP4_AVC3
) {
981 MockMediaSource
source("bear-1280x720-v_frag-avc3.mp4", kMP4VideoAVC3
,
983 StartPipelineWithMediaSource(&source
);
984 source
.EndOfStream();
986 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
987 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
988 EXPECT_EQ(k1280IsoAVC3FileDurationMs
,
989 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
993 ASSERT_TRUE(WaitUntilOnEnded());
1000 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1001 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePaused
) {
1002 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
1004 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
1005 base::TimeDelta
start_seek_time(duration
/ 4);
1006 base::TimeDelta
seek_time(duration
* 3 / 4);
1009 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
1011 ASSERT_TRUE(Seek(seek_time
));
1012 EXPECT_EQ(pipeline_
->GetMediaTime(), seek_time
);
1014 ASSERT_TRUE(WaitUntilOnEnded());
1016 // Make sure seeking after reaching the end works as expected.
1018 ASSERT_TRUE(Seek(seek_time
));
1019 EXPECT_EQ(pipeline_
->GetMediaTime(), seek_time
);
1021 ASSERT_TRUE(WaitUntilOnEnded());
1024 // TODO(acolwell): Fix flakiness http://crbug.com/117921
1025 TEST_F(PipelineIntegrationTest
, DISABLED_SeekWhilePlaying
) {
1026 ASSERT_TRUE(Start(GetTestDataFilePath("bear-320x240.webm"), PIPELINE_OK
));
1028 base::TimeDelta
duration(pipeline_
->GetMediaDuration());
1029 base::TimeDelta
start_seek_time(duration
/ 4);
1030 base::TimeDelta
seek_time(duration
* 3 / 4);
1033 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time
));
1034 ASSERT_TRUE(Seek(seek_time
));
1035 EXPECT_GE(pipeline_
->GetMediaTime(), seek_time
);
1036 ASSERT_TRUE(WaitUntilOnEnded());
1038 // Make sure seeking after reaching the end works as expected.
1039 ASSERT_TRUE(Seek(seek_time
));
1040 EXPECT_GE(pipeline_
->GetMediaTime(), seek_time
);
1041 ASSERT_TRUE(WaitUntilOnEnded());
1044 // Verify audio decoder & renderer can handle aborted demuxer reads.
1045 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_AudioOnly
) {
1046 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", kAudioOnlyWebM
,
1048 base::TimeDelta::FromMilliseconds(464),
1049 base::TimeDelta::FromMilliseconds(617),
1053 // Verify video decoder & renderer can handle aborted demuxer reads.
1054 TEST_F(PipelineIntegrationTest
, ChunkDemuxerAbortRead_VideoOnly
) {
1055 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", kVideoOnlyWebM
,
1057 base::TimeDelta::FromMilliseconds(200),
1058 base::TimeDelta::FromMilliseconds(1668),
1062 // Verify that Opus audio in WebM containers can be played back.
1063 TEST_F(PipelineIntegrationTest
, BasicPlayback_AudioOnly_Opus_WebM
) {
1064 ASSERT_TRUE(Start(GetTestDataFilePath("bear-opus-end-trimming.webm"),
1066 EXPECT_EQ(1u, pipeline_
->GetBufferedTimeRanges().size());
1067 EXPECT_EQ(0, pipeline_
->GetBufferedTimeRanges().start(0).InMilliseconds());
1068 EXPECT_EQ(kOpusEndTrimmingWebMFileDurationMs
,
1069 pipeline_
->GetBufferedTimeRanges().end(0).InMilliseconds());
1071 ASSERT_TRUE(WaitUntilOnEnded());
1074 // Verify that VP9 video in WebM containers can be played back.
1075 // TODO(fgalligan): Enable after new vp9 files are landed.
1076 // http://crbug.com/259116
1077 TEST_F(PipelineIntegrationTest
, DISABLED_BasicPlayback_VideoOnly_VP9_WebM
) {
1078 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9.webm"),
1081 ASSERT_TRUE(WaitUntilOnEnded());
1084 // Verify that VP9 video and Opus audio in the same WebM container can be played
1086 // TODO(fgalligan): Enable after new vp9 files are landed.
1087 // http://crbug.com/259116
1088 TEST_F(PipelineIntegrationTest
, DISABLED_BasicPlayback_VP9_Opus_WebM
) {
1089 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp9-opus.webm"),
1092 ASSERT_TRUE(WaitUntilOnEnded());
1095 // Verify that VP8 video with alpha channel can be played back.
1096 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP8A_WebM
) {
1097 EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber());
1098 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a.webm"),
1101 ASSERT_TRUE(WaitUntilOnEnded());
1102 EXPECT_EQ(last_video_frame_format_
, VideoFrame::YV12A
);
1105 // Verify that VP8A video with odd width/height can be played back.
1106 TEST_F(PipelineIntegrationTest
, BasicPlayback_VP8A_Odd_WebM
) {
1107 EXPECT_CALL(*this, OnSetOpaque(false)).Times(AnyNumber());
1108 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8a-odd-dimensions.webm"),
1111 ASSERT_TRUE(WaitUntilOnEnded());
1112 EXPECT_EQ(last_video_frame_format_
, VideoFrame::YV12A
);
1115 // Verify that VP8 video with inband text track can be played back.
1116 TEST_F(PipelineIntegrationTest
,
1117 BasicPlayback_VP8_WebVTT_WebM
) {
1118 ASSERT_TRUE(Start(GetTestDataFilePath("bear-vp8-webvtt.webm"),
1121 ASSERT_TRUE(WaitUntilOnEnded());
1124 } // namespace media