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

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

Issue 1091293005: MSE: Relax the 'media segment must begin with keyframe' requirement (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Checkpoint. Not ready for review yet. Created 5 years, 3 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
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 return SourceBufferRange::NO_GAPS_ALLOWED; 127 return SourceBufferRange::NO_GAPS_ALLOWED;
128 } 128 }
129 129
130 } // namespace 130 } // namespace
131 131
132 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config, 132 SourceBufferStream::SourceBufferStream(const AudioDecoderConfig& audio_config,
133 const scoped_refptr<MediaLog>& media_log, 133 const scoped_refptr<MediaLog>& media_log,
134 bool splice_frames_enabled) 134 bool splice_frames_enabled)
135 : media_log_(media_log), 135 : media_log_(media_log),
136 seek_buffer_timestamp_(kNoTimestamp()), 136 seek_buffer_timestamp_(kNoTimestamp()),
137 media_segment_start_time_(kNoDecodeTimestamp()), 137 coded_frame_group_start_time_(kNoDecodeTimestamp()),
138 range_for_next_append_(ranges_.end()), 138 range_for_next_append_(ranges_.end()),
139 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), 139 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
140 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 140 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
141 max_interbuffer_distance_(kNoTimestamp()), 141 max_interbuffer_distance_(kNoTimestamp()),
142 memory_limit_(kSourceBufferAudioMemoryLimit), 142 memory_limit_(kSourceBufferAudioMemoryLimit),
143 splice_frames_enabled_(splice_frames_enabled) { 143 splice_frames_enabled_(splice_frames_enabled) {
144 DCHECK(audio_config.IsValidConfig()); 144 DCHECK(audio_config.IsValidConfig());
145 audio_configs_.push_back(audio_config); 145 audio_configs_.push_back(audio_config);
146 } 146 }
147 147
148 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config, 148 SourceBufferStream::SourceBufferStream(const VideoDecoderConfig& video_config,
149 const scoped_refptr<MediaLog>& media_log, 149 const scoped_refptr<MediaLog>& media_log,
150 bool splice_frames_enabled) 150 bool splice_frames_enabled)
151 : media_log_(media_log), 151 : media_log_(media_log),
152 seek_buffer_timestamp_(kNoTimestamp()), 152 seek_buffer_timestamp_(kNoTimestamp()),
153 media_segment_start_time_(kNoDecodeTimestamp()), 153 coded_frame_group_start_time_(kNoDecodeTimestamp()),
154 range_for_next_append_(ranges_.end()), 154 range_for_next_append_(ranges_.end()),
155 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), 155 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
156 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 156 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
157 max_interbuffer_distance_(kNoTimestamp()), 157 max_interbuffer_distance_(kNoTimestamp()),
158 memory_limit_(kSourceBufferVideoMemoryLimit), 158 memory_limit_(kSourceBufferVideoMemoryLimit),
159 splice_frames_enabled_(splice_frames_enabled) { 159 splice_frames_enabled_(splice_frames_enabled) {
160 DCHECK(video_config.IsValidConfig()); 160 DCHECK(video_config.IsValidConfig());
161 video_configs_.push_back(video_config); 161 video_configs_.push_back(video_config);
162 } 162 }
163 163
164 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config, 164 SourceBufferStream::SourceBufferStream(const TextTrackConfig& text_config,
165 const scoped_refptr<MediaLog>& media_log, 165 const scoped_refptr<MediaLog>& media_log,
166 bool splice_frames_enabled) 166 bool splice_frames_enabled)
167 : media_log_(media_log), 167 : media_log_(media_log),
168 text_track_config_(text_config), 168 text_track_config_(text_config),
169 seek_buffer_timestamp_(kNoTimestamp()), 169 seek_buffer_timestamp_(kNoTimestamp()),
170 media_segment_start_time_(kNoDecodeTimestamp()), 170 coded_frame_group_start_time_(kNoDecodeTimestamp()),
171 range_for_next_append_(ranges_.end()), 171 range_for_next_append_(ranges_.end()),
172 last_appended_buffer_timestamp_(kNoDecodeTimestamp()), 172 last_appended_buffer_timestamp_(kNoDecodeTimestamp()),
173 last_output_buffer_timestamp_(kNoDecodeTimestamp()), 173 last_output_buffer_timestamp_(kNoDecodeTimestamp()),
174 max_interbuffer_distance_(kNoTimestamp()), 174 max_interbuffer_distance_(kNoTimestamp()),
175 memory_limit_(kSourceBufferAudioMemoryLimit), 175 memory_limit_(kSourceBufferAudioMemoryLimit),
176 splice_frames_enabled_(splice_frames_enabled) {} 176 splice_frames_enabled_(splice_frames_enabled) {}
177 177
178 SourceBufferStream::~SourceBufferStream() { 178 SourceBufferStream::~SourceBufferStream() {
179 while (!ranges_.empty()) { 179 while (!ranges_.empty()) {
180 delete ranges_.front(); 180 delete ranges_.front();
181 ranges_.pop_front(); 181 ranges_.pop_front();
182 } 182 }
183 } 183 }
184 184
185 void SourceBufferStream::OnNewMediaSegment( 185 void SourceBufferStream::OnStartOfCodedFrameGroup(
186 DecodeTimestamp media_segment_start_time) { 186 DecodeTimestamp coded_frame_group_start_time) {
187 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 187 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() << " ("
188 << " (" << media_segment_start_time.InSecondsF() << ")"; 188 << coded_frame_group_start_time.InSecondsF() << ")";
189 DCHECK(!end_of_stream_); 189 DCHECK(!end_of_stream_);
190 media_segment_start_time_ = media_segment_start_time; 190 coded_frame_group_start_time_ = coded_frame_group_start_time;
191 new_media_segment_ = true; 191 new_coded_frame_group_ = true;
192 192
193 RangeList::iterator last_range = range_for_next_append_; 193 RangeList::iterator last_range = range_for_next_append_;
194 range_for_next_append_ = FindExistingRangeFor(media_segment_start_time); 194 range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_time);
195 195
196 // Only reset |last_appended_buffer_timestamp_| if this new media segment is 196 // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
197 // not adjacent to the previous media segment appended to the stream. 197 // is not adjacent to the previous coded frame group appended to the stream.
198 // TODO(wolenetz): Change this to DCHECK or MEDIA_LOG if found to be adjacent,
199 // and otherwise trust the caller to signal correctly only when there is a
200 // discontinuity detected by coded frame processor?
198 if (range_for_next_append_ == ranges_.end() || 201 if (range_for_next_append_ == ranges_.end() ||
199 !AreAdjacentInSequence(last_appended_buffer_timestamp_, 202 !AreAdjacentInSequence(last_appended_buffer_timestamp_,
200 media_segment_start_time)) { 203 coded_frame_group_start_time)) {
201 last_appended_buffer_timestamp_ = kNoDecodeTimestamp(); 204 last_appended_buffer_timestamp_ = kNoDecodeTimestamp();
202 last_appended_buffer_is_keyframe_ = false; 205 last_appended_buffer_is_keyframe_ = false;
203 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range"; 206 DVLOG(3) << __FUNCTION__ << " next appended buffers will be in a new range";
204 } else if (last_range != ranges_.end()) { 207 } else if (last_range != ranges_.end()) {
205 DCHECK(last_range == range_for_next_append_); 208 DCHECK(last_range == range_for_next_append_);
206 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range " 209 DVLOG(3) << __FUNCTION__ << " next appended buffers will continue range "
207 << "unless intervening remove makes discontinuity"; 210 << "unless intervening remove makes discontinuity";
208 } 211 }
209 } 212 }
210 213
211 bool SourceBufferStream::Append(const BufferQueue& buffers) { 214 bool SourceBufferStream::Append(const BufferQueue& buffers) {
212 TRACE_EVENT2("media", "SourceBufferStream::Append", 215 TRACE_EVENT2("media", "SourceBufferStream::Append",
213 "stream type", GetStreamTypeName(), 216 "stream type", GetStreamTypeName(),
214 "buffers to append", buffers.size()); 217 "buffers to append", buffers.size());
215 218
216 DCHECK(!buffers.empty()); 219 DCHECK(!buffers.empty());
217 DCHECK(media_segment_start_time_ != kNoDecodeTimestamp()); 220 DCHECK(coded_frame_group_start_time_ != kNoDecodeTimestamp());
218 DCHECK(media_segment_start_time_ <= buffers.front()->GetDecodeTimestamp()); 221 DCHECK(coded_frame_group_start_time_ <=
222 buffers.front()->GetDecodeTimestamp());
219 DCHECK(!end_of_stream_); 223 DCHECK(!end_of_stream_);
220 224
221 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName() 225 DVLOG(1) << __FUNCTION__ << " " << GetStreamTypeName()
222 << ": buffers " << BufferQueueToLogString(buffers); 226 << ": buffers " << BufferQueueToLogString(buffers);
223 227
224 // New media segments must begin with a keyframe. 228 // New coded frame groups emitted by the coded frame processor must begin with
225 // TODO(wolenetz): Relax this requirement. See http://crbug.com/229412. 229 // a keyframe.
226 if (new_media_segment_ && !buffers.front()->is_key_frame()) { 230 // TODO(wolenetz): Change this to a DCHECK, if not a CHECK, once the frame
227 MEDIA_LOG(ERROR, media_log_) << "Media segment did not begin with key " 231 // processor becomes aware of discontinuities introduced by the range removal
228 "frame. Support for such segments will be " 232 // algorithm. See http://crbug.com/229412.
229 "available in a future version. Please see " 233 // BIG TODO: ensure this new log is exercised in unit test; adjust tests for
230 "https://crbug.com/229412."; 234 // lack of old log "Media segment did not begin with key frame..."
235 if (new_coded_frame_group_ && !buffers.front()->is_key_frame()) {
236 MEDIA_LOG(ERROR, media_log_)
237 << "Coded frame group did not begin with key frame.";
231 return false; 238 return false;
232 } 239 }
233 240
234 // Buffers within a media segment should be monotonically increasing. 241 // Buffers within a coded frame group should be monotonically increasing.
235 if (!IsMonotonicallyIncreasing(buffers)) 242 // TODO(wolenetz): Change this to a DCHECK in debug builds?
236 return false; 243 if (!IsMonotonicallyIncreasing(buffers)) {
237
238 if (media_segment_start_time_ < DecodeTimestamp() ||
239 buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) {
240 MEDIA_LOG(ERROR, media_log_)
241 << "Cannot append a media segment with negative timestamps.";
242 return false; 244 return false;
243 } 245 }
244 246
247 if (coded_frame_group_start_time_ < DecodeTimestamp() ||
248 buffers.front()->GetDecodeTimestamp() < DecodeTimestamp()) {
249 // BIG TODO: if necessary, adjust any existing test log expectation
250 MEDIA_LOG(ERROR, media_log_)
251 << "Cannot append a coded frame group with negative timestamps.";
252 return false;
253 }
254
245 if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(), 255 if (!IsNextTimestampValid(buffers.front()->GetDecodeTimestamp(),
246 buffers.front()->is_key_frame())) { 256 buffers.front()->is_key_frame())) {
247 const DecodeTimestamp& dts = buffers.front()->GetDecodeTimestamp(); 257 const DecodeTimestamp& dts = buffers.front()->GetDecodeTimestamp();
248 MEDIA_LOG(ERROR, media_log_) 258 MEDIA_LOG(ERROR, media_log_)
249 << "Invalid same timestamp construct detected at" 259 << "Invalid same timestamp construct detected at"
250 << " time " << dts.InSecondsF(); 260 << " time " << dts.InSecondsF();
251 261
252 return false; 262 return false;
253 } 263 }
254 264
255 UpdateMaxInterbufferDistance(buffers); 265 UpdateMaxInterbufferDistance(buffers);
256 SetConfigIds(buffers); 266 SetConfigIds(buffers);
257 267
258 // Save a snapshot of stream state before range modifications are made. 268 // Save a snapshot of stream state before range modifications are made.
259 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp(); 269 DecodeTimestamp next_buffer_timestamp = GetNextBufferTimestamp();
260 BufferQueue deleted_buffers; 270 BufferQueue deleted_buffers;
261 271
262 PrepareRangesForNextAppend(buffers, &deleted_buffers); 272 PrepareRangesForNextAppend(buffers, &deleted_buffers);
263 273
264 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise, 274 // If there's a range for |buffers|, insert |buffers| accordingly. Otherwise,
265 // create a new range with |buffers|. 275 // create a new range with |buffers|.
266 if (range_for_next_append_ != ranges_.end()) { 276 if (range_for_next_append_ != ranges_.end()) {
267 (*range_for_next_append_)->AppendBuffersToEnd(buffers); 277 (*range_for_next_append_)->AppendBuffersToEnd(buffers);
268 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp(); 278 last_appended_buffer_timestamp_ = buffers.back()->GetDecodeTimestamp();
269 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame(); 279 last_appended_buffer_is_keyframe_ = buffers.back()->is_key_frame();
270 } else { 280 } else {
271 DecodeTimestamp new_range_start_time = std::min( 281 DecodeTimestamp new_range_start_time = std::min(
272 media_segment_start_time_, buffers.front()->GetDecodeTimestamp()); 282 coded_frame_group_start_time_, buffers.front()->GetDecodeTimestamp());
273 const BufferQueue* buffers_for_new_range = &buffers; 283 const BufferQueue* buffers_for_new_range = &buffers;
274 BufferQueue trimmed_buffers; 284 BufferQueue trimmed_buffers;
275 285
276 // If the new range is not being created because of a new media 286 // If the new range is not being created because of a new coded frame group,
277 // segment, then we must make sure that we start with a key frame. 287 // then we must make sure that we start with a key frame. This can happen
278 // This can happen if the GOP in the previous append gets destroyed 288 // if the GOP in the previous append gets destroyed by a Remove() call.
279 // by a Remove() call. 289 // TODO(wolenetz): Change this to at least a DCHECK once the frame processor
280 if (!new_media_segment_) { 290 // becomes aware of discontinuities introduced by the range removal
291 // algorithm. See http://crbug.com/229412.
292 if (!new_coded_frame_group_) {
281 BufferQueue::const_iterator itr = buffers.begin(); 293 BufferQueue::const_iterator itr = buffers.begin();
282 294
283 // Scan past all the non-key-frames. 295 // Scan past all the non-key-frames.
284 while (itr != buffers.end() && !(*itr)->is_key_frame()) { 296 while (itr != buffers.end() && !(*itr)->is_key_frame()) {
285 ++itr; 297 ++itr;
286 } 298 }
287 299
288 // If we didn't find a key frame, then update the last appended 300 // If we didn't find a key frame, then update the last appended
289 // buffer state and return. 301 // buffer state and return.
290 if (itr == buffers.end()) { 302 if (itr == buffers.end()) {
(...skipping 22 matching lines...) Expand all
313 TypeToGapPolicy(GetType()), 325 TypeToGapPolicy(GetType()),
314 *buffers_for_new_range, new_range_start_time, 326 *buffers_for_new_range, new_range_start_time,
315 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance, 327 base::Bind(&SourceBufferStream::GetMaxInterbufferDistance,
316 base::Unretained(this)))); 328 base::Unretained(this))));
317 last_appended_buffer_timestamp_ = 329 last_appended_buffer_timestamp_ =
318 buffers_for_new_range->back()->GetDecodeTimestamp(); 330 buffers_for_new_range->back()->GetDecodeTimestamp();
319 last_appended_buffer_is_keyframe_ = 331 last_appended_buffer_is_keyframe_ =
320 buffers_for_new_range->back()->is_key_frame(); 332 buffers_for_new_range->back()->is_key_frame();
321 } 333 }
322 334
323 new_media_segment_ = false; 335 new_coded_frame_group_ = false;
324 336
325 MergeWithAdjacentRangeIfNecessary(range_for_next_append_); 337 MergeWithAdjacentRangeIfNecessary(range_for_next_append_);
326 338
327 // Seek to try to fulfill a previous call to Seek(). 339 // Seek to try to fulfill a previous call to Seek().
328 if (seek_pending_) { 340 if (seek_pending_) {
329 DCHECK(!selected_range_); 341 DCHECK(!selected_range_);
330 DCHECK(deleted_buffers.empty()); 342 DCHECK(deleted_buffers.empty());
331 Seek(seek_buffer_timestamp_); 343 Seek(seek_buffer_timestamp_);
332 } 344 }
333 345
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 565
554 prev_timestamp = current_timestamp; 566 prev_timestamp = current_timestamp;
555 prev_is_keyframe = current_is_keyframe; 567 prev_is_keyframe = current_is_keyframe;
556 } 568 }
557 return true; 569 return true;
558 } 570 }
559 571
560 bool SourceBufferStream::IsNextTimestampValid( 572 bool SourceBufferStream::IsNextTimestampValid(
561 DecodeTimestamp next_timestamp, bool next_is_keyframe) const { 573 DecodeTimestamp next_timestamp, bool next_is_keyframe) const {
562 return (last_appended_buffer_timestamp_ != next_timestamp) || 574 return (last_appended_buffer_timestamp_ != next_timestamp) ||
563 new_media_segment_ || 575 new_coded_frame_group_ ||
564 SourceBufferRange::AllowSameTimestamp(last_appended_buffer_is_keyframe_, 576 SourceBufferRange::AllowSameTimestamp(
565 next_is_keyframe); 577 last_appended_buffer_is_keyframe_, next_is_keyframe);
566 } 578 }
567 579
568 580
569 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const { 581 bool SourceBufferStream::OnlySelectedRangeIsSeeked() const {
570 for (RangeList::const_iterator itr = ranges_.begin(); 582 for (RangeList::const_iterator itr = ranges_.begin();
571 itr != ranges_.end(); ++itr) { 583 itr != ranges_.end(); ++itr) {
572 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_) 584 if ((*itr)->HasNextBufferPosition() && (*itr) != selected_range_)
573 return false; 585 return false;
574 } 586 }
575 return !selected_range_ || selected_range_->HasNextBufferPosition(); 587 return !selected_range_ || selected_range_->HasNextBufferPosition();
(...skipping 1155 matching lines...) Expand 10 before | Expand all | Expand 10 after
1731 return false; 1743 return false;
1732 1744
1733 DCHECK_NE(have_splice_buffers, have_preroll_buffer); 1745 DCHECK_NE(have_splice_buffers, have_preroll_buffer);
1734 splice_buffers_index_ = 0; 1746 splice_buffers_index_ = 0;
1735 pending_buffer_.swap(*out_buffer); 1747 pending_buffer_.swap(*out_buffer);
1736 pending_buffers_complete_ = false; 1748 pending_buffers_complete_ = false;
1737 return true; 1749 return true;
1738 } 1750 }
1739 1751
1740 } // namespace media 1752 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/source_buffer_stream.h ('k') | media/filters/source_buffer_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698