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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 | 197 |
193 CreateDemuxerStreamCB create_demuxer_stream_cb_; | 198 CreateDemuxerStreamCB create_demuxer_stream_cb_; |
194 NewTextTrackCB new_text_track_cb_; | 199 NewTextTrackCB new_text_track_cb_; |
195 | 200 |
196 // During Append(), if OnNewBuffers() coded frame processing updates the | 201 // During Append(), if OnNewBuffers() coded frame processing updates the |
197 // timestamp offset then |*timestamp_offset_during_append_| is also updated | 202 // timestamp offset then |*timestamp_offset_during_append_| is also updated |
198 // so Append()'s caller can know the new offset. This pointer is only non-NULL | 203 // so Append()'s caller can know the new offset. This pointer is only non-NULL |
199 // during the lifetime of an Append() call. | 204 // during the lifetime of an Append() call. |
200 TimeDelta* timestamp_offset_during_append_; | 205 TimeDelta* timestamp_offset_during_append_; |
201 | 206 |
207 // During Append(), OnNewConfigs() will trigger the initialization segment | |
208 // received algorithm. This callback is only non-NULL during the lifetime of | |
209 // an Append() call. Note, the MSE spec explicitly disallows this algorithm | |
210 // during an Abort(), since Abort() is allowed only to emit coded frames, and | |
211 // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). | |
212 InitSegmentReceivedCB init_segment_received_cb_during_append_; | |
acolwell GONE FROM CHROMIUM
2014/09/10 18:02:38
nit: move cb_ to the end like all the other callba
wolenetz
2014/09/11 22:40:37
Done.
| |
213 | |
202 // During Append(), coded frame processing triggered by OnNewBuffers() | 214 // During Append(), coded frame processing triggered by OnNewBuffers() |
203 // requires these two attributes. These are only valid during the lifetime of | 215 // requires these two attributes. These are only valid during the lifetime of |
204 // an Append() call. | 216 // an Append() call. |
205 TimeDelta append_window_start_during_append_; | 217 TimeDelta append_window_start_during_append_; |
206 TimeDelta append_window_end_during_append_; | 218 TimeDelta append_window_end_during_append_; |
207 | 219 |
208 // Set to true if the next buffers appended within the append window | 220 // Set to true if the next buffers appended within the append window |
209 // represent the start of a new media segment. This flag being set | 221 // represent the start of a new media segment. This flag being set |
210 // triggers a call to |new_segment_cb_| when the new buffers are | 222 // triggers a call to |new_segment_cb_| when the new buffers are |
211 // appended. The flag is set on actual media segment boundaries and | 223 // appended. The flag is set on actual media segment boundaries and |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 frame_processor_->SetSequenceMode(sequence_mode); | 304 frame_processor_->SetSequenceMode(sequence_mode); |
293 } | 305 } |
294 | 306 |
295 void SourceState::SetGroupStartTimestampIfInSequenceMode( | 307 void SourceState::SetGroupStartTimestampIfInSequenceMode( |
296 base::TimeDelta timestamp_offset) { | 308 base::TimeDelta timestamp_offset) { |
297 DCHECK(!parsing_media_segment_); | 309 DCHECK(!parsing_media_segment_); |
298 | 310 |
299 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); | 311 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset); |
300 } | 312 } |
301 | 313 |
302 bool SourceState::Append(const uint8* data, size_t length, | 314 bool SourceState::Append( |
303 TimeDelta append_window_start, | 315 const uint8* data, |
304 TimeDelta append_window_end, | 316 size_t length, |
305 TimeDelta* timestamp_offset) { | 317 TimeDelta append_window_start, |
318 TimeDelta append_window_end, | |
319 TimeDelta* timestamp_offset, | |
320 const InitSegmentReceivedCB& init_segment_received_cb) { | |
306 DCHECK(timestamp_offset); | 321 DCHECK(timestamp_offset); |
307 DCHECK(!timestamp_offset_during_append_); | 322 DCHECK(!timestamp_offset_during_append_); |
323 DCHECK(init_segment_received_cb_during_append_.is_null()); | |
324 DCHECK(!init_segment_received_cb.is_null()); | |
308 append_window_start_during_append_ = append_window_start; | 325 append_window_start_during_append_ = append_window_start; |
309 append_window_end_during_append_ = append_window_end; | 326 append_window_end_during_append_ = append_window_end; |
310 timestamp_offset_during_append_ = timestamp_offset; | 327 timestamp_offset_during_append_ = timestamp_offset; |
328 init_segment_received_cb_during_append_ = init_segment_received_cb; | |
311 | 329 |
312 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with | 330 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with |
313 // append window and timestamp offset pointer. See http://crbug.com/351454. | 331 // append window and timestamp offset pointer. See http://crbug.com/351454. |
314 bool err = stream_parser_->Parse(data, length); | 332 bool err = stream_parser_->Parse(data, length); |
315 timestamp_offset_during_append_ = NULL; | 333 timestamp_offset_during_append_ = NULL; |
334 init_segment_received_cb_during_append_.Reset(); | |
316 return err; | 335 return err; |
317 } | 336 } |
318 | 337 |
319 void SourceState::Abort(TimeDelta append_window_start, | 338 void SourceState::Abort(TimeDelta append_window_start, |
320 TimeDelta append_window_end, | 339 TimeDelta append_window_end, |
321 base::TimeDelta* timestamp_offset) { | 340 base::TimeDelta* timestamp_offset) { |
322 DCHECK(timestamp_offset); | 341 DCHECK(timestamp_offset); |
323 DCHECK(!timestamp_offset_during_append_); | 342 DCHECK(!timestamp_offset_during_append_); |
324 timestamp_offset_during_append_ = timestamp_offset; | 343 timestamp_offset_during_append_ = timestamp_offset; |
325 append_window_start_during_append_ = append_window_start; | 344 append_window_start_during_append_ = append_window_start; |
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
658 << " does not match old one."; | 677 << " does not match old one."; |
659 break; | 678 break; |
660 } | 679 } |
661 } | 680 } |
662 } | 681 } |
663 } | 682 } |
664 | 683 |
665 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); | 684 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); |
666 | 685 |
667 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 686 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); |
687 if (success) | |
688 init_segment_received_cb_during_append_.Run(); | |
damienv1
2014/09/10 18:41:03
Can you DCHECK(!init_segment_received_cb_during_ap
wolenetz
2014/09/11 22:40:37
I'm confused. Running an is_null() callback should
wolenetz
2014/09/13 00:41:25
Done.
| |
689 | |
668 return success; | 690 return success; |
669 } | 691 } |
670 | 692 |
671 void SourceState::OnNewMediaSegment() { | 693 void SourceState::OnNewMediaSegment() { |
672 DVLOG(2) << "OnNewMediaSegment()"; | 694 DVLOG(2) << "OnNewMediaSegment()"; |
673 parsing_media_segment_ = true; | 695 parsing_media_segment_ = true; |
674 new_media_segment_ = true; | 696 new_media_segment_ = true; |
675 } | 697 } |
676 | 698 |
677 void SourceState::OnEndOfMediaSegment() { | 699 void SourceState::OnEndOfMediaSegment() { |
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1222 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { | 1244 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { |
1223 base::AutoLock auto_lock(lock_); | 1245 base::AutoLock auto_lock(lock_); |
1224 DCHECK(!id.empty()); | 1246 DCHECK(!id.empty()); |
1225 | 1247 |
1226 SourceStateMap::const_iterator itr = source_state_map_.find(id); | 1248 SourceStateMap::const_iterator itr = source_state_map_.find(id); |
1227 | 1249 |
1228 DCHECK(itr != source_state_map_.end()); | 1250 DCHECK(itr != source_state_map_.end()); |
1229 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); | 1251 return itr->second->GetBufferedRanges(duration_, state_ == ENDED); |
1230 } | 1252 } |
1231 | 1253 |
1232 void ChunkDemuxer::AppendData(const std::string& id, | 1254 void ChunkDemuxer::AppendData( |
1233 const uint8* data, size_t length, | 1255 const std::string& id, |
1234 TimeDelta append_window_start, | 1256 const uint8* data, |
1235 TimeDelta append_window_end, | 1257 size_t length, |
1236 TimeDelta* timestamp_offset) { | 1258 TimeDelta append_window_start, |
1259 TimeDelta append_window_end, | |
1260 TimeDelta* timestamp_offset, | |
1261 const InitSegmentReceivedCB& init_segment_received_cb) { | |
1237 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 1262 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
1238 | 1263 |
1239 DCHECK(!id.empty()); | 1264 DCHECK(!id.empty()); |
1240 DCHECK(timestamp_offset); | 1265 DCHECK(timestamp_offset); |
1266 DCHECK(!init_segment_received_cb.is_null()); | |
1241 | 1267 |
1242 Ranges<TimeDelta> ranges; | 1268 Ranges<TimeDelta> ranges; |
1243 | 1269 |
1244 { | 1270 { |
1245 base::AutoLock auto_lock(lock_); | 1271 base::AutoLock auto_lock(lock_); |
1246 DCHECK_NE(state_, ENDED); | 1272 DCHECK_NE(state_, ENDED); |
1247 | 1273 |
1248 // Capture if any of the SourceBuffers are waiting for data before we start | 1274 // Capture if any of the SourceBuffers are waiting for data before we start |
1249 // parsing. | 1275 // parsing. |
1250 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); | 1276 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); |
1251 | 1277 |
1252 if (length == 0u) | 1278 if (length == 0u) |
1253 return; | 1279 return; |
1254 | 1280 |
1255 DCHECK(data); | 1281 DCHECK(data); |
1256 | 1282 |
1257 switch (state_) { | 1283 switch (state_) { |
1258 case INITIALIZING: | 1284 case INITIALIZING: |
1259 DCHECK(IsValidId(id)); | 1285 DCHECK(IsValidId(id)); |
1260 if (!source_state_map_[id]->Append(data, length, | 1286 if (!source_state_map_[id]->Append(data, length, |
1261 append_window_start, | 1287 append_window_start, |
1262 append_window_end, | 1288 append_window_end, |
1263 timestamp_offset)) { | 1289 timestamp_offset, |
1290 init_segment_received_cb)) { | |
1264 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); | 1291 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); |
1265 return; | 1292 return; |
1266 } | 1293 } |
1267 break; | 1294 break; |
1268 | 1295 |
1269 case INITIALIZED: { | 1296 case INITIALIZED: { |
1270 DCHECK(IsValidId(id)); | 1297 DCHECK(IsValidId(id)); |
1271 if (!source_state_map_[id]->Append(data, length, | 1298 if (!source_state_map_[id]->Append(data, length, |
1272 append_window_start, | 1299 append_window_start, |
1273 append_window_end, | 1300 append_window_end, |
1274 timestamp_offset)) { | 1301 timestamp_offset, |
1302 init_segment_received_cb)) { | |
1275 ReportError_Locked(PIPELINE_ERROR_DECODE); | 1303 ReportError_Locked(PIPELINE_ERROR_DECODE); |
1276 return; | 1304 return; |
1277 } | 1305 } |
1278 } break; | 1306 } break; |
1279 | 1307 |
1280 case PARSE_ERROR: | 1308 case PARSE_ERROR: |
1281 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; | 1309 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; |
1282 return; | 1310 return; |
1283 | 1311 |
1284 case WAITING_FOR_INIT: | 1312 case WAITING_FOR_INIT: |
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1752 } | 1780 } |
1753 | 1781 |
1754 void ChunkDemuxer::ShutdownAllStreams() { | 1782 void ChunkDemuxer::ShutdownAllStreams() { |
1755 for (SourceStateMap::iterator itr = source_state_map_.begin(); | 1783 for (SourceStateMap::iterator itr = source_state_map_.begin(); |
1756 itr != source_state_map_.end(); ++itr) { | 1784 itr != source_state_map_.end(); ++itr) { |
1757 itr->second->Shutdown(); | 1785 itr->second->Shutdown(); |
1758 } | 1786 } |
1759 } | 1787 } |
1760 | 1788 |
1761 } // namespace media | 1789 } // namespace media |
OLD | NEW |