Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/source_buffer_stream.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 namespace { | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
We don't do anonymous namespaces in the media code
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 10 | |
| 11 // Comparison function for two Buffers based on timestamp. | |
| 12 static bool BufferComparitor(scoped_refptr<media::Buffer> first, | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Comparator
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 13 scoped_refptr<media::Buffer> second) { | |
| 14 return first->GetTimestamp() < second->GetTimestamp(); | |
| 15 } | |
| 16 | |
| 17 } // namespace | |
| 18 | |
| 19 namespace media { | |
| 20 | |
| 21 SourceBufferStream::SourceBufferStream() | |
| 22 : seek_pending_(false), | |
| 23 selected_range_(NULL) { | |
| 24 } | |
| 25 | |
| 26 SourceBufferStream::~SourceBufferStream() { | |
| 27 while (!ranges_.empty()) { | |
| 28 delete ranges_.front(); | |
| 29 ranges_.pop_front(); | |
| 30 } | |
| 31 } | |
| 32 | |
| 33 void SourceBufferStream::Append( | |
| 34 const SourceBufferStream::BufferQueue& buffers) { | |
| 35 base::TimeDelta start_timestamp = buffers.front()->GetTimestamp(); | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
DCHECK(!buffers.empty())?
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 36 base::TimeDelta end_timestamp = buffers.back()->GetTimestamp(); | |
| 37 | |
| 38 // Check to see if |buffers| will overlap the currently |selected_range_|, | |
| 39 // and if so, ignore this Append() request. | |
| 40 // TODO(vrk): Support end overlap properly. (crbug.com/125072) | |
| 41 if (selected_range_) { | |
| 42 Timespan selected_range_span = selected_range_->GetBufferedTime(); | |
| 43 if (selected_range_span.second > start_timestamp && | |
| 44 selected_range_span.first <= end_timestamp) { | |
| 45 return; | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Do we really want to silently drop this data? Perh
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Good idea. Bool added!
| |
| 46 } | |
| 47 } | |
| 48 | |
| 49 bool create_new_range = true; | |
| 50 RangeList::iterator itr = ranges_.begin(); | |
| 51 while (itr != ranges_.end()) { | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
nit: consider using for instead of while here
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 52 int range_value = (*itr)->BelongsToRange(start_timestamp); | |
| 53 if (range_value > 0) | |
| 54 break; | |
| 55 | |
| 56 if (range_value == 0) { | |
| 57 // Found an existing range into which we can append buffers. | |
| 58 create_new_range = false; | |
| 59 break; | |
| 60 } | |
| 61 itr++; | |
| 62 } | |
| 63 | |
| 64 RangeList::iterator current = itr; | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
I don't think current & next actually make things
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 65 if (create_new_range) | |
| 66 current = ranges_.insert(itr, new Range()); | |
| 67 Range* range = *current; | |
| 68 RangeList::iterator next = ++current; | |
| 69 | |
| 70 // Append buffers to the appropriate range. | |
| 71 range->Append(buffers); | |
| 72 | |
| 73 // Handle overlaps if they were created. | |
| 74 while (next != ranges_.end() && range->EndOverlaps(*next)) { | |
| 75 DCHECK(!(*next)->is_selected_range()); | |
| 76 delete *next; | |
| 77 next = ranges_.erase(next); | |
| 78 } | |
| 79 | |
| 80 // Merge with neighbor if necessary. | |
| 81 if (next != ranges_.end() && range->CanMerge(*next)) { | |
| 82 range->Merge(*next); | |
| 83 // Update |selected_range_| pointer if |range| has become selected after | |
| 84 // merges. | |
| 85 if (range->is_selected_range()) | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Do we really need is_selected_range()? Can't we ju
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Yeah I didn't like that either! Removed, thanks!
| |
| 86 selected_range_ = range; | |
| 87 | |
| 88 delete *next; | |
| 89 ranges_.erase(next); | |
| 90 } | |
| 91 | |
| 92 // Finally, try to complete pending seek if one exists. | |
| 93 if (seek_pending_) | |
| 94 Seek(seek_buffer_timestamp_); | |
| 95 | |
| 96 DCHECK(IsRangeListSorted()); | |
| 97 } | |
| 98 | |
| 99 void SourceBufferStream::Seek(base::TimeDelta timestamp) { | |
| 100 if (selected_range_) { | |
| 101 selected_range_->set_selected_range(false); | |
| 102 selected_range_ = NULL; | |
| 103 } | |
| 104 | |
| 105 seek_buffer_timestamp_ = timestamp; | |
| 106 seek_pending_ = true; | |
| 107 | |
| 108 RangeList::iterator itr = ranges_.begin(); | |
| 109 bool range_found = false; | |
| 110 while (itr != ranges_.end()) { | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
nit: use for here
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done, and cleaned up some surrounding logic.
| |
| 111 if ((*itr)->CanSeekTo(timestamp)) { | |
| 112 range_found = true; | |
| 113 break; | |
| 114 } | |
| 115 itr++; | |
| 116 } | |
| 117 | |
| 118 if (!range_found) | |
| 119 return; | |
| 120 | |
| 121 selected_range_ = *itr; | |
| 122 selected_range_->set_selected_range(true); | |
| 123 selected_range_->Seek(timestamp); | |
| 124 seek_pending_ = false; | |
| 125 } | |
| 126 | |
| 127 bool SourceBufferStream::GetNextBuffer(scoped_refptr<Buffer>* out_buffer) { | |
| 128 if (!selected_range_) | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
nit: Can combine with the return below.
selected_
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 129 return false; | |
| 130 return selected_range_->GetNextBuffer(out_buffer); | |
| 131 } | |
| 132 | |
| 133 std::list<SourceBufferStream::Timespan> | |
| 134 SourceBufferStream::GetBufferedTime() const { | |
| 135 std::list<Timespan> timespans; | |
| 136 for (RangeList::const_iterator itr = ranges_.begin(); | |
| 137 itr != ranges_.end(); itr++) { | |
| 138 timespans.push_back((*itr)->GetBufferedTime()); | |
| 139 } | |
| 140 return timespans; | |
| 141 } | |
| 142 | |
| 143 bool SourceBufferStream::IsRangeListSorted() const { | |
| 144 base::TimeDelta prev = kNoTimestamp(); | |
| 145 for (RangeList::const_iterator itr = ranges_.begin(); | |
| 146 itr != ranges_.end(); itr++) { | |
| 147 Timespan buffered = (*itr)->GetBufferedTime(); | |
| 148 if (prev != kNoTimestamp() && prev > buffered.first) | |
| 149 return false; | |
| 150 prev = buffered.second; | |
| 151 } | |
| 152 return true; | |
| 153 } | |
| 154 | |
| 155 SourceBufferStream::Range::Range() | |
| 156 : is_selected_range_(false), | |
| 157 next_buffer_index_(-1) { | |
| 158 } | |
| 159 | |
| 160 void SourceBufferStream::Range::Append(const BufferQueue& new_buffers) { | |
| 161 base::TimeDelta start_timestamp = new_buffers.front()->GetTimestamp(); | |
| 162 | |
| 163 if (!buffers_.empty() && start_timestamp < BufferedEnd()) { | |
| 164 // We are overwriting existing data, so find the starting point where | |
| 165 // things will get overwritten. | |
| 166 BufferQueue::iterator starting_point = | |
| 167 std::lower_bound(buffers_.begin(), buffers_.end(), | |
| 168 new_buffers.front(), | |
| 169 BufferComparitor); | |
| 170 | |
| 171 // Remove everything from |starting_point| onward. | |
| 172 buffers_.erase(starting_point, buffers_.end()); | |
| 173 } | |
| 174 | |
| 175 // Append data. | |
| 176 AppendToEnd(new_buffers); | |
| 177 } | |
| 178 | |
| 179 void SourceBufferStream::Range::AppendToEnd(const BufferQueue& new_buffers) { | |
| 180 for (BufferQueue::const_iterator itr = new_buffers.begin(); | |
| 181 itr != new_buffers.end(); itr++) { | |
| 182 buffers_.push_back(*itr); | |
| 183 if ((*itr)->IsKeyframe()) { | |
| 184 keyframe_map_.insert( | |
| 185 std::make_pair((*itr)->GetTimestamp(), buffers_.size() - 1)); | |
| 186 } | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 void SourceBufferStream::Range::Seek(base::TimeDelta timestamp) { | |
| 191 DCHECK(is_selected_range_); | |
| 192 DCHECK(CanSeekTo(timestamp)); | |
| 193 DCHECK(!keyframe_map_.empty()); | |
| 194 | |
| 195 KeyframeMap::iterator result = keyframe_map_.lower_bound(timestamp); | |
| 196 // lower_bound() returns the first element >= |timestamp|, so we want the | |
| 197 // previous element if it did not return the element exactly equal to | |
| 198 // |timestamp|. | |
| 199 if (result->first != timestamp) { | |
| 200 DCHECK(result != keyframe_map_.begin()); | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Shouldn't this be before the if? Putting it here a
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Talked offline!
BTW, I confirmed that if there's
| |
| 201 result--; | |
| 202 } | |
| 203 next_buffer_index_ = result->second; | |
| 204 DCHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size())); | |
| 205 } | |
| 206 | |
| 207 bool SourceBufferStream::Range::GetNextBuffer( | |
| 208 scoped_refptr<Buffer>* out_buffer) { | |
| 209 if (next_buffer_index_ >= static_cast<int>(buffers_.size())) | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
I think you need a next_buffer_index_ < 0 check he
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Yes, thanks! Done.
| |
| 210 return false; | |
| 211 | |
| 212 *out_buffer = buffers_.at(next_buffer_index_); | |
| 213 next_buffer_index_++; | |
| 214 return true; | |
| 215 } | |
| 216 | |
| 217 SourceBufferStream::Timespan | |
| 218 SourceBufferStream::Range::GetBufferedTime() const { | |
| 219 return std::make_pair<base::TimeDelta, base::TimeDelta>( | |
| 220 BufferedStart(), BufferedEnd()); | |
| 221 } | |
| 222 | |
| 223 void SourceBufferStream::Range::Merge(Range* range) { | |
| 224 DCHECK(CanMerge(range)); | |
| 225 | |
| 226 if (range->is_selected_range_) { | |
| 227 next_buffer_index_ = range->next_buffer_index_; | |
| 228 if (!buffers_.empty()) | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Is it possible for buffers_.empty() to be true? It
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
You're right, shouldn't be true. I'll DCHECK inste
| |
| 229 next_buffer_index_ += buffers_.size() - 1; | |
| 230 is_selected_range_ = true; | |
| 231 } | |
| 232 | |
| 233 AppendToEnd(range->buffers_); | |
| 234 range->Reset(); | |
| 235 } | |
| 236 | |
| 237 bool SourceBufferStream::Range::CanMerge(const Range* range) const { | |
| 238 return range->BufferedStart() >= BufferedEnd() && | |
| 239 range->BufferedStart() <= MaxNextTimestamp(); | |
| 240 } | |
| 241 | |
| 242 int SourceBufferStream::Range::BelongsToRange(base::TimeDelta timestamp) const { | |
| 243 if (buffers_.empty() || MaxNextTimestamp() < timestamp) | |
| 244 return -1; | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
This and the line below seems reversed from what t
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Oops, you're right! Originally I had done this bac
| |
| 245 else if (BufferedStart() > timestamp) | |
| 246 return 1; | |
| 247 else | |
| 248 return 0; | |
| 249 } | |
| 250 | |
| 251 bool SourceBufferStream::Range::CanSeekTo(base::TimeDelta timestamp) const { | |
| 252 if (buffers_.empty()) | |
| 253 return false; | |
| 254 | |
| 255 return buffers_.front()->GetTimestamp() <= timestamp && | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Use BufferedStart() & BufferedEnd() here & drop th
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 256 buffers_.back()->GetTimestamp() >= timestamp; | |
| 257 } | |
| 258 | |
| 259 bool SourceBufferStream::Range::EndOverlaps(const Range* range) const { | |
| 260 return range->BufferedStart() < BufferedEnd(); | |
| 261 } | |
| 262 | |
| 263 base::TimeDelta SourceBufferStream::Range::BufferedStart() const { | |
| 264 if (buffers_.empty()) | |
| 265 return kNoTimestamp(); | |
| 266 | |
| 267 return buffers_.front()->GetTimestamp(); | |
| 268 } | |
| 269 | |
| 270 base::TimeDelta SourceBufferStream::Range::BufferedEnd() const { | |
| 271 if (buffers_.empty()) | |
| 272 return kNoTimestamp(); | |
| 273 | |
| 274 return buffers_.back()->GetTimestamp() + buffers_.back()->GetDuration(); | |
| 275 } | |
| 276 | |
| 277 base::TimeDelta SourceBufferStream::Range::MaxNextTimestamp() const { | |
| 278 if (buffers_.empty()) | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
Should this be a DCHECK?
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 279 return kNoTimestamp(); | |
| 280 | |
| 281 return BufferedEnd() + buffers_.back()->GetDuration() / 3; | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
You might want to add a comment here. I realize th
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Tried to write a comment, let me know if it doesn'
| |
| 282 } | |
| 283 | |
| 284 void SourceBufferStream::Range::Reset() { | |
| 285 keyframe_map_.clear(); | |
| 286 buffers_.clear(); | |
| 287 is_selected_range_ = false; | |
|
acolwell GONE FROM CHROMIUM
2012/04/26 19:51:38
reset next_buffer_index_ too?
vrk (LEFT CHROMIUM)
2012/04/27 23:19:30
Done.
| |
| 288 } | |
| 289 | |
| 290 } // namespace media | |
| OLD | NEW |