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/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <deque> | 8 #include <deque> |
9 #include <limits> | 9 #include <limits> |
10 | 10 |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 198 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
199 typedef std::deque<ReadCB> ReadCBQueue; | 199 typedef std::deque<ReadCB> ReadCBQueue; |
200 typedef std::deque<base::Closure> ClosureQueue; | 200 typedef std::deque<base::Closure> ClosureQueue; |
201 | 201 |
202 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 202 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
203 const LogCB& log_cb); | 203 const LogCB& log_cb); |
204 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 204 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
205 const LogCB& log_cb); | 205 const LogCB& log_cb); |
206 virtual ~ChunkDemuxerStream(); | 206 virtual ~ChunkDemuxerStream(); |
207 | 207 |
208 void StartWaitingForSeek(); | 208 void AbortReads(); |
209 void Seek(TimeDelta time); | 209 void Seek(TimeDelta time); |
210 void CancelPendingSeek(); | |
211 bool IsSeekWaitingForData() const; | 210 bool IsSeekWaitingForData() const; |
212 | 211 |
213 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 212 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
214 // which handle ordering and overlap resolution. | 213 // which handle ordering and overlap resolution. |
215 // Returns true if buffers were successfully added. | 214 // Returns true if buffers were successfully added. |
216 bool Append(const StreamParser::BufferQueue& buffers); | 215 bool Append(const StreamParser::BufferQueue& buffers); |
217 | 216 |
218 // Signal to the stream that duration has changed to |duration|. | 217 // Signal to the stream that duration has changed to |duration|. |
219 void OnSetDuration(TimeDelta duration); | 218 void OnSetDuration(TimeDelta duration); |
220 | 219 |
(...skipping 17 matching lines...) Expand all Loading... |
238 | 237 |
239 // DemuxerStream methods. | 238 // DemuxerStream methods. |
240 virtual void Read(const ReadCB& read_cb) OVERRIDE; | 239 virtual void Read(const ReadCB& read_cb) OVERRIDE; |
241 virtual Type type() OVERRIDE; | 240 virtual Type type() OVERRIDE; |
242 virtual void EnableBitstreamConverter() OVERRIDE; | 241 virtual void EnableBitstreamConverter() OVERRIDE; |
243 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; | 242 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; |
244 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; | 243 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; |
245 | 244 |
246 private: | 245 private: |
247 enum State { | 246 enum State { |
| 247 UNINITIALIZED, |
248 RETURNING_DATA_FOR_READS, | 248 RETURNING_DATA_FOR_READS, |
249 WAITING_FOR_SEEK, | 249 RETURNING_ABORT_FOR_READS, |
250 CANCELED, | |
251 SHUTDOWN, | 250 SHUTDOWN, |
252 }; | 251 }; |
253 | 252 |
254 // Assigns |state_| to |state| | 253 // Assigns |state_| to |state| |
255 void ChangeState_Locked(State state); | 254 void ChangeState_Locked(State state); |
256 | 255 |
257 // Adds the callback to |read_cbs_| so it can be called later when we | 256 // Adds the callback to |read_cbs_| so it can be called later when we |
258 // have data. | 257 // have data. |
259 void DeferRead_Locked(const ReadCB& read_cb); | 258 void DeferRead_Locked(const ReadCB& read_cb); |
260 | 259 |
(...skipping 15 matching lines...) Expand all Loading... |
276 mutable base::Lock lock_; | 275 mutable base::Lock lock_; |
277 State state_; | 276 State state_; |
278 ReadCBQueue read_cbs_; | 277 ReadCBQueue read_cbs_; |
279 | 278 |
280 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 279 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
281 }; | 280 }; |
282 | 281 |
283 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 282 ChunkDemuxerStream::ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
284 const LogCB& log_cb) | 283 const LogCB& log_cb) |
285 : type_(AUDIO), | 284 : type_(AUDIO), |
286 state_(RETURNING_DATA_FOR_READS) { | 285 state_(UNINITIALIZED) { |
287 stream_.reset(new SourceBufferStream(audio_config, log_cb)); | 286 stream_.reset(new SourceBufferStream(audio_config, log_cb)); |
288 } | 287 } |
289 | 288 |
290 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 289 ChunkDemuxerStream::ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
291 const LogCB& log_cb) | 290 const LogCB& log_cb) |
292 : type_(VIDEO), | 291 : type_(VIDEO), |
293 state_(RETURNING_DATA_FOR_READS) { | 292 state_(UNINITIALIZED) { |
294 stream_.reset(new SourceBufferStream(video_config, log_cb)); | 293 stream_.reset(new SourceBufferStream(video_config, log_cb)); |
295 } | 294 } |
296 | 295 |
297 void ChunkDemuxerStream::StartWaitingForSeek() { | 296 void ChunkDemuxerStream::AbortReads() { |
298 DVLOG(1) << "ChunkDemuxerStream::StartWaitingForSeek()"; | 297 DVLOG(1) << "ChunkDemuxerStream::AbortReads()"; |
299 ReadCBQueue read_cbs; | 298 ReadCBQueue read_cbs; |
300 { | 299 { |
301 base::AutoLock auto_lock(lock_); | 300 base::AutoLock auto_lock(lock_); |
302 ChangeState_Locked(WAITING_FOR_SEEK); | 301 ChangeState_Locked(RETURNING_ABORT_FOR_READS); |
303 std::swap(read_cbs_, read_cbs); | 302 std::swap(read_cbs_, read_cbs); |
304 } | 303 } |
305 | 304 |
306 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | 305 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
307 it->Run(kAborted, NULL); | 306 it->Run(kAborted, NULL); |
308 } | 307 } |
309 | 308 |
310 void ChunkDemuxerStream::Seek(TimeDelta time) { | 309 void ChunkDemuxerStream::Seek(TimeDelta time) { |
311 base::AutoLock auto_lock(lock_); | 310 base::AutoLock auto_lock(lock_); |
312 | |
313 DCHECK(read_cbs_.empty()); | 311 DCHECK(read_cbs_.empty()); |
314 | 312 DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS); |
315 // Ignore seek requests when canceled. | |
316 if (state_ == CANCELED) | |
317 return; | |
318 | 313 |
319 stream_->Seek(time); | 314 stream_->Seek(time); |
320 | 315 ChangeState_Locked(RETURNING_DATA_FOR_READS); |
321 if (state_ == WAITING_FOR_SEEK) | |
322 ChangeState_Locked(RETURNING_DATA_FOR_READS); | |
323 } | |
324 | |
325 void ChunkDemuxerStream::CancelPendingSeek() { | |
326 DVLOG(1) << "ChunkDemuxerStream::CancelPendingSeek()"; | |
327 ReadCBQueue read_cbs; | |
328 { | |
329 base::AutoLock auto_lock(lock_); | |
330 ChangeState_Locked(CANCELED); | |
331 std::swap(read_cbs_, read_cbs); | |
332 } | |
333 | |
334 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | |
335 it->Run(kAborted, NULL); | |
336 } | 316 } |
337 | 317 |
338 bool ChunkDemuxerStream::IsSeekWaitingForData() const { | 318 bool ChunkDemuxerStream::IsSeekWaitingForData() const { |
339 base::AutoLock auto_lock(lock_); | 319 base::AutoLock auto_lock(lock_); |
340 return stream_->IsSeekPending(); | 320 return stream_->IsSeekPending(); |
341 } | 321 } |
342 | 322 |
343 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { | 323 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { |
344 base::AutoLock auto_lock(lock_); | 324 base::AutoLock auto_lock(lock_); |
345 stream_->OnNewMediaSegment(start_timestamp); | 325 stream_->OnNewMediaSegment(start_timestamp); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
442 message_loop_proxy->PostTask(FROM_HERE, base::Bind( | 422 message_loop_proxy->PostTask(FROM_HERE, base::Bind( |
443 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); | 423 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); |
444 return; | 424 return; |
445 } | 425 } |
446 | 426 |
447 read_cb.Run(status, buffer); | 427 read_cb.Run(status, buffer); |
448 } | 428 } |
449 | 429 |
450 // DemuxerStream methods. | 430 // DemuxerStream methods. |
451 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { | 431 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { |
| 432 base::AutoLock auto_lock(lock_); |
| 433 DCHECK_NE(state_, UNINITIALIZED); |
| 434 |
452 DemuxerStream::Status status = kOk; | 435 DemuxerStream::Status status = kOk; |
453 scoped_refptr<StreamParserBuffer> buffer; | 436 scoped_refptr<StreamParserBuffer> buffer; |
454 { | 437 |
455 base::AutoLock auto_lock(lock_); | 438 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { |
456 if (!read_cbs_.empty() || !GetNextBuffer_Locked(&status, &buffer)) { | 439 DeferRead_Locked(read_cb); |
457 DeferRead_Locked(read_cb); | 440 return; |
458 return; | |
459 } | |
460 } | 441 } |
461 | 442 |
462 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 443 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( |
463 read_cb, status, buffer)); | 444 read_cb, status, buffer)); |
464 } | 445 } |
465 | 446 |
466 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } | 447 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } |
467 | 448 |
468 void ChunkDemuxerStream::EnableBitstreamConverter() {} | 449 void ChunkDemuxerStream::EnableBitstreamConverter() {} |
469 | 450 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 read_cbs_.pop_front(); | 494 read_cbs_.pop_front(); |
514 } | 495 } |
515 } | 496 } |
516 | 497 |
517 bool ChunkDemuxerStream::GetNextBuffer_Locked( | 498 bool ChunkDemuxerStream::GetNextBuffer_Locked( |
518 DemuxerStream::Status* status, | 499 DemuxerStream::Status* status, |
519 scoped_refptr<StreamParserBuffer>* buffer) { | 500 scoped_refptr<StreamParserBuffer>* buffer) { |
520 lock_.AssertAcquired(); | 501 lock_.AssertAcquired(); |
521 | 502 |
522 switch (state_) { | 503 switch (state_) { |
| 504 case UNINITIALIZED: |
| 505 NOTREACHED(); |
| 506 return false; |
523 case RETURNING_DATA_FOR_READS: | 507 case RETURNING_DATA_FOR_READS: |
524 switch (stream_->GetNextBuffer(buffer)) { | 508 switch (stream_->GetNextBuffer(buffer)) { |
525 case SourceBufferStream::kSuccess: | 509 case SourceBufferStream::kSuccess: |
526 *status = DemuxerStream::kOk; | 510 *status = DemuxerStream::kOk; |
527 return true; | 511 return true; |
528 case SourceBufferStream::kNeedBuffer: | 512 case SourceBufferStream::kNeedBuffer: |
529 return false; | 513 return false; |
530 case SourceBufferStream::kEndOfStream: | 514 case SourceBufferStream::kEndOfStream: |
531 *status = DemuxerStream::kOk; | 515 *status = DemuxerStream::kOk; |
532 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 516 *buffer = StreamParserBuffer::CreateEOSBuffer(); |
533 return true; | 517 return true; |
534 case SourceBufferStream::kConfigChange: | 518 case SourceBufferStream::kConfigChange: |
535 DVLOG(2) << "Config change reported to ChunkDemuxerStream."; | 519 DVLOG(2) << "Config change reported to ChunkDemuxerStream."; |
536 *status = kConfigChanged; | 520 *status = kConfigChanged; |
537 *buffer = NULL; | 521 *buffer = NULL; |
538 return true; | 522 return true; |
539 } | 523 } |
540 break; | 524 break; |
541 case CANCELED: | 525 case RETURNING_ABORT_FOR_READS: |
542 case WAITING_FOR_SEEK: | |
543 // Null buffers should be returned in this state since we are waiting | 526 // Null buffers should be returned in this state since we are waiting |
544 // for a seek. Any buffers in the SourceBuffer should NOT be returned | 527 // for a seek. Any buffers in the SourceBuffer should NOT be returned |
545 // because they are associated with the seek. | 528 // because they are associated with the seek. |
546 DCHECK(read_cbs_.empty()); | 529 DCHECK(read_cbs_.empty()); |
547 *status = DemuxerStream::kAborted; | 530 *status = DemuxerStream::kAborted; |
548 *buffer = NULL; | 531 *buffer = NULL; |
549 return true; | 532 return true; |
550 case SHUTDOWN: | 533 case SHUTDOWN: |
551 DCHECK(read_cbs_.empty()); | 534 DCHECK(read_cbs_.empty()); |
552 *status = DemuxerStream::kOk; | 535 *status = DemuxerStream::kOk; |
553 *buffer = StreamParserBuffer::CreateEOSBuffer(); | 536 *buffer = StreamParserBuffer::CreateEOSBuffer(); |
554 return true; | 537 return true; |
555 } | 538 } |
556 | 539 |
557 NOTREACHED(); | 540 NOTREACHED(); |
558 return false; | 541 return false; |
559 } | 542 } |
560 | 543 |
561 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, | 544 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, |
562 const NeedKeyCB& need_key_cb, | 545 const NeedKeyCB& need_key_cb, |
563 const AddTextTrackCB& add_text_track_cb, | 546 const AddTextTrackCB& add_text_track_cb, |
564 const LogCB& log_cb) | 547 const LogCB& log_cb) |
565 : state_(WAITING_FOR_INIT), | 548 : state_(WAITING_FOR_INIT), |
| 549 cancel_next_seek_(false), |
566 host_(NULL), | 550 host_(NULL), |
567 open_cb_(open_cb), | 551 open_cb_(open_cb), |
568 need_key_cb_(need_key_cb), | 552 need_key_cb_(need_key_cb), |
569 add_text_track_cb_(add_text_track_cb), | 553 add_text_track_cb_(add_text_track_cb), |
570 log_cb_(log_cb), | 554 log_cb_(log_cb), |
571 duration_(kNoTimestamp()), | 555 duration_(kNoTimestamp()), |
572 user_specified_duration_(-1) { | 556 user_specified_duration_(-1) { |
573 DCHECK(!open_cb_.is_null()); | 557 DCHECK(!open_cb_.is_null()); |
574 DCHECK(!need_key_cb_.is_null()); | 558 DCHECK(!need_key_cb_.is_null()); |
575 } | 559 } |
(...skipping 18 matching lines...) Expand all Loading... |
594 | 578 |
595 void ChunkDemuxer::Stop(const base::Closure& callback) { | 579 void ChunkDemuxer::Stop(const base::Closure& callback) { |
596 DVLOG(1) << "Stop()"; | 580 DVLOG(1) << "Stop()"; |
597 Shutdown(); | 581 Shutdown(); |
598 callback.Run(); | 582 callback.Run(); |
599 } | 583 } |
600 | 584 |
601 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { | 585 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { |
602 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 586 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
603 DCHECK(time >= TimeDelta()); | 587 DCHECK(time >= TimeDelta()); |
| 588 |
| 589 base::AutoLock auto_lock(lock_); |
604 DCHECK(seek_cb_.is_null()); | 590 DCHECK(seek_cb_.is_null()); |
605 | 591 |
606 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | |
607 base::AutoLock auto_lock(lock_); | |
608 | |
609 seek_cb_ = BindToCurrentLoop(cb); | 592 seek_cb_ = BindToCurrentLoop(cb); |
610 if (state_ == INITIALIZED || state_ == ENDED) { | 593 if (state_ != INITIALIZED && state_ != ENDED) { |
611 if (audio_) | 594 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE); |
612 audio_->Seek(time); | 595 return; |
613 | |
614 if (video_) | |
615 video_->Seek(time); | |
616 | |
617 if (IsSeekWaitingForData_Locked()) { | |
618 DVLOG(1) << "Seek() : waiting for more data to arrive."; | |
619 return; | |
620 } | |
621 | |
622 status = PIPELINE_OK; | |
623 } | 596 } |
624 | 597 |
625 base::ResetAndReturn(&seek_cb_).Run(status); | 598 if (cancel_next_seek_) { |
| 599 cancel_next_seek_ = false; |
| 600 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
| 601 return; |
| 602 } |
| 603 |
| 604 if (audio_) |
| 605 audio_->Seek(time); |
| 606 |
| 607 if (video_) |
| 608 video_->Seek(time); |
| 609 |
| 610 if (IsSeekWaitingForData_Locked()) { |
| 611 DVLOG(1) << "Seek() : waiting for more data to arrive."; |
| 612 return; |
| 613 } |
| 614 |
| 615 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
626 } | 616 } |
627 | 617 |
628 void ChunkDemuxer::OnAudioRendererDisabled() { | 618 void ChunkDemuxer::OnAudioRendererDisabled() { |
629 base::AutoLock auto_lock(lock_); | 619 base::AutoLock auto_lock(lock_); |
630 audio_->Shutdown(); | 620 audio_->Shutdown(); |
631 disabled_audio_ = audio_.Pass(); | 621 disabled_audio_ = audio_.Pass(); |
632 } | 622 } |
633 | 623 |
634 // Demuxer implementation. | 624 // Demuxer implementation. |
635 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { | 625 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { |
636 base::AutoLock auto_lock(lock_); | 626 base::AutoLock auto_lock(lock_); |
637 if (type == DemuxerStream::VIDEO) | 627 if (type == DemuxerStream::VIDEO) |
638 return video_.get(); | 628 return video_.get(); |
639 | 629 |
640 if (type == DemuxerStream::AUDIO) | 630 if (type == DemuxerStream::AUDIO) |
641 return audio_.get(); | 631 return audio_.get(); |
642 | 632 |
643 return NULL; | 633 return NULL; |
644 } | 634 } |
645 | 635 |
646 TimeDelta ChunkDemuxer::GetStartTime() const { | 636 TimeDelta ChunkDemuxer::GetStartTime() const { |
647 return TimeDelta(); | 637 return TimeDelta(); |
648 } | 638 } |
649 | 639 |
650 void ChunkDemuxer::StartWaitingForSeek() { | 640 void ChunkDemuxer::StartWaitingForSeek() { |
651 DVLOG(1) << "StartWaitingForSeek()"; | 641 DVLOG(1) << "StartWaitingForSeek()"; |
652 base::AutoLock auto_lock(lock_); | 642 base::AutoLock auto_lock(lock_); |
653 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); | 643 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN); |
| 644 DCHECK(seek_cb_.is_null()); |
654 | 645 |
655 if (state_ == SHUTDOWN) | 646 if (state_ == SHUTDOWN) |
656 return; | 647 return; |
657 | 648 |
658 if (audio_) | 649 if (audio_) |
659 audio_->StartWaitingForSeek(); | 650 audio_->AbortReads(); |
660 | 651 |
661 if (video_) | 652 if (video_) |
662 video_->StartWaitingForSeek(); | 653 video_->AbortReads(); |
| 654 |
| 655 // Cancel state set in CancelPendingSeek() since we want to |
| 656 // accept the next Seek(). |
| 657 cancel_next_seek_ = false; |
663 } | 658 } |
664 | 659 |
665 void ChunkDemuxer::CancelPendingSeek() { | 660 void ChunkDemuxer::CancelPendingSeek() { |
666 base::AutoLock auto_lock(lock_); | 661 base::AutoLock auto_lock(lock_); |
667 DCHECK(seek_cb_.is_null() != IsSeekWaitingForData_Locked()); | 662 DCHECK_NE(state_, INITIALIZING); |
| 663 DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked()); |
| 664 |
| 665 if (cancel_next_seek_) |
| 666 return; |
668 | 667 |
669 if (audio_) | 668 if (audio_) |
670 audio_->CancelPendingSeek(); | 669 audio_->AbortReads(); |
671 | 670 |
672 if (video_) | 671 if (video_) |
673 video_->CancelPendingSeek(); | 672 video_->AbortReads(); |
674 | 673 |
675 if (!seek_cb_.is_null()) | 674 if (seek_cb_.is_null()) { |
676 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | 675 cancel_next_seek_ = true; |
| 676 return; |
| 677 } |
| 678 |
| 679 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); |
677 } | 680 } |
678 | 681 |
679 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, | 682 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
680 const std::string& type, | 683 const std::string& type, |
681 std::vector<std::string>& codecs) { | 684 std::vector<std::string>& codecs) { |
682 DCHECK_GT(codecs.size(), 0u); | 685 DCHECK_GT(codecs.size(), 0u); |
683 base::AutoLock auto_lock(lock_); | 686 base::AutoLock auto_lock(lock_); |
684 | 687 |
685 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) | 688 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
686 return kReachedIdLimit; | 689 return kReachedIdLimit; |
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 } | 1080 } |
1078 | 1081 |
1079 if (duration != TimeDelta() && duration_ == kNoTimestamp()) | 1082 if (duration != TimeDelta() && duration_ == kNoTimestamp()) |
1080 UpdateDuration(duration); | 1083 UpdateDuration(duration); |
1081 | 1084 |
1082 // Wait until all streams have initialized. | 1085 // Wait until all streams have initialized. |
1083 if ((!source_id_audio_.empty() && !audio_) || | 1086 if ((!source_id_audio_.empty() && !audio_) || |
1084 (!source_id_video_.empty() && !video_)) | 1087 (!source_id_video_.empty() && !video_)) |
1085 return; | 1088 return; |
1086 | 1089 |
| 1090 TimeDelta start_time = GetStartTime(); |
1087 if (audio_) | 1091 if (audio_) |
1088 audio_->Seek(TimeDelta()); | 1092 audio_->Seek(start_time); |
1089 | 1093 |
1090 if (video_) | 1094 if (video_) |
1091 video_->Seek(TimeDelta()); | 1095 video_->Seek(start_time); |
1092 | 1096 |
1093 if (duration_ == kNoTimestamp()) | 1097 if (duration_ == kNoTimestamp()) |
1094 duration_ = kInfiniteDuration(); | 1098 duration_ = kInfiniteDuration(); |
1095 | 1099 |
1096 // The demuxer is now initialized after the |start_timestamp_| was set. | 1100 // The demuxer is now initialized after the |start_timestamp_| was set. |
1097 ChangeState_Locked(INITIALIZED); | 1101 ChangeState_Locked(INITIALIZED); |
1098 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 1102 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
1099 } | 1103 } |
1100 | 1104 |
1101 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 1105 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1276 | 1280 |
1277 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1281 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
1278 if (audio_ && !video_) | 1282 if (audio_ && !video_) |
1279 return audio_->GetBufferedRanges(duration_); | 1283 return audio_->GetBufferedRanges(duration_); |
1280 else if (!audio_ && video_) | 1284 else if (!audio_ && video_) |
1281 return video_->GetBufferedRanges(duration_); | 1285 return video_->GetBufferedRanges(duration_); |
1282 return ComputeIntersection(); | 1286 return ComputeIntersection(); |
1283 } | 1287 } |
1284 | 1288 |
1285 } // namespace media | 1289 } // namespace media |
OLD | NEW |