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

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

Issue 10581050: Ensure media's buffered ranges always have a range that includes currentTime. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 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/base/ranges.cc ('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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 74
75 static const SupportedTypeInfo kSupportedTypeInfo[] = { 75 static const SupportedTypeInfo kSupportedTypeInfo[] = {
76 { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, 76 { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
77 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, 77 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
78 #if defined(USE_PROPRIETARY_CODECS) 78 #if defined(USE_PROPRIETARY_CODECS)
79 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, 79 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
80 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, 80 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
81 #endif 81 #endif
82 }; 82 };
83 83
84
85 // The fake total size we use for converting times to bytes
86 // for AddBufferedByteRange() calls.
87 // TODO(acolwell): Remove this once Pipeline accepts buffered times
88 // instead of only buffered bytes.
89 enum { kFakeTotalBytes = 1000000 };
90
91 // Checks to see if the specified |type| and |codecs| list are supported. 84 // Checks to see if the specified |type| and |codecs| list are supported.
92 // Returns true if |type| and all codecs listed in |codecs| are supported. 85 // Returns true if |type| and all codecs listed in |codecs| are supported.
93 // |factory_function| contains a function that can build a StreamParser 86 // |factory_function| contains a function that can build a StreamParser
94 // for this type. 87 // for this type.
95 // |has_audio| is true if an audio codec was specified. 88 // |has_audio| is true if an audio codec was specified.
96 // |has_video| is true if a video codec was specified. 89 // |has_video| is true if a video codec was specified.
97 // Returns false otherwise. The values of |factory_function|, |has_audio|, 90 // Returns false otherwise. The values of |factory_function|, |has_audio|,
98 // and |has_video| are undefined. 91 // and |has_video| are undefined.
99 static bool IsSupported(const std::string& type, 92 static bool IsSupported(const std::string& type,
100 std::vector<std::string>& codecs, 93 std::vector<std::string>& codecs,
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 void StartWaitingForSeek(); 157 void StartWaitingForSeek();
165 void Seek(TimeDelta time); 158 void Seek(TimeDelta time);
166 bool IsSeekPending() const; 159 bool IsSeekPending() const;
167 void Flush(); 160 void Flush();
168 161
169 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, 162 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
170 // which handle ordering and overlap resolution. 163 // which handle ordering and overlap resolution.
171 // Returns true if buffers were successfully added. 164 // Returns true if buffers were successfully added.
172 bool Append(const StreamParser::BufferQueue& buffers); 165 bool Append(const StreamParser::BufferQueue& buffers);
173 166
174 // Returns a list of the buffered time ranges.
175 Ranges<TimeDelta> GetBufferedTime() const;
176
177 // Signal to the stream that buffers handed in through subsequent calls to 167 // Signal to the stream that buffers handed in through subsequent calls to
178 // Append() belong to a media segment that starts at |start_timestamp|. 168 // Append() belong to a media segment that starts at |start_timestamp|.
179 void OnNewMediaSegment(TimeDelta start_timestamp); 169 void OnNewMediaSegment(TimeDelta start_timestamp);
180 170
181 // Called when mid-stream config updates occur. 171 // Called when mid-stream config updates occur.
182 // Returns true if the new config is accepted. 172 // Returns true if the new config is accepted.
183 // Returns false if the new config should trigger an error. 173 // Returns false if the new config should trigger an error.
184 bool UpdateAudioConfig(const AudioDecoderConfig& config); 174 bool UpdateAudioConfig(const AudioDecoderConfig& config);
185 bool UpdateVideoConfig(const VideoDecoderConfig& config); 175 bool UpdateVideoConfig(const VideoDecoderConfig& config);
186 176
187 void EndOfStream(); 177 void EndOfStream();
188 bool CanEndOfStream() const; 178 bool CanEndOfStream() const;
189 void Shutdown(); 179 void Shutdown();
190 180
191 // DemuxerStream methods. 181 // DemuxerStream methods.
192 virtual void Read(const ReadCB& read_cb) OVERRIDE; 182 virtual void Read(const ReadCB& read_cb) OVERRIDE;
193 virtual Type type() OVERRIDE; 183 virtual Type type() OVERRIDE;
194 virtual void EnableBitstreamConverter() OVERRIDE; 184 virtual void EnableBitstreamConverter() OVERRIDE;
195 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE; 185 virtual const AudioDecoderConfig& audio_decoder_config() OVERRIDE;
196 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE; 186 virtual const VideoDecoderConfig& video_decoder_config() OVERRIDE;
187 virtual Ranges<TimeDelta> GetBufferedRanges() OVERRIDE;
197 188
198 protected: 189 protected:
199 virtual ~ChunkDemuxerStream(); 190 virtual ~ChunkDemuxerStream();
200 191
201 private: 192 private:
202 enum State { 193 enum State {
203 RETURNING_DATA_FOR_READS, 194 RETURNING_DATA_FOR_READS,
204 WAITING_FOR_SEEK, 195 WAITING_FOR_SEEK,
205 SHUTDOWN, 196 SHUTDOWN,
206 }; 197 };
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 } 289 }
299 CreateReadDoneClosures_Locked(&closures); 290 CreateReadDoneClosures_Locked(&closures);
300 } 291 }
301 292
302 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) 293 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it)
303 it->Run(); 294 it->Run();
304 295
305 return true; 296 return true;
306 } 297 }
307 298
308 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedTime() const { 299 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges() {
309 base::AutoLock auto_lock(lock_); 300 base::AutoLock auto_lock(lock_);
310 return stream_->GetBufferedTime(); 301 return stream_->GetBufferedTime();
311 } 302 }
312 303
313 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { 304 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) {
314 DCHECK(config.IsValidConfig()); 305 DCHECK(config.IsValidConfig());
315 DCHECK_EQ(type_, AUDIO); 306 DCHECK_EQ(type_, AUDIO);
316 307
317 const AudioDecoderConfig& current_config = 308 const AudioDecoderConfig& current_config =
318 stream_->GetCurrentAudioDecoderConfig(); 309 stream_->GetCurrentAudioDecoderConfig();
(...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after
643 634
644 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 635 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
645 DCHECK(!id.empty()); 636 DCHECK(!id.empty());
646 DCHECK_GT(stream_parser_map_.count(id), 0u); 637 DCHECK_GT(stream_parser_map_.count(id), 0u);
647 DCHECK(id == source_id_audio_ || id == source_id_video_); 638 DCHECK(id == source_id_audio_ || id == source_id_video_);
648 639
649 base::AutoLock auto_lock(lock_); 640 base::AutoLock auto_lock(lock_);
650 641
651 if (id == source_id_audio_ && id != source_id_video_) { 642 if (id == source_id_audio_ && id != source_id_video_) {
652 // Only include ranges that have been buffered in |audio_| 643 // Only include ranges that have been buffered in |audio_|
653 return audio_ ? audio_->GetBufferedTime() : Ranges<TimeDelta>(); 644 return audio_ ? audio_->GetBufferedRanges() : Ranges<TimeDelta>();
654 } 645 }
655 646
656 if (id != source_id_audio_ && id == source_id_video_) { 647 if (id != source_id_audio_ && id == source_id_video_) {
657 // Only include ranges that have been buffered in |video_| 648 // Only include ranges that have been buffered in |video_|
658 return video_ ? video_->GetBufferedTime() : Ranges<TimeDelta>(); 649 return video_ ? video_->GetBufferedRanges() : Ranges<TimeDelta>();
659 } 650 }
660 651
661 return ComputeIntersection(); 652 return ComputeIntersection();
662 } 653 }
663 654
664 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const { 655 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const {
665 lock_.AssertAcquired(); 656 lock_.AssertAcquired();
666 657
667 if (!audio_ || !video_) 658 if (!audio_ || !video_)
668 return Ranges<TimeDelta>(); 659 return Ranges<TimeDelta>();
669 660
670 // Include ranges that have been buffered in both |audio_| and |video_|. 661 // Include ranges that have been buffered in both |audio_| and |video_|.
671 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedTime(); 662 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges();
672 Ranges<TimeDelta> video_ranges = video_->GetBufferedTime(); 663 Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges();
673 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges); 664 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges);
674 665
675 if (state_ == ENDED && result.size() > 0) { 666 if (state_ == ENDED && result.size() > 0) {
676 // If appending has ended, extend the last intersection range to include the 667 // If appending has ended, extend the last intersection range to include the
677 // max end time of the last audio/video range. This allows the buffered 668 // max end time of the last audio/video range. This allows the buffered
678 // information to match the actual time range that will get played out if 669 // information to match the actual time range that will get played out if
679 // the streams have slightly different lengths. 670 // the streams have slightly different lengths.
680 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); 671 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1);
681 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); 672 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1);
682 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); 673 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 } 728 }
738 729
739 // Check to see if data was appended at the pending seek point. This 730 // Check to see if data was appended at the pending seek point. This
740 // indicates we have parsed enough data to complete the seek. 731 // indicates we have parsed enough data to complete the seek.
741 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { 732 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) {
742 std::swap(cb, seek_cb_); 733 std::swap(cb, seek_cb_);
743 } 734 }
744 735
745 if (duration_ > TimeDelta() && duration_ != kInfiniteDuration()) { 736 if (duration_ > TimeDelta() && duration_ != kInfiniteDuration()) {
746 if (audio_ && !video_) { 737 if (audio_ && !video_) {
747 ranges = audio_->GetBufferedTime(); 738 ranges = audio_->GetBufferedRanges();
748 } else if (!audio_ && video_) { 739 } else if (!audio_ && video_) {
749 ranges = video_->GetBufferedTime(); 740 ranges = video_->GetBufferedRanges();
750 } else { 741 } else {
751 ranges = ComputeIntersection(); 742 ranges = ComputeIntersection();
752 } 743 }
753 } 744 }
754 } 745 }
755 746
756 DCHECK(!ranges.size() || duration_ > TimeDelta()); 747 for (size_t i = 0; i < ranges.size(); ++i)
757 for (size_t i = 0; i < ranges.size(); ++i) { 748 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i));
758 // Notify the host of 'network activity' because we got data.
759 int64 start =
760 kFakeTotalBytes * ranges.start(i).InSecondsF() / duration_.InSecondsF();
761 int64 end =
762 kFakeTotalBytes * ranges.end(i).InSecondsF() / duration_.InSecondsF();
763 host_->AddBufferedByteRange(start, end);
764 }
765 749
766 if (!cb.is_null()) 750 if (!cb.is_null())
767 cb.Run(PIPELINE_OK); 751 cb.Run(PIPELINE_OK);
768 752
769 return true; 753 return true;
770 } 754 }
771 755
772 void ChunkDemuxer::Abort(const std::string& id) { 756 void ChunkDemuxer::Abort(const std::string& id) {
773 DVLOG(1) << "Abort(" << id << ")"; 757 DVLOG(1) << "Abort(" << id << ")";
774 DCHECK(!id.empty()); 758 DCHECK(!id.empty());
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 } 906 }
923 907
924 if (duration > duration_) 908 if (duration > duration_)
925 duration_ = duration; 909 duration_ = duration;
926 910
927 // Wait until all streams have initialized. 911 // Wait until all streams have initialized.
928 if ((!source_id_audio_.empty() && !audio_) || 912 if ((!source_id_audio_.empty() && !audio_) ||
929 (!source_id_video_.empty() && !video_)) 913 (!source_id_video_.empty() && !video_))
930 return; 914 return;
931 915
932 if (duration_ > TimeDelta() && duration_ != kInfiniteDuration())
933 host_->SetTotalBytes(kFakeTotalBytes);
934 host_->SetDuration(duration_); 916 host_->SetDuration(duration_);
935 917
936 ChangeState_Locked(INITIALIZED); 918 ChangeState_Locked(INITIALIZED);
937 PipelineStatusCB cb; 919 PipelineStatusCB cb;
938 std::swap(cb, init_cb_); 920 std::swap(cb, init_cb_);
939 cb.Run(PIPELINE_OK); 921 cb.Run(PIPELINE_OK);
940 } 922 }
941 923
942 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, 924 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
943 const AudioDecoderConfig& audio_config, 925 const AudioDecoderConfig& audio_config,
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 // TODO(vrk): There should be a special case for the first appends where all 994 // TODO(vrk): There should be a special case for the first appends where all
1013 // streams (for both demuxed and muxed case) begin at the earliest stream 995 // streams (for both demuxed and muxed case) begin at the earliest stream
1014 // timestamp. (crbug.com/132815) 996 // timestamp. (crbug.com/132815)
1015 if (audio_ && source_id == source_id_audio_) 997 if (audio_ && source_id == source_id_audio_)
1016 audio_->OnNewMediaSegment(start_timestamp); 998 audio_->OnNewMediaSegment(start_timestamp);
1017 if (video_ && source_id == source_id_video_) 999 if (video_ && source_id == source_id_video_)
1018 video_->OnNewMediaSegment(start_timestamp); 1000 video_->OnNewMediaSegment(start_timestamp);
1019 } 1001 }
1020 1002
1021 } // namespace media 1003 } // namespace media
OLDNEW
« no previous file with comments | « media/base/ranges.cc ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698