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

Side by Side Diff: media/base/pipeline.cc

Issue 9155003: Fix media timeline so that thumb never exceeds buffered data (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 11 months 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "media/base/pipeline.h" 5 #include "media/base/pipeline.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 } 214 }
215 } 215 }
216 216
217 base::TimeDelta Pipeline::GetCurrentTime() const { 217 base::TimeDelta Pipeline::GetCurrentTime() const {
218 base::AutoLock auto_lock(lock_); 218 base::AutoLock auto_lock(lock_);
219 return GetCurrentTime_Locked(); 219 return GetCurrentTime_Locked();
220 } 220 }
221 221
222 base::TimeDelta Pipeline::GetCurrentTime_Locked() const { 222 base::TimeDelta Pipeline::GetCurrentTime_Locked() const {
223 lock_.AssertAcquired(); 223 lock_.AssertAcquired();
224 base::TimeDelta elapsed = clock_->Elapsed(); 224 return clock_->Elapsed();
225 if (elapsed > duration_)
226 return duration_;
227
228 return elapsed;
229 } 225 }
230 226
231 base::TimeDelta Pipeline::GetBufferedTime() { 227 base::TimeDelta Pipeline::GetBufferedTime() {
232 base::AutoLock auto_lock(lock_); 228 base::AutoLock auto_lock(lock_);
233 229
234 // If media is fully loaded, then return duration. 230 // If media is fully loaded, then return duration.
235 if (local_source_ || total_bytes_ == buffered_bytes_) { 231 if (local_source_ || total_bytes_ == buffered_bytes_) {
236 max_buffered_time_ = duration_; 232 max_buffered_time_ = clock_->Duration();
237 return duration_; 233 return max_buffered_time_;
238 } 234 }
239 235
240 base::TimeDelta current_time = GetCurrentTime_Locked(); 236 base::TimeDelta current_time = GetCurrentTime_Locked();
241 237
242 // If buffered time was set, we report that value directly. 238 // If buffered time was set, we report that value directly.
243 if (buffered_time_.ToInternalValue() > 0) 239 if (buffered_time_.ToInternalValue() > 0)
244 return std::max(buffered_time_, current_time); 240 return std::max(buffered_time_, current_time);
245 241
246 if (total_bytes_ == 0) 242 if (total_bytes_ == 0)
247 return base::TimeDelta(); 243 return base::TimeDelta();
248 244
249 // If buffered time was not set, we use current time, current bytes, and 245 // If buffered time was not set, we use current time, current bytes, and
250 // buffered bytes to estimate the buffered time. 246 // buffered bytes to estimate the buffered time.
251 double estimated_rate = duration_.InMillisecondsF() / total_bytes_; 247 double estimated_rate =
248 clock_->Duration().InMillisecondsF() / total_bytes_;
252 double estimated_current_time = estimated_rate * current_bytes_; 249 double estimated_current_time = estimated_rate * current_bytes_;
253 DCHECK_GE(buffered_bytes_, current_bytes_); 250 DCHECK_GE(buffered_bytes_, current_bytes_);
254 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds( 251 base::TimeDelta buffered_time = base::TimeDelta::FromMilliseconds(
255 static_cast<int64>(estimated_rate * (buffered_bytes_ - current_bytes_) + 252 static_cast<int64>(estimated_rate * (buffered_bytes_ - current_bytes_) +
256 estimated_current_time)); 253 estimated_current_time));
257 254
258 // Cap approximated buffered time at the length of the video. 255 // Cap approximated buffered time at the length of the video.
259 buffered_time = std::min(buffered_time, duration_); 256 buffered_time = std::min(buffered_time, clock_->Duration());
260 257
261 // Make sure buffered_time is at least the current time 258 // Make sure buffered_time is at least the current time
262 buffered_time = std::max(buffered_time, current_time); 259 buffered_time = std::max(buffered_time, current_time);
263 260
264 // Only print the max buffered time for smooth buffering. 261 // Only print the max buffered time for smooth buffering.
265 max_buffered_time_ = std::max(buffered_time, max_buffered_time_); 262 max_buffered_time_ = std::max(buffered_time, max_buffered_time_);
266 263
267 return max_buffered_time_; 264 return max_buffered_time_;
268 } 265 }
269 266
270 base::TimeDelta Pipeline::GetMediaDuration() const { 267 base::TimeDelta Pipeline::GetMediaDuration() const {
271 base::AutoLock auto_lock(lock_); 268 base::AutoLock auto_lock(lock_);
272 return duration_; 269 return clock_->Duration();
273 } 270 }
274 271
275 int64 Pipeline::GetBufferedBytes() const { 272 int64 Pipeline::GetBufferedBytes() const {
276 base::AutoLock auto_lock(lock_); 273 base::AutoLock auto_lock(lock_);
277 return buffered_bytes_; 274 return buffered_bytes_;
278 } 275 }
279 276
280 int64 Pipeline::GetTotalBytes() const { 277 int64 Pipeline::GetTotalBytes() const {
281 base::AutoLock auto_lock(lock_); 278 base::AutoLock auto_lock(lock_);
282 return total_bytes_; 279 return total_bytes_;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 320
324 void Pipeline::ResetState() { 321 void Pipeline::ResetState() {
325 base::AutoLock auto_lock(lock_); 322 base::AutoLock auto_lock(lock_);
326 const base::TimeDelta kZero; 323 const base::TimeDelta kZero;
327 running_ = false; 324 running_ = false;
328 stop_pending_ = false; 325 stop_pending_ = false;
329 seek_pending_ = false; 326 seek_pending_ = false;
330 tearing_down_ = false; 327 tearing_down_ = false;
331 error_caused_teardown_ = false; 328 error_caused_teardown_ = false;
332 playback_rate_change_pending_ = false; 329 playback_rate_change_pending_ = false;
333 duration_ = kZero;
334 buffered_time_ = kZero; 330 buffered_time_ = kZero;
335 buffered_bytes_ = 0; 331 buffered_bytes_ = 0;
336 streaming_ = false; 332 streaming_ = false;
337 local_source_ = false; 333 local_source_ = false;
338 total_bytes_ = 0; 334 total_bytes_ = 0;
339 natural_size_.SetSize(0, 0); 335 natural_size_.SetSize(0, 0);
340 volume_ = 1.0f; 336 volume_ = 1.0f;
341 preload_ = AUTO; 337 preload_ = AUTO;
342 playback_rate_ = 0.0f; 338 playback_rate_ = 0.0f;
343 pending_playback_rate_ = 0.0f; 339 pending_playback_rate_ = 0.0f;
344 status_ = PIPELINE_OK; 340 status_ = PIPELINE_OK;
345 has_audio_ = false; 341 has_audio_ = false;
346 has_video_ = false; 342 has_video_ = false;
347 waiting_for_clock_update_ = false; 343 waiting_for_clock_update_ = false;
348 audio_disabled_ = false; 344 audio_disabled_ = false;
349 clock_->SetTime(kZero); 345 clock_->Reset();
350 download_rate_monitor_.Reset(); 346 download_rate_monitor_.Reset();
351 } 347 }
352 348
353 void Pipeline::SetState(State next_state) { 349 void Pipeline::SetState(State next_state) {
354 if (state_ != kStarted && next_state == kStarted && 350 if (state_ != kStarted && next_state == kStarted &&
355 !creation_time_.is_null()) { 351 !creation_time_.is_null()) {
356 UMA_HISTOGRAM_TIMES( 352 UMA_HISTOGRAM_TIMES(
357 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_); 353 "Media.TimeToPipelineStarted", base::Time::Now() - creation_time_);
358 creation_time_ = base::Time(); 354 creation_time_ = base::Time();
359 } 355 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 base::TimeDelta Pipeline::GetTime() const { 447 base::TimeDelta Pipeline::GetTime() const {
452 DCHECK(IsRunning()); 448 DCHECK(IsRunning());
453 return GetCurrentTime(); 449 return GetCurrentTime();
454 } 450 }
455 451
456 base::TimeDelta Pipeline::GetDuration() const { 452 base::TimeDelta Pipeline::GetDuration() const {
457 DCHECK(IsRunning()); 453 DCHECK(IsRunning());
458 return GetMediaDuration(); 454 return GetMediaDuration();
459 } 455 }
460 456
461 void Pipeline::SetTime(base::TimeDelta time) { 457 void Pipeline::OnAudioTimeUpdate(base::TimeDelta time,
458 base::TimeDelta max_time) {
459 DCHECK(time <= max_time);
462 DCHECK(IsRunning()); 460 DCHECK(IsRunning());
463 base::AutoLock auto_lock(lock_); 461 base::AutoLock auto_lock(lock_);
464 462
465 // If we were waiting for a valid timestamp and such timestamp arrives, we 463 if (!has_audio_)
466 // need to clear the flag for waiting and start the clock.
467 if (waiting_for_clock_update_) {
468 if (time < clock_->Elapsed())
469 return;
470 clock_->SetTime(time);
471 StartClockIfWaitingForTimeUpdate_Locked();
472 return; 464 return;
473 } 465 if (waiting_for_clock_update_ && time < clock_->Elapsed())
474 clock_->SetTime(time); 466 return;
467
468 clock_->SetTime(time, max_time);
469 StartClockIfWaitingForTimeUpdate_Locked();
470 }
471
472 void Pipeline::OnVideoTimeUpdate(base::TimeDelta max_time) {
473 DCHECK(IsRunning());
474 base::AutoLock auto_lock(lock_);
475
476 if (has_audio_)
477 return;
478
479 DCHECK(!waiting_for_clock_update_);
480 DCHECK(clock_->Elapsed() <= max_time);
481 clock_->SetMaxTime(max_time);
475 } 482 }
476 483
477 void Pipeline::SetDuration(base::TimeDelta duration) { 484 void Pipeline::SetDuration(base::TimeDelta duration) {
478 DCHECK(IsRunning()); 485 DCHECK(IsRunning());
479 media_log_->AddEvent( 486 media_log_->AddEvent(
480 media_log_->CreateTimeEvent( 487 media_log_->CreateTimeEvent(
481 MediaLogEvent::DURATION_SET, "duration", duration)); 488 MediaLogEvent::DURATION_SET, "duration", duration));
482 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); 489 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration);
483 490
484 base::AutoLock auto_lock(lock_); 491 base::AutoLock auto_lock(lock_);
485 duration_ = duration; 492 clock_->SetDuration(duration);
486 } 493 }
487 494
488 void Pipeline::SetBufferedTime(base::TimeDelta buffered_time) { 495 void Pipeline::SetBufferedTime(base::TimeDelta buffered_time) {
489 DCHECK(IsRunning()); 496 DCHECK(IsRunning());
490 base::AutoLock auto_lock(lock_); 497 base::AutoLock auto_lock(lock_);
491 buffered_time_ = buffered_time; 498 buffered_time_ = buffered_time;
492 } 499 }
493 500
494 void Pipeline::SetTotalBytes(int64 total_bytes) { 501 void Pipeline::SetTotalBytes(int64 total_bytes) {
495 DCHECK(IsRunning()); 502 DCHECK(IsRunning());
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 } 915 }
909 916
910 if (video_renderer_ && !video_renderer_->HasEnded()) { 917 if (video_renderer_ && !video_renderer_->HasEnded()) {
911 return; 918 return;
912 } 919 }
913 920
914 // Transition to ended, executing the callback if present. 921 // Transition to ended, executing the callback if present.
915 SetState(kEnded); 922 SetState(kEnded);
916 { 923 {
917 base::AutoLock auto_lock(lock_); 924 base::AutoLock auto_lock(lock_);
918 clock_->Pause(); 925 clock_->EndOfStream();
919 clock_->SetTime(duration_);
920 } 926 }
921 927
922 if (!ended_callback_.is_null()) { 928 if (!ended_callback_.is_null()) {
923 ended_callback_.Run(status_); 929 ended_callback_.Run(status_);
924 } 930 }
925 } 931 }
926 932
927 void Pipeline::NotifyNetworkEventTask(NetworkEvent type) { 933 void Pipeline::NotifyNetworkEventTask(NetworkEvent type) {
928 DCHECK_EQ(MessageLoop::current(), message_loop_); 934 DCHECK_EQ(MessageLoop::current(), message_loop_);
929 if (!network_callback_.is_null()) 935 if (!network_callback_.is_null())
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 NOTREACHED() << "Invalid current state: " << state_; 975 NOTREACHED() << "Invalid current state: " << state_;
970 SetError(PIPELINE_ERROR_ABORT); 976 SetError(PIPELINE_ERROR_ABORT);
971 return; 977 return;
972 } 978 }
973 979
974 // Decrement the number of remaining transitions, making sure to transition 980 // Decrement the number of remaining transitions, making sure to transition
975 // to the next state if needed. 981 // to the next state if needed.
976 SetState(FindNextState(state_)); 982 SetState(FindNextState(state_));
977 if (state_ == kSeeking) { 983 if (state_ == kSeeking) {
978 base::AutoLock auto_lock(lock_); 984 base::AutoLock auto_lock(lock_);
979 clock_->SetTime(seek_timestamp_); 985 clock_->SetTime(seek_timestamp_, seek_timestamp_);
980 } 986 }
981 987
982 // Carry out the action for the current state. 988 // Carry out the action for the current state.
983 if (TransientState(state_)) { 989 if (TransientState(state_)) {
984 if (state_ == kPausing) { 990 if (state_ == kPausing) {
985 pipeline_filter_->Pause( 991 pipeline_filter_->Pause(
986 base::Bind(&Pipeline::OnFilterStateTransition, this)); 992 base::Bind(&Pipeline::OnFilterStateTransition, this));
987 } else if (state_ == kFlushing) { 993 } else if (state_ == kFlushing) {
988 pipeline_filter_->Flush( 994 pipeline_filter_->Flush(
989 base::Bind(&Pipeline::OnFilterStateTransition, this)); 995 base::Bind(&Pipeline::OnFilterStateTransition, this));
(...skipping 18 matching lines...) Expand all
1008 // the seek has compelted. 1014 // the seek has compelted.
1009 if (playback_rate_change_pending_) { 1015 if (playback_rate_change_pending_) {
1010 playback_rate_change_pending_ = false; 1016 playback_rate_change_pending_ = false;
1011 PlaybackRateChangedTask(pending_playback_rate_); 1017 PlaybackRateChangedTask(pending_playback_rate_);
1012 } 1018 }
1013 1019
1014 base::AutoLock auto_lock(lock_); 1020 base::AutoLock auto_lock(lock_);
1015 // We use audio stream to update the clock. So if there is such a stream, 1021 // We use audio stream to update the clock. So if there is such a stream,
1016 // we pause the clock until we receive a valid timestamp. 1022 // we pause the clock until we receive a valid timestamp.
1017 waiting_for_clock_update_ = true; 1023 waiting_for_clock_update_ = true;
1018 if (!has_audio_) 1024 if (!has_audio_) {
1025 clock_->SetMaxTime(clock_->Duration());
1019 StartClockIfWaitingForTimeUpdate_Locked(); 1026 StartClockIfWaitingForTimeUpdate_Locked();
1027 }
1020 1028
1021 // Start monitoring rate of downloading. 1029 // Start monitoring rate of downloading.
1022 int bitrate = 0; 1030 int bitrate = 0;
1023 if (demuxer_.get()) { 1031 if (demuxer_.get()) {
1024 bitrate = demuxer_->GetBitrate(); 1032 bitrate = demuxer_->GetBitrate();
1025 local_source_ = demuxer_->IsLocalSource(); 1033 local_source_ = demuxer_->IsLocalSource();
1026 streaming_ = !demuxer_->IsSeekable(); 1034 streaming_ = !demuxer_->IsSeekable();
1027 } 1035 }
1028 // Needs to be locked because most other calls to |download_rate_monitor_| 1036 // Needs to be locked because most other calls to |download_rate_monitor_|
1029 // occur on the renderer thread. 1037 // occur on the renderer thread.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1138 return; 1146 return;
1139 } 1147 }
1140 1148
1141 demuxer_ = demuxer; 1149 demuxer_ = demuxer;
1142 demuxer_->set_host(this); 1150 demuxer_->set_host(this);
1143 1151
1144 { 1152 {
1145 base::AutoLock auto_lock(lock_); 1153 base::AutoLock auto_lock(lock_);
1146 // We do not want to start the clock running. We only want to set the base 1154 // We do not want to start the clock running. We only want to set the base
1147 // media time so our timestamp calculations will be correct. 1155 // media time so our timestamp calculations will be correct.
1148 clock_->SetTime(demuxer_->GetStartTime()); 1156 clock_->SetTime(demuxer_->GetStartTime(), demuxer_->GetStartTime());
1149 } 1157 }
1150 1158
1151 OnFilterInitialize(PIPELINE_OK); 1159 OnFilterInitialize(PIPELINE_OK);
1152 } 1160 }
1153 1161
1154 bool Pipeline::InitializeAudioDecoder( 1162 bool Pipeline::InitializeAudioDecoder(
1155 const scoped_refptr<Demuxer>& demuxer) { 1163 const scoped_refptr<Demuxer>& demuxer) {
1156 DCHECK_EQ(MessageLoop::current(), message_loop_); 1164 DCHECK_EQ(MessageLoop::current(), message_loop_);
1157 DCHECK(IsPipelineOk()); 1165 DCHECK(IsPipelineOk());
1158 1166
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); 1234 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING);
1227 return false; 1235 return false;
1228 } 1236 }
1229 1237
1230 if (!PrepareFilter(audio_renderer_)) 1238 if (!PrepareFilter(audio_renderer_))
1231 return false; 1239 return false;
1232 1240
1233 audio_renderer_->Initialize( 1241 audio_renderer_->Initialize(
1234 decoder, 1242 decoder,
1235 base::Bind(&Pipeline::OnFilterInitialize, this, PIPELINE_OK), 1243 base::Bind(&Pipeline::OnFilterInitialize, this, PIPELINE_OK),
1236 base::Bind(&Pipeline::OnAudioUnderflow, this)); 1244 base::Bind(&Pipeline::OnAudioUnderflow, this),
1245 base::Bind(&Pipeline::OnAudioTimeUpdate, this));
1246
1237 return true; 1247 return true;
1238 } 1248 }
1239 1249
1240 bool Pipeline::InitializeVideoRenderer( 1250 bool Pipeline::InitializeVideoRenderer(
1241 const scoped_refptr<VideoDecoder>& decoder) { 1251 const scoped_refptr<VideoDecoder>& decoder) {
1242 DCHECK_EQ(MessageLoop::current(), message_loop_); 1252 DCHECK_EQ(MessageLoop::current(), message_loop_);
1243 DCHECK(IsPipelineOk()); 1253 DCHECK(IsPipelineOk());
1244 1254
1245 if (!decoder) 1255 if (!decoder)
1246 return false; 1256 return false;
1247 1257
1248 filter_collection_->SelectVideoRenderer(&video_renderer_); 1258 filter_collection_->SelectVideoRenderer(&video_renderer_);
1249 if (!video_renderer_) { 1259 if (!video_renderer_) {
1250 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING); 1260 SetError(PIPELINE_ERROR_REQUIRED_FILTER_MISSING);
1251 return false; 1261 return false;
1252 } 1262 }
1253 1263
1254 if (!PrepareFilter(video_renderer_)) 1264 if (!PrepareFilter(video_renderer_))
1255 return false; 1265 return false;
1256 1266
1257 video_renderer_->Initialize( 1267 video_renderer_->Initialize(
1258 decoder, 1268 decoder,
1259 base::Bind(&Pipeline::OnFilterInitialize, this, PIPELINE_OK), 1269 base::Bind(&Pipeline::OnFilterInitialize, this, PIPELINE_OK),
1260 base::Bind(&Pipeline::OnUpdateStatistics, this)); 1270 base::Bind(&Pipeline::OnUpdateStatistics, this),
1271 base::Bind(&Pipeline::OnVideoTimeUpdate, this));
1261 return true; 1272 return true;
1262 } 1273 }
1263 1274
1264 void Pipeline::TearDownPipeline() { 1275 void Pipeline::TearDownPipeline() {
1265 DCHECK_EQ(MessageLoop::current(), message_loop_); 1276 DCHECK_EQ(MessageLoop::current(), message_loop_);
1266 DCHECK_NE(kStopped, state_); 1277 DCHECK_NE(kStopped, state_);
1267 1278
1268 DCHECK(!tearing_down_ || // Teardown on Stop(). 1279 DCHECK(!tearing_down_ || // Teardown on Stop().
1269 (tearing_down_ && error_caused_teardown_) || // Teardown on error. 1280 (tearing_down_ && error_caused_teardown_) || // Teardown on error.
1270 (tearing_down_ && stop_pending_)); // Stop during teardown by error. 1281 (tearing_down_ && stop_pending_)); // Stop during teardown by error.
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
1413 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { 1424 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() {
1414 lock_.AssertAcquired(); 1425 lock_.AssertAcquired();
1415 if (!waiting_for_clock_update_) 1426 if (!waiting_for_clock_update_)
1416 return; 1427 return;
1417 1428
1418 waiting_for_clock_update_ = false; 1429 waiting_for_clock_update_ = false;
1419 clock_->Play(); 1430 clock_->Play();
1420 } 1431 }
1421 1432
1422 } // namespace media 1433 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698