OLD | NEW |
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 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/media_source_state.h" | 5 #include "media/filters/media_source_state.h" |
6 | 6 |
7 #include "base/callback_helpers.h" | 7 #include "base/callback_helpers.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "media/filters/chunk_demuxer.h" | 9 #include "media/filters/chunk_demuxer.h" |
10 #include "media/filters/frame_processor.h" | 10 #include "media/filters/frame_processor.h" |
11 #include "media/filters/source_buffer_stream.h" | 11 #include "media/filters/source_buffer_stream.h" |
12 | 12 |
13 namespace media { | 13 namespace media { |
14 | 14 |
| 15 enum { |
| 16 // Limits the number of MEDIA_LOG() calls warning the user that a muxed stream |
| 17 // media segment is missing a block from at least one of the audio or video |
| 18 // tracks. |
| 19 kMaxMissingTrackInSegmentLogs = 10, |
| 20 }; |
| 21 |
15 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { | 22 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { |
16 return queue.back()->timestamp() + queue.back()->duration(); | 23 return queue.back()->timestamp() + queue.back()->duration(); |
17 } | 24 } |
18 | 25 |
19 // List of time ranges for each SourceBuffer. | 26 // List of time ranges for each SourceBuffer. |
20 // static | 27 // static |
21 Ranges<TimeDelta> MediaSourceState::ComputeRangesIntersection( | 28 Ranges<TimeDelta> MediaSourceState::ComputeRangesIntersection( |
22 const RangesList& activeRanges, | 29 const RangesList& activeRanges, |
23 bool ended) { | 30 bool ended) { |
24 // TODO(servolk): Perhaps this can be removed in favor of blink implementation | 31 // TODO(servolk): Perhaps this can be removed in favor of blink implementation |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 | 85 |
79 MediaSourceState::MediaSourceState( | 86 MediaSourceState::MediaSourceState( |
80 scoped_ptr<StreamParser> stream_parser, | 87 scoped_ptr<StreamParser> stream_parser, |
81 scoped_ptr<FrameProcessor> frame_processor, | 88 scoped_ptr<FrameProcessor> frame_processor, |
82 const CreateDemuxerStreamCB& create_demuxer_stream_cb, | 89 const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
83 const scoped_refptr<MediaLog>& media_log) | 90 const scoped_refptr<MediaLog>& media_log) |
84 : create_demuxer_stream_cb_(create_demuxer_stream_cb), | 91 : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
85 timestamp_offset_during_append_(NULL), | 92 timestamp_offset_during_append_(NULL), |
86 new_media_segment_(false), | 93 new_media_segment_(false), |
87 parsing_media_segment_(false), | 94 parsing_media_segment_(false), |
| 95 media_segment_contained_audio_frame_(false), |
| 96 media_segment_contained_video_frame_(false), |
88 stream_parser_(stream_parser.release()), | 97 stream_parser_(stream_parser.release()), |
89 audio_(NULL), | 98 audio_(NULL), |
90 video_(NULL), | 99 video_(NULL), |
91 frame_processor_(frame_processor.release()), | 100 frame_processor_(frame_processor.release()), |
92 media_log_(media_log), | 101 media_log_(media_log), |
93 auto_update_timestamp_offset_(false) { | 102 auto_update_timestamp_offset_(false) { |
94 DCHECK(!create_demuxer_stream_cb_.is_null()); | 103 DCHECK(!create_demuxer_stream_cb_.is_null()); |
95 DCHECK(frame_processor_); | 104 DCHECK(frame_processor_); |
96 } | 105 } |
97 | 106 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 DCHECK(!timestamp_offset_during_append_); | 182 DCHECK(!timestamp_offset_during_append_); |
174 timestamp_offset_during_append_ = timestamp_offset; | 183 timestamp_offset_during_append_ = timestamp_offset; |
175 append_window_start_during_append_ = append_window_start; | 184 append_window_start_during_append_ = append_window_start; |
176 append_window_end_during_append_ = append_window_end; | 185 append_window_end_during_append_ = append_window_end; |
177 | 186 |
178 stream_parser_->Flush(); | 187 stream_parser_->Flush(); |
179 timestamp_offset_during_append_ = NULL; | 188 timestamp_offset_during_append_ = NULL; |
180 | 189 |
181 frame_processor_->Reset(); | 190 frame_processor_->Reset(); |
182 parsing_media_segment_ = false; | 191 parsing_media_segment_ = false; |
| 192 media_segment_contained_audio_frame_ = false; |
| 193 media_segment_contained_video_frame_ = false; |
183 } | 194 } |
184 | 195 |
185 void MediaSourceState::Remove(TimeDelta start, | 196 void MediaSourceState::Remove(TimeDelta start, |
186 TimeDelta end, | 197 TimeDelta end, |
187 TimeDelta duration) { | 198 TimeDelta duration) { |
188 if (audio_) | 199 if (audio_) |
189 audio_->Remove(start, end, duration); | 200 audio_->Remove(start, end, duration); |
190 | 201 |
191 if (video_) | 202 if (video_) |
192 video_->Remove(start, end, duration); | 203 video_->Remove(start, end, duration); |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 if (success) | 641 if (success) |
631 init_segment_received_cb_.Run(); | 642 init_segment_received_cb_.Run(); |
632 | 643 |
633 return success; | 644 return success; |
634 } | 645 } |
635 | 646 |
636 void MediaSourceState::OnNewMediaSegment() { | 647 void MediaSourceState::OnNewMediaSegment() { |
637 DVLOG(2) << "OnNewMediaSegment()"; | 648 DVLOG(2) << "OnNewMediaSegment()"; |
638 parsing_media_segment_ = true; | 649 parsing_media_segment_ = true; |
639 new_media_segment_ = true; | 650 new_media_segment_ = true; |
| 651 media_segment_contained_audio_frame_ = false; |
| 652 media_segment_contained_video_frame_ = false; |
640 } | 653 } |
641 | 654 |
642 void MediaSourceState::OnEndOfMediaSegment() { | 655 void MediaSourceState::OnEndOfMediaSegment() { |
643 DVLOG(2) << "OnEndOfMediaSegment()"; | 656 DVLOG(2) << "OnEndOfMediaSegment()"; |
644 parsing_media_segment_ = false; | 657 parsing_media_segment_ = false; |
645 new_media_segment_ = false; | 658 new_media_segment_ = false; |
| 659 |
| 660 const bool missing_audio = audio_ && !media_segment_contained_audio_frame_; |
| 661 const bool missing_video = video_ && !media_segment_contained_video_frame_; |
| 662 if (!missing_audio && !missing_video) |
| 663 return; |
| 664 |
| 665 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_missing_track_logs_, |
| 666 kMaxMissingTrackInSegmentLogs) |
| 667 << "Media segment did not contain any " |
| 668 << (missing_audio && missing_video ? "audio or video" |
| 669 : missing_audio ? "audio" : "video") |
| 670 << " coded frames, mismatching initialization segment. Therefore, MSE " |
| 671 "coded frame processing may not interoperably detect discontinuities " |
| 672 "in appended media."; |
646 } | 673 } |
647 | 674 |
648 bool MediaSourceState::OnNewBuffers( | 675 bool MediaSourceState::OnNewBuffers( |
649 const StreamParser::BufferQueue& audio_buffers, | 676 const StreamParser::BufferQueue& audio_buffers, |
650 const StreamParser::BufferQueue& video_buffers, | 677 const StreamParser::BufferQueue& video_buffers, |
651 const StreamParser::TextBufferQueueMap& text_map) { | 678 const StreamParser::TextBufferQueueMap& text_map) { |
652 DVLOG(2) << "OnNewBuffers()"; | 679 DVLOG(2) << "OnNewBuffers()"; |
653 DCHECK(timestamp_offset_during_append_); | 680 DCHECK(timestamp_offset_during_append_); |
654 DCHECK(parsing_media_segment_); | 681 DCHECK(parsing_media_segment_); |
655 | 682 |
| 683 media_segment_contained_audio_frame_ |= !audio_buffers.empty(); |
| 684 media_segment_contained_video_frame_ |= !video_buffers.empty(); |
| 685 |
656 const TimeDelta timestamp_offset_before_processing = | 686 const TimeDelta timestamp_offset_before_processing = |
657 *timestamp_offset_during_append_; | 687 *timestamp_offset_during_append_; |
658 | 688 |
659 // Calculate the new timestamp offset for audio/video tracks if the stream | 689 // Calculate the new timestamp offset for audio/video tracks if the stream |
660 // parser has requested automatic updates. | 690 // parser has requested automatic updates. |
661 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; | 691 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; |
662 if (auto_update_timestamp_offset_) { | 692 if (auto_update_timestamp_offset_) { |
663 const bool have_audio_buffers = !audio_buffers.empty(); | 693 const bool have_audio_buffers = !audio_buffers.empty(); |
664 const bool have_video_buffers = !video_buffers.empty(); | 694 const bool have_video_buffers = !video_buffers.empty(); |
665 if (have_audio_buffers && have_video_buffers) { | 695 if (have_audio_buffers && have_video_buffers) { |
(...skipping 22 matching lines...) Expand all Loading... |
688 return true; | 718 return true; |
689 } | 719 } |
690 | 720 |
691 void MediaSourceState::OnSourceInitDone( | 721 void MediaSourceState::OnSourceInitDone( |
692 const StreamParser::InitParameters& params) { | 722 const StreamParser::InitParameters& params) { |
693 auto_update_timestamp_offset_ = params.auto_update_timestamp_offset; | 723 auto_update_timestamp_offset_ = params.auto_update_timestamp_offset; |
694 base::ResetAndReturn(&init_cb_).Run(params); | 724 base::ResetAndReturn(&init_cb_).Run(params); |
695 } | 725 } |
696 | 726 |
697 } // namespace media | 727 } // namespace media |
OLD | NEW |