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/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 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/message_loop/message_loop_proxy.h" | 14 #include "base/message_loop/message_loop_proxy.h" |
| 15 #include "media/base/audio_decoder_config.h" | 15 #include "media/base/audio_decoder_config.h" |
| 16 #include "media/base/bind_to_loop.h" | |
| 16 #include "media/base/stream_parser_buffer.h" | 17 #include "media/base/stream_parser_buffer.h" |
| 17 #include "media/base/video_decoder_config.h" | 18 #include "media/base/video_decoder_config.h" |
| 18 #include "media/filters/stream_parser_factory.h" | 19 #include "media/filters/stream_parser_factory.h" |
| 19 #include "media/webm/webm_webvtt_parser.h" | 20 #include "media/webm/webm_webvtt_parser.h" |
| 20 | 21 |
| 21 using base::TimeDelta; | 22 using base::TimeDelta; |
| 22 | 23 |
| 23 namespace media { | 24 namespace media { |
| 24 | 25 |
| 25 // Contains state belonging to a source id. | 26 // Contains state belonging to a source id. |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 | 201 |
| 201 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, | 202 ChunkDemuxerStream(const AudioDecoderConfig& audio_config, |
| 202 const LogCB& log_cb); | 203 const LogCB& log_cb); |
| 203 ChunkDemuxerStream(const VideoDecoderConfig& video_config, | 204 ChunkDemuxerStream(const VideoDecoderConfig& video_config, |
| 204 const LogCB& log_cb); | 205 const LogCB& log_cb); |
| 205 virtual ~ChunkDemuxerStream(); | 206 virtual ~ChunkDemuxerStream(); |
| 206 | 207 |
| 207 void StartWaitingForSeek(); | 208 void StartWaitingForSeek(); |
| 208 void Seek(TimeDelta time); | 209 void Seek(TimeDelta time); |
| 209 void CancelPendingSeek(); | 210 void CancelPendingSeek(); |
| 210 bool IsSeekPending() const; | 211 bool IsSeekWaitingForData() const; |
| 211 | 212 |
| 212 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 213 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| 213 // which handle ordering and overlap resolution. | 214 // which handle ordering and overlap resolution. |
| 214 // Returns true if buffers were successfully added. | 215 // Returns true if buffers were successfully added. |
| 215 bool Append(const StreamParser::BufferQueue& buffers); | 216 bool Append(const StreamParser::BufferQueue& buffers); |
| 216 | 217 |
| 217 // Signal to the stream that duration has changed to |duration|. | 218 // Signal to the stream that duration has changed to |duration|. |
| 218 void OnSetDuration(base::TimeDelta duration); | 219 void OnSetDuration(TimeDelta duration); |
| 219 | 220 |
| 220 // Returns the range of buffered data in this stream, capped at |duration|. | 221 // Returns the range of buffered data in this stream, capped at |duration|. |
| 221 Ranges<TimeDelta> GetBufferedRanges(base::TimeDelta duration) const; | 222 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const; |
| 222 | 223 |
| 223 // Signal to the stream that buffers handed in through subsequent calls to | 224 // Signal to the stream that buffers handed in through subsequent calls to |
| 224 // Append() belong to a media segment that starts at |start_timestamp|. | 225 // Append() belong to a media segment that starts at |start_timestamp|. |
| 225 void OnNewMediaSegment(TimeDelta start_timestamp); | 226 void OnNewMediaSegment(TimeDelta start_timestamp); |
| 226 | 227 |
| 227 // Called when midstream config updates occur. | 228 // Called when midstream config updates occur. |
| 228 // Returns true if the new config is accepted. | 229 // Returns true if the new config is accepted. |
| 229 // Returns false if the new config should trigger an error. | 230 // Returns false if the new config should trigger an error. |
| 230 bool UpdateAudioConfig(const AudioDecoderConfig& config); | 231 bool UpdateAudioConfig(const AudioDecoderConfig& config); |
| 231 bool UpdateVideoConfig(const VideoDecoderConfig& config); | 232 bool UpdateVideoConfig(const VideoDecoderConfig& config); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 { | 328 { |
| 328 base::AutoLock auto_lock(lock_); | 329 base::AutoLock auto_lock(lock_); |
| 329 ChangeState_Locked(CANCELED); | 330 ChangeState_Locked(CANCELED); |
| 330 std::swap(read_cbs_, read_cbs); | 331 std::swap(read_cbs_, read_cbs); |
| 331 } | 332 } |
| 332 | 333 |
| 333 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) | 334 for (ReadCBQueue::iterator it = read_cbs.begin(); it != read_cbs.end(); ++it) |
| 334 it->Run(kAborted, NULL); | 335 it->Run(kAborted, NULL); |
| 335 } | 336 } |
| 336 | 337 |
| 337 bool ChunkDemuxerStream::IsSeekPending() const { | 338 bool ChunkDemuxerStream::IsSeekWaitingForData() const { |
| 338 base::AutoLock auto_lock(lock_); | 339 base::AutoLock auto_lock(lock_); |
| 339 return stream_->IsSeekPending(); | 340 return stream_->IsSeekPending(); |
| 340 } | 341 } |
| 341 | 342 |
| 342 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { | 343 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { |
| 343 base::AutoLock auto_lock(lock_); | 344 base::AutoLock auto_lock(lock_); |
| 344 stream_->OnNewMediaSegment(start_timestamp); | 345 stream_->OnNewMediaSegment(start_timestamp); |
| 345 } | 346 } |
| 346 | 347 |
| 347 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { | 348 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 358 } | 359 } |
| 359 CreateReadDoneClosures_Locked(&closures); | 360 CreateReadDoneClosures_Locked(&closures); |
| 360 } | 361 } |
| 361 | 362 |
| 362 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) | 363 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) |
| 363 it->Run(); | 364 it->Run(); |
| 364 | 365 |
| 365 return true; | 366 return true; |
| 366 } | 367 } |
| 367 | 368 |
| 368 void ChunkDemuxerStream::OnSetDuration(base::TimeDelta duration) { | 369 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) { |
| 369 base::AutoLock auto_lock(lock_); | 370 base::AutoLock auto_lock(lock_); |
| 370 stream_->OnSetDuration(duration); | 371 stream_->OnSetDuration(duration); |
| 371 } | 372 } |
| 372 | 373 |
| 373 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( | 374 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( |
| 374 base::TimeDelta duration) const { | 375 TimeDelta duration) const { |
| 375 base::AutoLock auto_lock(lock_); | 376 base::AutoLock auto_lock(lock_); |
| 376 Ranges<TimeDelta> range = stream_->GetBufferedTime(); | 377 Ranges<TimeDelta> range = stream_->GetBufferedTime(); |
| 377 | 378 |
| 378 if (range.size() == 0u) | 379 if (range.size() == 0u) |
| 379 return range; | 380 return range; |
| 380 | 381 |
| 381 // Clamp the end of the stream's buffered ranges to fit within the duration. | 382 // Clamp the end of the stream's buffered ranges to fit within the duration. |
| 382 // This can be done by intersecting the stream's range with the valid time | 383 // This can be done by intersecting the stream's range with the valid time |
| 383 // range. | 384 // range. |
| 384 Ranges<TimeDelta> valid_time_range; | 385 Ranges<TimeDelta> valid_time_range; |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 571 user_specified_duration_(-1) { | 572 user_specified_duration_(-1) { |
| 572 DCHECK(!open_cb_.is_null()); | 573 DCHECK(!open_cb_.is_null()); |
| 573 DCHECK(!need_key_cb_.is_null()); | 574 DCHECK(!need_key_cb_.is_null()); |
| 574 } | 575 } |
| 575 | 576 |
| 576 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { | 577 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { |
| 577 DVLOG(1) << "Init()"; | 578 DVLOG(1) << "Init()"; |
| 578 | 579 |
| 579 base::AutoLock auto_lock(lock_); | 580 base::AutoLock auto_lock(lock_); |
| 580 | 581 |
| 582 init_cb_ = BindToCurrentLoop(cb); | |
| 581 if (state_ == SHUTDOWN) { | 583 if (state_ == SHUTDOWN) { |
| 582 base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind( | 584 base::ResetAndReturn(&init_cb_).Run(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 583 cb, DEMUXER_ERROR_COULD_NOT_OPEN)); | |
| 584 return; | 585 return; |
| 585 } | 586 } |
| 586 DCHECK_EQ(state_, WAITING_FOR_INIT); | 587 DCHECK_EQ(state_, WAITING_FOR_INIT); |
| 587 host_ = host; | 588 host_ = host; |
| 588 | 589 |
| 589 ChangeState_Locked(INITIALIZING); | 590 ChangeState_Locked(INITIALIZING); |
| 590 init_cb_ = cb; | |
| 591 | 591 |
| 592 base::ResetAndReturn(&open_cb_).Run(); | 592 base::ResetAndReturn(&open_cb_).Run(); |
| 593 } | 593 } |
| 594 | 594 |
| 595 void ChunkDemuxer::Stop(const base::Closure& callback) { | 595 void ChunkDemuxer::Stop(const base::Closure& callback) { |
| 596 DVLOG(1) << "Stop()"; | 596 DVLOG(1) << "Stop()"; |
| 597 Shutdown(); | 597 Shutdown(); |
| 598 callback.Run(); | 598 callback.Run(); |
| 599 } | 599 } |
| 600 | 600 |
| 601 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { | 601 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { |
| 602 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; | 602 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; |
| 603 DCHECK(time >= TimeDelta()); | 603 DCHECK(time >= TimeDelta()); |
| 604 DCHECK(seek_cb_.is_null()); | 604 DCHECK(seek_cb_.is_null()); |
| 605 | 605 |
| 606 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; | 606 PipelineStatus status = PIPELINE_ERROR_INVALID_STATE; |
| 607 { | 607 base::AutoLock auto_lock(lock_); |
| 608 base::AutoLock auto_lock(lock_); | |
| 609 | 608 |
| 610 if (state_ == INITIALIZED || state_ == ENDED) { | 609 seek_cb_ = BindToCurrentLoop(cb); |
| 611 if (audio_) | 610 if (state_ == INITIALIZED || state_ == ENDED) { |
| 612 audio_->Seek(time); | 611 if (audio_) |
| 612 audio_->Seek(time); | |
| 613 | 613 |
| 614 if (video_) | 614 if (video_) |
| 615 video_->Seek(time); | 615 video_->Seek(time); |
| 616 | 616 |
| 617 if (IsSeekPending_Locked()) { | 617 if (IsSeekWaitingForData_Locked()) { |
| 618 DVLOG(1) << "Seek() : waiting for more data to arrive."; | 618 DVLOG(1) << "Seek() : waiting for more data to arrive."; |
| 619 seek_cb_ = cb; | 619 return; |
| 620 return; | 620 } |
| 621 } | |
| 622 | 621 |
| 623 status = PIPELINE_OK; | 622 status = PIPELINE_OK; |
| 624 } | |
| 625 } | 623 } |
| 626 | 624 |
| 627 cb.Run(status); | 625 base::ResetAndReturn(&seek_cb_).Run(status); |
| 628 } | 626 } |
| 629 | 627 |
| 630 void ChunkDemuxer::OnAudioRendererDisabled() { | 628 void ChunkDemuxer::OnAudioRendererDisabled() { |
| 631 base::AutoLock auto_lock(lock_); | 629 base::AutoLock auto_lock(lock_); |
| 632 audio_->Shutdown(); | 630 audio_->Shutdown(); |
| 633 disabled_audio_ = audio_.Pass(); | 631 disabled_audio_ = audio_.Pass(); |
| 634 } | 632 } |
| 635 | 633 |
| 636 // Demuxer implementation. | 634 // Demuxer implementation. |
| 637 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { | 635 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 658 return; | 656 return; |
| 659 | 657 |
| 660 if (audio_) | 658 if (audio_) |
| 661 audio_->StartWaitingForSeek(); | 659 audio_->StartWaitingForSeek(); |
| 662 | 660 |
| 663 if (video_) | 661 if (video_) |
| 664 video_->StartWaitingForSeek(); | 662 video_->StartWaitingForSeek(); |
| 665 } | 663 } |
| 666 | 664 |
| 667 void ChunkDemuxer::CancelPendingSeek() { | 665 void ChunkDemuxer::CancelPendingSeek() { |
| 668 PipelineStatusCB cb; | 666 base::AutoLock auto_lock(lock_); |
| 669 { | 667 DCHECK(seek_cb_.is_null() ^ IsSeekWaitingForData_Locked()); |
|
xhwang
2013/06/20 22:06:47
s/^/!=/ which may be a little easier to understand
acolwell GONE FROM CHROMIUM
2013/06/20 23:09:37
Done.
| |
| 670 base::AutoLock auto_lock(lock_); | |
| 671 if (IsSeekPending_Locked() && !seek_cb_.is_null()) { | |
| 672 std::swap(cb, seek_cb_); | |
| 673 } | |
| 674 if (audio_) | |
| 675 audio_->CancelPendingSeek(); | |
| 676 | 668 |
| 677 if (video_) | 669 if (audio_) |
| 678 video_->CancelPendingSeek(); | 670 audio_->CancelPendingSeek(); |
| 679 } | |
| 680 | 671 |
| 681 if (!cb.is_null()) | 672 if (video_) |
| 682 cb.Run(PIPELINE_OK); | 673 video_->CancelPendingSeek(); |
| 674 | |
| 675 if (!seek_cb_.is_null()) | |
| 676 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | |
| 683 } | 677 } |
| 684 | 678 |
| 685 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, | 679 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, |
| 686 const std::string& type, | 680 const std::string& type, |
| 687 std::vector<std::string>& codecs) { | 681 std::vector<std::string>& codecs) { |
| 688 DCHECK_GT(codecs.size(), 0u); | 682 DCHECK_GT(codecs.size(), 0u); |
| 689 base::AutoLock auto_lock(lock_); | 683 base::AutoLock auto_lock(lock_); |
| 690 | 684 |
| 691 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) | 685 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) |
| 692 return kReachedIdLimit; | 686 return kReachedIdLimit; |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 808 | 802 |
| 809 void ChunkDemuxer::AppendData(const std::string& id, | 803 void ChunkDemuxer::AppendData(const std::string& id, |
| 810 const uint8* data, | 804 const uint8* data, |
| 811 size_t length) { | 805 size_t length) { |
| 812 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 806 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| 813 | 807 |
| 814 DCHECK(!id.empty()); | 808 DCHECK(!id.empty()); |
| 815 | 809 |
| 816 Ranges<TimeDelta> ranges; | 810 Ranges<TimeDelta> ranges; |
| 817 | 811 |
| 818 PipelineStatusCB cb; | |
| 819 { | 812 { |
| 820 base::AutoLock auto_lock(lock_); | 813 base::AutoLock auto_lock(lock_); |
| 821 | 814 |
| 822 // Capture if the SourceBuffer has a pending seek before we start parsing. | 815 // Capture if any of the SourceBuffers are waiting for data before we start |
| 823 bool old_seek_pending = IsSeekPending_Locked(); | 816 // parsing. |
| 817 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); | |
| 824 | 818 |
| 825 if (state_ == ENDED) { | 819 if (state_ == ENDED) { |
| 826 ChangeState_Locked(INITIALIZED); | 820 ChangeState_Locked(INITIALIZED); |
| 827 | 821 |
| 828 if (audio_) | 822 if (audio_) |
| 829 audio_->CancelEndOfStream(); | 823 audio_->CancelEndOfStream(); |
| 830 | 824 |
| 831 if (video_) | 825 if (video_) |
| 832 video_->CancelEndOfStream(); | 826 video_->CancelEndOfStream(); |
| 833 } | 827 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 860 | 854 |
| 861 case WAITING_FOR_INIT: | 855 case WAITING_FOR_INIT: |
| 862 case ENDED: | 856 case ENDED: |
| 863 case SHUTDOWN: | 857 case SHUTDOWN: |
| 864 DVLOG(1) << "AppendData(): called in unexpected state " << state_; | 858 DVLOG(1) << "AppendData(): called in unexpected state " << state_; |
| 865 return; | 859 return; |
| 866 } | 860 } |
| 867 | 861 |
| 868 // Check to see if data was appended at the pending seek point. This | 862 // Check to see if data was appended at the pending seek point. This |
| 869 // indicates we have parsed enough data to complete the seek. | 863 // indicates we have parsed enough data to complete the seek. |
| 870 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { | 864 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && |
| 871 std::swap(cb, seek_cb_); | 865 !seek_cb_.is_null()) { |
| 866 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | |
| 872 } | 867 } |
| 873 | 868 |
| 874 ranges = GetBufferedRanges(); | 869 ranges = GetBufferedRanges(); |
| 875 } | 870 } |
| 876 | 871 |
| 877 for (size_t i = 0; i < ranges.size(); ++i) | 872 for (size_t i = 0; i < ranges.size(); ++i) |
| 878 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i)); | 873 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i)); |
| 879 | |
| 880 if (!cb.is_null()) | |
| 881 cb.Run(PIPELINE_OK); | |
| 882 } | 874 } |
| 883 | 875 |
| 884 void ChunkDemuxer::Abort(const std::string& id) { | 876 void ChunkDemuxer::Abort(const std::string& id) { |
| 885 DVLOG(1) << "Abort(" << id << ")"; | 877 DVLOG(1) << "Abort(" << id << ")"; |
| 886 base::AutoLock auto_lock(lock_); | 878 base::AutoLock auto_lock(lock_); |
| 887 DCHECK(!id.empty()); | 879 DCHECK(!id.empty()); |
| 888 CHECK(IsValidId(id)); | 880 CHECK(IsValidId(id)); |
| 889 source_state_map_[id]->Abort(); | 881 source_state_map_[id]->Abort(); |
| 890 } | 882 } |
| 891 | 883 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 913 void ChunkDemuxer::SetDuration(double duration) { | 905 void ChunkDemuxer::SetDuration(double duration) { |
| 914 base::AutoLock auto_lock(lock_); | 906 base::AutoLock auto_lock(lock_); |
| 915 DVLOG(1) << "SetDuration(" << duration << ")"; | 907 DVLOG(1) << "SetDuration(" << duration << ")"; |
| 916 DCHECK_GE(duration, 0); | 908 DCHECK_GE(duration, 0); |
| 917 | 909 |
| 918 if (duration == GetDuration_Locked()) | 910 if (duration == GetDuration_Locked()) |
| 919 return; | 911 return; |
| 920 | 912 |
| 921 // Compute & bounds check the TimeDelta representation of duration. | 913 // Compute & bounds check the TimeDelta representation of duration. |
| 922 // This can be different if the value of |duration| doesn't fit the range or | 914 // This can be different if the value of |duration| doesn't fit the range or |
| 923 // precision of base::TimeDelta. | 915 // precision of TimeDelta. |
| 924 base::TimeDelta min_duration = base::TimeDelta::FromInternalValue(1); | 916 TimeDelta min_duration = TimeDelta::FromInternalValue(1); |
| 925 base::TimeDelta max_duration = | 917 TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1); |
| 926 base::TimeDelta::FromInternalValue(kint64max - 1); | |
| 927 double min_duration_in_seconds = min_duration.InSecondsF(); | 918 double min_duration_in_seconds = min_duration.InSecondsF(); |
| 928 double max_duration_in_seconds = max_duration.InSecondsF(); | 919 double max_duration_in_seconds = max_duration.InSecondsF(); |
| 929 | 920 |
| 930 base::TimeDelta duration_td; | 921 TimeDelta duration_td; |
| 931 if (duration == std::numeric_limits<double>::infinity()) { | 922 if (duration == std::numeric_limits<double>::infinity()) { |
| 932 duration_td = media::kInfiniteDuration(); | 923 duration_td = media::kInfiniteDuration(); |
| 933 } else if (duration < min_duration_in_seconds) { | 924 } else if (duration < min_duration_in_seconds) { |
| 934 duration_td = min_duration; | 925 duration_td = min_duration; |
| 935 } else if (duration > max_duration_in_seconds) { | 926 } else if (duration > max_duration_in_seconds) { |
| 936 duration_td = max_duration; | 927 duration_td = max_duration; |
| 937 } else { | 928 } else { |
| 938 duration_td = base::TimeDelta::FromMicroseconds( | 929 duration_td = TimeDelta::FromMicroseconds( |
| 939 duration * base::Time::kMicrosecondsPerSecond); | 930 duration * base::Time::kMicrosecondsPerSecond); |
| 940 } | 931 } |
| 941 | 932 |
| 942 DCHECK(duration_td > base::TimeDelta()); | 933 DCHECK(duration_td > TimeDelta()); |
| 943 | 934 |
| 944 user_specified_duration_ = duration; | 935 user_specified_duration_ = duration; |
| 945 duration_ = duration_td; | 936 duration_ = duration_td; |
| 946 host_->SetDuration(duration_); | 937 host_->SetDuration(duration_); |
| 947 | 938 |
| 948 if (audio_) | 939 if (audio_) |
| 949 audio_->OnSetDuration(duration_); | 940 audio_->OnSetDuration(duration_); |
| 950 | 941 |
| 951 if (video_) | 942 if (video_) |
| 952 video_->OnSetDuration(duration_); | 943 video_->OnSetDuration(duration_); |
| 953 } | 944 } |
| 954 | 945 |
| 955 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { | 946 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { |
| 956 base::AutoLock auto_lock(lock_); | 947 base::AutoLock auto_lock(lock_); |
| 957 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; | 948 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; |
| 958 CHECK(IsValidId(id)); | 949 CHECK(IsValidId(id)); |
| 959 | 950 |
| 960 return source_state_map_[id]->SetTimestampOffset(offset); | 951 return source_state_map_[id]->SetTimestampOffset(offset); |
| 961 } | 952 } |
| 962 | 953 |
| 963 void ChunkDemuxer::EndOfStream(PipelineStatus status) { | 954 void ChunkDemuxer::EndOfStream(PipelineStatus status) { |
| 964 DVLOG(1) << "EndOfStream(" << status << ")"; | 955 DVLOG(1) << "EndOfStream(" << status << ")"; |
| 965 PipelineStatusCB cb; | 956 base::AutoLock auto_lock(lock_); |
| 966 { | 957 DCHECK_NE(state_, WAITING_FOR_INIT); |
| 967 base::AutoLock auto_lock(lock_); | 958 DCHECK_NE(state_, ENDED); |
| 968 DCHECK_NE(state_, WAITING_FOR_INIT); | |
| 969 DCHECK_NE(state_, ENDED); | |
| 970 | 959 |
| 971 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 960 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
| 972 return; | 961 return; |
| 973 | 962 |
| 974 if (state_ == INITIALIZING) { | 963 if (state_ == INITIALIZING) { |
| 975 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 964 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 976 return; | 965 return; |
| 977 } | |
| 978 | |
| 979 bool old_seek_pending = IsSeekPending_Locked(); | |
| 980 if (audio_) | |
| 981 audio_->EndOfStream(); | |
| 982 | |
| 983 if (video_) | |
| 984 video_->EndOfStream(); | |
| 985 | |
| 986 // Give a chance to resume the pending seek process. | |
| 987 if (status != PIPELINE_OK) { | |
| 988 ReportError_Locked(status); | |
| 989 return; | |
| 990 } | |
| 991 | |
| 992 ChangeState_Locked(ENDED); | |
| 993 DecreaseDurationIfNecessary(); | |
| 994 | |
| 995 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) | |
| 996 std::swap(cb, seek_cb_); | |
| 997 } | 966 } |
| 998 | 967 |
| 999 if (!cb.is_null()) | 968 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); |
| 1000 cb.Run(PIPELINE_OK); | 969 if (audio_) |
| 970 audio_->EndOfStream(); | |
| 971 | |
| 972 if (video_) | |
| 973 video_->EndOfStream(); | |
| 974 | |
| 975 // Give a chance to resume the pending seek process. | |
| 976 if (status != PIPELINE_OK) { | |
| 977 ReportError_Locked(status); | |
| 978 return; | |
| 979 } | |
| 980 | |
| 981 ChangeState_Locked(ENDED); | |
| 982 DecreaseDurationIfNecessary(); | |
| 983 | |
| 984 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && | |
| 985 !seek_cb_.is_null()) { | |
| 986 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); | |
| 987 } | |
| 1001 } | 988 } |
| 1002 | 989 |
| 1003 void ChunkDemuxer::Shutdown() { | 990 void ChunkDemuxer::Shutdown() { |
| 1004 DVLOG(1) << "Shutdown()"; | 991 DVLOG(1) << "Shutdown()"; |
| 1005 PipelineStatusCB cb; | 992 base::AutoLock auto_lock(lock_); |
| 1006 { | |
| 1007 base::AutoLock auto_lock(lock_); | |
| 1008 | 993 |
| 1009 if (state_ == SHUTDOWN) | 994 if (state_ == SHUTDOWN) |
| 1010 return; | 995 return; |
| 1011 | 996 |
| 1012 std::swap(cb, seek_cb_); | 997 if (audio_) |
| 998 audio_->Shutdown(); | |
| 1013 | 999 |
| 1014 if (audio_) | 1000 if (video_) |
| 1015 audio_->Shutdown(); | 1001 video_->Shutdown(); |
| 1016 | 1002 |
| 1017 if (video_) | 1003 ChangeState_Locked(SHUTDOWN); |
| 1018 video_->Shutdown(); | |
| 1019 | 1004 |
| 1020 ChangeState_Locked(SHUTDOWN); | 1005 if(!seek_cb_.is_null()) |
| 1021 } | 1006 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT); |
| 1022 | |
| 1023 if (!cb.is_null()) | |
| 1024 cb.Run(PIPELINE_ERROR_ABORT); | |
| 1025 } | 1007 } |
| 1026 | 1008 |
| 1027 void ChunkDemuxer::ChangeState_Locked(State new_state) { | 1009 void ChunkDemuxer::ChangeState_Locked(State new_state) { |
| 1028 lock_.AssertAcquired(); | 1010 lock_.AssertAcquired(); |
| 1029 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " | 1011 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " |
| 1030 << state_ << " -> " << new_state; | 1012 << state_ << " -> " << new_state; |
| 1031 state_ = new_state; | 1013 state_ = new_state; |
| 1032 } | 1014 } |
| 1033 | 1015 |
| 1034 ChunkDemuxer::~ChunkDemuxer() { | 1016 ChunkDemuxer::~ChunkDemuxer() { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1056 std::swap(cb, seek_cb_); | 1038 std::swap(cb, seek_cb_); |
| 1057 | 1039 |
| 1058 if (audio_) | 1040 if (audio_) |
| 1059 audio_->Shutdown(); | 1041 audio_->Shutdown(); |
| 1060 | 1042 |
| 1061 if (video_) | 1043 if (video_) |
| 1062 video_->Shutdown(); | 1044 video_->Shutdown(); |
| 1063 } | 1045 } |
| 1064 | 1046 |
| 1065 if (!cb.is_null()) { | 1047 if (!cb.is_null()) { |
| 1066 base::AutoUnlock auto_unlock(lock_); | |
| 1067 cb.Run(error); | 1048 cb.Run(error); |
| 1068 return; | 1049 return; |
| 1069 } | 1050 } |
| 1070 | 1051 |
| 1071 base::AutoUnlock auto_unlock(lock_); | 1052 base::AutoUnlock auto_unlock(lock_); |
| 1072 host_->OnDemuxerError(error); | 1053 host_->OnDemuxerError(error); |
| 1073 } | 1054 } |
| 1074 | 1055 |
| 1075 bool ChunkDemuxer::IsSeekPending_Locked() const { | 1056 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const { |
| 1076 lock_.AssertAcquired(); | 1057 lock_.AssertAcquired(); |
| 1077 bool seek_pending = false; | 1058 bool waiting_for_data = false; |
| 1078 | 1059 |
| 1079 if (audio_) | 1060 if (audio_) |
| 1080 seek_pending = audio_->IsSeekPending(); | 1061 waiting_for_data = audio_->IsSeekWaitingForData(); |
| 1081 | 1062 |
| 1082 if (!seek_pending && video_) | 1063 if (!waiting_for_data && video_) |
| 1083 seek_pending = video_->IsSeekPending(); | 1064 waiting_for_data = video_->IsSeekWaitingForData(); |
| 1084 | 1065 |
| 1085 return seek_pending; | 1066 return waiting_for_data; |
| 1086 } | 1067 } |
| 1087 | 1068 |
| 1088 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { | 1069 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { |
| 1089 DVLOG(1) << "OnSourceInitDone(" << success << ", " | 1070 DVLOG(1) << "OnSourceInitDone(" << success << ", " |
| 1090 << duration.InSecondsF() << ")"; | 1071 << duration.InSecondsF() << ")"; |
| 1091 lock_.AssertAcquired(); | 1072 lock_.AssertAcquired(); |
| 1092 DCHECK_EQ(state_, INITIALIZING); | 1073 DCHECK_EQ(state_, INITIALIZING); |
| 1093 if (!success || (!audio_ && !video_)) { | 1074 if (!success || (!audio_ && !video_)) { |
| 1094 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1075 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 1095 return; | 1076 return; |
| 1096 } | 1077 } |
| 1097 | 1078 |
| 1098 if (duration != base::TimeDelta() && duration_ == kNoTimestamp()) | 1079 if (duration != TimeDelta() && duration_ == kNoTimestamp()) |
| 1099 UpdateDuration(duration); | 1080 UpdateDuration(duration); |
| 1100 | 1081 |
| 1101 // Wait until all streams have initialized. | 1082 // Wait until all streams have initialized. |
| 1102 if ((!source_id_audio_.empty() && !audio_) || | 1083 if ((!source_id_audio_.empty() && !audio_) || |
| 1103 (!source_id_video_.empty() && !video_)) | 1084 (!source_id_video_.empty() && !video_)) |
| 1104 return; | 1085 return; |
| 1105 | 1086 |
| 1106 if (audio_) | 1087 if (audio_) |
| 1107 audio_->Seek(TimeDelta()); | 1088 audio_->Seek(TimeDelta()); |
| 1108 | 1089 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1209 TextTrack* text_track, | 1190 TextTrack* text_track, |
| 1210 const StreamParser::BufferQueue& buffers) { | 1191 const StreamParser::BufferQueue& buffers) { |
| 1211 lock_.AssertAcquired(); | 1192 lock_.AssertAcquired(); |
| 1212 DCHECK_NE(state_, SHUTDOWN); | 1193 DCHECK_NE(state_, SHUTDOWN); |
| 1213 | 1194 |
| 1214 // TODO(matthewjheaney): IncreaseDurationIfNecessary | 1195 // TODO(matthewjheaney): IncreaseDurationIfNecessary |
| 1215 | 1196 |
| 1216 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 1197 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 1217 itr != buffers.end(); ++itr) { | 1198 itr != buffers.end(); ++itr) { |
| 1218 const StreamParserBuffer* const buffer = itr->get(); | 1199 const StreamParserBuffer* const buffer = itr->get(); |
| 1219 const base::TimeDelta start = buffer->GetTimestamp(); | 1200 const TimeDelta start = buffer->GetTimestamp(); |
| 1220 const base::TimeDelta end = start + buffer->GetDuration(); | 1201 const TimeDelta end = start + buffer->GetDuration(); |
| 1221 | 1202 |
| 1222 std::string id, settings, content; | 1203 std::string id, settings, content; |
| 1223 | 1204 |
| 1224 WebMWebVTTParser::Parse(buffer->GetData(), | 1205 WebMWebVTTParser::Parse(buffer->GetData(), |
| 1225 buffer->GetDataSize(), | 1206 buffer->GetDataSize(), |
| 1226 &id, &settings, &content); | 1207 &id, &settings, &content); |
| 1227 | 1208 |
| 1228 text_track->addWebVTTCue(start, end, id, content, settings); | 1209 text_track->addWebVTTCue(start, end, id, content, settings); |
| 1229 } | 1210 } |
| 1230 | 1211 |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1254 audio_->OnNewMediaSegment(timestamp); | 1235 audio_->OnNewMediaSegment(timestamp); |
| 1255 if (video_ && source_id == source_id_video_) | 1236 if (video_ && source_id == source_id_video_) |
| 1256 video_->OnNewMediaSegment(timestamp); | 1237 video_->OnNewMediaSegment(timestamp); |
| 1257 } | 1238 } |
| 1258 | 1239 |
| 1259 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 1240 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
| 1260 lock_.AssertAcquired(); | 1241 lock_.AssertAcquired(); |
| 1261 return source_state_map_.count(source_id) > 0u; | 1242 return source_state_map_.count(source_id) > 0u; |
| 1262 } | 1243 } |
| 1263 | 1244 |
| 1264 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) { | 1245 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { |
| 1265 DCHECK(duration_ != new_duration); | 1246 DCHECK(duration_ != new_duration); |
| 1266 user_specified_duration_ = -1; | 1247 user_specified_duration_ = -1; |
| 1267 duration_ = new_duration; | 1248 duration_ = new_duration; |
| 1268 host_->SetDuration(new_duration); | 1249 host_->SetDuration(new_duration); |
| 1269 } | 1250 } |
| 1270 | 1251 |
| 1271 void ChunkDemuxer::IncreaseDurationIfNecessary( | 1252 void ChunkDemuxer::IncreaseDurationIfNecessary( |
| 1272 const StreamParser::BufferQueue& buffers, | 1253 const StreamParser::BufferQueue& buffers, |
| 1273 ChunkDemuxerStream* stream) { | 1254 ChunkDemuxerStream* stream) { |
| 1274 DCHECK(!buffers.empty()); | 1255 DCHECK(!buffers.empty()); |
| 1275 if (buffers.back()->GetTimestamp() <= duration_) | 1256 if (buffers.back()->GetTimestamp() <= duration_) |
| 1276 return; | 1257 return; |
| 1277 | 1258 |
| 1278 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); | 1259 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); |
| 1279 DCHECK_GT(ranges.size(), 0u); | 1260 DCHECK_GT(ranges.size(), 0u); |
| 1280 | 1261 |
| 1281 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1262 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1282 if (last_timestamp_buffered > duration_) | 1263 if (last_timestamp_buffered > duration_) |
| 1283 UpdateDuration(last_timestamp_buffered); | 1264 UpdateDuration(last_timestamp_buffered); |
| 1284 } | 1265 } |
| 1285 | 1266 |
| 1286 void ChunkDemuxer::DecreaseDurationIfNecessary() { | 1267 void ChunkDemuxer::DecreaseDurationIfNecessary() { |
| 1287 Ranges<TimeDelta> ranges = GetBufferedRanges(); | 1268 Ranges<TimeDelta> ranges = GetBufferedRanges(); |
| 1288 if (ranges.size() == 0u) | 1269 if (ranges.size() == 0u) |
| 1289 return; | 1270 return; |
| 1290 | 1271 |
| 1291 base::TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); | 1272 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); |
| 1292 if (last_timestamp_buffered < duration_) | 1273 if (last_timestamp_buffered < duration_) |
| 1293 UpdateDuration(last_timestamp_buffered); | 1274 UpdateDuration(last_timestamp_buffered); |
| 1294 } | 1275 } |
| 1295 | 1276 |
| 1296 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { | 1277 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { |
| 1297 if (audio_ && !video_) | 1278 if (audio_ && !video_) |
| 1298 return audio_->GetBufferedRanges(duration_); | 1279 return audio_->GetBufferedRanges(duration_); |
| 1299 else if (!audio_ && video_) | 1280 else if (!audio_ && video_) |
| 1300 return video_->GetBufferedRanges(duration_); | 1281 return video_->GetBufferedRanges(duration_); |
| 1301 return ComputeIntersection(); | 1282 return ComputeIntersection(); |
| 1302 } | 1283 } |
| 1303 | 1284 |
| 1304 } // namespace media | 1285 } // namespace media |
| OLD | NEW |