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()); |
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 |