OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stddef.h> | 5 #include <stddef.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
16 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
17 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
18 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
19 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
21 #include "media/base/cdm_callback_promise.h" | 21 #include "media/base/cdm_callback_promise.h" |
22 #include "media/base/cdm_context.h" | |
23 #include "media/base/cdm_key_information.h" | 22 #include "media/base/cdm_key_information.h" |
24 #include "media/base/content_decryption_module.h" | |
25 #include "media/base/decoder_buffer.h" | 23 #include "media/base/decoder_buffer.h" |
26 #include "media/base/media.h" | 24 #include "media/base/media.h" |
27 #include "media/base/media_switches.h" | 25 #include "media/base/media_switches.h" |
28 #include "media/base/media_tracks.h" | 26 #include "media/base/media_tracks.h" |
29 #include "media/base/test_data_util.h" | 27 #include "media/base/test_data_util.h" |
30 #include "media/base/timestamp_constants.h" | 28 #include "media/base/timestamp_constants.h" |
31 #include "media/cdm/aes_decryptor.h" | 29 #include "media/cdm/aes_decryptor.h" |
32 #include "media/cdm/json_web_key.h" | 30 #include "media/cdm/json_web_key.h" |
33 #include "media/filters/chunk_demuxer.h" | |
34 #include "media/media_features.h" | 31 #include "media/media_features.h" |
35 #include "media/renderers/renderer_impl.h" | 32 #include "media/renderers/renderer_impl.h" |
| 33 #include "media/test/fake_encrypted_media.h" |
| 34 #include "media/test/mock_media_source.h" |
36 #include "media/test/pipeline_integration_test_base.h" | 35 #include "media/test/pipeline_integration_test_base.h" |
37 #include "testing/gmock/include/gmock/gmock.h" | 36 #include "testing/gmock/include/gmock/gmock.h" |
38 #include "url/gurl.h" | 37 #include "url/gurl.h" |
39 | 38 |
40 #if defined(MOJO_RENDERER) | 39 #if defined(MOJO_RENDERER) |
41 #include "media/mojo/clients/mojo_renderer.h" | 40 #include "media/mojo/clients/mojo_renderer.h" |
42 #include "media/mojo/interfaces/interface_factory.mojom.h" | 41 #include "media/mojo/interfaces/interface_factory.mojom.h" |
43 #include "media/mojo/interfaces/renderer.mojom.h" | 42 #include "media/mojo/interfaces/renderer.mojom.h" |
44 #include "services/service_manager/public/cpp/connect.h" | 43 #include "services/service_manager/public/cpp/connect.h" |
45 #include "services/service_manager/public/cpp/service_test.h" | 44 #include "services/service_manager/public/cpp/service_test.h" |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 #endif | 86 #endif |
88 | 87 |
89 using testing::_; | 88 using testing::_; |
90 using testing::AnyNumber; | 89 using testing::AnyNumber; |
91 using testing::AtLeast; | 90 using testing::AtLeast; |
92 using testing::AtMost; | 91 using testing::AtMost; |
93 using testing::SaveArg; | 92 using testing::SaveArg; |
94 | 93 |
95 namespace media { | 94 namespace media { |
96 | 95 |
97 const char kSourceId[] = "SourceId"; | |
98 | |
99 const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; | 96 const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\""; |
100 const char kWebMVP9[] = "video/webm; codecs=\"vp9\""; | 97 const char kWebMVP9[] = "video/webm; codecs=\"vp9\""; |
101 const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; | 98 const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\""; |
102 const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\""; | 99 const char kOpusAudioOnlyWebM[] = "video/webm; codecs=\"opus\""; |
103 const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; | 100 const char kVideoOnlyWebM[] = "video/webm; codecs=\"vp8\""; |
104 #if BUILDFLAG(USE_PROPRIETARY_CODECS) | 101 #if BUILDFLAG(USE_PROPRIETARY_CODECS) |
105 const char kADTS[] = "audio/aac"; | 102 const char kADTS[] = "audio/aac"; |
106 const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; | 103 const char kMP4[] = "video/mp4; codecs=\"avc1.4D4041,mp4a.40.2\""; |
107 const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\""; | 104 const char kMP4VideoAVC3[] = "video/mp4; codecs=\"avc3.64001f\""; |
108 const char kMP4VideoVP9[] = "video/mp4; codecs=\"vp09.00.10.08.01.05.01\""; | 105 const char kMP4VideoVP9[] = "video/mp4; codecs=\"vp09.00.10.08.01.05.01\""; |
109 const char kMP4VideoHEVC1[] = "video/mp4; codecs=\"hvc1.1.6.L93.B0\""; | 106 const char kMP4VideoHEVC1[] = "video/mp4; codecs=\"hvc1.1.6.L93.B0\""; |
110 const char kMP4VideoHEVC2[] = "video/mp4; codecs=\"hev1.1.6.L93.B0\""; | 107 const char kMP4VideoHEVC2[] = "video/mp4; codecs=\"hev1.1.6.L93.B0\""; |
111 const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; | 108 const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\""; |
112 const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\""; | 109 const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\""; |
113 const char kMP3[] = "audio/mpeg"; | 110 const char kMP3[] = "audio/mpeg"; |
114 const char kMP2AudioSBR[] = "video/mp2t; codecs=\"avc1.4D4041,mp4a.40.5\""; | 111 const char kMP2AudioSBR[] = "video/mp2t; codecs=\"avc1.4D4041,mp4a.40.5\""; |
115 #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) | 112 #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) |
116 | 113 |
117 const size_t kAppendWholeFile = std::numeric_limits<size_t>::max(); | |
118 | |
119 // Constants for the Media Source config change tests. | 114 // Constants for the Media Source config change tests. |
120 const int kAppendTimeSec = 1; | 115 const int kAppendTimeSec = 1; |
121 const int kAppendTimeMs = kAppendTimeSec * 1000; | 116 const int kAppendTimeMs = kAppendTimeSec * 1000; |
122 const int k320WebMFileDurationMs = 2736; | 117 const int k320WebMFileDurationMs = 2736; |
123 const int k640WebMFileDurationMs = 2749; | 118 const int k640WebMFileDurationMs = 2749; |
124 const int kOpusEndTrimmingWebMFileDurationMs = 2741; | 119 const int kOpusEndTrimmingWebMFileDurationMs = 2741; |
125 const int kVP9WebMFileDurationMs = 2736; | 120 const int kVP9WebMFileDurationMs = 2736; |
126 const int kVP8AWebMFileDurationMs = 2734; | 121 const int kVP8AWebMFileDurationMs = 2734; |
127 | 122 |
128 #if !defined(MOJO_RENDERER) | 123 #if !defined(MOJO_RENDERER) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 exploded_time.second = 56; | 175 exploded_time.second = 56; |
181 exploded_time.millisecond = 789; | 176 exploded_time.millisecond = 789; |
182 base::Time timeline_offset; | 177 base::Time timeline_offset; |
183 EXPECT_TRUE(base::Time::FromUTCExploded(exploded_time, &timeline_offset)); | 178 EXPECT_TRUE(base::Time::FromUTCExploded(exploded_time, &timeline_offset)); |
184 | 179 |
185 timeline_offset += base::TimeDelta::FromMicroseconds(123); | 180 timeline_offset += base::TimeDelta::FromMicroseconds(123); |
186 | 181 |
187 return timeline_offset; | 182 return timeline_offset; |
188 } | 183 } |
189 | 184 |
190 // Note: Tests using this class only exercise the DecryptingDemuxerStream path. | |
191 // They do not exercise the Decrypting{Audio|Video}Decoder path. | |
192 class FakeEncryptedMedia { | |
193 public: | |
194 // Defines the behavior of the "app" that responds to EME events. | |
195 class AppBase { | |
196 public: | |
197 virtual ~AppBase() {} | |
198 | |
199 virtual void OnSessionMessage( | |
200 const std::string& session_id, | |
201 ContentDecryptionModule::MessageType message_type, | |
202 const std::vector<uint8_t>& message, | |
203 AesDecryptor* decryptor) = 0; | |
204 | |
205 virtual void OnSessionClosed(const std::string& session_id) = 0; | |
206 | |
207 virtual void OnSessionKeysChange(const std::string& session_id, | |
208 bool has_additional_usable_key, | |
209 CdmKeysInfo keys_info) = 0; | |
210 | |
211 virtual void OnEncryptedMediaInitData(EmeInitDataType init_data_type, | |
212 const std::vector<uint8_t>& init_data, | |
213 AesDecryptor* decryptor) = 0; | |
214 }; | |
215 | |
216 FakeEncryptedMedia(AppBase* app) | |
217 : decryptor_(new AesDecryptor( | |
218 GURL::EmptyGURL(), | |
219 base::Bind(&FakeEncryptedMedia::OnSessionMessage, | |
220 base::Unretained(this)), | |
221 base::Bind(&FakeEncryptedMedia::OnSessionClosed, | |
222 base::Unretained(this)), | |
223 base::Bind(&FakeEncryptedMedia::OnSessionKeysChange, | |
224 base::Unretained(this)))), | |
225 cdm_context_(decryptor_.get()), | |
226 app_(app) {} | |
227 | |
228 CdmContext* GetCdmContext() { return &cdm_context_; } | |
229 | |
230 // Callbacks for firing session events. Delegate to |app_|. | |
231 void OnSessionMessage(const std::string& session_id, | |
232 ContentDecryptionModule::MessageType message_type, | |
233 const std::vector<uint8_t>& message) { | |
234 app_->OnSessionMessage(session_id, message_type, message, decryptor_.get()); | |
235 } | |
236 | |
237 void OnSessionClosed(const std::string& session_id) { | |
238 app_->OnSessionClosed(session_id); | |
239 } | |
240 | |
241 void OnSessionKeysChange(const std::string& session_id, | |
242 bool has_additional_usable_key, | |
243 CdmKeysInfo keys_info) { | |
244 app_->OnSessionKeysChange(session_id, has_additional_usable_key, | |
245 std::move(keys_info)); | |
246 } | |
247 | |
248 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, | |
249 const std::vector<uint8_t>& init_data) { | |
250 app_->OnEncryptedMediaInitData(init_data_type, init_data, decryptor_.get()); | |
251 } | |
252 | |
253 private: | |
254 class TestCdmContext : public CdmContext { | |
255 public: | |
256 TestCdmContext(Decryptor* decryptor) : decryptor_(decryptor) {} | |
257 | |
258 Decryptor* GetDecryptor() final { return decryptor_; } | |
259 int GetCdmId() const final { return kInvalidCdmId; } | |
260 | |
261 private: | |
262 Decryptor* decryptor_; | |
263 }; | |
264 | |
265 scoped_refptr<AesDecryptor> decryptor_; | |
266 TestCdmContext cdm_context_; | |
267 std::unique_ptr<AppBase> app_; | |
268 }; | |
269 | |
270 enum PromiseResult { RESOLVED, REJECTED }; | 185 enum PromiseResult { RESOLVED, REJECTED }; |
271 | 186 |
272 // Provides the test key in response to the encrypted event. | 187 // Provides the test key in response to the encrypted event. |
273 class KeyProvidingApp : public FakeEncryptedMedia::AppBase { | 188 class KeyProvidingApp : public FakeEncryptedMedia::AppBase { |
274 public: | 189 public: |
275 KeyProvidingApp() {} | 190 KeyProvidingApp() {} |
276 | 191 |
277 void OnResolveWithSession(PromiseResult expected, | 192 void OnResolveWithSession(PromiseResult expected, |
278 const std::string& session_id) { | 193 const std::string& session_id) { |
279 EXPECT_EQ(expected, RESOLVED); | 194 EXPECT_EQ(expected, RESOLVED); |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 CdmKeysInfo keys_info) override { | 350 CdmKeysInfo keys_info) override { |
436 EXPECT_FALSE(session_id.empty()); | 351 EXPECT_FALSE(session_id.empty()); |
437 EXPECT_EQ(has_additional_usable_key, true); | 352 EXPECT_EQ(has_additional_usable_key, true); |
438 } | 353 } |
439 | 354 |
440 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, | 355 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, |
441 const std::vector<uint8_t>& init_data, | 356 const std::vector<uint8_t>& init_data, |
442 AesDecryptor* decryptor) override {} | 357 AesDecryptor* decryptor) override {} |
443 }; | 358 }; |
444 | 359 |
445 // Helper class that emulates calls made on the ChunkDemuxer by the | |
446 // Media Source API. | |
447 class MockMediaSource { | |
448 public: | |
449 MockMediaSource(const std::string& filename, | |
450 const std::string& mimetype, | |
451 size_t initial_append_size) | |
452 : current_position_(0), | |
453 initial_append_size_(initial_append_size), | |
454 mimetype_(mimetype), | |
455 chunk_demuxer_(new ChunkDemuxer( | |
456 base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)), | |
457 base::Bind(&MockMediaSource::OnEncryptedMediaInitData, | |
458 base::Unretained(this)), | |
459 &media_log_)), | |
460 owned_chunk_demuxer_(chunk_demuxer_) { | |
461 file_data_ = ReadTestDataFile(filename); | |
462 | |
463 if (initial_append_size_ == kAppendWholeFile) | |
464 initial_append_size_ = file_data_->data_size(); | |
465 | |
466 DCHECK_GT(initial_append_size_, 0u); | |
467 DCHECK_LE(initial_append_size_, file_data_->data_size()); | |
468 } | |
469 | |
470 virtual ~MockMediaSource() {} | |
471 | |
472 std::unique_ptr<Demuxer> GetDemuxer() { | |
473 return std::move(owned_chunk_demuxer_); | |
474 } | |
475 | |
476 void set_encrypted_media_init_data_cb( | |
477 const Demuxer::EncryptedMediaInitDataCB& encrypted_media_init_data_cb) { | |
478 encrypted_media_init_data_cb_ = encrypted_media_init_data_cb; | |
479 } | |
480 | |
481 void set_demuxer_failure_cb(const PipelineStatusCB& demuxer_failure_cb) { | |
482 demuxer_failure_cb_ = demuxer_failure_cb; | |
483 } | |
484 | |
485 void Seek(base::TimeDelta seek_time, | |
486 size_t new_position, | |
487 size_t seek_append_size) { | |
488 chunk_demuxer_->StartWaitingForSeek(seek_time); | |
489 | |
490 chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(), | |
491 kInfiniteDuration, | |
492 &last_timestamp_offset_); | |
493 | |
494 DCHECK_LT(new_position, file_data_->data_size()); | |
495 current_position_ = new_position; | |
496 | |
497 AppendData(seek_append_size); | |
498 } | |
499 | |
500 void Seek(base::TimeDelta seek_time) { | |
501 chunk_demuxer_->StartWaitingForSeek(seek_time); | |
502 } | |
503 | |
504 void AppendData(size_t size) { | |
505 DCHECK(chunk_demuxer_); | |
506 DCHECK_LT(current_position_, file_data_->data_size()); | |
507 DCHECK_LE(current_position_ + size, file_data_->data_size()); | |
508 | |
509 ASSERT_TRUE(chunk_demuxer_->AppendData( | |
510 kSourceId, file_data_->data() + current_position_, size, | |
511 base::TimeDelta(), kInfiniteDuration, &last_timestamp_offset_)); | |
512 current_position_ += size; | |
513 } | |
514 | |
515 bool AppendAtTime(base::TimeDelta timestamp_offset, | |
516 const uint8_t* pData, | |
517 int size) { | |
518 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); | |
519 bool success = | |
520 chunk_demuxer_->AppendData(kSourceId, pData, size, base::TimeDelta(), | |
521 kInfiniteDuration, ×tamp_offset); | |
522 last_timestamp_offset_ = timestamp_offset; | |
523 return success; | |
524 } | |
525 | |
526 void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset, | |
527 base::TimeDelta append_window_start, | |
528 base::TimeDelta append_window_end, | |
529 const uint8_t* pData, | |
530 int size) { | |
531 CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId)); | |
532 ASSERT_TRUE( | |
533 chunk_demuxer_->AppendData(kSourceId, pData, size, append_window_start, | |
534 append_window_end, ×tamp_offset)); | |
535 last_timestamp_offset_ = timestamp_offset; | |
536 } | |
537 | |
538 void SetMemoryLimits(size_t limit_bytes) { | |
539 chunk_demuxer_->SetMemoryLimitsForTest(DemuxerStream::AUDIO, limit_bytes); | |
540 chunk_demuxer_->SetMemoryLimitsForTest(DemuxerStream::VIDEO, limit_bytes); | |
541 } | |
542 | |
543 bool EvictCodedFrames(base::TimeDelta currentMediaTime, size_t newDataSize) { | |
544 return chunk_demuxer_->EvictCodedFrames(kSourceId, currentMediaTime, | |
545 newDataSize); | |
546 } | |
547 | |
548 void RemoveRange(base::TimeDelta start, base::TimeDelta end) { | |
549 chunk_demuxer_->Remove(kSourceId, start, end); | |
550 } | |
551 | |
552 void EndOfStream() { chunk_demuxer_->MarkEndOfStream(PIPELINE_OK); } | |
553 | |
554 void Shutdown() { | |
555 if (!chunk_demuxer_) | |
556 return; | |
557 chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(), | |
558 kInfiniteDuration, | |
559 &last_timestamp_offset_); | |
560 chunk_demuxer_->Shutdown(); | |
561 chunk_demuxer_ = NULL; | |
562 } | |
563 | |
564 void DemuxerOpened() { | |
565 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
566 FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask, | |
567 base::Unretained(this))); | |
568 } | |
569 | |
570 void DemuxerOpenedTask() { | |
571 ChunkDemuxer::Status status = AddId(); | |
572 if (status != ChunkDemuxer::kOk) { | |
573 CHECK(!demuxer_failure_cb_.is_null()); | |
574 demuxer_failure_cb_.Run(DEMUXER_ERROR_COULD_NOT_OPEN); | |
575 return; | |
576 } | |
577 chunk_demuxer_->SetTracksWatcher( | |
578 kSourceId, base::Bind(&MockMediaSource::InitSegmentReceived, | |
579 base::Unretained(this))); | |
580 | |
581 AppendData(initial_append_size_); | |
582 } | |
583 | |
584 ChunkDemuxer::Status AddId() { | |
585 // This code assumes that |mimetype_| is one of the following forms. | |
586 // 1. audio/mpeg | |
587 // 2. video/webm;codec="vorbis,vp8". | |
588 size_t semicolon = mimetype_.find(";"); | |
589 std::string type = mimetype_; | |
590 std::string codecs_param = ""; | |
591 if (semicolon != std::string::npos) { | |
592 type = mimetype_.substr(0, semicolon); | |
593 size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon); | |
594 | |
595 CHECK_NE(codecs_param_start, std::string::npos); | |
596 | |
597 codecs_param_start += 8; // Skip over the codecs=". | |
598 | |
599 size_t codecs_param_end = mimetype_.find("\"", codecs_param_start); | |
600 | |
601 CHECK_NE(codecs_param_end, std::string::npos); | |
602 | |
603 codecs_param = mimetype_.substr(codecs_param_start, | |
604 codecs_param_end - codecs_param_start); | |
605 } | |
606 | |
607 return chunk_demuxer_->AddId(kSourceId, type, codecs_param); | |
608 } | |
609 | |
610 void OnEncryptedMediaInitData(EmeInitDataType init_data_type, | |
611 const std::vector<uint8_t>& init_data) { | |
612 DCHECK(!init_data.empty()); | |
613 CHECK(!encrypted_media_init_data_cb_.is_null()); | |
614 encrypted_media_init_data_cb_.Run(init_data_type, init_data); | |
615 } | |
616 | |
617 base::TimeDelta last_timestamp_offset() const { | |
618 return last_timestamp_offset_; | |
619 } | |
620 | |
621 void InitSegmentReceived(std::unique_ptr<MediaTracks> tracks) { | |
622 CHECK(tracks.get()); | |
623 EXPECT_GT(tracks->tracks().size(), 0u); | |
624 CHECK(chunk_demuxer_); | |
625 // Verify that track ids are unique. | |
626 std::set<MediaTrack::Id> track_ids; | |
627 for (const auto& track : tracks->tracks()) { | |
628 EXPECT_EQ(track_ids.end(), track_ids.find(track->id())); | |
629 track_ids.insert(track->id()); | |
630 } | |
631 InitSegmentReceivedMock(tracks); | |
632 } | |
633 | |
634 MOCK_METHOD1(InitSegmentReceivedMock, void(std::unique_ptr<MediaTracks>&)); | |
635 | |
636 private: | |
637 MediaLog media_log_; | |
638 scoped_refptr<DecoderBuffer> file_data_; | |
639 size_t current_position_; | |
640 size_t initial_append_size_; | |
641 std::string mimetype_; | |
642 ChunkDemuxer* chunk_demuxer_; | |
643 std::unique_ptr<Demuxer> owned_chunk_demuxer_; | |
644 PipelineStatusCB demuxer_failure_cb_; | |
645 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_; | |
646 base::TimeDelta last_timestamp_offset_; | |
647 }; | |
648 | |
649 // A rough simulation of GpuVideoDecoder that fails every Decode() request. This | 360 // A rough simulation of GpuVideoDecoder that fails every Decode() request. This |
650 // is used to test post-Initialize() fallback paths. | 361 // is used to test post-Initialize() fallback paths. |
651 class FailingVideoDecoder : public VideoDecoder { | 362 class FailingVideoDecoder : public VideoDecoder { |
652 public: | 363 public: |
653 std::string GetDisplayName() const override { return "FailingVideoDecoder"; } | 364 std::string GetDisplayName() const override { return "FailingVideoDecoder"; } |
654 void Initialize(const VideoDecoderConfig& config, | 365 void Initialize(const VideoDecoderConfig& config, |
655 bool low_delay, | 366 bool low_delay, |
656 CdmContext* cdm_context, | 367 CdmContext* cdm_context, |
657 const InitCB& init_cb, | 368 const InitCB& init_cb, |
658 const OutputCB& output_cb) override { | 369 const OutputCB& output_cb) override { |
659 init_cb.Run(true); | 370 init_cb.Run(true); |
660 } | 371 } |
661 void Decode(const scoped_refptr<DecoderBuffer>& buffer, | 372 void Decode(const scoped_refptr<DecoderBuffer>& buffer, |
662 const DecodeCB& decode_cb) override { | 373 const DecodeCB& decode_cb) override { |
663 base::ThreadTaskRunnerHandle::Get()->PostTask( | 374 base::ThreadTaskRunnerHandle::Get()->PostTask( |
664 FROM_HERE, base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); | 375 FROM_HERE, base::Bind(decode_cb, DecodeStatus::DECODE_ERROR)); |
665 } | 376 } |
666 void Reset(const base::Closure& closure) override { closure.Run(); } | 377 void Reset(const base::Closure& closure) override { closure.Run(); } |
667 bool NeedsBitstreamConversion() const override { return true; } | 378 bool NeedsBitstreamConversion() const override { return true; } |
668 }; | 379 }; |
669 | 380 |
670 // TODO(xhwang): These tests have been disabled for some time as apptests and no | 381 // TODO(xhwang): These tests have been disabled for some time as apptests and no |
671 // longer pass. They need to be reconstituted as shell tests. | 382 // longer pass. They need to be reconstituted as shell tests. |
672 // Currently there are compile issues which must be resolved, | 383 // Currently there are compile issues which must be resolved, |
673 // preferably by eliminating multiple inheritance here which is | 384 // preferably by eliminating multiple inheritance here which is |
674 // banned by Google C++ style. | 385 // banned by Google C++ style. |
675 #if defined(MOJO_RENDERER) && defined(ENABLE_MOJO_PIPELINE_INTEGRATION_TEST) | 386 #if defined(MOJO_RENDERER) && defined(ENABLE_MOJO_PIPELINE_INTEGRATION_TEST) |
676 class PipelineIntegrationTestHost : public service_manager::test::ServiceTest, | 387 class PipelineIntegrationTest : public service_manager::test::ServiceTest, |
677 public PipelineIntegrationTestBase { | 388 public PipelineIntegrationTestBase { |
678 public: | 389 public: |
679 PipelineIntegrationTestHost() | 390 PipelineIntegrationTest() |
680 : service_manager::test::ServiceTest( | 391 : service_manager::test::ServiceTest( |
681 "media_pipeline_integration_shelltests") {} | 392 "media_pipeline_integration_shelltests") {} |
682 | 393 |
683 void SetUp() override { | 394 void SetUp() override { |
684 ServiceTest::SetUp(); | 395 ServiceTest::SetUp(); |
685 InitializeMediaLibrary(); | 396 InitializeMediaLibrary(); |
686 } | 397 } |
687 | 398 |
688 protected: | 399 protected: |
689 std::unique_ptr<Renderer> CreateRenderer( | 400 std::unique_ptr<Renderer> CreateRenderer( |
690 CreateVideoDecodersCB prepend_video_decoders_cb, | 401 CreateVideoDecodersCB prepend_video_decoders_cb, |
691 CreateAudioDecodersCB prepend_audio_decoders_cb) override { | 402 CreateAudioDecodersCB prepend_audio_decoders_cb) override { |
692 connector()->BindInterface("media", &media_interface_factory_); | 403 connector()->BindInterface("media", &media_interface_factory_); |
693 | 404 |
694 mojom::RendererPtr mojo_renderer; | 405 mojom::RendererPtr mojo_renderer; |
695 media_interface_factory_->CreateRenderer(std::string(), | 406 media_interface_factory_->CreateRenderer(std::string(), |
696 mojo::MakeRequest(&mojo_renderer)); | 407 mojo::MakeRequest(&mojo_renderer)); |
697 | 408 |
698 return base::MakeUnique<MojoRenderer>(message_loop_.task_runner(), | 409 return base::MakeUnique<MojoRenderer>(message_loop_.task_runner(), |
699 std::move(mojo_renderer)); | 410 std::move(mojo_renderer)); |
700 } | 411 } |
701 | 412 |
702 private: | 413 private: |
703 mojom::InterfaceFactoryPtr media_interface_factory_; | 414 mojom::InterfaceFactoryPtr media_interface_factory_; |
704 }; | 415 }; |
705 #else | 416 #else |
706 class PipelineIntegrationTestHost : public testing::Test, | 417 class PipelineIntegrationTest : public testing::Test, |
707 public PipelineIntegrationTestBase {}; | 418 public PipelineIntegrationTestBase { |
708 #endif // defined(MOJO_RENDERER) | |
709 | |
710 class PipelineIntegrationTest : public PipelineIntegrationTestHost { | |
711 public: | 419 public: |
712 PipelineStatus StartPipelineWithMediaSource(MockMediaSource* source) { | |
713 return StartPipelineWithMediaSource(source, kNormal, nullptr); | |
714 } | |
715 | |
716 PipelineStatus StartPipelineWithEncryptedMedia( | |
717 MockMediaSource* source, | |
718 FakeEncryptedMedia* encrypted_media) { | |
719 return StartPipelineWithMediaSource(source, kNormal, encrypted_media); | |
720 } | |
721 | |
722 PipelineStatus StartPipelineWithMediaSource( | |
723 MockMediaSource* source, | |
724 uint8_t test_type, | |
725 FakeEncryptedMedia* encrypted_media) { | |
726 hashing_enabled_ = test_type & kHashed; | |
727 clockless_playback_ = test_type & kClockless; | |
728 | |
729 if (!(test_type & kExpectDemuxerFailure)) | |
730 EXPECT_CALL(*source, InitSegmentReceivedMock(_)).Times(AtLeast(1)); | |
731 | |
732 EXPECT_CALL(*this, OnMetadata(_)) | |
733 .Times(AtMost(1)) | |
734 .WillRepeatedly(SaveArg<0>(&metadata_)); | |
735 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)) | |
736 .Times(AnyNumber()); | |
737 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)) | |
738 .Times(AnyNumber()); | |
739 EXPECT_CALL(*this, OnDurationChange()).Times(AnyNumber()); | |
740 EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(AtMost(1)); | |
741 EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(AtMost(1)); | |
742 | |
743 source->set_demuxer_failure_cb(base::Bind( | |
744 &PipelineIntegrationTest::OnStatusCallback, base::Unretained(this))); | |
745 demuxer_ = source->GetDemuxer(); | |
746 | |
747 if (encrypted_media) { | |
748 EXPECT_CALL(*this, DecryptorAttached(true)); | |
749 | |
750 // Encrypted content used but keys provided in advance, so this is | |
751 // never called. | |
752 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); | |
753 pipeline_->SetCdm(encrypted_media->GetCdmContext(), | |
754 base::Bind(&PipelineIntegrationTest::DecryptorAttached, | |
755 base::Unretained(this))); | |
756 } else { | |
757 // Encrypted content not used, so this is never called. | |
758 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0); | |
759 } | |
760 | |
761 pipeline_->Start(demuxer_.get(), CreateRenderer(), this, | |
762 base::Bind(&PipelineIntegrationTest::OnStatusCallback, | |
763 base::Unretained(this))); | |
764 | |
765 if (encrypted_media) { | |
766 source->set_encrypted_media_init_data_cb( | |
767 base::Bind(&FakeEncryptedMedia::OnEncryptedMediaInitData, | |
768 base::Unretained(encrypted_media))); | |
769 } | |
770 base::RunLoop().Run(); | |
771 return pipeline_status_; | |
772 } | |
773 | |
774 // Verifies that seeking works properly for ChunkDemuxer when the | 420 // Verifies that seeking works properly for ChunkDemuxer when the |
775 // seek happens while there is a pending read on the ChunkDemuxer | 421 // seek happens while there is a pending read on the ChunkDemuxer |
776 // and no data is available. | 422 // and no data is available. |
777 bool TestSeekDuringRead(const std::string& filename, | 423 bool TestSeekDuringRead(const std::string& filename, |
778 const std::string& mimetype, | 424 const std::string& mimetype, |
779 int initial_append_size, | 425 int initial_append_size, |
780 base::TimeDelta start_seek_time, | 426 base::TimeDelta start_seek_time, |
781 base::TimeDelta seek_time, | 427 base::TimeDelta seek_time, |
782 int seek_file_position, | 428 int seek_file_position, |
783 int seek_append_size) { | 429 int seek_append_size) { |
(...skipping 10 matching lines...) Expand all Loading... |
794 if (!Seek(seek_time)) | 440 if (!Seek(seek_time)) |
795 return false; | 441 return false; |
796 | 442 |
797 source.EndOfStream(); | 443 source.EndOfStream(); |
798 | 444 |
799 source.Shutdown(); | 445 source.Shutdown(); |
800 Stop(); | 446 Stop(); |
801 return true; | 447 return true; |
802 } | 448 } |
803 }; | 449 }; |
| 450 #endif // defined(MOJO_RENDERER) |
804 | 451 |
805 struct PlaybackTestData { | 452 struct PlaybackTestData { |
806 const std::string filename; | 453 const std::string filename; |
807 const uint32_t start_time_ms; | 454 const uint32_t start_time_ms; |
808 const uint32_t duration_ms; | 455 const uint32_t duration_ms; |
809 }; | 456 }; |
810 | 457 |
811 struct MSEPlaybackTestData { | 458 struct MSEPlaybackTestData { |
812 const std::string filename; | 459 const std::string filename; |
813 const std::string mimetype; | 460 const std::string mimetype; |
(...skipping 1889 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2703 | 2350 |
2704 TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) { | 2351 TEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) { |
2705 ASSERT_EQ(PIPELINE_OK, Start("nonzero-start-time.webm")); | 2352 ASSERT_EQ(PIPELINE_OK, Start("nonzero-start-time.webm")); |
2706 Play(); | 2353 Play(); |
2707 ASSERT_TRUE(WaitUntilOnEnded()); | 2354 ASSERT_TRUE(WaitUntilOnEnded()); |
2708 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000), | 2355 ASSERT_EQ(base::TimeDelta::FromMicroseconds(396000), |
2709 demuxer_->GetStartTime()); | 2356 demuxer_->GetStartTime()); |
2710 } | 2357 } |
2711 | 2358 |
2712 } // namespace media | 2359 } // namespace media |
OLD | NEW |