Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: media/filters/source_buffer_stream.cc

Issue 10228017: Add initial implementation of SourceBufferStream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698