Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 547223003: MSE: Notify Blink SourceBuffer on init segment received (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address damienv's comment Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698