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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 // Calls Remove(|start|, |end|, |duration|) on all | 126 // Calls Remove(|start|, |end|, |duration|) on all |
126 // ChunkDemuxerStreams managed by this object. | 127 // ChunkDemuxerStreams managed by this object. |
127 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); | 128 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); |
128 | 129 |
129 // Returns true if currently parsing a media segment, or false otherwise. | 130 // Returns true if currently parsing a media segment, or false otherwise. |
130 bool parsing_media_segment() const { return parsing_media_segment_; } | 131 bool parsing_media_segment() const { return parsing_media_segment_; } |
131 | 132 |
132 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. | 133 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. |
133 void SetSequenceMode(bool sequence_mode); | 134 void SetSequenceMode(bool sequence_mode); |
134 | 135 |
| 136 // Signals the coded frame processor to update its group start timestamp to be |
| 137 // |timestamp_offset| if it is in sequence append mode. |
| 138 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset); |
| 139 |
135 // Returns the range of buffered data in this source, capped at |duration|. | 140 // Returns the range of buffered data in this source, capped at |duration|. |
136 // |ended| - Set to true if end of stream has been signaled and the special | 141 // |ended| - Set to true if end of stream has been signaled and the special |
137 // end of stream range logic needs to be executed. | 142 // end of stream range logic needs to be executed. |
138 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; | 143 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; |
139 | 144 |
140 // Returns the highest buffered duration across all streams managed | 145 // Returns the highest buffered duration across all streams managed |
141 // by this object. | 146 // by this object. |
142 // Returns TimeDelta() if none of the streams contain buffered data. | 147 // Returns TimeDelta() if none of the streams contain buffered data. |
143 TimeDelta GetMaxBufferedDuration() const; | 148 TimeDelta GetMaxBufferedDuration() const; |
144 | 149 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 | 227 |
223 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; | 228 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; |
224 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. | 229 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. |
225 | 230 |
226 scoped_ptr<FrameProcessorBase> frame_processor_; | 231 scoped_ptr<FrameProcessorBase> frame_processor_; |
227 LogCB log_cb_; | 232 LogCB log_cb_; |
228 StreamParser::InitCB init_cb_; | 233 StreamParser::InitCB init_cb_; |
229 | 234 |
230 // Indicates that timestampOffset should be updated automatically during | 235 // Indicates that timestampOffset should be updated automatically during |
231 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. | 236 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. |
| 237 // TODO(wolenetz): Refactor this function while integrating April 29, 2014 |
| 238 // changes to MSE spec. See http://crbug.com/371499. |
232 bool auto_update_timestamp_offset_; | 239 bool auto_update_timestamp_offset_; |
233 | 240 |
234 DISALLOW_COPY_AND_ASSIGN(SourceState); | 241 DISALLOW_COPY_AND_ASSIGN(SourceState); |
235 }; | 242 }; |
236 | 243 |
237 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, | 244 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
238 scoped_ptr<FrameProcessorBase> frame_processor, | 245 scoped_ptr<FrameProcessorBase> frame_processor, |
239 const LogCB& log_cb, | 246 const LogCB& log_cb, |
240 const CreateDemuxerStreamCB& create_demuxer_stream_cb) | 247 const CreateDemuxerStreamCB& create_demuxer_stream_cb) |
241 : create_demuxer_stream_cb_(create_demuxer_stream_cb), | 248 : create_demuxer_stream_cb_(create_demuxer_stream_cb), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), | 286 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), |
280 log_cb_); | 287 log_cb_); |
281 } | 288 } |
282 | 289 |
283 void SourceState::SetSequenceMode(bool sequence_mode) { | 290 void SourceState::SetSequenceMode(bool sequence_mode) { |
284 DCHECK(!parsing_media_segment_); | 291 DCHECK(!parsing_media_segment_); |
285 | 292 |
286 frame_processor_->SetSequenceMode(sequence_mode); | 293 frame_processor_->SetSequenceMode(sequence_mode); |
287 } | 294 } |
288 | 295 |
| 296 void SourceState::SetGroupStartTimestampIfInSequenceMode( |
| 297 base::TimeDelta timestamp_offset) { |
| 298 DCHECK(!parsing_media_segment_); |
| 299 |
| 300 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); |
| 301 } |
| 302 |
289 bool SourceState::Append(const uint8* data, size_t length, | 303 bool SourceState::Append(const uint8* data, size_t length, |
290 TimeDelta append_window_start, | 304 TimeDelta append_window_start, |
291 TimeDelta append_window_end, | 305 TimeDelta append_window_end, |
292 TimeDelta* timestamp_offset) { | 306 TimeDelta* timestamp_offset) { |
293 DCHECK(timestamp_offset); | 307 DCHECK(timestamp_offset); |
294 DCHECK(!timestamp_offset_during_append_); | 308 DCHECK(!timestamp_offset_during_append_); |
295 timestamp_offset_during_append_ = timestamp_offset; | |
296 append_window_start_during_append_ = append_window_start; | 309 append_window_start_during_append_ = append_window_start; |
297 append_window_end_during_append_ = append_window_end; | 310 append_window_end_during_append_ = append_window_end; |
| 311 timestamp_offset_during_append_ = timestamp_offset; |
298 | 312 |
299 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with | 313 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with |
300 // append window and timestamp offset pointer. See http://crbug.com/351454. | 314 // append window and timestamp offset pointer. See http://crbug.com/351454. |
301 bool err = stream_parser_->Parse(data, length); | 315 bool err = stream_parser_->Parse(data, length); |
302 timestamp_offset_during_append_ = NULL; | 316 timestamp_offset_during_append_ = NULL; |
303 return err; | 317 return err; |
304 } | 318 } |
305 | 319 |
306 void SourceState::Abort(TimeDelta append_window_start, | 320 void SourceState::Abort(TimeDelta append_window_start, |
307 TimeDelta append_window_end, | 321 TimeDelta append_window_end, |
(...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 if ((has_audio && !source_id_audio_.empty()) || | 1163 if ((has_audio && !source_id_audio_.empty()) || |
1150 (has_video && !source_id_video_.empty())) | 1164 (has_video && !source_id_video_.empty())) |
1151 return kReachedIdLimit; | 1165 return kReachedIdLimit; |
1152 | 1166 |
1153 if (has_audio) | 1167 if (has_audio) |
1154 source_id_audio_ = id; | 1168 source_id_audio_ = id; |
1155 | 1169 |
1156 if (has_video) | 1170 if (has_video) |
1157 source_id_video_ = id; | 1171 source_id_video_ = id; |
1158 | 1172 |
1159 if (!use_legacy_frame_processor) { | 1173 scoped_ptr<FrameProcessorBase> frame_processor; |
1160 DLOG(WARNING) << "New frame processor is not yet supported. Using legacy."; | 1174 if (use_legacy_frame_processor) { |
| 1175 frame_processor.reset(new LegacyFrameProcessor( |
| 1176 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| 1177 base::Unretained(this)))); |
| 1178 } else { |
| 1179 frame_processor.reset(new FrameProcessor( |
| 1180 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
| 1181 base::Unretained(this)))); |
1161 } | 1182 } |
1162 | 1183 |
1163 scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor( | |
1164 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, | |
1165 base::Unretained(this)))); | |
1166 | |
1167 scoped_ptr<SourceState> source_state( | 1184 scoped_ptr<SourceState> source_state( |
1168 new SourceState(stream_parser.Pass(), | 1185 new SourceState(stream_parser.Pass(), |
1169 frame_processor.Pass(), log_cb_, | 1186 frame_processor.Pass(), log_cb_, |
1170 base::Bind(&ChunkDemuxer::CreateDemuxerStream, | 1187 base::Bind(&ChunkDemuxer::CreateDemuxerStream, |
1171 base::Unretained(this)))); | 1188 base::Unretained(this)))); |
1172 | 1189 |
1173 SourceState::NewTextTrackCB new_text_track_cb; | 1190 SourceState::NewTextTrackCB new_text_track_cb; |
1174 | 1191 |
1175 if (enable_text_) { | 1192 if (enable_text_) { |
1176 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, | 1193 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1382 void ChunkDemuxer::SetSequenceMode(const std::string& id, | 1399 void ChunkDemuxer::SetSequenceMode(const std::string& id, |
1383 bool sequence_mode) { | 1400 bool sequence_mode) { |
1384 base::AutoLock auto_lock(lock_); | 1401 base::AutoLock auto_lock(lock_); |
1385 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; | 1402 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; |
1386 CHECK(IsValidId(id)); | 1403 CHECK(IsValidId(id)); |
1387 DCHECK_NE(state_, ENDED); | 1404 DCHECK_NE(state_, ENDED); |
1388 | 1405 |
1389 source_state_map_[id]->SetSequenceMode(sequence_mode); | 1406 source_state_map_[id]->SetSequenceMode(sequence_mode); |
1390 } | 1407 } |
1391 | 1408 |
| 1409 void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode( |
| 1410 const std::string& id, |
| 1411 base::TimeDelta timestamp_offset) { |
| 1412 base::AutoLock auto_lock(lock_); |
| 1413 DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", " |
| 1414 << timestamp_offset.InSecondsF() << ")"; |
| 1415 CHECK(IsValidId(id)); |
| 1416 DCHECK_NE(state_, ENDED); |
| 1417 |
| 1418 source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode( |
| 1419 timestamp_offset); |
| 1420 } |
| 1421 |
| 1422 |
1392 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { | 1423 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { |
1393 DVLOG(1) << "MarkEndOfStream(" << status << ")"; | 1424 DVLOG(1) << "MarkEndOfStream(" << status << ")"; |
1394 base::AutoLock auto_lock(lock_); | 1425 base::AutoLock auto_lock(lock_); |
1395 DCHECK_NE(state_, WAITING_FOR_INIT); | 1426 DCHECK_NE(state_, WAITING_FOR_INIT); |
1396 DCHECK_NE(state_, ENDED); | 1427 DCHECK_NE(state_, ENDED); |
1397 | 1428 |
1398 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) | 1429 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) |
1399 return; | 1430 return; |
1400 | 1431 |
1401 if (state_ == INITIALIZING) { | 1432 if (state_ == INITIALIZING) { |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1612 | 1643 |
1613 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { | 1644 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { |
1614 DCHECK(duration_ != new_duration); | 1645 DCHECK(duration_ != new_duration); |
1615 user_specified_duration_ = -1; | 1646 user_specified_duration_ = -1; |
1616 duration_ = new_duration; | 1647 duration_ = new_duration; |
1617 host_->SetDuration(new_duration); | 1648 host_->SetDuration(new_duration); |
1618 } | 1649 } |
1619 | 1650 |
1620 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) { | 1651 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) { |
1621 DCHECK(new_duration != kNoTimestamp()); | 1652 DCHECK(new_duration != kNoTimestamp()); |
| 1653 DCHECK(new_duration != kInfiniteDuration()); |
| 1654 |
| 1655 // Per April 1, 2014 MSE spec editor's draft: |
| 1656 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/ |
| 1657 // media-source.html#sourcebuffer-coded-frame-processing |
| 1658 // 5. If the media segment contains data beyond the current duration, then run |
| 1659 // the duration change algorithm with new duration set to the maximum of |
| 1660 // the current duration and the group end timestamp. |
1622 | 1661 |
1623 if (new_duration <= duration_) | 1662 if (new_duration <= duration_) |
1624 return; | 1663 return; |
1625 | 1664 |
1626 DVLOG(2) << __FUNCTION__ << ": Increasing duration: " | 1665 DVLOG(2) << __FUNCTION__ << ": Increasing duration: " |
1627 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF(); | 1666 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF(); |
1628 | 1667 |
1629 UpdateDuration(new_duration); | 1668 UpdateDuration(new_duration); |
1630 } | 1669 } |
1631 | 1670 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1696 } | 1735 } |
1697 | 1736 |
1698 void ChunkDemuxer::ShutdownAllStreams() { | 1737 void ChunkDemuxer::ShutdownAllStreams() { |
1699 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1738 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
1700 itr != source_state_map_.end(); ++itr) { | 1739 itr != source_state_map_.end(); ++itr) { |
1701 itr->second->Shutdown(); | 1740 itr->second->Shutdown(); |
1702 } | 1741 } |
1703 } | 1742 } |
1704 | 1743 |
1705 } // namespace media | 1744 } // namespace media |
OLD | NEW |