Chromium Code Reviews| 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 #include <sstream> | 9 #include <sstream> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
| 14 #include "media/base/audio_splicer.h" | 14 #include "media/base/audio_splicer.h" |
| 15 #include "media/filters/source_buffer_platform.h" | 15 #include "media/filters/source_buffer_platform.h" |
| 16 #include "media/filters/source_buffer_range.h" | 16 #include "media/filters/source_buffer_range.h" |
| 17 | 17 |
| 18 namespace media { | 18 namespace media { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 enum { | 22 // An arbitrarily-chosen number to estimate the duration of a buffer if none is |
| 23 // An arbitrarily-chosen number to estimate the duration of a buffer if none | 23 // set and there's not enough information to get a better estimate. |
| 24 // is set and there's not enough information to get a better estimate. | 24 const int kDefaultBufferDurationInMs = 125; |
| 25 kDefaultBufferDurationInMs = 125, | |
| 26 | 25 |
| 27 // Limit the number of MEDIA_LOG() logs for splice buffer generation warnings | 26 // Limit the number of MEDIA_LOG() logs for splice buffer generation warnings |
| 28 // and successes. Though these values are high enough to possibly exhaust the | 27 // and successes. Though these values are high enough to possibly exhaust the |
| 29 // media internals event cache (along with other events), these logs are | 28 // media internals event cache (along with other events), these logs are |
| 30 // important for debugging splice generation. | 29 // important for debugging splice generation. |
| 31 kMaxSpliceGenerationWarningLogs = 50, | 30 const int kMaxSpliceGenerationWarningLogs = 50; |
| 32 kMaxSpliceGenerationSuccessLogs = 20, | 31 const int kMaxSpliceGenerationSuccessLogs = 20; |
| 33 }; | 32 |
| 33 // Limit the number of MEDIA_LOG() logs for track buffer time gaps. | |
| 34 const int kMaxTrackBufferGapWarningLogs = 20; | |
| 34 | 35 |
| 35 // Helper method that returns true if |ranges| is sorted in increasing order, | 36 // Helper method that returns true if |ranges| is sorted in increasing order, |
| 36 // false otherwise. | 37 // false otherwise. |
| 37 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) { | 38 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) { |
| 38 DecodeTimestamp prev = kNoDecodeTimestamp(); | 39 DecodeTimestamp prev = kNoDecodeTimestamp(); |
| 39 for (std::list<SourceBufferRange*>::const_iterator itr = | 40 for (std::list<SourceBufferRange*>::const_iterator itr = |
| 40 ranges.begin(); itr != ranges.end(); ++itr) { | 41 ranges.begin(); itr != ranges.end(); ++itr) { |
| 41 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp()) | 42 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp()) |
| 42 return false; | 43 return false; |
| 43 prev = (*itr)->GetEndTimestamp(); | 44 prev = (*itr)->GetEndTimestamp(); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, | 128 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, |
| 128 const scoped_refptr<MediaLog>& media_log, | 129 const scoped_refptr<MediaLog>& media_log, |
| 129 bool splice_frames_enabled) | 130 bool splice_frames_enabled) |
| 130 : media_log_(media_log), | 131 : media_log_(media_log), |
| 131 current_config_index_(0), | 132 current_config_index_(0), |
| 132 append_config_index_(0), | 133 append_config_index_(0), |
| 133 seek_pending_(false), | 134 seek_pending_(false), |
| 134 end_of_stream_(false), | 135 end_of_stream_(false), |
| 135 seek_buffer_timestamp_(kNoTimestamp()), | 136 seek_buffer_timestamp_(kNoTimestamp()), |
| 136 selected_range_(NULL), | 137 selected_range_(NULL), |
| 138 just_exhausted_track_buffer_(false), | |
| 137 media_segment_start_time_(kNoDecodeTimestamp()), | 139 media_segment_start_time_(kNoDecodeTimestamp()), |
| 138 range_for_next_append_(ranges_.end()), | 140 range_for_next_append_(ranges_.end()), |
| 139 new_media_segment_(false), | 141 new_media_segment_(false), |
| 140 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), | 142 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), |
| 141 last_appended_buffer_is_keyframe_(false), | 143 last_appended_buffer_is_keyframe_(false), |
| 142 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 144 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 143 max_interbuffer_distance_(kNoTimestamp()), | 145 max_interbuffer_distance_(kNoTimestamp()), |
| 144 memory_limit_(kSourceBufferAudioMemoryLimit), | 146 memory_limit_(kSourceBufferAudioMemoryLimit), |
| 145 config_change_pending_(false), | 147 config_change_pending_(false), |
| 146 splice_buffers_index_(0), | 148 splice_buffers_index_(0), |
| 147 pending_buffers_complete_(false), | 149 pending_buffers_complete_(false), |
| 148 splice_frames_enabled_(splice_frames_enabled), | 150 splice_frames_enabled_(splice_frames_enabled), |
| 149 num_splice_generation_warning_logs_(0), | 151 num_splice_generation_warning_logs_(0), |
| 150 num_splice_generation_success_logs_(0) { | 152 num_splice_generation_success_logs_(0), |
| 153 num_track_buffer_gap_warning_logs_(0) { | |
| 151 DCHECK(audio_config.IsValidConfig()); | 154 DCHECK(audio_config.IsValidConfig()); |
| 152 audio_configs_.push_back(audio_config); | 155 audio_configs_.push_back(audio_config); |
| 153 } | 156 } |
| 154 | 157 |
| 155 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, | 158 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, |
| 156 const scoped_refptr<MediaLog>& media_log, | 159 const scoped_refptr<MediaLog>& media_log, |
| 157 bool splice_frames_enabled) | 160 bool splice_frames_enabled) |
| 158 : media_log_(media_log), | 161 : media_log_(media_log), |
| 159 current_config_index_(0), | 162 current_config_index_(0), |
| 160 append_config_index_(0), | 163 append_config_index_(0), |
| 161 seek_pending_(false), | 164 seek_pending_(false), |
| 162 end_of_stream_(false), | 165 end_of_stream_(false), |
| 163 seek_buffer_timestamp_(kNoTimestamp()), | 166 seek_buffer_timestamp_(kNoTimestamp()), |
| 164 selected_range_(NULL), | 167 selected_range_(NULL), |
| 168 just_exhausted_track_buffer_(false), | |
| 165 media_segment_start_time_(kNoDecodeTimestamp()), | 169 media_segment_start_time_(kNoDecodeTimestamp()), |
| 166 range_for_next_append_(ranges_.end()), | 170 range_for_next_append_(ranges_.end()), |
| 167 new_media_segment_(false), | 171 new_media_segment_(false), |
| 168 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), | 172 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), |
| 169 last_appended_buffer_is_keyframe_(false), | 173 last_appended_buffer_is_keyframe_(false), |
| 170 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 174 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 171 max_interbuffer_distance_(kNoTimestamp()), | 175 max_interbuffer_distance_(kNoTimestamp()), |
| 172 memory_limit_(kSourceBufferVideoMemoryLimit), | 176 memory_limit_(kSourceBufferVideoMemoryLimit), |
| 173 config_change_pending_(false), | 177 config_change_pending_(false), |
| 174 splice_buffers_index_(0), | 178 splice_buffers_index_(0), |
| 175 pending_buffers_complete_(false), | 179 pending_buffers_complete_(false), |
| 176 splice_frames_enabled_(splice_frames_enabled), | 180 splice_frames_enabled_(splice_frames_enabled), |
| 177 num_splice_generation_warning_logs_(0), | 181 num_splice_generation_warning_logs_(0), |
| 178 num_splice_generation_success_logs_(0) { | 182 num_splice_generation_success_logs_(0), |
| 183 num_track_buffer_gap_warning_logs_(0) { | |
| 179 DCHECK(video_config.IsValidConfig()); | 184 DCHECK(video_config.IsValidConfig()); |
| 180 video_configs_.push_back(video_config); | 185 video_configs_.push_back(video_config); |
| 181 } | 186 } |
| 182 | 187 |
| 183 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, | 188 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, |
| 184 const scoped_refptr<MediaLog>& media_log, | 189 const scoped_refptr<MediaLog>& media_log, |
| 185 bool splice_frames_enabled) | 190 bool splice_frames_enabled) |
| 186 : media_log_(media_log), | 191 : media_log_(media_log), |
| 187 current_config_index_(0), | 192 current_config_index_(0), |
| 188 append_config_index_(0), | 193 append_config_index_(0), |
| 189 text_track_config_(text_config), | 194 text_track_config_(text_config), |
| 190 seek_pending_(false), | 195 seek_pending_(false), |
| 191 end_of_stream_(false), | 196 end_of_stream_(false), |
| 192 seek_buffer_timestamp_(kNoTimestamp()), | 197 seek_buffer_timestamp_(kNoTimestamp()), |
| 193 selected_range_(NULL), | 198 selected_range_(NULL), |
| 199 just_exhausted_track_buffer_(false), | |
| 194 media_segment_start_time_(kNoDecodeTimestamp()), | 200 media_segment_start_time_(kNoDecodeTimestamp()), |
| 195 range_for_next_append_(ranges_.end()), | 201 range_for_next_append_(ranges_.end()), |
| 196 new_media_segment_(false), | 202 new_media_segment_(false), |
| 197 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), | 203 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), |
| 198 last_appended_buffer_is_keyframe_(false), | 204 last_appended_buffer_is_keyframe_(false), |
| 199 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 205 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 200 max_interbuffer_distance_(kNoTimestamp()), | 206 max_interbuffer_distance_(kNoTimestamp()), |
| 201 memory_limit_(kSourceBufferAudioMemoryLimit), | 207 memory_limit_(kSourceBufferAudioMemoryLimit), |
| 202 config_change_pending_(false), | 208 config_change_pending_(false), |
| 203 splice_buffers_index_(0), | 209 splice_buffers_index_(0), |
| 204 pending_buffers_complete_(false), | 210 pending_buffers_complete_(false), |
| 205 splice_frames_enabled_(splice_frames_enabled), | 211 splice_frames_enabled_(splice_frames_enabled), |
| 206 num_splice_generation_warning_logs_(0), | 212 num_splice_generation_warning_logs_(0), |
| 207 num_splice_generation_success_logs_(0) {} | 213 num_splice_generation_success_logs_(0), |
| 214 num_track_buffer_gap_warning_logs_(0) {} | |
|
xhwang
2015/08/11 07:04:36
For future cleanup, consider using in-class member
wolenetz
2015/08/11 15:54:40
Acknowledged.
wolenetz
2015/08/11 17:52:16
Thanks for pointing out this cleanup opportunity!
| |
| 208 | 215 |
| 209 SourceBufferStream::~SourceBufferStream() { | 216 SourceBufferStream::~SourceBufferStream() { |
| 210 while (!ranges_.empty()) { | 217 while (!ranges_.empty()) { |
| 211 delete ranges_.front(); | 218 delete ranges_.front(); |
| 212 ranges_.pop_front(); | 219 ranges_.pop_front(); |
| 213 } | 220 } |
| 214 } | 221 } |
| 215 | 222 |
| 216 void SourceBufferStream::OnNewMediaSegment( | 223 void SourceBufferStream::OnNewMediaSegment( |
| 217 DecodeTimestamp media_segment_start_time) { | 224 DecodeTimestamp media_segment_start_time) { |
| (...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 | 533 |
| 527 DCHECK(IsRangeListSorted(ranges_)); | 534 DCHECK(IsRangeListSorted(ranges_)); |
| 528 DCHECK(OnlySelectedRangeIsSeeked()); | 535 DCHECK(OnlySelectedRangeIsSeeked()); |
| 529 } | 536 } |
| 530 | 537 |
| 531 void SourceBufferStream::ResetSeekState() { | 538 void SourceBufferStream::ResetSeekState() { |
| 532 SetSelectedRange(NULL); | 539 SetSelectedRange(NULL); |
| 533 track_buffer_.clear(); | 540 track_buffer_.clear(); |
| 534 config_change_pending_ = false; | 541 config_change_pending_ = false; |
| 535 last_output_buffer_timestamp_ = kNoDecodeTimestamp(); | 542 last_output_buffer_timestamp_ = kNoDecodeTimestamp(); |
| 543 just_exhausted_track_buffer_ = false; | |
| 536 splice_buffers_index_ = 0; | 544 splice_buffers_index_ = 0; |
| 537 pending_buffer_ = NULL; | 545 pending_buffer_ = NULL; |
| 538 pending_buffers_complete_ = false; | 546 pending_buffers_complete_ = false; |
| 539 } | 547 } |
| 540 | 548 |
| 541 bool SourceBufferStream::ShouldSeekToStartOfBuffered( | 549 bool SourceBufferStream::ShouldSeekToStartOfBuffered( |
| 542 base::TimeDelta seek_timestamp) const { | 550 base::TimeDelta seek_timestamp) const { |
| 543 if (ranges_.empty()) | 551 if (ranges_.empty()) |
| 544 return false; | 552 return false; |
| 545 base::TimeDelta beginning_of_buffered = | 553 base::TimeDelta beginning_of_buffered = |
| (...skipping 583 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1129 // comes from the first splice buffer. | 1137 // comes from the first splice buffer. |
| 1130 if (next_buffer->GetSpliceBufferConfigId(0) != current_config_index_) { | 1138 if (next_buffer->GetSpliceBufferConfigId(0) != current_config_index_) { |
| 1131 config_change_pending_ = true; | 1139 config_change_pending_ = true; |
| 1132 DVLOG(1) << "Config change (track buffer config ID does not match)."; | 1140 DVLOG(1) << "Config change (track buffer config ID does not match)."; |
| 1133 return kConfigChange; | 1141 return kConfigChange; |
| 1134 } | 1142 } |
| 1135 | 1143 |
| 1136 DVLOG(3) << __FUNCTION__ << " Next buffer coming from track_buffer_"; | 1144 DVLOG(3) << __FUNCTION__ << " Next buffer coming from track_buffer_"; |
| 1137 *out_buffer = next_buffer; | 1145 *out_buffer = next_buffer; |
| 1138 track_buffer_.pop_front(); | 1146 track_buffer_.pop_front(); |
| 1147 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer); | |
| 1139 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); | 1148 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); |
| 1140 | 1149 |
| 1141 // If the track buffer becomes empty, then try to set the selected range | 1150 // If the track buffer becomes empty, then try to set the selected range |
| 1142 // based on the timestamp of this buffer being returned. | 1151 // based on the timestamp of this buffer being returned. |
| 1143 if (track_buffer_.empty()) | 1152 if (track_buffer_.empty()) { |
| 1153 just_exhausted_track_buffer_ = true; | |
| 1144 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_); | 1154 SetSelectedRangeIfNeeded(last_output_buffer_timestamp_); |
| 1155 } | |
| 1145 | 1156 |
| 1146 return kSuccess; | 1157 return kSuccess; |
| 1147 } | 1158 } |
| 1148 | 1159 |
| 1149 DCHECK(track_buffer_.empty()); | 1160 DCHECK(track_buffer_.empty()); |
| 1150 if (!selected_range_ || !selected_range_->HasNextBuffer()) { | 1161 if (!selected_range_ || !selected_range_->HasNextBuffer()) { |
| 1151 if (IsEndOfStreamReached()) { | 1162 if (IsEndOfStreamReached()) { |
| 1152 return kEndOfStream; | 1163 return kEndOfStream; |
| 1153 } | 1164 } |
| 1154 DVLOG(3) << __FUNCTION__ << " " << GetStreamTypeName() | 1165 DVLOG(3) << __FUNCTION__ << " " << GetStreamTypeName() |
| 1155 << ": returning kNeedBuffer " | 1166 << ": returning kNeedBuffer " |
| 1156 << (selected_range_ ? "(selected range has no next buffer)" | 1167 << (selected_range_ ? "(selected range has no next buffer)" |
| 1157 : "(no selected range)"); | 1168 : "(no selected range)"); |
| 1158 return kNeedBuffer; | 1169 return kNeedBuffer; |
| 1159 } | 1170 } |
| 1160 | 1171 |
| 1161 if (selected_range_->GetNextConfigId() != current_config_index_) { | 1172 if (selected_range_->GetNextConfigId() != current_config_index_) { |
| 1162 config_change_pending_ = true; | 1173 config_change_pending_ = true; |
| 1163 DVLOG(1) << "Config change (selected range config ID does not match)."; | 1174 DVLOG(1) << "Config change (selected range config ID does not match)."; |
| 1164 return kConfigChange; | 1175 return kConfigChange; |
| 1165 } | 1176 } |
| 1166 | 1177 |
| 1167 CHECK(selected_range_->GetNextBuffer(out_buffer)); | 1178 CHECK(selected_range_->GetNextBuffer(out_buffer)); |
| 1179 WarnIfTrackBufferExhaustionSkipsForward(*out_buffer); | |
| 1168 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); | 1180 last_output_buffer_timestamp_ = (*out_buffer)->GetDecodeTimestamp(); |
| 1169 return kSuccess; | 1181 return kSuccess; |
| 1170 } | 1182 } |
| 1171 | 1183 |
| 1184 void SourceBufferStream::WarnIfTrackBufferExhaustionSkipsForward( | |
| 1185 const scoped_refptr<StreamParserBuffer>& next_buffer) { | |
| 1186 if (!just_exhausted_track_buffer_) | |
| 1187 return; | |
| 1188 | |
| 1189 just_exhausted_track_buffer_ = false; | |
| 1190 DCHECK(next_buffer->is_key_frame()); | |
| 1191 DecodeTimestamp next_output_buffer_timestamp = | |
| 1192 next_buffer->GetDecodeTimestamp(); | |
| 1193 base::TimeDelta delta = | |
| 1194 next_output_buffer_timestamp - last_output_buffer_timestamp_; | |
| 1195 DCHECK_GE(delta, base::TimeDelta()); | |
| 1196 if (delta > GetMaxInterbufferDistance()) { | |
| 1197 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_track_buffer_gap_warning_logs_, | |
| 1198 kMaxTrackBufferGapWarningLogs) | |
| 1199 << "Media append that overlapped current playback position caused time " | |
| 1200 "gap in playing " | |
| 1201 << GetStreamTypeName() << " stream because the next keyframe is " | |
| 1202 << delta.InMilliseconds() << "ms beyond last overlapped frame. Media " | |
| 1203 "may appear temporarily frozen."; | |
| 1204 } | |
| 1205 } | |
| 1206 | |
| 1172 DecodeTimestamp SourceBufferStream::GetNextBufferTimestamp() { | 1207 DecodeTimestamp SourceBufferStream::GetNextBufferTimestamp() { |
| 1173 if (!track_buffer_.empty()) | 1208 if (!track_buffer_.empty()) |
| 1174 return track_buffer_.front()->GetDecodeTimestamp(); | 1209 return track_buffer_.front()->GetDecodeTimestamp(); |
| 1175 | 1210 |
| 1176 if (!selected_range_) | 1211 if (!selected_range_) |
| 1177 return kNoDecodeTimestamp(); | 1212 return kNoDecodeTimestamp(); |
| 1178 | 1213 |
| 1179 DCHECK(selected_range_->HasNextBufferPosition()); | 1214 DCHECK(selected_range_->HasNextBufferPosition()); |
| 1180 return selected_range_->GetNextTimestamp(); | 1215 return selected_range_->GetNextTimestamp(); |
| 1181 } | 1216 } |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1667 return false; | 1702 return false; |
| 1668 | 1703 |
| 1669 DCHECK_NE(have_splice_buffers, have_preroll_buffer); | 1704 DCHECK_NE(have_splice_buffers, have_preroll_buffer); |
| 1670 splice_buffers_index_ = 0; | 1705 splice_buffers_index_ = 0; |
| 1671 pending_buffer_.swap(*out_buffer); | 1706 pending_buffer_.swap(*out_buffer); |
| 1672 pending_buffers_complete_ = false; | 1707 pending_buffers_complete_ = false; |
| 1673 return true; | 1708 return true; |
| 1674 } | 1709 } |
| 1675 | 1710 |
| 1676 } // namespace media | 1711 } // namespace media |
| OLD | NEW |