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