| 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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_|. |
| 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 Loading... |
| 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 DVLOG_IF(3, !result) << __FUNCTION__ |
| 152 << "(): Failure appending processed frames to stream"; |
| 153 |
| 154 return result; |
| 155 } |
| 156 |
| 127 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb) | 157 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb) |
| 128 : sequence_mode_(false), | 158 : sequence_mode_(false), |
| 129 group_start_timestamp_(kNoTimestamp()), | 159 group_start_timestamp_(kNoTimestamp()), |
| 130 update_duration_cb_(update_duration_cb) { | 160 update_duration_cb_(update_duration_cb) { |
| 131 DVLOG(2) << __FUNCTION__ << "()"; | 161 DVLOG(2) << __FUNCTION__ << "()"; |
| 132 DCHECK(!update_duration_cb.is_null()); | 162 DCHECK(!update_duration_cb.is_null()); |
| 133 } | 163 } |
| 134 | 164 |
| 135 FrameProcessor::~FrameProcessor() { | 165 FrameProcessor::~FrameProcessor() { |
| 136 DVLOG(2) << __FUNCTION__ << "()"; | 166 DVLOG(2) << __FUNCTION__ << "()"; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 // Note that ProcessFrame() implements an inner loop for a single frame that | 203 // 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 | 204 // 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: | 205 // coded frame" per April 1, 2014 MSE spec editor's draft: |
| 176 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ | 206 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ |
| 177 // media-source.html#sourcebuffer-coded-frame-processing | 207 // media-source.html#sourcebuffer-coded-frame-processing |
| 178 // 1. For each coded frame in the media segment run the following steps: | 208 // 1. For each coded frame in the media segment run the following steps: |
| 179 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); | 209 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); |
| 180 frames_itr != frames.end(); ++frames_itr) { | 210 frames_itr != frames.end(); ++frames_itr) { |
| 181 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, | 211 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, |
| 182 timestamp_offset, new_media_segment)) { | 212 timestamp_offset, new_media_segment)) { |
| 213 FlushProcessedFrames(); |
| 183 return false; | 214 return false; |
| 184 } | 215 } |
| 185 } | 216 } |
| 186 | 217 |
| 218 if (!FlushProcessedFrames()) |
| 219 return false; |
| 220 |
| 187 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. | 221 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. |
| 188 | 222 |
| 189 // Step 5: | 223 // Step 5: |
| 190 update_duration_cb_.Run(group_end_timestamp_); | 224 update_duration_cb_.Run(group_end_timestamp_); |
| 191 | 225 |
| 192 return true; | 226 return true; |
| 193 } | 227 } |
| 194 | 228 |
| 195 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( | 229 void FrameProcessor::SetGroupStartTimestampIfInSequenceMode( |
| 196 base::TimeDelta timestamp_offset) { | 230 base::TimeDelta timestamp_offset) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 base::TimeDelta segment_timestamp) { | 305 base::TimeDelta segment_timestamp) { |
| 272 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; | 306 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; |
| 273 | 307 |
| 274 for (TrackBufferMap::iterator itr = track_buffers_.begin(); | 308 for (TrackBufferMap::iterator itr = track_buffers_.begin(); |
| 275 itr != track_buffers_.end(); | 309 itr != track_buffers_.end(); |
| 276 ++itr) { | 310 ++itr) { |
| 277 itr->second->stream()->OnNewMediaSegment(segment_timestamp); | 311 itr->second->stream()->OnNewMediaSegment(segment_timestamp); |
| 278 } | 312 } |
| 279 } | 313 } |
| 280 | 314 |
| 315 bool FrameProcessor::FlushProcessedFrames() { |
| 316 DVLOG(2) << __FUNCTION__ << "()"; |
| 317 |
| 318 bool result = true; |
| 319 for (TrackBufferMap::iterator itr = track_buffers_.begin(); |
| 320 itr != track_buffers_.end(); |
| 321 ++itr) { |
| 322 if (!itr->second->FlushProcessedFrames()) |
| 323 result = false; |
| 324 } |
| 325 |
| 326 return result; |
| 327 } |
| 328 |
| 281 bool FrameProcessor::HandlePartialAppendWindowTrimming( | 329 bool FrameProcessor::HandlePartialAppendWindowTrimming( |
| 282 base::TimeDelta append_window_start, | 330 base::TimeDelta append_window_start, |
| 283 base::TimeDelta append_window_end, | 331 base::TimeDelta append_window_end, |
| 284 const scoped_refptr<StreamParserBuffer>& buffer) { | 332 const scoped_refptr<StreamParserBuffer>& buffer) { |
| 285 DCHECK(buffer->duration() > base::TimeDelta()); | 333 DCHECK(buffer->duration() > base::TimeDelta()); |
| 286 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); | 334 DCHECK_EQ(DemuxerStream::AUDIO, buffer->type()); |
| 287 | 335 |
| 288 const base::TimeDelta frame_end_timestamp = | 336 const base::TimeDelta frame_end_timestamp = |
| 289 buffer->timestamp() + buffer->duration(); | 337 buffer->timestamp() + buffer->duration(); |
| 290 | 338 |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 } | 636 } |
| 589 | 637 |
| 590 // 12.2. Set the need random access point flag on track buffer to false. | 638 // 12.2. Set the need random access point flag on track buffer to false. |
| 591 track_buffer->set_needs_random_access_point(false); | 639 track_buffer->set_needs_random_access_point(false); |
| 592 } | 640 } |
| 593 | 641 |
| 594 // We now have a processed buffer to append to the track buffer's stream. | 642 // We now have a processed buffer to append to the track buffer's stream. |
| 595 // If it is the first in a new media segment or following a discontinuity, | 643 // If it is the first in a new media segment or following a discontinuity, |
| 596 // notify all the track buffers' streams that a new segment is beginning. | 644 // notify all the track buffers' streams that a new segment is beginning. |
| 597 if (*new_media_segment) { | 645 if (*new_media_segment) { |
| 646 // First, complete the append to track buffer streams of previous media |
| 647 // segment's frames, if any. |
| 648 if (!FlushProcessedFrames()) |
| 649 return false; |
| 650 |
| 598 *new_media_segment = false; | 651 *new_media_segment = false; |
| 599 NotifyNewMediaSegmentStarting(decode_timestamp); | 652 NotifyNewMediaSegmentStarting(decode_timestamp); |
| 600 } | 653 } |
| 601 | 654 |
| 602 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " | 655 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " |
| 603 << "PTS=" << presentation_timestamp.InSecondsF() | 656 << "PTS=" << presentation_timestamp.InSecondsF() |
| 604 << ", DTS=" << decode_timestamp.InSecondsF(); | 657 << ", DTS=" << decode_timestamp.InSecondsF(); |
| 605 | 658 |
| 606 // Steps 13-18: | 659 // Steps 13-18: Note, we optimize by appending groups of contiguous |
| 607 // TODO(wolenetz): Collect and emit more than one buffer at a time, if | 660 // processed frames for each track buffer at end of ProcessFrames() or prior |
| 608 // possible. Also refactor SourceBufferStream to conform to spec GC timing. | 661 // to NotifyNewMediaSegmentStarting(). |
| 662 // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing. |
| 609 // See http://crbug.com/371197. | 663 // See http://crbug.com/371197. |
| 610 StreamParser::BufferQueue buffer_to_append; | 664 track_buffer->EnqueueProcessedFrame(frame); |
| 611 buffer_to_append.push_back(frame); | |
| 612 if (!track_buffer->stream()->Append(buffer_to_append)) { | |
| 613 DVLOG(3) << __FUNCTION__ << ": Failure appending frame to stream"; | |
| 614 return false; | |
| 615 } | |
| 616 | 665 |
| 617 // 19. Set last decode timestamp for track buffer to decode timestamp. | 666 // 19. Set last decode timestamp for track buffer to decode timestamp. |
| 618 track_buffer->set_last_decode_timestamp(decode_timestamp); | 667 track_buffer->set_last_decode_timestamp(decode_timestamp); |
| 619 | 668 |
| 620 // 20. Set last frame duration for track buffer to frame duration. | 669 // 20. Set last frame duration for track buffer to frame duration. |
| 621 track_buffer->set_last_frame_duration(frame_duration); | 670 track_buffer->set_last_frame_duration(frame_duration); |
| 622 | 671 |
| 623 // 21. If highest presentation timestamp for track buffer is unset or frame | 672 // 21. If highest presentation timestamp for track buffer is unset or frame |
| 624 // end timestamp is greater than highest presentation timestamp, then | 673 // end timestamp is greater than highest presentation timestamp, then |
| 625 // set highest presentation timestamp for track buffer to frame end | 674 // set highest presentation timestamp for track buffer to frame end |
| 626 // timestamp. | 675 // timestamp. |
| 627 track_buffer->SetHighestPresentationTimestampIfIncreased( | 676 track_buffer->SetHighestPresentationTimestampIfIncreased( |
| 628 frame_end_timestamp); | 677 frame_end_timestamp); |
| 629 | 678 |
| 630 // 22. If frame end timestamp is greater than group end timestamp, then set | 679 // 22. If frame end timestamp is greater than group end timestamp, then set |
| 631 // group end timestamp equal to frame end timestamp. | 680 // group end timestamp equal to frame end timestamp. |
| 632 if (frame_end_timestamp > group_end_timestamp_) | 681 if (frame_end_timestamp > group_end_timestamp_) |
| 633 group_end_timestamp_ = frame_end_timestamp; | 682 group_end_timestamp_ = frame_end_timestamp; |
| 634 DCHECK(group_end_timestamp_ >= base::TimeDelta()); | 683 DCHECK(group_end_timestamp_ >= base::TimeDelta()); |
| 635 | 684 |
| 636 return true; | 685 return true; |
| 637 } | 686 } |
| 638 | 687 |
| 639 NOTREACHED(); | 688 NOTREACHED(); |
| 640 return false; | 689 return false; |
| 641 } | 690 } |
| 642 | 691 |
| 643 } // namespace media | 692 } // namespace media |
| OLD | NEW |