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

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

Issue 1091293005: MSE: Relax the 'media segment must begin with keyframe' requirement (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Checkpoint. Not ready for review yet. Created 5 years, 3 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
« no previous file with comments | « media/filters/frame_processor.h ('k') | media/filters/frame_processor_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <cstdlib> 7 #include <cstdlib>
8 8
9 #include "base/stl_util.h" 9 #include "base/stl_util.h"
10 #include "media/base/stream_parser_buffer.h" 10 #include "media/base/stream_parser_buffer.h"
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 154
155 DVLOG_IF(3, !result) << __FUNCTION__ 155 DVLOG_IF(3, !result) << __FUNCTION__
156 << "(): Failure appending processed frames to stream"; 156 << "(): Failure appending processed frames to stream";
157 157
158 return result; 158 return result;
159 } 159 }
160 160
161 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb, 161 FrameProcessor::FrameProcessor(const UpdateDurationCB& update_duration_cb,
162 const scoped_refptr<MediaLog>& media_log) 162 const scoped_refptr<MediaLog>& media_log)
163 : group_start_timestamp_(kNoTimestamp()), 163 : group_start_timestamp_(kNoTimestamp()),
164 last_processed_decode_timestamp_(kNoDecodeTimestamp()),
164 update_duration_cb_(update_duration_cb), 165 update_duration_cb_(update_duration_cb),
165 media_log_(media_log) { 166 media_log_(media_log) {
166 DVLOG(2) << __FUNCTION__ << "()"; 167 DVLOG(2) << __FUNCTION__ << "()";
167 DCHECK(!update_duration_cb.is_null()); 168 DCHECK(!update_duration_cb.is_null());
168 } 169 }
169 170
170 FrameProcessor::~FrameProcessor() { 171 FrameProcessor::~FrameProcessor() {
171 DVLOG(2) << __FUNCTION__ << "()"; 172 DVLOG(2) << __FUNCTION__ << "()";
172 STLDeleteValues(&track_buffers_); 173 STLDeleteValues(&track_buffers_);
173 } 174 }
(...skipping 13 matching lines...) Expand all
187 // Step 8: Update the attribute to new mode. 188 // Step 8: Update the attribute to new mode.
188 sequence_mode_ = sequence_mode; 189 sequence_mode_ = sequence_mode;
189 } 190 }
190 191
191 bool FrameProcessor::ProcessFrames( 192 bool FrameProcessor::ProcessFrames(
192 const StreamParser::BufferQueue& audio_buffers, 193 const StreamParser::BufferQueue& audio_buffers,
193 const StreamParser::BufferQueue& video_buffers, 194 const StreamParser::BufferQueue& video_buffers,
194 const StreamParser::TextBufferQueueMap& text_map, 195 const StreamParser::TextBufferQueueMap& text_map,
195 base::TimeDelta append_window_start, 196 base::TimeDelta append_window_start,
196 base::TimeDelta append_window_end, 197 base::TimeDelta append_window_end,
197 bool* new_media_segment,
198 base::TimeDelta* timestamp_offset) { 198 base::TimeDelta* timestamp_offset) {
199 StreamParser::BufferQueue frames; 199 StreamParser::BufferQueue frames;
200 if (!MergeBufferQueues(audio_buffers, video_buffers, text_map, &frames)) { 200 if (!MergeBufferQueues(audio_buffers, video_buffers, text_map, &frames)) {
201 MEDIA_LOG(ERROR, media_log_) << "Parsed buffers not in DTS sequence"; 201 MEDIA_LOG(ERROR, media_log_) << "Parsed buffers not in DTS sequence";
202 return false; 202 return false;
203 } 203 }
204 204
205 DCHECK(!frames.empty()); 205 DCHECK(!frames.empty());
206 206
207 // Implements the coded frame processing algorithm's outer loop for step 1. 207 // Implements the coded frame processing algorithm's outer loop for step 1.
208 // Note that ProcessFrame() implements an inner loop for a single frame that 208 // Note that ProcessFrame() implements an inner loop for a single frame that
209 // handles "jump to the Loop Top step to restart processing of the current 209 // handles "jump to the Loop Top step to restart processing of the current
210 // coded frame" per April 1, 2014 MSE spec editor's draft: 210 // coded frame" per April 1, 2014 MSE spec editor's draft:
211 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 211 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
212 // media-source.html#sourcebuffer-coded-frame-processing 212 // media-source.html#sourcebuffer-coded-frame-processing
213 // 1. For each coded frame in the media segment run the following steps: 213 // 1. For each coded frame in the media segment run the following steps:
214 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); 214 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin();
215 frames_itr != frames.end(); ++frames_itr) { 215 frames_itr != frames.end(); ++frames_itr) {
216 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, 216 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end,
217 timestamp_offset, new_media_segment)) { 217 timestamp_offset)) {
218 FlushProcessedFrames(); 218 FlushProcessedFrames();
219 return false; 219 return false;
220 } 220 }
221 } 221 }
222 222
223 if (!FlushProcessedFrames()) 223 if (!FlushProcessedFrames())
224 return false; 224 return false;
225 225
226 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. 226 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element.
227 227
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
280 itr->second->set_needs_random_access_point(true); 280 itr->second->set_needs_random_access_point(true);
281 } 281 }
282 } 282 }
283 283
284 void FrameProcessor::Reset() { 284 void FrameProcessor::Reset() {
285 DVLOG(2) << __FUNCTION__ << "()"; 285 DVLOG(2) << __FUNCTION__ << "()";
286 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 286 for (TrackBufferMap::iterator itr = track_buffers_.begin();
287 itr != track_buffers_.end(); ++itr) { 287 itr != track_buffers_.end(); ++itr) {
288 itr->second->Reset(); 288 itr->second->Reset();
289 } 289 }
290
291 last_processed_decode_timestamp_ = kNoDecodeTimestamp();
292 in_coded_frame_group_ =
293 false; // BIG TODO: Does this need to be conditioned on appendMode?
290 } 294 }
291 295
292 void FrameProcessor::OnPossibleAudioConfigUpdate( 296 void FrameProcessor::OnPossibleAudioConfigUpdate(
293 const AudioDecoderConfig& config) { 297 const AudioDecoderConfig& config) {
294 DCHECK(config.IsValidConfig()); 298 DCHECK(config.IsValidConfig());
295 299
296 // Always clear the preroll buffer when a config update is received. 300 // Always clear the preroll buffer when a config update is received.
297 audio_preroll_buffer_ = NULL; 301 audio_preroll_buffer_ = NULL;
298 302
299 if (config.Matches(current_audio_config_)) 303 if (config.Matches(current_audio_config_))
300 return; 304 return;
301 305
302 current_audio_config_ = config; 306 current_audio_config_ = config;
303 sample_duration_ = base::TimeDelta::FromSecondsD( 307 sample_duration_ = base::TimeDelta::FromSecondsD(
304 1.0 / current_audio_config_.samples_per_second()); 308 1.0 / current_audio_config_.samples_per_second());
305 } 309 }
306 310
307 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) { 311 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) {
308 TrackBufferMap::iterator itr = track_buffers_.find(id); 312 TrackBufferMap::iterator itr = track_buffers_.find(id);
309 if (itr == track_buffers_.end()) 313 if (itr == track_buffers_.end())
310 return NULL; 314 return NULL;
311 315
312 return itr->second; 316 return itr->second;
313 } 317 }
314 318
315 void FrameProcessor::NotifyNewMediaSegmentStarting( 319 void FrameProcessor::NotifyStartOfCodedFrameGroup(
316 DecodeTimestamp segment_timestamp) { 320 DecodeTimestamp start_timestamp) {
317 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; 321 DVLOG(2) << __FUNCTION__ << "(" << start_timestamp.InSecondsF() << ")";
318 322
319 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 323 for (TrackBufferMap::iterator itr = track_buffers_.begin();
320 itr != track_buffers_.end(); 324 itr != track_buffers_.end();
321 ++itr) { 325 ++itr) {
322 itr->second->stream()->OnNewMediaSegment(segment_timestamp); 326 itr->second->stream()->OnStartOfCodedFrameGroup(start_timestamp);
323 } 327 }
324 } 328 }
325 329
326 bool FrameProcessor::FlushProcessedFrames() { 330 bool FrameProcessor::FlushProcessedFrames() {
327 DVLOG(2) << __FUNCTION__ << "()"; 331 DVLOG(2) << __FUNCTION__ << "()";
328 332
329 bool result = true; 333 bool result = true;
330 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 334 for (TrackBufferMap::iterator itr = track_buffers_.begin();
331 itr != track_buffers_.end(); 335 itr != track_buffers_.end();
332 ++itr) { 336 ++itr) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 processed_buffer = true; 437 processed_buffer = true;
434 } 438 }
435 439
436 return processed_buffer; 440 return processed_buffer;
437 } 441 }
438 442
439 bool FrameProcessor::ProcessFrame( 443 bool FrameProcessor::ProcessFrame(
440 const scoped_refptr<StreamParserBuffer>& frame, 444 const scoped_refptr<StreamParserBuffer>& frame,
441 base::TimeDelta append_window_start, 445 base::TimeDelta append_window_start,
442 base::TimeDelta append_window_end, 446 base::TimeDelta append_window_end,
443 base::TimeDelta* timestamp_offset, 447 base::TimeDelta* timestamp_offset) {
444 bool* new_media_segment) {
445 // Implements the loop within step 1 of the coded frame processing algorithm 448 // Implements the loop within step 1 of the coded frame processing algorithm
446 // for a single input frame per April 1, 2014 MSE spec editor's draft: 449 // for a single input frame per April 1, 2014 MSE spec editor's draft:
447 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 450 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
448 // media-source.html#sourcebuffer-coded-frame-processing 451 // media-source.html#sourcebuffer-coded-frame-processing
449 452
450 while (true) { 453 while (true) {
451 // 1. Loop Top: Let presentation timestamp be a double precision floating 454 // 1. Loop Top: Let presentation timestamp be a double precision floating
452 // point representation of the coded frame's presentation timestamp in 455 // point representation of the coded frame's presentation timestamp in
453 // seconds. 456 // seconds.
454 // 2. Let decode timestamp be a double precision floating point 457 // 2. Let decode timestamp be a double precision floating point
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
574 } 577 }
575 578
576 // 7. If last decode timestamp for track buffer is set and decode timestamp 579 // 7. If last decode timestamp for track buffer is set and decode timestamp
577 // is less than last decode timestamp 580 // is less than last decode timestamp
578 // OR 581 // OR
579 // If last decode timestamp for track buffer is set and the difference 582 // If last decode timestamp for track buffer is set and the difference
580 // between decode timestamp and last decode timestamp is greater than 2 583 // between decode timestamp and last decode timestamp is greater than 2
581 // times last frame duration: 584 // times last frame duration:
582 DecodeTimestamp last_decode_timestamp = 585 DecodeTimestamp last_decode_timestamp =
583 track_buffer->last_decode_timestamp(); 586 track_buffer->last_decode_timestamp();
587 // BIG TODO: continue here, using last_processed_decode_timestamp_. And
588 // conditionally resetting in_coded_frame_group_. And investigating how
589 // common single-stream-cluster appends are in mp4 or other muxed byte
590 // stream formats.
584 if (last_decode_timestamp != kNoDecodeTimestamp()) { 591 if (last_decode_timestamp != kNoDecodeTimestamp()) {
585 base::TimeDelta dts_delta = decode_timestamp - last_decode_timestamp; 592 base::TimeDelta dts_delta = decode_timestamp - last_decode_timestamp;
586 if (dts_delta < base::TimeDelta() || 593 if (dts_delta < base::TimeDelta() ||
587 dts_delta > 2 * track_buffer->last_frame_duration()) { 594 dts_delta > 2 * track_buffer->last_frame_duration()) {
588 // 7.1. If mode equals "segments": Set group end timestamp to 595 // 7.1. If mode equals "segments": Set group end timestamp to
589 // presentation timestamp. 596 // presentation timestamp.
590 // If mode equals "sequence": Set group start timestamp equal to 597 // If mode equals "sequence": Set group start timestamp equal to
591 // the group end timestamp. 598 // the group end timestamp.
592 if (!sequence_mode_) { 599 if (!sequence_mode_) {
593 group_end_timestamp_ = presentation_timestamp; 600 group_end_timestamp_ = presentation_timestamp;
594 // This triggers a discontinuity so we need to treat the next frames 601 // This triggers a discontinuity so we need to treat the next frames
595 // appended within the append window as if they were the beginning of 602 // appended within the append window as if they were the beginning of
596 // a new segment. 603 // a new coded frame group.
597 *new_media_segment = true; 604 in_coded_frame_group_ = false;
598 } else { 605 } else {
599 DVLOG(3) << __FUNCTION__ << " : Sequence mode discontinuity, GETS: " 606 DVLOG(3) << __FUNCTION__ << " : Sequence mode discontinuity, GETS: "
600 << group_end_timestamp_.InSecondsF(); 607 << group_end_timestamp_.InSecondsF();
601 DCHECK(kNoTimestamp() != group_end_timestamp_); 608 DCHECK(kNoTimestamp() != group_end_timestamp_);
602 group_start_timestamp_ = group_end_timestamp_; 609 group_start_timestamp_ = group_end_timestamp_;
603 } 610 }
604 611
605 // 7.2. - 7.5.: 612 // 7.2. - 7.5.:
606 Reset(); 613 Reset();
607 614
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 DVLOG(3) << __FUNCTION__ 684 DVLOG(3) << __FUNCTION__
678 << ": Dropping frame that is not a random access point"; 685 << ": Dropping frame that is not a random access point";
679 return true; 686 return true;
680 } 687 }
681 688
682 // 12.2. Set the need random access point flag on track buffer to false. 689 // 12.2. Set the need random access point flag on track buffer to false.
683 track_buffer->set_needs_random_access_point(false); 690 track_buffer->set_needs_random_access_point(false);
684 } 691 }
685 692
686 // We now have a processed buffer to append to the track buffer's stream. 693 // We now have a processed buffer to append to the track buffer's stream.
687 // If it is the first in a new media segment or following a discontinuity, 694 // If it is the first in a new coded frame group (such as following a
688 // notify all the track buffers' streams that a new segment is beginning. 695 // discontinuity), notify all the track buffers' streams that a coded frame
689 if (*new_media_segment) { 696 // group is starting.
690 // First, complete the append to track buffer streams of previous media 697 if (!in_coded_frame_group_) {
691 // segment's frames, if any. 698 // First, complete the append to track buffer streams of the previous
699 // coded frame group's frames, if any.
692 if (!FlushProcessedFrames()) 700 if (!FlushProcessedFrames())
693 return false; 701 return false;
694 702
695 *new_media_segment = false;
696
697 // TODO(acolwell/wolenetz): This should be changed to a presentation 703 // TODO(acolwell/wolenetz): This should be changed to a presentation
698 // timestamp. See http://crbug.com/402502 704 // timestamp. See http://crbug.com/402502
699 NotifyNewMediaSegmentStarting(decode_timestamp); 705 NotifyStartOfCodedFrameGroup(decode_timestamp);
706 in_coded_frame_group_ = true;
700 } 707 }
701 708
702 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " 709 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, "
703 << "PTS=" << presentation_timestamp.InSecondsF() 710 << "PTS=" << presentation_timestamp.InSecondsF()
704 << ", DTS=" << decode_timestamp.InSecondsF(); 711 << ", DTS=" << decode_timestamp.InSecondsF();
705 712
706 // Steps 13-18: Note, we optimize by appending groups of contiguous 713 // Steps 13-18: Note, we optimize by appending groups of contiguous
707 // processed frames for each track buffer at end of ProcessFrames() or prior 714 // processed frames for each track buffer at end of ProcessFrames() or prior
708 // to NotifyNewMediaSegmentStarting(). 715 // to NotifyStartOfCodedFrameGroup().
709 // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing. 716 // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing.
710 // See http://crbug.com/371197. 717 // See http://crbug.com/371197.
711 track_buffer->EnqueueProcessedFrame(frame); 718 track_buffer->EnqueueProcessedFrame(frame);
712 719
713 // 19. Set last decode timestamp for track buffer to decode timestamp. 720 // 19. Set last decode timestamp for track buffer to decode timestamp.
714 track_buffer->set_last_decode_timestamp(decode_timestamp); 721 track_buffer->set_last_decode_timestamp(decode_timestamp);
715 722
716 // 20. Set last frame duration for track buffer to frame duration. 723 // 20. Set last frame duration for track buffer to frame duration.
717 track_buffer->set_last_frame_duration(frame_duration); 724 track_buffer->set_last_frame_duration(frame_duration);
718 725
(...skipping 11 matching lines...) Expand all
730 DCHECK(group_end_timestamp_ >= base::TimeDelta()); 737 DCHECK(group_end_timestamp_ >= base::TimeDelta());
731 738
732 return true; 739 return true;
733 } 740 }
734 741
735 NOTREACHED(); 742 NOTREACHED();
736 return false; 743 return false;
737 } 744 }
738 745
739 } // namespace media 746 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/frame_processor.h ('k') | media/filters/frame_processor_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698