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/frame_processor.h" | 5 #include "media/filters/frame_processor.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <cstdlib> | 9 #include <cstdlib> |
10 | 10 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 // Adds |frame| to the end of |processed_frames_|. | 76 // Adds |frame| to the end of |processed_frames_|. |
77 void EnqueueProcessedFrame(const scoped_refptr<StreamParserBuffer>& frame); | 77 void EnqueueProcessedFrame(const scoped_refptr<StreamParserBuffer>& frame); |
78 | 78 |
79 // Appends |processed_frames_|, if not empty, to |stream_| and clears | 79 // Appends |processed_frames_|, if not empty, to |stream_| and clears |
80 // |processed_frames_|. Returns false if append failed, true otherwise. | 80 // |processed_frames_|. Returns false if append failed, true otherwise. |
81 // |processed_frames_| is cleared in both cases. | 81 // |processed_frames_| is cleared in both cases. |
82 bool FlushProcessedFrames(); | 82 bool FlushProcessedFrames(); |
83 | 83 |
84 private: | 84 private: |
85 // The decode timestamp of the last coded frame appended in the current coded | 85 // The decode timestamp of the last coded frame appended in the current coded |
86 // frame group. Initially kNoTimestamp(), meaning "unset". | 86 // frame group. Initially kNoTimestamp, meaning "unset". |
87 DecodeTimestamp last_decode_timestamp_; | 87 DecodeTimestamp last_decode_timestamp_; |
88 | 88 |
89 // The coded frame duration of the last coded frame appended in the current | 89 // The coded frame duration of the last coded frame appended in the current |
90 // coded frame group. Initially kNoTimestamp(), meaning "unset". | 90 // coded frame group. Initially kNoTimestamp, meaning "unset". |
91 base::TimeDelta last_frame_duration_; | 91 base::TimeDelta last_frame_duration_; |
92 | 92 |
93 // The highest presentation timestamp encountered in a coded frame appended | 93 // The highest presentation timestamp encountered in a coded frame appended |
94 // in the current coded frame group. Initially kNoTimestamp(), meaning | 94 // in the current coded frame group. Initially kNoTimestamp, meaning |
95 // "unset". | 95 // "unset". |
96 base::TimeDelta highest_presentation_timestamp_; | 96 base::TimeDelta highest_presentation_timestamp_; |
97 | 97 |
98 // Keeps track of whether the track buffer is waiting for a random access | 98 // Keeps track of whether the track buffer is waiting for a random access |
99 // point coded frame. Initially set to true to indicate that a random access | 99 // point coded frame. Initially set to true to indicate that a random access |
100 // point coded frame is needed before anything can be added to the track | 100 // point coded frame is needed before anything can be added to the track |
101 // buffer. | 101 // buffer. |
102 bool needs_random_access_point_; | 102 bool needs_random_access_point_; |
103 | 103 |
104 // Pointer to the stream associated with this track. The stream is not owned | 104 // Pointer to the stream associated with this track. The stream is not owned |
105 // by |this|. | 105 // by |this|. |
106 ChunkDemuxerStream* const stream_; | 106 ChunkDemuxerStream* const stream_; |
107 | 107 |
108 // Queue of processed frames that have not yet been appended to |stream_|. | 108 // Queue of processed frames that have not yet been appended to |stream_|. |
109 // EnqueueProcessedFrame() adds to this queue, and FlushProcessedFrames() | 109 // EnqueueProcessedFrame() adds to this queue, and FlushProcessedFrames() |
110 // clears it. | 110 // clears it. |
111 StreamParser::BufferQueue processed_frames_; | 111 StreamParser::BufferQueue processed_frames_; |
112 | 112 |
113 DISALLOW_COPY_AND_ASSIGN(MseTrackBuffer); | 113 DISALLOW_COPY_AND_ASSIGN(MseTrackBuffer); |
114 }; | 114 }; |
115 | 115 |
116 MseTrackBuffer::MseTrackBuffer(ChunkDemuxerStream* stream) | 116 MseTrackBuffer::MseTrackBuffer(ChunkDemuxerStream* stream) |
117 : last_decode_timestamp_(kNoDecodeTimestamp()), | 117 : last_decode_timestamp_(kNoDecodeTimestamp()), |
118 last_frame_duration_(kNoTimestamp()), | 118 last_frame_duration_(kNoTimestamp), |
119 highest_presentation_timestamp_(kNoTimestamp()), | 119 highest_presentation_timestamp_(kNoTimestamp), |
120 needs_random_access_point_(true), | 120 needs_random_access_point_(true), |
121 stream_(stream) { | 121 stream_(stream) { |
122 DCHECK(stream_); | 122 DCHECK(stream_); |
123 } | 123 } |
124 | 124 |
125 MseTrackBuffer::~MseTrackBuffer() { | 125 MseTrackBuffer::~MseTrackBuffer() { |
126 DVLOG(2) << __FUNCTION__ << "()"; | 126 DVLOG(2) << __FUNCTION__ << "()"; |
127 } | 127 } |
128 | 128 |
129 void MseTrackBuffer::Reset() { | 129 void MseTrackBuffer::Reset() { |
130 DVLOG(2) << __FUNCTION__ << "()"; | 130 DVLOG(2) << __FUNCTION__ << "()"; |
131 | 131 |
132 last_decode_timestamp_ = kNoDecodeTimestamp(); | 132 last_decode_timestamp_ = kNoDecodeTimestamp(); |
133 last_frame_duration_ = kNoTimestamp(); | 133 last_frame_duration_ = kNoTimestamp; |
134 highest_presentation_timestamp_ = kNoTimestamp(); | 134 highest_presentation_timestamp_ = kNoTimestamp; |
135 needs_random_access_point_ = true; | 135 needs_random_access_point_ = true; |
136 } | 136 } |
137 | 137 |
138 void MseTrackBuffer::SetHighestPresentationTimestampIfIncreased( | 138 void MseTrackBuffer::SetHighestPresentationTimestampIfIncreased( |
139 base::TimeDelta timestamp) { | 139 base::TimeDelta timestamp) { |
140 if (highest_presentation_timestamp_ == kNoTimestamp() || | 140 if (highest_presentation_timestamp_ == kNoTimestamp || |
141 timestamp > highest_presentation_timestamp_) { | 141 timestamp > highest_presentation_timestamp_) { |
142 highest_presentation_timestamp_ = timestamp; | 142 highest_presentation_timestamp_ = timestamp; |
143 } | 143 } |
144 } | 144 } |
145 | 145 |
146 void MseTrackBuffer::EnqueueProcessedFrame( | 146 void MseTrackBuffer::EnqueueProcessedFrame( |
147 const scoped_refptr<StreamParserBuffer>& frame) { | 147 const scoped_refptr<StreamParserBuffer>& frame) { |
148 processed_frames_.push_back(frame); | 148 processed_frames_.push_back(frame); |
149 } | 149 } |
150 | 150 |
151 bool MseTrackBuffer::FlushProcessedFrames() { | 151 bool MseTrackBuffer::FlushProcessedFrames() { |
152 if (processed_frames_.empty()) | 152 if (processed_frames_.empty()) |
153 return true; | 153 return true; |
154 | 154 |
155 bool result = stream_->Append(processed_frames_); | 155 bool result = stream_->Append(processed_frames_); |
156 processed_frames_.clear(); | 156 processed_frames_.clear(); |
157 | 157 |
158 DVLOG_IF(3, !result) << __FUNCTION__ | 158 DVLOG_IF(3, !result) << __FUNCTION__ |
159 << "(): Failure appending processed frames to stream"; | 159 << "(): Failure appending processed frames to stream"; |
160 | 160 |
161 return result; | 161 return result; |
162 } | 162 } |
163 | 163 |
164 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb, | 164 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb, |
165 const scoped_refptr<MediaLog>& media_log) | 165 const scoped_refptr<MediaLog>& media_log) |
166 : group_start_timestamp_(kNoTimestamp()), | 166 : group_start_timestamp_(kNoTimestamp), |
167 update_duration_cb_(update_duration_cb), | 167 update_duration_cb_(update_duration_cb), |
168 media_log_(media_log) { | 168 media_log_(media_log) { |
169 DVLOG(2) << __FUNCTION__ << "()"; | 169 DVLOG(2) << __FUNCTION__ << "()"; |
170 DCHECK(!update_duration_cb.is_null()); | 170 DCHECK(!update_duration_cb.is_null()); |
171 } | 171 } |
172 | 172 |
173 FrameProcessor::~FrameProcessor() { | 173 FrameProcessor::~FrameProcessor() { |
174 DVLOG(2) << __FUNCTION__ << "()"; | 174 DVLOG(2) << __FUNCTION__ << "()"; |
175 STLDeleteValues(&track_buffers_); | 175 STLDeleteValues(&track_buffers_); |
176 } | 176 } |
177 | 177 |
178 void FrameProcessor::SetSequenceMode(bool sequence_mode) { | 178 void FrameProcessor::SetSequenceMode(bool sequence_mode) { |
179 DVLOG(2) << __FUNCTION__ << "(" << sequence_mode << ")"; | 179 DVLOG(2) << __FUNCTION__ << "(" << sequence_mode << ")"; |
180 // Per June 9, 2016 MSE spec editor's draft: | 180 // Per June 9, 2016 MSE spec editor's draft: |
181 // https://rawgit.com/w3c/media-source/d8f901f22/ | 181 // https://rawgit.com/w3c/media-source/d8f901f22/ |
182 // index.html#widl-SourceBuffer-mode | 182 // index.html#widl-SourceBuffer-mode |
183 // Step 7: If the new mode equals "sequence", then set the group start | 183 // Step 7: If the new mode equals "sequence", then set the group start |
184 // timestamp to the group end timestamp. | 184 // timestamp to the group end timestamp. |
185 if (sequence_mode) { | 185 if (sequence_mode) { |
186 DCHECK(kNoTimestamp() != group_end_timestamp_); | 186 DCHECK(kNoTimestamp != group_end_timestamp_); |
187 group_start_timestamp_ = group_end_timestamp_; | 187 group_start_timestamp_ = group_end_timestamp_; |
188 } else if (sequence_mode_) { | 188 } else if (sequence_mode_) { |
189 // We're switching from 'sequence' to 'segments' mode. Be safe and signal a | 189 // We're switching from 'sequence' to 'segments' mode. Be safe and signal a |
190 // new coded frame group on the next frame emitted. | 190 // new coded frame group on the next frame emitted. |
191 coded_frame_group_last_dts_ = kNoDecodeTimestamp(); | 191 coded_frame_group_last_dts_ = kNoDecodeTimestamp(); |
192 } | 192 } |
193 | 193 |
194 // Step 8: Update the attribute to new mode. | 194 // Step 8: Update the attribute to new mode. |
195 sequence_mode_ = sequence_mode; | 195 sequence_mode_ = sequence_mode; |
196 } | 196 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 // the duration change algorithm with new duration set to the maximum of | 235 // the duration change algorithm with new duration set to the maximum of |
236 // the current duration and the group end timestamp. | 236 // the current duration and the group end timestamp. |
237 update_duration_cb_.Run(group_end_timestamp_); | 237 update_duration_cb_.Run(group_end_timestamp_); |
238 | 238 |
239 return true; | 239 return true; |
240 } | 240 } |
241 | 241 |
242 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( | 242 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( |
243 base::TimeDelta timestamp_offset) { | 243 base::TimeDelta timestamp_offset) { |
244 DVLOG(2) << __FUNCTION__ << "(" << timestamp_offset.InSecondsF() << ")"; | 244 DVLOG(2) << __FUNCTION__ << "(" << timestamp_offset.InSecondsF() << ")"; |
245 DCHECK(kNoTimestamp() != timestamp_offset); | 245 DCHECK(kNoTimestamp != timestamp_offset); |
246 if (sequence_mode_) | 246 if (sequence_mode_) |
247 group_start_timestamp_ = timestamp_offset; | 247 group_start_timestamp_ = timestamp_offset; |
248 | 248 |
249 // Changes to timestampOffset should invalidate the preroll buffer. | 249 // Changes to timestampOffset should invalidate the preroll buffer. |
250 audio_preroll_buffer_ = NULL; | 250 audio_preroll_buffer_ = NULL; |
251 } | 251 } |
252 | 252 |
253 bool FrameProcessor::AddTrack(StreamParser::TrackId id, | 253 bool FrameProcessor::AddTrack(StreamParser::TrackId id, |
254 ChunkDemuxerStream* stream) { | 254 ChunkDemuxerStream* stream) { |
255 DVLOG(2) << __FUNCTION__ << "(): id=" << id; | 255 DVLOG(2) << __FUNCTION__ << "(): id=" << id; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 // sequence mode. Reset it here only if in segments mode. In sequence mode, | 300 // sequence mode. Reset it here only if in segments mode. In sequence mode, |
301 // the current coded frame group may be continued across Reset() operations to | 301 // the current coded frame group may be continued across Reset() operations to |
302 // allow the stream to coaelesce what might otherwise be gaps in the buffered | 302 // allow the stream to coaelesce what might otherwise be gaps in the buffered |
303 // ranges. See also the declaration for |coded_frame_group_last_dts_|. | 303 // ranges. See also the declaration for |coded_frame_group_last_dts_|. |
304 if (!sequence_mode_) { | 304 if (!sequence_mode_) { |
305 coded_frame_group_last_dts_ = kNoDecodeTimestamp(); | 305 coded_frame_group_last_dts_ = kNoDecodeTimestamp(); |
306 return; | 306 return; |
307 } | 307 } |
308 | 308 |
309 // Sequence mode | 309 // Sequence mode |
310 DCHECK(kNoTimestamp() != group_end_timestamp_); | 310 DCHECK(kNoTimestamp != group_end_timestamp_); |
311 group_start_timestamp_ = group_end_timestamp_; | 311 group_start_timestamp_ = group_end_timestamp_; |
312 } | 312 } |
313 | 313 |
314 void FrameProcessor::OnPossibleAudioConfigUpdate( | 314 void FrameProcessor::OnPossibleAudioConfigUpdate( |
315 const AudioDecoderConfig& config) { | 315 const AudioDecoderConfig& config) { |
316 DCHECK(config.IsValidConfig()); | 316 DCHECK(config.IsValidConfig()); |
317 | 317 |
318 // Always clear the preroll buffer when a config update is received. | 318 // Always clear the preroll buffer when a config update is received. |
319 audio_preroll_buffer_ = NULL; | 319 audio_preroll_buffer_ = NULL; |
320 | 320 |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
485 | 485 |
486 DVLOG(3) << __FUNCTION__ << ": Processing frame " | 486 DVLOG(3) << __FUNCTION__ << ": Processing frame " |
487 << "Type=" << frame->type() | 487 << "Type=" << frame->type() |
488 << ", TrackID=" << frame->track_id() | 488 << ", TrackID=" << frame->track_id() |
489 << ", PTS=" << presentation_timestamp.InSecondsF() | 489 << ", PTS=" << presentation_timestamp.InSecondsF() |
490 << ", DTS=" << decode_timestamp.InSecondsF() | 490 << ", DTS=" << decode_timestamp.InSecondsF() |
491 << ", DUR=" << frame_duration.InSecondsF() | 491 << ", DUR=" << frame_duration.InSecondsF() |
492 << ", RAP=" << frame->is_key_frame(); | 492 << ", RAP=" << frame->is_key_frame(); |
493 | 493 |
494 // Sanity check the timestamps. | 494 // Sanity check the timestamps. |
495 if (presentation_timestamp == kNoTimestamp()) { | 495 if (presentation_timestamp == kNoTimestamp) { |
496 MEDIA_LOG(ERROR, media_log_) << "Unknown PTS for " << frame->GetTypeName() | 496 MEDIA_LOG(ERROR, media_log_) << "Unknown PTS for " << frame->GetTypeName() |
497 << " frame"; | 497 << " frame"; |
498 return false; | 498 return false; |
499 } | 499 } |
500 if (decode_timestamp == kNoDecodeTimestamp()) { | 500 if (decode_timestamp == kNoDecodeTimestamp()) { |
501 MEDIA_LOG(ERROR, media_log_) << "Unknown DTS for " << frame->GetTypeName() | 501 MEDIA_LOG(ERROR, media_log_) << "Unknown DTS for " << frame->GetTypeName() |
502 << " frame"; | 502 << " frame"; |
503 return false; | 503 return false; |
504 } | 504 } |
505 if (decode_timestamp.ToPresentationTime() > presentation_timestamp) { | 505 if (decode_timestamp.ToPresentationTime() > presentation_timestamp) { |
506 // TODO(wolenetz): Determine whether DTS>PTS should really be allowed. See | 506 // TODO(wolenetz): Determine whether DTS>PTS should really be allowed. See |
507 // http://crbug.com/354518. | 507 // http://crbug.com/354518. |
508 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_dts_beyond_pts_warnings_, | 508 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_dts_beyond_pts_warnings_, |
509 kMaxDtsBeyondPtsWarnings) | 509 kMaxDtsBeyondPtsWarnings) |
510 << "Parsed " << frame->GetTypeName() << " frame has DTS " | 510 << "Parsed " << frame->GetTypeName() << " frame has DTS " |
511 << decode_timestamp.InMicroseconds() | 511 << decode_timestamp.InMicroseconds() |
512 << "us, which is after the frame's PTS " | 512 << "us, which is after the frame's PTS " |
513 << presentation_timestamp.InMicroseconds() << "us"; | 513 << presentation_timestamp.InMicroseconds() << "us"; |
514 DVLOG(2) << __FUNCTION__ << ": WARNING: Frame DTS(" | 514 DVLOG(2) << __FUNCTION__ << ": WARNING: Frame DTS(" |
515 << decode_timestamp.InSecondsF() << ") > PTS(" | 515 << decode_timestamp.InSecondsF() << ") > PTS(" |
516 << presentation_timestamp.InSecondsF() | 516 << presentation_timestamp.InSecondsF() |
517 << "), frame type=" << frame->GetTypeName(); | 517 << "), frame type=" << frame->GetTypeName(); |
518 } | 518 } |
519 | 519 |
520 // All stream parsers must emit valid (non-negative) frame durations. | 520 // All stream parsers must emit valid (non-negative) frame durations. |
521 // Note that duration of 0 can occur for at least WebM alt-ref frames. | 521 // Note that duration of 0 can occur for at least WebM alt-ref frames. |
522 if (frame_duration == kNoTimestamp()) { | 522 if (frame_duration == kNoTimestamp) { |
523 MEDIA_LOG(ERROR, media_log_) | 523 MEDIA_LOG(ERROR, media_log_) |
524 << "Unknown duration for " << frame->GetTypeName() << " frame at PTS " | 524 << "Unknown duration for " << frame->GetTypeName() << " frame at PTS " |
525 << presentation_timestamp.InMicroseconds() << "us"; | 525 << presentation_timestamp.InMicroseconds() << "us"; |
526 return false; | 526 return false; |
527 } | 527 } |
528 if (frame_duration < base::TimeDelta()) { | 528 if (frame_duration < base::TimeDelta()) { |
529 MEDIA_LOG(ERROR, media_log_) | 529 MEDIA_LOG(ERROR, media_log_) |
530 << "Negative duration " << frame_duration.InMicroseconds() | 530 << "Negative duration " << frame_duration.InMicroseconds() |
531 << "us for " << frame->GetTypeName() << " frame at PTS " | 531 << "us for " << frame->GetTypeName() << " frame at PTS " |
532 << presentation_timestamp.InMicroseconds() << "us"; | 532 << presentation_timestamp.InMicroseconds() << "us"; |
533 return false; | 533 return false; |
534 } | 534 } |
535 | 535 |
536 // 3. If mode equals "sequence" and group start timestamp is set, then run | 536 // 3. If mode equals "sequence" and group start timestamp is set, then run |
537 // the following steps: | 537 // the following steps: |
538 if (sequence_mode_ && group_start_timestamp_ != kNoTimestamp()) { | 538 if (sequence_mode_ && group_start_timestamp_ != kNoTimestamp) { |
539 // 3.1. Set timestampOffset equal to group start timestamp - | 539 // 3.1. Set timestampOffset equal to group start timestamp - |
540 // presentation timestamp. | 540 // presentation timestamp. |
541 *timestamp_offset = group_start_timestamp_ - presentation_timestamp; | 541 *timestamp_offset = group_start_timestamp_ - presentation_timestamp; |
542 | 542 |
543 DVLOG(3) << __FUNCTION__ << ": updated timestampOffset is now " | 543 DVLOG(3) << __FUNCTION__ << ": updated timestampOffset is now " |
544 << timestamp_offset->InSecondsF(); | 544 << timestamp_offset->InSecondsF(); |
545 | 545 |
546 // 3.2. Set group end timestamp equal to group start timestamp. | 546 // 3.2. Set group end timestamp equal to group start timestamp. |
547 group_end_timestamp_ = group_start_timestamp_; | 547 group_end_timestamp_ = group_start_timestamp_; |
548 | 548 |
549 // 3.3. Set the need random access point flag on all track buffers to | 549 // 3.3. Set the need random access point flag on all track buffers to |
550 // true. | 550 // true. |
551 SetAllTrackBuffersNeedRandomAccessPoint(); | 551 SetAllTrackBuffersNeedRandomAccessPoint(); |
552 | 552 |
553 // 3.4. Unset group start timestamp. | 553 // 3.4. Unset group start timestamp. |
554 group_start_timestamp_ = kNoTimestamp(); | 554 group_start_timestamp_ = kNoTimestamp; |
555 } | 555 } |
556 | 556 |
557 // 4. If timestampOffset is not 0, then run the following steps: | 557 // 4. If timestampOffset is not 0, then run the following steps: |
558 if (!timestamp_offset->is_zero()) { | 558 if (!timestamp_offset->is_zero()) { |
559 // 4.1. Add timestampOffset to the presentation timestamp. | 559 // 4.1. Add timestampOffset to the presentation timestamp. |
560 // Note: |frame| PTS is only updated if it survives discontinuity | 560 // Note: |frame| PTS is only updated if it survives discontinuity |
561 // processing. | 561 // processing. |
562 presentation_timestamp += *timestamp_offset; | 562 presentation_timestamp += *timestamp_offset; |
563 | 563 |
564 // 4.2. Add timestampOffset to the decode timestamp. | 564 // 4.2. Add timestampOffset to the decode timestamp. |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 // Step 21 is currently handled differently. See MediaSourceState's | 760 // Step 21 is currently handled differently. See MediaSourceState's |
761 // |auto_update_timestamp_offset_|. | 761 // |auto_update_timestamp_offset_|. |
762 return true; | 762 return true; |
763 } | 763 } |
764 | 764 |
765 NOTREACHED(); | 765 NOTREACHED(); |
766 return false; | 766 return false; |
767 } | 767 } |
768 | 768 |
769 } // namespace media | 769 } // namespace media |
OLD | NEW |