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 && |
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) { |
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 && |
acolwell GONE FROM CHROMIUM
2014/07/23 00:15:42
s/<=/</ ? How do you get into the == situation? It
DaleCurtis
2014/07/23 01:50:41
You're right, <= should have been skipped in the i
| |
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 |
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 |
acolwell GONE FROM CHROMIUM
2014/07/23 00:15:42
Is this still true since you are setting a new fra
DaleCurtis
2014/07/23 01:50:41
I'm not sure, wolenetz?
wolenetz
2014/07/25 22:33:03
I believe this is still correct. |frame_duration|
| |
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(); |
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 |