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

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

Issue 2226443002: Support multiple media tracks in MSE / ChunkDemuxer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed integer overflow Created 4 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/media_source_state.h ('k') | media/filters/stream_parser_factory.h » ('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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/media_source_state.h" 5 #include "media/filters/media_source_state.h"
6 6
7 #include <set>
8
7 #include "base/callback_helpers.h" 9 #include "base/callback_helpers.h"
8 #include "base/command_line.h" 10 #include "base/command_line.h"
9 #include "base/stl_util.h" 11 #include "base/stl_util.h"
10 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
11 #include "media/base/media_switches.h" 13 #include "media/base/media_switches.h"
12 #include "media/base/media_track.h" 14 #include "media/base/media_track.h"
13 #include "media/base/media_tracks.h" 15 #include "media/base/media_tracks.h"
16 #include "media/base/mime_util.h"
14 #include "media/filters/chunk_demuxer.h" 17 #include "media/filters/chunk_demuxer.h"
15 #include "media/filters/frame_processor.h" 18 #include "media/filters/frame_processor.h"
16 #include "media/filters/source_buffer_stream.h" 19 #include "media/filters/source_buffer_stream.h"
17 20
18 namespace media { 21 namespace media {
19 22
20 enum { 23 enum {
21 // Limits the number of MEDIA_LOG() calls warning the user that a muxed stream 24 // Limits the number of MEDIA_LOG() calls warning the user that a muxed stream
22 // media segment is missing a block from at least one of the audio or video 25 // media segment is missing a block from at least one of the audio or video
23 // tracks. 26 // tracks.
24 kMaxMissingTrackInSegmentLogs = 10, 27 kMaxMissingTrackInSegmentLogs = 10,
25 }; 28 };
26 29
27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { 30 namespace {
31
32 TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) {
28 return queue.back()->timestamp() + queue.back()->duration(); 33 return queue.back()->timestamp() + queue.back()->duration();
29 } 34 }
30 35
36 // Check the input |text_configs| and |bytestream_ids| and return false if
37 // duplicate track ids are detected.
38 bool CheckBytestreamTrackIds(
39 const MediaTracks& tracks,
40 const StreamParser::TextTrackConfigMap& text_configs) {
41 std::set<StreamParser::TrackId> bytestream_ids;
42 for (const auto& track : tracks.tracks()) {
43 const StreamParser::TrackId& track_id = track->bytestream_track_id();
44 if (bytestream_ids.find(track_id) != bytestream_ids.end()) {
45 return false;
46 }
47 bytestream_ids.insert(track_id);
48 }
49 for (const auto& text_track : text_configs) {
50 const StreamParser::TrackId& track_id = text_track.first;
51 if (bytestream_ids.find(track_id) != bytestream_ids.end()) {
52 return false;
53 }
54 bytestream_ids.insert(track_id);
55 }
56 return true;
57 }
58
59 } // namespace
60
31 // List of time ranges for each SourceBuffer. 61 // List of time ranges for each SourceBuffer.
32 // static 62 // static
33 Ranges<TimeDelta> MediaSourceState::ComputeRangesIntersection( 63 Ranges<TimeDelta> MediaSourceState::ComputeRangesIntersection(
34 const RangesList& active_ranges, 64 const RangesList& active_ranges,
35 bool ended) { 65 bool ended) {
36 // TODO(servolk): Perhaps this can be removed in favor of blink implementation 66 // TODO(servolk): Perhaps this can be removed in favor of blink implementation
37 // (MediaSource::buffered)? Currently this is only used on Android and for 67 // (MediaSource::buffered)? Currently this is only used on Android and for
38 // updating DemuxerHost's buffered ranges during AppendData() as well as 68 // updating DemuxerHost's buffered ranges during AppendData() as well as
39 // SourceBuffer.buffered property implemetation. 69 // SourceBuffer.buffered property implemetation.
40 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec. 70 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec.
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 } 117 }
88 118
89 MediaSourceState::MediaSourceState( 119 MediaSourceState::MediaSourceState(
90 std::unique_ptr<StreamParser> stream_parser, 120 std::unique_ptr<StreamParser> stream_parser,
91 std::unique_ptr<FrameProcessor> frame_processor, 121 std::unique_ptr<FrameProcessor> frame_processor,
92 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 122 const CreateDemuxerStreamCB& create_demuxer_stream_cb,
93 const scoped_refptr<MediaLog>& media_log) 123 const scoped_refptr<MediaLog>& media_log)
94 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 124 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
95 timestamp_offset_during_append_(NULL), 125 timestamp_offset_during_append_(NULL),
96 parsing_media_segment_(false), 126 parsing_media_segment_(false),
97 media_segment_contained_audio_frame_(false),
98 media_segment_contained_video_frame_(false),
99 stream_parser_(stream_parser.release()), 127 stream_parser_(stream_parser.release()),
100 audio_(NULL),
101 video_(NULL),
102 frame_processor_(frame_processor.release()), 128 frame_processor_(frame_processor.release()),
103 media_log_(media_log), 129 media_log_(media_log),
104 state_(UNINITIALIZED), 130 state_(UNINITIALIZED),
105 auto_update_timestamp_offset_(false) { 131 auto_update_timestamp_offset_(false) {
106 DCHECK(!create_demuxer_stream_cb_.is_null()); 132 DCHECK(!create_demuxer_stream_cb_.is_null());
107 DCHECK(frame_processor_); 133 DCHECK(frame_processor_);
108 } 134 }
109 135
110 MediaSourceState::~MediaSourceState() { 136 MediaSourceState::~MediaSourceState() {
111 Shutdown(); 137 Shutdown();
112 138
113 base::STLDeleteValues(&text_stream_map_); 139 base::STLDeleteValues(&text_stream_map_);
114 } 140 }
115 141
116 void MediaSourceState::Init( 142 void MediaSourceState::Init(
117 const StreamParser::InitCB& init_cb, 143 const StreamParser::InitCB& init_cb,
118 bool allow_audio, 144 const std::string& expected_codecs,
119 bool allow_video,
120 const StreamParser::EncryptedMediaInitDataCB& encrypted_media_init_data_cb, 145 const StreamParser::EncryptedMediaInitDataCB& encrypted_media_init_data_cb,
121 const NewTextTrackCB& new_text_track_cb) { 146 const NewTextTrackCB& new_text_track_cb) {
122 DCHECK_EQ(state_, UNINITIALIZED); 147 DCHECK_EQ(state_, UNINITIALIZED);
123 new_text_track_cb_ = new_text_track_cb; 148 new_text_track_cb_ = new_text_track_cb;
124 init_cb_ = init_cb; 149 init_cb_ = init_cb;
125 150
151 std::vector<std::string> expected_codecs_parsed;
152 ParseCodecString(expected_codecs, &expected_codecs_parsed, false);
153
154 std::vector<AudioCodec> expected_acodecs;
155 std::vector<VideoCodec> expected_vcodecs;
156 for (const auto& codec_id : expected_codecs_parsed) {
157 AudioCodec acodec = StringToAudioCodec(codec_id);
158 if (acodec != kUnknownAudioCodec) {
159 expected_audio_codecs_.push_back(acodec);
160 continue;
161 }
162 VideoCodec vcodec = StringToVideoCodec(codec_id);
163 if (vcodec != kUnknownVideoCodec) {
164 expected_video_codecs_.push_back(vcodec);
165 continue;
166 }
167 MEDIA_LOG(INFO, media_log_) << "Unrecognized media codec: " << codec_id;
168 }
169
126 state_ = PENDING_PARSER_CONFIG; 170 state_ = PENDING_PARSER_CONFIG;
127 stream_parser_->Init( 171 stream_parser_->Init(
128 base::Bind(&MediaSourceState::OnSourceInitDone, base::Unretained(this)), 172 base::Bind(&MediaSourceState::OnSourceInitDone, base::Unretained(this)),
129 base::Bind(&MediaSourceState::OnNewConfigs, base::Unretained(this), 173 base::Bind(&MediaSourceState::OnNewConfigs, base::Unretained(this),
130 allow_audio, allow_video), 174 expected_codecs),
131 base::Bind(&MediaSourceState::OnNewBuffers, base::Unretained(this)), 175 base::Bind(&MediaSourceState::OnNewBuffers, base::Unretained(this)),
132 new_text_track_cb_.is_null(), encrypted_media_init_data_cb, 176 new_text_track_cb_.is_null(), encrypted_media_init_data_cb,
133 base::Bind(&MediaSourceState::OnNewMediaSegment, base::Unretained(this)), 177 base::Bind(&MediaSourceState::OnNewMediaSegment, base::Unretained(this)),
134 base::Bind(&MediaSourceState::OnEndOfMediaSegment, 178 base::Bind(&MediaSourceState::OnEndOfMediaSegment,
135 base::Unretained(this)), 179 base::Unretained(this)),
136 media_log_); 180 media_log_);
137 } 181 }
138 182
139 void MediaSourceState::SetSequenceMode(bool sequence_mode) { 183 void MediaSourceState::SetSequenceMode(bool sequence_mode) {
140 DCHECK(!parsing_media_segment_); 184 DCHECK(!parsing_media_segment_);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 DCHECK(!timestamp_offset_during_append_); 233 DCHECK(!timestamp_offset_during_append_);
190 timestamp_offset_during_append_ = timestamp_offset; 234 timestamp_offset_during_append_ = timestamp_offset;
191 append_window_start_during_append_ = append_window_start; 235 append_window_start_during_append_ = append_window_start;
192 append_window_end_during_append_ = append_window_end; 236 append_window_end_during_append_ = append_window_end;
193 237
194 stream_parser_->Flush(); 238 stream_parser_->Flush();
195 timestamp_offset_during_append_ = NULL; 239 timestamp_offset_during_append_ = NULL;
196 240
197 frame_processor_->Reset(); 241 frame_processor_->Reset();
198 parsing_media_segment_ = false; 242 parsing_media_segment_ = false;
199 media_segment_contained_audio_frame_ = false; 243 media_segment_has_data_for_track_.clear();
200 media_segment_contained_video_frame_ = false;
201 } 244 }
202 245
203 void MediaSourceState::Remove(TimeDelta start, 246 void MediaSourceState::Remove(TimeDelta start,
204 TimeDelta end, 247 TimeDelta end,
205 TimeDelta duration) { 248 TimeDelta duration) {
206 if (audio_) 249 for (const auto& it : audio_streams_) {
207 audio_->Remove(start, end, duration); 250 it.second->Remove(start, end, duration);
251 }
208 252
209 if (video_) 253 for (const auto& it : video_streams_) {
210 video_->Remove(start, end, duration); 254 it.second->Remove(start, end, duration);
255 }
211 256
212 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 257 for (TextStreamMap::iterator itr = text_stream_map_.begin();
213 itr != text_stream_map_.end(); ++itr) { 258 itr != text_stream_map_.end(); ++itr) {
214 itr->second->Remove(start, end, duration); 259 itr->second->Remove(start, end, duration);
215 } 260 }
216 } 261 }
217 262
218 size_t MediaSourceState::EstimateVideoDataSize(
219 size_t muxed_data_chunk_size) const {
220 DCHECK(audio_);
221 DCHECK(video_);
222
223 size_t videoBufferedSize = video_->GetBufferedSize();
224 size_t audioBufferedSize = audio_->GetBufferedSize();
225 if (videoBufferedSize == 0 || audioBufferedSize == 0) {
226 // At this point either audio or video buffer is empty, which means buffer
227 // levels are probably low anyway and we should have enough space in the
228 // buffers for appending new data, so just take a very rough guess.
229 return muxed_data_chunk_size * 7 / 8;
230 }
231
232 // We need to estimate how much audio and video data is going to be in the
233 // newly appended data chunk to make space for the new data. And we need to do
234 // that without parsing the data (which will happen later, in the Append
235 // phase). So for now we can only rely on some heuristic here. Let's assume
236 // that the proportion of the audio/video in the new data chunk is the same as
237 // the current ratio of buffered audio/video.
238 // Longer term this should go away once we further change the MSE GC algorithm
239 // to work across all streams of a SourceBuffer (see crbug.com/520704).
240 double videoBufferedSizeF = static_cast<double>(videoBufferedSize);
241 double audioBufferedSizeF = static_cast<double>(audioBufferedSize);
242
243 double totalBufferedSizeF = videoBufferedSizeF + audioBufferedSizeF;
244 CHECK_GT(totalBufferedSizeF, 0.0);
245
246 double videoRatio = videoBufferedSizeF / totalBufferedSizeF;
247 CHECK_GE(videoRatio, 0.0);
248 CHECK_LE(videoRatio, 1.0);
249 double estimatedVideoSize = muxed_data_chunk_size * videoRatio;
250 return static_cast<size_t>(estimatedVideoSize);
251 }
252
253 bool MediaSourceState::EvictCodedFrames(DecodeTimestamp media_time, 263 bool MediaSourceState::EvictCodedFrames(DecodeTimestamp media_time,
254 size_t newDataSize) { 264 size_t newDataSize) {
255 bool success = true; 265 size_t total_buffered_size = 0;
266 for (const auto& it : audio_streams_)
267 total_buffered_size += it.second->GetBufferedSize();
268 for (const auto& it : video_streams_)
269 total_buffered_size += it.second->GetBufferedSize();
270 for (const auto& it : text_stream_map_)
271 total_buffered_size += it.second->GetBufferedSize();
256 272
257 DVLOG(3) << __func__ << " media_time=" << media_time.InSecondsF() 273 DVLOG(3) << __func__ << " media_time=" << media_time.InSecondsF()
258 << " newDataSize=" << newDataSize 274 << " newDataSize=" << newDataSize
259 << " videoBufferedSize=" << (video_ ? video_->GetBufferedSize() : 0) 275 << " total_buffered_size=" << total_buffered_size;
260 << " audioBufferedSize=" << (audio_ ? audio_->GetBufferedSize() : 0);
261 276
262 size_t newAudioSize = 0; 277 if (total_buffered_size == 0)
263 size_t newVideoSize = 0; 278 return true;
264 if (audio_ && video_) { 279
265 newVideoSize = EstimateVideoDataSize(newDataSize); 280 bool success = true;
266 newAudioSize = newDataSize - newVideoSize; 281 for (const auto& it : audio_streams_) {
267 } else if (video_) { 282 uint64_t curr_size = it.second->GetBufferedSize();
268 newVideoSize = newDataSize; 283 if (curr_size == 0)
269 } else if (audio_) { 284 continue;
270 newAudioSize = newDataSize; 285 uint64_t estimated_new_size = newDataSize * curr_size / total_buffered_size;
286 DCHECK_LE(estimated_new_size, SIZE_MAX);
287 success &= it.second->EvictCodedFrames(
288 media_time, static_cast<size_t>(estimated_new_size));
289 }
290 for (const auto& it : video_streams_) {
291 uint64_t curr_size = it.second->GetBufferedSize();
292 if (curr_size == 0)
293 continue;
294 uint64_t estimated_new_size = newDataSize * curr_size / total_buffered_size;
295 DCHECK_LE(estimated_new_size, SIZE_MAX);
296 success &= it.second->EvictCodedFrames(
297 media_time, static_cast<size_t>(estimated_new_size));
298 }
299 for (const auto& it : text_stream_map_) {
300 uint64_t curr_size = it.second->GetBufferedSize();
301 if (curr_size == 0)
302 continue;
303 uint64_t estimated_new_size = newDataSize * curr_size / total_buffered_size;
304 DCHECK_LE(estimated_new_size, SIZE_MAX);
305 success &= it.second->EvictCodedFrames(
306 media_time, static_cast<size_t>(estimated_new_size));
271 } 307 }
272 308
273 DVLOG(3) << __func__ 309 DVLOG(3) << __func__ << " success=" << success;
274 << " estimated audio/video sizes: newVideoSize=" << newVideoSize
275 << " newAudioSize=" << newAudioSize;
276
277 if (audio_)
278 success = audio_->EvictCodedFrames(media_time, newAudioSize) && success;
279
280 if (video_)
281 success = video_->EvictCodedFrames(media_time, newVideoSize) && success;
282
283 for (TextStreamMap::iterator itr = text_stream_map_.begin();
284 itr != text_stream_map_.end(); ++itr) {
285 success = itr->second->EvictCodedFrames(media_time, 0) && success;
286 }
287
288 DVLOG(3) << __func__ << " result=" << success
289 << " videoBufferedSize=" << (video_ ? video_->GetBufferedSize() : 0)
290 << " audioBufferedSize=" << (audio_ ? audio_->GetBufferedSize() : 0);
291
292 return success; 310 return success;
293 } 311 }
294 312
295 Ranges<TimeDelta> MediaSourceState::GetBufferedRanges(TimeDelta duration, 313 Ranges<TimeDelta> MediaSourceState::GetBufferedRanges(TimeDelta duration,
296 bool ended) const { 314 bool ended) const {
297 // TODO(acolwell): When we start allowing disabled tracks we'll need to update
298 // this code to only add ranges from active tracks.
299 RangesList ranges_list; 315 RangesList ranges_list;
300 if (audio_) 316 for (const auto& it : audio_streams_)
301 ranges_list.push_back(audio_->GetBufferedRanges(duration)); 317 ranges_list.push_back(it.second->GetBufferedRanges(duration));
302 318
303 if (video_) 319 for (const auto& it : video_streams_)
304 ranges_list.push_back(video_->GetBufferedRanges(duration)); 320 ranges_list.push_back(it.second->GetBufferedRanges(duration));
305 321
306 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); 322 for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
307 itr != text_stream_map_.end(); ++itr) { 323 itr != text_stream_map_.end(); ++itr) {
308 ranges_list.push_back(itr->second->GetBufferedRanges(duration)); 324 ranges_list.push_back(itr->second->GetBufferedRanges(duration));
309 } 325 }
310 326
311 return ComputeRangesIntersection(ranges_list, ended); 327 return ComputeRangesIntersection(ranges_list, ended);
312 } 328 }
313 329
314 TimeDelta MediaSourceState::GetHighestPresentationTimestamp() const { 330 TimeDelta MediaSourceState::GetHighestPresentationTimestamp() const {
315 TimeDelta max_pts; 331 TimeDelta max_pts;
316 332
317 if (audio_) 333 for (const auto& it : audio_streams_) {
318 max_pts = std::max(max_pts, audio_->GetHighestPresentationTimestamp()); 334 max_pts = std::max(max_pts, it.second->GetHighestPresentationTimestamp());
335 }
319 336
320 if (video_) 337 for (const auto& it : video_streams_) {
321 max_pts = std::max(max_pts, video_->GetHighestPresentationTimestamp()); 338 max_pts = std::max(max_pts, it.second->GetHighestPresentationTimestamp());
339 }
322 340
323 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); 341 for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
324 itr != text_stream_map_.end(); ++itr) { 342 itr != text_stream_map_.end(); ++itr) {
325 max_pts = std::max(max_pts, itr->second->GetHighestPresentationTimestamp()); 343 max_pts = std::max(max_pts, itr->second->GetHighestPresentationTimestamp());
326 } 344 }
327 345
328 return max_pts; 346 return max_pts;
329 } 347 }
330 348
331 TimeDelta MediaSourceState::GetMaxBufferedDuration() const { 349 TimeDelta MediaSourceState::GetMaxBufferedDuration() const {
332 TimeDelta max_duration; 350 TimeDelta max_duration;
333 351
334 if (audio_) 352 for (const auto& it : audio_streams_) {
335 max_duration = std::max(max_duration, audio_->GetBufferedDuration()); 353 max_duration = std::max(max_duration, it.second->GetBufferedDuration());
354 }
336 355
337 if (video_) 356 for (const auto& it : video_streams_) {
338 max_duration = std::max(max_duration, video_->GetBufferedDuration()); 357 max_duration = std::max(max_duration, it.second->GetBufferedDuration());
358 }
339 359
340 for (TextStreamMap::const_iterator itr = text_stream_map_.begin(); 360 for (TextStreamMap::const_iterator itr = text_stream_map_.begin();
341 itr != text_stream_map_.end(); ++itr) { 361 itr != text_stream_map_.end(); ++itr) {
342 max_duration = std::max(max_duration, itr->second->GetBufferedDuration()); 362 max_duration = std::max(max_duration, itr->second->GetBufferedDuration());
343 } 363 }
344 364
345 return max_duration; 365 return max_duration;
346 } 366 }
347 367
348 void MediaSourceState::StartReturningData() { 368 void MediaSourceState::StartReturningData() {
349 if (audio_) 369 for (const auto& it : audio_streams_) {
350 audio_->StartReturningData(); 370 it.second->StartReturningData();
371 }
351 372
352 if (video_) 373 for (const auto& it : video_streams_) {
353 video_->StartReturningData(); 374 it.second->StartReturningData();
375 }
354 376
355 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 377 for (TextStreamMap::iterator itr = text_stream_map_.begin();
356 itr != text_stream_map_.end(); ++itr) { 378 itr != text_stream_map_.end(); ++itr) {
357 itr->second->StartReturningData(); 379 itr->second->StartReturningData();
358 } 380 }
359 } 381 }
360 382
361 void MediaSourceState::AbortReads() { 383 void MediaSourceState::AbortReads() {
362 if (audio_) 384 for (const auto& it : audio_streams_) {
363 audio_->AbortReads(); 385 it.second->AbortReads();
386 }
364 387
365 if (video_) 388 for (const auto& it : video_streams_) {
366 video_->AbortReads(); 389 it.second->AbortReads();
390 }
367 391
368 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 392 for (TextStreamMap::iterator itr = text_stream_map_.begin();
369 itr != text_stream_map_.end(); ++itr) { 393 itr != text_stream_map_.end(); ++itr) {
370 itr->second->AbortReads(); 394 itr->second->AbortReads();
371 } 395 }
372 } 396 }
373 397
374 void MediaSourceState::Seek(TimeDelta seek_time) { 398 void MediaSourceState::Seek(TimeDelta seek_time) {
375 if (audio_) 399 for (const auto& it : audio_streams_) {
376 audio_->Seek(seek_time); 400 it.second->Seek(seek_time);
401 }
377 402
378 if (video_) 403 for (const auto& it : video_streams_) {
379 video_->Seek(seek_time); 404 it.second->Seek(seek_time);
405 }
380 406
381 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 407 for (TextStreamMap::iterator itr = text_stream_map_.begin();
382 itr != text_stream_map_.end(); ++itr) { 408 itr != text_stream_map_.end(); ++itr) {
383 itr->second->Seek(seek_time); 409 itr->second->Seek(seek_time);
384 } 410 }
385 } 411 }
386 412
387 void MediaSourceState::CompletePendingReadIfPossible() { 413 void MediaSourceState::CompletePendingReadIfPossible() {
388 if (audio_) 414 for (const auto& it : audio_streams_) {
389 audio_->CompletePendingReadIfPossible(); 415 it.second->CompletePendingReadIfPossible();
416 }
390 417
391 if (video_) 418 for (const auto& it : video_streams_) {
392 video_->CompletePendingReadIfPossible(); 419 it.second->CompletePendingReadIfPossible();
420 }
393 421
394 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 422 for (TextStreamMap::iterator itr = text_stream_map_.begin();
395 itr != text_stream_map_.end(); ++itr) { 423 itr != text_stream_map_.end(); ++itr) {
396 itr->second->CompletePendingReadIfPossible(); 424 itr->second->CompletePendingReadIfPossible();
397 } 425 }
398 } 426 }
399 427
400 void MediaSourceState::OnSetDuration(TimeDelta duration) { 428 void MediaSourceState::OnSetDuration(TimeDelta duration) {
401 if (audio_) 429 for (const auto& it : audio_streams_) {
402 audio_->OnSetDuration(duration); 430 it.second->OnSetDuration(duration);
431 }
403 432
404 if (video_) 433 for (const auto& it : video_streams_) {
405 video_->OnSetDuration(duration); 434 it.second->OnSetDuration(duration);
435 }
406 436
407 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 437 for (TextStreamMap::iterator itr = text_stream_map_.begin();
408 itr != text_stream_map_.end(); ++itr) { 438 itr != text_stream_map_.end(); ++itr) {
409 itr->second->OnSetDuration(duration); 439 itr->second->OnSetDuration(duration);
410 } 440 }
411 } 441 }
412 442
413 void MediaSourceState::MarkEndOfStream() { 443 void MediaSourceState::MarkEndOfStream() {
414 if (audio_) 444 for (const auto& it : audio_streams_) {
415 audio_->MarkEndOfStream(); 445 it.second->MarkEndOfStream();
446 }
416 447
417 if (video_) 448 for (const auto& it : video_streams_) {
418 video_->MarkEndOfStream(); 449 it.second->MarkEndOfStream();
450 }
419 451
420 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 452 for (TextStreamMap::iterator itr = text_stream_map_.begin();
421 itr != text_stream_map_.end(); ++itr) { 453 itr != text_stream_map_.end(); ++itr) {
422 itr->second->MarkEndOfStream(); 454 itr->second->MarkEndOfStream();
423 } 455 }
424 } 456 }
425 457
426 void MediaSourceState::UnmarkEndOfStream() { 458 void MediaSourceState::UnmarkEndOfStream() {
427 if (audio_) 459 for (const auto& it : audio_streams_) {
428 audio_->UnmarkEndOfStream(); 460 it.second->UnmarkEndOfStream();
461 }
429 462
430 if (video_) 463 for (const auto& it : video_streams_) {
431 video_->UnmarkEndOfStream(); 464 it.second->UnmarkEndOfStream();
465 }
432 466
433 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 467 for (TextStreamMap::iterator itr = text_stream_map_.begin();
434 itr != text_stream_map_.end(); ++itr) { 468 itr != text_stream_map_.end(); ++itr) {
435 itr->second->UnmarkEndOfStream(); 469 itr->second->UnmarkEndOfStream();
436 } 470 }
437 } 471 }
438 472
439 void MediaSourceState::Shutdown() { 473 void MediaSourceState::Shutdown() {
440 if (audio_) 474 for (const auto& it : audio_streams_) {
441 audio_->Shutdown(); 475 it.second->Shutdown();
476 }
442 477
443 if (video_) 478 for (const auto& it : video_streams_) {
444 video_->Shutdown(); 479 it.second->Shutdown();
480 }
445 481
446 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 482 for (TextStreamMap::iterator itr = text_stream_map_.begin();
447 itr != text_stream_map_.end(); ++itr) { 483 itr != text_stream_map_.end(); ++itr) {
448 itr->second->Shutdown(); 484 itr->second->Shutdown();
449 } 485 }
450 } 486 }
451 487
452 void MediaSourceState::SetMemoryLimits(DemuxerStream::Type type, 488 void MediaSourceState::SetMemoryLimits(DemuxerStream::Type type,
453 size_t memory_limit) { 489 size_t memory_limit) {
454 switch (type) { 490 switch (type) {
455 case DemuxerStream::AUDIO: 491 case DemuxerStream::AUDIO:
456 if (audio_) 492 for (const auto& it : audio_streams_) {
457 audio_->SetStreamMemoryLimit(memory_limit); 493 it.second->SetStreamMemoryLimit(memory_limit);
494 }
458 break; 495 break;
459 case DemuxerStream::VIDEO: 496 case DemuxerStream::VIDEO:
460 if (video_) 497 for (const auto& it : video_streams_) {
461 video_->SetStreamMemoryLimit(memory_limit); 498 it.second->SetStreamMemoryLimit(memory_limit);
499 }
462 break; 500 break;
463 case DemuxerStream::TEXT: 501 case DemuxerStream::TEXT:
464 for (TextStreamMap::iterator itr = text_stream_map_.begin(); 502 for (TextStreamMap::iterator itr = text_stream_map_.begin();
465 itr != text_stream_map_.end(); ++itr) { 503 itr != text_stream_map_.end(); ++itr) {
466 itr->second->SetStreamMemoryLimit(memory_limit); 504 itr->second->SetStreamMemoryLimit(memory_limit);
467 } 505 }
468 break; 506 break;
469 case DemuxerStream::UNKNOWN: 507 case DemuxerStream::UNKNOWN:
470 case DemuxerStream::NUM_TYPES: 508 case DemuxerStream::NUM_TYPES:
471 NOTREACHED(); 509 NOTREACHED();
472 break; 510 break;
473 } 511 }
474 } 512 }
475 513
476 bool MediaSourceState::IsSeekWaitingForData() const { 514 bool MediaSourceState::IsSeekWaitingForData() const {
477 if (audio_ && audio_->IsSeekWaitingForData()) 515 for (const auto& it : audio_streams_) {
478 return true; 516 if (it.second->IsSeekWaitingForData())
517 return true;
518 }
479 519
480 if (video_ && video_->IsSeekWaitingForData()) 520 for (const auto& it : video_streams_) {
481 return true; 521 if (it.second->IsSeekWaitingForData())
522 return true;
523 }
482 524
483 // NOTE: We are intentionally not checking the text tracks 525 // NOTE: We are intentionally not checking the text tracks
484 // because text tracks are discontinuous and may not have data 526 // because text tracks are discontinuous and may not have data
485 // for the seek position. This is ok and playback should not be 527 // for the seek position. This is ok and playback should not be
486 // stalled because we don't have cues. If cues, with timestamps after 528 // stalled because we don't have cues. If cues, with timestamps after
487 // the seek time, eventually arrive they will be delivered properly 529 // the seek time, eventually arrive they will be delivered properly
488 // in response to ChunkDemuxerStream::Read() calls. 530 // in response to ChunkDemuxerStream::Read() calls.
489 531
490 return false; 532 return false;
491 } 533 }
492 534
493 bool MediaSourceState::OnNewConfigs( 535 bool MediaSourceState::OnNewConfigs(
494 bool allow_audio, 536 std::string expected_codecs,
495 bool allow_video,
496 std::unique_ptr<MediaTracks> tracks, 537 std::unique_ptr<MediaTracks> tracks,
497 const StreamParser::TextTrackConfigMap& text_configs) { 538 const StreamParser::TextTrackConfigMap& text_configs) {
539 DCHECK(tracks.get());
540 DVLOG(1) << __func__ << " expected_codecs=" << expected_codecs
541 << " tracks=" << tracks->tracks().size();
498 DCHECK_GE(state_, PENDING_PARSER_CONFIG); 542 DCHECK_GE(state_, PENDING_PARSER_CONFIG);
499 DCHECK(tracks.get());
500 543
501 MediaTrack* audio_track = nullptr; 544 // Check that there is no clashing bytestream track ids.
502 MediaTrack* video_track = nullptr; 545 if (!CheckBytestreamTrackIds(*tracks, text_configs)) {
503 AudioDecoderConfig audio_config; 546 MEDIA_LOG(ERROR, media_log_) << "Duplicate bytestream track ids detected";
504 VideoDecoderConfig video_config; 547 for (const auto& track : tracks->tracks()) {
548 const StreamParser::TrackId& track_id = track->bytestream_track_id();
549 MEDIA_LOG(DEBUG, media_log_) << TrackTypeToStr(track->type()) << " track "
550 << " bytestream track id=" << track_id;
551 }
552 return false;
553 }
554
555 // MSE spec allows new configs to be emitted only during Append, but not
556 // during Flush or parser reset operations.
557 CHECK(append_in_progress_);
558
559 bool success = true;
560
561 // TODO(wolenetz): Update codec string strictness, if necessary, once spec
562 // issue https://github.com/w3c/media-source/issues/161 is resolved.
563 std::vector<AudioCodec> expected_acodecs = expected_audio_codecs_;
564 std::vector<VideoCodec> expected_vcodecs = expected_video_codecs_;
565
505 for (const auto& track : tracks->tracks()) { 566 for (const auto& track : tracks->tracks()) {
506 const auto& track_id = track->bytestream_track_id(); 567 const auto& track_id = track->bytestream_track_id();
507 568
508 if (track->type() == MediaTrack::Audio) { 569 if (track->type() == MediaTrack::Audio) {
509 if (audio_track) { 570 AudioDecoderConfig audio_config = tracks->getAudioConfig(track_id);
510 MEDIA_LOG(ERROR, media_log_) 571 DVLOG(1) << "Audio track_id=" << track_id
511 << "Error: more than one audio track is currently not supported."; 572 << " config: " << audio_config.AsHumanReadableString();
573 DCHECK(audio_config.IsValidConfig());
574
575 const auto& it = std::find(expected_acodecs.begin(),
576 expected_acodecs.end(), audio_config.codec());
577 if (it == expected_acodecs.end()) {
578 MEDIA_LOG(ERROR, media_log_) << "Audio stream codec "
579 << GetCodecName(audio_config.codec())
580 << " doesn't match SourceBuffer codecs.";
512 return false; 581 return false;
513 } 582 }
514 audio_track = track.get(); 583 expected_acodecs.erase(it);
515 audio_config = tracks->getAudioConfig(track_id); 584
516 DCHECK(audio_config.IsValidConfig()); 585 ChunkDemuxerStream* stream = nullptr;
586 if (!first_init_segment_received_) {
587 DCHECK(audio_streams_.find(track_id) == audio_streams_.end());
588 stream = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
589 if (!stream || !frame_processor_->AddTrack(track_id, stream)) {
590 MEDIA_LOG(ERROR, media_log_) << "Failed to create audio stream.";
591 return false;
592 }
593 audio_streams_[track_id] = stream;
594 media_log_->SetBooleanProperty("found_audio_stream", true);
595 media_log_->SetStringProperty("audio_codec_name",
596 GetCodecName(audio_config.codec()));
597 } else {
598 if (audio_streams_.size() > 1) {
599 auto it = audio_streams_.find(track_id);
600 if (it != audio_streams_.end())
601 stream = it->second;
602 } else {
603 // If there is only one audio track then bytestream id might change in
604 // a new init segment. So update our state and nofity frame processor.
605 const auto& it = audio_streams_.begin();
606 if (it != audio_streams_.end()) {
607 stream = it->second;
608 if (it->first != track_id) {
609 frame_processor_->UpdateTrack(it->first, track_id);
610 audio_streams_[track_id] = stream;
611 audio_streams_.erase(it->first);
612 }
613 }
614 }
615 if (!stream) {
616 MEDIA_LOG(ERROR, media_log_) << "Got unexpected audio track"
617 << " track_id=" << track_id;
618 return false;
619 }
620 }
621
622 track->set_id(stream->media_track_id());
623 frame_processor_->OnPossibleAudioConfigUpdate(audio_config);
624 success &= stream->UpdateAudioConfig(audio_config, media_log_);
517 } else if (track->type() == MediaTrack::Video) { 625 } else if (track->type() == MediaTrack::Video) {
518 if (video_track) { 626 VideoDecoderConfig video_config = tracks->getVideoConfig(track_id);
519 MEDIA_LOG(ERROR, media_log_) 627 DVLOG(1) << "Video track_id=" << track_id
520 << "Error: more than one video track is currently not supported."; 628 << " config: " << video_config.AsHumanReadableString();
629 DCHECK(video_config.IsValidConfig());
630
631 const auto& it = std::find(expected_vcodecs.begin(),
632 expected_vcodecs.end(), video_config.codec());
633 if (it == expected_vcodecs.end()) {
634 MEDIA_LOG(ERROR, media_log_) << "Video stream codec "
635 << GetCodecName(video_config.codec())
636 << " doesn't match SourceBuffer codecs.";
521 return false; 637 return false;
522 } 638 }
523 video_track = track.get(); 639 expected_vcodecs.erase(it);
524 video_config = tracks->getVideoConfig(track_id); 640
525 DCHECK(video_config.IsValidConfig()); 641 ChunkDemuxerStream* stream = nullptr;
642 if (!first_init_segment_received_) {
643 DCHECK(video_streams_.find(track_id) == video_streams_.end());
644 stream = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
645 if (!stream || !frame_processor_->AddTrack(track_id, stream)) {
646 MEDIA_LOG(ERROR, media_log_) << "Failed to create video stream.";
647 return false;
648 }
649 video_streams_[track_id] = stream;
650 media_log_->SetBooleanProperty("found_video_stream", true);
651 media_log_->SetStringProperty("video_codec_name",
652 GetCodecName(video_config.codec()));
653 } else {
654 if (video_streams_.size() > 1) {
655 auto it = video_streams_.find(track_id);
656 if (it != video_streams_.end())
657 stream = it->second;
658 } else {
659 // If there is only one video track then bytestream id might change in
660 // a new init segment. So update our state and nofity frame processor.
661 const auto& it = video_streams_.begin();
662 if (it != video_streams_.end()) {
663 stream = it->second;
664 if (it->first != track_id) {
665 frame_processor_->UpdateTrack(it->first, track_id);
666 video_streams_[track_id] = stream;
667 video_streams_.erase(it->first);
668 }
669 }
670 }
671 if (!stream) {
672 MEDIA_LOG(ERROR, media_log_) << "Got unexpected video track"
673 << " track_id=" << track_id;
674 return false;
675 }
676 }
677
678 track->set_id(stream->media_track_id());
679 success &= stream->UpdateVideoConfig(video_config, media_log_);
526 } else { 680 } else {
527 MEDIA_LOG(ERROR, media_log_) << "Error: unsupported media track type " 681 MEDIA_LOG(ERROR, media_log_) << "Error: unsupported media track type "
528 << track->type(); 682 << track->type();
529 return false; 683 return false;
530 } 684 }
531 } 685 }
532 686
533 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video << ", " 687 if (!expected_acodecs.empty() || !expected_vcodecs.empty()) {
534 << audio_config.IsValidConfig() << ", " 688 for (const auto& acodec : expected_acodecs) {
535 << video_config.IsValidConfig() << ")"; 689 MEDIA_LOG(ERROR, media_log_) << "Initialization segment misses expected "
536 // MSE spec allows new configs to be emitted only during Append, but not 690 << GetCodecName(acodec) << " track.";
537 // during Flush or parser reset operations. 691 }
538 CHECK(append_in_progress_); 692 for (const auto& vcodec : expected_vcodecs) {
539 693 MEDIA_LOG(ERROR, media_log_) << "Initialization segment misses expected "
540 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { 694 << GetCodecName(vcodec) << " track.";
541 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; 695 }
542 return false; 696 return false;
543 } 697 }
544 698
545 // Signal an error if we get configuration info for stream types that weren't
546 // specified in AddId() or more configs after a stream is initialized.
547 if (allow_audio != audio_config.IsValidConfig()) {
548 MEDIA_LOG(ERROR, media_log_)
549 << "Initialization segment"
550 << (audio_config.IsValidConfig() ? " has" : " does not have")
551 << " an audio track, but the mimetype"
552 << (allow_audio ? " specifies" : " does not specify")
553 << " an audio codec.";
554 return false;
555 }
556
557 if (allow_video != video_config.IsValidConfig()) {
558 MEDIA_LOG(ERROR, media_log_)
559 << "Initialization segment"
560 << (video_config.IsValidConfig() ? " has" : " does not have")
561 << " a video track, but the mimetype"
562 << (allow_video ? " specifies" : " does not specify")
563 << " a video codec.";
564 return false;
565 }
566
567 bool success = true;
568 if (audio_config.IsValidConfig()) {
569 if (!audio_) {
570 media_log_->SetBooleanProperty("found_audio_stream", true);
571 }
572 if (!audio_ ||
573 audio_->audio_decoder_config().codec() != audio_config.codec()) {
574 media_log_->SetStringProperty("audio_codec_name",
575 GetCodecName(audio_config.codec()));
576 }
577
578 bool audio_stream_just_created = false;
579 if (!audio_) {
580 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO);
581
582 if (!audio_) {
583 DVLOG(1) << "Failed to create an audio stream.";
584 return false;
585 }
586 audio_stream_just_created = true;
587
588 if (!frame_processor_->AddTrack(FrameProcessor::kAudioTrackId, audio_)) {
589 DVLOG(1) << "Failed to add audio track to frame processor.";
590 return false;
591 }
592 }
593
594 frame_processor_->OnPossibleAudioConfigUpdate(audio_config);
595 success &= audio_->UpdateAudioConfig(audio_config, media_log_);
596
597 if (audio_stream_just_created) {
598 std::string audio_buf_limit_switch =
599 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
600 switches::kMSEAudioBufferSizeLimit);
601 unsigned audio_buf_size_limit = 0;
602 if (base::StringToUint(audio_buf_limit_switch, &audio_buf_size_limit) &&
603 audio_buf_size_limit > 0) {
604 MEDIA_LOG(INFO, media_log_) << "Custom audio SourceBuffer size limit="
605 << audio_buf_size_limit;
606 audio_->SetStreamMemoryLimit(audio_buf_size_limit);
607 }
608 }
609 }
610
611 if (video_config.IsValidConfig()) {
612 if (!video_) {
613 media_log_->SetBooleanProperty("found_video_stream", true);
614 }
615 if (!video_ ||
616 video_->video_decoder_config().codec() != video_config.codec()) {
617 media_log_->SetStringProperty("video_codec_name",
618 GetCodecName(video_config.codec()));
619 }
620
621 bool video_stream_just_created = false;
622 if (!video_) {
623 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO);
624
625 if (!video_) {
626 DVLOG(1) << "Failed to create a video stream.";
627 return false;
628 }
629 video_stream_just_created = true;
630
631 if (!frame_processor_->AddTrack(FrameProcessor::kVideoTrackId, video_)) {
632 DVLOG(1) << "Failed to add video track to frame processor.";
633 return false;
634 }
635 }
636
637 success &= video_->UpdateVideoConfig(video_config, media_log_);
638
639 if (video_stream_just_created) {
640 std::string video_buf_limit_switch =
641 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
642 switches::kMSEVideoBufferSizeLimit);
643 unsigned video_buf_size_limit = 0;
644 if (base::StringToUint(video_buf_limit_switch, &video_buf_size_limit) &&
645 video_buf_size_limit > 0) {
646 MEDIA_LOG(INFO, media_log_) << "Custom video SourceBuffer size limit="
647 << video_buf_size_limit;
648 video_->SetStreamMemoryLimit(video_buf_size_limit);
649 }
650 }
651 }
652
653 typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr; 699 typedef StreamParser::TextTrackConfigMap::const_iterator TextConfigItr;
654 if (text_stream_map_.empty()) { 700 if (text_stream_map_.empty()) {
655 for (TextConfigItr itr = text_configs.begin(); itr != text_configs.end(); 701 for (TextConfigItr itr = text_configs.begin(); itr != text_configs.end();
656 ++itr) { 702 ++itr) {
657 ChunkDemuxerStream* const text_stream = 703 ChunkDemuxerStream* const text_stream =
658 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT); 704 create_demuxer_stream_cb_.Run(DemuxerStream::TEXT);
659 if (!frame_processor_->AddTrack(itr->first, text_stream)) { 705 if (!frame_processor_->AddTrack(itr->first, text_stream)) {
660 success &= false; 706 success &= false;
661 MEDIA_LOG(ERROR, media_log_) << "Failed to add text track ID " 707 MEDIA_LOG(ERROR, media_log_) << "Failed to add text track ID "
662 << itr->first << " to frame processor."; 708 << itr->first << " to frame processor.";
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 success &= false; 764 success &= false;
719 MEDIA_LOG(ERROR, media_log_) << "New text track config for track ID " 765 MEDIA_LOG(ERROR, media_log_) << "New text track config for track ID "
720 << config_itr->first 766 << config_itr->first
721 << " does not match old one."; 767 << " does not match old one.";
722 break; 768 break;
723 } 769 }
724 } 770 }
725 } 771 }
726 } 772 }
727 773
774 if (audio_streams_.empty() && video_streams_.empty()) {
775 DVLOG(1) << __func__ << ": couldn't find a valid audio or video stream";
776 return false;
777 }
778
728 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint(); 779 frame_processor_->SetAllTrackBuffersNeedRandomAccessPoint();
729 780
730 if (audio_track) { 781 if (!first_init_segment_received_) {
731 DCHECK(audio_); 782 first_init_segment_received_ = true;
732 audio_track->set_id(audio_->media_track_id()); 783 SetStreamMemoryLimits();
733 }
734 if (video_track) {
735 DCHECK(video_);
736 video_track->set_id(video_->media_track_id());
737 } 784 }
738 785
739 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); 786 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
740 if (success) { 787 if (success) {
741 if (state_ == PENDING_PARSER_CONFIG) 788 if (state_ == PENDING_PARSER_CONFIG)
742 state_ = PENDING_PARSER_INIT; 789 state_ = PENDING_PARSER_INIT;
743 DCHECK(!init_segment_received_cb_.is_null()); 790 DCHECK(!init_segment_received_cb_.is_null());
744 init_segment_received_cb_.Run(std::move(tracks)); 791 init_segment_received_cb_.Run(std::move(tracks));
745 } 792 }
746 793
747 return success; 794 return success;
748 } 795 }
749 796
797 void MediaSourceState::SetStreamMemoryLimits() {
798 auto cmd_line = base::CommandLine::ForCurrentProcess();
799
800 std::string audio_buf_limit_switch =
801 cmd_line->GetSwitchValueASCII(switches::kMSEAudioBufferSizeLimit);
802 unsigned audio_buf_size_limit = 0;
803 if (base::StringToUint(audio_buf_limit_switch, &audio_buf_size_limit) &&
804 audio_buf_size_limit > 0) {
805 MEDIA_LOG(INFO, media_log_)
806 << "Custom audio per-track SourceBuffer size limit="
807 << audio_buf_size_limit;
808 for (const auto& it : audio_streams_) {
809 it.second->SetStreamMemoryLimit(audio_buf_size_limit);
810 }
811 }
812
813 std::string video_buf_limit_switch =
814 cmd_line->GetSwitchValueASCII(switches::kMSEVideoBufferSizeLimit);
815 unsigned video_buf_size_limit = 0;
816 if (base::StringToUint(video_buf_limit_switch, &video_buf_size_limit) &&
817 video_buf_size_limit > 0) {
818 MEDIA_LOG(INFO, media_log_)
819 << "Custom video per-track SourceBuffer size limit="
820 << video_buf_size_limit;
821 for (const auto& it : video_streams_) {
822 it.second->SetStreamMemoryLimit(video_buf_size_limit);
823 }
824 }
825 }
826
750 void MediaSourceState::OnNewMediaSegment() { 827 void MediaSourceState::OnNewMediaSegment() {
751 DVLOG(2) << "OnNewMediaSegment()"; 828 DVLOG(2) << "OnNewMediaSegment()";
752 DCHECK_EQ(state_, PARSER_INITIALIZED); 829 DCHECK_EQ(state_, PARSER_INITIALIZED);
753 parsing_media_segment_ = true; 830 parsing_media_segment_ = true;
754 media_segment_contained_audio_frame_ = false; 831 media_segment_has_data_for_track_.clear();
755 media_segment_contained_video_frame_ = false;
756 } 832 }
757 833
758 void MediaSourceState::OnEndOfMediaSegment() { 834 void MediaSourceState::OnEndOfMediaSegment() {
759 DVLOG(2) << "OnEndOfMediaSegment()"; 835 DVLOG(2) << "OnEndOfMediaSegment()";
760 DCHECK_EQ(state_, PARSER_INITIALIZED); 836 DCHECK_EQ(state_, PARSER_INITIALIZED);
761 parsing_media_segment_ = false; 837 parsing_media_segment_ = false;
762 838
763 const bool missing_audio = audio_ && !media_segment_contained_audio_frame_; 839 for (const auto& it : audio_streams_) {
764 const bool missing_video = video_ && !media_segment_contained_video_frame_; 840 if (!media_segment_has_data_for_track_[it.first]) {
765 if (!missing_audio && !missing_video) 841 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_missing_track_logs_,
766 return; 842 kMaxMissingTrackInSegmentLogs)
767 843 << "Media segment did not contain any coded frames for track "
768 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_missing_track_logs_, 844 << it.first << ", mismatching initialization segment. Therefore, MSE"
769 kMaxMissingTrackInSegmentLogs) 845 " coded frame processing may not interoperably detect"
770 << "Media segment did not contain any " 846 " discontinuities in appended media.";
771 << (missing_audio && missing_video ? "audio or video" 847 }
772 : missing_audio ? "audio" : "video") 848 }
773 << " coded frames, mismatching initialization segment. Therefore, MSE " 849 for (const auto& it : video_streams_) {
774 "coded frame processing may not interoperably detect discontinuities " 850 if (!media_segment_has_data_for_track_[it.first]) {
775 "in appended media."; 851 LIMITED_MEDIA_LOG(DEBUG, media_log_, num_missing_track_logs_,
852 kMaxMissingTrackInSegmentLogs)
853 << "Media segment did not contain any coded frames for track "
854 << it.first << ", mismatching initialization segment. Therefore, MSE"
855 " coded frame processing may not interoperably detect"
856 " discontinuities in appended media.";
857 }
858 }
776 } 859 }
777 860
778 bool MediaSourceState::OnNewBuffers( 861 bool MediaSourceState::OnNewBuffers(
779 const StreamParser::BufferQueueMap& buffer_queue_map) { 862 const StreamParser::BufferQueueMap& buffer_queue_map) {
780 DVLOG(2) << "OnNewBuffers()"; 863 DVLOG(2) << __func__ << " buffer_queues=" << buffer_queue_map.size();
781 DCHECK_EQ(state_, PARSER_INITIALIZED); 864 DCHECK_EQ(state_, PARSER_INITIALIZED);
782 DCHECK(timestamp_offset_during_append_); 865 DCHECK(timestamp_offset_during_append_);
783 DCHECK(parsing_media_segment_); 866 DCHECK(parsing_media_segment_);
784 867
785 for (const auto& it : buffer_queue_map) { 868 for (const auto& it : buffer_queue_map) {
786 const StreamParser::BufferQueue& bufq = it.second; 869 const StreamParser::BufferQueue& bufq = it.second;
787 DCHECK(!bufq.empty()); 870 DCHECK(!bufq.empty());
788 if (bufq[0]->type() == DemuxerStream::AUDIO) { 871 media_segment_has_data_for_track_[it.first] = true;
789 media_segment_contained_audio_frame_ = true;
790 } else if (bufq[0]->type() == DemuxerStream::VIDEO) {
791 media_segment_contained_video_frame_ = true;
792 }
793 } 872 }
794 873
795 const TimeDelta timestamp_offset_before_processing = 874 const TimeDelta timestamp_offset_before_processing =
796 *timestamp_offset_during_append_; 875 *timestamp_offset_during_append_;
797 876
798 // Calculate the new timestamp offset for audio/video tracks if the stream 877 // Calculate the new timestamp offset for audio/video tracks if the stream
799 // parser has requested automatic updates. 878 // parser has requested automatic updates.
800 TimeDelta new_timestamp_offset = timestamp_offset_before_processing; 879 TimeDelta new_timestamp_offset = timestamp_offset_before_processing;
801 if (auto_update_timestamp_offset_) { 880 if (auto_update_timestamp_offset_) {
802 TimeDelta min_end_timestamp = kNoTimestamp; 881 TimeDelta min_end_timestamp = kNoTimestamp;
(...skipping 17 matching lines...) Expand all
820 } 899 }
821 900
822 // Only update the timestamp offset if the frame processor hasn't already. 901 // Only update the timestamp offset if the frame processor hasn't already.
823 if (auto_update_timestamp_offset_ && 902 if (auto_update_timestamp_offset_ &&
824 timestamp_offset_before_processing == *timestamp_offset_during_append_) { 903 timestamp_offset_before_processing == *timestamp_offset_during_append_) {
825 *timestamp_offset_during_append_ = new_timestamp_offset; 904 *timestamp_offset_during_append_ = new_timestamp_offset;
826 } 905 }
827 906
828 return true; 907 return true;
829 } 908 }
830
831 void MediaSourceState::OnSourceInitDone( 909 void MediaSourceState::OnSourceInitDone(
832 const StreamParser::InitParameters& params) { 910 const StreamParser::InitParameters& params) {
833 DCHECK_EQ(state_, PENDING_PARSER_INIT); 911 DCHECK_EQ(state_, PENDING_PARSER_INIT);
834 state_ = PARSER_INITIALIZED; 912 state_ = PARSER_INITIALIZED;
835 auto_update_timestamp_offset_ = params.auto_update_timestamp_offset; 913 auto_update_timestamp_offset_ = params.auto_update_timestamp_offset;
836 base::ResetAndReturn(&init_cb_).Run(params); 914 base::ResetAndReturn(&init_cb_).Run(params);
837 } 915 }
838 916
839 } // namespace media 917 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/media_source_state.h ('k') | media/filters/stream_parser_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698