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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |