[M120 Migration][hbbtv] Audio tracks count notification
[platform/framework/web/chromium-efl.git] / media / filters / chunk_demuxer.cc
1 // Copyright 2012 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/chunk_demuxer.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <memory>
10 #include <utility>
11
12 #include "base/functional/bind.h"
13 #include "base/functional/callback_helpers.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/task/bind_post_task.h"
16 #include "base/trace_event/trace_event.h"
17 #include "media/base/audio_decoder_config.h"
18 #include "media/base/demuxer.h"
19 #include "media/base/media_tracks.h"
20 #include "media/base/mime_util.h"
21 #include "media/base/stream_parser.h"
22 #include "media/base/stream_parser_buffer.h"
23 #include "media/base/timestamp_constants.h"
24 #include "media/base/video_codecs.h"
25 #include "media/base/video_decoder_config.h"
26 #include "media/filters/frame_processor.h"
27 #include "media/filters/source_buffer_stream.h"
28 #include "media/filters/stream_parser_factory.h"
29
30 namespace {
31
32 // Helper to attempt construction of a StreamParser specific to |content_type|
33 // and |codecs|.
34 // TODO(wolenetz): Consider relocating this to StreamParserFactory in
35 // conjunction with updating StreamParserFactory's isTypeSupported() to also
36 // parse codecs, rather than require preparsed vector.
37 std::unique_ptr<media::StreamParser> CreateParserForTypeAndCodecs(
38     const std::string& content_type,
39     const std::string& codecs,
40     media::MediaLog* media_log,
41     bool* has_audio,
42     bool* has_video) {
43   std::vector<std::string> parsed_codec_ids;
44   media::SplitCodecs(codecs, &parsed_codec_ids);
45   return media::StreamParserFactory::Create(content_type, parsed_codec_ids,
46                                             media_log, has_audio, has_video);
47 }
48
49 // Helper to calculate the expected codecs parsed from initialization segments
50 // for a few mime types that have an implicit codec.
51 std::string ExpectedCodecs(const std::string& content_type,
52                            const std::string& codecs) {
53   if (codecs == "" && content_type == "audio/aac")
54     return "aac";
55   if (codecs == "" &&
56       (content_type == "audio/mpeg" || content_type == "audio/mp3"))
57     return "mp3";
58   return codecs;
59 }
60
61 }  // namespace
62
63 namespace media {
64
65 ChunkDemuxerStream::ChunkDemuxerStream(Type type, MediaTrack::Id media_track_id)
66     : type_(type),
67       liveness_(StreamLiveness::kUnknown),
68       media_track_id_(media_track_id),
69       state_(UNINITIALIZED),
70       is_enabled_(true) {}
71
72 void ChunkDemuxerStream::StartReturningData() {
73   DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
74   base::AutoLock auto_lock(lock_);
75   DCHECK(!read_cb_);
76   ChangeState_Locked(RETURNING_DATA_FOR_READS);
77 }
78
79 #if BUILDFLAG(IS_TIZEN_TV)
80 void ChunkDemuxerStream::SetFramerate(
81     const StreamFramerate::Framerate& framerate) {
82   if (!stream_) {
83     LOG(ERROR) << "stream is null,this:" << (void*)this;
84     return;
85   }
86   stream_->updateFramerate(framerate);
87 }
88 #endif
89
90 void ChunkDemuxerStream::AbortReads() {
91   DVLOG(1) << "ChunkDemuxerStream::AbortReads()";
92   base::AutoLock auto_lock(lock_);
93   ChangeState_Locked(RETURNING_ABORT_FOR_READS);
94   if (read_cb_)
95     std::move(read_cb_).Run(kAborted, {});
96 }
97
98 void ChunkDemuxerStream::CompletePendingReadIfPossible() {
99   base::AutoLock auto_lock(lock_);
100   if (!read_cb_)
101     return;
102
103   CompletePendingReadIfPossible_Locked();
104 }
105
106 void ChunkDemuxerStream::Shutdown() {
107   DVLOG(1) << "ChunkDemuxerStream::Shutdown()";
108   base::AutoLock auto_lock(lock_);
109   ChangeState_Locked(SHUTDOWN);
110
111   // Pass an end of stream buffer to the pending callback to signal that no more
112   // data will be sent.
113   if (read_cb_) {
114     std::move(read_cb_).Run(DemuxerStream::kOk,
115                             {StreamParserBuffer::CreateEOSBuffer()});
116   }
117 }
118
119 bool ChunkDemuxerStream::IsSeekWaitingForData() const {
120   base::AutoLock auto_lock(lock_);
121   return stream_->IsSeekPending();
122 }
123
124 void ChunkDemuxerStream::Seek(base::TimeDelta time) {
125   DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")";
126   base::AutoLock auto_lock(lock_);
127   DCHECK(!read_cb_);
128   DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS)
129       << state_;
130
131   stream_->Seek(time);
132 }
133
134 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) {
135   if (append_observer_cb_)
136     append_observer_cb_.Run(&buffers);
137
138   if (buffers.empty())
139     return false;
140
141   base::AutoLock auto_lock(lock_);
142   DCHECK_NE(state_, SHUTDOWN);
143   stream_->Append(buffers);
144
145   if (read_cb_)
146     CompletePendingReadIfPossible_Locked();
147
148   return true;
149 }
150
151 void ChunkDemuxerStream::Remove(base::TimeDelta start,
152                                 base::TimeDelta end,
153                                 base::TimeDelta duration) {
154   base::AutoLock auto_lock(lock_);
155   stream_->Remove(start, end, duration);
156 }
157
158 bool ChunkDemuxerStream::EvictCodedFrames(base::TimeDelta media_time,
159                                           size_t newDataSize) {
160   base::AutoLock auto_lock(lock_);
161
162   // If the stream is disabled, then the renderer is not reading from it and
163   // thus the read position might be stale. MSE GC algorithm uses the read
164   // position to determine when to stop removing data from the front of buffered
165   // ranges, so do a Seek in order to update the read position and allow the GC
166   // to collect unnecessary data that is earlier than the GOP containing
167   // |media_time|.
168   if (!is_enabled_)
169     stream_->Seek(media_time);
170
171   // |media_time| is allowed to be a little imprecise here. GC only needs to
172   // know which GOP currentTime points to.
173   return stream_->GarbageCollectIfNeeded(media_time, newDataSize);
174 }
175
176 void ChunkDemuxerStream::OnMemoryPressure(
177     base::TimeDelta media_time,
178     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
179     bool force_instant_gc) {
180   // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
181   // ignored.
182   if (memory_pressure_level ==
183       base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
184     return;
185   }
186   base::AutoLock auto_lock(lock_);
187   return stream_->OnMemoryPressure(media_time, memory_pressure_level,
188                                    force_instant_gc);
189 }
190
191 void ChunkDemuxerStream::OnSetDuration(base::TimeDelta duration) {
192   base::AutoLock auto_lock(lock_);
193   stream_->OnSetDuration(duration);
194 }
195
196 Ranges<base::TimeDelta> ChunkDemuxerStream::GetBufferedRanges(
197     base::TimeDelta duration) const {
198   base::AutoLock auto_lock(lock_);
199
200   Ranges<base::TimeDelta> range = stream_->GetBufferedTime();
201
202   if (range.size() == 0u)
203     return range;
204
205   // Clamp the end of the stream's buffered ranges to fit within the duration.
206   // This can be done by intersecting the stream's range with the valid time
207   // range.
208   Ranges<base::TimeDelta> valid_time_range;
209   valid_time_range.Add(range.start(0), range.start(0) + duration);
210   return range.IntersectionWith(valid_time_range);
211 }
212
213 base::TimeDelta ChunkDemuxerStream::GetLowestPresentationTimestamp() const {
214   base::AutoLock auto_lock(lock_);
215   return stream_->GetLowestPresentationTimestamp();
216 }
217
218 base::TimeDelta ChunkDemuxerStream::GetHighestPresentationTimestamp() const {
219   base::AutoLock auto_lock(lock_);
220   return stream_->GetHighestPresentationTimestamp();
221 }
222
223 base::TimeDelta ChunkDemuxerStream::GetBufferedDuration() const {
224   base::AutoLock auto_lock(lock_);
225   return stream_->GetBufferedDuration();
226 }
227
228 size_t ChunkDemuxerStream::GetBufferedSize() const {
229   base::AutoLock auto_lock(lock_);
230   return stream_->GetBufferedSize();
231 }
232
233 void ChunkDemuxerStream::OnStartOfCodedFrameGroup(DecodeTimestamp start_dts,
234                                                   base::TimeDelta start_pts) {
235   DVLOG(2) << "ChunkDemuxerStream::OnStartOfCodedFrameGroup(dts "
236            << start_dts.InSecondsF() << ", pts " << start_pts.InSecondsF()
237            << ")";
238
239   if (group_start_observer_cb_)
240     group_start_observer_cb_.Run(start_dts, start_pts);
241
242   base::AutoLock auto_lock(lock_);
243   stream_->OnStartOfCodedFrameGroup(start_pts);
244 }
245
246 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config,
247                                            bool allow_codec_change,
248                                            MediaLog* media_log) {
249   DCHECK(config.IsValidConfig());
250   DCHECK_EQ(type_, AUDIO);
251   base::AutoLock auto_lock(lock_);
252   if (!stream_) {
253     DCHECK_EQ(state_, UNINITIALIZED);
254     stream_ = std::make_unique<SourceBufferStream>(config, media_log);
255     return true;
256   }
257
258   return stream_->UpdateAudioConfig(config, allow_codec_change);
259 }
260
261 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config,
262                                            bool allow_codec_change,
263                                            MediaLog* media_log) {
264   DCHECK(config.IsValidConfig());
265   DCHECK_EQ(type_, VIDEO);
266   base::AutoLock auto_lock(lock_);
267
268   if (!stream_) {
269     DCHECK_EQ(state_, UNINITIALIZED);
270     stream_ = std::make_unique<SourceBufferStream>(config, media_log);
271     return true;
272   }
273
274   return stream_->UpdateVideoConfig(config, allow_codec_change);
275 }
276
277 void ChunkDemuxerStream::MarkEndOfStream() {
278   base::AutoLock auto_lock(lock_);
279   stream_->MarkEndOfStream();
280 }
281
282 void ChunkDemuxerStream::UnmarkEndOfStream() {
283   base::AutoLock auto_lock(lock_);
284   stream_->UnmarkEndOfStream();
285 }
286
287 // DemuxerStream methods.
288 void ChunkDemuxerStream::Read(uint32_t count, ReadCB read_cb) {
289   base::AutoLock auto_lock(lock_);
290   DCHECK_NE(state_, UNINITIALIZED);
291   DCHECK(!read_cb_);
292
293   read_cb_ = base::BindPostTaskToCurrentDefault(std::move(read_cb));
294   requested_buffer_count_ = count;
295
296   if (!is_enabled_) {
297     DVLOG(1) << "Read from disabled stream, returning EOS";
298     std::move(read_cb_).Run(DemuxerStream::kOk,
299                             {StreamParserBuffer::CreateEOSBuffer()});
300     return;
301   }
302
303   CompletePendingReadIfPossible_Locked();
304 }
305
306 DemuxerStream::Type ChunkDemuxerStream::type() const { return type_; }
307
308 StreamLiveness ChunkDemuxerStream::liveness() const {
309   base::AutoLock auto_lock(lock_);
310   return liveness_;
311 }
312
313 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() {
314   CHECK_EQ(type_, AUDIO);
315   base::AutoLock auto_lock(lock_);
316   // Trying to track down crash. http://crbug.com/715761
317   CHECK(stream_);
318   return stream_->GetCurrentAudioDecoderConfig();
319 }
320
321 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() {
322   CHECK_EQ(type_, VIDEO);
323   base::AutoLock auto_lock(lock_);
324   // Trying to track down crash. http://crbug.com/715761
325   CHECK(stream_);
326   return stream_->GetCurrentVideoDecoderConfig();
327 }
328
329 bool ChunkDemuxerStream::SupportsConfigChanges() { return true; }
330
331 bool ChunkDemuxerStream::IsEnabled() const {
332   base::AutoLock auto_lock(lock_);
333   return is_enabled_;
334 }
335
336 void ChunkDemuxerStream::SetEnabled(bool enabled, base::TimeDelta timestamp) {
337   base::AutoLock auto_lock(lock_);
338
339   if (enabled == is_enabled_)
340     return;
341
342   is_enabled_ = enabled;
343   if (enabled) {
344     DCHECK(stream_);
345     stream_->Seek(timestamp);
346   } else if (read_cb_) {
347     DVLOG(1) << "Read from disabled stream, returning EOS";
348     std::move(read_cb_).Run(kOk, {StreamParserBuffer::CreateEOSBuffer()});
349   }
350 }
351
352 void ChunkDemuxerStream::SetStreamMemoryLimit(size_t memory_limit) {
353   base::AutoLock auto_lock(lock_);
354   stream_->set_memory_limit(memory_limit);
355 }
356
357 void ChunkDemuxerStream::SetLiveness(StreamLiveness liveness) {
358   base::AutoLock auto_lock(lock_);
359   liveness_ = liveness;
360 }
361
362 void ChunkDemuxerStream::ChangeState_Locked(State state) {
363   lock_.AssertAcquired();
364   DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : "
365            << "type " << type_
366            << " - " << state_ << " -> " << state;
367   state_ = state;
368 }
369
370 ChunkDemuxerStream::~ChunkDemuxerStream() = default;
371
372 void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() {
373   lock_.AssertAcquired();
374   DCHECK(read_cb_);
375
376   switch (state_) {
377     case UNINITIALIZED:
378       if (stream_->GetCurrentVideoDecoderConfig().is_rtc())
379         return;
380       NOTREACHED_NORETURN();
381     case RETURNING_ABORT_FOR_READS:
382       // Null buffers should be returned in this state since we are waiting
383       // for a seek. Any buffers in the SourceBuffer should NOT be returned
384       // because they are associated with the seek.
385       requested_buffer_count_ = 0;
386       std::move(read_cb_).Run(kAborted, {});
387       DVLOG(2) << __func__ << ": returning kAborted, type " << type_;
388       return;
389     case SHUTDOWN:
390       requested_buffer_count_ = 0;
391       std::move(read_cb_).Run(kOk, {StreamParserBuffer::CreateEOSBuffer()});
392       DVLOG(2) << __func__ << ": returning kOk with EOS buffer, type " << type_;
393       return;
394     case RETURNING_DATA_FOR_READS:
395       break;
396   }
397   DCHECK(state_ == RETURNING_DATA_FOR_READS);
398
399   auto [status, buffers] = GetPendingBuffers_Locked();
400
401   // If the status from |stream_| is kNeedBuffer and there's no buffers,
402   // then after ChunkDemuxerStream::Append, try to read data again,
403   // 'requested_buffer_count_' does not need to be cleared to 0.
404   if (status == SourceBufferStreamStatus::kNeedBuffer && buffers.empty()) {
405     return;
406   }
407   // If the status from |stream_| is kConfigChange, the vector muse be
408   // empty, then need to notify new config by running |read_cb_|.
409   if (status == SourceBufferStreamStatus::kConfigChange) {
410     DCHECK(buffers.empty());
411     requested_buffer_count_ = 0;
412     std::move(read_cb_).Run(kConfigChanged, std::move(buffers));
413     return;
414   }
415   // Other cases are kOk and just return the buffers.
416   DCHECK(!buffers.empty());
417   requested_buffer_count_ = 0;
418   std::move(read_cb_).Run(kOk, std::move(buffers));
419 }
420
421 std::pair<SourceBufferStreamStatus, DemuxerStream::DecoderBufferVector>
422 ChunkDemuxerStream::GetPendingBuffers_Locked() {
423   lock_.AssertAcquired();
424   DemuxerStream::DecoderBufferVector output_buffers;
425   for (uint32_t i = 0; i < requested_buffer_count_; ++i) {
426     // This aims to avoid send out buffers with different config. To
427     // simply the config change handling on renderer(receiver) side, prefer to
428     // send out buffers before config change happens.
429     if (stream_->IsNextBufferConfigChanged() && !output_buffers.empty()) {
430       DVLOG(3) << __func__ << " status=0"
431                << ", type=" << type_ << ", req_size=" << requested_buffer_count_
432                << ", out_size=" << output_buffers.size();
433       return {SourceBufferStreamStatus::kSuccess, std::move(output_buffers)};
434     }
435
436     scoped_refptr<StreamParserBuffer> buffer;
437     SourceBufferStreamStatus status = stream_->GetNextBuffer(&buffer);
438     switch (status) {
439       case SourceBufferStreamStatus::kSuccess:
440         output_buffers.emplace_back(buffer);
441         break;
442       case SourceBufferStreamStatus::kNeedBuffer:
443         // Return early with calling |read_cb_| if output_buffers has buffers
444         // since there is no more readable data.
445         DVLOG(3) << __func__ << " status=" << (int)status << ", type=" << type_
446                  << ", req_size=" << requested_buffer_count_
447                  << ", out_size=" << output_buffers.size();
448         return {status, std::move(output_buffers)};
449       case SourceBufferStreamStatus::kEndOfStream:
450         output_buffers.emplace_back(StreamParserBuffer::CreateEOSBuffer());
451         DVLOG(3) << __func__ << " status=" << (int)status << ", type=" << type_
452                  << ", req_size=" << requested_buffer_count_
453                  << ", out_size=" << output_buffers.size();
454         return {status, std::move(output_buffers)};
455       case SourceBufferStreamStatus::kConfigChange:
456         // Since IsNextBufferConfigChanged has detected config change happen and
457         // send out buffers if |output_buffers| has buffer. When confige
458         // change actually happen it should be the first time run this |for
459         // loop|, i.e. output_buffers should be empty.
460         DCHECK(output_buffers.empty());
461         DVLOG(3) << __func__ << " status=" << (int)status << ", type=" << type_
462                  << ", req_size=" << requested_buffer_count_
463                  << ", out_size=" << output_buffers.size();
464         return {status, std::move(output_buffers)};
465     }
466   }
467
468   DCHECK_EQ(output_buffers.size(),
469             static_cast<size_t>(requested_buffer_count_));
470   DVLOG(3) << __func__ << " status are always kSuccess"
471            << ", type=" << type_ << ", req_size=" << requested_buffer_count_
472            << ", out_size=" << output_buffers.size();
473   return {SourceBufferStreamStatus::kSuccess, std::move(output_buffers)};
474 }
475
476 ChunkDemuxer::ChunkDemuxer(
477     base::OnceClosure open_cb,
478     base::RepeatingClosure progress_cb,
479     EncryptedMediaInitDataCB encrypted_media_init_data_cb,
480     AudioTracksCountChangedCB audio_tracks_count_changed_cb,
481     MediaLog* media_log)
482     : open_cb_(std::move(open_cb)),
483       progress_cb_(std::move(progress_cb)),
484       encrypted_media_init_data_cb_(std::move(encrypted_media_init_data_cb)),
485       audio_tracks_count_changed_cb_(std::move(audio_tracks_count_changed_cb)),
486       media_log_(media_log) {
487   DCHECK(open_cb_);
488   DCHECK(encrypted_media_init_data_cb_);
489   MEDIA_LOG(INFO, media_log_) << GetDisplayName();
490 }
491
492 std::string ChunkDemuxer::GetDisplayName() const {
493   return "ChunkDemuxer";
494 }
495
496 DemuxerType ChunkDemuxer::GetDemuxerType() const {
497   return DemuxerType::kChunkDemuxer;
498 }
499
500 void ChunkDemuxer::Initialize(DemuxerHost* host,
501                               PipelineStatusCallback init_cb) {
502   DVLOG(1) << "Initialize()";
503   TRACE_EVENT_ASYNC_BEGIN0("media", "ChunkDemuxer::Initialize", this);
504
505   base::OnceClosure open_cb;
506
507   // Locked scope
508   {
509     base::AutoLock auto_lock(lock_);
510     if (state_ == SHUTDOWN) {
511       // Init cb must only be run after this method returns, so post.
512       init_cb_ = base::BindPostTaskToCurrentDefault(std::move(init_cb));
513       RunInitCB_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
514       return;
515     }
516
517     DCHECK_EQ(state_, WAITING_FOR_INIT);
518     host_ = host;
519     // Do not post init_cb once this function returns because if there is an
520     // error after initialization, the error might be reported before init_cb
521     // has a chance to run. This is because ChunkDemuxer::ReportError_Locked
522     // directly calls DemuxerHost::OnDemuxerError: crbug.com/633016.
523     init_cb_ = std::move(init_cb);
524
525     ChangeState_Locked(INITIALIZING);
526     open_cb = std::move(open_cb_);
527   }
528
529   std::move(open_cb).Run();
530
531 #if BUILDFLAG(IS_TIZEN_TV)
532   framerate_set_cb_ = base::BindPostTaskToCurrentDefault(base::BindRepeating(
533       &ChunkDemuxer::OnFramerateSet, base::Unretained(this)));
534 #endif
535 }
536
537 void ChunkDemuxer::Stop() {
538   DVLOG(1) << "Stop()";
539   Shutdown();
540 }
541
542 void ChunkDemuxer::Seek(base::TimeDelta time, PipelineStatusCallback cb) {
543   DVLOG(1) << "Seek(" << time.InSecondsF() << ")";
544   DCHECK(time >= base::TimeDelta());
545   TRACE_EVENT_ASYNC_BEGIN0("media", "ChunkDemuxer::Seek", this);
546
547   base::AutoLock auto_lock(lock_);
548   DCHECK(!seek_cb_);
549
550   seek_cb_ = base::BindPostTaskToCurrentDefault(std::move(cb));
551   if (state_ != INITIALIZED && state_ != ENDED) {
552     RunSeekCB_Locked(PIPELINE_ERROR_INVALID_STATE);
553     return;
554   }
555
556   if (cancel_next_seek_) {
557     cancel_next_seek_ = false;
558     RunSeekCB_Locked(PIPELINE_OK);
559     return;
560   }
561
562   SeekAllSources(time);
563   StartReturningData();
564
565   if (IsSeekWaitingForData_Locked()) {
566     DVLOG(1) << "Seek() : waiting for more data to arrive.";
567     return;
568   }
569
570   RunSeekCB_Locked(PIPELINE_OK);
571 }
572
573 bool ChunkDemuxer::IsSeekable() const {
574   return true;
575 }
576
577 // Demuxer implementation.
578 base::Time ChunkDemuxer::GetTimelineOffset() const {
579   return timeline_offset_;
580 }
581
582 std::vector<DemuxerStream*> ChunkDemuxer::GetAllStreams() {
583   base::AutoLock auto_lock(lock_);
584   std::vector<DemuxerStream*> result;
585   // Put enabled streams at the beginning of the list so that
586   // MediaResource::GetFirstStream returns the enabled stream if there is one.
587   // TODO(servolk): Revisit this after media track switching is supported.
588   for (const auto& stream : audio_streams_) {
589     if (stream->IsEnabled())
590       result.push_back(stream.get());
591   }
592   for (const auto& stream : video_streams_) {
593     if (stream->IsEnabled())
594       result.push_back(stream.get());
595   }
596   // Put disabled streams at the end of the vector.
597   for (const auto& stream : audio_streams_) {
598     if (!stream->IsEnabled())
599       result.push_back(stream.get());
600   }
601   for (const auto& stream : video_streams_) {
602     if (!stream->IsEnabled())
603       result.push_back(stream.get());
604   }
605   return result;
606 }
607
608 base::TimeDelta ChunkDemuxer::GetStartTime() const {
609   return base::TimeDelta();
610 }
611
612 int64_t ChunkDemuxer::GetMemoryUsage() const {
613   base::AutoLock auto_lock(lock_);
614   int64_t mem = 0;
615   for (const auto& s : audio_streams_)
616     mem += s->GetBufferedSize();
617   for (const auto& s : video_streams_)
618     mem += s->GetBufferedSize();
619   return mem;
620 }
621
622 absl::optional<container_names::MediaContainerName>
623 ChunkDemuxer::GetContainerForMetrics() const {
624   return absl::nullopt;
625 }
626
627 void ChunkDemuxer::AbortPendingReads() {
628   base::AutoLock auto_lock(lock_);
629   DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
630          state_ == PARSE_ERROR)
631       << state_;
632
633   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
634     return;
635
636   AbortPendingReads_Locked();
637 }
638
639 void ChunkDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {
640   DVLOG(1) << "StartWaitingForSeek()";
641   base::AutoLock auto_lock(lock_);
642   DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN ||
643          state_ == PARSE_ERROR) << state_;
644   DCHECK(!seek_cb_);
645
646   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
647     return;
648
649   AbortPendingReads_Locked();
650   SeekAllSources(seek_time);
651
652   // Cancel state set in CancelPendingSeek() since we want to
653   // accept the next Seek().
654   cancel_next_seek_ = false;
655 }
656
657 void ChunkDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {
658   base::AutoLock auto_lock(lock_);
659   DCHECK_NE(state_, INITIALIZING);
660   DCHECK(!seek_cb_ || IsSeekWaitingForData_Locked());
661
662   if (cancel_next_seek_)
663     return;
664
665   AbortPendingReads_Locked();
666   SeekAllSources(seek_time);
667
668   if (!seek_cb_) {
669     cancel_next_seek_ = true;
670     return;
671   }
672
673   RunSeekCB_Locked(PIPELINE_OK);
674 }
675
676 ChunkDemuxer::Status ChunkDemuxer::AddId(
677     const std::string& id,
678     std::unique_ptr<AudioDecoderConfig> audio_config) {
679   DCHECK(audio_config);
680   DVLOG(1) << __func__ << " id="
681            << " audio_config=" << audio_config->AsHumanReadableString();
682   base::AutoLock auto_lock(lock_);
683
684   // Any valid audio config provided by WC is bufferable here, though decode
685   // error may occur later.
686   if (!audio_config->IsValidConfig())
687     return ChunkDemuxer::kNotSupported;
688
689   if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) ||
690       IsValidId_Locked(id)) {
691     return kReachedIdLimit;
692   }
693
694   DCHECK(init_cb_);
695
696   std::string expected_codec = GetCodecName(audio_config->codec());
697   std::unique_ptr<media::StreamParser> stream_parser(
698       media::StreamParserFactory::Create(std::move(audio_config)));
699   DCHECK(stream_parser);
700
701   return AddIdInternal(id, std::move(stream_parser), expected_codec, false);
702 }
703
704 ChunkDemuxer::Status ChunkDemuxer::AddId(
705     const std::string& id,
706     std::unique_ptr<VideoDecoderConfig> video_config) {
707   DCHECK(video_config);
708   DVLOG(1) << __func__ << " id="
709            << " video_config=" << video_config->AsHumanReadableString();
710   base::AutoLock auto_lock(lock_);
711
712   // Any valid video config provided by WC is bufferable here, though decode
713   // error may occur later.
714   if (!video_config->IsValidConfig())
715     return ChunkDemuxer::kNotSupported;
716
717   if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) ||
718       IsValidId_Locked(id)) {
719     return kReachedIdLimit;
720   }
721
722   DCHECK(init_cb_);
723
724   std::string expected_codec = GetCodecName(video_config->codec());
725   std::unique_ptr<media::StreamParser> stream_parser(
726       media::StreamParserFactory::Create(std::move(video_config)));
727   DCHECK(stream_parser);
728
729   return AddIdInternal(id, std::move(stream_parser), expected_codec, true);
730 }
731
732 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
733                                          const std::string& content_type,
734                                          const std::string& codecs) {
735   DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
736            << " codecs=" << codecs;
737   base::AutoLock auto_lock(lock_);
738
739   if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) ||
740       IsValidId_Locked(id)) {
741     return kReachedIdLimit;
742   }
743
744   // TODO(wolenetz): Change to DCHECK once less verification in release build is
745   // needed. See https://crbug.com/786975.
746   CHECK(init_cb_);
747
748   bool has_audio = false;
749   bool has_video = false;
750
751   std::unique_ptr<media::StreamParser> stream_parser(
752       CreateParserForTypeAndCodecs(content_type, codecs, media_log_, &has_audio,
753                                    &has_video));
754   if (!stream_parser) {
755     DVLOG(1) << __func__ << " failed: unsupported content_type=" << content_type
756              << " codecs=" << codecs;
757     return ChunkDemuxer::kNotSupported;
758   }
759
760   return AddIdInternal(id, std::move(stream_parser),
761                        ExpectedCodecs(content_type, codecs), has_video);
762 }
763
764 ChunkDemuxer::Status ChunkDemuxer::AddIdInternal(
765     const std::string& id,
766     std::unique_ptr<media::StreamParser> stream_parser,
767     std::string expected_codecs,
768     bool has_video) {
769   DVLOG(2) << __func__ << " id=" << id
770            << " expected_codecs=" << expected_codecs;
771   lock_.AssertAcquired();
772
773   std::unique_ptr<FrameProcessor> frame_processor =
774       std::make_unique<FrameProcessor>(
775           base::BindRepeating(&ChunkDemuxer::IncreaseDurationIfNecessary,
776                               base::Unretained(this)),
777           media_log_);
778
779   std::unique_ptr<SourceBufferState> source_state =
780       std::make_unique<SourceBufferState>(
781           std::move(stream_parser), std::move(frame_processor),
782           base::BindRepeating(&ChunkDemuxer::CreateDemuxerStream,
783                               base::Unretained(this), id),
784           media_log_);
785
786 #if BUILDFLAG(IS_TIZEN_TV)
787   StreamParser::FramerateSetCB framerate_set_cb;
788   if (has_video)
789     framerate_set_cb = framerate_set_cb_;
790   else
791     // Audio don't need this call back.
792     framerate_set_cb.Reset();
793 #endif
794
795   // TODO(wolenetz): Change these to DCHECKs or switch to returning
796   // kReachedIdLimit once less verification in release build is needed. See
797   // https://crbug.com/786975.
798   CHECK(pending_source_init_ids_.find(id) == pending_source_init_ids_.end());
799   auto insert_result = pending_source_init_ids_.insert(id);
800   CHECK(insert_result.first != pending_source_init_ids_.end());
801   CHECK(*insert_result.first == id);
802   CHECK(insert_result.second);  // Only true if insertion succeeded.
803
804   source_state->Init(base::BindOnce(&ChunkDemuxer::OnSourceInitDone,
805                                     base::Unretained(this), id),
806                      expected_codecs,
807 #if BUILDFLAG(IS_TIZEN_TV)
808                      framerate_set_cb,
809 #endif
810                      encrypted_media_init_data_cb_);
811
812   // TODO(wolenetz): Change to DCHECKs once less verification in release build
813   // is needed. See https://crbug.com/786975.
814   CHECK(!IsValidId_Locked(id));
815   source_state_map_[id] = std::move(source_state);
816   CHECK(IsValidId_Locked(id));
817   return kOk;
818 }
819
820 void ChunkDemuxer::SetTracksWatcher(const std::string& id,
821                                     MediaTracksUpdatedCB tracks_updated_cb) {
822   base::AutoLock auto_lock(lock_);
823   CHECK(IsValidId_Locked(id));
824   media_tracks_updated_cb_[id] = tracks_updated_cb;
825   source_state_map_[id]->SetTracksWatcher(base::BindRepeating(
826       &ChunkDemuxer::InitSegmentReceived, base::Unretained(this), id));
827 }
828
829 void ChunkDemuxer::InitSegmentReceived(const std::string& id,
830                                        std::unique_ptr<MediaTracks> tracks) {
831   bool audio_track_detected = false;
832   for (const auto& track : tracks->tracks()) {
833     if (track->type() == MediaTrack::Type::kAudio) {
834       audio_tracks_count_[id]++;
835       audio_tracks_count_total_++;
836       audio_track_detected = true;
837     }
838   }
839   if (audio_track_detected)
840     audio_tracks_count_changed_cb_.Run(audio_tracks_count_total_);
841   media_tracks_updated_cb_[id].Run(std::move(tracks));
842 }
843
844 void ChunkDemuxer::SetParseWarningCallback(
845     const std::string& id,
846     SourceBufferParseWarningCB parse_warning_cb) {
847   base::AutoLock auto_lock(lock_);
848   CHECK(IsValidId_Locked(id));
849   source_state_map_[id]->SetParseWarningCallback(std::move(parse_warning_cb));
850 }
851
852 void ChunkDemuxer::RemoveId(const std::string& id) {
853   DVLOG(1) << __func__ << " id=" << id;
854   base::AutoLock auto_lock(lock_);
855   CHECK(IsValidId_Locked(id));
856
857   source_state_map_.erase(id);
858   pending_source_init_ids_.erase(id);
859   // Remove demuxer streams created for this id.
860   for (const ChunkDemuxerStream* s : id_to_streams_map_[id]) {
861     bool stream_found = false;
862     for (size_t i = 0; i < audio_streams_.size(); ++i) {
863       if (audio_streams_[i].get() == s) {
864         stream_found = true;
865         removed_streams_.push_back(std::move(audio_streams_[i]));
866         audio_streams_.erase(audio_streams_.begin() + i);
867         break;
868       }
869     }
870     if (stream_found)
871       continue;
872     for (size_t i = 0; i < video_streams_.size(); ++i) {
873       if (video_streams_[i].get() == s) {
874         stream_found = true;
875         removed_streams_.push_back(std::move(video_streams_[i]));
876         video_streams_.erase(video_streams_.begin() + i);
877         break;
878       }
879     }
880     CHECK(stream_found);
881   }
882   id_to_streams_map_.erase(id);
883
884   audio_tracks_count_total_ -= audio_tracks_count_[id];
885   audio_tracks_count_.erase(id);
886   audio_tracks_count_changed_cb_.Run(audio_tracks_count_total_);
887   media_tracks_updated_cb_.erase(id);
888 }
889
890 Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges(
891     const std::string& id) const {
892   base::AutoLock auto_lock(lock_);
893   DCHECK(!id.empty());
894
895   auto itr = source_state_map_.find(id);
896
897   DCHECK(itr != source_state_map_.end());
898   return itr->second->GetBufferedRanges(duration_, state_ == ENDED);
899 }
900
901 base::TimeDelta ChunkDemuxer::GetLowestPresentationTimestamp(
902     const std::string& id) const {
903   base::AutoLock auto_lock(lock_);
904   DCHECK(!id.empty());
905
906   auto itr = source_state_map_.find(id);
907
908   DCHECK(itr != source_state_map_.end());
909   return itr->second->GetLowestPresentationTimestamp();
910 }
911
912 base::TimeDelta ChunkDemuxer::GetHighestPresentationTimestamp(
913     const std::string& id) const {
914   base::AutoLock auto_lock(lock_);
915   DCHECK(!id.empty());
916
917   auto itr = source_state_map_.find(id);
918
919   DCHECK(itr != source_state_map_.end());
920   return itr->second->GetHighestPresentationTimestamp();
921 }
922
923 void ChunkDemuxer::FindAndEnableProperTracks(
924     const std::vector<MediaTrack::Id>& track_ids,
925     base::TimeDelta curr_time,
926     DemuxerStream::Type track_type,
927     TrackChangeCB change_completed_cb) {
928   base::AutoLock auto_lock(lock_);
929
930   std::set<ChunkDemuxerStream*> enabled_streams;
931   for (const auto& id : track_ids) {
932     auto it = track_id_to_demux_stream_map_.find(id);
933     if (it == track_id_to_demux_stream_map_.end())
934       continue;
935     ChunkDemuxerStream* stream = it->second;
936     DCHECK(stream);
937     DCHECK_EQ(track_type, stream->type());
938     // TODO(servolk): Remove after multiple enabled audio tracks are supported
939     // by the media::RendererImpl.
940     if (!enabled_streams.empty()) {
941       MEDIA_LOG(INFO, media_log_)
942           << "Only one enabled track is supported, ignoring track " << id;
943       continue;
944     }
945     enabled_streams.insert(stream);
946     stream->SetEnabled(true, curr_time);
947   }
948
949   bool is_audio = track_type == DemuxerStream::AUDIO;
950   for (const auto& stream : is_audio ? audio_streams_ : video_streams_) {
951     if (stream && enabled_streams.find(stream.get()) == enabled_streams.end()) {
952       DVLOG(1) << __func__ << ": disabling stream " << stream.get();
953       stream->SetEnabled(false, curr_time);
954     }
955   }
956
957   std::vector<DemuxerStream*> streams(enabled_streams.begin(),
958                                       enabled_streams.end());
959   std::move(change_completed_cb).Run(track_type, streams);
960 }
961
962 void ChunkDemuxer::OnEnabledAudioTracksChanged(
963     const std::vector<MediaTrack::Id>& track_ids,
964     base::TimeDelta curr_time,
965     TrackChangeCB change_completed_cb) {
966   FindAndEnableProperTracks(track_ids, curr_time, DemuxerStream::AUDIO,
967                             std::move(change_completed_cb));
968 }
969
970 void ChunkDemuxer::OnSelectedVideoTrackChanged(
971     const std::vector<MediaTrack::Id>& track_ids,
972     base::TimeDelta curr_time,
973     TrackChangeCB change_completed_cb) {
974   FindAndEnableProperTracks(track_ids, curr_time, DemuxerStream::VIDEO,
975                             std::move(change_completed_cb));
976 }
977
978 void ChunkDemuxer::DisableCanChangeType() {
979   supports_change_type_ = false;
980 }
981
982 void ChunkDemuxer::OnMemoryPressure(
983     base::TimeDelta currentMediaTime,
984     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
985     bool force_instant_gc) {
986   // TODO(sebmarchand): Check if MEMORY_PRESSURE_LEVEL_MODERATE should also be
987   // ignored.
988   if (memory_pressure_level ==
989       base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
990     return;
991   }
992   base::AutoLock auto_lock(lock_);
993   for (const auto& [source, state] : source_state_map_) {
994     state->OnMemoryPressure(currentMediaTime, memory_pressure_level,
995                             force_instant_gc);
996   }
997 }
998
999 bool ChunkDemuxer::EvictCodedFrames(const std::string& id,
1000                                     base::TimeDelta currentMediaTime,
1001                                     size_t newDataSize) {
1002   DVLOG(1) << __func__ << "(" << id << ")"
1003            << " media_time=" << currentMediaTime.InSecondsF()
1004            << " newDataSize=" << newDataSize;
1005   base::AutoLock auto_lock(lock_);
1006
1007   DCHECK(!id.empty());
1008   auto itr = source_state_map_.find(id);
1009   if (itr == source_state_map_.end()) {
1010     LOG(WARNING) << __func__ << " stream " << id << " not found";
1011     return false;
1012   }
1013   return itr->second->EvictCodedFrames(currentMediaTime, newDataSize);
1014 }
1015
1016 bool ChunkDemuxer::AppendToParseBuffer(const std::string& id,
1017                                        const uint8_t* data,
1018                                        size_t length) {
1019   DVLOG(1) << "AppendToParseBuffer(" << id << ", " << length << ")";
1020
1021   DCHECK(!id.empty());
1022
1023   if (length == 0u) {
1024     // We don't DCHECK that |state_| != ENDED here, since |state_| is protected
1025     // by |lock_|. However, transition into ENDED can happen only on
1026     // MarkEndOfStream called by the MediaSource object on parse failure or on
1027     // app calling endOfStream(). In case that contract is violated for
1028     // nonzero-length appends, we still DCHECK within the lock, below.
1029     return true;
1030   }
1031
1032   DCHECK(data);
1033
1034   {
1035     base::AutoLock auto_lock(lock_);
1036     DCHECK_NE(state_, ENDED);
1037
1038     switch (state_) {
1039       case INITIALIZING:
1040       case INITIALIZED:
1041         DCHECK(IsValidId_Locked(id));
1042         if (!source_state_map_[id]->AppendToParseBuffer(data, length)) {
1043           // Just indicate that the append failed. Let the caller give app an
1044           // error so that it may adapt. This is different from
1045           // RunSegmentParserLoop(), where fatal MediaSource failure should
1046           // occur if the underlying parse fails.
1047           return false;
1048         }
1049         break;
1050
1051       case PARSE_ERROR:
1052       case WAITING_FOR_INIT:
1053       case ENDED:
1054       case SHUTDOWN:
1055         DVLOG(1) << "AppendToParseBuffer(): called in unexpected state "
1056                  << state_;
1057         // To preserve previous app-visible behavior in this hopefully
1058         // never-encountered path, report no failure to caller due to being in
1059         // invalid underlying state. If caller then proceeds with async parse
1060         // (via RunSegmentParserLoop, below), they will get the expected parse
1061         // failure for this set of states. If, instead, we returned false here,
1062         // then caller would instead tell app QuotaExceededErr synchronous with
1063         // the app's appendBuffer() call, instead of async decode error during
1064         // async parse.
1065         // TODO(crbug.com/1379160): Instrument this path to see if it can be
1066         // changed to just NOTREACHED() << state_.
1067         return true;
1068     }
1069   }
1070
1071   return true;
1072 }
1073
1074 StreamParser::ParseStatus ChunkDemuxer::RunSegmentParserLoop(
1075     const std::string& id,
1076     base::TimeDelta append_window_start,
1077     base::TimeDelta append_window_end,
1078     base::TimeDelta* timestamp_offset) {
1079   DVLOG(1) << "RunSegmentParserLoop(" << id << ")";
1080
1081   DCHECK(!id.empty());
1082   DCHECK(timestamp_offset);
1083
1084   Ranges<base::TimeDelta> ranges;
1085
1086   StreamParser::ParseStatus result = StreamParser::ParseStatus::kFailed;
1087
1088   {
1089     base::AutoLock auto_lock(lock_);
1090     DCHECK_NE(state_, ENDED);
1091
1092     // Capture if any of the SourceBuffers are waiting for data before we start
1093     // parsing.
1094     bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1095
1096     switch (state_) {
1097       case INITIALIZING:
1098       case INITIALIZED:
1099         DCHECK(IsValidId_Locked(id));
1100         result = source_state_map_[id]->RunSegmentParserLoop(
1101             append_window_start, append_window_end, timestamp_offset);
1102         if (result == StreamParser::ParseStatus::kFailed) {
1103           ReportError_Locked(CHUNK_DEMUXER_ERROR_APPEND_FAILED);
1104           return result;
1105         }
1106         break;
1107
1108       case PARSE_ERROR:
1109       case WAITING_FOR_INIT:
1110       case ENDED:
1111       case SHUTDOWN:
1112         DVLOG(1) << "RunSegmentParserLoop(): called in unexpected state "
1113                  << state_;
1114         return StreamParser::ParseStatus::kFailed;
1115     }
1116
1117     // Check to see if newly parsed data was at the pending seek point. This
1118     // indicates we have parsed enough data to complete the seek. Work is still
1119     // in progress at this point, but it's okay since |seek_cb_| will post.
1120     if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_) {
1121       RunSeekCB_Locked(PIPELINE_OK);
1122     }
1123
1124     ranges = GetBufferedRanges_Locked();
1125   }
1126
1127   DCHECK_NE(StreamParser::ParseStatus::kFailed, result);
1128   host_->OnBufferedTimeRangesChanged(ranges);
1129   progress_cb_.Run();
1130   return result;
1131 }
1132
1133 bool ChunkDemuxer::AppendChunks(
1134     const std::string& id,
1135     std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
1136     base::TimeDelta append_window_start,
1137     base::TimeDelta append_window_end,
1138     base::TimeDelta* timestamp_offset) {
1139   DCHECK(buffer_queue);
1140   DVLOG(1) << __func__ << ": " << id
1141            << ", buffer_queue size()=" << buffer_queue->size();
1142
1143   DCHECK(!id.empty());
1144   DCHECK(timestamp_offset);
1145
1146   Ranges<base::TimeDelta> ranges;
1147
1148   {
1149     base::AutoLock auto_lock(lock_);
1150     DCHECK_NE(state_, ENDED);
1151
1152     // Capture if any of the SourceBuffers are waiting for data before we start
1153     // buffering new chunks.
1154     bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1155
1156     if (buffer_queue->size() == 0u)
1157       return true;
1158
1159     switch (state_) {
1160       case INITIALIZING:
1161       case INITIALIZED:
1162         DCHECK(IsValidId_Locked(id));
1163         if (!source_state_map_[id]->AppendChunks(
1164                 std::move(buffer_queue), append_window_start, append_window_end,
1165                 timestamp_offset)) {
1166           ReportError_Locked(CHUNK_DEMUXER_ERROR_APPEND_FAILED);
1167           return false;
1168         }
1169         break;
1170
1171       case PARSE_ERROR:
1172       case WAITING_FOR_INIT:
1173       case ENDED:
1174       case SHUTDOWN:
1175         DVLOG(1) << "AppendChunks(): called in unexpected state " << state_;
1176         return false;
1177     }
1178
1179     // Check to see if data was appended at the pending seek point. This
1180     // indicates we have parsed enough data to complete the seek. Work is still
1181     // in progress at this point, but it's okay since |seek_cb_| will post.
1182     if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
1183       RunSeekCB_Locked(PIPELINE_OK);
1184
1185     ranges = GetBufferedRanges_Locked();
1186   }
1187
1188   host_->OnBufferedTimeRangesChanged(ranges);
1189   progress_cb_.Run();
1190   return true;
1191 }
1192
1193 void ChunkDemuxer::ResetParserState(const std::string& id,
1194                                     base::TimeDelta append_window_start,
1195                                     base::TimeDelta append_window_end,
1196                                     base::TimeDelta* timestamp_offset) {
1197   DVLOG(1) << "ResetParserState(" << id << ")";
1198   base::AutoLock auto_lock(lock_);
1199   DCHECK(!id.empty());
1200   CHECK(IsValidId_Locked(id));
1201   bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1202   source_state_map_[id]->ResetParserState(append_window_start,
1203                                           append_window_end,
1204                                           timestamp_offset);
1205   // ResetParserState can possibly emit some buffers.
1206   // Need to check whether seeking can be completed.
1207   if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
1208     RunSeekCB_Locked(PIPELINE_OK);
1209 }
1210
1211 void ChunkDemuxer::Remove(const std::string& id,
1212                           base::TimeDelta start,
1213                           base::TimeDelta end) {
1214   DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF()
1215            << ", " << end.InSecondsF() << ")";
1216   base::AutoLock auto_lock(lock_);
1217
1218   DCHECK(!id.empty());
1219   CHECK(IsValidId_Locked(id));
1220   DCHECK(start >= base::TimeDelta()) << start.InSecondsF();
1221   DCHECK(start < end) << "start " << start.InSecondsF()
1222                       << " end " << end.InSecondsF();
1223   DCHECK(duration_ != kNoTimestamp);
1224   DCHECK(start <= duration_) << "start " << start.InSecondsF()
1225                              << " duration " << duration_.InSecondsF();
1226
1227   if (start == duration_)
1228     return;
1229
1230   source_state_map_[id]->Remove(start, end, duration_);
1231   host_->OnBufferedTimeRangesChanged(GetBufferedRanges_Locked());
1232 }
1233
1234 bool ChunkDemuxer::CanChangeType(const std::string& id,
1235                                  const std::string& content_type,
1236                                  const std::string& codecs) {
1237   // Note, Chromium currently will not compare content_type and codecs, if any,
1238   // with previous content_type and codecs of the SourceBuffer.
1239   // TODO(wolenetz): Consider returning false if the codecs parameters are ever
1240   // made to be precise such that they signal that the number of tracks of
1241   // various media types differ from the first initialization segment (if
1242   // received already).  Switching to an audio-only container, when the first
1243   // initialization segment only contained non-audio tracks, is one example we
1244   // could enforce earlier here.
1245
1246   DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
1247            << " codecs=" << codecs;
1248   base::AutoLock auto_lock(lock_);
1249
1250   DCHECK(IsValidId_Locked(id));
1251
1252   if (!supports_change_type_) {
1253     return false;
1254   }
1255
1256   // CanChangeType() doesn't care if there has or hasn't been received a first
1257   // initialization segment for the source buffer corresponding to |id|.
1258   bool has_audio = false;
1259   bool has_video = false;
1260
1261   std::unique_ptr<media::StreamParser> stream_parser(
1262       CreateParserForTypeAndCodecs(content_type, codecs, media_log_, &has_audio,
1263                                    &has_video));
1264   return !!stream_parser;
1265 }
1266
1267 void ChunkDemuxer::ChangeType(const std::string& id,
1268                               const std::string& content_type,
1269                               const std::string& codecs) {
1270   DVLOG(1) << __func__ << " id=" << id << " content_type=" << content_type
1271            << " codecs=" << codecs;
1272
1273   base::AutoLock auto_lock(lock_);
1274
1275   DCHECK(state_ == INITIALIZING || state_ == INITIALIZED) << state_;
1276   DCHECK(IsValidId_Locked(id));
1277
1278   bool has_audio = false;
1279   bool has_video = false;
1280
1281   std::unique_ptr<media::StreamParser> stream_parser(
1282       CreateParserForTypeAndCodecs(content_type, codecs, media_log_, &has_audio,
1283                                    &has_video));
1284   // Caller should query CanChangeType() first to protect from failing this.
1285   DCHECK(stream_parser);
1286
1287 #if BUILDFLAG(IS_TIZEN_TV)
1288   StreamParser::FramerateSetCB framerate_set_cb;
1289   if (has_video)
1290     framerate_set_cb = framerate_set_cb_;
1291   else
1292     // Audio don't need this call back.
1293     framerate_set_cb.Reset();
1294 #endif
1295   source_state_map_[id]->ChangeType(std::move(stream_parser),
1296 #if BUILDFLAG(IS_TIZEN_TV)
1297                                     framerate_set_cb,
1298 #endif
1299                                     ExpectedCodecs(content_type, codecs));
1300 }
1301
1302 double ChunkDemuxer::GetDuration() {
1303   base::AutoLock auto_lock(lock_);
1304   return GetDuration_Locked();
1305 }
1306
1307 double ChunkDemuxer::GetDuration_Locked() {
1308   lock_.AssertAcquired();
1309   if (duration_ == kNoTimestamp)
1310     return std::numeric_limits<double>::quiet_NaN();
1311
1312   // Return positive infinity if the resource is unbounded.
1313   // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration
1314   if (duration_ == kInfiniteDuration)
1315     return std::numeric_limits<double>::infinity();
1316
1317   if (user_specified_duration_ >= 0)
1318     return user_specified_duration_;
1319
1320   return duration_.InSecondsF();
1321 }
1322
1323 void ChunkDemuxer::SetDuration(double duration) {
1324   base::AutoLock auto_lock(lock_);
1325   DVLOG(1) << "SetDuration(" << duration << ")";
1326   DCHECK_GE(duration, 0);
1327
1328   if (duration == GetDuration_Locked())
1329     return;
1330
1331   // Compute & bounds check the base::TimeDelta representation of duration.
1332   // This can be different if the value of |duration| doesn't fit the range or
1333   // precision of base::TimeDelta.
1334   base::TimeDelta min_duration = base::TimeDelta::FromInternalValue(1);
1335   // Don't use base::TimeDelta::Max() here, as we want the largest finite time
1336   // delta.
1337   base::TimeDelta max_duration = base::TimeDelta::FromInternalValue(
1338       std::numeric_limits<int64_t>::max() - 1);
1339   double min_duration_in_seconds = min_duration.InSecondsF();
1340   double max_duration_in_seconds = max_duration.InSecondsF();
1341
1342   base::TimeDelta duration_td;
1343   if (duration == std::numeric_limits<double>::infinity()) {
1344     duration_td = media::kInfiniteDuration;
1345   } else if (duration < min_duration_in_seconds) {
1346     duration_td = min_duration;
1347   } else if (duration > max_duration_in_seconds) {
1348     duration_td = max_duration;
1349   } else {
1350     duration_td =
1351         base::Microseconds(duration * base::Time::kMicrosecondsPerSecond);
1352   }
1353
1354   DCHECK(duration_td.is_positive());
1355
1356   user_specified_duration_ = duration;
1357   duration_ = duration_td;
1358   host_->SetDuration(duration_);
1359
1360   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1361        ++itr) {
1362     itr->second->OnSetDuration(duration_);
1363   }
1364 }
1365
1366 bool ChunkDemuxer::IsParsingMediaSegment(const std::string& id) {
1367   base::AutoLock auto_lock(lock_);
1368   DVLOG(1) << "IsParsingMediaSegment(" << id << ")";
1369   CHECK(IsValidId_Locked(id));
1370
1371   return source_state_map_[id]->parsing_media_segment();
1372 }
1373
1374 bool ChunkDemuxer::GetGenerateTimestampsFlag(const std::string& id) {
1375   base::AutoLock auto_lock(lock_);
1376   DVLOG(1) << "GetGenerateTimestampsFlag(" << id << ")";
1377   CHECK(IsValidId_Locked(id));
1378
1379   return source_state_map_[id]->generate_timestamps_flag();
1380 }
1381
1382 void ChunkDemuxer::SetSequenceMode(const std::string& id,
1383                                    bool sequence_mode) {
1384   base::AutoLock auto_lock(lock_);
1385   DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")";
1386   CHECK(IsValidId_Locked(id));
1387   DCHECK_NE(state_, ENDED);
1388
1389   source_state_map_[id]->SetSequenceMode(sequence_mode);
1390 }
1391
1392 void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode(
1393     const std::string& id,
1394     base::TimeDelta timestamp_offset) {
1395   base::AutoLock auto_lock(lock_);
1396   DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", "
1397            << timestamp_offset.InSecondsF() << ")";
1398   CHECK(IsValidId_Locked(id));
1399   DCHECK_NE(state_, ENDED);
1400
1401   source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode(
1402       timestamp_offset);
1403 }
1404
1405
1406 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) {
1407   DVLOG(1) << "MarkEndOfStream(" << status << ")";
1408   base::AutoLock auto_lock(lock_);
1409   DCHECK_NE(state_, WAITING_FOR_INIT);
1410   DCHECK_NE(state_, ENDED);
1411
1412   if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
1413     return;
1414
1415   if (state_ == INITIALIZING) {
1416     MEDIA_LOG(ERROR, media_log_)
1417         << "MediaSource endOfStream before demuxer initialization completes "
1418            "(before HAVE_METADATA) is treated as an error. This may also occur "
1419            "as consequence of other MediaSource errors before HAVE_METADATA.";
1420     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1421     return;
1422   }
1423
1424   bool old_waiting_for_data = IsSeekWaitingForData_Locked();
1425   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1426        ++itr) {
1427     itr->second->MarkEndOfStream();
1428   }
1429
1430   CompletePendingReadsIfPossible();
1431
1432   // Give a chance to resume the pending seek process.
1433   if (status != PIPELINE_OK) {
1434     DCHECK(status == CHUNK_DEMUXER_ERROR_EOS_STATUS_DECODE_ERROR ||
1435            status == CHUNK_DEMUXER_ERROR_EOS_STATUS_NETWORK_ERROR);
1436     ReportError_Locked(status);
1437     return;
1438   }
1439
1440   ChangeState_Locked(ENDED);
1441   DecreaseDurationIfNecessary();
1442
1443   if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && seek_cb_)
1444     RunSeekCB_Locked(PIPELINE_OK);
1445 }
1446
1447 void ChunkDemuxer::UnmarkEndOfStream() {
1448   DVLOG(1) << "UnmarkEndOfStream()";
1449   base::AutoLock auto_lock(lock_);
1450   DCHECK(state_ == ENDED || state_ == SHUTDOWN || state_ == PARSE_ERROR)
1451       << state_;
1452
1453   // At least ReportError_Locked()'s error reporting to Blink hops threads, so
1454   // SourceBuffer may not be aware of media element error on another operation
1455   // that might race to this point.
1456   if (state_ == PARSE_ERROR || state_ == SHUTDOWN)
1457     return;
1458
1459   ChangeState_Locked(INITIALIZED);
1460
1461   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1462        ++itr) {
1463     itr->second->UnmarkEndOfStream();
1464   }
1465 }
1466
1467 void ChunkDemuxer::Shutdown() {
1468   DVLOG(1) << "Shutdown()";
1469   base::AutoLock auto_lock(lock_);
1470
1471   if (state_ == SHUTDOWN)
1472     return;
1473
1474   ShutdownAllStreams();
1475
1476   ChangeState_Locked(SHUTDOWN);
1477
1478   if (seek_cb_)
1479     RunSeekCB_Locked(PIPELINE_ERROR_ABORT);
1480 }
1481
1482 void ChunkDemuxer::SetMemoryLimitsForTest(DemuxerStream::Type type,
1483                                           size_t memory_limit) {
1484   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1485        ++itr) {
1486     itr->second->SetMemoryLimits(type, memory_limit);
1487   }
1488 }
1489
1490 void ChunkDemuxer::ChangeState_Locked(State new_state) {
1491   lock_.AssertAcquired();
1492   DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : "
1493            << state_ << " -> " << new_state;
1494
1495   // TODO(wolenetz): Change to DCHECK once less verification in release build is
1496   // needed. See https://crbug.com/786975.
1497   // Disallow changes from at or beyond PARSE_ERROR to below PARSE_ERROR.
1498   CHECK(!(state_ >= PARSE_ERROR && new_state < PARSE_ERROR));
1499
1500   state_ = new_state;
1501 }
1502
1503 ChunkDemuxer::~ChunkDemuxer() {
1504   DCHECK_NE(state_, INITIALIZED);
1505 }
1506
1507 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
1508   DVLOG(1) << "ReportError_Locked(" << error << ")";
1509   lock_.AssertAcquired();
1510   DCHECK(error != PIPELINE_OK);
1511
1512   ChangeState_Locked(PARSE_ERROR);
1513
1514   if (init_cb_) {
1515     RunInitCB_Locked(error);
1516     return;
1517   }
1518
1519   ShutdownAllStreams();
1520   if (seek_cb_) {
1521     RunSeekCB_Locked(error);
1522     return;
1523   }
1524
1525   base::AutoUnlock auto_unlock(lock_);
1526   host_->OnDemuxerError(error);
1527 }
1528
1529 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const {
1530   lock_.AssertAcquired();
1531   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1532        ++itr) {
1533     if (itr->second->IsSeekWaitingForData())
1534       return true;
1535   }
1536
1537   return false;
1538 }
1539
1540 #if BUILDFLAG(IS_TIZEN_TV)
1541 void ChunkDemuxer::OnFramerateSet(const StreamFramerate::Framerate& framerate) {
1542   if (framerate.num && framerate.den) {
1543     for (const auto& s : video_streams_)
1544       s->SetFramerate(framerate);
1545   }
1546 }
1547 #endif
1548
1549 void ChunkDemuxer::OnSourceInitDone(
1550     const std::string& source_id,
1551     const StreamParser::InitParameters& params) {
1552   DVLOG(1) << "OnSourceInitDone source_id=" << source_id
1553            << " duration=" << params.duration.InSecondsF();
1554   lock_.AssertAcquired();
1555
1556   // TODO(wolenetz): Change these to DCHECKs once less verification in release
1557   // build is needed. See https://crbug.com/786975.
1558   CHECK(!pending_source_init_ids_.empty());
1559   CHECK(IsValidId_Locked(source_id));
1560   CHECK(pending_source_init_ids_.find(source_id) !=
1561         pending_source_init_ids_.end());
1562   CHECK(init_cb_);
1563   CHECK_EQ(state_, INITIALIZING);
1564   if (audio_streams_.empty() && video_streams_.empty()) {
1565     ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1566     return;
1567   }
1568
1569   if (!params.duration.is_zero() && duration_ == kNoTimestamp)
1570     UpdateDuration(params.duration);
1571
1572   if (!params.timeline_offset.is_null()) {
1573     if (!timeline_offset_.is_null() &&
1574         params.timeline_offset != timeline_offset_) {
1575       MEDIA_LOG(ERROR, media_log_)
1576           << "Timeline offset is not the same across all SourceBuffers.";
1577       ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1578       return;
1579     }
1580
1581     timeline_offset_ = params.timeline_offset;
1582   }
1583
1584   if (params.liveness != StreamLiveness::kUnknown) {
1585     for (const auto& s : audio_streams_)
1586       s->SetLiveness(params.liveness);
1587     for (const auto& s : video_streams_)
1588       s->SetLiveness(params.liveness);
1589   }
1590
1591   // Wait until all streams have initialized.
1592   pending_source_init_ids_.erase(source_id);
1593   if (!pending_source_init_ids_.empty())
1594     return;
1595
1596   SeekAllSources(GetStartTime());
1597   StartReturningData();
1598
1599   if (duration_ == kNoTimestamp)
1600     duration_ = kInfiniteDuration;
1601
1602   // The demuxer is now initialized after the |start_timestamp_| was set.
1603   // TODO(wolenetz): Change these to DCHECKs once less verification in release
1604   // build is needed. See https://crbug.com/786975.
1605   CHECK_EQ(state_, INITIALIZING);
1606   ChangeState_Locked(INITIALIZED);
1607   RunInitCB_Locked(PIPELINE_OK);
1608 }
1609
1610 // static
1611 MediaTrack::Id ChunkDemuxer::GenerateMediaTrackId() {
1612   static unsigned g_track_count = 0;
1613   return MediaTrack::Id(base::NumberToString(++g_track_count));
1614 }
1615
1616 ChunkDemuxerStream* ChunkDemuxer::CreateDemuxerStream(
1617     const std::string& source_id,
1618     DemuxerStream::Type type) {
1619   // New ChunkDemuxerStreams can be created only during initialization segment
1620   // processing, which happens when a new chunk of data is appended and the
1621   // lock_ must be held by ChunkDemuxer::RunSegmentParserLoop/AppendChunks.
1622   lock_.AssertAcquired();
1623
1624   MediaTrack::Id media_track_id = GenerateMediaTrackId();
1625
1626   OwnedChunkDemuxerStreamVector* owning_vector = nullptr;
1627   switch (type) {
1628     case DemuxerStream::AUDIO:
1629       owning_vector = &audio_streams_;
1630       break;
1631
1632     case DemuxerStream::VIDEO:
1633       owning_vector = &video_streams_;
1634       break;
1635
1636     case DemuxerStream::UNKNOWN:
1637       NOTREACHED_NORETURN();
1638   }
1639
1640   std::unique_ptr<ChunkDemuxerStream> stream =
1641       std::make_unique<ChunkDemuxerStream>(type, media_track_id);
1642   DCHECK(track_id_to_demux_stream_map_.find(media_track_id) ==
1643          track_id_to_demux_stream_map_.end());
1644   track_id_to_demux_stream_map_[media_track_id] = stream.get();
1645   id_to_streams_map_[source_id].push_back(stream.get());
1646   stream->SetEnabled(owning_vector->empty(), base::TimeDelta());
1647   owning_vector->push_back(std::move(stream));
1648   return owning_vector->back().get();
1649 }
1650
1651 bool ChunkDemuxer::IsValidId_Locked(const std::string& source_id) const {
1652   lock_.AssertAcquired();
1653   return source_state_map_.count(source_id) > 0u;
1654 }
1655
1656 void ChunkDemuxer::UpdateDuration(base::TimeDelta new_duration) {
1657   DCHECK(duration_ != new_duration ||
1658          user_specified_duration_ != new_duration.InSecondsF());
1659   user_specified_duration_ = -1;
1660   duration_ = new_duration;
1661   host_->SetDuration(new_duration);
1662 }
1663
1664 void ChunkDemuxer::IncreaseDurationIfNecessary(base::TimeDelta new_duration) {
1665   DCHECK(new_duration != kNoTimestamp);
1666   DCHECK(new_duration != kInfiniteDuration);
1667
1668   // Per April 1, 2014 MSE spec editor's draft:
1669   // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
1670   //     media-source.html#sourcebuffer-coded-frame-processing
1671   // 5. If the media segment contains data beyond the current duration, then run
1672   //    the duration change algorithm with new duration set to the maximum of
1673   //    the current duration and the group end timestamp.
1674
1675   if (new_duration <= duration_)
1676     return;
1677
1678   DVLOG(2) << __func__ << ": Increasing duration: " << duration_.InSecondsF()
1679            << " -> " << new_duration.InSecondsF();
1680
1681   UpdateDuration(new_duration);
1682 }
1683
1684 void ChunkDemuxer::DecreaseDurationIfNecessary() {
1685   lock_.AssertAcquired();
1686
1687   base::TimeDelta max_duration;
1688
1689   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1690        ++itr) {
1691     max_duration = std::max(max_duration,
1692                             itr->second->GetMaxBufferedDuration());
1693   }
1694
1695   if (max_duration.is_zero())
1696     return;
1697
1698   // Note: be careful to also check |user_specified_duration_|, which may have
1699   // higher precision than |duration_|.
1700   if (max_duration < duration_ ||
1701       max_duration.InSecondsF() < user_specified_duration_) {
1702     UpdateDuration(max_duration);
1703   }
1704 }
1705
1706 Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges() const {
1707   base::AutoLock auto_lock(lock_);
1708   return GetBufferedRanges_Locked();
1709 }
1710
1711 Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges_Locked() const {
1712   lock_.AssertAcquired();
1713
1714   bool ended = state_ == ENDED;
1715   // TODO(acolwell): When we start allowing SourceBuffers that are not active,
1716   // we'll need to update this loop to only add ranges from active sources.
1717   SourceBufferState::RangesList ranges_list;
1718   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1719        ++itr) {
1720     ranges_list.push_back(itr->second->GetBufferedRanges(duration_, ended));
1721   }
1722
1723   return SourceBufferState::ComputeRangesIntersection(ranges_list, ended);
1724 }
1725
1726 void ChunkDemuxer::StartReturningData() {
1727   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1728        ++itr) {
1729     itr->second->StartReturningData();
1730   }
1731 }
1732
1733 void ChunkDemuxer::AbortPendingReads_Locked() {
1734   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1735        ++itr) {
1736     itr->second->AbortReads();
1737   }
1738 }
1739
1740 void ChunkDemuxer::SeekAllSources(base::TimeDelta seek_time) {
1741   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1742        ++itr) {
1743     itr->second->Seek(seek_time);
1744   }
1745 }
1746
1747 void ChunkDemuxer::CompletePendingReadsIfPossible() {
1748   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1749        ++itr) {
1750     itr->second->CompletePendingReadIfPossible();
1751   }
1752 }
1753
1754 void ChunkDemuxer::ShutdownAllStreams() {
1755   for (auto itr = source_state_map_.begin(); itr != source_state_map_.end();
1756        ++itr) {
1757     itr->second->Shutdown();
1758   }
1759 }
1760
1761 void ChunkDemuxer::RunInitCB_Locked(PipelineStatus status) {
1762   lock_.AssertAcquired();
1763   DCHECK(init_cb_);
1764   TRACE_EVENT_ASYNC_END1("media", "ChunkDemuxer::Initialize", this, "status",
1765                          PipelineStatusToString(status));
1766   std::move(init_cb_).Run(status);
1767 }
1768
1769 void ChunkDemuxer::RunSeekCB_Locked(PipelineStatus status) {
1770   lock_.AssertAcquired();
1771   DCHECK(seek_cb_);
1772   TRACE_EVENT_ASYNC_END1("media", "ChunkDemuxer::Seek", this, "status",
1773                          PipelineStatusToString(status));
1774   std::move(seek_cb_).Run(status);
1775 }
1776
1777 }  // namespace media