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 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 // important for debugging splice generation. | 30 // important for debugging splice generation. |
| 31 const int kMaxSpliceGenerationWarningLogs = 50; | 31 const int kMaxSpliceGenerationWarningLogs = 50; |
| 32 const int kMaxSpliceGenerationSuccessLogs = 20; | 32 const int kMaxSpliceGenerationSuccessLogs = 20; |
| 33 | 33 |
| 34 // Limit the number of MEDIA_LOG() logs for track buffer time gaps. | 34 // Limit the number of MEDIA_LOG() logs for track buffer time gaps. |
| 35 const int kMaxTrackBufferGapWarningLogs = 20; | 35 const int kMaxTrackBufferGapWarningLogs = 20; |
| 36 | 36 |
| 37 // Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings. | 37 // Limit the number of MEDIA_LOG() logs for MSE GC algorithm warnings. |
| 38 const int kMaxGarbageCollectAlgorithmWarningLogs = 20; | 38 const int kMaxGarbageCollectAlgorithmWarningLogs = 20; |
| 39 | 39 |
| 40 // Limit the number of MEDIA_LOG() logs for same DTS for non-keyframe followed | |
| 41 // by keyframe. Prior to relaxing the "media segments must begin with a | |
| 42 // keyframe" requirement, we issued decode error for this situation. That was | |
| 43 // likely too strict, and now that the keyframe requirement is relaxed, we have | |
| 44 // no knowledge of media segment boundaries here. Now, we log but don't trigger | |
| 45 // decode error, since we allow these sequences which may cause extra decoder | |
| 46 // work or other side-effects. | |
| 47 const int kMaxStrangeSameTimestampsLogs = 20; | |
| 48 | |
| 40 // Helper method that returns true if |ranges| is sorted in increasing order, | 49 // Helper method that returns true if |ranges| is sorted in increasing order, |
| 41 // false otherwise. | 50 // false otherwise. |
| 42 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) { | 51 bool IsRangeListSorted(const std::list<media::SourceBufferRange*>& ranges) { |
| 43 DecodeTimestamp prev = kNoDecodeTimestamp(); | 52 DecodeTimestamp prev = kNoDecodeTimestamp(); |
| 44 for (std::list<SourceBufferRange*>::const_iterator itr = | 53 for (std::list<SourceBufferRange*>::const_iterator itr = |
| 45 ranges.begin(); itr != ranges.end(); ++itr) { | 54 ranges.begin(); itr != ranges.end(); ++itr) { |
| 46 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp()) | 55 if (prev != kNoDecodeTimestamp() && prev >= (*itr)->GetStartTimestamp()) |
| 47 return false; | 56 return false; |
| 48 prev = (*itr)->GetEndTimestamp(); | 57 prev = (*itr)->GetEndTimestamp(); |
| 49 } | 58 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 130 return SourceBufferRange::NO_GAPS_ALLOWED; | 139 return SourceBufferRange::NO_GAPS_ALLOWED; |
| 131 } | 140 } |
| 132 | 141 |
| 133 } // namespace | 142 } // namespace |
| 134 | 143 |
| 135 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, | 144 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, |
| 136 const scoped_refptr<MediaLog>& media_log, | 145 const scoped_refptr<MediaLog>& media_log, |
| 137 bool splice_frames_enabled) | 146 bool splice_frames_enabled) |
| 138 : media_log_(media_log), | 147 : media_log_(media_log), |
| 139 seek_buffer_timestamp_(kNoTimestamp()), | 148 seek_buffer_timestamp_(kNoTimestamp()), |
| 140 media_segment_start_time_(kNoDecodeTimestamp()), | 149 coded_frame_group_start_time_(kNoDecodeTimestamp()), |
| 141 range_for_next_append_(ranges_.end()), | 150 range_for_next_append_(ranges_.end()), |
| 142 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 151 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 143 max_interbuffer_distance_(kNoTimestamp()), | 152 max_interbuffer_distance_(kNoTimestamp()), |
| 144 memory_limit_(kSourceBufferAudioMemoryLimit), | 153 memory_limit_(kSourceBufferAudioMemoryLimit), |
| 145 splice_frames_enabled_(splice_frames_enabled) { | 154 splice_frames_enabled_(splice_frames_enabled) { |
| 146 DCHECK(audio_config.IsValidConfig()); | 155 DCHECK(audio_config.IsValidConfig()); |
| 147 audio_configs_.push_back(audio_config); | 156 audio_configs_.push_back(audio_config); |
| 148 } | 157 } |
| 149 | 158 |
| 150 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, | 159 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, |
| 151 const scoped_refptr<MediaLog>& media_log, | 160 const scoped_refptr<MediaLog>& media_log, |
| 152 bool splice_frames_enabled) | 161 bool splice_frames_enabled) |
| 153 : media_log_(media_log), | 162 : media_log_(media_log), |
| 154 seek_buffer_timestamp_(kNoTimestamp()), | 163 seek_buffer_timestamp_(kNoTimestamp()), |
| 155 media_segment_start_time_(kNoDecodeTimestamp()), | 164 coded_frame_group_start_time_(kNoDecodeTimestamp()), |
| 156 range_for_next_append_(ranges_.end()), | 165 range_for_next_append_(ranges_.end()), |
| 157 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 166 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 158 max_interbuffer_distance_(kNoTimestamp()), | 167 max_interbuffer_distance_(kNoTimestamp()), |
| 159 memory_limit_(kSourceBufferVideoMemoryLimit), | 168 memory_limit_(kSourceBufferVideoMemoryLimit), |
| 160 splice_frames_enabled_(splice_frames_enabled) { | 169 splice_frames_enabled_(splice_frames_enabled) { |
| 161 DCHECK(video_config.IsValidConfig()); | 170 DCHECK(video_config.IsValidConfig()); |
| 162 video_configs_.push_back(video_config); | 171 video_configs_.push_back(video_config); |
| 163 } | 172 } |
| 164 | 173 |
| 165 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, | 174 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, |
| 166 const scoped_refptr<MediaLog>& media_log, | 175 const scoped_refptr<MediaLog>& media_log, |
| 167 bool splice_frames_enabled) | 176 bool splice_frames_enabled) |
| 168 : media_log_(media_log), | 177 : media_log_(media_log), |
| 169 text_track_config_(text_config), | 178 text_track_config_(text_config), |
| 170 seek_buffer_timestamp_(kNoTimestamp()), | 179 seek_buffer_timestamp_(kNoTimestamp()), |
| 171 media_segment_start_time_(kNoDecodeTimestamp()), | 180 coded_frame_group_start_time_(kNoDecodeTimestamp()), |
| 172 range_for_next_append_(ranges_.end()), | 181 range_for_next_append_(ranges_.end()), |
| 173 last_output_buffer_timestamp_(kNoDecodeTimestamp()), | 182 last_output_buffer_timestamp_(kNoDecodeTimestamp()), |
| 174 max_interbuffer_distance_(kNoTimestamp()), | 183 max_interbuffer_distance_(kNoTimestamp()), |
| 175 memory_limit_(kSourceBufferAudioMemoryLimit), | 184 memory_limit_(kSourceBufferAudioMemoryLimit), |
| 176 splice_frames_enabled_(splice_frames_enabled) {} | 185 splice_frames_enabled_(splice_frames_enabled) {} |
| 177 | 186 |
| 178 SourceBufferStream::~SourceBufferStream() { | 187 SourceBufferStream::~SourceBufferStream() { |
| 179 while (!ranges_.empty()) { | 188 while (!ranges_.empty()) { |
| 180 delete ranges_.front(); | 189 delete ranges_.front(); |
| 181 ranges_.pop_front(); | 190 ranges_.pop_front(); |
| 182 } | 191 } |
| 183 } | 192 } |
| 184 | 193 |
| 185 void SourceBufferStream::OnNewMediaSegment( | 194 void SourceBufferStream::OnStartOfCodedFrameGroup( |
| 186 DecodeTimestamp media_segment_start_time) { | 195 DecodeTimestamp coded_frame_group_start_time) { |
| 187 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() | 196 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << " (" |
| 188 << " (" << media_segment_start_time.InSecondsF() << ")"; | 197 << coded_frame_group_start_time.InSecondsF() << ")"; |
| 189 DCHECK(!end_of_stream_); | 198 DCHECK(!end_of_stream_); |
| 190 media_segment_start_time_ = media_segment_start_time; | 199 coded_frame_group_start_time_ = coded_frame_group_start_time; |
| 191 new_media_segment_ = true; | 200 new_coded_frame_group_ = true; |
| 192 | 201 |
| 193 RangeList::iterator last_range = range_for_next_append_; | 202 RangeList::iterator last_range = range_for_next_append_; |
| 194 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time); | 203 range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_time); |
| 195 | 204 |
| 196 // Only reset |last_appended_buffer_timestamp_| if this new media segment is | 205 // Only reset |last_appended_buffer_timestamp_| if this new coded frame group |
| 197 // not adjacent to the previous media segment appended to the stream. | 206 // is not adjacent to the previous coded frame group appended to the stream. |
| 198 if (range_for_next_append_ == ranges_.end() || | 207 if (range_for_next_append_ == ranges_.end() || |
| 199 !AreAdjacentInSequence(last_appended_buffer_timestamp_, | 208 !AreAdjacentInSequence(last_appended_buffer_timestamp_, |
| 200 media_segment_start_time)) { | 209 coded_frame_group_start_time)) { |
| 201 last_appended_buffer_timestamp_ = kNoDecodeTimestamp(); | 210 last_appended_buffer_timestamp_ = kNoDecodeTimestamp(); |
| 202 last_appended_buffer_duration_ = kNoTimestamp(); | 211 last_appended_buffer_duration_ = kNoTimestamp(); |
| 203 last_appended_buffer_is_keyframe_ = false; | 212 last_appended_buffer_is_keyframe_ = false; |
| 204 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range"; | 213 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range"; |
| 205 } else if (last_range != ranges_.end()) { | 214 } else if (last_range != ranges_.end()) { |
| 206 DCHECK(last_range == range_for_next_append_); | 215 DCHECK(last_range == range_for_next_append_); |
| 207 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range " | 216 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range " |
| 208 << "unless intervening remove makes discontinuity"; | 217 << "unless intervening remove makes discontinuity"; |
| 209 } | 218 } |
| 210 } | 219 } |
| 211 | 220 |
| 212 bool SourceBufferStream::Append(const BufferQueue& buffers) { | 221 bool SourceBufferStream::Append(const BufferQueue& buffers) { |
| 213 TRACE_EVENT2("media", "SourceBufferStream::Append", | 222 TRACE_EVENT2("media", "SourceBufferStream::Append", |
| 214 "stream type", GetStreamTypeName(), | 223 "stream type", GetStreamTypeName(), |
| 215 "buffers to append", buffers.size()); | 224 "buffers to append", buffers.size()); |
| 216 | 225 |
| 217 DCHECK(!buffers.empty()); | 226 DCHECK(!buffers.empty()); |
| 218 DCHECK(media_segment_start_time_ != kNoDecodeTimestamp()); | 227 DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp()); |
| 219 DCHECK(media_segment_start_time_ <= buffers.front()->GetDecodeTimestamp()); | 228 DCHECK(coded_frame_group_start_time_ <= |
| 229 buffers.front()->GetDecodeTimestamp()); | |
| 220 DCHECK(!end_of_stream_); | 230 DCHECK(!end_of_stream_); |
| 221 | 231 |
| 222 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() | 232 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() |
| 223 << ": buffers " << BufferQueueToLogString(buffers); | 233 << ": buffers " << BufferQueueToLogString(buffers); |
| 224 | 234 |
| 225 // New media segments must begin with a keyframe. | 235 // New coded frame groups emitted by the coded frame processor must begin with |
| 226 // TODO(wolenetz): Relax this requirement. See http://crbug.com/229412. | 236 // a keyframe. TODO(wolenetz): Change this to [DCHECK + MEDIA_LOG(ERROR...) + |
| 227 if (new_media_segment_ && !buffers.front()->is_key_frame()) { | 237 // return false] once the CHECK has baked in a stable release. See |
| 228 MEDIA_LOG(ERROR, media_log_) << "Media segment did not begin with key " | 238 // https://crbug.com/580621. |
| 229 "frame. Support for such segments will be " | 239 CHECK(!new_coded_frame_group_ || buffers.front()->is_key_frame()); |
| 230 "available in a future version. Please see " | 240 |
| 231 "https://crbug.com/229412."; | 241 // Buffers within a coded frame group should be monotonically increasing. |
|
wolenetz
2016/02/05 23:27:24
Note that IsMonotonicallyIncreasing() does the sam
chcunningham
2016/02/09 00:21:08
Acknowledged.
| |
| 242 if (!IsMonotonicallyIncreasing(buffers)) { | |
| 232 return false; | 243 return false; |
| 233 } | 244 } |
| 234 | 245 |
| 235 // Buffers within a media segment should be monotonically increasing. | 246 if (coded_frame_group_start_time_ < DecodeTimestamp() || |
| 236 if (!IsMonotonicallyIncreasing(buffers)) | |
| 237 return false; | |
| 238 | |
| 239 if (media_segment_start_time_ < DecodeTimestamp() || | |
| 240 buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) { | 247 buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) { |
| 241 MEDIA_LOG(ERROR, media_log_) | 248 MEDIA_LOG(ERROR, media_log_) |
| 242 << "Cannot append a media segment with negative timestamps."; | 249 << "Cannot append a coded frame group with negative timestamps."; |
| 243 return false; | 250 return false; |
| 244 } | 251 } |
| 245 | 252 |
| 246 if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(), | |
| 247 buffers.front()->is_key_frame())) { | |
| 248 const DecodeTimestamp& dts = buffers.front()->GetDecodeTimestamp(); | |
| 249 MEDIA_LOG(ERROR, media_log_) | |
| 250 << "Invalid same timestamp construct detected at" | |
| 251 << " time " << dts.InSecondsF(); | |
| 252 | |
| 253 return false; | |
| 254 } | |
| 255 | |
| 256 UpdateMaxInterbufferDistance(buffers); | 253 UpdateMaxInterbufferDistance(buffers); |
| 257 SetConfigIds(buffers); | 254 SetConfigIds(buffers); |
| 258 | 255 |
| 259 // Save a snapshot of stream state before range modifications are made. | 256 // Save a snapshot of stream state before range modifications are made. |
| 260 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); | 257 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); |
| 261 BufferQueue deleted_buffers; | 258 BufferQueue deleted_buffers; |
| 262 | 259 |
| 263 PrepareRangesForNextAppend(buffers, &deleted_buffers); | 260 PrepareRangesForNextAppend(buffers, &deleted_buffers); |
| 264 | 261 |
| 265 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, | 262 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, |
| 266 // create a new range with |buffers|. | 263 // create a new range with |buffers|. |
| 267 if (range_for_next_append_ != ranges_.end()) { | 264 if (range_for_next_append_ != ranges_.end()) { |
| 268 (*range_for_next_append_)->AppendBuffersToEnd(buffers); | 265 (*range_for_next_append_)->AppendBuffersToEnd(buffers); |
| 269 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); | 266 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); |
| 270 last_appended_buffer_duration_ = buffers.back()->duration(); | 267 last_appended_buffer_duration_ = buffers.back()->duration(); |
| 271 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); | 268 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); |
| 272 } else { | 269 } else { |
| 273 DecodeTimestamp new_range_start_time = std::min( | 270 DecodeTimestamp new_range_start_time = std::min( |
| 274 media_segment_start_time_, buffers.front()->GetDecodeTimestamp()); | 271 coded_frame_group_start_time_, buffers.front()->GetDecodeTimestamp()); |
| 275 const BufferQueue* buffers_for_new_range = &buffers; | 272 const BufferQueue* buffers_for_new_range = &buffers; |
| 276 BufferQueue trimmed_buffers; | 273 BufferQueue trimmed_buffers; |
| 277 | 274 |
| 278 // If the new range is not being created because of a new media | 275 // If the new range is not being created because of a new coded frame group, |
| 279 // segment, then we must make sure that we start with a key frame. | 276 // then we must make sure that we start with a key frame. This can happen |
| 280 // This can happen if the GOP in the previous append gets destroyed | 277 // if the GOP in the previous append gets destroyed by a Remove() call. |
| 281 // by a Remove() call. | 278 if (!new_coded_frame_group_) { |
| 282 if (!new_media_segment_) { | |
| 283 BufferQueue::const_iterator itr = buffers.begin(); | 279 BufferQueue::const_iterator itr = buffers.begin(); |
| 284 | 280 |
| 285 // Scan past all the non-key-frames. | 281 // Scan past all the non-key-frames. |
| 286 while (itr != buffers.end() && !(*itr)->is_key_frame()) { | 282 while (itr != buffers.end() && !(*itr)->is_key_frame()) { |
| 287 ++itr; | 283 ++itr; |
| 288 } | 284 } |
| 289 | 285 |
| 290 // If we didn't find a key frame, then update the last appended | 286 // If we didn't find a key frame, then update the last appended |
| 291 // buffer state and return. | 287 // buffer state and return. |
| 292 if (itr == buffers.end()) { | 288 if (itr == buffers.end()) { |
| 293 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); | 289 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); |
| 294 last_appended_buffer_duration_ = buffers.back()->duration(); | 290 last_appended_buffer_duration_ = buffers.back()->duration(); |
| 295 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); | 291 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); |
| 296 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() | 292 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() |
| 297 << ": new buffers in the middle of media segment depend on" | 293 << ": new buffers in the middle of coded frame group depend on" |
| 298 "keyframe that has been removed, and contain no keyframes." | 294 "keyframe that has been removed, and contain no keyframes." |
| 299 "Skipping further processing."; | 295 "Skipping further processing."; |
| 300 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() | 296 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() |
| 301 << ": done. ranges_=" << RangesToString(ranges_); | 297 << ": done. ranges_=" << RangesToString(ranges_); |
| 302 return true; | 298 return true; |
| 303 } else if (itr != buffers.begin()) { | 299 } else if (itr != buffers.begin()) { |
| 304 // Copy the first key frame and everything after it into | 300 // Copy the first key frame and everything after it into |
| 305 // |trimmed_buffers|. | 301 // |trimmed_buffers|. |
| 306 trimmed_buffers.assign(itr, buffers.end()); | 302 trimmed_buffers.assign(itr, buffers.end()); |
| 307 buffers_for_new_range = &trimmed_buffers; | 303 buffers_for_new_range = &trimmed_buffers; |
| 308 } | 304 } |
| 309 | 305 |
| 310 new_range_start_time = | 306 new_range_start_time = |
| 311 buffers_for_new_range->front()->GetDecodeTimestamp(); | 307 buffers_for_new_range->front()->GetDecodeTimestamp(); |
| 312 } | 308 } |
| 313 | 309 |
| 314 range_for_next_append_ = | 310 range_for_next_append_ = |
| 315 AddToRanges(new SourceBufferRange( | 311 AddToRanges(new SourceBufferRange( |
| 316 TypeToGapPolicy(GetType()), | 312 TypeToGapPolicy(GetType()), |
| 317 *buffers_for_new_range, new_range_start_time, | 313 *buffers_for_new_range, new_range_start_time, |
| 318 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, | 314 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, |
| 319 base::Unretained(this)))); | 315 base::Unretained(this)))); |
| 320 last_appended_buffer_timestamp_ = | 316 last_appended_buffer_timestamp_ = |
| 321 buffers_for_new_range->back()->GetDecodeTimestamp(); | 317 buffers_for_new_range->back()->GetDecodeTimestamp(); |
| 322 last_appended_buffer_duration_ = buffers_for_new_range->back()->duration(); | 318 last_appended_buffer_duration_ = buffers_for_new_range->back()->duration(); |
| 323 last_appended_buffer_is_keyframe_ = | 319 last_appended_buffer_is_keyframe_ = |
| 324 buffers_for_new_range->back()->is_key_frame(); | 320 buffers_for_new_range->back()->is_key_frame(); |
| 325 } | 321 } |
| 326 | 322 |
| 327 new_media_segment_ = false; | 323 new_coded_frame_group_ = false; |
| 328 | 324 |
| 329 MergeWithAdjacentRangeIfNecessary(range_for_next_append_); | 325 MergeWithAdjacentRangeIfNecessary(range_for_next_append_); |
| 330 | 326 |
| 331 // Seek to try to fulfill a previous call to Seek(). | 327 // Seek to try to fulfill a previous call to Seek(). |
| 332 if (seek_pending_) { | 328 if (seek_pending_) { |
| 333 DCHECK(!selected_range_); | 329 DCHECK(!selected_range_); |
| 334 DCHECK(deleted_buffers.empty()); | 330 DCHECK(deleted_buffers.empty()); |
| 335 Seek(seek_buffer_timestamp_); | 331 Seek(seek_buffer_timestamp_); |
| 336 } | 332 } |
| 337 | 333 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 while (itr != ranges_.end()) { | 429 while (itr != ranges_.end()) { |
| 434 SourceBufferRange* range = *itr; | 430 SourceBufferRange* range = *itr; |
| 435 if (range->GetStartTimestamp() >= end) | 431 if (range->GetStartTimestamp() >= end) |
| 436 break; | 432 break; |
| 437 | 433 |
| 438 // Split off any remaining GOPs starting at or after |end| and add it to | 434 // Split off any remaining GOPs starting at or after |end| and add it to |
| 439 // |ranges_|. | 435 // |ranges_|. |
| 440 SourceBufferRange* new_range = range->SplitRange(end); | 436 SourceBufferRange* new_range = range->SplitRange(end); |
| 441 if (new_range) { | 437 if (new_range) { |
| 442 itr = ranges_.insert(++itr, new_range); | 438 itr = ranges_.insert(++itr, new_range); |
| 439 | |
| 440 // Update |range_for_next_append_| if it was previously |range| and should | |
|
wolenetz
2016/02/05 23:27:24
Note: this is the core of the fix for crbug 581458
chcunningham
2016/02/09 00:21:08
Acknowledged.
| |
| 441 // be |new_range| now. | |
| 442 if (range_for_next_append_ != ranges_.end() && | |
| 443 *range_for_next_append_ == range && | |
| 444 last_appended_buffer_timestamp_ != kNoDecodeTimestamp()) { | |
|
chcunningham
2016/02/09 00:21:08
I'm wondering about the case where we've just gott
wolenetz
2016/02/09 00:47:19
I'll need to grok this a little more. I'll get an
wolenetz
2016/02/09 01:36:41
Great comment, Chris!
We've never tested any case
wolenetz
2016/02/12 01:23:47
Done. (as of patch set #5)
| |
| 445 DecodeTimestamp potential_next_append_timestamp = | |
| 446 last_appended_buffer_timestamp_ + | |
| 447 base::TimeDelta::FromInternalValue(1); | |
| 448 if (new_range->BelongsToRange(potential_next_append_timestamp)) | |
| 449 range_for_next_append_ = itr; | |
| 450 } | |
| 451 | |
| 443 --itr; | 452 --itr; |
| 444 | 453 |
| 445 // Update the selected range if the next buffer position was transferred | 454 // Update the selected range if the next buffer position was transferred |
| 446 // to |new_range|. | 455 // to |new_range|. |
| 447 if (new_range->HasNextBufferPosition()) | 456 if (new_range->HasNextBufferPosition()) |
| 448 SetSelectedRange(new_range); | 457 SetSelectedRange(new_range); |
| 449 } | 458 } |
| 450 | 459 |
| 451 // Truncate the current range so that it only contains data before | 460 // Truncate the current range so that it only contains data before |
| 452 // the removal range. | 461 // the removal range. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 515 bool SourceBufferStream::ShouldSeekToStartOfBuffered( | 524 bool SourceBufferStream::ShouldSeekToStartOfBuffered( |
| 516 base::TimeDelta seek_timestamp) const { | 525 base::TimeDelta seek_timestamp) const { |
| 517 if (ranges_.empty()) | 526 if (ranges_.empty()) |
| 518 return false; | 527 return false; |
| 519 base::TimeDelta beginning_of_buffered = | 528 base::TimeDelta beginning_of_buffered = |
| 520 ranges_.front()->GetStartTimestamp().ToPresentationTime(); | 529 ranges_.front()->GetStartTimestamp().ToPresentationTime(); |
| 521 return (seek_timestamp <= beginning_of_buffered && | 530 return (seek_timestamp <= beginning_of_buffered && |
| 522 beginning_of_buffered < kSeekToStartFudgeRoom()); | 531 beginning_of_buffered < kSeekToStartFudgeRoom()); |
| 523 } | 532 } |
| 524 | 533 |
| 525 bool SourceBufferStream::IsMonotonicallyIncreasing( | 534 bool SourceBufferStream::IsMonotonicallyIncreasing(const BufferQueue& buffers) { |
| 526 const BufferQueue& buffers) const { | |
| 527 DCHECK(!buffers.empty()); | 535 DCHECK(!buffers.empty()); |
| 528 DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_; | 536 DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_; |
| 529 bool prev_is_keyframe = last_appended_buffer_is_keyframe_; | 537 bool prev_is_keyframe = last_appended_buffer_is_keyframe_; |
| 530 for (BufferQueue::const_iterator itr = buffers.begin(); | 538 for (BufferQueue::const_iterator itr = buffers.begin(); |
| 531 itr != buffers.end(); ++itr) { | 539 itr != buffers.end(); ++itr) { |
| 532 DecodeTimestamp current_timestamp = (*itr)->GetDecodeTimestamp(); | 540 DecodeTimestamp current_timestamp = (*itr)->GetDecodeTimestamp(); |
| 533 bool current_is_keyframe = (*itr)->is_key_frame(); | 541 bool current_is_keyframe = (*itr)->is_key_frame(); |
| 534 DCHECK(current_timestamp != kNoDecodeTimestamp()); | 542 DCHECK(current_timestamp != kNoDecodeTimestamp()); |
| 535 DCHECK((*itr)->duration() >= base::TimeDelta()) | 543 DCHECK((*itr)->duration() >= base::TimeDelta()) |
| 536 << "Packet with invalid duration." | 544 << "Packet with invalid duration." |
| 537 << " pts " << (*itr)->timestamp().InSecondsF() | 545 << " pts " << (*itr)->timestamp().InSecondsF() |
| 538 << " dts " << (*itr)->GetDecodeTimestamp().InSecondsF() | 546 << " dts " << (*itr)->GetDecodeTimestamp().InSecondsF() |
| 539 << " dur " << (*itr)->duration().InSecondsF(); | 547 << " dur " << (*itr)->duration().InSecondsF(); |
| 540 | 548 |
| 541 if (prev_timestamp != kNoDecodeTimestamp()) { | 549 if (prev_timestamp != kNoDecodeTimestamp()) { |
| 542 if (current_timestamp < prev_timestamp) { | 550 if (current_timestamp < prev_timestamp) { |
| 543 MEDIA_LOG(ERROR, media_log_) | 551 MEDIA_LOG(ERROR, media_log_) |
| 544 << "Buffers did not monotonically increase."; | 552 << "Buffers did not monotonically increase."; |
| 545 return false; | 553 return false; |
| 546 } | 554 } |
| 547 | 555 |
| 548 if (current_timestamp == prev_timestamp && | 556 if (current_timestamp == prev_timestamp && |
| 549 !SourceBufferRange::AllowSameTimestamp(prev_is_keyframe, | 557 SourceBufferRange::IsUncommonSameTimestampSequence( |
|
wolenetz
2016/02/05 23:27:24
Note, this is the core of the fix for crbug 581125
chcunningham
2016/02/09 00:21:08
Acknowledged.
| |
| 550 current_is_keyframe)) { | 558 prev_is_keyframe, current_is_keyframe)) { |
| 551 MEDIA_LOG(ERROR, media_log_) << "Unexpected combination of buffers with" | 559 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_strange_same_timestamps_logs_, |
| 552 << " the same timestamp detected at " | 560 kMaxStrangeSameTimestampsLogs) |
| 553 << current_timestamp.InSecondsF(); | 561 << "Detected an append sequence with keyframe following a " |
| 554 return false; | 562 "non-keyframe, both with the same decode timestamp of " |
| 563 << current_timestamp.InSecondsF(); | |
| 555 } | 564 } |
| 556 } | 565 } |
| 557 | 566 |
| 558 prev_timestamp = current_timestamp; | 567 prev_timestamp = current_timestamp; |
| 559 prev_is_keyframe = current_is_keyframe; | 568 prev_is_keyframe = current_is_keyframe; |
| 560 } | 569 } |
| 561 return true; | 570 return true; |
| 562 } | 571 } |
| 563 | 572 |
| 564 bool SourceBufferStream::IsNextTimestampValid( | |
| 565 DecodeTimestamp next_timestamp, bool next_is_keyframe) const { | |
| 566 return (last_appended_buffer_timestamp_ != next_timestamp) || | |
| 567 new_media_segment_ || | |
| 568 SourceBufferRange::AllowSameTimestamp(last_appended_buffer_is_keyframe_, | |
| 569 next_is_keyframe); | |
| 570 } | |
| 571 | |
| 572 | |
| 573 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const { | 573 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const { |
| 574 for (RangeList::const_iterator itr = ranges_.begin(); | 574 for (RangeList::const_iterator itr = ranges_.begin(); |
| 575 itr != ranges_.end(); ++itr) { | 575 itr != ranges_.end(); ++itr) { |
| 576 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_) | 576 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_) |
| 577 return false; | 577 return false; |
| 578 } | 578 } |
| 579 return !selected_range_ || selected_range_->HasNextBufferPosition(); | 579 return !selected_range_ || selected_range_->HasNextBufferPosition(); |
| 580 } | 580 } |
| 581 | 581 |
| 582 void SourceBufferStream::UpdateMaxInterbufferDistance( | 582 void SourceBufferStream::UpdateMaxInterbufferDistance( |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 920 const BufferQueue& new_buffers, BufferQueue* deleted_buffers) { | 920 const BufferQueue& new_buffers, BufferQueue* deleted_buffers) { |
| 921 DCHECK(deleted_buffers); | 921 DCHECK(deleted_buffers); |
| 922 | 922 |
| 923 // Handle splices between the existing buffers and the new buffers. If a | 923 // Handle splices between the existing buffers and the new buffers. If a |
| 924 // splice is generated the timestamp and duration of the first buffer in | 924 // splice is generated the timestamp and duration of the first buffer in |
| 925 // |new_buffers| will be modified. | 925 // |new_buffers| will be modified. |
| 926 if (splice_frames_enabled_) | 926 if (splice_frames_enabled_) |
| 927 GenerateSpliceFrame(new_buffers); | 927 GenerateSpliceFrame(new_buffers); |
| 928 | 928 |
| 929 DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_; | 929 DecodeTimestamp prev_timestamp = last_appended_buffer_timestamp_; |
| 930 bool prev_is_keyframe = last_appended_buffer_is_keyframe_; | |
| 931 DecodeTimestamp next_timestamp = new_buffers.front()->GetDecodeTimestamp(); | 930 DecodeTimestamp next_timestamp = new_buffers.front()->GetDecodeTimestamp(); |
| 932 bool next_is_keyframe = new_buffers.front()->is_key_frame(); | |
| 933 | 931 |
| 934 if (prev_timestamp != kNoDecodeTimestamp() && | 932 if (prev_timestamp != kNoDecodeTimestamp() && |
| 935 prev_timestamp != next_timestamp) { | 933 prev_timestamp != next_timestamp) { |
| 936 // Clean up the old buffers between the last appended buffer and the | 934 // Clean up the old buffers between the last appended buffer and the |
| 937 // beginning of |new_buffers|. | 935 // beginning of |new_buffers|. |
| 938 RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers); | 936 RemoveInternal(prev_timestamp, next_timestamp, true, deleted_buffers); |
| 939 } | 937 } |
| 940 | 938 |
| 941 // Make the delete range exclusive if we are dealing with an allowed same | 939 // Always make the start of the delete range exclusive for same timestamp |
| 942 // timestamp situation. This prevents the first buffer in the current append | 940 // across the last buffer in the previous append and the first buffer in the |
| 943 // from deleting the last buffer in the previous append if both buffers | 941 // current append. Never be exclusive if a splice frame was generated because |
|
chcunningham
2016/02/09 00:21:08
Does the splice buffers check really make sense he
wolenetz
2016/02/09 00:47:19
Hmm. PrepareRangesForNextAppend() actually calls G
wolenetz
2016/02/12 01:23:47
From chat, this is fodder for a low pri later CL.
| |
| 944 // have the same timestamp. | 942 // we don't generate splice frames for same timestamp situations. |
| 945 // | |
| 946 // The delete range should never be exclusive if a splice frame was generated | |
| 947 // because we don't generate splice frames for same timestamp situations. | |
| 948 DCHECK(new_buffers.front()->splice_timestamp() != | 943 DCHECK(new_buffers.front()->splice_timestamp() != |
| 949 new_buffers.front()->timestamp()); | 944 new_buffers.front()->timestamp()); |
| 950 const bool exclude_start = | 945 const bool exclude_start = new_buffers.front()->splice_buffers().empty() && |
| 951 new_buffers.front()->splice_buffers().empty() && | 946 prev_timestamp == next_timestamp; |
| 952 prev_timestamp == next_timestamp && | |
| 953 SourceBufferRange::AllowSameTimestamp(prev_is_keyframe, next_is_keyframe); | |
| 954 | 947 |
| 955 // Delete the buffers that |new_buffers| overlaps. | 948 // Delete the buffers that |new_buffers| overlaps. |
| 956 DecodeTimestamp start = new_buffers.front()->GetDecodeTimestamp(); | 949 DecodeTimestamp start = new_buffers.front()->GetDecodeTimestamp(); |
| 957 DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp(); | 950 DecodeTimestamp end = new_buffers.back()->GetDecodeTimestamp(); |
| 958 base::TimeDelta duration = new_buffers.back()->duration(); | 951 base::TimeDelta duration = new_buffers.back()->duration(); |
| 959 | 952 |
| 960 // Set end time for remove to include the duration of last buffer. If the | 953 // Set end time for remove to include the duration of last buffer. If the |
| 961 // duration is estimated, use 1 microsecond instead to ensure frames are not | 954 // duration is estimated, use 1 microsecond instead to ensure frames are not |
| 962 // accidentally removed due to over-estimation. | 955 // accidentally removed due to over-estimation. |
| 963 if (duration != kNoTimestamp() && duration > base::TimeDelta() && | 956 if (duration != kNoTimestamp() && duration > base::TimeDelta() && |
| (...skipping 818 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1782 return false; | 1775 return false; |
| 1783 | 1776 |
| 1784 DCHECK_NE(have_splice_buffers, have_preroll_buffer); | 1777 DCHECK_NE(have_splice_buffers, have_preroll_buffer); |
| 1785 splice_buffers_index_ = 0; | 1778 splice_buffers_index_ = 0; |
| 1786 pending_buffer_.swap(*out_buffer); | 1779 pending_buffer_.swap(*out_buffer); |
| 1787 pending_buffers_complete_ = false; | 1780 pending_buffers_complete_ = false; |
| 1788 return true; | 1781 return true; |
| 1789 } | 1782 } |
| 1790 | 1783 |
| 1791 } // namespace media | 1784 } // namespace media |
| OLD | NEW |