Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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_range.h" | 5 #include "media/filters/source_buffer_range.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "media/base/timestamp_constants.h" | 9 #include "media/base/timestamp_constants.h" |
| 10 | 10 |
| 11 namespace media { | 11 namespace media { |
| 12 | 12 |
| 13 // Comparison operators for std::upper_bound() and std::lower_bound(). | 13 // Comparison operators for std::upper_bound() and std::lower_bound(). |
| 14 static bool CompareTimeDeltaToStreamParserBuffer( | 14 static bool CompareTimeDeltaToStreamParserBuffer( |
| 15 const DecodeTimestamp& decode_timestamp, | 15 const DecodeTimestamp& decode_timestamp, |
| 16 const scoped_refptr<StreamParserBuffer>& buffer) { | 16 const scoped_refptr<StreamParserBuffer>& buffer) { |
| 17 return decode_timestamp < buffer->GetDecodeTimestamp(); | 17 return decode_timestamp < buffer->GetDecodeTimestamp(); |
| 18 } | 18 } |
| 19 static bool CompareStreamParserBufferToTimeDelta( | 19 static bool CompareStreamParserBufferToTimeDelta( |
| 20 const scoped_refptr<StreamParserBuffer>& buffer, | 20 const scoped_refptr<StreamParserBuffer>& buffer, |
| 21 const DecodeTimestamp& decode_timestamp) { | 21 const DecodeTimestamp& decode_timestamp) { |
| 22 return buffer->GetDecodeTimestamp() < decode_timestamp; | 22 return buffer->GetDecodeTimestamp() < decode_timestamp; |
| 23 } | 23 } |
| 24 | 24 |
| 25 bool SourceBufferRange::AllowSameTimestamp( | 25 bool SourceBufferRange::IsUncommonSameTimestampSequence( |
| 26 bool prev_is_keyframe, bool current_is_keyframe) { | 26 bool prev_is_keyframe, |
| 27 return prev_is_keyframe || !current_is_keyframe; | 27 bool current_is_keyframe) { |
| 28 return current_is_keyframe && !prev_is_keyframe; | |
| 28 } | 29 } |
| 29 | 30 |
| 30 SourceBufferRange::SourceBufferRange( | 31 SourceBufferRange::SourceBufferRange( |
| 31 GapPolicy gap_policy, const BufferQueue& new_buffers, | 32 GapPolicy gap_policy, const BufferQueue& new_buffers, |
| 32 DecodeTimestamp media_segment_start_time, | 33 DecodeTimestamp media_segment_start_time, |
| 33 const InterbufferDistanceCB& interbuffer_distance_cb) | 34 const InterbufferDistanceCB& interbuffer_distance_cb) |
| 34 : gap_policy_(gap_policy), | 35 : gap_policy_(gap_policy), |
| 35 keyframe_map_index_base_(0), | 36 keyframe_map_index_base_(0), |
| 36 next_buffer_index_(-1), | 37 next_buffer_index_(-1), |
| 37 media_segment_start_time_(media_segment_start_time), | 38 media_segment_start_time_(media_segment_start_time), |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 91 } | 92 } |
| 92 } | 93 } |
| 93 } | 94 } |
| 94 | 95 |
| 95 void SourceBufferRange::Seek(DecodeTimestamp timestamp) { | 96 void SourceBufferRange::Seek(DecodeTimestamp timestamp) { |
| 96 DCHECK(CanSeekTo(timestamp)); | 97 DCHECK(CanSeekTo(timestamp)); |
| 97 DCHECK(!keyframe_map_.empty()); | 98 DCHECK(!keyframe_map_.empty()); |
| 98 | 99 |
| 99 KeyframeMap::iterator result = GetFirstKeyframeAtOrBefore(timestamp); | 100 KeyframeMap::iterator result = GetFirstKeyframeAtOrBefore(timestamp); |
| 100 next_buffer_index_ = result->second - keyframe_map_index_base_; | 101 next_buffer_index_ = result->second - keyframe_map_index_base_; |
| 101 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); | 102 CHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())) |
| 103 << next_buffer_index_ << ", size = " << buffers_.size(); | |
| 102 } | 104 } |
| 103 | 105 |
| 104 void SourceBufferRange::SeekAheadTo(DecodeTimestamp timestamp) { | 106 void SourceBufferRange::SeekAheadTo(DecodeTimestamp timestamp) { |
| 105 SeekAhead(timestamp, false); | 107 SeekAhead(timestamp, false); |
| 106 } | 108 } |
| 107 | 109 |
| 108 void SourceBufferRange::SeekAheadPast(DecodeTimestamp timestamp) { | 110 void SourceBufferRange::SeekAheadPast(DecodeTimestamp timestamp) { |
| 109 SeekAhead(timestamp, true); | 111 SeekAhead(timestamp, true); |
| 110 } | 112 } |
| 111 | 113 |
| 112 void SourceBufferRange::SeekAhead(DecodeTimestamp timestamp, | 114 void SourceBufferRange::SeekAhead(DecodeTimestamp timestamp, |
| 113 bool skip_given_timestamp) { | 115 bool skip_given_timestamp) { |
| 114 DCHECK(!keyframe_map_.empty()); | 116 DCHECK(!keyframe_map_.empty()); |
| 115 | 117 |
| 116 KeyframeMap::iterator result = | 118 KeyframeMap::iterator result = |
| 117 GetFirstKeyframeAt(timestamp, skip_given_timestamp); | 119 GetFirstKeyframeAt(timestamp, skip_given_timestamp); |
| 118 | 120 |
| 119 // If there isn't a keyframe after |timestamp|, then seek to end and return | 121 // If there isn't a keyframe after |timestamp|, then seek to end and return |
| 120 // kNoTimestamp to signal such. | 122 // kNoTimestamp to signal such. |
| 121 if (result == keyframe_map_.end()) { | 123 if (result == keyframe_map_.end()) { |
| 122 next_buffer_index_ = -1; | 124 next_buffer_index_ = -1; |
| 123 return; | 125 return; |
| 124 } | 126 } |
| 125 next_buffer_index_ = result->second - keyframe_map_index_base_; | 127 next_buffer_index_ = result->second - keyframe_map_index_base_; |
| 126 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); | 128 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); |
| 127 } | 129 } |
| 128 | 130 |
| 129 void SourceBufferRange::SeekToStart() { | 131 void SourceBufferRange::SeekToStart() { |
| 130 DCHECK(!buffers_.empty()); | 132 CHECK(!buffers_.empty()); |
| 131 next_buffer_index_ = 0; | 133 next_buffer_index_ = 0; |
| 132 } | 134 } |
| 133 | 135 |
| 134 SourceBufferRange* SourceBufferRange::SplitRange(DecodeTimestamp timestamp) { | 136 SourceBufferRange* SourceBufferRange::SplitRange(DecodeTimestamp timestamp) { |
| 135 CHECK(!buffers_.empty()); | 137 CHECK(!buffers_.empty()); |
| 136 | 138 |
| 137 // Find the first keyframe at or after |timestamp|. | 139 // Find the first keyframe at or after |timestamp|. |
| 138 KeyframeMap::iterator new_beginning_keyframe = | 140 KeyframeMap::iterator new_beginning_keyframe = |
| 139 GetFirstKeyframeAt(timestamp, false); | 141 GetFirstKeyframeAt(timestamp, false); |
| 140 | 142 |
| 141 // If there is no keyframe after |timestamp|, we can't split the range. | 143 // If there is no keyframe after |timestamp|, we can't split the range. |
| 142 if (new_beginning_keyframe == keyframe_map_.end()) | 144 if (new_beginning_keyframe == keyframe_map_.end()) |
| 143 return NULL; | 145 return NULL; |
| 144 | 146 |
| 145 // Remove the data beginning at |keyframe_index| from |buffers_| and save it | 147 // Remove the data beginning at |keyframe_index| from |buffers_| and save it |
| 146 // into |removed_buffers|. | 148 // into |removed_buffers|. |
| 147 int keyframe_index = | 149 int keyframe_index = |
| 148 new_beginning_keyframe->second - keyframe_map_index_base_; | 150 new_beginning_keyframe->second - keyframe_map_index_base_; |
| 149 DCHECK_LT(keyframe_index, static_cast<int>(buffers_.size())); | 151 DCHECK_LT(keyframe_index, static_cast<int>(buffers_.size())); |
| 150 BufferQueue::iterator starting_point = buffers_.begin() + keyframe_index; | 152 BufferQueue::iterator starting_point = buffers_.begin() + keyframe_index; |
| 151 BufferQueue removed_buffers(starting_point, buffers_.end()); | 153 BufferQueue removed_buffers(starting_point, buffers_.end()); |
| 152 | 154 |
| 153 DecodeTimestamp new_range_start_timestamp = kNoDecodeTimestamp(); | 155 DecodeTimestamp new_range_start_timestamp = kNoDecodeTimestamp(); |
| 154 if (GetStartTimestamp() < buffers_.front()->GetDecodeTimestamp() && | 156 if (GetStartTimestamp() < buffers_.front()->GetDecodeTimestamp() && |
| 155 timestamp < removed_buffers.front()->GetDecodeTimestamp()) { | 157 timestamp < removed_buffers.front()->GetDecodeTimestamp()) { |
| 156 // The split is in the gap between |media_segment_start_time_| and | 158 // The split is in the gap between |media_segment_start_time_| and |
| 157 // the first buffer of the new range so we should set the start | 159 // the first buffer of the new range so we should set the start |
| 158 // time of the new range to |timestamp| so we preserve part of the | 160 // time of the new range to |timestamp| so we preserve part of the |
| 159 // gap in the new range. | 161 // gap in the new range. |
| 160 new_range_start_timestamp = timestamp; | 162 new_range_start_timestamp = timestamp; |
|
chcunningham
2016/02/12 22:46:40
I might be missing something here, but this sounds
wolenetz
2016/02/24 00:34:46
Hmm. This doesn't appear to be broken, though is a
chcunningham
2016/02/24 19:06:26
Acknowledged.
| |
| 161 } | 163 } |
| 162 | 164 |
| 163 keyframe_map_.erase(new_beginning_keyframe, keyframe_map_.end()); | 165 keyframe_map_.erase(new_beginning_keyframe, keyframe_map_.end()); |
| 164 FreeBufferRange(starting_point, buffers_.end()); | 166 FreeBufferRange(starting_point, buffers_.end()); |
| 165 | 167 |
| 166 // Create a new range with |removed_buffers|. | 168 // Create a new range with |removed_buffers|. |
| 167 SourceBufferRange* split_range = | 169 SourceBufferRange* split_range = |
| 168 new SourceBufferRange( | 170 new SourceBufferRange( |
| 169 gap_policy_, removed_buffers, new_range_start_timestamp, | 171 gap_policy_, removed_buffers, new_range_start_timestamp, |
| 170 interbuffer_distance_cb_); | 172 interbuffer_distance_cb_); |
| 171 | 173 |
| 172 // If the next buffer position is now in |split_range|, update the state of | 174 // If the next buffer position is now in |split_range|, update the state of |
| 173 // this range and |split_range| accordingly. | 175 // this range and |split_range| accordingly. |
| 174 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { | 176 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { |
| 175 split_range->next_buffer_index_ = next_buffer_index_ - keyframe_index; | 177 split_range->next_buffer_index_ = next_buffer_index_ - keyframe_index; |
| 178 CHECK_GE(split_range->next_buffer_index_, 0) | |
|
chcunningham
2016/02/12 22:46:40
You might also add a check for next_buffer_index <
wolenetz
2016/02/24 00:34:46
Done.... BUT: the new CHECK_LT triggered a crash i
chcunningham
2016/02/24 19:06:26
Acknowledged. Will be interesting to see whats goi
chcunningham
2016/02/24 19:12:54
We chatted. For posterity: You made needed to make
| |
| 179 << split_range->next_buffer_index_; | |
| 176 ResetNextBufferPosition(); | 180 ResetNextBufferPosition(); |
| 177 } | 181 } |
| 178 | 182 |
| 179 return split_range; | 183 return split_range; |
| 180 } | 184 } |
| 181 | 185 |
| 182 SourceBufferRange::BufferQueue::iterator SourceBufferRange::GetBufferItrAt( | 186 SourceBufferRange::BufferQueue::iterator SourceBufferRange::GetBufferItrAt( |
| 183 DecodeTimestamp timestamp, | 187 DecodeTimestamp timestamp, |
| 184 bool skip_given_timestamp) { | 188 bool skip_given_timestamp) { |
| 185 return skip_given_timestamp | 189 return skip_given_timestamp |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 256 deleted_buffers->push_back(buffers_.front()); | 260 deleted_buffers->push_back(buffers_.front()); |
| 257 buffers_.pop_front(); | 261 buffers_.pop_front(); |
| 258 ++buffers_deleted; | 262 ++buffers_deleted; |
| 259 } | 263 } |
| 260 | 264 |
| 261 // Update |keyframe_map_index_base_| to account for the deleted buffers. | 265 // Update |keyframe_map_index_base_| to account for the deleted buffers. |
| 262 keyframe_map_index_base_ += buffers_deleted; | 266 keyframe_map_index_base_ += buffers_deleted; |
| 263 | 267 |
| 264 if (next_buffer_index_ > -1) { | 268 if (next_buffer_index_ > -1) { |
| 265 next_buffer_index_ -= buffers_deleted; | 269 next_buffer_index_ -= buffers_deleted; |
| 266 DCHECK_GE(next_buffer_index_, 0); | 270 CHECK_GE(next_buffer_index_, 0) << next_buffer_index_ << ", deleted " |
| 271 << buffers_deleted; | |
| 267 } | 272 } |
| 268 | 273 |
| 269 // Invalidate media segment start time if we've deleted the first buffer of | 274 // Invalidate media segment start time if we've deleted the first buffer of |
| 270 // the range. | 275 // the range. |
| 271 if (buffers_deleted > 0) | 276 if (buffers_deleted > 0) |
| 272 media_segment_start_time_ = kNoDecodeTimestamp(); | 277 media_segment_start_time_ = kNoDecodeTimestamp(); |
| 273 | 278 |
| 274 return total_bytes_deleted; | 279 return total_bytes_deleted; |
| 275 } | 280 } |
| 276 | 281 |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 436 next_buffer_index_++; | 441 next_buffer_index_++; |
| 437 return true; | 442 return true; |
| 438 } | 443 } |
| 439 | 444 |
| 440 bool SourceBufferRange::HasNextBuffer() const { | 445 bool SourceBufferRange::HasNextBuffer() const { |
| 441 return next_buffer_index_ >= 0 && | 446 return next_buffer_index_ >= 0 && |
| 442 next_buffer_index_ < static_cast<int>(buffers_.size()); | 447 next_buffer_index_ < static_cast<int>(buffers_.size()); |
| 443 } | 448 } |
| 444 | 449 |
| 445 int SourceBufferRange::GetNextConfigId() const { | 450 int SourceBufferRange::GetNextConfigId() const { |
| 446 DCHECK(HasNextBuffer()); | 451 CHECK(HasNextBuffer()) << next_buffer_index_; |
| 447 // If the next buffer is an audio splice frame, the next effective config id | 452 // If the next buffer is an audio splice frame, the next effective config id |
| 448 // comes from the first fade out preroll buffer. | 453 // comes from the first fade out preroll buffer. |
| 449 return buffers_[next_buffer_index_]->GetSpliceBufferConfigId(0); | 454 return buffers_[next_buffer_index_]->GetSpliceBufferConfigId(0); |
| 450 } | 455 } |
| 451 | 456 |
| 452 DecodeTimestamp SourceBufferRange::GetNextTimestamp() const { | 457 DecodeTimestamp SourceBufferRange::GetNextTimestamp() const { |
| 453 DCHECK(!buffers_.empty()); | 458 CHECK(!buffers_.empty()) << next_buffer_index_; |
| 454 DCHECK(HasNextBufferPosition()); | 459 CHECK(HasNextBufferPosition()) << next_buffer_index_ |
| 460 << ", size=" << buffers_.size(); | |
| 455 | 461 |
| 456 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { | 462 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) { |
| 457 return kNoDecodeTimestamp(); | 463 return kNoDecodeTimestamp(); |
| 458 } | 464 } |
| 459 | 465 |
| 460 return buffers_[next_buffer_index_]->GetDecodeTimestamp(); | 466 return buffers_[next_buffer_index_]->GetDecodeTimestamp(); |
| 461 } | 467 } |
| 462 | 468 |
| 463 bool SourceBufferRange::HasNextBufferPosition() const { | 469 bool SourceBufferRange::HasNextBufferPosition() const { |
| 464 return next_buffer_index_ >= 0; | 470 return next_buffer_index_ >= 0; |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 480 } | 486 } |
| 481 | 487 |
| 482 bool SourceBufferRange::CanAppendRangeToEnd( | 488 bool SourceBufferRange::CanAppendRangeToEnd( |
| 483 const SourceBufferRange& range) const { | 489 const SourceBufferRange& range) const { |
| 484 return CanAppendBuffersToEnd(range.buffers_); | 490 return CanAppendBuffersToEnd(range.buffers_); |
| 485 } | 491 } |
| 486 | 492 |
| 487 bool SourceBufferRange::CanAppendBuffersToEnd( | 493 bool SourceBufferRange::CanAppendBuffersToEnd( |
| 488 const BufferQueue& buffers) const { | 494 const BufferQueue& buffers) const { |
| 489 DCHECK(!buffers_.empty()); | 495 DCHECK(!buffers_.empty()); |
| 490 return IsNextInSequence(buffers.front()->GetDecodeTimestamp(), | 496 return IsNextInSequence(buffers.front()->GetDecodeTimestamp()); |
| 491 buffers.front()->is_key_frame()); | |
| 492 } | 497 } |
| 493 | 498 |
| 494 bool SourceBufferRange::BelongsToRange(DecodeTimestamp timestamp) const { | 499 bool SourceBufferRange::BelongsToRange(DecodeTimestamp timestamp) const { |
| 495 DCHECK(!buffers_.empty()); | 500 DCHECK(!buffers_.empty()); |
| 496 | 501 |
| 497 return (IsNextInSequence(timestamp, false) || | 502 return (IsNextInSequence(timestamp) || |
| 498 (GetStartTimestamp() <= timestamp && timestamp <= GetEndTimestamp())); | 503 (GetStartTimestamp() <= timestamp && timestamp <= GetEndTimestamp())); |
| 499 } | 504 } |
| 500 | 505 |
| 501 bool SourceBufferRange::CanSeekTo(DecodeTimestamp timestamp) const { | 506 bool SourceBufferRange::CanSeekTo(DecodeTimestamp timestamp) const { |
| 502 DecodeTimestamp start_timestamp = | 507 DecodeTimestamp start_timestamp = |
| 503 std::max(DecodeTimestamp(), GetStartTimestamp() - GetFudgeRoom()); | 508 std::max(DecodeTimestamp(), GetStartTimestamp() - GetFudgeRoom()); |
| 504 return !keyframe_map_.empty() && start_timestamp <= timestamp && | 509 return !keyframe_map_.empty() && start_timestamp <= timestamp && |
| 505 timestamp < GetBufferedEndTimestamp(); | 510 timestamp < GetBufferedEndTimestamp(); |
| 506 } | 511 } |
| 507 | 512 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 563 DecodeTimestamp SourceBufferRange::KeyframeBeforeTimestamp( | 568 DecodeTimestamp SourceBufferRange::KeyframeBeforeTimestamp( |
| 564 DecodeTimestamp timestamp) { | 569 DecodeTimestamp timestamp) { |
| 565 DCHECK(!keyframe_map_.empty()); | 570 DCHECK(!keyframe_map_.empty()); |
| 566 | 571 |
| 567 if (timestamp < GetStartTimestamp() || timestamp >= GetBufferedEndTimestamp()) | 572 if (timestamp < GetStartTimestamp() || timestamp >= GetBufferedEndTimestamp()) |
| 568 return kNoDecodeTimestamp(); | 573 return kNoDecodeTimestamp(); |
| 569 | 574 |
| 570 return GetFirstKeyframeAtOrBefore(timestamp)->first; | 575 return GetFirstKeyframeAtOrBefore(timestamp)->first; |
| 571 } | 576 } |
| 572 | 577 |
| 573 bool SourceBufferRange::IsNextInSequence( | 578 bool SourceBufferRange::IsNextInSequence(DecodeTimestamp timestamp) const { |
| 574 DecodeTimestamp timestamp, bool is_key_frame) const { | |
| 575 DecodeTimestamp end = buffers_.back()->GetDecodeTimestamp(); | 579 DecodeTimestamp end = buffers_.back()->GetDecodeTimestamp(); |
| 576 if (end < timestamp && | 580 return (end == timestamp || |
| 577 (gap_policy_ == ALLOW_GAPS || | 581 (end < timestamp && |
| 578 timestamp <= end + GetFudgeRoom())) { | 582 (gap_policy_ == ALLOW_GAPS || timestamp <= end + GetFudgeRoom()))); |
| 579 return true; | |
| 580 } | |
| 581 | |
| 582 return timestamp == end && AllowSameTimestamp( | |
| 583 buffers_.back()->is_key_frame(), is_key_frame); | |
| 584 } | 583 } |
| 585 | 584 |
| 586 base::TimeDelta SourceBufferRange::GetFudgeRoom() const { | 585 base::TimeDelta SourceBufferRange::GetFudgeRoom() const { |
| 587 // Because we do not know exactly when is the next timestamp, any buffer | 586 // Because we do not know exactly when is the next timestamp, any buffer |
| 588 // that starts within 2x the approximate duration of a buffer is considered | 587 // that starts within 2x the approximate duration of a buffer is considered |
| 589 // within this range. | 588 // within this range. |
| 590 return 2 * GetApproximateDuration(); | 589 return 2 * GetApproximateDuration(); |
| 591 } | 590 } |
| 592 | 591 |
| 593 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { | 592 base::TimeDelta SourceBufferRange::GetApproximateDuration() const { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 621 } | 620 } |
| 622 | 621 |
| 623 if (buffer->timestamp() + buffer->duration() <= start.ToPresentationTime()) | 622 if (buffer->timestamp() + buffer->duration() <= start.ToPresentationTime()) |
| 624 continue; | 623 continue; |
| 625 buffers->push_back(buffer); | 624 buffers->push_back(buffer); |
| 626 } | 625 } |
| 627 return previous_size < buffers->size(); | 626 return previous_size < buffers->size(); |
| 628 } | 627 } |
| 629 | 628 |
| 630 } // namespace media | 629 } // namespace media |
| OLD | NEW |