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

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

Issue 360843002: MSE: Move FrameProcessorBase code into FrameProcessor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix lint error 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
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>
8
7 #include "base/stl_util.h" 9 #include "base/stl_util.h"
8 #include "media/base/buffers.h" 10 #include "media/base/buffers.h"
9 #include "media/base/stream_parser_buffer.h" 11 #include "media/base/stream_parser_buffer.h"
10 12
11 namespace media { 13 namespace media {
12 14
15 MseTrackBuffer::MseTrackBuffer(ChunkDemuxerStream* stream)
16 : last_decode_timestamp_(kNoTimestamp()),
17 last_frame_duration_(kNoTimestamp()),
18 highest_presentation_timestamp_(kNoTimestamp()),
19 needs_random_access_point_(true),
20 stream_(stream) {
21 DCHECK(stream_);
22 }
23
24 MseTrackBuffer::~MseTrackBuffer() {
25 DVLOG(2) << __FUNCTION__ << "()";
26 }
27
28 void MseTrackBuffer::Reset() {
29 DVLOG(2) << __FUNCTION__ << "()";
30
31 last_decode_timestamp_ = kNoTimestamp();
32 last_frame_duration_ = kNoTimestamp();
33 highest_presentation_timestamp_ = kNoTimestamp();
34 needs_random_access_point_ = true;
35 }
36
37 void MseTrackBuffer::SetHighestPresentationTimestampIfIncreased(
38 base::TimeDelta timestamp) {
39 if (highest_presentation_timestamp_ == kNoTimestamp() ||
40 timestamp > highest_presentation_timestamp_) {
41 highest_presentation_timestamp_ = timestamp;
42 }
43 }
44
13 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb) 45 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb)
14 : update_duration_cb_(update_duration_cb) { 46 : sequence_mode_(false),
47 group_start_timestamp_(kNoTimestamp()),
48 update_duration_cb_(update_duration_cb) {
15 DVLOG(2) << __FUNCTION__ << "()"; 49 DVLOG(2) << __FUNCTION__ << "()";
16 DCHECK(!update_duration_cb.is_null()); 50 DCHECK(!update_duration_cb.is_null());
17 } 51 }
18 52
19 FrameProcessor::~FrameProcessor() { 53 FrameProcessor::~FrameProcessor() {
20 DVLOG(2) << __FUNCTION__; 54 DVLOG(2) << __FUNCTION__ << "()";
55 STLDeleteValues(&track_buffers_);
21 } 56 }
22 57
23 void FrameProcessor::SetSequenceMode(bool sequence_mode) { 58 void FrameProcessor::SetSequenceMode(bool sequence_mode) {
24 DVLOG(2) << __FUNCTION__ << "(" << sequence_mode << ")"; 59 DVLOG(2) << __FUNCTION__ << "(" << sequence_mode << ")";
25 60
26 // Per April 1, 2014 MSE spec editor's draft: 61 // Per April 1, 2014 MSE spec editor's draft:
27 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/media- source.html#widl-SourceBuffer-mode 62 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/media- source.html#widl-SourceBuffer-mode
28 // Step 7: If the new mode equals "sequence", then set the group start 63 // Step 7: If the new mode equals "sequence", then set the group start
29 // timestamp to the group end timestamp. 64 // timestamp to the group end timestamp.
30 if (sequence_mode) { 65 if (sequence_mode) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 } 103 }
69 104
70 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. 105 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element.
71 106
72 // Step 5: 107 // Step 5:
73 update_duration_cb_.Run(group_end_timestamp_); 108 update_duration_cb_.Run(group_end_timestamp_);
74 109
75 return true; 110 return true;
76 } 111 }
77 112
113 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode(
114 base::TimeDelta timestamp_offset) {
115 DVLOG(2) << __FUNCTION__ << "(" << timestamp_offset.InSecondsF() << ")";
116 DCHECK(kNoTimestamp() != timestamp_offset);
117 if (sequence_mode_)
118 group_start_timestamp_ = timestamp_offset;
119
120 // Changes to timestampOffset should invalidate the preroll buffer.
121 audio_preroll_buffer_ = NULL;
122 }
123
124 bool FrameProcessor::AddTrack(StreamParser::TrackId id,
125 ChunkDemuxerStream* stream) {
126 DVLOG(2) << __FUNCTION__ << "(): id=" << id;
127
128 MseTrackBuffer* existing_track = FindTrack(id);
129 DCHECK(!existing_track);
130 if (existing_track)
131 return false;
132
133 track_buffers_[id] = new MseTrackBuffer(stream);
134 return true;
135 }
136
137 bool FrameProcessor::UpdateTrack(StreamParser::TrackId old_id,
138 StreamParser::TrackId new_id) {
139 DVLOG(2) << __FUNCTION__ << "() : old_id=" << old_id << ", new_id=" << new_id;
140
141 if (old_id == new_id || !FindTrack(old_id) || FindTrack(new_id))
142 return false;
143
144 track_buffers_[new_id] = track_buffers_[old_id];
145 CHECK_EQ(1u, track_buffers_.erase(old_id));
146 return true;
147 }
148
149 void FrameProcessor::SetAllTrackBuffersNeedRandomAccessPoint() {
150 for (TrackBufferMap::iterator itr = track_buffers_.begin();
151 itr != track_buffers_.end();
152 ++itr) {
153 itr->second->set_needs_random_access_point(true);
154 }
155 }
156
157 void FrameProcessor::Reset() {
158 DVLOG(2) << __FUNCTION__ << "()";
159 for (TrackBufferMap::iterator itr = track_buffers_.begin();
160 itr != track_buffers_.end(); ++itr) {
161 itr->second->Reset();
162 }
163 }
164
165 void FrameProcessor::OnPossibleAudioConfigUpdate(
166 const AudioDecoderConfig& config) {
167 DCHECK(config.IsValidConfig());
168
169 // Always clear the preroll buffer when a config update is received.
170 audio_preroll_buffer_ = NULL;
171
172 if (config.Matches(current_audio_config_))
173 return;
174
175 current_audio_config_ = config;
176 sample_duration_ = base::TimeDelta::FromSecondsD(
177 1.0 / current_audio_config_.samples_per_second());
178 }
179
180 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) {
181 TrackBufferMap::iterator itr = track_buffers_.find(id);
182 if (itr == track_buffers_.end())
183 return NULL;
184
185 return itr->second;
186 }
187
188 void FrameProcessor::NotifyNewMediaSegmentStarting(
189 base::TimeDelta segment_timestamp) {
190 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")";
191
192 for (TrackBufferMap::iterator itr = track_buffers_.begin();
193 itr != track_buffers_.end();
194 ++itr) {
195 itr->second->stream()->OnNewMediaSegment(segment_timestamp);
196 }
197 }
198
199 bool FrameProcessor::HandlePartialAppendWindowTrimming(
200 base::TimeDelta append_window_start,
201 base::TimeDelta append_window_end,
202 const scoped_refptr<StreamParserBuffer>& buffer) {
203 DCHECK(buffer->duration() > base::TimeDelta());
204 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type());
205
206 const base::TimeDelta frame_end_timestamp =
207 buffer->timestamp() + buffer->duration();
208
209 // Ignore any buffers which start after |append_window_start| or end after
210 // |append_window_end|. For simplicity, even those that start before
211 // |append_window_start|.
212 if (buffer->timestamp() > append_window_start ||
213 frame_end_timestamp > append_window_end) {
214 // TODO(dalecurtis): Partial append window trimming could also be done
215 // around |append_window_end|, but is not necessary since splice frames
216 // cover overlaps there.
217 return false;
218 }
219
220 // If the buffer is entirely before |append_window_start|, save it as preroll
221 // for the first buffer which overlaps |append_window_start|.
222 if (buffer->timestamp() < append_window_start &&
223 frame_end_timestamp <= append_window_start) {
224 audio_preroll_buffer_ = buffer;
225 return false;
226 }
227
228 // There's nothing to be done if we have no preroll and the buffer starts on
229 // the append window start.
230 if (buffer->timestamp() == append_window_start && !audio_preroll_buffer_)
231 return false;
232
233 // See if a partial discard can be done around |append_window_start|.
234 DCHECK(buffer->timestamp() <= append_window_start);
235 DCHECK(buffer->IsKeyframe());
236 DVLOG(1) << "Truncating buffer which overlaps append window start."
237 << " presentation_timestamp " << buffer->timestamp().InSecondsF()
238 << " append_window_start " << append_window_start.InSecondsF();
239
240 // If this isn't the first buffer discarded by the append window, try to use
241 // the last buffer discarded for preroll. This ensures that the partially
242 // trimmed buffer can be correctly decoded.
243 if (audio_preroll_buffer_) {
244 // We only want to use the preroll buffer if it directly precedes (less than
245 // one sample apart) the current buffer.
246 const int64 delta = std::abs((audio_preroll_buffer_->timestamp() +
247 audio_preroll_buffer_->duration() -
248 buffer->timestamp()).InMicroseconds());
249 if (delta < sample_duration_.InMicroseconds()) {
250 buffer->SetPrerollBuffer(audio_preroll_buffer_);
251 } else {
252 // TODO(dalecurtis): Add a MEDIA_LOG() for when this is dropped unused.
253 }
254 audio_preroll_buffer_ = NULL;
255 }
256
257 // Decrease the duration appropriately. We only need to shorten the buffer if
258 // it overlaps |append_window_start|.
259 if (buffer->timestamp() < append_window_start) {
260 buffer->set_discard_padding(std::make_pair(
261 append_window_start - buffer->timestamp(), base::TimeDelta()));
262 buffer->set_duration(frame_end_timestamp - append_window_start);
263 }
264
265 // Adjust the timestamp of this buffer forward to |append_window_start|. The
266 // timestamps are always set, even if |buffer|'s timestamp is already set to
267 // |append_window_start|, to ensure the preroll buffer is setup correctly.
268 buffer->set_timestamp(append_window_start);
269 buffer->SetDecodeTimestamp(append_window_start);
270 return true;
271 }
272
78 bool FrameProcessor::ProcessFrame( 273 bool FrameProcessor::ProcessFrame(
79 const scoped_refptr<StreamParserBuffer>& frame, 274 const scoped_refptr<StreamParserBuffer>& frame,
80 base::TimeDelta append_window_start, 275 base::TimeDelta append_window_start,
81 base::TimeDelta append_window_end, 276 base::TimeDelta append_window_end,
82 base::TimeDelta* timestamp_offset, 277 base::TimeDelta* timestamp_offset,
83 bool* new_media_segment) { 278 bool* new_media_segment) {
84 // Implements the loop within step 1 of the coded frame processing algorithm 279 // Implements the loop within step 1 of the coded frame processing algorithm
85 // for a single input frame per April 1, 2014 MSE spec editor's draft: 280 // for a single input frame per April 1, 2014 MSE spec editor's draft:
86 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 281 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
87 // media-source.html#sourcebuffer-coded-frame-processing 282 // media-source.html#sourcebuffer-coded-frame-processing
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 DCHECK(group_end_timestamp_ >= base::TimeDelta()); 559 DCHECK(group_end_timestamp_ >= base::TimeDelta());
365 560
366 return true; 561 return true;
367 } 562 }
368 563
369 NOTREACHED(); 564 NOTREACHED();
370 return false; 565 return false;
371 } 566 }
372 567
373 } // namespace media 568 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698