Chromium Code Reviews| 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 |