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.
5 #ifndef MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_
6 #define MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_
9 #include "base/memory/memory_pressure_listener.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/time/time.h"
12 #include "media/base/audio_codecs.h"
13 #include "media/base/demuxer.h"
14 #include "media/base/demuxer_stream.h"
15 #include "media/base/media_export.h"
16 #include "media/base/media_log.h"
17 #include "media/base/stream_parser.h"
18 #include "media/base/stream_parser_buffer.h"
19 #include "media/base/video_codecs.h"
20 #include "media/filters/source_buffer_parse_warnings.h"
25 class ChunkDemuxerStream;
28 // Contains state belonging to a source id.
29 class MEDIA_EXPORT SourceBufferState {
31 // Callback signature used to create ChunkDemuxerStreams.
32 using CreateDemuxerStreamCB =
33 base::RepeatingCallback<ChunkDemuxerStream*(DemuxerStream::Type)>;
35 using NewTextTrackCB = base::RepeatingCallback<void(ChunkDemuxerStream*,
36 const TextTrackConfig&)>;
38 SourceBufferState(std::unique_ptr<StreamParser> stream_parser,
39 std::unique_ptr<FrameProcessor> frame_processor,
40 CreateDemuxerStreamCB create_demuxer_stream_cb,
43 SourceBufferState(const SourceBufferState&) = delete;
44 SourceBufferState& operator=(const SourceBufferState&) = delete;
48 void Init(StreamParser::InitCB init_cb,
49 const std::string& expected_codecs,
50 const StreamParser::EncryptedMediaInitDataCB&
51 encrypted_media_init_data_cb,
52 NewTextTrackCB new_text_track_cb);
54 // Reconfigures this source buffer to use |new_stream_parser|. Caller must
55 // first ensure that ResetParserState() was done to flush any pending frames
56 // from the old stream parser.
57 void ChangeType(std::unique_ptr<StreamParser> new_stream_parser,
58 const std::string& new_expected_codecs);
60 // Appends new data to the StreamParser.
61 // Returns true if the data was successfully appended. Returns false if an
62 // error occurred. |*timestamp_offset| is used and possibly updated by the
63 // append. |append_window_start| and |append_window_end| correspond to the MSE
64 // spec's similarly named source buffer attributes that are used in coded
66 // AppendChunks appends the provided BufferQueue.
67 bool Append(const uint8_t* data,
69 base::TimeDelta append_window_start,
70 base::TimeDelta append_window_end,
71 base::TimeDelta* timestamp_offset);
72 bool AppendChunks(std::unique_ptr<StreamParser::BufferQueue> buffer_queue,
73 base::TimeDelta append_window_start,
74 base::TimeDelta append_window_end,
75 base::TimeDelta* timestamp_offset);
77 // Aborts the current append sequence and resets the parser.
78 void ResetParserState(base::TimeDelta append_window_start,
79 base::TimeDelta append_window_end,
80 base::TimeDelta* timestamp_offset);
82 // Calls Remove(|start|, |end|, |duration|) on all
83 // ChunkDemuxerStreams managed by this object.
84 void Remove(base::TimeDelta start,
86 base::TimeDelta duration);
88 // If the buffer is full, attempts to try to free up space, as specified in
89 // the "Coded Frame Eviction Algorithm" in the Media Source Extensions Spec.
90 // Returns false iff buffer is still full after running eviction.
91 // https://w3c.github.io/media-source/#sourcebuffer-coded-frame-eviction
92 bool EvictCodedFrames(base::TimeDelta media_time, size_t newDataSize);
94 // Gets invoked when the system is experiencing memory pressure, i.e. there's
95 // not enough free memory. The |media_time| is the media playback position at
96 // the time of memory pressure notification (needed for accurate GC). The
97 // |memory_pressure_level| indicates memory pressure severity. The
98 // |force_instant_gc| is used to force the MSE garbage collection algorithm to
99 // be run right away, without waiting for the next append.
100 void OnMemoryPressure(
101 base::TimeDelta media_time,
102 base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level,
103 bool force_instant_gc);
105 // Returns true if currently parsing a media segment, or false otherwise.
106 bool parsing_media_segment() const { return parsing_media_segment_; }
108 // Returns the 'Generate Timestamps Flag' for this SourceBuffer's byte stream
109 // format parser as described in the MSE Byte Stream Format Registry.
110 bool generate_timestamps_flag() const {
111 return stream_parser_->GetGenerateTimestampsFlag();
114 // Sets |frame_processor_|'s sequence mode to |sequence_mode|.
115 void SetSequenceMode(bool sequence_mode);
117 // Signals the coded frame processor to update its group start timestamp to be
118 // |timestamp_offset| if it is in sequence append mode.
119 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset);
121 // Returns the range of buffered data in this source, capped at |duration|.
122 // |ended| - Set to true if end of stream has been signaled and the special
123 // end of stream range logic needs to be executed.
124 Ranges<base::TimeDelta> GetBufferedRanges(base::TimeDelta duration,
127 // Returns the highest PTS of currently buffered frames in this source, or
128 // base::TimeDelta() if none of the streams contain buffered data.
129 base::TimeDelta GetHighestPresentationTimestamp() const;
131 // Returns the highest buffered duration across all streams managed
133 // Returns base::TimeDelta() if none of the streams contain buffered data.
134 base::TimeDelta GetMaxBufferedDuration() const;
136 // Helper methods that call methods with similar names on all the
137 // ChunkDemuxerStreams managed by this object.
138 void StartReturningData();
140 void Seek(base::TimeDelta seek_time);
141 void CompletePendingReadIfPossible();
142 void OnSetDuration(base::TimeDelta duration);
143 void MarkEndOfStream();
144 void UnmarkEndOfStream();
146 // Sets the memory limit on each stream of a specific type.
147 // |memory_limit| is the maximum number of bytes each stream of type |type|
148 // is allowed to hold in its buffer.
149 void SetMemoryLimits(DemuxerStream::Type type, size_t memory_limit);
150 bool IsSeekWaitingForData() const;
152 using RangesList = std::vector<Ranges<base::TimeDelta>>;
153 static Ranges<base::TimeDelta> ComputeRangesIntersection(
154 const RangesList& active_ranges,
157 void SetTracksWatcher(Demuxer::MediaTracksUpdatedCB tracks_updated_cb);
159 void SetParseWarningCallback(SourceBufferParseWarningCB parse_warning_cb);
162 // State advances through this list to PARSER_INITIALIZED.
163 // The intent is to ensure at least one config is received prior to parser
164 // calling initialization callback, and that such initialization callback
165 // occurs at most once per parser.
166 // PENDING_PARSER_RECONFIG occurs if State had reached PARSER_INITIALIZED
167 // before changing to a new StreamParser in ChangeType(). In such case, State
168 // would then advance to PENDING_PARSER_REINIT, then PARSER_INITIALIZED upon
169 // the next initialization segment parsed, but would not run the
170 // initialization callback in this case (since such would already have
171 // occurred on the initial transition from PENDING_PARSER_INIT to
172 // PARSER_INITIALIZED.)
175 PENDING_PARSER_CONFIG,
178 PENDING_PARSER_RECONFIG,
179 PENDING_PARSER_REINIT
182 // Initializes |stream_parser_|. Also, updates |expected_audio_codecs| and
183 // |expected_video_codecs|.
184 void InitializeParser(const std::string& expected_codecs);
186 // Called by the |stream_parser_| when a new initialization segment is
188 // Returns true on a successful call. Returns false if an error occurred while
189 // processing decoder configurations.
190 bool OnNewConfigs(std::string expected_codecs,
191 std::unique_ptr<MediaTracks> tracks,
192 const StreamParser::TextTrackConfigMap& text_configs);
194 // Called by the |stream_parser_| at the beginning of a new media segment.
195 void OnNewMediaSegment();
197 // Called by the |stream_parser_| at the end of a media segment.
198 void OnEndOfMediaSegment();
200 // Called by the |stream_parser_| when new buffers have been parsed.
201 // It processes the new buffers using |frame_processor_|, which includes
202 // appending the processed frames to associated demuxer streams for each
204 // Returns true on a successful call. Returns false if an error occurred while
205 // processing the buffers.
206 bool OnNewBuffers(const StreamParser::BufferQueueMap& buffer_queue_map);
208 // Called when StreamParser encounters encrypted media init data.
209 void OnEncryptedMediaInitData(EmeInitDataType type,
210 const std::vector<uint8_t>& init_data);
212 void OnSourceInitDone(const StreamParser::InitParameters& params);
214 // Sets memory limits for all demuxer streams.
215 void SetStreamMemoryLimits();
217 // Tracks the number of MEDIA_LOGs emitted for segments missing expected audio
218 // or video blocks. Useful to prevent log spam.
219 int num_missing_track_logs_ = 0;
221 // During Append(), if OnNewBuffers() coded frame processing updates the
222 // timestamp offset then |*timestamp_offset_during_append_| is also updated
223 // so Append()'s caller can know the new offset. This pointer is only non-NULL
224 // during the lifetime of an Append() call.
225 raw_ptr<base::TimeDelta> timestamp_offset_during_append_;
227 // During Append(), coded frame processing triggered by OnNewBuffers()
228 // requires these two attributes. These are only valid during the lifetime of
230 base::TimeDelta append_window_start_during_append_;
231 base::TimeDelta append_window_end_during_append_;
233 // Keeps track of whether a media segment is being parsed.
234 bool parsing_media_segment_;
236 // Valid only while |parsing_media_segment_| is true. These flags enable
237 // warning when the parsed media segment doesn't have frames for some track.
238 std::map<StreamParser::TrackId, bool> media_segment_has_data_for_track_;
240 // The object used to parse appended data.
241 std::unique_ptr<StreamParser> stream_parser_;
243 // Note that ChunkDemuxerStreams are created and owned by the parent
244 // ChunkDemuxer. They are not owned by |this|.
245 using DemuxerStreamMap = std::map<StreamParser::TrackId, ChunkDemuxerStream*>;
246 DemuxerStreamMap audio_streams_;
247 DemuxerStreamMap video_streams_;
248 DemuxerStreamMap text_streams_;
250 std::unique_ptr<FrameProcessor> frame_processor_;
251 const CreateDemuxerStreamCB create_demuxer_stream_cb_;
252 raw_ptr<MediaLog> media_log_;
254 StreamParser::InitCB init_cb_;
255 StreamParser::EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
256 NewTextTrackCB new_text_track_cb_;
260 // During Append(), OnNewConfigs() will trigger the initialization segment
261 // received algorithm. Note, the MSE spec explicitly disallows this algorithm
262 // during an Abort(), since Abort() is allowed only to emit coded frames, and
263 // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). So we
264 // also have a flag here that indicates if Append is in progress and we can
265 // invoke this callback.
266 Demuxer::MediaTracksUpdatedCB init_segment_received_cb_;
267 bool append_in_progress_ = false;
268 bool first_init_segment_received_ = false;
269 bool encrypted_media_init_data_reported_ = false;
271 std::vector<AudioCodec> expected_audio_codecs_;
272 std::vector<VideoCodec> expected_video_codecs_;
277 #endif // MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_