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.
5 #ifndef MEDIA_FILTERS_CHUNK_DEMUXER_H_
6 #define MEDIA_FILTERS_CHUNK_DEMUXER_H_
16 #include "base/containers/circular_deque.h"
17 #include "base/memory/memory_pressure_listener.h"
18 #include "base/memory/raw_ptr.h"
19 #include "base/synchronization/lock.h"
20 #include "base/thread_annotations.h"
21 #include "base/time/time.h"
22 #include "media/base/demuxer.h"
23 #include "media/base/demuxer_stream.h"
24 #include "media/base/media_tracks.h"
25 #include "media/base/ranges.h"
26 #include "media/base/stream_parser.h"
27 #include "media/filters/source_buffer_parse_warnings.h"
28 #include "media/filters/source_buffer_state.h"
29 #include "media/filters/source_buffer_stream.h"
31 class MEDIA_EXPORT SourceBufferStream;
35 class AudioDecoderConfig;
36 class VideoDecoderConfig;
38 class MEDIA_EXPORT ChunkDemuxerStream : public DemuxerStream {
40 using BufferQueue = base::circular_deque<scoped_refptr<StreamParserBuffer>>;
42 ChunkDemuxerStream() = delete;
44 ChunkDemuxerStream(Type type, MediaTrack::Id media_track_id);
46 ChunkDemuxerStream(const ChunkDemuxerStream&) = delete;
47 ChunkDemuxerStream& operator=(const ChunkDemuxerStream&) = delete;
49 ~ChunkDemuxerStream() override;
51 // ChunkDemuxerStream control methods.
52 void StartReturningData();
54 void CompletePendingReadIfPossible();
57 #if BUILDFLAG(IS_TIZEN_TV)
58 void SetFramerate(const StreamFramerate::Framerate& framerate);
61 // SourceBufferStream manipulation methods.
62 void Seek(base::TimeDelta time);
63 bool IsSeekWaitingForData() const;
65 // Add buffers to this stream. Buffers are stored in SourceBufferStreams,
66 // which handle ordering and overlap resolution.
67 // Returns true if buffers were successfully added.
68 bool Append(const StreamParser::BufferQueue& buffers);
70 // Removes buffers between |start| and |end| according to the steps
71 // in the "Coded Frame Removal Algorithm" in the Media Source
73 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-coded-frame-removal
75 // |duration| is the current duration of the presentation. It is
76 // required by the computation outlined in the spec.
77 void Remove(base::TimeDelta start, base::TimeDelta end,
78 base::TimeDelta duration);
80 // If the buffer is full, attempts to try to free up space, as specified in
81 // the "Coded Frame Eviction Algorithm" in the Media Source Extensions Spec.
82 // Returns false iff buffer is still full after running eviction.
83 // https://w3c.github.io/media-source/#sourcebuffer-coded-frame-eviction
84 bool EvictCodedFrames(base::TimeDelta media_time, size_t newDataSize);
86 void OnMemoryPressure(
87 base::TimeDelta media_time,
88 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
89 bool force_instant_gc);
91 // Signal to the stream that duration has changed to |duration|.
92 void OnSetDuration(base::TimeDelta duration);
94 // Returns the range of buffered data in this stream, capped at |duration|.
95 Ranges<base::TimeDelta> GetBufferedRanges(base::TimeDelta duration) const;
97 // Returns the lowest PTS of the buffered data.
98 // Returns base::TimeDelta() if the stream has no buffered data.
99 base::TimeDelta GetLowestPresentationTimestamp() const;
101 // Returns the highest PTS of the buffered data.
102 // Returns base::TimeDelta() if the stream has no buffered data.
103 base::TimeDelta GetHighestPresentationTimestamp() const;
105 // Returns the duration of the buffered data.
106 // Returns base::TimeDelta() if the stream has no buffered data.
107 base::TimeDelta GetBufferedDuration() const;
109 // Returns the size of the buffered data in bytes.
110 size_t GetBufferedSize() const;
112 // Signal to the stream that buffers handed in through subsequent calls to
113 // Append() belong to a coded frame group that starts at |start_pts|.
114 // |start_dts| is used only to help tests verify correctness of calls to this
115 // method. If |group_start_observer_cb_| is set, first invokes this test-only
116 // callback with |start_dts| and |start_pts| to assist test verification.
117 void OnStartOfCodedFrameGroup(DecodeTimestamp start_dts,
118 base::TimeDelta start_pts);
120 // Called when midstream config updates occur.
121 // For audio and video, if the codec is allowed to change, the caller should
122 // set |allow_codec_change| to true.
123 // Returns true if the new config is accepted.
124 // Returns false if the new config should trigger an error.
125 bool UpdateAudioConfig(const AudioDecoderConfig& config,
126 bool allow_codec_change,
127 MediaLog* media_log);
128 bool UpdateVideoConfig(const VideoDecoderConfig& config,
129 bool allow_codec_change,
130 MediaLog* media_log);
132 void MarkEndOfStream();
133 void UnmarkEndOfStream();
135 // DemuxerStream methods.
136 void Read(uint32_t count, ReadCB read_cb) override;
137 Type type() const override;
138 StreamLiveness liveness() const override;
139 AudioDecoderConfig audio_decoder_config() override;
140 VideoDecoderConfig video_decoder_config() override;
141 bool SupportsConfigChanges() override;
143 bool IsEnabled() const;
144 void SetEnabled(bool enabled, base::TimeDelta timestamp);
146 // Sets the memory limit, in bytes, on the SourceBufferStream.
147 void SetStreamMemoryLimit(size_t memory_limit);
149 void SetLiveness(StreamLiveness liveness);
151 MediaTrack::Id media_track_id() const { return media_track_id_; }
153 // Allows tests to verify invocations of Append().
154 using AppendObserverCB = base::RepeatingCallback<void(const BufferQueue*)>;
155 void set_append_observer_for_testing(AppendObserverCB append_observer_cb) {
156 append_observer_cb_ = std::move(append_observer_cb);
159 // Allows tests to verify invocations of OnStartOfCodedFrameGroup().
160 using GroupStartObserverCB =
161 base::RepeatingCallback<void(DecodeTimestamp, base::TimeDelta)>;
162 void set_group_start_observer_for_testing(
163 GroupStartObserverCB group_start_observer_cb) {
164 group_start_observer_cb_ = std::move(group_start_observer_cb);
170 RETURNING_DATA_FOR_READS,
171 RETURNING_ABORT_FOR_READS,
175 // Assigns |state_| to |state|
176 void ChangeState_Locked(State state) EXCLUSIVE_LOCKS_REQUIRED(lock_);
178 void CompletePendingReadIfPossible_Locked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
180 std::pair<SourceBufferStreamStatus, DemuxerStream::DecoderBufferVector>
181 GetPendingBuffers_Locked() EXCLUSIVE_LOCKS_REQUIRED(lock_);
183 // Specifies the type of the stream.
186 StreamLiveness liveness_ GUARDED_BY(lock_);
188 std::unique_ptr<SourceBufferStream> stream_ GUARDED_BY(lock_);
190 const MediaTrack::Id media_track_id_;
192 // Test-only callbacks to assist verification of Append() and
193 // OnStartOfCodedFrameGroup() calls, respectively.
194 AppendObserverCB append_observer_cb_;
195 GroupStartObserverCB group_start_observer_cb_;
197 // Requested buffer count. The actual returned buffer count could be less
198 // according to DemuxerStream::Read() API.
199 uint32_t requested_buffer_count_ = 0;
201 mutable base::Lock lock_;
202 State state_ GUARDED_BY(lock_);
203 ReadCB read_cb_ GUARDED_BY(lock_);
204 bool is_enabled_ GUARDED_BY(lock_);
207 // Demuxer implementation that allows chunks of media data to be passed
208 // from JavaScript to the media stack.
209 class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
212 kOk, // ID added w/o error.
213 kNotSupported, // Type specified is not supported.
214 kReachedIdLimit, // Reached ID limit. We can't handle any more IDs.
217 // |open_cb| Run when Initialize() is called to signal that the demuxer
218 // is ready to receive media data via AppendToParseBuffer()/AppendChunks().
219 // |progress_cb| Run each time data is appended.
220 // |encrypted_media_init_data_cb| Run when the demuxer determines that an
221 // encryption key is needed to decrypt the content.
222 // |media_log| Used to report content and engine debug messages.
223 ChunkDemuxer(base::OnceClosure open_cb,
224 base::RepeatingClosure progress_cb,
225 EncryptedMediaInitDataCB encrypted_media_init_data_cb,
226 AudioTracksCountChangedCB audio_tracks_count_changed_cb,
227 MediaLog* media_log);
229 ChunkDemuxer(const ChunkDemuxer&) = delete;
230 ChunkDemuxer& operator=(const ChunkDemuxer&) = delete;
232 ~ChunkDemuxer() override;
234 // Demuxer implementation.
235 std::string GetDisplayName() const override;
236 DemuxerType GetDemuxerType() const override;
238 void Initialize(DemuxerHost* host, PipelineStatusCallback init_cb) override;
239 void Stop() override;
240 void Seek(base::TimeDelta time, PipelineStatusCallback cb) override;
241 bool IsSeekable() const override;
242 base::Time GetTimelineOffset() const override;
243 std::vector<DemuxerStream*> GetAllStreams() override;
244 base::TimeDelta GetStartTime() const override;
245 int64_t GetMemoryUsage() const override;
246 absl::optional<container_names::MediaContainerName> GetContainerForMetrics()
248 void AbortPendingReads() override;
250 // ChunkDemuxer reads are abortable. StartWaitingForSeek() and
251 // CancelPendingSeek() always abort pending and future reads until the
252 // expected seek occurs, so that ChunkDemuxer can stay synchronized with the
253 // associated JS method calls.
254 void StartWaitingForSeek(base::TimeDelta seek_time) override;
255 void CancelPendingSeek(base::TimeDelta seek_time) override;
257 // Registers a new `id` to use for AppendToParseBuffer(),
258 // RunSegmentParserLoop(), AppendChunks(), etc calls. `content_type` indicates
259 // the MIME type's ContentType and `codecs` indicates the MIME type's "codecs"
260 // parameter string (if any) for the data that we intend to append for this
261 // ID. kOk is returned if the demuxer has enough resources to support another
262 // ID and supports the format indicated by `content_type` and `codecs`.
263 // kReachedIdLimit is returned if the demuxer cannot handle another ID right
264 // now. kNotSupported is returned if `content_type` and `codecs` is not a
266 // The `audio_config` and `video_config` overloads behave similarly, except
267 // the caller must provide valid, supported decoder configs; those overloads'
268 // usage indicates that we intend to append WebCodecs encoded audio or video
269 // chunks for this ID.
270 [[nodiscard]] Status AddId(const std::string& id,
271 const std::string& content_type,
272 const std::string& codecs);
273 [[nodiscard]] Status AddId(const std::string& id,
274 std::unique_ptr<AudioDecoderConfig> audio_config);
275 [[nodiscard]] Status AddId(const std::string& id,
276 std::unique_ptr<VideoDecoderConfig> video_config);
278 // Notifies a caller via `tracks_updated_cb` that the set of media tracks
279 // for a given `id` has changed. This callback must be set before any calls to
280 // AppendToParseBuffer() for this `id`.
281 void SetTracksWatcher(const std::string& id,
282 MediaTracksUpdatedCB tracks_updated_cb);
284 // Notifies a caller via `parse_warning_cb` of a parse warning. This callback
285 // must be set before any calls to AppendToParseBuffer() for this `id`.
286 void SetParseWarningCallback(const std::string& id,
287 SourceBufferParseWarningCB parse_warning_cb);
289 // Removed an ID & associated resources that were previously added with
291 void RemoveId(const std::string& id);
293 // Gets the currently buffered ranges for the specified ID.
294 Ranges<base::TimeDelta> GetBufferedRanges(const std::string& id) const;
296 // Gets the lowest buffered PTS for the specified |id|. If there is nothing
297 // buffered, returns base::TimeDelta().
298 base::TimeDelta GetLowestPresentationTimestamp(const std::string& id) const;
300 // Gets the highest buffered PTS for the specified |id|. If there is nothing
301 // buffered, returns base::TimeDelta().
302 base::TimeDelta GetHighestPresentationTimestamp(const std::string& id) const;
304 void OnEnabledAudioTracksChanged(const std::vector<MediaTrack::Id>& track_ids,
305 base::TimeDelta curr_time,
306 TrackChangeCB change_completed_cb) override;
308 void OnSelectedVideoTrackChanged(const std::vector<MediaTrack::Id>& track_ids,
309 base::TimeDelta curr_time,
310 TrackChangeCB change_completed_cb) override;
312 void SetPlaybackRate(double rate) override {}
314 void DisableCanChangeType() override;
316 // Appends media data to the source buffer's stream parser associated with
317 // `id`. No parsing is done, just buffering the media data for future parsing
318 // via RunSegmentParserLoop calls. Returns true on success. Returns false if
319 // the parser was unable to allocate resources; content in `data` is not
320 // copied as a result, and this failure is reported (through various layers)
321 // up to the SourceBuffer's implementation of appendBuffer(), which should
322 // then notify the app of append failure using a `QuotaExceededErr` exception
323 // per the MSE specification. App could use a back-off and retry strategy or
324 // otherwise alter their behavior to attempt to buffer media for further
326 [[nodiscard]] bool AppendToParseBuffer(const std::string& id,
330 // Tells the stream parser for the source buffer associated with `id` to parse
331 // more of the data previously sent to it from this object's
332 // AppendToParseBuffer(). This operation applies and possibly updates
333 // `*timestamp_offset` during coded frame processing. `append_window_start`
334 // and `append_window_end` correspond to the MSE spec's similarly named source
335 // buffer attributes that are used in coded frame processing.
336 // Returns kSuccess if the segment parser loop iteration succeeded and all
337 // previously provided data from AppendToParseBuffer() has been inspected.
338 // Returns kSuccessHasMoreData if the segment parser loop iteration succeeded,
339 // yet there remains uninspected data remaining from AppendToParseBuffer();
340 // more call(s) to this method are necessary for the parser to attempt
341 // inspection of that data.
342 // Returns kFailed if the segment parser loop iteration hit error and the
343 // caller needs to run the append error algorithm with decode error parameter
345 [[nodiscard]] StreamParser::ParseStatus RunSegmentParserLoop(
346 const std::string& id,
347 base::TimeDelta append_window_start,
348 base::TimeDelta append_window_end,
349 base::TimeDelta* timestamp_offset);
351 // Appends webcodecs encoded chunks (already converted by caller into a
352 // BufferQueue of StreamParserBuffers) to the source buffer associated with
353 // |id|, with same semantic for other parameters and return value as
354 // RunSegmentParserLoop().
355 [[nodiscard]] bool AppendChunks(
356 const std::string& id,
357 std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
358 base::TimeDelta append_window_start,
359 base::TimeDelta append_window_end,
360 base::TimeDelta* timestamp_offset);
362 // Aborts parsing the current segment and reset the parser to a state where
363 // it can accept a new segment.
364 // Some pending frames can be emitted during that process. These frames are
365 // applied |timestamp_offset|.
366 void ResetParserState(const std::string& id,
367 base::TimeDelta append_window_start,
368 base::TimeDelta append_window_end,
369 base::TimeDelta* timestamp_offset);
371 // Remove buffers between |start| and |end| for the source buffer
372 // associated with |id|.
373 void Remove(const std::string& id, base::TimeDelta start,
374 base::TimeDelta end);
376 // Returns whether or not the source buffer associated with |id| can change
377 // its parser type to one which parses |content_type| and |codecs|.
378 // |content_type| indicates the ContentType of the MIME type for the data that
379 // we intend to append for this |id|; |codecs| similarly indicates the MIME
380 // type's "codecs" parameter, if any.
381 bool CanChangeType(const std::string& id,
382 const std::string& content_type,
383 const std::string& codecs);
385 // For the source buffer associated with |id|, changes its parser type to one
386 // which parses |content_type| and |codecs|. |content_type| indicates the
387 // ContentType of the MIME type for the data that we intend to append for this
388 // |id|; |codecs| similarly indicates the MIME type's "codecs" parameter, if
389 // any. Caller must first ensure CanChangeType() returns true for the same
390 // parameters. Caller must also ensure that ResetParserState() is done before
391 // calling this, to flush any pending frames.
392 void ChangeType(const std::string& id,
393 const std::string& content_type,
394 const std::string& codecs);
396 // If the buffer is full, attempts to try to free up space, as specified in
397 // the "Coded Frame Eviction Algorithm" in the Media Source Extensions Spec.
398 // Returns false iff buffer is still full after running eviction.
399 // https://w3c.github.io/media-source/#sourcebuffer-coded-frame-eviction
400 [[nodiscard]] bool EvictCodedFrames(const std::string& id,
401 base::TimeDelta currentMediaTime,
404 void OnMemoryPressure(
405 base::TimeDelta currentMediaTime,
406 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
407 bool force_instant_gc);
409 // Returns the current presentation duration.
410 double GetDuration();
411 double GetDuration_Locked();
413 // Notifies the demuxer that the duration of the media has changed to
415 void SetDuration(double duration);
417 // Returns true if the source buffer associated with |id| is currently parsing
418 // a media segment, or false otherwise.
419 bool IsParsingMediaSegment(const std::string& id);
421 // Returns the 'Generate Timestamps Flag', as described in the MSE Byte Stream
422 // Format Registry, for the source buffer associated with |id|.
423 bool GetGenerateTimestampsFlag(const std::string& id);
425 // Set the append mode to be applied to subsequent buffers appended to the
426 // source buffer associated with |id|. If |sequence_mode| is true, caller
427 // is requesting "sequence" mode. Otherwise, caller is requesting "segments"
429 void SetSequenceMode(const std::string& id, bool sequence_mode);
431 // Signals the coded frame processor for the source buffer associated with
432 // |id| to update its group start timestamp to be |timestamp_offset| if it is
433 // in sequence append mode.
434 void SetGroupStartTimestampIfInSequenceMode(const std::string& id,
435 base::TimeDelta timestamp_offset);
437 // Called to signal changes in the "end of stream"
438 // state. UnmarkEndOfStream() must not be called if a matching
439 // MarkEndOfStream() has not come before it.
440 void MarkEndOfStream(PipelineStatus status);
441 void UnmarkEndOfStream();
445 // Sets the memory limit on each stream of a specific type.
446 // |memory_limit| is the maximum number of bytes each stream of type |type|
447 // is allowed to hold in its buffer.
448 void SetMemoryLimitsForTest(DemuxerStream::Type type, size_t memory_limit);
450 // Returns the ranges representing the buffered data in the demuxer.
451 // TODO(wolenetz): Remove this method once MediaSourceDelegate no longer
452 // requires it for doing hack browser seeks to I-frame on Android. See
453 // http://crbug.com/304234.
454 Ranges<base::TimeDelta> GetBufferedRanges() const;
458 WAITING_FOR_INIT = 0,
463 // Any State at or beyond PARSE_ERROR cannot be changed to a state before
464 // this. See ChangeState_Locked.
469 // Helper for AddId's creation of FrameProcessor, and
470 // SourceBufferState creation, initialization and tracking in
471 // source_state_map_.
472 ChunkDemuxer::Status AddIdInternal(
473 const std::string& id,
474 std::unique_ptr<media::StreamParser> stream_parser,
475 std::string expected_codecs,
478 // Helper for vide and audio track changing.
479 void FindAndEnableProperTracks(const std::vector<MediaTrack::Id>& track_ids,
480 base::TimeDelta curr_time,
481 DemuxerStream::Type track_type,
482 TrackChangeCB change_completed_cb);
484 void ChangeState_Locked(State new_state);
486 // Reports an error and puts the demuxer in a state where it won't accept more
488 void ReportError_Locked(PipelineStatus error);
490 // Returns true if any stream has seeked to a time without buffered data.
491 bool IsSeekWaitingForData_Locked() const;
493 // Returns true if all streams can successfully call EndOfStream,
494 // false if any can not.
495 bool CanEndOfStream_Locked() const;
497 // SourceBufferState callbacks.
498 void OnSourceInitDone(const std::string& source_id,
499 const StreamParser::InitParameters& params);
501 #if BUILDFLAG(IS_TIZEN_TV)
502 void OnFramerateSet(const StreamFramerate::Framerate& framerate);
505 void InitSegmentReceived(const std::string& id,
506 std::unique_ptr<MediaTracks> tracks);
508 // Creates a DemuxerStream of the specified |type| for the SourceBufferState
509 // with the given |source_id|.
510 // Returns a pointer to a new ChunkDemuxerStream instance, which is owned by
512 ChunkDemuxerStream* CreateDemuxerStream(const std::string& source_id,
513 DemuxerStream::Type type);
515 // Returns true if |source_id| is valid, false otherwise.
516 bool IsValidId_Locked(const std::string& source_id) const;
518 // Increases |duration_| to |new_duration|, if |new_duration| is higher.
519 void IncreaseDurationIfNecessary(base::TimeDelta new_duration);
521 // Decreases |duration_| if the buffered region is less than |duration_| when
522 // EndOfStream() is called.
523 void DecreaseDurationIfNecessary();
525 // Sets |duration_| to |new_duration|, sets |user_specified_duration_| to -1
526 // and notifies |host_|.
527 void UpdateDuration(base::TimeDelta new_duration);
529 // Returns the ranges representing the buffered data in the demuxer.
530 Ranges<base::TimeDelta> GetBufferedRanges_Locked() const;
532 // Start returning data on all DemuxerStreams.
533 void StartReturningData();
535 void AbortPendingReads_Locked();
537 // Completes any pending reads if it is possible to do so.
538 void CompletePendingReadsIfPossible();
540 // Seeks all SourceBufferStreams to |seek_time|.
541 void SeekAllSources(base::TimeDelta seek_time);
543 // Generates and returns a unique media track id.
544 static MediaTrack::Id GenerateMediaTrackId();
546 // Shuts down all DemuxerStreams by calling Shutdown() on
547 // all objects in |source_state_map_|.
548 void ShutdownAllStreams();
550 // Executes |init_cb_| with |status| and closes out the async trace.
551 void RunInitCB_Locked(PipelineStatus status);
553 // Executes |seek_cb_| with |status| and closes out the async trace.
554 void RunSeekCB_Locked(PipelineStatus status);
556 mutable base::Lock lock_;
557 State state_ = WAITING_FOR_INIT;
558 bool cancel_next_seek_ = false;
560 // Found dangling on `linux-rel` in
561 // `benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.
562 // system_health.memory_desktop/browse:media:youtubetv:2019`.
563 raw_ptr<DemuxerHost, DanglingUntriaged> host_ = nullptr;
564 base::OnceClosure open_cb_;
565 const base::RepeatingClosure progress_cb_;
566 EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
568 AudioTracksCountChangedCB audio_tracks_count_changed_cb_;
569 std::map<std::string, MediaTracksUpdatedCB> media_tracks_updated_cb_;
571 // MediaLog for reporting messages and properties to debug content and engine.
572 raw_ptr<MediaLog> media_log_;
574 PipelineStatusCallback init_cb_;
575 // Callback to execute upon seek completion.
576 // TODO(wolenetz/acolwell): Protect against possible double-locking by first
577 // releasing |lock_| before executing this callback. See
578 // http://crbug.com/308226
579 PipelineStatusCallback seek_cb_;
581 using OwnedChunkDemuxerStreamVector =
582 std::vector<std::unique_ptr<ChunkDemuxerStream>>;
583 OwnedChunkDemuxerStreamVector audio_streams_;
584 OwnedChunkDemuxerStreamVector video_streams_;
586 // Keep track of which ids still remain uninitialized so that we transition
587 // into the INITIALIZED only after all ids/SourceBuffers got init segment.
588 std::set<std::string> pending_source_init_ids_;
590 #if BUILDFLAG(IS_TIZEN_TV)
591 StreamParser::FramerateSetCB framerate_set_cb_;
594 std::map<std::string, unsigned> audio_tracks_count_;
595 unsigned audio_tracks_count_total_{0};
597 base::TimeDelta duration_ = kNoTimestamp;
599 // The duration passed to the last SetDuration(). If SetDuration() is never
600 // called or a RunSegmentParserLoop()/AppendChunks() call or a EndOfStream()
601 // call changes `duration_`, then this variable is set to < 0 to indicate that
602 // the `duration_` represents the actual duration instead of a user specified
604 double user_specified_duration_ = -1;
606 base::Time timeline_offset_;
607 StreamLiveness liveness_ = StreamLiveness::kUnknown;
609 std::map<std::string, std::unique_ptr<SourceBufferState>> source_state_map_;
611 std::map<std::string, std::vector<ChunkDemuxerStream*>> id_to_streams_map_;
612 // Used to hold alive the demuxer streams that were created for removed /
613 // released SourceBufferState objects. Demuxer clients might still have
614 // references to these streams, so we need to keep them alive. But they'll be
615 // in a shut down state, so reading from them will return EOS.
616 std::vector<std::unique_ptr<ChunkDemuxerStream>> removed_streams_;
618 std::map<MediaTrack::Id, ChunkDemuxerStream*> track_id_to_demux_stream_map_;
620 bool supports_change_type_ = true;
625 #endif // MEDIA_FILTERS_CHUNK_DEMUXER_H_