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 | 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 |