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

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: Fixed nits. Plan is to depend on blink-side CL landing first (https://codereview.chromium.org/55294… 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
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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698