OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/logging.h" | 6 #include "base/logging.h" |
7 #include "base/timer/timer.h" | 7 #include "base/timer/timer.h" |
8 #include "media/base/android/demuxer_android.h" | 8 #include "media/base/android/demuxer_android.h" |
9 #include "media/base/android/media_codec_bridge.h" | 9 #include "media/base/android/media_codec_bridge.h" |
10 #include "media/base/android/media_codec_player.h" | 10 #include "media/base/android/media_codec_player.h" |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override { | 168 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override { |
169 unit->is_key_frame = true; | 169 unit->is_key_frame = true; |
170 } | 170 } |
171 }; | 171 }; |
172 | 172 |
173 // VideoFactory creates a video stream from demuxer. | 173 // VideoFactory creates a video stream from demuxer. |
174 | 174 |
175 class VideoFactory : public TestDataFactory { | 175 class VideoFactory : public TestDataFactory { |
176 public: | 176 public: |
177 VideoFactory(base::TimeDelta duration) | 177 VideoFactory(base::TimeDelta duration) |
178 : TestDataFactory("h264-320x180-frame-%d", duration, kVideoFramePeriod) {} | 178 : TestDataFactory("h264-320x180-frame-%d", duration, kVideoFramePeriod), |
| 179 key_frame_requested_(true) {} |
179 | 180 |
180 DemuxerConfigs GetConfigs() const override { | 181 DemuxerConfigs GetConfigs() const override { |
181 return TestDataFactory::CreateVideoConfigs(kCodecH264, duration_, | 182 return TestDataFactory::CreateVideoConfigs(kCodecH264, duration_, |
182 gfx::Size(320, 180)); | 183 gfx::Size(320, 180)); |
183 } | 184 } |
184 | 185 |
| 186 void RequestKeyFrame() { key_frame_requested_ = true; } |
| 187 |
185 protected: | 188 protected: |
186 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override { | 189 void ModifyAccessUnit(int index_in_chunk, AccessUnit* unit) override { |
187 // The frames are taken from High profile and some are B-frames. | 190 // The frames are taken from High profile and some are B-frames. |
188 // The first 4 frames appear in the file in the following order: | 191 // The first 4 frames appear in the file in the following order: |
189 // | 192 // |
190 // Frames: I P B P | 193 // Frames: I P B P |
191 // Decoding order: 0 1 2 3 | 194 // Decoding order: 0 1 2 3 |
192 // Presentation order: 0 2 1 4(3) | 195 // Presentation order: 0 2 1 4(3) |
193 // | 196 // |
194 // I keep the last PTS to be 3 for simplicity. | 197 // I keep the last PTS to be 3 for simplicity. |
195 | 198 |
196 // Swap pts for second and third frames. Make first frame a key frame. | 199 // Swap pts for second and third frames. Make first frame a key frame. |
197 switch (index_in_chunk) { | 200 switch (index_in_chunk) { |
198 case 0: // first frame | 201 case 0: // first frame |
199 unit->is_key_frame = true; | 202 unit->is_key_frame = key_frame_requested_; |
| 203 key_frame_requested_ = false; |
200 break; | 204 break; |
201 case 1: // second frame | 205 case 1: // second frame |
202 unit->timestamp += frame_period_; | 206 unit->timestamp += frame_period_; |
203 break; | 207 break; |
204 case 2: // third frame | 208 case 2: // third frame |
205 unit->timestamp -= frame_period_; | 209 unit->timestamp -= frame_period_; |
206 break; | 210 break; |
207 case 3: // fourth frame, do not modify | 211 case 3: // fourth frame, do not modify |
208 break; | 212 break; |
209 default: | 213 default: |
210 NOTREACHED(); | 214 NOTREACHED(); |
211 break; | 215 break; |
212 } | 216 } |
213 } | 217 } |
| 218 |
| 219 private: |
| 220 bool key_frame_requested_; |
214 }; | 221 }; |
215 | 222 |
216 // Mock of DemuxerAndroid for testing purpose. | 223 // Mock of DemuxerAndroid for testing purpose. |
217 | 224 |
218 class MockDemuxerAndroid : public DemuxerAndroid { | 225 class MockDemuxerAndroid : public DemuxerAndroid { |
219 public: | 226 public: |
220 MockDemuxerAndroid() : client_(nullptr) {} | 227 MockDemuxerAndroid() : client_(nullptr), num_browser_seeks_(0) {} |
221 ~MockDemuxerAndroid() override {} | 228 ~MockDemuxerAndroid() override {} |
222 | 229 |
223 // DemuxerAndroid implementation | 230 // DemuxerAndroid implementation |
224 void Initialize(DemuxerAndroidClient* client) override; | 231 void Initialize(DemuxerAndroidClient* client) override; |
225 void RequestDemuxerData(DemuxerStream::Type type) override; | 232 void RequestDemuxerData(DemuxerStream::Type type) override; |
226 void RequestDemuxerSeek(const base::TimeDelta& time_to_seek, | 233 void RequestDemuxerSeek(const base::TimeDelta& time_to_seek, |
227 bool is_browser_seek) override; | 234 bool is_browser_seek) override; |
228 | 235 |
229 // Sets the audio data factory. | 236 // Sets the audio data factory. |
230 void SetAudioFactory(scoped_ptr<TestDataFactory> factory) { | 237 void SetAudioFactory(scoped_ptr<AudioFactory> factory) { |
231 audio_factory_ = factory.Pass(); | 238 audio_factory_ = factory.Pass(); |
232 } | 239 } |
233 | 240 |
234 // Sets the video data factory. | 241 // Sets the video data factory. |
235 void SetVideoFactory(scoped_ptr<TestDataFactory> factory) { | 242 void SetVideoFactory(scoped_ptr<VideoFactory> factory) { |
236 video_factory_ = factory.Pass(); | 243 video_factory_ = factory.Pass(); |
237 } | 244 } |
238 | 245 |
239 // Post DemuxerConfigs to the client (i.e. the player) on correct thread. | 246 // Post DemuxerConfigs to the client (i.e. the player) on correct thread. |
240 void PostConfigs(const DemuxerConfigs& configs); | 247 void PostConfigs(const DemuxerConfigs& configs); |
241 | 248 |
242 // Post DemuxerConfigs derived from data factories that has been set. | 249 // Post DemuxerConfigs derived from data factories that has been set. |
243 void PostInternalConfigs(); | 250 void PostInternalConfigs(); |
244 | 251 |
245 // Conditions to wait for. | 252 // Conditions to wait for. |
246 bool IsInitialized() const { return client_; } | 253 bool IsInitialized() const { return client_; } |
247 bool HasPendingConfigs() const { return pending_configs_; } | 254 bool HasPendingConfigs() const { return pending_configs_; } |
| 255 bool ReceivedBrowserSeekRequest() const { return num_browser_seeks_ > 0; } |
248 | 256 |
249 private: | 257 private: |
250 DemuxerAndroidClient* client_; | 258 DemuxerAndroidClient* client_; |
251 scoped_ptr<DemuxerConfigs> pending_configs_; | 259 scoped_ptr<DemuxerConfigs> pending_configs_; |
252 scoped_ptr<TestDataFactory> audio_factory_; | 260 scoped_ptr<AudioFactory> audio_factory_; |
253 scoped_ptr<TestDataFactory> video_factory_; | 261 scoped_ptr<VideoFactory> video_factory_; |
| 262 int num_browser_seeks_; |
254 | 263 |
255 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); | 264 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); |
256 }; | 265 }; |
257 | 266 |
258 void MockDemuxerAndroid::Initialize(DemuxerAndroidClient* client) { | 267 void MockDemuxerAndroid::Initialize(DemuxerAndroidClient* client) { |
259 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; | 268 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; |
260 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | 269 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
261 | 270 |
262 client_ = client; | 271 client_ = client; |
263 if (pending_configs_) | 272 if (pending_configs_) |
(...skipping 21 matching lines...) Expand all Loading... |
285 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable, | 294 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable, |
286 base::Unretained(client_), chunk), | 295 base::Unretained(client_), chunk), |
287 delay); | 296 delay); |
288 } | 297 } |
289 | 298 |
290 void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek, | 299 void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek, |
291 bool is_browser_seek) { | 300 bool is_browser_seek) { |
292 // Tell data factories to start next chunk with the new timestamp. | 301 // Tell data factories to start next chunk with the new timestamp. |
293 if (audio_factory_) | 302 if (audio_factory_) |
294 audio_factory_->SeekTo(time_to_seek); | 303 audio_factory_->SeekTo(time_to_seek); |
295 if (video_factory_) | 304 if (video_factory_) { |
296 video_factory_->SeekTo(time_to_seek); | 305 video_factory_->SeekTo(time_to_seek); |
| 306 video_factory_->RequestKeyFrame(); |
| 307 } |
| 308 |
| 309 if (is_browser_seek) |
| 310 ++num_browser_seeks_; |
297 | 311 |
298 // Post OnDemuxerSeekDone() to the player. | 312 // Post OnDemuxerSeekDone() to the player. |
299 DCHECK(client_); | 313 DCHECK(client_); |
300 base::TimeDelta reported_seek_time = | 314 base::TimeDelta reported_seek_time = |
301 is_browser_seek ? time_to_seek : kNoTimestamp(); | 315 is_browser_seek ? time_to_seek : kNoTimestamp(); |
302 GetMediaTaskRunner()->PostTask( | 316 GetMediaTaskRunner()->PostTask( |
303 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone, | 317 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone, |
304 base::Unretained(client_), reported_seek_time)); | 318 base::Unretained(client_), reported_seek_time)); |
305 } | 319 } |
306 | 320 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 ~MediaCodecPlayerTest() override; | 354 ~MediaCodecPlayerTest() override; |
341 | 355 |
342 // Conditions to wait for. | 356 // Conditions to wait for. |
343 bool IsPaused() const { return !(player_ && player_->IsPlaying()); } | 357 bool IsPaused() const { return !(player_ && player_->IsPlaying()); } |
344 | 358 |
345 protected: | 359 protected: |
346 typedef base::Callback<bool()> Predicate; | 360 typedef base::Callback<bool()> Predicate; |
347 | 361 |
348 void CreatePlayer(); | 362 void CreatePlayer(); |
349 void SetVideoSurface(); | 363 void SetVideoSurface(); |
| 364 void SetVideoSurfaceB(); |
| 365 void RemoveVideoSurface(); |
350 | 366 |
351 // Waits for condition to become true or for timeout to expire. | 367 // Waits for condition to become true or for timeout to expire. |
352 // Returns true if the condition becomes true. | 368 // Returns true if the condition becomes true. |
353 bool WaitForCondition(const Predicate& condition, | 369 bool WaitForCondition(const Predicate& condition, |
354 const base::TimeDelta& timeout = kDefaultTimeout); | 370 const base::TimeDelta& timeout = kDefaultTimeout); |
355 | 371 |
356 // Waits for timeout to expire. | 372 // Waits for timeout to expire. |
357 void WaitForDelay(const base::TimeDelta& timeout); | 373 void WaitForDelay(const base::TimeDelta& timeout); |
358 | 374 |
359 // Waits till playback position as determined by maximal reported pts | 375 // Waits till playback position as determined by maximal reported pts |
360 // reaches the given value or for timeout to expire. Returns true if the | 376 // reaches the given value or for timeout to expire. Returns true if the |
361 // playback passed the given position. | 377 // playback passed the given position. |
362 bool WaitForPlaybackPassedPosition( | 378 bool WaitForPlaybackPassedPosition( |
363 const base::TimeDelta& pts, | 379 const base::TimeDelta& pts, |
364 const base::TimeDelta& timeout = kDefaultTimeout); | 380 const base::TimeDelta& timeout = kDefaultTimeout); |
365 | 381 |
| 382 // Helper method that starts video only stream. Waits till it actually |
| 383 // started. |
| 384 void StartVideoPlayback(base::TimeDelta duration); |
| 385 |
366 base::MessageLoop message_loop_; | 386 base::MessageLoop message_loop_; |
367 MockMediaPlayerManager manager_; | 387 MockMediaPlayerManager manager_; |
368 MockDemuxerAndroid* demuxer_; // owned by player_ | 388 MockDemuxerAndroid* demuxer_; // owned by player_ |
369 scoped_refptr<gfx::SurfaceTexture> surface_texture_; | 389 scoped_refptr<gfx::SurfaceTexture> surface_texture_a_; |
| 390 scoped_refptr<gfx::SurfaceTexture> surface_texture_b_; |
370 MediaCodecPlayer* player_; // raw pointer due to DeleteOnCorrectThread() | 391 MediaCodecPlayer* player_; // raw pointer due to DeleteOnCorrectThread() |
371 | 392 |
372 private: | 393 private: |
373 bool is_timeout_expired() const { return is_timeout_expired_; } | 394 bool is_timeout_expired() const { return is_timeout_expired_; } |
374 void SetTimeoutExpired(bool value) { is_timeout_expired_ = value; } | 395 void SetTimeoutExpired(bool value) { is_timeout_expired_ = value; } |
375 | 396 |
376 bool is_timeout_expired_; | 397 bool is_timeout_expired_; |
377 | 398 |
378 DISALLOW_COPY_AND_ASSIGN(MediaCodecPlayerTest); | 399 DISALLOW_COPY_AND_ASSIGN(MediaCodecPlayerTest); |
379 }; | 400 }; |
(...skipping 13 matching lines...) Expand all Loading... |
393 0, // player_id | 414 0, // player_id |
394 manager_.GetWeakPtr(), | 415 manager_.GetWeakPtr(), |
395 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested, | 416 base::Bind(&MockMediaPlayerManager::OnMediaResourcesRequested, |
396 base::Unretained(&manager_)), | 417 base::Unretained(&manager_)), |
397 scoped_ptr<MockDemuxerAndroid>(demuxer_), GURL()); | 418 scoped_ptr<MockDemuxerAndroid>(demuxer_), GURL()); |
398 | 419 |
399 DCHECK(player_); | 420 DCHECK(player_); |
400 } | 421 } |
401 | 422 |
402 void MediaCodecPlayerTest::SetVideoSurface() { | 423 void MediaCodecPlayerTest::SetVideoSurface() { |
403 surface_texture_ = gfx::SurfaceTexture::Create(0); | 424 surface_texture_a_ = gfx::SurfaceTexture::Create(0); |
404 gfx::ScopedJavaSurface surface(surface_texture_.get()); | 425 gfx::ScopedJavaSurface surface(surface_texture_a_.get()); |
405 | 426 |
406 ASSERT_NE(nullptr, player_); | 427 ASSERT_NE(nullptr, player_); |
407 player_->SetVideoSurface(surface.Pass()); | 428 player_->SetVideoSurface(surface.Pass()); |
408 } | 429 } |
409 | 430 |
| 431 void MediaCodecPlayerTest::SetVideoSurfaceB() { |
| 432 surface_texture_b_ = gfx::SurfaceTexture::Create(1); |
| 433 gfx::ScopedJavaSurface surface(surface_texture_b_.get()); |
| 434 |
| 435 ASSERT_NE(nullptr, player_); |
| 436 player_->SetVideoSurface(surface.Pass()); |
| 437 } |
| 438 |
| 439 void MediaCodecPlayerTest::RemoveVideoSurface() { |
| 440 player_->SetVideoSurface(gfx::ScopedJavaSurface()); |
| 441 surface_texture_a_ = NULL; |
| 442 } |
| 443 |
410 bool MediaCodecPlayerTest::WaitForCondition(const Predicate& condition, | 444 bool MediaCodecPlayerTest::WaitForCondition(const Predicate& condition, |
411 const base::TimeDelta& timeout) { | 445 const base::TimeDelta& timeout) { |
412 // Let the message_loop_ process events. | 446 // Let the message_loop_ process events. |
413 // We start the timer and RunUntilIdle() until it signals. | 447 // We start the timer and RunUntilIdle() until it signals. |
414 | 448 |
415 SetTimeoutExpired(false); | 449 SetTimeoutExpired(false); |
416 | 450 |
417 base::Timer timer(false, false); | 451 base::Timer timer(false, false); |
418 timer.Start(FROM_HERE, timeout, | 452 timer.Start(FROM_HERE, timeout, |
419 base::Bind(&MediaCodecPlayerTest::SetTimeoutExpired, | 453 base::Bind(&MediaCodecPlayerTest::SetTimeoutExpired, |
(...skipping 17 matching lines...) Expand all Loading... |
437 | 471 |
438 bool MediaCodecPlayerTest::WaitForPlaybackPassedPosition( | 472 bool MediaCodecPlayerTest::WaitForPlaybackPassedPosition( |
439 const base::TimeDelta& pts, | 473 const base::TimeDelta& pts, |
440 const base::TimeDelta& timeout) { | 474 const base::TimeDelta& timeout) { |
441 return WaitForCondition( | 475 return WaitForCondition( |
442 base::Bind(&MockMediaPlayerManager::IsPlaybackPassedPosition, | 476 base::Bind(&MockMediaPlayerManager::IsPlaybackPassedPosition, |
443 base::Unretained(&manager_), pts), | 477 base::Unretained(&manager_), pts), |
444 timeout); | 478 timeout); |
445 } | 479 } |
446 | 480 |
| 481 void MediaCodecPlayerTest::StartVideoPlayback(base::TimeDelta duration) { |
| 482 const base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
| 483 |
| 484 demuxer_->SetVideoFactory( |
| 485 scoped_ptr<VideoFactory>(new VideoFactory(duration))); |
| 486 |
| 487 CreatePlayer(); |
| 488 SetVideoSurface(); |
| 489 |
| 490 // Wait till the player is initialized on media thread. |
| 491 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, |
| 492 base::Unretained(demuxer_)))); |
| 493 |
| 494 // Post configuration after the player has been initialized. |
| 495 demuxer_->PostInternalConfigs(); |
| 496 |
| 497 // Start the player. |
| 498 EXPECT_FALSE(manager_.IsPlaybackStarted()); |
| 499 player_->Start(); |
| 500 |
| 501 // Wait for playback to start. |
| 502 EXPECT_TRUE( |
| 503 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
| 504 base::Unretained(&manager_)), |
| 505 start_timeout)); |
| 506 } |
| 507 |
447 TEST_F(MediaCodecPlayerTest, SetAudioConfigsBeforePlayerCreation) { | 508 TEST_F(MediaCodecPlayerTest, SetAudioConfigsBeforePlayerCreation) { |
448 // Post configuration when there is no player yet. | 509 // Post configuration when there is no player yet. |
449 EXPECT_EQ(nullptr, player_); | 510 EXPECT_EQ(nullptr, player_); |
450 | 511 |
451 base::TimeDelta duration = base::TimeDelta::FromSeconds(10); | 512 base::TimeDelta duration = base::TimeDelta::FromSeconds(10); |
452 | 513 |
453 demuxer_->PostConfigs( | 514 demuxer_->PostConfigs( |
454 TestDataFactory::CreateAudioConfigs(kCodecAAC, duration)); | 515 TestDataFactory::CreateAudioConfigs(kCodecAAC, duration)); |
455 | 516 |
456 // Wait until the configuration gets to the media thread. | 517 // Wait until the configuration gets to the media thread. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 base::TimeDelta audio_pts_delay = base::TimeDelta::FromMilliseconds(100); | 606 base::TimeDelta audio_pts_delay = base::TimeDelta::FromMilliseconds(100); |
546 EXPECT_LT(duration - audio_pts_delay, manager_.pts_stat_.max()); | 607 EXPECT_LT(duration - audio_pts_delay, manager_.pts_stat_.max()); |
547 } | 608 } |
548 | 609 |
549 TEST_F(MediaCodecPlayerTest, VideoPlayTillCompletion) { | 610 TEST_F(MediaCodecPlayerTest, VideoPlayTillCompletion) { |
550 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); | 611 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
551 | 612 |
552 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); | 613 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(500); |
553 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1500); | 614 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1500); |
554 | 615 |
555 demuxer_->SetVideoFactory( | 616 StartVideoPlayback(duration); |
556 scoped_ptr<VideoFactory>(new VideoFactory(duration))); | |
557 | 617 |
558 CreatePlayer(); | 618 // Wait till completion. |
559 SetVideoSurface(); | |
560 | |
561 // Wait till the player is initialized on media thread. | |
562 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, | |
563 base::Unretained(demuxer_)))); | |
564 | |
565 // Post configuration after the player has been initialized. | |
566 demuxer_->PostInternalConfigs(); | |
567 | |
568 EXPECT_FALSE(manager_.IsPlaybackCompleted()); | |
569 | |
570 player_->Start(); | |
571 | |
572 EXPECT_TRUE( | 619 EXPECT_TRUE( |
573 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, | 620 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, |
574 base::Unretained(&manager_)), | 621 base::Unretained(&manager_)), |
575 timeout)); | 622 timeout)); |
576 | 623 |
577 EXPECT_LE(duration, manager_.pts_stat_.max()); | 624 EXPECT_LE(duration, manager_.pts_stat_.max()); |
578 } | 625 } |
579 | 626 |
580 TEST_F(MediaCodecPlayerTest, AudioSeekAfterStop) { | 627 TEST_F(MediaCodecPlayerTest, AudioSeekAfterStop) { |
581 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); | 628 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 player_->SeekTo(base::TimeDelta::FromSeconds(3)); | 782 player_->SeekTo(base::TimeDelta::FromSeconds(3)); |
736 player_->SeekTo(base::TimeDelta::FromSeconds(4)); | 783 player_->SeekTo(base::TimeDelta::FromSeconds(4)); |
737 player_->SeekTo(base::TimeDelta::FromSeconds(5)); | 784 player_->SeekTo(base::TimeDelta::FromSeconds(5)); |
738 | 785 |
739 // Make sure that we reached the last timestamp within default timeout, | 786 // Make sure that we reached the last timestamp within default timeout, |
740 // i.e. 200 ms. | 787 // i.e. 200 ms. |
741 EXPECT_TRUE(WaitForPlaybackPassedPosition(base::TimeDelta::FromSeconds(5))); | 788 EXPECT_TRUE(WaitForPlaybackPassedPosition(base::TimeDelta::FromSeconds(5))); |
742 EXPECT_TRUE(player_->IsPlaying()); | 789 EXPECT_TRUE(player_->IsPlaying()); |
743 } | 790 } |
744 | 791 |
| 792 TEST_F(MediaCodecPlayerTest, VideoReplaceSurface) { |
| 793 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 794 |
| 795 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1000); |
| 796 base::TimeDelta timeout = base::TimeDelta::FromMilliseconds(1500); |
| 797 |
| 798 StartVideoPlayback(duration); |
| 799 |
| 800 // Wait for some time and check statistics. |
| 801 WaitForDelay(base::TimeDelta::FromMilliseconds(200)); |
| 802 |
| 803 // Make sure we played at least 100 ms. |
| 804 EXPECT_LT(base::TimeDelta::FromMilliseconds(100), manager_.pts_stat_.max()); |
| 805 |
| 806 // Set new video surface without removing the old one. |
| 807 SetVideoSurfaceB(); |
| 808 |
| 809 // We should receive a browser seek request. |
| 810 EXPECT_TRUE(WaitForCondition( |
| 811 base::Bind(&MockDemuxerAndroid::ReceivedBrowserSeekRequest, |
| 812 base::Unretained(demuxer_)))); |
| 813 |
| 814 // Playback should continue with a new surface. Wait till completion. |
| 815 EXPECT_TRUE( |
| 816 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, |
| 817 base::Unretained(&manager_)), |
| 818 timeout)); |
| 819 EXPECT_LE(duration, manager_.pts_stat_.max()); |
| 820 } |
| 821 |
| 822 TEST_F(MediaCodecPlayerTest, VideoRemoveAndSetSurface) { |
| 823 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 824 |
| 825 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1000); |
| 826 |
| 827 StartVideoPlayback(duration); |
| 828 |
| 829 // Wait for some time and check statistics. |
| 830 WaitForDelay(base::TimeDelta::FromMilliseconds(200)); |
| 831 |
| 832 // Make sure we played at least 100 ms. |
| 833 EXPECT_LT(base::TimeDelta::FromMilliseconds(100), manager_.pts_stat_.max()); |
| 834 |
| 835 // Remove video surface. |
| 836 RemoveVideoSurface(); |
| 837 |
| 838 // We should be stuck waiting for the new surface. |
| 839 WaitForDelay(base::TimeDelta::FromMilliseconds(200)); |
| 840 EXPECT_FALSE(player_->IsPlaying()); |
| 841 |
| 842 // Save last PTS and clear statistics. |
| 843 base::TimeDelta max_pts_before_removal = manager_.pts_stat_.max(); |
| 844 manager_.pts_stat_.Clear(); |
| 845 |
| 846 // After clearing statistics we are ready to wait for IsPlaybackStarted again. |
| 847 EXPECT_FALSE(manager_.IsPlaybackStarted()); |
| 848 |
| 849 // Extra RemoveVideoSurface() should not change anything. |
| 850 RemoveVideoSurface(); |
| 851 |
| 852 // Set another video surface. |
| 853 SetVideoSurfaceB(); |
| 854 |
| 855 // We should receive a browser seek request. |
| 856 EXPECT_TRUE(WaitForCondition( |
| 857 base::Bind(&MockDemuxerAndroid::ReceivedBrowserSeekRequest, |
| 858 base::Unretained(demuxer_)))); |
| 859 |
| 860 // Playback should continue with a new surface. Wait till it starts again. |
| 861 base::TimeDelta reconfigure_timeout = base::TimeDelta::FromMilliseconds(800); |
| 862 EXPECT_TRUE( |
| 863 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
| 864 base::Unretained(&manager_)), |
| 865 reconfigure_timeout)); |
| 866 |
| 867 // Timestamps should not go back. |
| 868 EXPECT_LE(max_pts_before_removal, manager_.pts_stat_.max()); |
| 869 } |
| 870 |
| 871 TEST_F(MediaCodecPlayerTest, VideoBackgroundForeground) { |
| 872 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 873 |
| 874 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(1000); |
| 875 |
| 876 StartVideoPlayback(duration); |
| 877 |
| 878 // Wait for some time and check statistics. |
| 879 WaitForDelay(base::TimeDelta::FromMilliseconds(200)); |
| 880 |
| 881 // Make sure we played at least 100 ms. |
| 882 EXPECT_LT(base::TimeDelta::FromMilliseconds(100), manager_.pts_stat_.max()); |
| 883 |
| 884 // When the user presses Tasks button Chrome calls Pause() and Release(). |
| 885 player_->Pause(true); |
| 886 player_->Release(); |
| 887 |
| 888 // Make sure we are not playing any more. |
| 889 WaitForDelay(base::TimeDelta::FromMilliseconds(200)); |
| 890 EXPECT_FALSE(player_->IsPlaying()); |
| 891 |
| 892 // Save last PTS and clear statistics. |
| 893 base::TimeDelta max_pts_before_backgrounding = manager_.pts_stat_.max(); |
| 894 manager_.pts_stat_.Clear(); |
| 895 |
| 896 // After clearing statistics we are ready to wait for IsPlaybackStarted again. |
| 897 EXPECT_FALSE(manager_.IsPlaybackStarted()); |
| 898 |
| 899 // Emulate that we returned to the foreground: set video surface and start |
| 900 // the player. |
| 901 SetVideoSurface(); |
| 902 player_->Start(); |
| 903 |
| 904 // We should receive a browser seek request. |
| 905 EXPECT_TRUE(WaitForCondition( |
| 906 base::Bind(&MockDemuxerAndroid::ReceivedBrowserSeekRequest, |
| 907 base::Unretained(demuxer_)))); |
| 908 |
| 909 // Wait for playback to start again. |
| 910 base::TimeDelta reconfigure_timeout = base::TimeDelta::FromMilliseconds(800); |
| 911 EXPECT_TRUE( |
| 912 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
| 913 base::Unretained(&manager_)), |
| 914 reconfigure_timeout)); |
| 915 |
| 916 // Timestamps should not go back. |
| 917 EXPECT_LE(max_pts_before_backgrounding, manager_.pts_stat_.max()); |
| 918 } |
| 919 |
745 } // namespace media | 920 } // namespace media |
OLD | NEW |