| 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" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // same timestamp situation that is allowed. False is returned otherwise. | 22 // same timestamp situation that is allowed. False is returned otherwise. |
| 23 static bool AllowSameTimestamp( | 23 static bool AllowSameTimestamp( |
| 24 bool prev_is_keyframe, bool current_is_keyframe, | 24 bool prev_is_keyframe, bool current_is_keyframe, |
| 25 SourceBufferStream::Type type) { | 25 SourceBufferStream::Type type) { |
| 26 if (type == SourceBufferStream::kVideo) | 26 if (type == SourceBufferStream::kVideo) |
| 27 return !prev_is_keyframe && !current_is_keyframe; | 27 return !prev_is_keyframe && !current_is_keyframe; |
| 28 | 28 |
| 29 return prev_is_keyframe || !current_is_keyframe; | 29 return prev_is_keyframe || !current_is_keyframe; |
| 30 } | 30 } |
| 31 | 31 |
| 32 // Returns the config ID of |buffer| if |buffer| has no fade out preroll or |
| 33 // |index| is out of range. Otherwise returns the config ID for the fade out |
| 34 // preroll buffer at position |index|. |
| 35 static int GetConfigId(StreamParserBuffer* buffer, size_t index) { |
| 36 return index < buffer->GetFadeOutPreroll().size() |
| 37 ? buffer->GetFadeOutPreroll()[index]->GetConfigId() |
| 38 : buffer->GetConfigId(); |
| 39 } |
| 40 |
| 32 // Helper class representing a range of buffered data. All buffers in a | 41 // Helper class representing a range of buffered data. All buffers in a |
| 33 // SourceBufferRange are ordered sequentially in presentation order with no | 42 // SourceBufferRange are ordered sequentially in presentation order with no |
| 34 // gaps. | 43 // gaps. |
| 35 class SourceBufferRange { | 44 class SourceBufferRange { |
| 36 public: | 45 public: |
| 37 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 46 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 38 | 47 |
| 39 // Returns the maximum distance in time between any buffer seen in this | 48 // Returns the maximum distance in time between any buffer seen in this |
| 40 // stream. Used to estimate the duration of a buffer if its duration is not | 49 // stream. Used to estimate the duration of a buffer if its duration is not |
| 41 // known. | 50 // known. |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 seek_buffer_timestamp_(kNoTimestamp()), | 348 seek_buffer_timestamp_(kNoTimestamp()), |
| 340 selected_range_(NULL), | 349 selected_range_(NULL), |
| 341 media_segment_start_time_(kNoTimestamp()), | 350 media_segment_start_time_(kNoTimestamp()), |
| 342 range_for_next_append_(ranges_.end()), | 351 range_for_next_append_(ranges_.end()), |
| 343 new_media_segment_(false), | 352 new_media_segment_(false), |
| 344 last_appended_buffer_timestamp_(kNoTimestamp()), | 353 last_appended_buffer_timestamp_(kNoTimestamp()), |
| 345 last_appended_buffer_is_keyframe_(false), | 354 last_appended_buffer_is_keyframe_(false), |
| 346 last_output_buffer_timestamp_(kNoTimestamp()), | 355 last_output_buffer_timestamp_(kNoTimestamp()), |
| 347 max_interbuffer_distance_(kNoTimestamp()), | 356 max_interbuffer_distance_(kNoTimestamp()), |
| 348 memory_limit_(kDefaultAudioMemoryLimit), | 357 memory_limit_(kDefaultAudioMemoryLimit), |
| 349 config_change_pending_(false) { | 358 config_change_pending_(false), |
| 359 fade_out_preroll_index_(0) { |
| 350 DCHECK(audio_config.IsValidConfig()); | 360 DCHECK(audio_config.IsValidConfig()); |
| 351 audio_configs_.push_back(audio_config); | 361 audio_configs_.push_back(audio_config); |
| 352 } | 362 } |
| 353 | 363 |
| 354 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, | 364 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, |
| 355 const LogCB& log_cb) | 365 const LogCB& log_cb) |
| 356 : log_cb_(log_cb), | 366 : log_cb_(log_cb), |
| 357 current_config_index_(0), | 367 current_config_index_(0), |
| 358 append_config_index_(0), | 368 append_config_index_(0), |
| 359 seek_pending_(false), | 369 seek_pending_(false), |
| 360 end_of_stream_(false), | 370 end_of_stream_(false), |
| 361 seek_buffer_timestamp_(kNoTimestamp()), | 371 seek_buffer_timestamp_(kNoTimestamp()), |
| 362 selected_range_(NULL), | 372 selected_range_(NULL), |
| 363 media_segment_start_time_(kNoTimestamp()), | 373 media_segment_start_time_(kNoTimestamp()), |
| 364 range_for_next_append_(ranges_.end()), | 374 range_for_next_append_(ranges_.end()), |
| 365 new_media_segment_(false), | 375 new_media_segment_(false), |
| 366 last_appended_buffer_timestamp_(kNoTimestamp()), | 376 last_appended_buffer_timestamp_(kNoTimestamp()), |
| 367 last_appended_buffer_is_keyframe_(false), | 377 last_appended_buffer_is_keyframe_(false), |
| 368 last_output_buffer_timestamp_(kNoTimestamp()), | 378 last_output_buffer_timestamp_(kNoTimestamp()), |
| 369 max_interbuffer_distance_(kNoTimestamp()), | 379 max_interbuffer_distance_(kNoTimestamp()), |
| 370 memory_limit_(kDefaultVideoMemoryLimit), | 380 memory_limit_(kDefaultVideoMemoryLimit), |
| 371 config_change_pending_(false) { | 381 config_change_pending_(false), |
| 382 fade_out_preroll_index_(0) { |
| 372 DCHECK(video_config.IsValidConfig()); | 383 DCHECK(video_config.IsValidConfig()); |
| 373 video_configs_.push_back(video_config); | 384 video_configs_.push_back(video_config); |
| 374 } | 385 } |
| 375 | 386 |
| 376 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, | 387 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, |
| 377 const LogCB& log_cb) | 388 const LogCB& log_cb) |
| 378 : log_cb_(log_cb), | 389 : log_cb_(log_cb), |
| 379 current_config_index_(0), | 390 current_config_index_(0), |
| 380 append_config_index_(0), | 391 append_config_index_(0), |
| 381 text_track_config_(text_config), | 392 text_track_config_(text_config), |
| 382 seek_pending_(false), | 393 seek_pending_(false), |
| 383 end_of_stream_(false), | 394 end_of_stream_(false), |
| 384 seek_buffer_timestamp_(kNoTimestamp()), | 395 seek_buffer_timestamp_(kNoTimestamp()), |
| 385 selected_range_(NULL), | 396 selected_range_(NULL), |
| 386 media_segment_start_time_(kNoTimestamp()), | 397 media_segment_start_time_(kNoTimestamp()), |
| 387 range_for_next_append_(ranges_.end()), | 398 range_for_next_append_(ranges_.end()), |
| 388 new_media_segment_(false), | 399 new_media_segment_(false), |
| 389 last_appended_buffer_timestamp_(kNoTimestamp()), | 400 last_appended_buffer_timestamp_(kNoTimestamp()), |
| 390 last_appended_buffer_is_keyframe_(false), | 401 last_appended_buffer_is_keyframe_(false), |
| 391 last_output_buffer_timestamp_(kNoTimestamp()), | 402 last_output_buffer_timestamp_(kNoTimestamp()), |
| 392 max_interbuffer_distance_(kNoTimestamp()), | 403 max_interbuffer_distance_(kNoTimestamp()), |
| 393 memory_limit_(kDefaultAudioMemoryLimit), | 404 memory_limit_(kDefaultAudioMemoryLimit), |
| 394 config_change_pending_(false) { | 405 config_change_pending_(false), |
| 406 fade_out_preroll_index_(0) { |
| 395 } | 407 } |
| 396 | 408 |
| 397 SourceBufferStream::~SourceBufferStream() { | 409 SourceBufferStream::~SourceBufferStream() { |
| 398 while (!ranges_.empty()) { | 410 while (!ranges_.empty()) { |
| 399 delete ranges_.front(); | 411 delete ranges_.front(); |
| 400 ranges_.pop_front(); | 412 ranges_.pop_front(); |
| 401 } | 413 } |
| 402 } | 414 } |
| 403 | 415 |
| 404 void SourceBufferStream::OnNewMediaSegment( | 416 void SourceBufferStream::OnNewMediaSegment( |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 DCHECK(IsRangeListSorted(ranges_)); | 675 DCHECK(IsRangeListSorted(ranges_)); |
| 664 DCHECK(OnlySelectedRangeIsSeeked()); | 676 DCHECK(OnlySelectedRangeIsSeeked()); |
| 665 DVLOG(1) << __FUNCTION__ << " : done"; | 677 DVLOG(1) << __FUNCTION__ << " : done"; |
| 666 } | 678 } |
| 667 | 679 |
| 668 void SourceBufferStream::ResetSeekState() { | 680 void SourceBufferStream::ResetSeekState() { |
| 669 SetSelectedRange(NULL); | 681 SetSelectedRange(NULL); |
| 670 track_buffer_.clear(); | 682 track_buffer_.clear(); |
| 671 config_change_pending_ = false; | 683 config_change_pending_ = false; |
| 672 last_output_buffer_timestamp_ = kNoTimestamp(); | 684 last_output_buffer_timestamp_ = kNoTimestamp(); |
| 685 fade_out_preroll_index_ = 0; |
| 686 fade_in_buffer_ = NULL; |
| 673 } | 687 } |
| 674 | 688 |
| 675 bool SourceBufferStream::ShouldSeekToStartOfBuffered( | 689 bool SourceBufferStream::ShouldSeekToStartOfBuffered( |
| 676 base::TimeDelta seek_timestamp) const { | 690 base::TimeDelta seek_timestamp) const { |
| 677 if (ranges_.empty()) | 691 if (ranges_.empty()) |
| 678 return false; | 692 return false; |
| 679 base::TimeDelta beginning_of_buffered = | 693 base::TimeDelta beginning_of_buffered = |
| 680 ranges_.front()->GetStartTimestamp(); | 694 ranges_.front()->GetStartTimestamp(); |
| 681 return (seek_timestamp <= beginning_of_buffered && | 695 return (seek_timestamp <= beginning_of_buffered && |
| 682 beginning_of_buffered < kSeekToStartFudgeRoom()); | 696 beginning_of_buffered < kSeekToStartFudgeRoom()); |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1090 // If we're about to delete the selected range, also reset the seek state. | 1104 // If we're about to delete the selected range, also reset the seek state. |
| 1091 DCHECK((*itr)->GetStartTimestamp() >= duration); | 1105 DCHECK((*itr)->GetStartTimestamp() >= duration); |
| 1092 if (*itr == selected_range_) | 1106 if (*itr == selected_range_) |
| 1093 ResetSeekState(); | 1107 ResetSeekState(); |
| 1094 DeleteAndRemoveRange(&itr); | 1108 DeleteAndRemoveRange(&itr); |
| 1095 } | 1109 } |
| 1096 } | 1110 } |
| 1097 | 1111 |
| 1098 SourceBufferStream::Status SourceBufferStream::GetNextBuffer( | 1112 SourceBufferStream::Status SourceBufferStream::GetNextBuffer( |
| 1099 scoped_refptr<StreamParserBuffer>* out_buffer) { | 1113 scoped_refptr<StreamParserBuffer>* out_buffer) { |
| 1114 if (!fade_in_buffer_) { |
| 1115 const SourceBufferStream::Status status = GetNextBufferInternal(out_buffer); |
| 1116 |
| 1117 // Just return if GetNextBufferInternal() failed or there's no fade out |
| 1118 // preroll, there's nothing else to do. |
| 1119 if (status != SourceBufferStream::kSuccess || |
| 1120 (*out_buffer)->GetFadeOutPreroll().empty()) { |
| 1121 return status; |
| 1122 } |
| 1123 |
| 1124 // Setup fade in buffer and fall through into splice frame buffer handling. |
| 1125 fade_out_preroll_index_ = 0; |
| 1126 fade_in_buffer_.swap(*out_buffer); |
| 1127 } |
| 1128 |
| 1129 DCHECK(fade_in_buffer_); |
| 1130 const std::vector<scoped_refptr<StreamParserBuffer> >& fade_out_preroll = |
| 1131 fade_in_buffer_->GetFadeOutPreroll(); |
| 1132 |
| 1133 // Are there any fade out buffers left to hand out? |
| 1134 if (fade_out_preroll_index_ < fade_out_preroll.size()) { |
| 1135 // Account for config changes which occur between fade out buffers. |
| 1136 if (current_config_index_ != |
| 1137 fade_out_preroll[fade_out_preroll_index_]->GetConfigId()) { |
| 1138 config_change_pending_ = true; |
| 1139 DVLOG(1) << "Config change (fade out preroll config ID does not match)."; |
| 1140 return SourceBufferStream::kConfigChange; |
| 1141 } |
| 1142 |
| 1143 *out_buffer = fade_out_preroll[fade_out_preroll_index_++]; |
| 1144 return SourceBufferStream::kSuccess; |
| 1145 } |
| 1146 |
| 1147 // Did we hand out the last fade out buffer on the last call? |
| 1148 if (fade_out_preroll_index_ == fade_out_preroll.size()) { |
| 1149 fade_out_preroll_index_++; |
| 1150 config_change_pending_ = true; |
| 1151 DVLOG(1) << "Config change (forced for fade in of splice frame)."; |
| 1152 return SourceBufferStream::kConfigChange; |
| 1153 } |
| 1154 |
| 1155 // All fade out buffers have been handed out and a config change completed, so |
| 1156 // hand out the final buffer for fade in. Because a config change is always |
| 1157 // issued prior to handing out this buffer, any changes in config id have been |
| 1158 // inherently handled. |
| 1159 DCHECK_GT(fade_out_preroll_index_, fade_out_preroll.size()); |
| 1160 out_buffer->swap(fade_in_buffer_); |
| 1161 fade_in_buffer_ = NULL; |
| 1162 fade_out_preroll_index_ = 0; |
| 1163 return SourceBufferStream::kSuccess; |
| 1164 } |
| 1165 |
| 1166 SourceBufferStream::Status SourceBufferStream::GetNextBufferInternal( |
| 1167 scoped_refptr<StreamParserBuffer>* out_buffer) { |
| 1100 CHECK(!config_change_pending_); | 1168 CHECK(!config_change_pending_); |
| 1101 | 1169 |
| 1102 if (!track_buffer_.empty()) { | 1170 if (!track_buffer_.empty()) { |
| 1103 DCHECK(!selected_range_); | 1171 DCHECK(!selected_range_); |
| 1104 if (track_buffer_.front()->GetConfigId() != current_config_index_) { | 1172 scoped_refptr<StreamParserBuffer>& next_buffer = track_buffer_.front(); |
| 1173 |
| 1174 // If the next buffer is an audio splice frame, the next effective config id |
| 1175 // comes from the first fade out preroll buffer. |
| 1176 if (GetConfigId(next_buffer, 0) != current_config_index_) { |
| 1105 config_change_pending_ = true; | 1177 config_change_pending_ = true; |
| 1106 DVLOG(1) << "Config change (track buffer config ID does not match)."; | 1178 DVLOG(1) << "Config change (track buffer config ID does not match)."; |
| 1107 return kConfigChange; | 1179 return kConfigChange; |
| 1108 } | 1180 } |
| 1109 | 1181 |
| 1110 *out_buffer = track_buffer_.front(); | 1182 *out_buffer = next_buffer; |
| 1111 track_buffer_.pop_front(); | 1183 track_buffer_.pop_front(); |
| 1112 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); | 1184 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); |
| 1113 | 1185 |
| 1114 // If the track buffer becomes empty, then try to set the selected range | 1186 // If the track buffer becomes empty, then try to set the selected range |
| 1115 // based on the timestamp of this buffer being returned. | 1187 // based on the timestamp of this buffer being returned. |
| 1116 if (track_buffer_.empty()) | 1188 if (track_buffer_.empty()) |
| 1117 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_); | 1189 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_); |
| 1118 | 1190 |
| 1119 return kSuccess; | 1191 return kSuccess; |
| 1120 } | 1192 } |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1336 append_config_index_ = video_configs_.size(); | 1408 append_config_index_ = video_configs_.size(); |
| 1337 DVLOG(2) << "New video config - index: " << append_config_index_; | 1409 DVLOG(2) << "New video config - index: " << append_config_index_; |
| 1338 video_configs_.resize(video_configs_.size() + 1); | 1410 video_configs_.resize(video_configs_.size() + 1); |
| 1339 video_configs_[append_config_index_] = config; | 1411 video_configs_[append_config_index_] = config; |
| 1340 return true; | 1412 return true; |
| 1341 } | 1413 } |
| 1342 | 1414 |
| 1343 void SourceBufferStream::CompleteConfigChange() { | 1415 void SourceBufferStream::CompleteConfigChange() { |
| 1344 config_change_pending_ = false; | 1416 config_change_pending_ = false; |
| 1345 | 1417 |
| 1346 if (!track_buffer_.empty()) { | 1418 if (fade_in_buffer_) { |
| 1347 current_config_index_ = track_buffer_.front()->GetConfigId(); | 1419 current_config_index_ = |
| 1420 GetConfigId(fade_in_buffer_, fade_out_preroll_index_); |
| 1348 return; | 1421 return; |
| 1349 } | 1422 } |
| 1350 | 1423 |
| 1424 if (!track_buffer_.empty()) { |
| 1425 current_config_index_ = GetConfigId(track_buffer_.front(), 0); |
| 1426 return; |
| 1427 } |
| 1428 |
| 1351 if (selected_range_ && selected_range_->HasNextBuffer()) | 1429 if (selected_range_ && selected_range_->HasNextBuffer()) |
| 1352 current_config_index_ = selected_range_->GetNextConfigId(); | 1430 current_config_index_ = selected_range_->GetNextConfigId(); |
| 1353 } | 1431 } |
| 1354 | 1432 |
| 1355 void SourceBufferStream::SetSelectedRangeIfNeeded( | 1433 void SourceBufferStream::SetSelectedRangeIfNeeded( |
| 1356 const base::TimeDelta timestamp) { | 1434 const base::TimeDelta timestamp) { |
| 1357 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")"; | 1435 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InSecondsF() << ")"; |
| 1358 | 1436 |
| 1359 if (selected_range_) { | 1437 if (selected_range_) { |
| 1360 DCHECK(track_buffer_.empty()); | 1438 DCHECK(track_buffer_.empty()); |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1857 // Remove everything from |starting_point| onward. | 1935 // Remove everything from |starting_point| onward. |
| 1858 FreeBufferRange(starting_point, buffers_.end()); | 1936 FreeBufferRange(starting_point, buffers_.end()); |
| 1859 return buffers_.empty(); | 1937 return buffers_.empty(); |
| 1860 } | 1938 } |
| 1861 | 1939 |
| 1862 bool SourceBufferRange::GetNextBuffer( | 1940 bool SourceBufferRange::GetNextBuffer( |
| 1863 scoped_refptr<StreamParserBuffer>* out_buffer) { | 1941 scoped_refptr<StreamParserBuffer>* out_buffer) { |
| 1864 if (!HasNextBuffer()) | 1942 if (!HasNextBuffer()) |
| 1865 return false; | 1943 return false; |
| 1866 | 1944 |
| 1867 *out_buffer = buffers_.at(next_buffer_index_); | 1945 *out_buffer = buffers_[next_buffer_index_]; |
| 1868 next_buffer_index_++; | 1946 next_buffer_index_++; |
| 1869 return true; | 1947 return true; |
| 1870 } | 1948 } |
| 1871 | 1949 |
| 1872 bool SourceBufferRange::HasNextBuffer() const { | 1950 bool SourceBufferRange::HasNextBuffer() const { |
| 1873 return next_buffer_index_ >= 0 && | 1951 return next_buffer_index_ >= 0 && |
| 1874 next_buffer_index_ < static_cast<int>(buffers_.size()); | 1952 next_buffer_index_ < static_cast<int>(buffers_.size()); |
| 1875 } | 1953 } |
| 1876 | 1954 |
| 1877 int SourceBufferRange::GetNextConfigId() const { | 1955 int SourceBufferRange::GetNextConfigId() const { |
| 1878 DCHECK(HasNextBuffer()); | 1956 DCHECK(HasNextBuffer()); |
| 1879 return buffers_.at(next_buffer_index_)->GetConfigId(); | 1957 // If the next buffer is an audio splice frame, the next effective config id |
| 1958 // comes from the first fade out preroll buffer. |
| 1959 return GetConfigId(buffers_[next_buffer_index_], 0); |
| 1880 } | 1960 } |
| 1881 | 1961 |
| 1882 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { | 1962 base::TimeDelta SourceBufferRange::GetNextTimestamp() const { |
| 1883 DCHECK(!buffers_.empty()); | 1963 DCHECK(!buffers_.empty()); |
| 1884 DCHECK(HasNextBufferPosition()); | 1964 DCHECK(HasNextBufferPosition()); |
| 1885 | 1965 |
| 1886 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { | 1966 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { |
| 1887 return kNoTimestamp(); | 1967 return kNoTimestamp(); |
| 1888 } | 1968 } |
| 1889 | 1969 |
| 1890 return buffers_.at(next_buffer_index_)->GetDecodeTimestamp(); | 1970 return buffers_[next_buffer_index_]->GetDecodeTimestamp(); |
| 1891 } | 1971 } |
| 1892 | 1972 |
| 1893 bool SourceBufferRange::HasNextBufferPosition() const { | 1973 bool SourceBufferRange::HasNextBufferPosition() const { |
| 1894 return next_buffer_index_ >= 0; | 1974 return next_buffer_index_ >= 0; |
| 1895 } | 1975 } |
| 1896 | 1976 |
| 1897 void SourceBufferRange::ResetNextBufferPosition() { | 1977 void SourceBufferRange::ResetNextBufferPosition() { |
| 1898 next_buffer_index_ = -1; | 1978 next_buffer_index_ = -1; |
| 1899 } | 1979 } |
| 1900 | 1980 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2007 return ComputeFudgeRoom(GetApproximateDuration()); | 2087 return ComputeFudgeRoom(GetApproximateDuration()); |
| 2008 } | 2088 } |
| 2009 | 2089 |
| 2010 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { | 2090 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { |
| 2011 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); | 2091 base::TimeDelta max_interbuffer_distance = interbuffer_distance_cb_.Run(); |
| 2012 DCHECK(max_interbuffer_distance != kNoTimestamp()); | 2092 DCHECK(max_interbuffer_distance != kNoTimestamp()); |
| 2013 return max_interbuffer_distance; | 2093 return max_interbuffer_distance; |
| 2014 } | 2094 } |
| 2015 | 2095 |
| 2016 } // namespace media | 2096 } // namespace media |
| OLD | NEW |