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/source_buffer_stream.h" | 5 #include "media/filters/source_buffer_stream.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <map> | 8 #include <map> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/stl_util.h" |
12 | 13 |
13 namespace media { | 14 namespace media { |
14 | 15 |
15 // Helper class representing a range of buffered data. All buffers in a | 16 // Helper class representing a range of buffered data. All buffers in a |
16 // SourceBufferRange are ordered sequentially in presentation order with no | 17 // SourceBufferRange are ordered sequentially in presentation order with no |
17 // gaps. | 18 // gaps. |
18 class SourceBufferRange { | 19 class SourceBufferRange { |
19 public: | 20 public: |
20 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 21 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
21 | 22 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 bool DeleteAll(BufferQueue* deleted_buffers); | 87 bool DeleteAll(BufferQueue* deleted_buffers); |
87 | 88 |
88 // Updates |out_buffer| with the next buffer in presentation order. Seek() | 89 // Updates |out_buffer| with the next buffer in presentation order. Seek() |
89 // must be called before calls to GetNextBuffer(), and buffers are returned | 90 // must be called before calls to GetNextBuffer(), and buffers are returned |
90 // in order from the last call to Seek(). Returns true if |out_buffer| is | 91 // in order from the last call to Seek(). Returns true if |out_buffer| is |
91 // filled with a valid buffer, false if there is not enough data to fulfill | 92 // filled with a valid buffer, false if there is not enough data to fulfill |
92 // the request. | 93 // the request. |
93 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); | 94 bool GetNextBuffer(scoped_refptr<StreamParserBuffer>* out_buffer); |
94 bool HasNextBuffer() const; | 95 bool HasNextBuffer() const; |
95 | 96 |
| 97 // Returns the config ID for the buffer that will be returned by |
| 98 // GetNextBuffer(). |
| 99 int GetNextConfigId() const; |
| 100 |
96 // Returns true if the range knows the position of the next buffer it should | 101 // Returns true if the range knows the position of the next buffer it should |
97 // return, i.e. it has been Seek()ed. This does not necessarily mean that it | 102 // return, i.e. it has been Seek()ed. This does not necessarily mean that it |
98 // has the next buffer yet. | 103 // has the next buffer yet. |
99 bool HasNextBufferPosition() const; | 104 bool HasNextBufferPosition() const; |
100 | 105 |
101 // Resets this range to an "unseeked" state. | 106 // Resets this range to an "unseeked" state. |
102 void ResetNextBufferPosition(); | 107 void ResetNextBufferPosition(); |
103 | 108 |
104 // Returns the timestamp of the next buffer that will be returned from | 109 // Returns the timestamp of the next buffer that will be returned from |
105 // GetNextBuffer(), or kNoTimestamp() if the timestamp is unknown. | 110 // GetNextBuffer(), or kNoTimestamp() if the timestamp is unknown. |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 return first->GetDecodeTimestamp() < second->GetDecodeTimestamp(); | 227 return first->GetDecodeTimestamp() < second->GetDecodeTimestamp(); |
223 } | 228 } |
224 | 229 |
225 // An arbitrarily-chosen number to estimate the duration of a buffer if none | 230 // An arbitrarily-chosen number to estimate the duration of a buffer if none |
226 // is set and there's not enough information to get a better estimate. | 231 // is set and there's not enough information to get a better estimate. |
227 static int kDefaultBufferDurationInMs = 125; | 232 static int kDefaultBufferDurationInMs = 125; |
228 | 233 |
229 namespace media { | 234 namespace media { |
230 | 235 |
231 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) | 236 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config) |
232 : stream_start_time_(kNoTimestamp()), | 237 : current_config_index_(0), |
| 238 append_config_index_(0), |
| 239 audio_configs_(1), |
| 240 video_configs_(0), |
| 241 stream_start_time_(kNoTimestamp()), |
233 seek_pending_(false), | 242 seek_pending_(false), |
234 seek_buffer_timestamp_(kNoTimestamp()), | 243 seek_buffer_timestamp_(kNoTimestamp()), |
235 selected_range_(NULL), | 244 selected_range_(NULL), |
236 media_segment_start_time_(kNoTimestamp()), | 245 media_segment_start_time_(kNoTimestamp()), |
237 range_for_next_append_(ranges_.end()), | 246 range_for_next_append_(ranges_.end()), |
238 new_media_segment_(false), | 247 new_media_segment_(false), |
239 last_buffer_timestamp_(kNoTimestamp()), | 248 last_buffer_timestamp_(kNoTimestamp()), |
240 max_interbuffer_distance_(kNoTimestamp()) { | 249 max_interbuffer_distance_(kNoTimestamp()) { |
241 audio_config_.CopyFrom(audio_config); | 250 audio_configs_[0] = new AudioDecoderConfig(); |
| 251 audio_configs_[0]->CopyFrom(audio_config); |
242 } | 252 } |
243 | 253 |
244 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) | 254 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config) |
245 : stream_start_time_(kNoTimestamp()), | 255 : current_config_index_(0), |
| 256 append_config_index_(0), |
| 257 audio_configs_(0), |
| 258 video_configs_(1), |
| 259 stream_start_time_(kNoTimestamp()), |
246 seek_pending_(false), | 260 seek_pending_(false), |
247 seek_buffer_timestamp_(kNoTimestamp()), | 261 seek_buffer_timestamp_(kNoTimestamp()), |
248 selected_range_(NULL), | 262 selected_range_(NULL), |
249 media_segment_start_time_(kNoTimestamp()), | 263 media_segment_start_time_(kNoTimestamp()), |
250 range_for_next_append_(ranges_.end()), | 264 range_for_next_append_(ranges_.end()), |
251 new_media_segment_(false), | 265 new_media_segment_(false), |
252 last_buffer_timestamp_(kNoTimestamp()), | 266 last_buffer_timestamp_(kNoTimestamp()), |
253 max_interbuffer_distance_(kNoTimestamp()) { | 267 max_interbuffer_distance_(kNoTimestamp()) { |
254 video_config_.CopyFrom(video_config); | 268 video_configs_[0] = new VideoDecoderConfig(); |
| 269 video_configs_[0]->CopyFrom(video_config); |
255 } | 270 } |
256 | 271 |
257 SourceBufferStream::~SourceBufferStream() { | 272 SourceBufferStream::~SourceBufferStream() { |
258 while (!ranges_.empty()) { | 273 while (!ranges_.empty()) { |
259 delete ranges_.front(); | 274 delete ranges_.front(); |
260 ranges_.pop_front(); | 275 ranges_.pop_front(); |
261 } | 276 } |
| 277 |
| 278 STLDeleteElements(&audio_configs_); |
| 279 STLDeleteElements(&video_configs_); |
262 } | 280 } |
263 | 281 |
264 void SourceBufferStream::OnNewMediaSegment( | 282 void SourceBufferStream::OnNewMediaSegment( |
265 base::TimeDelta media_segment_start_time) { | 283 base::TimeDelta media_segment_start_time) { |
266 media_segment_start_time_ = media_segment_start_time; | 284 media_segment_start_time_ = media_segment_start_time; |
267 | 285 |
268 // Find the range that will house the buffers appended through the next | 286 // Find the range that will house the buffers appended through the next |
269 // Append() call. | 287 // Append() call. |
270 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time); | 288 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time); |
271 new_media_segment_ = true; | 289 new_media_segment_ = true; |
(...skipping 26 matching lines...) Expand all Loading... |
298 return false; | 316 return false; |
299 } | 317 } |
300 | 318 |
301 if (stream_start_time_ != kNoTimestamp() && | 319 if (stream_start_time_ != kNoTimestamp() && |
302 media_segment_start_time_ < stream_start_time_) { | 320 media_segment_start_time_ < stream_start_time_) { |
303 DVLOG(1) << "Cannot append a media segment before the start of stream."; | 321 DVLOG(1) << "Cannot append a media segment before the start of stream."; |
304 return false; | 322 return false; |
305 } | 323 } |
306 | 324 |
307 UpdateMaxInterbufferDistance(buffers); | 325 UpdateMaxInterbufferDistance(buffers); |
| 326 SetConfigIds(buffers); |
308 | 327 |
309 // Save a snapshot of stream state before range modifications are made. | 328 // Save a snapshot of stream state before range modifications are made. |
310 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp(); | 329 base::TimeDelta next_buffer_timestamp = GetNextBufferTimestamp(); |
311 base::TimeDelta end_buffer_timestamp = GetEndBufferTimestamp(); | 330 base::TimeDelta end_buffer_timestamp = GetEndBufferTimestamp(); |
312 | 331 |
313 bool deleted_next_buffer = false; | 332 bool deleted_next_buffer = false; |
314 BufferQueue deleted_buffers; | 333 BufferQueue deleted_buffers; |
315 | 334 |
316 RangeList::iterator range_for_new_buffers = range_for_next_append_; | 335 RangeList::iterator range_for_new_buffers = range_for_next_append_; |
317 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, | 336 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 max_interbuffer_distance_ = interbuffer_distance; | 435 max_interbuffer_distance_ = interbuffer_distance; |
417 } else { | 436 } else { |
418 max_interbuffer_distance_ = | 437 max_interbuffer_distance_ = |
419 std::max(max_interbuffer_distance_, interbuffer_distance); | 438 std::max(max_interbuffer_distance_, interbuffer_distance); |
420 } | 439 } |
421 } | 440 } |
422 prev_timestamp = current_timestamp; | 441 prev_timestamp = current_timestamp; |
423 } | 442 } |
424 } | 443 } |
425 | 444 |
| 445 void SourceBufferStream::SetConfigIds(const BufferQueue& buffers) { |
| 446 for (BufferQueue::const_iterator itr = buffers.begin(); |
| 447 itr != buffers.end(); ++itr) { |
| 448 (*itr)->SetConfigId(append_config_index_); |
| 449 } |
| 450 } |
| 451 |
426 void SourceBufferStream::InsertIntoExistingRange( | 452 void SourceBufferStream::InsertIntoExistingRange( |
427 const RangeList::iterator& range_for_new_buffers_itr, | 453 const RangeList::iterator& range_for_new_buffers_itr, |
428 const BufferQueue& new_buffers, | 454 const BufferQueue& new_buffers, |
429 bool* deleted_next_buffer, BufferQueue* deleted_buffers) { | 455 bool* deleted_next_buffer, BufferQueue* deleted_buffers) { |
430 DCHECK(deleted_next_buffer); | 456 DCHECK(deleted_next_buffer); |
431 DCHECK(deleted_buffers); | 457 DCHECK(deleted_buffers); |
432 | 458 |
433 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr; | 459 SourceBufferRange* range_for_new_buffers = *range_for_new_buffers_itr; |
434 | 460 |
435 // If this is a simple case where we can just append to the end of the range, | 461 // If this is a simple case where we can just append to the end of the range, |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 | 672 |
647 SetSelectedRange(*itr); | 673 SetSelectedRange(*itr); |
648 selected_range_->Seek(timestamp); | 674 selected_range_->Seek(timestamp); |
649 seek_pending_ = false; | 675 seek_pending_ = false; |
650 } | 676 } |
651 | 677 |
652 bool SourceBufferStream::IsSeekPending() const { | 678 bool SourceBufferStream::IsSeekPending() const { |
653 return seek_pending_; | 679 return seek_pending_; |
654 } | 680 } |
655 | 681 |
656 bool SourceBufferStream::GetNextBuffer( | 682 SourceBufferStream::Status SourceBufferStream::GetNextBuffer( |
657 scoped_refptr<StreamParserBuffer>* out_buffer) { | 683 scoped_refptr<StreamParserBuffer>* out_buffer) { |
658 if (!track_buffer_.empty()) { | 684 if (!track_buffer_.empty()) { |
| 685 if (track_buffer_.front()->GetConfigId() != current_config_index_) |
| 686 return kConfigChange; |
| 687 |
659 *out_buffer = track_buffer_.front(); | 688 *out_buffer = track_buffer_.front(); |
660 track_buffer_.pop_front(); | 689 track_buffer_.pop_front(); |
661 return true; | 690 return kSuccess; |
662 } | 691 } |
663 | 692 |
664 return selected_range_ && selected_range_->GetNextBuffer(out_buffer); | 693 if (!selected_range_ || !selected_range_->HasNextBuffer()) |
| 694 return kNeedBuffer; |
| 695 |
| 696 if (selected_range_->GetNextConfigId() != current_config_index_) |
| 697 return kConfigChange; |
| 698 |
| 699 CHECK(selected_range_->GetNextBuffer(out_buffer)); |
| 700 return kSuccess; |
665 } | 701 } |
666 | 702 |
667 base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() { | 703 base::TimeDelta SourceBufferStream::GetNextBufferTimestamp() { |
668 if (!selected_range_) | 704 if (!selected_range_) |
669 return kNoTimestamp(); | 705 return kNoTimestamp(); |
670 | 706 |
671 DCHECK(selected_range_->HasNextBufferPosition()); | 707 DCHECK(selected_range_->HasNextBufferPosition()); |
672 return selected_range_->GetNextTimestamp(); | 708 return selected_range_->GetNextTimestamp(); |
673 } | 709 } |
674 | 710 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 itr != ranges_.end(); ++itr) { | 758 itr != ranges_.end(); ++itr) { |
723 ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetBufferedEndTimestamp()); | 759 ranges.Add((*itr)->GetStartTimestamp(), (*itr)->GetBufferedEndTimestamp()); |
724 } | 760 } |
725 return ranges; | 761 return ranges; |
726 } | 762 } |
727 | 763 |
728 bool SourceBufferStream::IsEndSelected() const { | 764 bool SourceBufferStream::IsEndSelected() const { |
729 return ranges_.empty() || selected_range_ == ranges_.back(); | 765 return ranges_.empty() || selected_range_ == ranges_.back(); |
730 } | 766 } |
731 | 767 |
| 768 const AudioDecoderConfig& SourceBufferStream::GetCurrentAudioDecoderConfig() { |
| 769 CompleteConfigChange(); |
| 770 return *audio_configs_[current_config_index_]; |
| 771 } |
| 772 |
| 773 const VideoDecoderConfig& SourceBufferStream::GetCurrentVideoDecoderConfig() { |
| 774 CompleteConfigChange(); |
| 775 return *video_configs_[current_config_index_]; |
| 776 } |
| 777 |
732 base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const { | 778 base::TimeDelta SourceBufferStream::GetMaxInterbufferDistance() const { |
733 if (max_interbuffer_distance_ == kNoTimestamp()) | 779 if (max_interbuffer_distance_ == kNoTimestamp()) |
734 return base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs); | 780 return base::TimeDelta::FromMilliseconds(kDefaultBufferDurationInMs); |
735 return max_interbuffer_distance_; | 781 return max_interbuffer_distance_; |
736 } | 782 } |
737 | 783 |
| 784 bool SourceBufferStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
| 785 DCHECK(!audio_configs_.empty()); |
| 786 DCHECK(video_configs_.empty()); |
| 787 |
| 788 if (audio_configs_[0]->codec() != config.codec()) { |
| 789 DVLOG(1) << "UpdateAudioConfig() : Codec changes not allowed."; |
| 790 return false; |
| 791 } |
| 792 |
| 793 if (audio_configs_[0]->samples_per_second() != config.samples_per_second()) { |
| 794 DVLOG(1) << "UpdateAudioConfig() : Sample rate changes not allowed."; |
| 795 return false; |
| 796 } |
| 797 |
| 798 if (audio_configs_[0]->channel_layout() != config.channel_layout()) { |
| 799 DVLOG(1) << "UpdateAudioConfig() : Channel layout changes not allowed."; |
| 800 return false; |
| 801 } |
| 802 |
| 803 if (audio_configs_[0]->bits_per_channel() != config.bits_per_channel()) { |
| 804 DVLOG(1) << "UpdateAudioConfig() : Bits per channel changes not allowed."; |
| 805 return false; |
| 806 } |
| 807 |
| 808 // Check to see if the new config matches an existing one. |
| 809 for (size_t i = 0; i < audio_configs_.size(); ++i) { |
| 810 if (config.Matches(*audio_configs_[i])) { |
| 811 append_config_index_ = i; |
| 812 return true; |
| 813 } |
| 814 } |
| 815 |
| 816 // No matches found so let's add this one to the list. |
| 817 append_config_index_ = audio_configs_.size(); |
| 818 audio_configs_.resize(audio_configs_.size() + 1); |
| 819 audio_configs_[append_config_index_] = new AudioDecoderConfig(); |
| 820 audio_configs_[append_config_index_]->CopyFrom(config); |
| 821 return true; |
| 822 } |
| 823 |
| 824 bool SourceBufferStream::UpdateVideoConfig(const VideoDecoderConfig& config) { |
| 825 DCHECK(!video_configs_.empty()); |
| 826 DCHECK(audio_configs_.empty()); |
| 827 |
| 828 if (video_configs_[0]->codec() != config.codec()) { |
| 829 DVLOG(1) << "UpdateVideoConfig() : Codec changes not allowed."; |
| 830 return false; |
| 831 } |
| 832 |
| 833 // Check to see if the new config matches an existing one. |
| 834 for (size_t i = 0; i < video_configs_.size(); ++i) { |
| 835 if (config.Matches(*video_configs_[i])) { |
| 836 append_config_index_ = i; |
| 837 return true; |
| 838 } |
| 839 } |
| 840 |
| 841 // No matches found so let's add this one to the list. |
| 842 append_config_index_ = video_configs_.size(); |
| 843 video_configs_.resize(video_configs_.size() + 1); |
| 844 video_configs_[append_config_index_] = new VideoDecoderConfig(); |
| 845 video_configs_[append_config_index_]->CopyFrom(config); |
| 846 return true; |
| 847 } |
| 848 |
| 849 void SourceBufferStream::CompleteConfigChange() { |
| 850 if (!track_buffer_.empty()) { |
| 851 current_config_index_ = track_buffer_.front()->GetConfigId(); |
| 852 return; |
| 853 } |
| 854 |
| 855 if (!selected_range_ || !selected_range_->HasNextBuffer()) |
| 856 return; |
| 857 |
| 858 current_config_index_ = selected_range_->GetNextConfigId(); |
| 859 } |
| 860 |
738 SourceBufferRange::SourceBufferRange( | 861 SourceBufferRange::SourceBufferRange( |
739 const BufferQueue& new_buffers, base::TimeDelta media_segment_start_time, | 862 const BufferQueue& new_buffers, base::TimeDelta media_segment_start_time, |
740 const InterbufferDistanceCB& interbuffer_distance_cb) | 863 const InterbufferDistanceCB& interbuffer_distance_cb) |
741 : next_buffer_index_(-1), | 864 : next_buffer_index_(-1), |
742 waiting_for_keyframe_(false), | 865 waiting_for_keyframe_(false), |
743 next_keyframe_timestamp_(kNoTimestamp()), | 866 next_keyframe_timestamp_(kNoTimestamp()), |
744 media_segment_start_time_(media_segment_start_time), | 867 media_segment_start_time_(media_segment_start_time), |
745 interbuffer_distance_cb_(interbuffer_distance_cb) { | 868 interbuffer_distance_cb_(interbuffer_distance_cb) { |
746 DCHECK(!new_buffers.empty()); | 869 DCHECK(!new_buffers.empty()); |
747 DCHECK(new_buffers.front()->IsKeyframe()); | 870 DCHECK(new_buffers.front()->IsKeyframe()); |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
918 keyframe_map_.lower_bound((*starting_point)->GetDecodeTimestamp()); | 1041 keyframe_map_.lower_bound((*starting_point)->GetDecodeTimestamp()); |
919 keyframe_map_.erase(starting_point_keyframe, keyframe_map_.end()); | 1042 keyframe_map_.erase(starting_point_keyframe, keyframe_map_.end()); |
920 | 1043 |
921 // Remove everything from |starting_point| onward. | 1044 // Remove everything from |starting_point| onward. |
922 buffers_.erase(starting_point, buffers_.end()); | 1045 buffers_.erase(starting_point, buffers_.end()); |
923 return removed_next_buffer; | 1046 return removed_next_buffer; |
924 } | 1047 } |
925 | 1048 |
926 bool SourceBufferRange::GetNextBuffer( | 1049 bool SourceBufferRange::GetNextBuffer( |
927 scoped_refptr<StreamParserBuffer>* out_buffer) { | 1050 scoped_refptr<StreamParserBuffer>* out_buffer) { |
928 if (waiting_for_keyframe_ || | 1051 if (!HasNextBuffer()) |
929 next_buffer_index_ >= static_cast<int>(buffers_.size())) { | |
930 return false; | 1052 return false; |
931 } | |
932 | 1053 |
933 DCHECK_GE(next_buffer_index_, 0); | |
934 *out_buffer = buffers_.at(next_buffer_index_); | 1054 *out_buffer = buffers_.at(next_buffer_index_); |
935 next_buffer_index_++; | 1055 next_buffer_index_++; |
936 return true; | 1056 return true; |
937 } | 1057 } |
938 | 1058 |
939 bool SourceBufferRange::HasNextBuffer() const { | 1059 bool SourceBufferRange::HasNextBuffer() const { |
940 return next_buffer_index_ >= 0 && | 1060 return next_buffer_index_ >= 0 && |
941 next_buffer_index_ < static_cast<int>(buffers_.size()); | 1061 next_buffer_index_ < static_cast<int>(buffers_.size()) && |
| 1062 !waiting_for_keyframe_; |
942 } | 1063 } |
943 | 1064 |
| 1065 int SourceBufferRange::GetNextConfigId() const { |
| 1066 DCHECK(HasNextBuffer()); |
| 1067 return buffers_.at(next_buffer_index_)->GetConfigId(); |
| 1068 } |
| 1069 |
| 1070 |
944 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { | 1071 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { |
945 DCHECK(!buffers_.empty()); | 1072 DCHECK(!buffers_.empty()); |
946 DCHECK(HasNextBufferPosition()); | 1073 DCHECK(HasNextBufferPosition()); |
947 | 1074 |
948 if (waiting_for_keyframe_) | 1075 if (waiting_for_keyframe_) |
949 return next_keyframe_timestamp_; | 1076 return next_keyframe_timestamp_; |
950 | 1077 |
951 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) | 1078 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) |
952 return kNoTimestamp(); | 1079 return kNoTimestamp(); |
953 | 1080 |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1047 return 2 * GetApproximateDuration(); | 1174 return 2 * GetApproximateDuration(); |
1048 } | 1175 } |
1049 | 1176 |
1050 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { | 1177 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { |
1051 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); | 1178 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); |
1052 DCHECK(max_interbuffer_distance != kNoTimestamp()); | 1179 DCHECK(max_interbuffer_distance != kNoTimestamp()); |
1053 return max_interbuffer_distance; | 1180 return max_interbuffer_distance; |
1054 } | 1181 } |
1055 | 1182 |
1056 } // namespace media | 1183 } // namespace media |
OLD | NEW |