Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Side by Side Diff: media/base/android/media_source_player_unittest.cc

Issue 51613002: Abort MSP::OnPrefetchDone() if just after MSP::Release(). Let seek and config change survive. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove an extra blank line Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
OLDNEW
« media/base/android/media_source_player.cc ('K') | « media/base/android/media_source_player.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698