OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <string> | 5 #include <string> |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/callback_helpers.h" | |
8 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
9 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
10 #include "media/base/android/media_codec_bridge.h" | 11 #include "media/base/android/media_codec_bridge.h" |
11 #include "media/base/android/media_drm_bridge.h" | 12 #include "media/base/android/media_drm_bridge.h" |
12 #include "media/base/android/media_player_manager.h" | 13 #include "media/base/android/media_player_manager.h" |
13 #include "media/base/android/media_source_player.h" | 14 #include "media/base/android/media_source_player.h" |
15 #include "media/base/bind_to_loop.h" | |
14 #include "media/base/decoder_buffer.h" | 16 #include "media/base/decoder_buffer.h" |
15 #include "media/base/test_data_util.h" | 17 #include "media/base/test_data_util.h" |
16 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
17 #include "ui/gl/android/surface_texture.h" | 19 #include "ui/gl/android/surface_texture.h" |
18 | 20 |
19 namespace media { | 21 namespace media { |
20 | 22 |
21 // Helper macro to skip the test if MediaCodecBridge isn't available. | 23 // Helper macro to skip the test if MediaCodecBridge isn't available. |
22 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \ | 24 #define SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE() \ |
23 do { \ | 25 do { \ |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 virtual void OnKeyAdded(int key_id, | 75 virtual void OnKeyAdded(int key_id, |
74 const std::string& session_id) OVERRIDE {} | 76 const std::string& session_id) OVERRIDE {} |
75 virtual void OnKeyError(int key_id, | 77 virtual void OnKeyError(int key_id, |
76 const std::string& session_id, | 78 const std::string& session_id, |
77 MediaKeys::KeyError error_code, | 79 MediaKeys::KeyError error_code, |
78 int system_code) OVERRIDE {} | 80 int system_code) OVERRIDE {} |
79 virtual void OnKeyMessage(int key_id, | 81 virtual void OnKeyMessage(int key_id, |
80 const std::string& session_id, | 82 const std::string& session_id, |
81 const std::vector<uint8>& message, | 83 const std::vector<uint8>& message, |
82 const std::string& destination_url) OVERRIDE {} | 84 const std::string& destination_url) OVERRIDE {} |
85 virtual void OnMediaDecoderCallback() OVERRIDE { | |
86 if (media_decoder_test_cb_.is_null()) | |
87 return; | |
88 base::ResetAndReturn(&media_decoder_test_cb_).Run(); | |
89 } | |
90 | |
91 // Hook the next OnMediaDecoderCallback() to run the supplied Closure. | |
92 void HookNextMediaDecoderCallback(const base::Closure& decode_cb) { | |
93 media_decoder_test_cb_ = decode_cb; | |
94 } | |
83 | 95 |
84 private: | 96 private: |
85 base::MessageLoop* message_loop_; | 97 base::MessageLoop* message_loop_; |
98 base::Closure media_decoder_test_cb_; | |
86 | 99 |
87 DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager); | 100 DISALLOW_COPY_AND_ASSIGN(MockMediaPlayerManager); |
88 }; | 101 }; |
89 | 102 |
90 class MockDemuxerAndroid : public DemuxerAndroid { | 103 class MockDemuxerAndroid : public DemuxerAndroid { |
91 public: | 104 public: |
92 explicit MockDemuxerAndroid(base::MessageLoop* message_loop) | 105 explicit MockDemuxerAndroid(base::MessageLoop* message_loop) |
93 : message_loop_(message_loop), | 106 : message_loop_(message_loop), |
94 num_data_requests_(0), | 107 num_data_requests_(0), |
95 num_seek_requests_(0), | 108 num_seek_requests_(0), |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
135 | 148 |
136 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); | 149 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); |
137 }; | 150 }; |
138 | 151 |
139 class MediaSourcePlayerTest : public testing::Test { | 152 class MediaSourcePlayerTest : public testing::Test { |
140 public: | 153 public: |
141 MediaSourcePlayerTest() | 154 MediaSourcePlayerTest() |
142 : manager_(&message_loop_), | 155 : manager_(&message_loop_), |
143 demuxer_(new MockDemuxerAndroid(&message_loop_)), | 156 demuxer_(new MockDemuxerAndroid(&message_loop_)), |
144 player_(0, &manager_, scoped_ptr<DemuxerAndroid>(demuxer_)), | 157 player_(0, &manager_, scoped_ptr<DemuxerAndroid>(demuxer_)), |
158 decoder_callback_hook_executed_(false), | |
145 surface_texture_a_is_next_(true) {} | 159 surface_texture_a_is_next_(true) {} |
146 virtual ~MediaSourcePlayerTest() {} | 160 virtual ~MediaSourcePlayerTest() {} |
147 | 161 |
148 protected: | 162 protected: |
149 // Get the decoder job from the MediaSourcePlayer. | 163 // Get the decoder job from the MediaSourcePlayer. |
150 MediaDecoderJob* GetMediaDecoderJob(bool is_audio) { | 164 MediaDecoderJob* GetMediaDecoderJob(bool is_audio) { |
151 if (is_audio) { | 165 if (is_audio) { |
152 return reinterpret_cast<MediaDecoderJob*>( | 166 return reinterpret_cast<MediaDecoderJob*>( |
153 player_.audio_decoder_job_.get()); | 167 player_.audio_decoder_job_.get()); |
154 } | 168 } |
155 return reinterpret_cast<MediaDecoderJob*>( | 169 return reinterpret_cast<MediaDecoderJob*>( |
156 player_.video_decoder_job_.get()); | 170 player_.video_decoder_job_.get()); |
157 } | 171 } |
158 | 172 |
159 // Get the per-job prerolling status from the MediaSourcePlayer's job matching | 173 // Get the per-job prerolling status from the MediaSourcePlayer's job matching |
160 // |is_audio|. Caller must guard against NPE if the player's job is NULL. | 174 // |is_audio|. Caller must guard against NPE if the player's job is NULL. |
161 bool IsPrerolling(bool is_audio) { | 175 bool IsPrerolling(bool is_audio) { |
162 return GetMediaDecoderJob(is_audio)->prerolling(); | 176 return GetMediaDecoderJob(is_audio)->prerolling(); |
163 } | 177 } |
164 | 178 |
165 // Get the preroll timestamp from the MediaSourcePlayer. | 179 // Get the preroll timestamp from the MediaSourcePlayer. |
166 base::TimeDelta GetPrerollTimestamp() { | 180 base::TimeDelta GetPrerollTimestamp() { |
167 return player_.preroll_timestamp_; | 181 return player_.preroll_timestamp_; |
168 } | 182 } |
169 | 183 |
184 // Check if the player is pending a surface change event. | |
185 bool IsPendingSurfaceChange() { | |
186 return player_.IsEventPending(player_.SURFACE_CHANGE_EVENT_PENDING); | |
187 } | |
188 | |
189 // Check if the player is pending a prefetch request event. | |
190 bool IsPendingPrefetchRequest() { | |
191 return player_.IsEventPending(player_.PREFETCH_REQUEST_EVENT_PENDING); | |
192 } | |
193 | |
194 // Check if the player is pending a prefetch done event. | |
195 bool IsPendingPrefetchDone() { | |
196 return player_.IsEventPending(player_.PREFETCH_DONE_EVENT_PENDING); | |
197 } | |
198 | |
199 // Simulate player has reached starvation timeout. | |
200 void TriggerPlayerStarvation() { | |
201 player_.decoder_starvation_callback_.Cancel(); | |
202 player_.OnDecoderStarved(); | |
203 } | |
204 | |
205 // Asynch test callback posted upon decode completion to verify that a pending | |
206 // prefetch done event is cleared across |player_|'s Release(). This helps | |
207 // ensure the ReleaseWithOnPrefetchDoneAlreadyPosted test scenario is met. | |
208 void ReleaseWithPendingPrefetchDoneVerification() { | |
209 EXPECT_TRUE(player_.IsPlaying()); | |
210 EXPECT_FALSE(IsPendingPrefetchRequest()); | |
211 EXPECT_TRUE(IsPendingPrefetchDone()); | |
212 player_.Release(); | |
213 EXPECT_FALSE(IsPendingPrefetchDone()); | |
214 EXPECT_FALSE(player_.IsPlaying()); | |
215 EXPECT_FALSE(decoder_callback_hook_executed_); | |
216 decoder_callback_hook_executed_ = true; | |
217 } | |
218 | |
170 DemuxerConfigs CreateAudioDemuxerConfigs() { | 219 DemuxerConfigs CreateAudioDemuxerConfigs() { |
171 DemuxerConfigs configs; | 220 DemuxerConfigs configs; |
172 configs.audio_codec = kCodecVorbis; | 221 configs.audio_codec = kCodecVorbis; |
173 configs.audio_channels = 2; | 222 configs.audio_channels = 2; |
174 configs.audio_sampling_rate = 44100; | 223 configs.audio_sampling_rate = 44100; |
175 configs.is_audio_encrypted = false; | 224 configs.is_audio_encrypted = false; |
176 configs.duration_ms = kDefaultDurationInMs; | 225 configs.duration_ms = kDefaultDurationInMs; |
177 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-extradata"); | 226 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile("vorbis-extradata"); |
178 configs.audio_extra_data = std::vector<uint8>( | 227 configs.audio_extra_data = std::vector<uint8>( |
179 buffer->data(), | 228 buffer->data(), |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
461 } | 510 } |
462 | 511 |
463 bool IsTypeSupported(const std::vector<uint8>& scheme_uuid, | 512 bool IsTypeSupported(const std::vector<uint8>& scheme_uuid, |
464 const std::string& security_level, | 513 const std::string& security_level, |
465 const std::string& container, | 514 const std::string& container, |
466 const std::vector<std::string>& codecs) { | 515 const std::vector<std::string>& codecs) { |
467 return MediaSourcePlayer::IsTypeSupported( | 516 return MediaSourcePlayer::IsTypeSupported( |
468 scheme_uuid, security_level, container, codecs); | 517 scheme_uuid, security_level, container, codecs); |
469 } | 518 } |
470 | 519 |
471 protected: | |
472 base::MessageLoop message_loop_; | 520 base::MessageLoop message_loop_; |
473 MockMediaPlayerManager manager_; | 521 MockMediaPlayerManager manager_; |
474 MockDemuxerAndroid* demuxer_; // Owned by |player_|. | 522 MockDemuxerAndroid* demuxer_; // Owned by |player_|. |
475 MediaSourcePlayer player_; | 523 MediaSourcePlayer player_; |
476 | 524 |
525 // Track whether a possibly asynch decoder callback test hook has run. | |
526 bool decoder_callback_hook_executed_; | |
527 | |
477 // We need to keep the surface texture while the decoder is actively decoding. | 528 // We need to keep the surface texture while the decoder is actively decoding. |
478 // Otherwise, it may trigger unexpected crashes on some devices. To switch | 529 // Otherwise, it may trigger unexpected crashes on some devices. To switch |
479 // surfaces, tests need to create a new surface texture without releasing | 530 // surfaces, tests need to create a new surface texture without releasing |
480 // their previous one. In CreateNextTextureAndSetVideoSurface(), we toggle | 531 // their previous one. In CreateNextTextureAndSetVideoSurface(), we toggle |
481 // between two surface textures, only replacing the N-2 texture. Assumption is | 532 // between two surface textures, only replacing the N-2 texture. Assumption is |
482 // that no more than N-1 texture is in use by decoder when | 533 // that no more than N-1 texture is in use by decoder when |
483 // CreateNextTextureAndSetVideoSurface() is called. | 534 // CreateNextTextureAndSetVideoSurface() is called. |
484 scoped_refptr<gfx::SurfaceTexture> surface_texture_a_; | 535 scoped_refptr<gfx::SurfaceTexture> surface_texture_a_; |
485 scoped_refptr<gfx::SurfaceTexture> surface_texture_b_; | 536 scoped_refptr<gfx::SurfaceTexture> surface_texture_b_; |
486 bool surface_texture_a_is_next_; | 537 bool surface_texture_a_is_next_; |
(...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1372 player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs()); | 1423 player_.OnDemuxerConfigsAvailable(CreateVideoDemuxerConfigs()); |
1373 MediaDecoderJob* second_job = GetMediaDecoderJob(false); | 1424 MediaDecoderJob* second_job = GetMediaDecoderJob(false); |
1374 EXPECT_NE(first_job, second_job); | 1425 EXPECT_NE(first_job, second_job); |
1375 EXPECT_TRUE(second_job); | 1426 EXPECT_TRUE(second_job); |
1376 | 1427 |
1377 EXPECT_EQ(3, demuxer_->num_data_requests()); | 1428 EXPECT_EQ(3, demuxer_->num_data_requests()); |
1378 EXPECT_EQ(1, demuxer_->num_config_requests()); | 1429 EXPECT_EQ(1, demuxer_->num_config_requests()); |
1379 EXPECT_EQ(0, demuxer_->num_seek_requests()); | 1430 EXPECT_EQ(0, demuxer_->num_seek_requests()); |
1380 } | 1431 } |
1381 | 1432 |
1433 TEST_F(MediaSourcePlayerTest, ReleaseClearsSurfaceChangeAndPrefetchDone) { | |
1434 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); | |
1435 | |
1436 // Test that Release() clears both a pending surface change event as well | |
1437 // as a pending prefetch done event. | |
1438 StartVideoDecoderJob(); | |
1439 CreateNextTextureAndSetVideoSurface(); | |
1440 EXPECT_EQ(1, demuxer_->num_data_requests()); | |
1441 EXPECT_TRUE(GetMediaDecoderJob(false)); | |
1442 | |
1443 EXPECT_FALSE(IsPendingSurfaceChange()); | |
1444 CreateNextTextureAndSetVideoSurface(); | |
1445 EXPECT_TRUE(IsPendingSurfaceChange()); | |
1446 EXPECT_TRUE(IsPendingPrefetchDone()); | |
1447 | |
1448 player_.Release(); | |
1449 EXPECT_FALSE(IsPendingSurfaceChange()); | |
1450 EXPECT_FALSE(IsPendingPrefetchDone()); | |
1451 | |
1452 // Player should have no decoder job until after Start() and setting non-empty | |
1453 // surface. | |
1454 EXPECT_FALSE(GetMediaDecoderJob(false)); | |
1455 EXPECT_FALSE(player_.IsPlaying()); | |
1456 StartVideoDecoderJob(); | |
1457 EXPECT_FALSE(GetMediaDecoderJob(false)); | |
1458 CreateNextTextureAndSetVideoSurface(); | |
1459 EXPECT_TRUE(GetMediaDecoderJob(false)); | |
1460 } | |
1461 | |
1462 TEST_F(MediaSourcePlayerTest, ReleaseWithOnPrefetchDoneAlreadyPosted) { | |
1463 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); | |
1464 | |
1465 // Test that if OnPrefetchDone() had already been posted before and is | |
1466 // executed after Release(), player does not DCHECK. | |
1467 StartAudioDecoderJob(); | |
1468 | |
1469 // Escape the original prefetch by decoding a single access unit. | |
1470 player_.OnDemuxerDataAvailable(CreateReadFromDemuxerAckForAudio(0)); | |
1471 message_loop_.Run(); | |
1472 | |
1473 // Prime the job with a few more access units, so that a later prefetch, | |
1474 // triggered by starvation to simulate decoder underrun, can trivially | |
1475 // post task to run OnPrefetchDone(). | |
1476 player_.OnDemuxerDataAvailable( | |
1477 CreateReadFromDemuxerAckWithConfigChanged(true, 4)); | |
1478 | |
1479 EXPECT_TRUE(GetMediaDecoderJob(true) && | |
1480 GetMediaDecoderJob(true)->is_decoding()); | |
1481 EXPECT_FALSE(IsPendingPrefetchRequest()); | |
1482 EXPECT_FALSE(IsPendingPrefetchDone()); | |
1483 | |
1484 // Simulate decoder underrun, so trivial prefetch starts while still decoding. | |
1485 // The prefetch and posting of OnPrefetchDone() will not occur until next | |
1486 // MediaDecoderCallBack() occurs. | |
1487 TriggerPlayerStarvation(); | |
1488 EXPECT_TRUE(IsPendingPrefetchRequest()); | |
1489 EXPECT_FALSE(IsPendingPrefetchDone()); | |
1490 | |
1491 // Upon the next successful decode callback, post a task to Release() | |
1492 // |player_|, such that the trivial OnPrefetchDone() task posting also occurs | |
1493 // and should execute after the Release(). | |
1494 manager_.HookNextMediaDecoderCallback(media::BindToLoop( | |
1495 message_loop_.message_loop_proxy(), | |
1496 base::Bind( | |
1497 &MediaSourcePlayerTest_ReleaseWithOnPrefetchDoneAlreadyPosted_Test:: | |
1498 ReleaseWithPendingPrefetchDoneVerification, | |
1499 base::Unretained(this)))); | |
1500 | |
1501 while (GetMediaDecoderJob(true)) | |
1502 message_loop_.RunUntilIdle(); | |
1503 EXPECT_TRUE(decoder_callback_hook_executed_); | |
1504 EXPECT_FALSE(IsPendingPrefetchRequest()); | |
1505 EXPECT_FALSE(IsPendingPrefetchDone()); | |
1506 EXPECT_EQ(2, demuxer_->num_data_requests()); | |
1507 EXPECT_FALSE(GetMediaDecoderJob(true)); | |
wolenetz
2013/10/30 00:06:45
This line was redundant with while(), above.
| |
1508 EXPECT_FALSE(player_.IsPlaying()); | |
1509 | |
1510 // Player should have no decoder job until after Start(). | |
1511 StartAudioDecoderJob(); | |
1512 EXPECT_TRUE(GetMediaDecoderJob(true)); | |
1513 } | |
1514 | |
1382 // TODO(xhwang): Enable this test when the test devices are updated. | 1515 // TODO(xhwang): Enable this test when the test devices are updated. |
1383 TEST_F(MediaSourcePlayerTest, DISABLED_IsTypeSupported_Widevine) { | 1516 TEST_F(MediaSourcePlayerTest, DISABLED_IsTypeSupported_Widevine) { |
1384 if (!MediaCodecBridge::IsAvailable() || !MediaDrmBridge::IsAvailable()) { | 1517 if (!MediaCodecBridge::IsAvailable() || !MediaDrmBridge::IsAvailable()) { |
1385 LOG(INFO) << "Could not run test - not supported on device."; | 1518 LOG(INFO) << "Could not run test - not supported on device."; |
1386 return; | 1519 return; |
1387 } | 1520 } |
1388 | 1521 |
1389 uint8 kWidevineUUID[] = { 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, | 1522 uint8 kWidevineUUID[] = { 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, |
1390 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; | 1523 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; |
1391 | 1524 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1446 | 1579 |
1447 std::vector<std::string> codec_avc(1, "avc1"); | 1580 std::vector<std::string> codec_avc(1, "avc1"); |
1448 EXPECT_FALSE(IsTypeSupported(invalid_uuid, "L3", kVideoMp4, codec_avc)); | 1581 EXPECT_FALSE(IsTypeSupported(invalid_uuid, "L3", kVideoMp4, codec_avc)); |
1449 EXPECT_FALSE(IsTypeSupported(invalid_uuid, "L1", kVideoMp4, codec_avc)); | 1582 EXPECT_FALSE(IsTypeSupported(invalid_uuid, "L1", kVideoMp4, codec_avc)); |
1450 } | 1583 } |
1451 | 1584 |
1452 // TODO(xhwang): Are these IsTypeSupported tests device specific? | 1585 // TODO(xhwang): Are these IsTypeSupported tests device specific? |
1453 // TODO(xhwang): Add more IsTypeSupported tests. | 1586 // TODO(xhwang): Add more IsTypeSupported tests. |
1454 | 1587 |
1455 } // namespace media | 1588 } // namespace media |
OLD | NEW |