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

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: Try to fix bot flakes by strictly ordering the blocks in muxed test 3 Created 4 years, 11 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
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 <stdint.h> 7 #include <stdint.h>
8 8
9 #include <cstdlib> 9 #include <cstdlib>
10 10
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 // Step 8: Update the attribute to new mode. 190 // Step 8: Update the attribute to new mode.
191 sequence_mode_ = sequence_mode; 191 sequence_mode_ = sequence_mode;
192 } 192 }
193 193
194 bool FrameProcessor::ProcessFrames( 194 bool FrameProcessor::ProcessFrames(
195 const StreamParser::BufferQueue& audio_buffers, 195 const StreamParser::BufferQueue& audio_buffers,
196 const StreamParser::BufferQueue& video_buffers, 196 const StreamParser::BufferQueue& video_buffers,
197 const StreamParser::TextBufferQueueMap& text_map, 197 const StreamParser::TextBufferQueueMap& text_map,
198 base::TimeDelta append_window_start, 198 base::TimeDelta append_window_start,
199 base::TimeDelta append_window_end, 199 base::TimeDelta append_window_end,
200 bool* new_media_segment,
201 base::TimeDelta* timestamp_offset) { 200 base::TimeDelta* timestamp_offset) {
202 StreamParser::BufferQueue frames; 201 StreamParser::BufferQueue frames;
203 if (!MergeBufferQueues(audio_buffers, video_buffers, text_map, &frames)) { 202 if (!MergeBufferQueues(audio_buffers, video_buffers, text_map, &frames)) {
204 MEDIA_LOG(ERROR, media_log_) << "Parsed buffers not in DTS sequence"; 203 MEDIA_LOG(ERROR, media_log_) << "Parsed buffers not in DTS sequence";
205 return false; 204 return false;
206 } 205 }
207 206
208 DCHECK(!frames.empty()); 207 DCHECK(!frames.empty());
209 208
210 // Implements the coded frame processing algorithm's outer loop for step 1. 209 // Implements the coded frame processing algorithm's outer loop for step 1.
211 // Note that ProcessFrame() implements an inner loop for a single frame that 210 // Note that ProcessFrame() implements an inner loop for a single frame that
212 // handles "jump to the Loop Top step to restart processing of the current 211 // handles "jump to the Loop Top step to restart processing of the current
213 // coded frame" per April 1, 2014 MSE spec editor's draft: 212 // coded frame" per April 1, 2014 MSE spec editor's draft:
214 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 213 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
215 // media-source.html#sourcebuffer-coded-frame-processing 214 // media-source.html#sourcebuffer-coded-frame-processing
216 // 1. For each coded frame in the media segment run the following steps: 215 // 1. For each coded frame in the media segment run the following steps:
217 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin(); 216 for (StreamParser::BufferQueue::const_iterator frames_itr = frames.begin();
218 frames_itr != frames.end(); ++frames_itr) { 217 frames_itr != frames.end(); ++frames_itr) {
219 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end, 218 if (!ProcessFrame(*frames_itr, append_window_start, append_window_end,
220 timestamp_offset, new_media_segment)) { 219 timestamp_offset)) {
221 FlushProcessedFrames(); 220 FlushProcessedFrames();
222 return false; 221 return false;
223 } 222 }
224 } 223 }
225 224
226 if (!FlushProcessedFrames()) 225 if (!FlushProcessedFrames())
227 return false; 226 return false;
228 227
229 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element. 228 // 2. - 4. Are handled by the WebMediaPlayer / Pipeline / Media Element.
230 229
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
287 void FrameProcessor::Reset() { 286 void FrameProcessor::Reset() {
288 DVLOG(2) << __FUNCTION__ << "()"; 287 DVLOG(2) << __FUNCTION__ << "()";
289 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 288 for (TrackBufferMap::iterator itr = track_buffers_.begin();
290 itr != track_buffers_.end(); ++itr) { 289 itr != track_buffers_.end(); ++itr) {
291 itr->second->Reset(); 290 itr->second->Reset();
292 } 291 }
293 292
294 if (sequence_mode_) { 293 if (sequence_mode_) {
295 DCHECK(kNoTimestamp() != group_end_timestamp_); 294 DCHECK(kNoTimestamp() != group_end_timestamp_);
296 group_start_timestamp_ = group_end_timestamp_; 295 group_start_timestamp_ = group_end_timestamp_;
296 return;
297 } 297 }
298
299 in_coded_frame_group_ = false;
chcunningham 2016/01/22 01:26:37 Do you not reset this in sequence mode? (return a
wolenetz 2016/01/22 01:50:03 Correct. Sequence mode means everything appended i
wolenetz 2016/01/22 18:59:31 Done.
chcunningham 2016/01/22 19:26:02 Acknowledged.
298 } 300 }
299 301
300 void FrameProcessor::OnPossibleAudioConfigUpdate( 302 void FrameProcessor::OnPossibleAudioConfigUpdate(
301 const AudioDecoderConfig& config) { 303 const AudioDecoderConfig& config) {
302 DCHECK(config.IsValidConfig()); 304 DCHECK(config.IsValidConfig());
303 305
304 // Always clear the preroll buffer when a config update is received. 306 // Always clear the preroll buffer when a config update is received.
305 audio_preroll_buffer_ = NULL; 307 audio_preroll_buffer_ = NULL;
306 308
307 if (config.Matches(current_audio_config_)) 309 if (config.Matches(current_audio_config_))
308 return; 310 return;
309 311
310 current_audio_config_ = config; 312 current_audio_config_ = config;
311 sample_duration_ = base::TimeDelta::FromSecondsD( 313 sample_duration_ = base::TimeDelta::FromSecondsD(
312 1.0 / current_audio_config_.samples_per_second()); 314 1.0 / current_audio_config_.samples_per_second());
313 } 315 }
314 316
315 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) { 317 MseTrackBuffer* FrameProcessor::FindTrack(StreamParser::TrackId id) {
316 TrackBufferMap::iterator itr = track_buffers_.find(id); 318 TrackBufferMap::iterator itr = track_buffers_.find(id);
317 if (itr == track_buffers_.end()) 319 if (itr == track_buffers_.end())
318 return NULL; 320 return NULL;
319 321
320 return itr->second; 322 return itr->second;
321 } 323 }
322 324
323 void FrameProcessor::NotifyNewMediaSegmentStarting( 325 void FrameProcessor::NotifyStartOfCodedFrameGroup(
324 DecodeTimestamp segment_timestamp) { 326 DecodeTimestamp start_timestamp) {
325 DVLOG(2) << __FUNCTION__ << "(" << segment_timestamp.InSecondsF() << ")"; 327 DVLOG(2) << __FUNCTION__ << "(" << start_timestamp.InSecondsF() << ")";
326 328
327 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 329 for (TrackBufferMap::iterator itr = track_buffers_.begin();
328 itr != track_buffers_.end(); 330 itr != track_buffers_.end();
329 ++itr) { 331 ++itr) {
330 itr->second->stream()->OnNewMediaSegment(segment_timestamp); 332 itr->second->stream()->OnStartOfCodedFrameGroup(start_timestamp);
331 } 333 }
332 } 334 }
333 335
334 bool FrameProcessor::FlushProcessedFrames() { 336 bool FrameProcessor::FlushProcessedFrames() {
335 DVLOG(2) << __FUNCTION__ << "()"; 337 DVLOG(2) << __FUNCTION__ << "()";
336 338
337 bool result = true; 339 bool result = true;
338 for (TrackBufferMap::iterator itr = track_buffers_.begin(); 340 for (TrackBufferMap::iterator itr = track_buffers_.begin();
339 itr != track_buffers_.end(); 341 itr != track_buffers_.end();
340 ++itr) { 342 ++itr) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 processed_buffer = true; 443 processed_buffer = true;
442 } 444 }
443 445
444 return processed_buffer; 446 return processed_buffer;
445 } 447 }
446 448
447 bool FrameProcessor::ProcessFrame( 449 bool FrameProcessor::ProcessFrame(
448 const scoped_refptr<StreamParserBuffer>& frame, 450 const scoped_refptr<StreamParserBuffer>& frame,
449 base::TimeDelta append_window_start, 451 base::TimeDelta append_window_start,
450 base::TimeDelta append_window_end, 452 base::TimeDelta append_window_end,
451 base::TimeDelta* timestamp_offset, 453 base::TimeDelta* timestamp_offset) {
452 bool* new_media_segment) {
453 // Implements the loop within step 1 of the coded frame processing algorithm 454 // Implements the loop within step 1 of the coded frame processing algorithm
454 // for a single input frame per April 1, 2014 MSE spec editor's draft: 455 // for a single input frame per April 1, 2014 MSE spec editor's draft:
455 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ 456 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
456 // media-source.html#sourcebuffer-coded-frame-processing 457 // media-source.html#sourcebuffer-coded-frame-processing
457 458
458 while (true) { 459 while (true) {
459 // 1. Loop Top: Let presentation timestamp be a double precision floating 460 // 1. Loop Top: Let presentation timestamp be a double precision floating
460 // point representation of the coded frame's presentation timestamp in 461 // point representation of the coded frame's presentation timestamp in
461 // seconds. 462 // seconds.
462 // 2. Let decode timestamp be a double precision floating point 463 // 2. Let decode timestamp be a double precision floating point
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 << ", and parser track id " << frame->track_id(); 581 << ", and parser track id " << frame->track_id();
581 return false; 582 return false;
582 } 583 }
583 584
584 // 7. If last decode timestamp for track buffer is set and decode timestamp 585 // 7. If last decode timestamp for track buffer is set and decode timestamp
585 // is less than last decode timestamp 586 // is less than last decode timestamp
586 // OR 587 // OR
587 // If last decode timestamp for track buffer is set and the difference 588 // If last decode timestamp for track buffer is set and the difference
588 // between decode timestamp and last decode timestamp is greater than 2 589 // between decode timestamp and last decode timestamp is greater than 2
589 // times last frame duration: 590 // times last frame duration:
590 DecodeTimestamp last_decode_timestamp = 591 DecodeTimestamp track_last_decode_timestamp =
591 track_buffer->last_decode_timestamp(); 592 track_buffer->last_decode_timestamp();
592 if (last_decode_timestamp != kNoDecodeTimestamp()) { 593 if (track_last_decode_timestamp != kNoDecodeTimestamp()) {
593 base::TimeDelta dts_delta = decode_timestamp - last_decode_timestamp; 594 base::TimeDelta track_dts_delta =
594 if (dts_delta < base::TimeDelta() || 595 decode_timestamp - track_last_decode_timestamp;
595 dts_delta > 2 * track_buffer->last_frame_duration()) { 596 if (track_dts_delta < base::TimeDelta() ||
597 track_dts_delta > 2 * track_buffer->last_frame_duration()) {
598 DCHECK(in_coded_frame_group_);
596 // 7.1. If mode equals "segments": Set group end timestamp to 599 // 7.1. If mode equals "segments": Set group end timestamp to
597 // presentation timestamp. 600 // presentation timestamp.
598 // If mode equals "sequence": Set group start timestamp equal to 601 // If mode equals "sequence": Set group start timestamp equal to
599 // the group end timestamp. 602 // the group end timestamp.
600 if (!sequence_mode_) { 603 if (!sequence_mode_) {
601 group_end_timestamp_ = presentation_timestamp; 604 group_end_timestamp_ = presentation_timestamp;
602 // This triggers a discontinuity so we need to treat the next frames 605 // This triggers a discontinuity so we need to treat the next frames
603 // appended within the append window as if they were the beginning of 606 // appended within the append window as if they were the beginning of
604 // a new segment. 607 // a new coded frame group.
605 *new_media_segment = true; 608 in_coded_frame_group_ = false;
606 } else { 609 } else {
607 DVLOG(3) << __FUNCTION__ << " : Sequence mode discontinuity, GETS: " 610 DVLOG(3) << __FUNCTION__ << " : Sequence mode discontinuity, GETS: "
608 << group_end_timestamp_.InSecondsF(); 611 << group_end_timestamp_.InSecondsF();
609 DCHECK(kNoTimestamp() != group_end_timestamp_); 612 DCHECK(kNoTimestamp() != group_end_timestamp_);
610 group_start_timestamp_ = group_end_timestamp_; 613 group_start_timestamp_ = group_end_timestamp_;
611 } 614 }
612 615
613 // 7.2. - 7.5.: 616 // 7.2. - 7.5.:
614 Reset(); 617 Reset();
615 618
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 DVLOG(3) << __FUNCTION__ 688 DVLOG(3) << __FUNCTION__
686 << ": Dropping frame that is not a random access point"; 689 << ": Dropping frame that is not a random access point";
687 return true; 690 return true;
688 } 691 }
689 692
690 // 12.2. Set the need random access point flag on track buffer to false. 693 // 12.2. Set the need random access point flag on track buffer to false.
691 track_buffer->set_needs_random_access_point(false); 694 track_buffer->set_needs_random_access_point(false);
692 } 695 }
693 696
694 // We now have a processed buffer to append to the track buffer's stream. 697 // We now have a processed buffer to append to the track buffer's stream.
695 // If it is the first in a new media segment or following a discontinuity, 698 // If it is the first in a new coded frame group (such as following a
696 // notify all the track buffers' streams that a new segment is beginning. 699 // discontinuity), notify all the track buffers' streams that a coded frame
697 if (*new_media_segment) { 700 // group is starting.
698 // First, complete the append to track buffer streams of previous media 701 if (!in_coded_frame_group_) {
699 // segment's frames, if any. 702 // First, complete the append to track buffer streams of the previous
703 // coded frame group's frames, if any.
700 if (!FlushProcessedFrames()) 704 if (!FlushProcessedFrames())
701 return false; 705 return false;
702 706
703 *new_media_segment = false;
704
705 // TODO(acolwell/wolenetz): This should be changed to a presentation 707 // TODO(acolwell/wolenetz): This should be changed to a presentation
706 // timestamp. See http://crbug.com/402502 708 // timestamp. See http://crbug.com/402502
707 NotifyNewMediaSegmentStarting(decode_timestamp); 709 NotifyStartOfCodedFrameGroup(decode_timestamp);
710 in_coded_frame_group_ = true;
708 } 711 }
709 712
710 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, " 713 DVLOG(3) << __FUNCTION__ << ": Sending processed frame to stream, "
711 << "PTS=" << presentation_timestamp.InSecondsF() 714 << "PTS=" << presentation_timestamp.InSecondsF()
712 << ", DTS=" << decode_timestamp.InSecondsF(); 715 << ", DTS=" << decode_timestamp.InSecondsF();
713 716
714 // Steps 13-18: Note, we optimize by appending groups of contiguous 717 // Steps 13-18: Note, we optimize by appending groups of contiguous
715 // processed frames for each track buffer at end of ProcessFrames() or prior 718 // processed frames for each track buffer at end of ProcessFrames() or prior
716 // to NotifyNewMediaSegmentStarting(). 719 // to NotifyStartOfCodedFrameGroup().
717 // TODO(wolenetz): Refactor SourceBufferStream to conform to spec GC timing.
718 // See http://crbug.com/371197.
719 track_buffer->EnqueueProcessedFrame(frame); 720 track_buffer->EnqueueProcessedFrame(frame);
720 721
721 // 19. Set last decode timestamp for track buffer to decode timestamp. 722 // 19. Set last decode timestamp for track buffer to decode timestamp.
722 track_buffer->set_last_decode_timestamp(decode_timestamp); 723 track_buffer->set_last_decode_timestamp(decode_timestamp);
723 724
724 // 20. Set last frame duration for track buffer to frame duration. 725 // 20. Set last frame duration for track buffer to frame duration.
725 track_buffer->set_last_frame_duration(frame_duration); 726 track_buffer->set_last_frame_duration(frame_duration);
726 727
727 // 21. If highest presentation timestamp for track buffer is unset or frame 728 // 21. If highest presentation timestamp for track buffer is unset or frame
728 // end timestamp is greater than highest presentation timestamp, then 729 // end timestamp is greater than highest presentation timestamp, then
729 // set highest presentation timestamp for track buffer to frame end 730 // set highest presentation timestamp for track buffer to frame end
730 // timestamp. 731 // timestamp.
731 track_buffer->SetHighestPresentationTimestampIfIncreased( 732 track_buffer->SetHighestPresentationTimestampIfIncreased(
732 frame_end_timestamp); 733 frame_end_timestamp);
733 734
734 // 22. If frame end timestamp is greater than group end timestamp, then set 735 // 22. If frame end timestamp is greater than group end timestamp, then set
735 // group end timestamp equal to frame end timestamp. 736 // group end timestamp equal to frame end timestamp.
736 if (frame_end_timestamp > group_end_timestamp_) 737 if (frame_end_timestamp > group_end_timestamp_)
737 group_end_timestamp_ = frame_end_timestamp; 738 group_end_timestamp_ = frame_end_timestamp;
738 DCHECK(group_end_timestamp_ >= base::TimeDelta()); 739 DCHECK(group_end_timestamp_ >= base::TimeDelta());
739 740
740 return true; 741 return true;
741 } 742 }
742 743
743 NOTREACHED(); 744 NOTREACHED();
744 return false; 745 return false;
745 } 746 }
746 747
747 } // namespace media 748 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698