Chromium Code Reviews| OLD | NEW |
|---|---|
| 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" |
| 11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/synchronization/condition_variable.h" | 17 #include "base/synchronization/condition_variable.h" |
| 18 #include "media/base/audio_decoder.h" | 18 #include "media/base/audio_decoder.h" |
| 19 #include "media/base/audio_renderer.h" | 19 #include "media/base/audio_renderer.h" |
| 20 #include "media/base/clock.h" | 20 #include "media/base/clock.h" |
| 21 #include "media/base/composite_filter.h" | 21 #include "media/base/composite_filter.h" |
| 22 #include "media/base/filter_collection.h" | 22 #include "media/base/filter_collection.h" |
| 23 #include "media/base/media_log.h" | 23 #include "media/base/media_log.h" |
| 24 #include "media/base/video_decoder.h" | 24 #include "media/base/video_decoder.h" |
| 25 #include "media/base/video_renderer.h" | 25 #include "media/base/video_renderer.h" |
| 26 | 26 |
| 27 using base::TimeDelta; | |
| 28 | |
| 27 namespace media { | 29 namespace media { |
| 28 | 30 |
| 29 PipelineStatusNotification::PipelineStatusNotification() | 31 PipelineStatusNotification::PipelineStatusNotification() |
| 30 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { | 32 : cv_(&lock_), status_(PIPELINE_OK), notified_(false) { |
| 31 } | 33 } |
| 32 | 34 |
| 33 PipelineStatusNotification::~PipelineStatusNotification() { | 35 PipelineStatusNotification::~PipelineStatusNotification() { |
| 34 DCHECK(notified_); | 36 DCHECK(notified_); |
| 35 } | 37 } |
| 36 | 38 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 | 109 |
| 108 void Pipeline::Stop(const base::Closure& stop_cb) { | 110 void Pipeline::Stop(const base::Closure& stop_cb) { |
| 109 base::AutoLock auto_lock(lock_); | 111 base::AutoLock auto_lock(lock_); |
| 110 CHECK(running_) << "Media pipeline isn't running"; | 112 CHECK(running_) << "Media pipeline isn't running"; |
| 111 | 113 |
| 112 // Stop the pipeline, which will set |running_| to false on our behalf. | 114 // Stop the pipeline, which will set |running_| to false on our behalf. |
| 113 message_loop_->PostTask(FROM_HERE, base::Bind( | 115 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 114 &Pipeline::StopTask, this, stop_cb)); | 116 &Pipeline::StopTask, this, stop_cb)); |
| 115 } | 117 } |
| 116 | 118 |
| 117 void Pipeline::Seek(base::TimeDelta time, | 119 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 118 const PipelineStatusCB& seek_cb) { | |
| 119 base::AutoLock auto_lock(lock_); | 120 base::AutoLock auto_lock(lock_); |
| 120 CHECK(running_) << "Media pipeline isn't running"; | 121 CHECK(running_) << "Media pipeline isn't running"; |
| 121 | 122 |
| 122 message_loop_->PostTask(FROM_HERE, base::Bind( | 123 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 123 &Pipeline::SeekTask, this, time, seek_cb)); | 124 &Pipeline::SeekTask, this, time, seek_cb)); |
| 124 } | 125 } |
| 125 | 126 |
| 126 bool Pipeline::IsRunning() const { | 127 bool Pipeline::IsRunning() const { |
| 127 base::AutoLock auto_lock(lock_); | 128 base::AutoLock auto_lock(lock_); |
| 128 return running_; | 129 return running_; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 183 return; | 184 return; |
| 184 | 185 |
| 185 base::AutoLock auto_lock(lock_); | 186 base::AutoLock auto_lock(lock_); |
| 186 volume_ = volume; | 187 volume_ = volume; |
| 187 if (running_ && !tearing_down_) { | 188 if (running_ && !tearing_down_) { |
| 188 message_loop_->PostTask(FROM_HERE, base::Bind( | 189 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 189 &Pipeline::VolumeChangedTask, this, volume)); | 190 &Pipeline::VolumeChangedTask, this, volume)); |
| 190 } | 191 } |
| 191 } | 192 } |
| 192 | 193 |
| 193 base::TimeDelta Pipeline::GetCurrentTime() const { | 194 TimeDelta Pipeline::GetCurrentTime() const { |
| 194 base::AutoLock auto_lock(lock_); | 195 base::AutoLock auto_lock(lock_); |
| 195 return GetCurrentTime_Locked(); | 196 return GetCurrentTime_Locked(); |
| 196 } | 197 } |
| 197 | 198 |
| 198 base::TimeDelta Pipeline::GetCurrentTime_Locked() const { | 199 TimeDelta Pipeline::GetCurrentTime_Locked() const { |
| 199 lock_.AssertAcquired(); | 200 lock_.AssertAcquired(); |
| 200 return clock_->Elapsed(); | 201 return clock_->Elapsed(); |
| 201 } | 202 } |
| 202 | 203 |
| 203 Ranges<base::TimeDelta> Pipeline::GetBufferedTimeRanges() { | 204 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() { |
| 204 base::AutoLock auto_lock(lock_); | 205 base::AutoLock auto_lock(lock_); |
| 205 return buffered_time_ranges_; | 206 return buffered_time_ranges_; |
|
scherkus (not reviewing)
2012/05/29 18:13:29
would it be simpler to compute buffered_time_range
Ami GONE FROM CHROMIUM
2012/05/29 20:45:44
Hmm; that does indeed simplify the code. There is
| |
| 206 } | 207 } |
| 207 | 208 |
| 208 base::TimeDelta Pipeline::GetMediaDuration() const { | 209 TimeDelta Pipeline::GetMediaDuration() const { |
| 209 base::AutoLock auto_lock(lock_); | 210 base::AutoLock auto_lock(lock_); |
| 210 return clock_->Duration(); | 211 return clock_->Duration(); |
| 211 } | 212 } |
| 212 | 213 |
| 213 int64 Pipeline::GetBufferedBytes() const { | 214 int64 Pipeline::GetBufferedBytes() const { |
| 214 base::AutoLock auto_lock(lock_); | 215 base::AutoLock auto_lock(lock_); |
| 215 return buffered_bytes_; | 216 int64 ret = 0; |
| 217 for (size_t i = 0; i < buffered_byte_ranges_.size(); ++i) | |
| 218 ret += buffered_byte_ranges_.end(i) - buffered_byte_ranges_.start(i); | |
| 219 return ret; | |
| 216 } | 220 } |
| 217 | 221 |
| 218 int64 Pipeline::GetTotalBytes() const { | 222 int64 Pipeline::GetTotalBytes() const { |
| 219 base::AutoLock auto_lock(lock_); | 223 base::AutoLock auto_lock(lock_); |
| 220 return total_bytes_; | 224 return total_bytes_; |
| 221 } | 225 } |
| 222 | 226 |
| 223 void Pipeline::GetNaturalVideoSize(gfx::Size* out_size) const { | 227 void Pipeline::GetNaturalVideoSize(gfx::Size* out_size) const { |
| 224 CHECK(out_size); | 228 CHECK(out_size); |
| 225 base::AutoLock auto_lock(lock_); | 229 base::AutoLock auto_lock(lock_); |
| 226 *out_size = natural_size_; | 230 *out_size = natural_size_; |
| 227 } | 231 } |
| 228 | 232 |
| 229 PipelineStatistics Pipeline::GetStatistics() const { | 233 PipelineStatistics Pipeline::GetStatistics() const { |
| 230 base::AutoLock auto_lock(lock_); | 234 base::AutoLock auto_lock(lock_); |
| 231 return statistics_; | 235 return statistics_; |
| 232 } | 236 } |
| 233 | 237 |
| 234 void Pipeline::SetClockForTesting(Clock* clock) { | 238 void Pipeline::SetClockForTesting(Clock* clock) { |
| 235 clock_.reset(clock); | 239 clock_.reset(clock); |
| 236 } | 240 } |
| 237 | 241 |
| 238 void Pipeline::SetCurrentReadPosition(int64 offset) { | 242 void Pipeline::SetCurrentReadPosition(int64 offset) { |
|
scherkus (not reviewing)
2012/05/29 18:13:29
AFAIK this is still called by FFDemuxer but I can'
Ami GONE FROM CHROMIUM
2012/05/29 20:45:44
Hahahahahahahahaha.
current_bytes_ is (was) a writ
| |
| 239 base::AutoLock auto_lock(lock_); | 243 base::AutoLock auto_lock(lock_); |
| 240 | 244 |
| 241 // The current read position should never be ahead of the buffered byte | 245 // The current read position should never be ahead of the buffered byte |
| 242 // position but threading issues between BufferedDataSource::DoneRead_Locked() | 246 // position but threading issues between BufferedDataSource::DoneRead_Locked() |
| 243 // and BufferedDataSource::NetworkEventCallback() can cause them to be | 247 // and BufferedDataSource::NetworkEventCallback() can cause them to be |
| 244 // temporarily out of sync. The easiest fix for this is to cap both | 248 // temporarily out of sync. The easiest fix for this is to cap both |
| 245 // buffered_bytes_ and current_bytes_ to always be legal values in | 249 // buffered_byte_ranges_ and current_bytes_ to always be legal values in |
|
scherkus (not reviewing)
2012/05/29 18:13:29
|var|
Ami GONE FROM CHROMIUM
2012/05/29 20:45:44
Done.
| |
| 246 // SetCurrentReadPosition() and in SetBufferedBytes(). | 250 // SetCurrentReadPosition() and in AddBufferedByteRange(). |
| 247 if (offset > buffered_bytes_) | |
| 248 buffered_bytes_ = offset; | |
| 249 current_bytes_ = offset; | 251 current_bytes_ = offset; |
| 252 if (!buffered_byte_ranges_.size()) { | |
| 253 buffered_byte_ranges_.Add(0, offset); | |
| 254 return; | |
| 255 } | |
| 256 int64 start = buffered_byte_ranges_.start(buffered_byte_ranges_.size() - 1); | |
| 257 int64 end = buffered_byte_ranges_.end(buffered_byte_ranges_.size() - 1); | |
| 258 if (end < offset) | |
| 259 buffered_byte_ranges_.Add(start, offset); | |
| 250 } | 260 } |
| 251 | 261 |
| 252 void Pipeline::ResetState() { | 262 void Pipeline::ResetState() { |
| 253 base::AutoLock auto_lock(lock_); | 263 base::AutoLock auto_lock(lock_); |
| 254 const base::TimeDelta kZero; | 264 const TimeDelta kZero; |
| 255 running_ = false; | 265 running_ = false; |
| 256 stop_pending_ = false; | 266 stop_pending_ = false; |
| 257 seek_pending_ = false; | 267 seek_pending_ = false; |
| 258 tearing_down_ = false; | 268 tearing_down_ = false; |
| 259 error_caused_teardown_ = false; | 269 error_caused_teardown_ = false; |
| 260 playback_rate_change_pending_ = false; | 270 playback_rate_change_pending_ = false; |
| 261 buffered_bytes_ = 0; | 271 buffered_byte_ranges_.clear(); |
| 262 buffered_time_ranges_.clear(); | 272 buffered_time_ranges_.clear(); |
| 263 total_bytes_ = 0; | 273 total_bytes_ = 0; |
| 264 natural_size_.SetSize(0, 0); | 274 natural_size_.SetSize(0, 0); |
| 265 volume_ = 1.0f; | 275 volume_ = 1.0f; |
| 266 playback_rate_ = 0.0f; | 276 playback_rate_ = 0.0f; |
| 267 pending_playback_rate_ = 0.0f; | 277 pending_playback_rate_ = 0.0f; |
| 268 status_ = PIPELINE_OK; | 278 status_ = PIPELINE_OK; |
| 269 has_audio_ = false; | 279 has_audio_ = false; |
| 270 has_video_ = false; | 280 has_video_ = false; |
| 271 waiting_for_clock_update_ = false; | 281 waiting_for_clock_update_ = false; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 DCHECK(IsRunning()); | 381 DCHECK(IsRunning()); |
| 372 DCHECK_NE(PIPELINE_OK, error); | 382 DCHECK_NE(PIPELINE_OK, error); |
| 373 VLOG(1) << "Media pipeline error: " << error; | 383 VLOG(1) << "Media pipeline error: " << error; |
| 374 | 384 |
| 375 message_loop_->PostTask(FROM_HERE, base::Bind( | 385 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 376 &Pipeline::ErrorChangedTask, this, error)); | 386 &Pipeline::ErrorChangedTask, this, error)); |
| 377 | 387 |
| 378 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 388 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
| 379 } | 389 } |
| 380 | 390 |
| 381 base::TimeDelta Pipeline::GetTime() const { | 391 TimeDelta Pipeline::GetTime() const { |
| 382 DCHECK(IsRunning()); | 392 DCHECK(IsRunning()); |
| 383 return GetCurrentTime(); | 393 return GetCurrentTime(); |
| 384 } | 394 } |
| 385 | 395 |
| 386 base::TimeDelta Pipeline::GetDuration() const { | 396 TimeDelta Pipeline::GetDuration() const { |
| 387 DCHECK(IsRunning()); | 397 DCHECK(IsRunning()); |
| 388 return GetMediaDuration(); | 398 return GetMediaDuration(); |
| 389 } | 399 } |
| 390 | 400 |
| 391 void Pipeline::OnAudioTimeUpdate(base::TimeDelta time, | 401 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
| 392 base::TimeDelta max_time) { | |
| 393 DCHECK(time <= max_time); | 402 DCHECK(time <= max_time); |
| 394 DCHECK(IsRunning()); | 403 DCHECK(IsRunning()); |
| 395 base::AutoLock auto_lock(lock_); | 404 base::AutoLock auto_lock(lock_); |
| 396 | 405 |
| 397 if (!has_audio_) | 406 if (!has_audio_) |
| 398 return; | 407 return; |
| 399 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 408 if (waiting_for_clock_update_ && time < clock_->Elapsed()) |
| 400 return; | 409 return; |
| 401 | 410 |
| 402 clock_->SetTime(time, max_time); | 411 clock_->SetTime(time, max_time); |
| 403 StartClockIfWaitingForTimeUpdate_Locked(); | 412 StartClockIfWaitingForTimeUpdate_Locked(); |
| 404 } | 413 } |
| 405 | 414 |
| 406 void Pipeline::OnVideoTimeUpdate(base::TimeDelta max_time) { | 415 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { |
| 407 DCHECK(IsRunning()); | 416 DCHECK(IsRunning()); |
| 408 base::AutoLock auto_lock(lock_); | 417 base::AutoLock auto_lock(lock_); |
| 409 | 418 |
| 410 if (has_audio_) | 419 if (has_audio_) |
| 411 return; | 420 return; |
| 412 | 421 |
| 413 DCHECK(!waiting_for_clock_update_); | 422 DCHECK(!waiting_for_clock_update_); |
| 414 clock_->SetMaxTime(max_time); | 423 clock_->SetMaxTime(max_time); |
| 415 } | 424 } |
| 416 | 425 |
| 417 void Pipeline::SetDuration(base::TimeDelta duration) { | 426 void Pipeline::SetDuration(TimeDelta duration) { |
| 418 DCHECK(IsRunning()); | 427 DCHECK(IsRunning()); |
| 419 media_log_->AddEvent( | 428 media_log_->AddEvent( |
| 420 media_log_->CreateTimeEvent( | 429 media_log_->CreateTimeEvent( |
| 421 MediaLogEvent::DURATION_SET, "duration", duration)); | 430 MediaLogEvent::DURATION_SET, "duration", duration)); |
| 422 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 431 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
| 423 | 432 |
| 424 base::AutoLock auto_lock(lock_); | 433 base::AutoLock auto_lock(lock_); |
| 425 clock_->SetDuration(duration); | 434 clock_->SetDuration(duration); |
| 426 UpdateBufferedTimeRanges_Locked(); | 435 |
| 436 if (total_bytes_ == 0) | |
| 437 return; | |
| 438 buffered_time_ranges_.clear(); | |
| 439 for (size_t i = 0; i < buffered_byte_ranges_.size(); ++i) { | |
| 440 TimeDelta start = TimeForByteOffset_Locked(buffered_byte_ranges_.start(i)); | |
| 441 TimeDelta end = TimeForByteOffset_Locked(buffered_byte_ranges_.end(i)); | |
| 442 // Cap approximated buffered time at the length of the video. | |
| 443 end = std::min(end, clock_->Duration()); | |
| 444 // Make sure buffered time is at least the current time. | |
| 445 end = std::max(end, GetCurrentTime_Locked()); | |
| 446 buffered_time_ranges_.Add(start, end); | |
| 447 } | |
| 427 } | 448 } |
| 428 | 449 |
| 429 void Pipeline::SetTotalBytes(int64 total_bytes) { | 450 void Pipeline::SetTotalBytes(int64 total_bytes) { |
| 430 DCHECK(IsRunning()); | 451 DCHECK(IsRunning()); |
| 431 media_log_->AddEvent( | 452 media_log_->AddEvent( |
| 432 media_log_->CreateIntegerEvent( | 453 media_log_->CreateIntegerEvent( |
| 433 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); | 454 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); |
| 434 int64 total_mbytes = total_bytes >> 20; | 455 int64 total_mbytes = total_bytes >> 20; |
| 435 if (total_mbytes > kint32max) | 456 if (total_mbytes > kint32max) |
| 436 total_mbytes = kint32max; | 457 total_mbytes = kint32max; |
| 437 UMA_HISTOGRAM_CUSTOM_COUNTS( | 458 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 438 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); | 459 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); |
| 439 | 460 |
| 440 base::AutoLock auto_lock(lock_); | 461 base::AutoLock auto_lock(lock_); |
| 441 total_bytes_ = total_bytes; | 462 total_bytes_ = total_bytes; |
| 442 } | 463 } |
| 443 | 464 |
| 444 void Pipeline::SetBufferedBytes(int64 buffered_bytes) { | 465 TimeDelta Pipeline::TimeForByteOffset_Locked(int64 byte_offset) const { |
| 466 lock_.AssertAcquired(); | |
| 467 TimeDelta time_offset = byte_offset * clock_->Duration() / total_bytes_; | |
| 468 // Since the byte->time calculation is approximate, fudge the beginning & | |
| 469 // ending areas to look better. | |
| 470 TimeDelta epsilon = clock_->Duration() / 100; | |
| 471 if (time_offset < epsilon) | |
| 472 return TimeDelta(); | |
| 473 if (time_offset + epsilon > clock_->Duration()) | |
| 474 return clock_->Duration(); | |
| 475 return time_offset; | |
| 476 } | |
| 477 | |
| 478 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { | |
| 445 DCHECK(IsRunning()); | 479 DCHECK(IsRunning()); |
| 446 base::AutoLock auto_lock(lock_); | 480 base::AutoLock auto_lock(lock_); |
| 447 // See comments in SetCurrentReadPosition() about capping. | 481 // See comments in SetCurrentReadPosition() about capping. |
| 448 if (buffered_bytes < current_bytes_) | 482 if (end < current_bytes_) |
| 449 current_bytes_ = buffered_bytes; | 483 current_bytes_ = end; |
| 450 buffered_bytes_ = buffered_bytes; | 484 buffered_byte_ranges_.Add(start, end); |
| 451 UpdateBufferedTimeRanges_Locked(); | |
| 452 } | |
| 453 | 485 |
| 454 void Pipeline::UpdateBufferedTimeRanges_Locked() { | |
| 455 lock_.AssertAcquired(); | |
| 456 if (total_bytes_ == 0) | 486 if (total_bytes_ == 0) |
| 457 return; | 487 return; |
| 458 base::TimeDelta buffered_time = | 488 buffered_time_ranges_.Add(TimeForByteOffset_Locked(start), |
| 459 clock_->Duration() * buffered_bytes_ / total_bytes_; | 489 TimeForByteOffset_Locked(end)); |
| 460 // Cap approximated buffered time at the length of the video. | |
| 461 buffered_time = std::min(buffered_time, clock_->Duration()); | |
| 462 // Make sure buffered_time is at least the current time and at least the | |
| 463 // current seek target. | |
| 464 buffered_time = std::max(buffered_time, GetCurrentTime_Locked()); | |
| 465 buffered_time = std::max(buffered_time, seek_timestamp_); | |
| 466 buffered_time_ranges_.Add(seek_timestamp_, buffered_time); | |
| 467 } | 490 } |
| 468 | 491 |
| 469 void Pipeline::SetNaturalVideoSize(const gfx::Size& size) { | 492 void Pipeline::SetNaturalVideoSize(const gfx::Size& size) { |
| 470 DCHECK(IsRunning()); | 493 DCHECK(IsRunning()); |
| 471 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( | 494 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( |
| 472 size.width(), size.height())); | 495 size.width(), size.height())); |
| 473 | 496 |
| 474 base::AutoLock auto_lock(lock_); | 497 base::AutoLock auto_lock(lock_); |
| 475 natural_size_ = size; | 498 natural_size_ = size; |
| 476 } | 499 } |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 775 | 798 |
| 776 void Pipeline::VolumeChangedTask(float volume) { | 799 void Pipeline::VolumeChangedTask(float volume) { |
| 777 DCHECK(message_loop_->BelongsToCurrentThread()); | 800 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 778 if (!running_ || tearing_down_) | 801 if (!running_ || tearing_down_) |
| 779 return; | 802 return; |
| 780 | 803 |
| 781 if (audio_renderer_) | 804 if (audio_renderer_) |
| 782 audio_renderer_->SetVolume(volume); | 805 audio_renderer_->SetVolume(volume); |
| 783 } | 806 } |
| 784 | 807 |
| 785 void Pipeline::SeekTask(base::TimeDelta time, | 808 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
| 786 const PipelineStatusCB& seek_cb) { | |
| 787 DCHECK(message_loop_->BelongsToCurrentThread()); | 809 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 788 DCHECK(!IsPipelineStopPending()); | 810 DCHECK(!IsPipelineStopPending()); |
| 789 | 811 |
| 790 // Suppress seeking if we're not fully started. | 812 // Suppress seeking if we're not fully started. |
| 791 if (state_ != kStarted && state_ != kEnded) { | 813 if (state_ != kStarted && state_ != kEnded) { |
| 792 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 814 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
| 793 // will only execute the first Seek() request. | 815 // will only execute the first Seek() request. |
| 794 DVLOG(1) << "Media pipeline has not started, ignoring seek to " | 816 DVLOG(1) << "Media pipeline has not started, ignoring seek to " |
| 795 << time.InMicroseconds() << " (current state: " << state_ << ")"; | 817 << time.InMicroseconds() << " (current state: " << state_ << ")"; |
| 796 return; | 818 return; |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1253 } | 1275 } |
| 1254 | 1276 |
| 1255 if (pipeline_filter_) { | 1277 if (pipeline_filter_) { |
| 1256 pipeline_filter_->Stop(callback); | 1278 pipeline_filter_->Stop(callback); |
| 1257 return; | 1279 return; |
| 1258 } | 1280 } |
| 1259 | 1281 |
| 1260 callback.Run(); | 1282 callback.Run(); |
| 1261 } | 1283 } |
| 1262 | 1284 |
| 1263 void Pipeline::DoSeek(base::TimeDelta seek_timestamp) { | 1285 void Pipeline::DoSeek(TimeDelta seek_timestamp) { |
| 1264 // TODO(acolwell): We might be able to convert this if (demuxer_) into a | 1286 // TODO(acolwell): We might be able to convert this if (demuxer_) into a |
| 1265 // DCHECK(). Further investigation is needed to make sure this won't introduce | 1287 // DCHECK(). Further investigation is needed to make sure this won't introduce |
| 1266 // a bug. | 1288 // a bug. |
| 1267 if (demuxer_) { | 1289 if (demuxer_) { |
| 1268 demuxer_->Seek(seek_timestamp, base::Bind( | 1290 demuxer_->Seek(seek_timestamp, base::Bind( |
| 1269 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); | 1291 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); |
| 1270 return; | 1292 return; |
| 1271 } | 1293 } |
| 1272 | 1294 |
| 1273 OnDemuxerSeekDone(seek_timestamp, PIPELINE_OK); | 1295 OnDemuxerSeekDone(seek_timestamp, PIPELINE_OK); |
| 1274 } | 1296 } |
| 1275 | 1297 |
| 1276 void Pipeline::OnDemuxerSeekDone(base::TimeDelta seek_timestamp, | 1298 void Pipeline::OnDemuxerSeekDone(TimeDelta seek_timestamp, |
| 1277 PipelineStatus status) { | 1299 PipelineStatus status) { |
| 1278 if (!message_loop_->BelongsToCurrentThread()) { | 1300 if (!message_loop_->BelongsToCurrentThread()) { |
| 1279 message_loop_->PostTask(FROM_HERE, base::Bind( | 1301 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 1280 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); | 1302 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); |
| 1281 return; | 1303 return; |
| 1282 } | 1304 } |
| 1283 | 1305 |
| 1284 PipelineStatusCB done_cb = | 1306 PipelineStatusCB done_cb = |
| 1285 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); | 1307 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); |
| 1286 | 1308 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1309 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1331 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
| 1310 lock_.AssertAcquired(); | 1332 lock_.AssertAcquired(); |
| 1311 if (!waiting_for_clock_update_) | 1333 if (!waiting_for_clock_update_) |
| 1312 return; | 1334 return; |
| 1313 | 1335 |
| 1314 waiting_for_clock_update_ = false; | 1336 waiting_for_clock_update_ = false; |
| 1315 clock_->Play(); | 1337 clock_->Play(); |
| 1316 } | 1338 } |
| 1317 | 1339 |
| 1318 } // namespace media | 1340 } // namespace media |
| OLD | NEW |