Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(140)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 17261029: Fix ChunkDemuxer seek and init callback dispatch. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make DCHECK in CancelPendingSeek() more restrictive. Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698