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

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

Issue 381443002: MSE: Optimize frame processor appends to streams (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 5 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
« no previous file with comments | « media/filters/frame_processor.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/frame_processor.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698