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 <cstdlib> | 7 #include <cstdlib> |
8 | 8 |
9 #include "base/stl_util.h" | 9 #include "base/stl_util.h" |
10 #include "media/base/buffers.h" | 10 #include "media/base/buffers.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
60 void Reset(); | 60 void Reset(); |
61 | 61 |
62 // If |highest_presentation_timestamp_| is unset or |timestamp| is greater | 62 // If |highest_presentation_timestamp_| is unset or |timestamp| is greater |
63 // than |highest_presentation_timestamp_|, sets | 63 // than |highest_presentation_timestamp_|, sets |
64 // |highest_presentation_timestamp_| to |timestamp|. Note that bidirectional | 64 // |highest_presentation_timestamp_| to |timestamp|. Note that bidirectional |
65 // prediction between coded frames can cause |timestamp| to not be | 65 // prediction between coded frames can cause |timestamp| to not be |
66 // monotonically increasing even though the decode timestamps are | 66 // monotonically increasing even though the decode timestamps are |
67 // monotonically increasing. | 67 // monotonically increasing. |
68 void SetHighestPresentationTimestampIfIncreased(base::TimeDelta timestamp); | 68 void SetHighestPresentationTimestampIfIncreased(base::TimeDelta timestamp); |
69 | 69 |
70 // Adds |frame_| to the end of |processed_frames_|. | |
acolwell GONE FROM CHROMIUM
2014/07/09 00:11:47
nit: s/frame_/frame/
wolenetz
2014/07/09 18:23:29
Done.
| |
71 void EnqueueProcessedFrame(const scoped_refptr<StreamParserBuffer>& frame); | |
72 | |
73 // Appends |processed_frames_|, if not empty, to |stream_| and clears | |
74 // |processed_frames_|. Returns false if append failed, true otherwise. | |
75 // |processed_frames_| is cleared in both cases. | |
76 bool FlushProcessedFrames(); | |
77 | |
70 private: | 78 private: |
71 // The decode timestamp of the last coded frame appended in the current coded | 79 // The decode timestamp of the last coded frame appended in the current coded |
72 // frame group. Initially kNoTimestamp(), meaning "unset". | 80 // frame group. Initially kNoTimestamp(), meaning "unset". |
73 base::TimeDelta last_decode_timestamp_; | 81 base::TimeDelta last_decode_timestamp_; |
74 | 82 |
75 // The coded frame duration of the last coded frame appended in the current | 83 // The coded frame duration of the last coded frame appended in the current |
76 // coded frame group. Initially kNoTimestamp(), meaning "unset". | 84 // coded frame group. Initially kNoTimestamp(), meaning "unset". |
77 base::TimeDelta last_frame_duration_; | 85 base::TimeDelta last_frame_duration_; |
78 | 86 |
79 // The highest presentation timestamp encountered in a coded frame appended | 87 // The highest presentation timestamp encountered in a coded frame appended |
80 // in the current coded frame group. Initially kNoTimestamp(), meaning | 88 // in the current coded frame group. Initially kNoTimestamp(), meaning |
81 // "unset". | 89 // "unset". |
82 base::TimeDelta highest_presentation_timestamp_; | 90 base::TimeDelta highest_presentation_timestamp_; |
83 | 91 |
84 // Keeps track of whether the track buffer is waiting for a random access | 92 // Keeps track of whether the track buffer is waiting for a random access |
85 // point coded frame. Initially set to true to indicate that a random access | 93 // point coded frame. Initially set to true to indicate that a random access |
86 // point coded frame is needed before anything can be added to the track | 94 // point coded frame is needed before anything can be added to the track |
87 // buffer. | 95 // buffer. |
88 bool needs_random_access_point_; | 96 bool needs_random_access_point_; |
89 | 97 |
90 // Pointer to the stream associated with this track. The stream is not owned | 98 // Pointer to the stream associated with this track. The stream is not owned |
91 // by |this|. | 99 // by |this|. |
92 ChunkDemuxerStream* const stream_; | 100 ChunkDemuxerStream* const stream_; |
93 | 101 |
102 // Queue of processed frames that have not yet been appended to |stream_|. | |
103 // EnqueueProcessedFrame() adds to this queue, and FlushProcessedFrames() | |
104 // clears it. | |
105 StreamParser::BufferQueue processed_frames_; | |
106 | |
94 DISALLOW_COPY_AND_ASSIGN(MseTrackBuffer); | 107 DISALLOW_COPY_AND_ASSIGN(MseTrackBuffer); |
95 }; | 108 }; |
96 | 109 |
97 MseTrackBuffer::MseTrackBuffer(ChunkDemuxerStream* stream) | 110 MseTrackBuffer::MseTrackBuffer(ChunkDemuxerStream* stream) |
98 : last_decode_timestamp_(kNoTimestamp()), | 111 : last_decode_timestamp_(kNoTimestamp()), |
99 last_frame_duration_(kNoTimestamp()), | 112 last_frame_duration_(kNoTimestamp()), |
100 highest_presentation_timestamp_(kNoTimestamp()), | 113 highest_presentation_timestamp_(kNoTimestamp()), |
101 needs_random_access_point_(true), | 114 needs_random_access_point_(true), |
102 stream_(stream) { | 115 stream_(stream) { |
103 DCHECK(stream_); | 116 DCHECK(stream_); |
(...skipping 13 matching lines...) Expand all Loading... | |
117 } | 130 } |
118 | 131 |
119 void MseTrackBuffer::SetHighestPresentationTimestampIfIncreased( | 132 void MseTrackBuffer::SetHighestPresentationTimestampIfIncreased( |
120 base::TimeDelta timestamp) { | 133 base::TimeDelta timestamp) { |
121 if (highest_presentation_timestamp_ == kNoTimestamp() || | 134 if (highest_presentation_timestamp_ == kNoTimestamp() || |
122 timestamp > highest_presentation_timestamp_) { | 135 timestamp > highest_presentation_timestamp_) { |
123 highest_presentation_timestamp_ = timestamp; | 136 highest_presentation_timestamp_ = timestamp; |
124 } | 137 } |
125 } | 138 } |
126 | 139 |
140 void MseTrackBuffer::EnqueueProcessedFrame( | |
141 const scoped_refptr<StreamParserBuffer>& frame) { | |
142 processed_frames_.push_back(frame); | |
143 } | |
144 | |
145 bool MseTrackBuffer::FlushProcessedFrames() { | |
146 if (processed_frames_.empty()) | |
147 return true; | |
148 | |
149 bool result = stream_->Append(processed_frames_); | |
150 processed_frames_.clear(); | |
151 if (!result) { | |
152 DVLOG(3) << __FUNCTION__ | |
damienv1
2014/07/09 01:59:24
nit: DVLOG_IF
wolenetz
2014/07/09 18:23:29
Done.
| |
153 << "(): Failure appending processed frames to stream"; | |
154 } | |
155 | |
156 return result; | |
157 } | |
158 | |
127 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb) | 159 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb) |
128 : sequence_mode_(false), | 160 : sequence_mode_(false), |
129 group_start_timestamp_(kNoTimestamp()), | 161 group_start_timestamp_(kNoTimestamp()), |
130 update_duration_cb_(update_duration_cb) { | 162 update_duration_cb_(update_duration_cb) { |
131 DVLOG(2) << __FUNCTION__ << "()"; | 163 DVLOG(2) << __FUNCTION__ << "()"; |
132 DCHECK(!update_duration_cb.is_null()); | 164 DCHECK(!update_duration_cb.is_null()); |
133 } | 165 } |
134 | 166 |
135 FrameProcessor::~FrameProcessor() { | 167 FrameProcessor::~FrameProcessor() { |
136 DVLOG(2) << __FUNCTION__ << "()"; | 168 DVLOG(2) << __FUNCTION__ << "()"; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 // Note that ProcessFrame() implements an inner loop for a single frame that | 205 // Note that ProcessFrame() implements an inner loop for a single frame that |
174 // handles "jump to the Loop Top step to restart processing of the current | 206 // handles "jump to the Loop Top step to restart processing of the current |
175 // coded frame" per April 1, 2014 MSE spec editor's draft: | 207 // coded frame" per April 1, 2014 MSE spec editor's draft: |
176 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ | 208 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ |
177 // media-source.html#sourcebuffer-coded-frame-processing | 209 // media-source.html#sourcebuffer-coded-frame-processing |
178 // 1. For each coded frame in the media segment run the following steps: | 210 // 1. For each coded frame in the media segment run the following steps: |
179 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); | 211 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); |
180 frames_itr != frames.end(); ++frames_itr) { | 212 frames_itr != frames.end(); ++frames_itr) { |
181 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, | 213 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, |
182 timestamp_offset, new_media_segment)) { | 214 timestamp_offset, new_media_segment)) { |
215 FlushProcessedFrames(); | |
183 return false; | 216 return false; |
184 } | 217 } |
185 } | 218 } |
186 | 219 |
220 if (!FlushProcessedFrames()) | |
221 return false; | |
222 | |
187 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. | 223 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. |
188 | 224 |
189 // Step 5: | 225 // Step 5: |
190 update_duration_cb_.Run(group_end_timestamp_); | 226 update_duration_cb_.Run(group_end_timestamp_); |
191 | 227 |
192 return true; | 228 return true; |
193 } | 229 } |
194 | 230 |
195 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( | 231 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( |
196 base::TimeDelta timestamp_offset) { | 232 base::TimeDelta timestamp_offset) { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
271 base::TimeDelta segment_timestamp) { | 307 base::TimeDelta segment_timestamp) { |
272 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; | 308 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; |
273 | 309 |
274 for (TrackBufferMap::iterator itr = track_buffers_.begin(); | 310 for (TrackBufferMap::iterator itr = track_buffers_.begin(); |
275 itr != track_buffers_.end(); | 311 itr != track_buffers_.end(); |
276 ++itr) { | 312 ++itr) { |
277 itr->second->stream()->OnNewMediaSegment(segment_timestamp); | 313 itr->second->stream()->OnNewMediaSegment(segment_timestamp); |
278 } | 314 } |
279 } | 315 } |
280 | 316 |
317 bool FrameProcessor::FlushProcessedFrames() { | |
318 DVLOG(2) << __FUNCTION__ << "()"; | |
319 | |
320 bool result = true; | |
321 for (TrackBufferMap::iterator itr = track_buffers_.begin(); | |
322 itr != track_buffers_.end(); | |
323 ++itr) { | |
324 result &= itr->second->FlushProcessedFrames(); | |
damienv1
2014/07/09 01:56:56
Notation might be confusing here.
I would rather d
wolenetz
2014/07/09 18:23:29
Done. Note, as you very probably know, C++ &= and
| |
325 } | |
326 | |
327 return result; | |
328 } | |
329 | |
281 bool FrameProcessor::HandlePartialAppendWindowTrimming( | 330 bool FrameProcessor::HandlePartialAppendWindowTrimming( |
282 base::TimeDelta append_window_start, | 331 base::TimeDelta append_window_start, |
283 base::TimeDelta append_window_end, | 332 base::TimeDelta append_window_end, |
284 const scoped_refptr<StreamParserBuffer>& buffer) { | 333 const scoped_refptr<StreamParserBuffer>& buffer) { |
285 DCHECK(buffer->duration() > base::TimeDelta()); | 334 DCHECK(buffer->duration() > base::TimeDelta()); |
286 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); | 335 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); |
287 | 336 |
288 const base::TimeDelta frame_end_timestamp = | 337 const base::TimeDelta frame_end_timestamp = |
289 buffer->timestamp() + buffer->duration(); | 338 buffer->timestamp() + buffer->duration(); |
290 | 339 |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
595 } | 644 } |
596 | 645 |
597 // 12.2. Set the need random access point flag on track buffer to false. | 646 // 12.2. Set the need random access point flag on track buffer to false. |
598 track_buffer->set_needs_random_access_point(false); | 647 track_buffer->set_needs_random_access_point(false); |
599 } | 648 } |
600 | 649 |
601 // We now have a processed buffer to append to the track buffer's stream. | 650 // We now have a processed buffer to append to the track buffer's stream. |
602 // If it is the first in a new media segment or following a discontinuity, | 651 // If it is the first in a new media segment or following a discontinuity, |
603 // notify all the track buffers' streams that a new segment is beginning. | 652 // notify all the track buffers' streams that a new segment is beginning. |
604 if (*new_media_segment) { | 653 if (*new_media_segment) { |
654 // First, complete the append to track buffer streams of previous media | |
655 // segment's frames, if any. | |
656 if (!FlushProcessedFrames()) | |
657 return false; | |
658 | |
605 *new_media_segment = false; | 659 *new_media_segment = false; |
606 NotifyNewMediaSegmentStarting(decode_timestamp); | 660 NotifyNewMediaSegmentStarting(decode_timestamp); |
607 } | 661 } |
608 | 662 |
609 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " | 663 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " |
610 << "PTS=" << presentation_timestamp.InSecondsF() | 664 << "PTS=" << presentation_timestamp.InSecondsF() |
611 << ", DTS=" << decode_timestamp.InSecondsF(); | 665 << ", DTS=" << decode_timestamp.InSecondsF(); |
612 | 666 |
613 // Steps 13-18: | 667 // Steps 13-18: Note, we optimize by appending groups of contiguous |
614 // TODO(wolenetz): Collect and emit more than one buffer at a time, if | 668 // processed frames for each track buffer at end of ProcessFrames() or prior |
615 // possible. Also refactor SourceBufferStream to conform to spec GC timing. | 669 // to NotifyNewMediaSegmentStarting(). |
670 // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing. | |
616 // See http://crbug.com/371197. | 671 // See http://crbug.com/371197. |
617 StreamParser::BufferQueue buffer_to_append; | 672 track_buffer->EnqueueProcessedFrame(frame); |
618 buffer_to_append.push_back(frame); | |
619 if (!track_buffer->stream()->Append(buffer_to_append)) { | |
620 DVLOG(3) << __FUNCTION__ << ": Failure appending frame to stream"; | |
621 return false; | |
622 } | |
623 | 673 |
624 // 19. Set last decode timestamp for track buffer to decode timestamp. | 674 // 19. Set last decode timestamp for track buffer to decode timestamp. |
625 track_buffer->set_last_decode_timestamp(decode_timestamp); | 675 track_buffer->set_last_decode_timestamp(decode_timestamp); |
626 | 676 |
627 // 20. Set last frame duration for track buffer to frame duration. | 677 // 20. Set last frame duration for track buffer to frame duration. |
628 track_buffer->set_last_frame_duration(frame_duration); | 678 track_buffer->set_last_frame_duration(frame_duration); |
629 | 679 |
630 // 21. If highest presentation timestamp for track buffer is unset or frame | 680 // 21. If highest presentation timestamp for track buffer is unset or frame |
631 // end timestamp is greater than highest presentation timestamp, then | 681 // end timestamp is greater than highest presentation timestamp, then |
632 // set highest presentation timestamp for track buffer to frame end | 682 // set highest presentation timestamp for track buffer to frame end |
633 // timestamp. | 683 // timestamp. |
634 track_buffer->SetHighestPresentationTimestampIfIncreased( | 684 track_buffer->SetHighestPresentationTimestampIfIncreased( |
635 frame_end_timestamp); | 685 frame_end_timestamp); |
636 | 686 |
637 // 22. If frame end timestamp is greater than group end timestamp, then set | 687 // 22. If frame end timestamp is greater than group end timestamp, then set |
638 // group end timestamp equal to frame end timestamp. | 688 // group end timestamp equal to frame end timestamp. |
639 if (frame_end_timestamp > group_end_timestamp_) | 689 if (frame_end_timestamp > group_end_timestamp_) |
640 group_end_timestamp_ = frame_end_timestamp; | 690 group_end_timestamp_ = frame_end_timestamp; |
641 DCHECK(group_end_timestamp_ >= base::TimeDelta()); | 691 DCHECK(group_end_timestamp_ >= base::TimeDelta()); |
642 | 692 |
643 return true; | 693 return true; |
644 } | 694 } |
645 | 695 |
646 NOTREACHED(); | 696 NOTREACHED(); |
647 return false; | 697 return false; |
648 } | 698 } |
649 | 699 |
650 } // namespace media | 700 } // namespace media |
OLD | NEW |