Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <list> | 9 #include <list> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 // processing decoder configurations. | 185 // processing decoder configurations. |
| 186 bool OnNewConfigs(bool allow_audio, bool allow_video, | 186 bool OnNewConfigs(bool allow_audio, bool allow_video, |
| 187 const AudioDecoderConfig& audio_config, | 187 const AudioDecoderConfig& audio_config, |
| 188 const VideoDecoderConfig& video_config, | 188 const VideoDecoderConfig& video_config, |
| 189 const StreamParser::TextTrackConfigMap& text_configs); | 189 const StreamParser::TextTrackConfigMap& text_configs); |
| 190 | 190 |
| 191 // Called by the |stream_parser_| at the beginning of a new media segment. | 191 // Called by the |stream_parser_| at the beginning of a new media segment. |
| 192 void OnNewMediaSegment(); | 192 void OnNewMediaSegment(); |
| 193 | 193 |
| 194 // Called by the |stream_parser_| at the end of a media segment. | 194 // Called by the |stream_parser_| at the end of a media segment. |
| 195 void OnEndOfMediaSegment(); | 195 bool OnEndOfMediaSegment(); |
| 196 | 196 |
| 197 // Called by the |stream_parser_| when new buffers have been parsed. | 197 // Called by the |stream_parser_| when new buffers have been parsed. |
| 198 // It processes the new buffers using |frame_processor_|, which includes | 198 // It processes the new buffers using |frame_processor_|, which includes |
| 199 // appending the processed frames to associated demuxer streams for each | 199 // appending the processed frames to associated demuxer streams for each |
| 200 // frame's track. | 200 // frame's track. |
| 201 // Returns true on a successful call. Returns false if an error occurred while | 201 // Returns true on a successful call. Returns false if an error occurred while |
| 202 // processing the buffers. | 202 // processing the buffers. |
| 203 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, | 203 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
| 204 const StreamParser::BufferQueue& video_buffers, | 204 const StreamParser::BufferQueue& video_buffers, |
| 205 const StreamParser::TextBufferQueueMap& text_map); | 205 const StreamParser::TextBufferQueueMap& text_map); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 233 // appended. The flag is set on actual media segment boundaries and | 233 // appended. The flag is set on actual media segment boundaries and |
| 234 // when the "append window" filtering causes discontinuities in the | 234 // when the "append window" filtering causes discontinuities in the |
| 235 // appended data. | 235 // appended data. |
| 236 // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame | 236 // TODO(wolenetz/acolwell): Investigate if we need this, or if coded frame |
| 237 // processing's discontinuity logic is enough. See http://crbug.com/351489. | 237 // processing's discontinuity logic is enough. See http://crbug.com/351489. |
| 238 bool new_media_segment_; | 238 bool new_media_segment_; |
| 239 | 239 |
| 240 // Keeps track of whether a media segment is being parsed. | 240 // Keeps track of whether a media segment is being parsed. |
| 241 bool parsing_media_segment_; | 241 bool parsing_media_segment_; |
| 242 | 242 |
| 243 // Valid only while |parsing_media_segment_| is true. These flags are to | |
| 244 // enforce adherence to MSE spec's requirement of at least one frame for each | |
| 245 // A/V track in each media segment. | |
| 246 bool media_segment_contained_audio_frame_; | |
| 247 bool media_segment_contained_video_frame_; | |
| 248 | |
| 243 // The object used to parse appended data. | 249 // The object used to parse appended data. |
| 244 scoped_ptr<StreamParser> stream_parser_; | 250 scoped_ptr<StreamParser> stream_parser_; |
| 245 | 251 |
| 246 ChunkDemuxerStream* audio_; // Not owned by |this|. | 252 ChunkDemuxerStream* audio_; // Not owned by |this|. |
| 247 ChunkDemuxerStream* video_; // Not owned by |this|. | 253 ChunkDemuxerStream* video_; // Not owned by |this|. |
| 248 | 254 |
| 249 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; | 255 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; |
| 250 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. | 256 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. |
| 251 | 257 |
| 252 scoped_ptr<FrameProcessor> frame_processor_; | 258 scoped_ptr<FrameProcessor> frame_processor_; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 270 }; | 276 }; |
| 271 | 277 |
| 272 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, | 278 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
| 273 scoped_ptr<FrameProcessor> frame_processor, | 279 scoped_ptr<FrameProcessor> frame_processor, |
| 274 const CreateDemuxerStreamCB& create_demuxer_stream_cb, | 280 const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
| 275 const scoped_refptr<MediaLog>& media_log) | 281 const scoped_refptr<MediaLog>& media_log) |
| 276 : create_demuxer_stream_cb_(create_demuxer_stream_cb), | 282 : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
| 277 timestamp_offset_during_append_(NULL), | 283 timestamp_offset_during_append_(NULL), |
| 278 new_media_segment_(false), | 284 new_media_segment_(false), |
| 279 parsing_media_segment_(false), | 285 parsing_media_segment_(false), |
| 286 media_segment_contained_audio_frame_(false), | |
| 287 media_segment_contained_video_frame_(false), | |
| 280 stream_parser_(stream_parser.release()), | 288 stream_parser_(stream_parser.release()), |
| 281 audio_(NULL), | 289 audio_(NULL), |
| 282 video_(NULL), | 290 video_(NULL), |
| 283 frame_processor_(frame_processor.release()), | 291 frame_processor_(frame_processor.release()), |
| 284 media_log_(media_log), | 292 media_log_(media_log), |
| 285 auto_update_timestamp_offset_(false) { | 293 auto_update_timestamp_offset_(false) { |
| 286 DCHECK(!create_demuxer_stream_cb_.is_null()); | 294 DCHECK(!create_demuxer_stream_cb_.is_null()); |
| 287 DCHECK(frame_processor_); | 295 DCHECK(frame_processor_); |
| 288 } | 296 } |
| 289 | 297 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 350 << __FUNCTION__ << ": stream parsing failed." | 358 << __FUNCTION__ << ": stream parsing failed." |
| 351 << " Data size=" << length | 359 << " Data size=" << length |
| 352 << " append_window_start=" << append_window_start.InSecondsF() | 360 << " append_window_start=" << append_window_start.InSecondsF() |
| 353 << " append_window_end=" << append_window_end.InSecondsF(); | 361 << " append_window_end=" << append_window_end.InSecondsF(); |
| 354 } | 362 } |
| 355 timestamp_offset_during_append_ = NULL; | 363 timestamp_offset_during_append_ = NULL; |
| 356 init_segment_received_cb_.Reset(); | 364 init_segment_received_cb_.Reset(); |
| 357 return result; | 365 return result; |
| 358 } | 366 } |
| 359 | 367 |
| 360 void SourceState::ResetParserState(TimeDelta append_window_start, | 368 void SourceState::ResetParserState(TimeDelta append_window_start, |
|
chcunningham
2016/01/07 22:23:56
Should you set media_segment_contained_{video|audi
wolenetz
2016/01/16 01:23:35
Good idea for at least maintainability. Done (in M
| |
| 361 TimeDelta append_window_end, | 369 TimeDelta append_window_end, |
| 362 base::TimeDelta* timestamp_offset) { | 370 base::TimeDelta* timestamp_offset) { |
| 363 DCHECK(timestamp_offset); | 371 DCHECK(timestamp_offset); |
| 364 DCHECK(!timestamp_offset_during_append_); | 372 DCHECK(!timestamp_offset_during_append_); |
| 365 timestamp_offset_during_append_ = timestamp_offset; | 373 timestamp_offset_during_append_ = timestamp_offset; |
| 366 append_window_start_during_append_ = append_window_start; | 374 append_window_start_during_append_ = append_window_start; |
| 367 append_window_end_during_append_ = append_window_end; | 375 append_window_end_during_append_ = append_window_end; |
| 368 | 376 |
| 369 stream_parser_->Flush(); | 377 stream_parser_->Flush(); |
| 370 timestamp_offset_during_append_ = NULL; | 378 timestamp_offset_during_append_ = NULL; |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 818 if (success) | 826 if (success) |
| 819 init_segment_received_cb_.Run(); | 827 init_segment_received_cb_.Run(); |
| 820 | 828 |
| 821 return success; | 829 return success; |
| 822 } | 830 } |
| 823 | 831 |
| 824 void SourceState::OnNewMediaSegment() { | 832 void SourceState::OnNewMediaSegment() { |
| 825 DVLOG(2) << "OnNewMediaSegment()"; | 833 DVLOG(2) << "OnNewMediaSegment()"; |
| 826 parsing_media_segment_ = true; | 834 parsing_media_segment_ = true; |
| 827 new_media_segment_ = true; | 835 new_media_segment_ = true; |
| 836 media_segment_contained_audio_frame_ = false; | |
| 837 media_segment_contained_video_frame_ = false; | |
| 828 } | 838 } |
| 829 | 839 |
| 830 void SourceState::OnEndOfMediaSegment() { | 840 bool SourceState::OnEndOfMediaSegment() { |
| 831 DVLOG(2) << "OnEndOfMediaSegment()"; | 841 DVLOG(2) << "OnEndOfMediaSegment()"; |
| 832 parsing_media_segment_ = false; | 842 parsing_media_segment_ = false; |
| 833 new_media_segment_ = false; | 843 new_media_segment_ = false; |
| 844 | |
| 845 const bool missing_audio = audio_ && !media_segment_contained_audio_frame_; | |
| 846 const bool missing_video = video_ && !media_segment_contained_video_frame_; | |
| 847 if (missing_audio || missing_video) { | |
| 848 MEDIA_LOG(ERROR, media_log_) | |
| 849 << "Media segment did not contain any " | |
| 850 << (missing_audio && missing_video ? "audio or video" | |
| 851 : missing_audio ? "audio" : "video") | |
| 852 << " coded frames, mismatching initialization segment"; | |
| 853 return false; | |
| 854 } | |
| 855 | |
| 856 return true; | |
| 834 } | 857 } |
| 835 | 858 |
| 836 bool SourceState::OnNewBuffers( | 859 bool SourceState::OnNewBuffers( |
| 837 const StreamParser::BufferQueue& audio_buffers, | 860 const StreamParser::BufferQueue& audio_buffers, |
| 838 const StreamParser::BufferQueue& video_buffers, | 861 const StreamParser::BufferQueue& video_buffers, |
| 839 const StreamParser::TextBufferQueueMap& text_map) { | 862 const StreamParser::TextBufferQueueMap& text_map) { |
| 840 DVLOG(2) << "OnNewBuffers()"; | 863 DVLOG(2) << "OnNewBuffers()"; |
| 841 DCHECK(timestamp_offset_during_append_); | 864 DCHECK(timestamp_offset_during_append_); |
| 842 DCHECK(parsing_media_segment_); | 865 DCHECK(parsing_media_segment_); |
| 843 | 866 |
| 867 media_segment_contained_audio_frame_ |= !audio_buffers.empty(); | |
| 868 media_segment_contained_video_frame_ |= !video_buffers.empty(); | |
| 869 | |
| 844 const TimeDelta timestamp_offset_before_processing = | 870 const TimeDelta timestamp_offset_before_processing = |
| 845 *timestamp_offset_during_append_; | 871 *timestamp_offset_during_append_; |
| 846 | 872 |
| 847 // Calculate the new timestamp offset for audio/video tracks if the stream | 873 // Calculate the new timestamp offset for audio/video tracks if the stream |
| 848 // parser has requested automatic updates. | 874 // parser has requested automatic updates. |
| 849 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; | 875 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; |
| 850 if (auto_update_timestamp_offset_) { | 876 if (auto_update_timestamp_offset_) { |
| 851 const bool have_audio_buffers = !audio_buffers.empty(); | 877 const bool have_audio_buffers = !audio_buffers.empty(); |
| 852 const bool have_video_buffers = !video_buffers.empty(); | 878 const bool have_video_buffers = !video_buffers.empty(); |
| 853 if (have_audio_buffers && have_video_buffers) { | 879 if (have_audio_buffers && have_video_buffers) { |
| (...skipping 1113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1967 } | 1993 } |
| 1968 | 1994 |
| 1969 void ChunkDemuxer::ShutdownAllStreams() { | 1995 void ChunkDemuxer::ShutdownAllStreams() { |
| 1970 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1996 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
| 1971 itr != source_state_map_.end(); ++itr) { | 1997 itr != source_state_map_.end(); ++itr) { |
| 1972 itr->second->Shutdown(); | 1998 itr->second->Shutdown(); |
| 1973 } | 1999 } |
| 1974 } | 2000 } |
| 1975 | 2001 |
| 1976 } // namespace media | 2002 } // namespace media |
| OLD | NEW |