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

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

Issue 276573002: Add gapless playback support for AAC playback. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Comments. Created 6 years, 7 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 "base/stl_util.h" 7 #include "base/stl_util.h"
8 #include "media/base/buffers.h" 8 #include "media/base/buffers.h"
9 #include "media/base/stream_parser_buffer.h" 9 #include "media/base/stream_parser_buffer.h"
10 10
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 } 68 }
69 69
70 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. 70 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element.
71 71
72 // Step 5: 72 // Step 5:
73 update_duration_cb_.Run(group_end_timestamp_); 73 update_duration_cb_.Run(group_end_timestamp_);
74 74
75 return true; 75 return true;
76 } 76 }
77 77
78 bool FrameProcessor::ProcessFrame(scoped_refptr<StreamParserBuffer> frame, 78 bool FrameProcessor::ProcessFrame(
79 base::TimeDelta append_window_start, 79 const scoped_refptr<StreamParserBuffer>& frame,
80 base::TimeDelta append_window_end, 80 base::TimeDelta append_window_start,
81 base::TimeDelta* timestamp_offset, 81 base::TimeDelta append_window_end,
82 bool* new_media_segment) { 82 base::TimeDelta* timestamp_offset,
83 bool* new_media_segment) {
83 // Implements the loop within step 1 of the coded frame processing algorithm 84 // Implements the loop within step 1 of the coded frame processing algorithm
84 // for a single input frame per April 1, 2014 MSE spec editor's draft: 85 // for a single input frame per April 1, 2014 MSE spec editor's draft:
85 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 86 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
86 // media-source.html#sourcebuffer-coded-frame-processing 87 // media-source.html#sourcebuffer-coded-frame-processing
87 88
88 while (true) { 89 while (true) {
89 // 1. Loop Top: Let presentation timestamp be a double precision floating 90 // 1. Loop Top: Let presentation timestamp be a double precision floating
90 // point representation of the coded frame's presentation timestamp in 91 // point representation of the coded frame's presentation timestamp in
91 // seconds. 92 // seconds.
92 // 2. Let decode timestamp be a double precision floating point 93 // 2. Let decode timestamp be a double precision floating point
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 // true. 155 // true.
155 SetAllTrackBuffersNeedRandomAccessPoint(); 156 SetAllTrackBuffersNeedRandomAccessPoint();
156 157
157 // 4.4. Unset group start timestamp. 158 // 4.4. Unset group start timestamp.
158 group_start_timestamp_ = kNoTimestamp(); 159 group_start_timestamp_ = kNoTimestamp();
159 } 160 }
160 161
161 // 5. If timestampOffset is not 0, then run the following steps: 162 // 5. If timestampOffset is not 0, then run the following steps:
162 if (*timestamp_offset != base::TimeDelta()) { 163 if (*timestamp_offset != base::TimeDelta()) {
163 // 5.1. Add timestampOffset to the presentation timestamp. 164 // 5.1. Add timestampOffset to the presentation timestamp.
164 // Note: |frame| PTS is only updated if it survives processing. 165 // Note: |frame| PTS is only updated if it survives processing.
wolenetz 2014/05/30 19:58:45 nit: s/survives/survives discontinuity/
DaleCurtis 2014/05/30 20:54:30 Done.
165 presentation_timestamp += *timestamp_offset; 166 presentation_timestamp += *timestamp_offset;
166 167
167 // 5.2. Add timestampOffset to the decode timestamp. 168 // 5.2. Add timestampOffset to the decode timestamp.
168 // Frame DTS is only updated if it survives processing. 169 // Frame DTS is only updated if it survives processing.
wolenetz 2014/05/30 19:58:45 nit: ditto
DaleCurtis 2014/05/30 20:54:30 Done.
169 decode_timestamp += *timestamp_offset; 170 decode_timestamp += *timestamp_offset;
170 } 171 }
171 172
172 // 6. Let track buffer equal the track buffer that the coded frame will be 173 // 6. Let track buffer equal the track buffer that the coded frame will be
173 // added to. 174 // added to.
174 175
175 // Remap audio and video track types to their special singleton identifiers. 176 // Remap audio and video track types to their special singleton identifiers.
176 StreamParser::TrackId track_id = kAudioTrackId; 177 StreamParser::TrackId track_id = kAudioTrackId;
177 switch (frame->type()) { 178 switch (frame->type()) {
178 case DemuxerStream::AUDIO: 179 case DemuxerStream::AUDIO:
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 DVLOG(2) << __FUNCTION__ 245 DVLOG(2) << __FUNCTION__
245 << ": frame PTS=" << presentation_timestamp.InSecondsF() 246 << ": frame PTS=" << presentation_timestamp.InSecondsF()
246 << " or DTS=" << decode_timestamp.InSecondsF() 247 << " or DTS=" << decode_timestamp.InSecondsF()
247 << " negative after applying timestampOffset and handling any " 248 << " negative after applying timestampOffset and handling any "
248 << " discontinuity"; 249 << " discontinuity";
249 return false; 250 return false;
250 } 251 }
251 252
252 // 9. Let frame end timestamp equal the sum of presentation timestamp and 253 // 9. Let frame end timestamp equal the sum of presentation timestamp and
253 // frame duration. 254 // frame duration.
254 base::TimeDelta frame_end_timestamp = presentation_timestamp + 255 const base::TimeDelta frame_end_timestamp =
255 frame_duration; 256 presentation_timestamp + frame_duration;
256 257
257 // 10. If presentation timestamp is less than appendWindowStart, then set 258 // 10. If presentation timestamp is less than appendWindowStart, then set
258 // the need random access point flag to true, drop the coded frame, and 259 // the need random access point flag to true, drop the coded frame, and
259 // jump to the top of the loop to start processing the next coded 260 // jump to the top of the loop to start processing the next coded
260 // frame. 261 // frame.
261 // Note: We keep the result of partial discard of a buffer that overlaps 262 // Note: We keep the result of partial discard of a buffer that overlaps
262 // |append_window_start| and does not end after |append_window_end|. 263 // |append_window_start| and does not end after |append_window_end|.
263 // 11. If frame end timestamp is greater than appendWindowEnd, then set the 264 // 11. If frame end timestamp is greater than appendWindowEnd, then set the
264 // need random access point flag to true, drop the coded frame, and jump 265 // need random access point flag to true, drop the coded frame, and jump
265 // to the top of the loop to start processing the next coded frame. 266 // to the top of the loop to start processing the next coded frame.
267 frame->set_timestamp(presentation_timestamp);
268 frame->SetDecodeTimestamp(decode_timestamp);
269 if (track_buffer->stream()->supports_partial_append_window_trimming() &&
270 HandlePartialAppendWindowTrimming(append_window_start,
271 append_window_end,
272 frame)) {
273 // |frame| has been partially trimmed or had preroll added.
wolenetz 2014/05/30 19:58:45 I agree that the false path would set the flags fo
wolenetz 2014/05/30 20:45:12 From our chat, it's also possible that append wind
DaleCurtis 2014/05/30 20:54:30 Done.
274 decode_timestamp = frame->GetDecodeTimestamp();
275 presentation_timestamp = frame->timestamp();
276 frame_duration = frame->duration();
277
278 // The end timestamp of the frame should be unchanged.
279 DCHECK(frame_end_timestamp == presentation_timestamp + frame_duration);
280 }
281
266 if (presentation_timestamp < append_window_start || 282 if (presentation_timestamp < append_window_start ||
267 frame_end_timestamp > append_window_end) { 283 frame_end_timestamp > append_window_end) {
268 // See if a partial discard can be done around |append_window_start|. 284 track_buffer->set_needs_random_access_point(true);
269 // TODO(wolenetz): Refactor this into a base helper across legacy and 285 DVLOG(3) << "Dropping frame that is outside append window.";
270 // new frame processors?
271 if (track_buffer->stream()->supports_partial_append_window_trimming() &&
272 presentation_timestamp < append_window_start &&
273 frame_end_timestamp > append_window_start &&
274 frame_end_timestamp <= append_window_end) {
275 DCHECK(frame->IsKeyframe());
276 DVLOG(1) << "Truncating buffer which overlaps append window start."
277 << " presentation_timestamp "
278 << presentation_timestamp.InSecondsF()
279 << " append_window_start " << append_window_start.InSecondsF();
280 286
281 // Adjust the timestamp of this frame forward to |append_window_start|, 287 if (!sequence_mode_) {
wolenetz 2014/05/30 20:45:12 From our chat, this condition needs to be dropped.
DaleCurtis 2014/05/30 20:54:30 I defer to you guys to sort this out outside of th
wolenetz 2014/05/30 22:31:42 SGTM. On further inspection, and per our offline c
wolenetz 2014/05/31 01:22:04 I have a separate CL to test/clarify small append
282 // while decreasing the duration appropriately. 288 // This also triggers a discontinuity so we need to treat the next
283 frame->set_discard_padding(std::make_pair( 289 // frames appended within the append window as if they were the
284 append_window_start - presentation_timestamp, base::TimeDelta())); 290 // beginning of a new segment.
285 presentation_timestamp = append_window_start; // |frame| updated below. 291 *new_media_segment = true;
286 decode_timestamp = append_window_start; // |frame| updated below. 292 }
287 frame_duration = frame_end_timestamp - presentation_timestamp;
288 frame->set_duration(frame_duration);
289 293
290 // TODO(dalecurtis): This could also be done with |append_window_end|, 294 return true;
291 // but is not necessary since splice frames covert the overlap there.
292 } else {
293 track_buffer->set_needs_random_access_point(true);
294 DVLOG(3) << "Dropping frame that is outside append window.";
295
296 if (!sequence_mode_) {
297 // This also triggers a discontinuity so we need to treat the next
298 // frames appended within the append window as if they were the
299 // beginning of a new segment.
300 *new_media_segment = true;
301 }
302
303 return true;
304 }
305 } 295 }
306 296
307 // 12. If the need random access point flag on track buffer equals true, 297 // 12. If the need random access point flag on track buffer equals true,
308 // then run the following steps: 298 // then run the following steps:
309 if (track_buffer->needs_random_access_point()) { 299 if (track_buffer->needs_random_access_point()) {
310 // 12.1. If the coded frame is not a random access point, then drop the 300 // 12.1. If the coded frame is not a random access point, then drop the
311 // coded frame and jump to the top of the loop to start processing 301 // coded frame and jump to the top of the loop to start processing
312 // the next coded frame. 302 // the next coded frame.
313 if (!frame->IsKeyframe()) { 303 if (!frame->IsKeyframe()) {
314 DVLOG(3) << __FUNCTION__ 304 DVLOG(3) << __FUNCTION__
315 << ": Dropping frame that is not a random access point"; 305 << ": Dropping frame that is not a random access point";
316 return true; 306 return true;
317 } 307 }
318 308
319 // 12.2. Set the need random access point flag on track buffer to false. 309 // 12.2. Set the need random access point flag on track buffer to false.
320 track_buffer->set_needs_random_access_point(false); 310 track_buffer->set_needs_random_access_point(false);
321 } 311 }
322 312
323 // We now have a processed buffer to append to the track buffer's stream. 313 // We now have a processed buffer to append to the track buffer's stream.
324 // If it is the first in a new media segment or following a discontinuity, 314 // If it is the first in a new media segment or following a discontinuity,
325 // notify all the track buffers' streams that a new segment is beginning. 315 // notify all the track buffers' streams that a new segment is beginning.
326 if (*new_media_segment) { 316 if (*new_media_segment) {
327 *new_media_segment = false; 317 *new_media_segment = false;
328 NotifyNewMediaSegmentStarting(decode_timestamp); 318 NotifyNewMediaSegmentStarting(decode_timestamp);
329 } 319 }
330 320
331 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " 321 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, "
332 << "PTS=" << presentation_timestamp.InSecondsF() 322 << "PTS=" << presentation_timestamp.InSecondsF()
333 << ", DTS=" << decode_timestamp.InSecondsF(); 323 << ", DTS=" << decode_timestamp.InSecondsF();
334 frame->set_timestamp(presentation_timestamp);
335 frame->SetDecodeTimestamp(decode_timestamp);
336 324
337 // Steps 13-18: 325 // Steps 13-18:
338 // TODO(wolenetz): Collect and emit more than one buffer at a time, if 326 // TODO(wolenetz): Collect and emit more than one buffer at a time, if
339 // possible. Also refactor SourceBufferStream to conform to spec GC timing. 327 // possible. Also refactor SourceBufferStream to conform to spec GC timing.
340 // See http://crbug.com/371197. 328 // See http://crbug.com/371197.
341 StreamParser::BufferQueue buffer_to_append; 329 StreamParser::BufferQueue buffer_to_append;
342 buffer_to_append.push_back(frame); 330 buffer_to_append.push_back(frame);
343 track_buffer->stream()->Append(buffer_to_append); 331 track_buffer->stream()->Append(buffer_to_append);
344 332
345 // 19. Set last decode timestamp for track buffer to decode timestamp. 333 // 19. Set last decode timestamp for track buffer to decode timestamp.
346 track_buffer->set_last_decode_timestamp(decode_timestamp); 334 track_buffer->set_last_decode_timestamp(decode_timestamp);
347 335
348 // 20. Set last frame duration for track buffer to frame duration. 336 // 20. Set last frame duration for track buffer to frame duration.
349 track_buffer->set_last_frame_duration(frame_duration); 337 track_buffer->set_last_frame_duration(frame_duration);
wolenetz 2014/05/30 19:58:45 fyi: A side effect of partial frame discard is tha
350 338
351 // 21. If highest presentation timestamp for track buffer is unset or frame 339 // 21. If highest presentation timestamp for track buffer is unset or frame
352 // end timestamp is greater than highest presentation timestamp, then 340 // end timestamp is greater than highest presentation timestamp, then
353 // set highest presentation timestamp for track buffer to frame end 341 // set highest presentation timestamp for track buffer to frame end
354 // timestamp. 342 // timestamp.
355 track_buffer->SetHighestPresentationTimestampIfIncreased( 343 track_buffer->SetHighestPresentationTimestampIfIncreased(
356 frame_end_timestamp); 344 frame_end_timestamp);
357 345
358 // 22. If frame end timestamp is greater than group end timestamp, then set 346 // 22. If frame end timestamp is greater than group end timestamp, then set
359 // group end timestamp equal to frame end timestamp. 347 // group end timestamp equal to frame end timestamp.
360 DCHECK(group_end_timestamp_ >= base::TimeDelta()); 348 DCHECK(group_end_timestamp_ >= base::TimeDelta());
361 if (frame_end_timestamp > group_end_timestamp_) 349 if (frame_end_timestamp > group_end_timestamp_)
362 group_end_timestamp_ = frame_end_timestamp; 350 group_end_timestamp_ = frame_end_timestamp;
363 351
364 return true; 352 return true;
365 } 353 }
366 354
367 NOTREACHED(); 355 NOTREACHED();
368 return false; 356 return false;
369 } 357 }
370 358
371 void FrameProcessor::SetAllTrackBuffersNeedRandomAccessPoint() { 359 void FrameProcessor::SetAllTrackBuffersNeedRandomAccessPoint() {
372 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 360 for (TrackBufferMap::iterator itr = track_buffers_.begin();
373 itr != track_buffers_.end(); ++itr) { 361 itr != track_buffers_.end(); ++itr) {
374 itr->second->set_needs_random_access_point(true); 362 itr->second->set_needs_random_access_point(true);
375 } 363 }
376 } 364 }
377 365
378 } // namespace media 366 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698