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

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

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

Powered by Google App Engine
This is Rietveld 408576698