| 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 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
| 13 #include "base/location.h" | 13 #include "base/location.h" |
| 14 #include "base/message_loop/message_loop_proxy.h" | 14 #include "base/message_loop/message_loop_proxy.h" |
| 15 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 16 #include "media/base/audio_decoder_config.h" | 16 #include "media/base/audio_decoder_config.h" |
| 17 #include "media/base/bind_to_current_loop.h" | 17 #include "media/base/bind_to_current_loop.h" |
| 18 #include "media/base/stream_parser_buffer.h" | 18 #include "media/base/stream_parser_buffer.h" |
| 19 #include "media/base/video_decoder_config.h" | 19 #include "media/base/video_decoder_config.h" |
| 20 #include "media/filters/frame_processor.h" |
| 20 #include "media/filters/legacy_frame_processor.h" | 21 #include "media/filters/legacy_frame_processor.h" |
| 21 #include "media/filters/stream_parser_factory.h" | 22 #include "media/filters/stream_parser_factory.h" |
| 22 | 23 |
| 23 using base::TimeDelta; | 24 using base::TimeDelta; |
| 24 | 25 |
| 25 namespace media { | 26 namespace media { |
| 26 | 27 |
| 27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { | 28 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { |
| 28 return queue.back()->timestamp() + queue.back()->duration(); | 29 return queue.back()->timestamp() + queue.back()->duration(); |
| 29 } | 30 } |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 // Calls Remove(|start|, |end|, |duration|) on all | 131 // Calls Remove(|start|, |end|, |duration|) on all |
| 131 // ChunkDemuxerStreams managed by this object. | 132 // ChunkDemuxerStreams managed by this object. |
| 132 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); | 133 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
| 133 | 134 |
| 134 // Returns true if currently parsing a media segment, or false otherwise. | 135 // Returns true if currently parsing a media segment, or false otherwise. |
| 135 bool parsing_media_segment() const { return parsing_media_segment_; } | 136 bool parsing_media_segment() const { return parsing_media_segment_; } |
| 136 | 137 |
| 137 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. | 138 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. |
| 138 void SetSequenceMode(bool sequence_mode); | 139 void SetSequenceMode(bool sequence_mode); |
| 139 | 140 |
| 141 // Signals the coded frame processor to update its group start timestamp to be |
| 142 // |timestamp_offset| if it is in sequence append mode. |
| 143 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset); |
| 144 |
| 140 // Returns the range of buffered data in this source, capped at |duration|. | 145 // Returns the range of buffered data in this source, capped at |duration|. |
| 141 // |ended| - Set to true if end of stream has been signalled and the special | 146 // |ended| - Set to true if end of stream has been signaled and the special |
| 142 // end of stream range logic needs to be executed. | 147 // end of stream range logic needs to be executed. |
| 143 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; | 148 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; |
| 144 | 149 |
| 145 // Returns the highest buffered duration across all streams managed | 150 // Returns the highest buffered duration across all streams managed |
| 146 // by this object. | 151 // by this object. |
| 147 // Returns TimeDelta() if none of the streams contain buffered data. | 152 // Returns TimeDelta() if none of the streams contain buffered data. |
| 148 TimeDelta GetMaxBufferedDuration() const; | 153 TimeDelta GetMaxBufferedDuration() const; |
| 149 | 154 |
| 150 // Helper methods that call methods with similar names on all the | 155 // Helper methods that call methods with similar names on all the |
| 151 // ChunkDemuxerStreams managed by this object. | 156 // ChunkDemuxerStreams managed by this object. |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), | 290 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), |
| 286 log_cb_); | 291 log_cb_); |
| 287 } | 292 } |
| 288 | 293 |
| 289 void SourceState::SetSequenceMode(bool sequence_mode) { | 294 void SourceState::SetSequenceMode(bool sequence_mode) { |
| 290 DCHECK(!parsing_media_segment_); | 295 DCHECK(!parsing_media_segment_); |
| 291 | 296 |
| 292 frame_processor_->SetSequenceMode(sequence_mode); | 297 frame_processor_->SetSequenceMode(sequence_mode); |
| 293 } | 298 } |
| 294 | 299 |
| 300 void SourceState::SetGroupStartTimestampIfInSequenceMode( |
| 301 base::TimeDelta timestamp_offset) { |
| 302 DCHECK(!parsing_media_segment_); |
| 303 |
| 304 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); |
| 305 } |
| 306 |
| 295 bool SourceState::Append(const uint8* data, size_t length, | 307 bool SourceState::Append(const uint8* data, size_t length, |
| 296 TimeDelta append_window_start, | 308 TimeDelta append_window_start, |
| 297 TimeDelta append_window_end, | 309 TimeDelta append_window_end, |
| 298 TimeDelta* timestamp_offset) { | 310 TimeDelta* timestamp_offset) { |
| 299 DCHECK(timestamp_offset); | 311 DCHECK(timestamp_offset); |
| 300 DCHECK(!timestamp_offset_during_append_); | 312 DCHECK(!timestamp_offset_during_append_); |
| 301 timestamp_offset_during_append_ = timestamp_offset; | |
| 302 append_window_start_during_append_ = append_window_start; | 313 append_window_start_during_append_ = append_window_start; |
| 303 append_window_end_during_append_ = append_window_end; | 314 append_window_end_during_append_ = append_window_end; |
| 315 timestamp_offset_during_append_ = timestamp_offset; |
| 304 | 316 |
| 305 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with | 317 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with |
| 306 // append window and timestamp offset pointer. See http://crbug.com/351454. | 318 // append window and timestamp offset pointer. See http://crbug.com/351454. |
| 307 bool err = stream_parser_->Parse(data, length); | 319 bool err = stream_parser_->Parse(data, length); |
| 308 timestamp_offset_during_append_ = NULL; | 320 timestamp_offset_during_append_ = NULL; |
| 309 return err; | 321 return err; |
| 310 } | 322 } |
| 311 | 323 |
| 312 void SourceState::Abort() { | 324 void SourceState::Abort() { |
| 313 stream_parser_->Flush(); | 325 stream_parser_->Flush(); |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 if (has_audio) | 1136 if (has_audio) |
| 1125 source_id_audio_ = id; | 1137 source_id_audio_ = id; |
| 1126 | 1138 |
| 1127 if (has_video) | 1139 if (has_video) |
| 1128 source_id_video_ = id; | 1140 source_id_video_ = id; |
| 1129 | 1141 |
| 1130 scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor( | 1142 scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor( |
| 1131 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, | 1143 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| 1132 base::Unretained(this)))); | 1144 base::Unretained(this)))); |
| 1133 | 1145 |
| 1146 // BIG TODO remove! |
| 1147 frame_processor.reset(new FrameProcessor( |
| 1148 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| 1149 base::Unretained(this)))); |
| 1150 |
| 1134 scoped_ptr<SourceState> source_state( | 1151 scoped_ptr<SourceState> source_state( |
| 1135 new SourceState(stream_parser.Pass(), | 1152 new SourceState(stream_parser.Pass(), |
| 1136 frame_processor.Pass(), log_cb_, | 1153 frame_processor.Pass(), log_cb_, |
| 1137 base::Bind(&ChunkDemuxer::CreateDemuxerStream, | 1154 base::Bind(&ChunkDemuxer::CreateDemuxerStream, |
| 1138 base::Unretained(this)))); | 1155 base::Unretained(this)))); |
| 1139 | 1156 |
| 1140 SourceState::NewTextTrackCB new_text_track_cb; | 1157 SourceState::NewTextTrackCB new_text_track_cb; |
| 1141 | 1158 |
| 1142 if (enable_text_) { | 1159 if (enable_text_) { |
| 1143 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, | 1160 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 void ChunkDemuxer::SetSequenceMode(const std::string& id, | 1361 void ChunkDemuxer::SetSequenceMode(const std::string& id, |
| 1345 bool sequence_mode) { | 1362 bool sequence_mode) { |
| 1346 base::AutoLock auto_lock(lock_); | 1363 base::AutoLock auto_lock(lock_); |
| 1347 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; | 1364 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; |
| 1348 CHECK(IsValidId(id)); | 1365 CHECK(IsValidId(id)); |
| 1349 DCHECK_NE(state_, ENDED); | 1366 DCHECK_NE(state_, ENDED); |
| 1350 | 1367 |
| 1351 source_state_map_[id]->SetSequenceMode(sequence_mode); | 1368 source_state_map_[id]->SetSequenceMode(sequence_mode); |
| 1352 } | 1369 } |
| 1353 | 1370 |
| 1371 void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode( |
| 1372 const std::string& id, |
| 1373 base::TimeDelta timestamp_offset) { |
| 1374 base::AutoLock auto_lock(lock_); |
| 1375 DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", " |
| 1376 << timestamp_offset.InSecondsF() << ")"; |
| 1377 CHECK(IsValidId(id)); |
| 1378 DCHECK_NE(state_, ENDED); |
| 1379 |
| 1380 source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode( |
| 1381 timestamp_offset); |
| 1382 } |
| 1383 |
| 1384 |
| 1354 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { | 1385 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { |
| 1355 DVLOG(1) << "MarkEndOfStream(" << status << ")"; | 1386 DVLOG(1) << "MarkEndOfStream(" << status << ")"; |
| 1356 base::AutoLock auto_lock(lock_); | 1387 base::AutoLock auto_lock(lock_); |
| 1357 DCHECK_NE(state_, WAITING_FOR_INIT); | 1388 DCHECK_NE(state_, WAITING_FOR_INIT); |
| 1358 DCHECK_NE(state_, ENDED); | 1389 DCHECK_NE(state_, ENDED); |
| 1359 | 1390 |
| 1360 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 1391 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
| 1361 return; | 1392 return; |
| 1362 | 1393 |
| 1363 if (state_ == INITIALIZING) { | 1394 if (state_ == INITIALIZING) { |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1545 | 1576 |
| 1546 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { | 1577 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { |
| 1547 DCHECK(duration_ != new_duration); | 1578 DCHECK(duration_ != new_duration); |
| 1548 user_specified_duration_ = -1; | 1579 user_specified_duration_ = -1; |
| 1549 duration_ = new_duration; | 1580 duration_ = new_duration; |
| 1550 host_->SetDuration(new_duration); | 1581 host_->SetDuration(new_duration); |
| 1551 } | 1582 } |
| 1552 | 1583 |
| 1553 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) { | 1584 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) { |
| 1554 DCHECK(new_duration != kNoTimestamp()); | 1585 DCHECK(new_duration != kNoTimestamp()); |
| 1586 DCHECK(new_duration != kInfiniteDuration()); |
| 1587 |
| 1588 // http://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-processing |
| 1589 // TODO(acolwell): Adjust the MSE spec text for this step to be like: |
| 1590 // 5. If highest presentation end timestamp is beyond the current duration, |
| 1591 // then run the duration change algorithm with new duration set to highest |
| 1592 // presentation end timestamp. |
| 1555 | 1593 |
| 1556 if (new_duration <= duration_) | 1594 if (new_duration <= duration_) |
| 1557 return; | 1595 return; |
| 1558 | 1596 |
| 1559 DVLOG(2) << __FUNCTION__ << ": Increasing duration: " | 1597 DVLOG(2) << __FUNCTION__ << ": Increasing duration: " |
| 1560 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF(); | 1598 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF(); |
| 1561 | 1599 |
| 1562 UpdateDuration(new_duration); | 1600 UpdateDuration(new_duration); |
| 1563 } | 1601 } |
| 1564 | 1602 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1629 } | 1667 } |
| 1630 | 1668 |
| 1631 void ChunkDemuxer::ShutdownAllStreams() { | 1669 void ChunkDemuxer::ShutdownAllStreams() { |
| 1632 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1670 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
| 1633 itr != source_state_map_.end(); ++itr) { | 1671 itr != source_state_map_.end(); ++itr) { |
| 1634 itr->second->Shutdown(); | 1672 itr->second->Shutdown(); |
| 1635 } | 1673 } |
| 1636 } | 1674 } |
| 1637 | 1675 |
| 1638 } // namespace media | 1676 } // namespace media |
| OLD | NEW |