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 | 10 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 return intersection_ranges; | 83 return intersection_ranges; |
84 } | 84 } |
85 | 85 |
86 // Contains state belonging to a source id. | 86 // Contains state belonging to a source id. |
87 class SourceState { | 87 class SourceState { |
88 public: | 88 public: |
89 // Callback signature used to create ChunkDemuxerStreams. | 89 // Callback signature used to create ChunkDemuxerStreams. |
90 typedef base::Callback<ChunkDemuxerStream*( | 90 typedef base::Callback<ChunkDemuxerStream*( |
91 DemuxerStream::Type)> CreateDemuxerStreamCB; | 91 DemuxerStream::Type)> CreateDemuxerStreamCB; |
92 | 92 |
| 93 typedef ChunkDemuxer::InitSegmentReceivedCB InitSegmentReceivedCB; |
| 94 |
93 typedef base::Callback<void( | 95 typedef base::Callback<void( |
94 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; | 96 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; |
95 | 97 |
96 SourceState( | 98 SourceState( |
97 scoped_ptr<StreamParser> stream_parser, | 99 scoped_ptr<StreamParser> stream_parser, |
98 scoped_ptr<FrameProcessor> frame_processor, const LogCB& log_cb, | 100 scoped_ptr<FrameProcessor> frame_processor, const LogCB& log_cb, |
99 const CreateDemuxerStreamCB& create_demuxer_stream_cb); | 101 const CreateDemuxerStreamCB& create_demuxer_stream_cb); |
100 | 102 |
101 ~SourceState(); | 103 ~SourceState(); |
102 | 104 |
103 void Init(const StreamParser::InitCB& init_cb, | 105 void Init(const StreamParser::InitCB& init_cb, |
104 bool allow_audio, | 106 bool allow_audio, |
105 bool allow_video, | 107 bool allow_video, |
106 const StreamParser::NeedKeyCB& need_key_cb, | 108 const StreamParser::NeedKeyCB& need_key_cb, |
107 const NewTextTrackCB& new_text_track_cb); | 109 const NewTextTrackCB& new_text_track_cb); |
108 | 110 |
109 // Appends new data to the StreamParser. | 111 // Appends new data to the StreamParser. |
110 // Returns true if the data was successfully appended. Returns false if an | 112 // Returns true if the data was successfully appended. Returns false if an |
111 // error occurred. |*timestamp_offset| is used and possibly updated by the | 113 // error occurred. |*timestamp_offset| is used and possibly updated by the |
112 // append. |append_window_start| and |append_window_end| correspond to the MSE | 114 // append. |append_window_start| and |append_window_end| correspond to the MSE |
113 // spec's similarly named source buffer attributes that are used in coded | 115 // spec's similarly named source buffer attributes that are used in coded |
114 // frame processing. | 116 // frame processing. |init_segment_received_cb| is run for each new fully |
115 bool Append(const uint8* data, size_t length, | 117 // parsed initialization segment. |
| 118 bool Append(const uint8* data, |
| 119 size_t length, |
116 TimeDelta append_window_start, | 120 TimeDelta append_window_start, |
117 TimeDelta append_window_end, | 121 TimeDelta append_window_end, |
118 TimeDelta* timestamp_offset); | 122 TimeDelta* timestamp_offset, |
| 123 const InitSegmentReceivedCB& init_segment_received_cb); |
119 | 124 |
120 // Aborts the current append sequence and resets the parser. | 125 // Aborts the current append sequence and resets the parser. |
121 void Abort(TimeDelta append_window_start, | 126 void Abort(TimeDelta append_window_start, |
122 TimeDelta append_window_end, | 127 TimeDelta append_window_end, |
123 TimeDelta* timestamp_offset); | 128 TimeDelta* timestamp_offset); |
124 | 129 |
125 // Calls Remove(|start|, |end|, |duration|) on all | 130 // Calls Remove(|start|, |end|, |duration|) on all |
126 // ChunkDemuxerStreams managed by this object. | 131 // ChunkDemuxerStreams managed by this object. |
127 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); | 132 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
128 | 133 |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 ChunkDemuxerStream* audio_; // Not owned by |this|. | 230 ChunkDemuxerStream* audio_; // Not owned by |this|. |
226 ChunkDemuxerStream* video_; // Not owned by |this|. | 231 ChunkDemuxerStream* video_; // Not owned by |this|. |
227 | 232 |
228 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; | 233 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; |
229 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. | 234 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. |
230 | 235 |
231 scoped_ptr<FrameProcessor> frame_processor_; | 236 scoped_ptr<FrameProcessor> frame_processor_; |
232 LogCB log_cb_; | 237 LogCB log_cb_; |
233 StreamParser::InitCB init_cb_; | 238 StreamParser::InitCB init_cb_; |
234 | 239 |
| 240 // During Append(), OnNewConfigs() will trigger the initialization segment |
| 241 // received algorithm. This callback is only non-NULL during the lifetime of |
| 242 // an Append() call. Note, the MSE spec explicitly disallows this algorithm |
| 243 // during an Abort(), since Abort() is allowed only to emit coded frames, and |
| 244 // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). |
| 245 InitSegmentReceivedCB init_segment_received_cb_; |
| 246 |
235 // Indicates that timestampOffset should be updated automatically during | 247 // Indicates that timestampOffset should be updated automatically during |
236 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. | 248 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. |
237 // TODO(wolenetz): Refactor this function while integrating April 29, 2014 | 249 // TODO(wolenetz): Refactor this function while integrating April 29, 2014 |
238 // changes to MSE spec. See http://crbug.com/371499. | 250 // changes to MSE spec. See http://crbug.com/371499. |
239 bool auto_update_timestamp_offset_; | 251 bool auto_update_timestamp_offset_; |
240 | 252 |
241 DISALLOW_COPY_AND_ASSIGN(SourceState); | 253 DISALLOW_COPY_AND_ASSIGN(SourceState); |
242 }; | 254 }; |
243 | 255 |
244 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, | 256 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 frame_processor_->SetSequenceMode(sequence_mode); | 305 frame_processor_->SetSequenceMode(sequence_mode); |
294 } | 306 } |
295 | 307 |
296 void SourceState::SetGroupStartTimestampIfInSequenceMode( | 308 void SourceState::SetGroupStartTimestampIfInSequenceMode( |
297 base::TimeDelta timestamp_offset) { | 309 base::TimeDelta timestamp_offset) { |
298 DCHECK(!parsing_media_segment_); | 310 DCHECK(!parsing_media_segment_); |
299 | 311 |
300 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); | 312 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); |
301 } | 313 } |
302 | 314 |
303 bool SourceState::Append(const uint8* data, size_t length, | 315 bool SourceState::Append( |
304 TimeDelta append_window_start, | 316 const uint8* data, |
305 TimeDelta append_window_end, | 317 size_t length, |
306 TimeDelta* timestamp_offset) { | 318 TimeDelta append_window_start, |
| 319 TimeDelta append_window_end, |
| 320 TimeDelta* timestamp_offset, |
| 321 const InitSegmentReceivedCB& init_segment_received_cb) { |
307 DCHECK(timestamp_offset); | 322 DCHECK(timestamp_offset); |
308 DCHECK(!timestamp_offset_during_append_); | 323 DCHECK(!timestamp_offset_during_append_); |
| 324 DCHECK(!init_segment_received_cb.is_null()); |
| 325 DCHECK(init_segment_received_cb_.is_null()); |
309 append_window_start_during_append_ = append_window_start; | 326 append_window_start_during_append_ = append_window_start; |
310 append_window_end_during_append_ = append_window_end; | 327 append_window_end_during_append_ = append_window_end; |
311 timestamp_offset_during_append_ = timestamp_offset; | 328 timestamp_offset_during_append_ = timestamp_offset; |
| 329 init_segment_received_cb_= init_segment_received_cb; |
312 | 330 |
313 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with | 331 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with |
314 // append window and timestamp offset pointer. See http://crbug.com/351454. | 332 // append window and timestamp offset pointer. See http://crbug.com/351454. |
315 bool err = stream_parser_->Parse(data, length); | 333 bool err = stream_parser_->Parse(data, length); |
316 timestamp_offset_during_append_ = NULL; | 334 timestamp_offset_during_append_ = NULL; |
| 335 init_segment_received_cb_.Reset(); |
317 return err; | 336 return err; |
318 } | 337 } |
319 | 338 |
320 void SourceState::Abort(TimeDelta append_window_start, | 339 void SourceState::Abort(TimeDelta append_window_start, |
321 TimeDelta append_window_end, | 340 TimeDelta append_window_end, |
322 base::TimeDelta* timestamp_offset) { | 341 base::TimeDelta* timestamp_offset) { |
323 DCHECK(timestamp_offset); | 342 DCHECK(timestamp_offset); |
324 DCHECK(!timestamp_offset_during_append_); | 343 DCHECK(!timestamp_offset_during_append_); |
325 timestamp_offset_during_append_ = timestamp_offset; | 344 timestamp_offset_during_append_ = timestamp_offset; |
326 append_window_start_during_append_ = append_window_start; | 345 append_window_start_during_append_ = append_window_start; |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 } | 546 } |
528 | 547 |
529 bool SourceState::OnNewConfigs( | 548 bool SourceState::OnNewConfigs( |
530 bool allow_audio, bool allow_video, | 549 bool allow_audio, bool allow_video, |
531 const AudioDecoderConfig& audio_config, | 550 const AudioDecoderConfig& audio_config, |
532 const VideoDecoderConfig& video_config, | 551 const VideoDecoderConfig& video_config, |
533 const StreamParser::TextTrackConfigMap& text_configs) { | 552 const StreamParser::TextTrackConfigMap& text_configs) { |
534 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video | 553 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video |
535 << ", " << audio_config.IsValidConfig() | 554 << ", " << audio_config.IsValidConfig() |
536 << ", " << video_config.IsValidConfig() << ")"; | 555 << ", " << video_config.IsValidConfig() << ")"; |
| 556 DCHECK(!init_segment_received_cb_.is_null()); |
537 | 557 |
538 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { | 558 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { |
539 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; | 559 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; |
540 return false; | 560 return false; |
541 } | 561 } |
542 | 562 |
543 // Signal an error if we get configuration info for stream types that weren't | 563 // Signal an error if we get configuration info for stream types that weren't |
544 // specified in AddId() or more configs after a stream is initialized. | 564 // specified in AddId() or more configs after a stream is initialized. |
545 if (allow_audio != audio_config.IsValidConfig()) { | 565 if (allow_audio != audio_config.IsValidConfig()) { |
546 MEDIA_LOG(log_cb_) | 566 MEDIA_LOG(log_cb_) |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 << " does not match old one."; | 689 << " does not match old one."; |
670 break; | 690 break; |
671 } | 691 } |
672 } | 692 } |
673 } | 693 } |
674 } | 694 } |
675 | 695 |
676 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); | 696 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); |
677 | 697 |
678 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 698 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); |
| 699 if (success) |
| 700 init_segment_received_cb_.Run(); |
| 701 |
679 return success; | 702 return success; |
680 } | 703 } |
681 | 704 |
682 void SourceState::OnNewMediaSegment() { | 705 void SourceState::OnNewMediaSegment() { |
683 DVLOG(2) << "OnNewMediaSegment()"; | 706 DVLOG(2) << "OnNewMediaSegment()"; |
684 parsing_media_segment_ = true; | 707 parsing_media_segment_ = true; |
685 new_media_segment_ = true; | 708 new_media_segment_ = true; |
686 } | 709 } |
687 | 710 |
688 void SourceState::OnEndOfMediaSegment() { | 711 void SourceState::OnEndOfMediaSegment() { |
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1231 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 1254 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
1232 base::AutoLock auto_lock(lock_); | 1255 base::AutoLock auto_lock(lock_); |
1233 DCHECK(!id.empty()); | 1256 DCHECK(!id.empty()); |
1234 | 1257 |
1235 SourceStateMap::const_iterator itr = source_state_map_.find(id); | 1258 SourceStateMap::const_iterator itr = source_state_map_.find(id); |
1236 | 1259 |
1237 DCHECK(itr != source_state_map_.end()); | 1260 DCHECK(itr != source_state_map_.end()); |
1238 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); | 1261 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); |
1239 } | 1262 } |
1240 | 1263 |
1241 void ChunkDemuxer::AppendData(const std::string& id, | 1264 void ChunkDemuxer::AppendData( |
1242 const uint8* data, size_t length, | 1265 const std::string& id, |
1243 TimeDelta append_window_start, | 1266 const uint8* data, |
1244 TimeDelta append_window_end, | 1267 size_t length, |
1245 TimeDelta* timestamp_offset) { | 1268 TimeDelta append_window_start, |
| 1269 TimeDelta append_window_end, |
| 1270 TimeDelta* timestamp_offset, |
| 1271 const InitSegmentReceivedCB& init_segment_received_cb) { |
1246 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 1272 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
1247 | 1273 |
1248 DCHECK(!id.empty()); | 1274 DCHECK(!id.empty()); |
1249 DCHECK(timestamp_offset); | 1275 DCHECK(timestamp_offset); |
| 1276 DCHECK(!init_segment_received_cb.is_null()); |
1250 | 1277 |
1251 Ranges<TimeDelta> ranges; | 1278 Ranges<TimeDelta> ranges; |
1252 | 1279 |
1253 { | 1280 { |
1254 base::AutoLock auto_lock(lock_); | 1281 base::AutoLock auto_lock(lock_); |
1255 DCHECK_NE(state_, ENDED); | 1282 DCHECK_NE(state_, ENDED); |
1256 | 1283 |
1257 // Capture if any of the SourceBuffers are waiting for data before we start | 1284 // Capture if any of the SourceBuffers are waiting for data before we start |
1258 // parsing. | 1285 // parsing. |
1259 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); | 1286 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); |
1260 | 1287 |
1261 if (length == 0u) | 1288 if (length == 0u) |
1262 return; | 1289 return; |
1263 | 1290 |
1264 DCHECK(data); | 1291 DCHECK(data); |
1265 | 1292 |
1266 switch (state_) { | 1293 switch (state_) { |
1267 case INITIALIZING: | 1294 case INITIALIZING: |
1268 DCHECK(IsValidId(id)); | 1295 DCHECK(IsValidId(id)); |
1269 if (!source_state_map_[id]->Append(data, length, | 1296 if (!source_state_map_[id]->Append(data, length, |
1270 append_window_start, | 1297 append_window_start, |
1271 append_window_end, | 1298 append_window_end, |
1272 timestamp_offset)) { | 1299 timestamp_offset, |
| 1300 init_segment_received_cb)) { |
1273 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1301 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
1274 return; | 1302 return; |
1275 } | 1303 } |
1276 break; | 1304 break; |
1277 | 1305 |
1278 case INITIALIZED: { | 1306 case INITIALIZED: { |
1279 DCHECK(IsValidId(id)); | 1307 DCHECK(IsValidId(id)); |
1280 if (!source_state_map_[id]->Append(data, length, | 1308 if (!source_state_map_[id]->Append(data, length, |
1281 append_window_start, | 1309 append_window_start, |
1282 append_window_end, | 1310 append_window_end, |
1283 timestamp_offset)) { | 1311 timestamp_offset, |
| 1312 init_segment_received_cb)) { |
1284 ReportError_Locked(PIPELINE_ERROR_DECODE); | 1313 ReportError_Locked(PIPELINE_ERROR_DECODE); |
1285 return; | 1314 return; |
1286 } | 1315 } |
1287 } break; | 1316 } break; |
1288 | 1317 |
1289 case PARSE_ERROR: | 1318 case PARSE_ERROR: |
1290 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; | 1319 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; |
1291 return; | 1320 return; |
1292 | 1321 |
1293 case WAITING_FOR_INIT: | 1322 case WAITING_FOR_INIT: |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 } | 1790 } |
1762 | 1791 |
1763 void ChunkDemuxer::ShutdownAllStreams() { | 1792 void ChunkDemuxer::ShutdownAllStreams() { |
1764 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1793 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
1765 itr != source_state_map_.end(); ++itr) { | 1794 itr != source_state_map_.end(); ++itr) { |
1766 itr->second->Shutdown(); | 1795 itr->second->Shutdown(); |
1767 } | 1796 } |
1768 } | 1797 } |
1769 | 1798 |
1770 } // namespace media | 1799 } // namespace media |
OLD | NEW |