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 "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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |