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 29 matching lines...) Expand all Loading... |
66 scoped_refptr<VideoRenderer> video_renderer; | 68 scoped_refptr<VideoRenderer> video_renderer; |
67 scoped_refptr<CompositeFilter> composite; | 69 scoped_refptr<CompositeFilter> composite; |
68 }; | 70 }; |
69 | 71 |
70 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) | 72 Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
71 : message_loop_(message_loop->message_loop_proxy()), | 73 : message_loop_(message_loop->message_loop_proxy()), |
72 media_log_(media_log), | 74 media_log_(media_log), |
73 clock_(new Clock(&base::Time::Now)), | 75 clock_(new Clock(&base::Time::Now)), |
74 waiting_for_clock_update_(false), | 76 waiting_for_clock_update_(false), |
75 state_(kCreated), | 77 state_(kCreated), |
76 current_bytes_(0), | |
77 creation_time_(base::Time::Now()) { | 78 creation_time_(base::Time::Now()) { |
78 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); | 79 media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated)); |
79 ResetState(); | 80 ResetState(); |
80 media_log_->AddEvent( | 81 media_log_->AddEvent( |
81 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); | 82 media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED)); |
82 } | 83 } |
83 | 84 |
84 Pipeline::~Pipeline() { | 85 Pipeline::~Pipeline() { |
85 base::AutoLock auto_lock(lock_); | 86 base::AutoLock auto_lock(lock_); |
86 DCHECK(!running_) << "Stop() must complete before destroying object"; | 87 DCHECK(!running_) << "Stop() must complete before destroying object"; |
(...skipping 20 matching lines...) Expand all Loading... |
107 | 108 |
108 void Pipeline::Stop(const base::Closure& stop_cb) { | 109 void Pipeline::Stop(const base::Closure& stop_cb) { |
109 base::AutoLock auto_lock(lock_); | 110 base::AutoLock auto_lock(lock_); |
110 CHECK(running_) << "Media pipeline isn't running"; | 111 CHECK(running_) << "Media pipeline isn't running"; |
111 | 112 |
112 // Stop the pipeline, which will set |running_| to false on our behalf. | 113 // Stop the pipeline, which will set |running_| to false on our behalf. |
113 message_loop_->PostTask(FROM_HERE, base::Bind( | 114 message_loop_->PostTask(FROM_HERE, base::Bind( |
114 &Pipeline::StopTask, this, stop_cb)); | 115 &Pipeline::StopTask, this, stop_cb)); |
115 } | 116 } |
116 | 117 |
117 void Pipeline::Seek(base::TimeDelta time, | 118 void Pipeline::Seek(TimeDelta time, const PipelineStatusCB& seek_cb) { |
118 const PipelineStatusCB& seek_cb) { | |
119 base::AutoLock auto_lock(lock_); | 119 base::AutoLock auto_lock(lock_); |
120 CHECK(running_) << "Media pipeline isn't running"; | 120 CHECK(running_) << "Media pipeline isn't running"; |
121 | 121 |
122 message_loop_->PostTask(FROM_HERE, base::Bind( | 122 message_loop_->PostTask(FROM_HERE, base::Bind( |
123 &Pipeline::SeekTask, this, time, seek_cb)); | 123 &Pipeline::SeekTask, this, time, seek_cb)); |
124 } | 124 } |
125 | 125 |
126 bool Pipeline::IsRunning() const { | 126 bool Pipeline::IsRunning() const { |
127 base::AutoLock auto_lock(lock_); | 127 base::AutoLock auto_lock(lock_); |
128 return running_; | 128 return running_; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 return; | 183 return; |
184 | 184 |
185 base::AutoLock auto_lock(lock_); | 185 base::AutoLock auto_lock(lock_); |
186 volume_ = volume; | 186 volume_ = volume; |
187 if (running_ && !tearing_down_) { | 187 if (running_ && !tearing_down_) { |
188 message_loop_->PostTask(FROM_HERE, base::Bind( | 188 message_loop_->PostTask(FROM_HERE, base::Bind( |
189 &Pipeline::VolumeChangedTask, this, volume)); | 189 &Pipeline::VolumeChangedTask, this, volume)); |
190 } | 190 } |
191 } | 191 } |
192 | 192 |
193 base::TimeDelta Pipeline::GetCurrentTime() const { | 193 TimeDelta Pipeline::GetCurrentTime() const { |
194 base::AutoLock auto_lock(lock_); | 194 base::AutoLock auto_lock(lock_); |
195 return GetCurrentTime_Locked(); | 195 return GetCurrentTime_Locked(); |
196 } | 196 } |
197 | 197 |
198 base::TimeDelta Pipeline::GetCurrentTime_Locked() const { | 198 TimeDelta Pipeline::GetCurrentTime_Locked() const { |
199 lock_.AssertAcquired(); | 199 lock_.AssertAcquired(); |
200 return clock_->Elapsed(); | 200 return clock_->Elapsed(); |
201 } | 201 } |
202 | 202 |
203 Ranges<base::TimeDelta> Pipeline::GetBufferedTimeRanges() { | 203 Ranges<TimeDelta> Pipeline::GetBufferedTimeRanges() { |
204 base::AutoLock auto_lock(lock_); | 204 base::AutoLock auto_lock(lock_); |
205 return buffered_time_ranges_; | 205 Ranges<TimeDelta> time_ranges; |
| 206 if (clock_->Duration() == TimeDelta() || total_bytes_ == 0) |
| 207 return time_ranges; |
| 208 for (size_t i = 0; i < buffered_byte_ranges_.size(); ++i) { |
| 209 TimeDelta start = TimeForByteOffset_Locked(buffered_byte_ranges_.start(i)); |
| 210 TimeDelta end = TimeForByteOffset_Locked(buffered_byte_ranges_.end(i)); |
| 211 // Cap approximated buffered time at the length of the video. |
| 212 end = std::min(end, clock_->Duration()); |
| 213 time_ranges.Add(start, end); |
| 214 } |
| 215 |
| 216 return time_ranges; |
206 } | 217 } |
207 | 218 |
208 base::TimeDelta Pipeline::GetMediaDuration() const { | 219 TimeDelta Pipeline::GetMediaDuration() const { |
209 base::AutoLock auto_lock(lock_); | 220 base::AutoLock auto_lock(lock_); |
210 return clock_->Duration(); | 221 return clock_->Duration(); |
211 } | 222 } |
212 | 223 |
213 int64 Pipeline::GetBufferedBytes() const { | 224 int64 Pipeline::GetBufferedBytes() const { |
214 base::AutoLock auto_lock(lock_); | 225 base::AutoLock auto_lock(lock_); |
215 return buffered_bytes_; | 226 int64 ret = 0; |
| 227 for (size_t i = 0; i < buffered_byte_ranges_.size(); ++i) |
| 228 ret += buffered_byte_ranges_.end(i) - buffered_byte_ranges_.start(i); |
| 229 return ret; |
216 } | 230 } |
217 | 231 |
218 int64 Pipeline::GetTotalBytes() const { | 232 int64 Pipeline::GetTotalBytes() const { |
219 base::AutoLock auto_lock(lock_); | 233 base::AutoLock auto_lock(lock_); |
220 return total_bytes_; | 234 return total_bytes_; |
221 } | 235 } |
222 | 236 |
223 void Pipeline::GetNaturalVideoSize(gfx::Size* out_size) const { | 237 void Pipeline::GetNaturalVideoSize(gfx::Size* out_size) const { |
224 CHECK(out_size); | 238 CHECK(out_size); |
225 base::AutoLock auto_lock(lock_); | 239 base::AutoLock auto_lock(lock_); |
226 *out_size = natural_size_; | 240 *out_size = natural_size_; |
227 } | 241 } |
228 | 242 |
229 PipelineStatistics Pipeline::GetStatistics() const { | 243 PipelineStatistics Pipeline::GetStatistics() const { |
230 base::AutoLock auto_lock(lock_); | 244 base::AutoLock auto_lock(lock_); |
231 return statistics_; | 245 return statistics_; |
232 } | 246 } |
233 | 247 |
234 void Pipeline::SetClockForTesting(Clock* clock) { | 248 void Pipeline::SetClockForTesting(Clock* clock) { |
235 clock_.reset(clock); | 249 clock_.reset(clock); |
236 } | 250 } |
237 | 251 |
238 void Pipeline::SetCurrentReadPosition(int64 offset) { | |
239 base::AutoLock auto_lock(lock_); | |
240 | |
241 // The current read position should never be ahead of the buffered byte | |
242 // position but threading issues between BufferedDataSource::DoneRead_Locked() | |
243 // and BufferedDataSource::NetworkEventCallback() can cause them to be | |
244 // 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 | |
246 // SetCurrentReadPosition() and in SetBufferedBytes(). | |
247 if (offset > buffered_bytes_) | |
248 buffered_bytes_ = offset; | |
249 current_bytes_ = offset; | |
250 } | |
251 | |
252 void Pipeline::ResetState() { | 252 void Pipeline::ResetState() { |
253 base::AutoLock auto_lock(lock_); | 253 base::AutoLock auto_lock(lock_); |
254 const base::TimeDelta kZero; | 254 const TimeDelta kZero; |
255 running_ = false; | 255 running_ = false; |
256 stop_pending_ = false; | 256 stop_pending_ = false; |
257 seek_pending_ = false; | 257 seek_pending_ = false; |
258 tearing_down_ = false; | 258 tearing_down_ = false; |
259 error_caused_teardown_ = false; | 259 error_caused_teardown_ = false; |
260 playback_rate_change_pending_ = false; | 260 playback_rate_change_pending_ = false; |
261 buffered_bytes_ = 0; | 261 buffered_byte_ranges_.clear(); |
262 buffered_time_ranges_.clear(); | |
263 total_bytes_ = 0; | 262 total_bytes_ = 0; |
264 natural_size_.SetSize(0, 0); | 263 natural_size_.SetSize(0, 0); |
265 volume_ = 1.0f; | 264 volume_ = 1.0f; |
266 playback_rate_ = 0.0f; | 265 playback_rate_ = 0.0f; |
267 pending_playback_rate_ = 0.0f; | 266 pending_playback_rate_ = 0.0f; |
268 status_ = PIPELINE_OK; | 267 status_ = PIPELINE_OK; |
269 has_audio_ = false; | 268 has_audio_ = false; |
270 has_video_ = false; | 269 has_video_ = false; |
271 waiting_for_clock_update_ = false; | 270 waiting_for_clock_update_ = false; |
272 audio_disabled_ = false; | 271 audio_disabled_ = false; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 DCHECK(IsRunning()); | 370 DCHECK(IsRunning()); |
372 DCHECK_NE(PIPELINE_OK, error); | 371 DCHECK_NE(PIPELINE_OK, error); |
373 VLOG(1) << "Media pipeline error: " << error; | 372 VLOG(1) << "Media pipeline error: " << error; |
374 | 373 |
375 message_loop_->PostTask(FROM_HERE, base::Bind( | 374 message_loop_->PostTask(FROM_HERE, base::Bind( |
376 &Pipeline::ErrorChangedTask, this, error)); | 375 &Pipeline::ErrorChangedTask, this, error)); |
377 | 376 |
378 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 377 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
379 } | 378 } |
380 | 379 |
381 base::TimeDelta Pipeline::GetTime() const { | 380 TimeDelta Pipeline::GetTime() const { |
382 DCHECK(IsRunning()); | 381 DCHECK(IsRunning()); |
383 return GetCurrentTime(); | 382 return GetCurrentTime(); |
384 } | 383 } |
385 | 384 |
386 base::TimeDelta Pipeline::GetDuration() const { | 385 TimeDelta Pipeline::GetDuration() const { |
387 DCHECK(IsRunning()); | 386 DCHECK(IsRunning()); |
388 return GetMediaDuration(); | 387 return GetMediaDuration(); |
389 } | 388 } |
390 | 389 |
391 void Pipeline::OnAudioTimeUpdate(base::TimeDelta time, | 390 void Pipeline::OnAudioTimeUpdate(TimeDelta time, TimeDelta max_time) { |
392 base::TimeDelta max_time) { | |
393 DCHECK(time <= max_time); | 391 DCHECK(time <= max_time); |
394 DCHECK(IsRunning()); | 392 DCHECK(IsRunning()); |
395 base::AutoLock auto_lock(lock_); | 393 base::AutoLock auto_lock(lock_); |
396 | 394 |
397 if (!has_audio_) | 395 if (!has_audio_) |
398 return; | 396 return; |
399 if (waiting_for_clock_update_ && time < clock_->Elapsed()) | 397 if (waiting_for_clock_update_ && time < clock_->Elapsed()) |
400 return; | 398 return; |
401 | 399 |
402 clock_->SetTime(time, max_time); | 400 clock_->SetTime(time, max_time); |
403 StartClockIfWaitingForTimeUpdate_Locked(); | 401 StartClockIfWaitingForTimeUpdate_Locked(); |
404 } | 402 } |
405 | 403 |
406 void Pipeline::OnVideoTimeUpdate(base::TimeDelta max_time) { | 404 void Pipeline::OnVideoTimeUpdate(TimeDelta max_time) { |
407 DCHECK(IsRunning()); | 405 DCHECK(IsRunning()); |
408 base::AutoLock auto_lock(lock_); | 406 base::AutoLock auto_lock(lock_); |
409 | 407 |
410 if (has_audio_) | 408 if (has_audio_) |
411 return; | 409 return; |
412 | 410 |
413 DCHECK(!waiting_for_clock_update_); | 411 DCHECK(!waiting_for_clock_update_); |
414 clock_->SetMaxTime(max_time); | 412 clock_->SetMaxTime(max_time); |
415 } | 413 } |
416 | 414 |
417 void Pipeline::SetDuration(base::TimeDelta duration) { | 415 void Pipeline::SetDuration(TimeDelta duration) { |
418 DCHECK(IsRunning()); | 416 DCHECK(IsRunning()); |
419 media_log_->AddEvent( | 417 media_log_->AddEvent( |
420 media_log_->CreateTimeEvent( | 418 media_log_->CreateTimeEvent( |
421 MediaLogEvent::DURATION_SET, "duration", duration)); | 419 MediaLogEvent::DURATION_SET, "duration", duration)); |
422 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); | 420 UMA_HISTOGRAM_LONG_TIMES("Media.Duration", duration); |
423 | 421 |
424 base::AutoLock auto_lock(lock_); | 422 base::AutoLock auto_lock(lock_); |
425 clock_->SetDuration(duration); | 423 clock_->SetDuration(duration); |
426 UpdateBufferedTimeRanges_Locked(); | |
427 } | 424 } |
428 | 425 |
429 void Pipeline::SetTotalBytes(int64 total_bytes) { | 426 void Pipeline::SetTotalBytes(int64 total_bytes) { |
430 DCHECK(IsRunning()); | 427 DCHECK(IsRunning()); |
431 media_log_->AddEvent( | 428 media_log_->AddEvent( |
432 media_log_->CreateIntegerEvent( | 429 media_log_->CreateIntegerEvent( |
433 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); | 430 MediaLogEvent::TOTAL_BYTES_SET, "total_bytes", total_bytes)); |
434 int64 total_mbytes = total_bytes >> 20; | 431 int64 total_mbytes = total_bytes >> 20; |
435 if (total_mbytes > kint32max) | 432 if (total_mbytes > kint32max) |
436 total_mbytes = kint32max; | 433 total_mbytes = kint32max; |
437 UMA_HISTOGRAM_CUSTOM_COUNTS( | 434 UMA_HISTOGRAM_CUSTOM_COUNTS( |
438 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); | 435 "Media.TotalMBytes", static_cast<int32>(total_mbytes), 1, kint32max, 50); |
439 | 436 |
440 base::AutoLock auto_lock(lock_); | 437 base::AutoLock auto_lock(lock_); |
441 total_bytes_ = total_bytes; | 438 total_bytes_ = total_bytes; |
442 } | 439 } |
443 | 440 |
444 void Pipeline::SetBufferedBytes(int64 buffered_bytes) { | 441 TimeDelta Pipeline::TimeForByteOffset_Locked(int64 byte_offset) const { |
| 442 lock_.AssertAcquired(); |
| 443 TimeDelta time_offset = byte_offset * clock_->Duration() / total_bytes_; |
| 444 // Since the byte->time calculation is approximate, fudge the beginning & |
| 445 // ending areas to look better. |
| 446 TimeDelta epsilon = clock_->Duration() / 100; |
| 447 if (time_offset < epsilon) |
| 448 return TimeDelta(); |
| 449 if (time_offset + epsilon > clock_->Duration()) |
| 450 return clock_->Duration(); |
| 451 return time_offset; |
| 452 } |
| 453 |
| 454 void Pipeline::AddBufferedByteRange(int64 start, int64 end) { |
445 DCHECK(IsRunning()); | 455 DCHECK(IsRunning()); |
446 base::AutoLock auto_lock(lock_); | 456 base::AutoLock auto_lock(lock_); |
447 // See comments in SetCurrentReadPosition() about capping. | 457 buffered_byte_ranges_.Add(start, end); |
448 if (buffered_bytes < current_bytes_) | |
449 current_bytes_ = buffered_bytes; | |
450 buffered_bytes_ = buffered_bytes; | |
451 UpdateBufferedTimeRanges_Locked(); | |
452 } | |
453 | |
454 void Pipeline::UpdateBufferedTimeRanges_Locked() { | |
455 lock_.AssertAcquired(); | |
456 if (total_bytes_ == 0) | |
457 return; | |
458 base::TimeDelta buffered_time = | |
459 clock_->Duration() * buffered_bytes_ / total_bytes_; | |
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 } | 458 } |
468 | 459 |
469 void Pipeline::SetNaturalVideoSize(const gfx::Size& size) { | 460 void Pipeline::SetNaturalVideoSize(const gfx::Size& size) { |
470 DCHECK(IsRunning()); | 461 DCHECK(IsRunning()); |
471 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( | 462 media_log_->AddEvent(media_log_->CreateVideoSizeSetEvent( |
472 size.width(), size.height())); | 463 size.width(), size.height())); |
473 | 464 |
474 base::AutoLock auto_lock(lock_); | 465 base::AutoLock auto_lock(lock_); |
475 natural_size_ = size; | 466 natural_size_ = size; |
476 } | 467 } |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
775 | 766 |
776 void Pipeline::VolumeChangedTask(float volume) { | 767 void Pipeline::VolumeChangedTask(float volume) { |
777 DCHECK(message_loop_->BelongsToCurrentThread()); | 768 DCHECK(message_loop_->BelongsToCurrentThread()); |
778 if (!running_ || tearing_down_) | 769 if (!running_ || tearing_down_) |
779 return; | 770 return; |
780 | 771 |
781 if (audio_renderer_) | 772 if (audio_renderer_) |
782 audio_renderer_->SetVolume(volume); | 773 audio_renderer_->SetVolume(volume); |
783 } | 774 } |
784 | 775 |
785 void Pipeline::SeekTask(base::TimeDelta time, | 776 void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) { |
786 const PipelineStatusCB& seek_cb) { | |
787 DCHECK(message_loop_->BelongsToCurrentThread()); | 777 DCHECK(message_loop_->BelongsToCurrentThread()); |
788 DCHECK(!IsPipelineStopPending()); | 778 DCHECK(!IsPipelineStopPending()); |
789 | 779 |
790 // Suppress seeking if we're not fully started. | 780 // Suppress seeking if we're not fully started. |
791 if (state_ != kStarted && state_ != kEnded) { | 781 if (state_ != kStarted && state_ != kEnded) { |
792 // TODO(scherkus): should we run the callback? I'm tempted to say the API | 782 // TODO(scherkus): should we run the callback? I'm tempted to say the API |
793 // will only execute the first Seek() request. | 783 // will only execute the first Seek() request. |
794 DVLOG(1) << "Media pipeline has not started, ignoring seek to " | 784 DVLOG(1) << "Media pipeline has not started, ignoring seek to " |
795 << time.InMicroseconds() << " (current state: " << state_ << ")"; | 785 << time.InMicroseconds() << " (current state: " << state_ << ")"; |
796 return; | 786 return; |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1253 } | 1243 } |
1254 | 1244 |
1255 if (pipeline_filter_) { | 1245 if (pipeline_filter_) { |
1256 pipeline_filter_->Stop(callback); | 1246 pipeline_filter_->Stop(callback); |
1257 return; | 1247 return; |
1258 } | 1248 } |
1259 | 1249 |
1260 callback.Run(); | 1250 callback.Run(); |
1261 } | 1251 } |
1262 | 1252 |
1263 void Pipeline::DoSeek(base::TimeDelta seek_timestamp) { | 1253 void Pipeline::DoSeek(TimeDelta seek_timestamp) { |
1264 // TODO(acolwell): We might be able to convert this if (demuxer_) into a | 1254 // 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 | 1255 // DCHECK(). Further investigation is needed to make sure this won't introduce |
1266 // a bug. | 1256 // a bug. |
1267 if (demuxer_) { | 1257 if (demuxer_) { |
1268 demuxer_->Seek(seek_timestamp, base::Bind( | 1258 demuxer_->Seek(seek_timestamp, base::Bind( |
1269 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); | 1259 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp)); |
1270 return; | 1260 return; |
1271 } | 1261 } |
1272 | 1262 |
1273 OnDemuxerSeekDone(seek_timestamp, PIPELINE_OK); | 1263 OnDemuxerSeekDone(seek_timestamp, PIPELINE_OK); |
1274 } | 1264 } |
1275 | 1265 |
1276 void Pipeline::OnDemuxerSeekDone(base::TimeDelta seek_timestamp, | 1266 void Pipeline::OnDemuxerSeekDone(TimeDelta seek_timestamp, |
1277 PipelineStatus status) { | 1267 PipelineStatus status) { |
1278 if (!message_loop_->BelongsToCurrentThread()) { | 1268 if (!message_loop_->BelongsToCurrentThread()) { |
1279 message_loop_->PostTask(FROM_HERE, base::Bind( | 1269 message_loop_->PostTask(FROM_HERE, base::Bind( |
1280 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); | 1270 &Pipeline::OnDemuxerSeekDone, this, seek_timestamp, status)); |
1281 return; | 1271 return; |
1282 } | 1272 } |
1283 | 1273 |
1284 PipelineStatusCB done_cb = | 1274 PipelineStatusCB done_cb = |
1285 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); | 1275 base::Bind(&Pipeline::OnFilterStateTransitionWithStatus, this); |
1286 | 1276 |
(...skipping 22 matching lines...) Expand all Loading... |
1309 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { | 1299 void Pipeline::StartClockIfWaitingForTimeUpdate_Locked() { |
1310 lock_.AssertAcquired(); | 1300 lock_.AssertAcquired(); |
1311 if (!waiting_for_clock_update_) | 1301 if (!waiting_for_clock_update_) |
1312 return; | 1302 return; |
1313 | 1303 |
1314 waiting_for_clock_update_ = false; | 1304 waiting_for_clock_update_ = false; |
1315 clock_->Play(); | 1305 clock_->Play(); |
1316 } | 1306 } |
1317 | 1307 |
1318 } // namespace media | 1308 } // namespace media |
OLD | NEW |