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