Chromium Code Reviews| 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 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 | 325 |
| 326 return result; | 326 return result; |
| 327 } | 327 } |
| 328 | 328 |
| 329 bool FrameProcessor::HandlePartialAppendWindowTrimming( | 329 bool FrameProcessor::HandlePartialAppendWindowTrimming( |
| 330 base::TimeDelta append_window_start, | 330 base::TimeDelta append_window_start, |
| 331 base::TimeDelta append_window_end, | 331 base::TimeDelta append_window_end, |
| 332 const scoped_refptr<StreamParserBuffer>& buffer) { | 332 const scoped_refptr<StreamParserBuffer>& buffer) { |
| 333 DCHECK(buffer->duration() > base::TimeDelta()); | 333 DCHECK(buffer->duration() > base::TimeDelta()); |
| 334 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); | 334 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); |
| 335 DCHECK(buffer->IsKeyframe()); | |
| 335 | 336 |
| 336 const base::TimeDelta frame_end_timestamp = | 337 const base::TimeDelta frame_end_timestamp = |
| 337 buffer->timestamp() + buffer->duration(); | 338 buffer->timestamp() + buffer->duration(); |
| 338 | 339 |
| 339 // Ignore any buffers which start after |append_window_start| or end after | 340 // Ignore any buffers entirely after or inside of the append window. |
| 340 // |append_window_end|. For simplicity, even those that start before | 341 if (buffer->timestamp() > append_window_end || |
| 341 // |append_window_start|. | 342 (buffer->timestamp() > append_window_start && |
|
wolenetz
2014/07/25 22:33:03
Is there any allowance we need to make here for ap
DaleCurtis
2014/07/29 01:35:10
We don't attach preroll for disjoint buffers. If
| |
| 342 if (buffer->timestamp() > append_window_start || | 343 frame_end_timestamp <= append_window_end)) { |
| 343 frame_end_timestamp > append_window_end) { | |
| 344 // TODO(dalecurtis): Partial append window trimming could also be done | |
| 345 // around |append_window_end|, but is not necessary since splice frames | |
| 346 // cover overlaps there. | |
| 347 return false; | 344 return false; |
| 348 } | 345 } |
| 349 | 346 |
| 350 // If the buffer is entirely before |append_window_start|, save it as preroll | 347 // If the buffer is entirely before |append_window_start|, save it as preroll |
| 351 // for the first buffer which overlaps |append_window_start|. | 348 // for the first buffer which overlaps |append_window_start|. |
| 352 if (buffer->timestamp() < append_window_start && | 349 if (buffer->timestamp() < append_window_start && |
| 353 frame_end_timestamp <= append_window_start) { | 350 frame_end_timestamp <= append_window_start) { |
| 354 audio_preroll_buffer_ = buffer; | 351 audio_preroll_buffer_ = buffer; |
| 355 return false; | 352 return false; |
| 356 } | 353 } |
| 357 | 354 |
| 358 // There's nothing to be done if we have no preroll and the buffer starts on | 355 // There's nothing to be done if we have no preroll and the buffer starts on |
| 359 // the append window start. | 356 // the append window start. |
| 360 if (buffer->timestamp() == append_window_start && !audio_preroll_buffer_) | 357 if (buffer->timestamp() == append_window_start && !audio_preroll_buffer_) |
| 361 return false; | 358 return false; |
| 362 | 359 |
| 360 bool trimmed_buffer = false; | |
| 361 | |
| 363 // See if a partial discard can be done around |append_window_start|. | 362 // See if a partial discard can be done around |append_window_start|. |
| 364 DCHECK(buffer->timestamp() <= append_window_start); | 363 if (buffer->timestamp() <= append_window_start) { |
|
wolenetz
2014/07/25 22:33:03
ditto
DaleCurtis
2014/07/29 01:35:10
Acknowledged.
| |
| 365 DCHECK(buffer->IsKeyframe()); | 364 DVLOG(1) << "Truncating buffer which overlaps append window start." |
| 366 DVLOG(1) << "Truncating buffer which overlaps append window start." | 365 << " presentation_timestamp " << buffer->timestamp().InSecondsF() |
| 367 << " presentation_timestamp " << buffer->timestamp().InSecondsF() | 366 << " frame_end_timestamp " << frame_end_timestamp.InSecondsF() |
| 368 << " append_window_start " << append_window_start.InSecondsF(); | 367 << " append_window_start " << append_window_start.InSecondsF(); |
| 369 | 368 |
| 370 // If this isn't the first buffer discarded by the append window, try to use | 369 // If this isn't the first buffer discarded by the append window, try to use |
| 371 // the last buffer discarded for preroll. This ensures that the partially | 370 // the last buffer discarded for preroll. This ensures that the partially |
| 372 // trimmed buffer can be correctly decoded. | 371 // trimmed buffer can be correctly decoded. |
| 373 if (audio_preroll_buffer_) { | 372 if (audio_preroll_buffer_) { |
| 374 // We only want to use the preroll buffer if it directly precedes (less than | 373 // We only want to use the preroll buffer if it directly precedes (less |
| 375 // one sample apart) the current buffer. | 374 // than one sample apart) the current buffer. |
| 376 const int64 delta = std::abs((audio_preroll_buffer_->timestamp() + | 375 const int64 delta = std::abs((audio_preroll_buffer_->timestamp() + |
| 377 audio_preroll_buffer_->duration() - | 376 audio_preroll_buffer_->duration() - |
| 378 buffer->timestamp()).InMicroseconds()); | 377 buffer->timestamp()).InMicroseconds()); |
| 379 if (delta < sample_duration_.InMicroseconds()) { | 378 if (delta < sample_duration_.InMicroseconds()) { |
| 380 buffer->SetPrerollBuffer(audio_preroll_buffer_); | 379 buffer->SetPrerollBuffer(audio_preroll_buffer_); |
| 381 } else { | 380 } else { |
| 382 // TODO(dalecurtis): Add a MEDIA_LOG() for when this is dropped unused. | 381 // TODO(dalecurtis): Add a MEDIA_LOG() for when this is dropped unused. |
| 382 } | |
| 383 audio_preroll_buffer_ = NULL; | |
| 383 } | 384 } |
| 384 audio_preroll_buffer_ = NULL; | 385 |
| 386 // Decrease the duration appropriately. We only need to shorten the buffer | |
| 387 // if it overlaps |append_window_start|. | |
| 388 if (buffer->timestamp() < append_window_start) { | |
| 389 buffer->set_discard_padding(std::make_pair( | |
| 390 append_window_start - buffer->timestamp(), base::TimeDelta())); | |
| 391 buffer->set_duration(frame_end_timestamp - append_window_start); | |
| 392 } | |
| 393 | |
| 394 // Adjust the timestamp of this buffer forward to |append_window_start|. The | |
| 395 // timestamps are always set, even if |buffer|'s timestamp is already set to | |
| 396 // |append_window_start| to ensure the preroll buffer is setup correctly. | |
| 397 buffer->set_timestamp(append_window_start); | |
| 398 buffer->SetDecodeTimestamp(append_window_start); | |
| 399 trimmed_buffer = true; | |
| 385 } | 400 } |
| 386 | 401 |
| 387 // Decrease the duration appropriately. We only need to shorten the buffer if | 402 // See if a partial discard can be done around |append_window_end|. |
| 388 // it overlaps |append_window_start|. | 403 if (buffer->timestamp() < append_window_end && |
| 389 if (buffer->timestamp() < append_window_start) { | 404 frame_end_timestamp > append_window_end) { |
| 390 buffer->set_discard_padding(std::make_pair( | 405 DVLOG(1) << "Truncating buffer which overlaps append window end." |
| 391 append_window_start - buffer->timestamp(), base::TimeDelta())); | 406 << " presentation_timestamp " << buffer->timestamp().InSecondsF() |
| 392 buffer->set_duration(frame_end_timestamp - append_window_start); | 407 << " frame_end_timestamp " << frame_end_timestamp.InSecondsF() |
| 408 << " append_window_end " << append_window_end.InSecondsF(); | |
| 409 buffer->set_discard_padding( | |
| 410 std::make_pair(buffer->discard_padding().first, | |
| 411 frame_end_timestamp - append_window_end)); | |
| 412 buffer->set_duration(append_window_end - buffer->timestamp()); | |
| 413 trimmed_buffer = true; | |
| 393 } | 414 } |
| 394 | 415 |
| 395 // Adjust the timestamp of this buffer forward to |append_window_start|. The | 416 return trimmed_buffer; |
| 396 // timestamps are always set, even if |buffer|'s timestamp is already set to | |
| 397 // |append_window_start|, to ensure the preroll buffer is setup correctly. | |
| 398 buffer->set_timestamp(append_window_start); | |
| 399 buffer->SetDecodeTimestamp(append_window_start); | |
| 400 return true; | |
| 401 } | 417 } |
| 402 | 418 |
| 403 bool FrameProcessor::ProcessFrame( | 419 bool FrameProcessor::ProcessFrame( |
| 404 const scoped_refptr<StreamParserBuffer>& frame, | 420 const scoped_refptr<StreamParserBuffer>& frame, |
| 405 base::TimeDelta append_window_start, | 421 base::TimeDelta append_window_start, |
| 406 base::TimeDelta append_window_end, | 422 base::TimeDelta append_window_end, |
| 407 base::TimeDelta* timestamp_offset, | 423 base::TimeDelta* timestamp_offset, |
| 408 bool* new_media_segment) { | 424 bool* new_media_segment) { |
| 409 // Implements the loop within step 1 of the coded frame processing algorithm | 425 // Implements the loop within step 1 of the coded frame processing algorithm |
| 410 // for a single input frame per April 1, 2014 MSE spec editor's draft: | 426 // for a single input frame per April 1, 2014 MSE spec editor's draft: |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 | 573 |
| 558 // 7.6. Jump to the Loop Top step above to restart processing of the | 574 // 7.6. Jump to the Loop Top step above to restart processing of the |
| 559 // current coded frame. | 575 // current coded frame. |
| 560 DVLOG(3) << __FUNCTION__ << ": Discontinuity: reprocessing frame"; | 576 DVLOG(3) << __FUNCTION__ << ": Discontinuity: reprocessing frame"; |
| 561 continue; | 577 continue; |
| 562 } | 578 } |
| 563 } | 579 } |
| 564 | 580 |
| 565 // 9. Let frame end timestamp equal the sum of presentation timestamp and | 581 // 9. Let frame end timestamp equal the sum of presentation timestamp and |
| 566 // frame duration. | 582 // frame duration. |
| 567 const base::TimeDelta frame_end_timestamp = | 583 base::TimeDelta frame_end_timestamp = |
| 568 presentation_timestamp + frame_duration; | 584 presentation_timestamp + frame_duration; |
| 569 | 585 |
| 570 // 10. If presentation timestamp is less than appendWindowStart, then set | 586 // 10. If presentation timestamp is less than appendWindowStart, then set |
| 571 // the need random access point flag to true, drop the coded frame, and | 587 // the need random access point flag to true, drop the coded frame, and |
| 572 // jump to the top of the loop to start processing the next coded | 588 // jump to the top of the loop to start processing the next coded |
| 573 // frame. | 589 // frame. |
| 574 // Note: We keep the result of partial discard of a buffer that overlaps | 590 // Note: We keep the result of partial discard of a buffer that overlaps |
| 575 // |append_window_start| and does not end after |append_window_end|. | 591 // |append_window_start| and does not end after |append_window_end|. |
| 576 // 11. If frame end timestamp is greater than appendWindowEnd, then set the | 592 // 11. If frame end timestamp is greater than appendWindowEnd, then set the |
| 577 // need random access point flag to true, drop the coded frame, and jump | 593 // need random access point flag to true, drop the coded frame, and jump |
| 578 // to the top of the loop to start processing the next coded frame. | 594 // to the top of the loop to start processing the next coded frame. |
| 579 frame->set_timestamp(presentation_timestamp); | 595 frame->set_timestamp(presentation_timestamp); |
| 580 frame->SetDecodeTimestamp(decode_timestamp); | 596 frame->SetDecodeTimestamp(decode_timestamp); |
| 581 if (track_buffer->stream()->supports_partial_append_window_trimming() && | 597 if (track_buffer->stream()->supports_partial_append_window_trimming() && |
| 582 HandlePartialAppendWindowTrimming(append_window_start, | 598 HandlePartialAppendWindowTrimming(append_window_start, |
| 583 append_window_end, | 599 append_window_end, |
| 584 frame)) { | 600 frame)) { |
| 585 // If |frame| was shortened a discontinuity may exist, so treat the next | 601 // If |frame| was shortened a discontinuity may exist, so treat the next |
|
wolenetz
2014/07/25 22:33:03
s/was shortened/was front-trimmed/
DaleCurtis
2014/07/29 01:35:10
Done.
| |
| 586 // frames appended as if they were the beginning of a new media segment. | 602 // frames appended as if they were the beginning of a new media segment. |
| 587 if (frame->timestamp() != presentation_timestamp && !sequence_mode_) | 603 if (frame->timestamp() != presentation_timestamp && !sequence_mode_) |
| 588 *new_media_segment = true; | 604 *new_media_segment = true; |
| 589 | 605 |
| 590 // |frame| has been partially trimmed or had preroll added. Though | 606 // |frame| has been partially trimmed or had preroll added. Though |
| 591 // |frame|'s duration may have changed, do not update |frame_duration| | 607 // |frame|'s duration may have changed, do not update |frame_duration| |
| 592 // here, so |track_buffer|'s last frame duration update uses original | 608 // here, so |track_buffer|'s last frame duration update uses original |
| 593 // frame duration and reduces spurious discontinuity detection. | 609 // frame duration and reduces spurious discontinuity detection. |
| 594 decode_timestamp = frame->GetDecodeTimestamp(); | 610 decode_timestamp = frame->GetDecodeTimestamp(); |
| 595 presentation_timestamp = frame->timestamp(); | 611 presentation_timestamp = frame->timestamp(); |
| 596 | 612 frame_end_timestamp = frame->timestamp() + frame->duration(); |
|
wolenetz
2014/07/25 22:33:04
nit: Though we currently require all paths that re
DaleCurtis
2014/07/29 01:35:10
Are you saying we should call that if we trim the
wolenetz
2014/07/30 22:04:31
I see. If just preroll added, we don't need to cal
wolenetz
2014/07/30 23:12:34
I think my earlier reply to this comment was misse
DaleCurtis
2014/07/31 00:00:32
Whoops, I didn't see this, though I'm not sure I f
| |
| 597 // The end timestamp of the frame should be unchanged. | |
| 598 DCHECK(frame_end_timestamp == presentation_timestamp + frame->duration()); | |
| 599 } | 613 } |
| 600 | 614 |
| 601 if (presentation_timestamp < append_window_start || | 615 if (presentation_timestamp < append_window_start || |
| 602 frame_end_timestamp > append_window_end) { | 616 frame_end_timestamp > append_window_end) { |
| 603 track_buffer->set_needs_random_access_point(true); | 617 track_buffer->set_needs_random_access_point(true); |
| 604 DVLOG(3) << "Dropping frame that is outside append window."; | 618 DVLOG(3) << "Dropping frame that is outside append window."; |
| 605 return true; | 619 return true; |
| 606 } | 620 } |
| 607 | 621 |
| 608 // Note: This step is relocated, versus April 1 spec, to allow append window | 622 // Note: This step is relocated, versus April 1 spec, to allow append window |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 683 DCHECK(group_end_timestamp_ >= base::TimeDelta()); | 697 DCHECK(group_end_timestamp_ >= base::TimeDelta()); |
| 684 | 698 |
| 685 return true; | 699 return true; |
| 686 } | 700 } |
| 687 | 701 |
| 688 NOTREACHED(); | 702 NOTREACHED(); |
| 689 return false; | 703 return false; |
| 690 } | 704 } |
| 691 | 705 |
| 692 } // namespace media | 706 } // namespace media |
| OLD | NEW |