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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 | 230 |
231 class MockDemuxerAndroid : public DemuxerAndroid { | 231 class MockDemuxerAndroid : public DemuxerAndroid { |
232 public: | 232 public: |
233 MockDemuxerAndroid() | 233 MockDemuxerAndroid() |
234 : client_(nullptr), num_seeks_(0), num_browser_seeks_(0) {} | 234 : client_(nullptr), num_seeks_(0), num_browser_seeks_(0) {} |
235 ~MockDemuxerAndroid() override {} | 235 ~MockDemuxerAndroid() override {} |
236 | 236 |
237 // DemuxerAndroid implementation | 237 // DemuxerAndroid implementation |
238 void Initialize(DemuxerAndroidClient* client) override; | 238 void Initialize(DemuxerAndroidClient* client) override; |
239 void RequestDemuxerData(DemuxerStream::Type type) override; | 239 void RequestDemuxerData(DemuxerStream::Type type) override; |
240 void RequestDemuxerSeek(const base::TimeDelta& time_to_seek, | 240 void RequestDemuxerSeek(const base::TimeDelta& seek_request, |
241 bool is_browser_seek) override; | 241 bool is_browser_seek) override; |
242 | 242 |
243 // Sets the audio data factory. | 243 // Sets the audio data factory. |
244 void SetAudioFactory(scoped_ptr<AudioFactory> factory) { | 244 void SetAudioFactory(scoped_ptr<AudioFactory> factory) { |
245 audio_factory_ = factory.Pass(); | 245 audio_factory_ = factory.Pass(); |
246 } | 246 } |
247 | 247 |
248 // Sets the video data factory. | 248 // Sets the video data factory. |
249 void SetVideoFactory(scoped_ptr<VideoFactory> factory) { | 249 void SetVideoFactory(scoped_ptr<VideoFactory> factory) { |
250 video_factory_ = factory.Pass(); | 250 video_factory_ = factory.Pass(); |
251 } | 251 } |
252 | 252 |
| 253 // Set the preroll interval after seek for audio stream. |
| 254 void SetAudioPrerollInterval(base::TimeDelta value) { |
| 255 audio_preroll_interval_ = value; |
| 256 } |
| 257 |
| 258 // Set the preroll interval after seek for video stream. |
| 259 void SetVideoPrerollInterval(base::TimeDelta value) { |
| 260 video_preroll_interval_ = value; |
| 261 } |
| 262 |
253 // Sets the delay in OnDemuxerSeekDone response. | 263 // Sets the delay in OnDemuxerSeekDone response. |
254 void SetSeekDoneDelay(base::TimeDelta delay) { seek_done_delay_ = delay; } | 264 void SetSeekDoneDelay(base::TimeDelta delay) { seek_done_delay_ = delay; } |
255 | 265 |
256 // Post DemuxerConfigs to the client (i.e. the player) on correct thread. | 266 // Post DemuxerConfigs to the client (i.e. the player) on correct thread. |
257 void PostConfigs(const DemuxerConfigs& configs); | 267 void PostConfigs(const DemuxerConfigs& configs); |
258 | 268 |
259 // Post DemuxerConfigs derived from data factories that has been set. | 269 // Post DemuxerConfigs derived from data factories that has been set. |
260 void PostInternalConfigs(); | 270 void PostInternalConfigs(); |
261 | 271 |
262 // Conditions to wait for. | 272 // Conditions to wait for. |
263 bool IsInitialized() const { return client_; } | 273 bool IsInitialized() const { return client_; } |
264 bool HasPendingConfigs() const { return pending_configs_; } | 274 bool HasPendingConfigs() const { return pending_configs_; } |
265 bool ReceivedSeekRequest() const { return num_seeks_ > 0; } | 275 bool ReceivedSeekRequest() const { return num_seeks_ > 0; } |
266 bool ReceivedBrowserSeekRequest() const { return num_browser_seeks_ > 0; } | 276 bool ReceivedBrowserSeekRequest() const { return num_browser_seeks_ > 0; } |
267 | 277 |
268 private: | 278 private: |
269 DemuxerAndroidClient* client_; | 279 DemuxerAndroidClient* client_; |
270 scoped_ptr<DemuxerConfigs> pending_configs_; | 280 scoped_ptr<DemuxerConfigs> pending_configs_; |
271 scoped_ptr<AudioFactory> audio_factory_; | 281 scoped_ptr<AudioFactory> audio_factory_; |
272 scoped_ptr<VideoFactory> video_factory_; | 282 scoped_ptr<VideoFactory> video_factory_; |
| 283 base::TimeDelta audio_preroll_interval_; |
| 284 base::TimeDelta video_preroll_interval_; |
273 base::TimeDelta seek_done_delay_; | 285 base::TimeDelta seek_done_delay_; |
274 int num_seeks_; | 286 int num_seeks_; |
275 int num_browser_seeks_; | 287 int num_browser_seeks_; |
276 | 288 |
277 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); | 289 DISALLOW_COPY_AND_ASSIGN(MockDemuxerAndroid); |
278 }; | 290 }; |
279 | 291 |
280 void MockDemuxerAndroid::Initialize(DemuxerAndroidClient* client) { | 292 void MockDemuxerAndroid::Initialize(DemuxerAndroidClient* client) { |
281 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; | 293 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; |
282 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); | 294 DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
(...skipping 19 matching lines...) Expand all Loading... |
302 chunk.type = type; | 314 chunk.type = type; |
303 | 315 |
304 // Post to Media thread. | 316 // Post to Media thread. |
305 DCHECK(client_); | 317 DCHECK(client_); |
306 GetMediaTaskRunner()->PostDelayedTask( | 318 GetMediaTaskRunner()->PostDelayedTask( |
307 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable, | 319 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerDataAvailable, |
308 base::Unretained(client_), chunk), | 320 base::Unretained(client_), chunk), |
309 delay); | 321 delay); |
310 } | 322 } |
311 | 323 |
312 void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& time_to_seek, | 324 void MockDemuxerAndroid::RequestDemuxerSeek(const base::TimeDelta& seek_request, |
313 bool is_browser_seek) { | 325 bool is_browser_seek) { |
314 // Tell data factories to start next chunk with the new timestamp. | 326 // Tell data factories to start next chunk with the new timestamp. |
315 if (audio_factory_) | 327 if (audio_factory_) { |
| 328 base::TimeDelta time_to_seek = |
| 329 std::max(base::TimeDelta(), seek_request - audio_preroll_interval_); |
316 audio_factory_->SeekTo(time_to_seek); | 330 audio_factory_->SeekTo(time_to_seek); |
| 331 } |
317 if (video_factory_) { | 332 if (video_factory_) { |
| 333 base::TimeDelta time_to_seek = |
| 334 std::max(base::TimeDelta(), seek_request - video_preroll_interval_); |
318 video_factory_->SeekTo(time_to_seek); | 335 video_factory_->SeekTo(time_to_seek); |
319 video_factory_->RequestKeyFrame(); | 336 video_factory_->RequestKeyFrame(); |
320 } | 337 } |
321 | 338 |
322 ++num_seeks_; | 339 ++num_seeks_; |
323 if (is_browser_seek) | 340 if (is_browser_seek) |
324 ++num_browser_seeks_; | 341 ++num_browser_seeks_; |
325 | 342 |
326 // Post OnDemuxerSeekDone() to the player. | 343 // Post OnDemuxerSeekDone() to the player. |
327 DCHECK(client_); | 344 DCHECK(client_); |
328 base::TimeDelta reported_seek_time = | 345 base::TimeDelta reported_seek_time = |
329 is_browser_seek ? time_to_seek : kNoTimestamp(); | 346 is_browser_seek ? seek_request : kNoTimestamp(); |
330 GetMediaTaskRunner()->PostDelayedTask( | 347 GetMediaTaskRunner()->PostDelayedTask( |
331 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone, | 348 FROM_HERE, base::Bind(&DemuxerAndroidClient::OnDemuxerSeekDone, |
332 base::Unretained(client_), reported_seek_time), | 349 base::Unretained(client_), reported_seek_time), |
333 seek_done_delay_); | 350 seek_done_delay_); |
334 } | 351 } |
335 | 352 |
336 void MockDemuxerAndroid::PostConfigs(const DemuxerConfigs& configs) { | 353 void MockDemuxerAndroid::PostConfigs(const DemuxerConfigs& configs) { |
337 RUN_ON_MEDIA_THREAD(MockDemuxerAndroid, PostConfigs, configs); | 354 RUN_ON_MEDIA_THREAD(MockDemuxerAndroid, PostConfigs, configs); |
338 | 355 |
339 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; | 356 DVLOG(1) << "MockDemuxerAndroid::" << __FUNCTION__; |
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1048 reconfigure_timeout)); | 1065 reconfigure_timeout)); |
1049 | 1066 |
1050 // Timestamps should start at the new seek position | 1067 // Timestamps should start at the new seek position |
1051 EXPECT_LE(seek_position, manager_.pts_stat_.min()); | 1068 EXPECT_LE(seek_position, manager_.pts_stat_.min()); |
1052 | 1069 |
1053 // The player should have reported the seek completion to the manager. | 1070 // The player should have reported the seek completion to the manager. |
1054 EXPECT_TRUE(WaitForCondition(base::Bind( | 1071 EXPECT_TRUE(WaitForCondition(base::Bind( |
1055 &MockMediaPlayerManager::IsSeekCompleted, base::Unretained(&manager_)))); | 1072 &MockMediaPlayerManager::IsSeekCompleted, base::Unretained(&manager_)))); |
1056 } | 1073 } |
1057 | 1074 |
| 1075 TEST_F(MediaCodecPlayerTest, VideoPrerollAfterSeek) { |
| 1076 SKIP_TEST_IF_MEDIA_CODEC_BRIDGE_IS_NOT_AVAILABLE(); |
| 1077 |
| 1078 // A simple test for preroll for video stream only. After the seek is done |
| 1079 // the data factory generates the frames with pts before the seek time, and |
| 1080 // they should not be rendered. We deduce which frame is rendered by looking |
| 1081 // at the reported time progress. |
| 1082 |
| 1083 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(600); |
| 1084 base::TimeDelta seek_position = base::TimeDelta::FromMilliseconds(500); |
| 1085 base::TimeDelta start_timeout = base::TimeDelta::FromMilliseconds(800); |
| 1086 |
| 1087 // Tell demuxer to make the first frame 100ms earlier than the seek request. |
| 1088 demuxer_->SetVideoPrerollInterval(base::TimeDelta::FromMilliseconds(100)); |
| 1089 |
| 1090 demuxer_->SetVideoFactory( |
| 1091 scoped_ptr<VideoFactory>(new VideoFactory(duration))); |
| 1092 |
| 1093 CreatePlayer(); |
| 1094 SetVideoSurface(); |
| 1095 |
| 1096 // Wait till the player is initialized on media thread. |
| 1097 EXPECT_TRUE(WaitForCondition(base::Bind(&MockDemuxerAndroid::IsInitialized, |
| 1098 base::Unretained(demuxer_)))); |
| 1099 |
| 1100 // Post configuration after the player has been initialized. |
| 1101 demuxer_->PostInternalConfigs(); |
| 1102 |
| 1103 // Issue SeekTo(). |
| 1104 player_->SeekTo(seek_position); |
| 1105 |
| 1106 // Start the playback and make sure it is started. |
| 1107 player_->Start(); |
| 1108 |
| 1109 EXPECT_TRUE( |
| 1110 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackStarted, |
| 1111 base::Unretained(&manager_)), |
| 1112 start_timeout)); |
| 1113 |
| 1114 // Wait for completion. |
| 1115 EXPECT_TRUE( |
| 1116 WaitForCondition(base::Bind(&MockMediaPlayerManager::IsPlaybackCompleted, |
| 1117 base::Unretained(&manager_)))); |
| 1118 |
| 1119 // The first pts should be equal than seek position even if video frames |
| 1120 // started 100 ms eralier than the seek request. |
| 1121 EXPECT_EQ(seek_position, manager_.pts_stat_.min()); |
| 1122 |
| 1123 EXPECT_EQ(6, manager_.pts_stat_.num_values()); |
| 1124 } |
| 1125 |
1058 } // namespace media | 1126 } // namespace media |
OLD | NEW |