| // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_ |
| #define MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_ |
| |
| #include <list> |
| |
| #include "base/bind.h" |
| #include "base/macros.h" |
| #include "base/memory/memory_pressure_listener.h" |
| #include "media/base/audio_codecs.h" |
| #include "media/base/demuxer.h" |
| #include "media/base/demuxer_stream.h" |
| #include "media/base/media_export.h" |
| #include "media/base/media_log.h" |
| #include "media/base/stream_parser.h" |
| #include "media/base/stream_parser_buffer.h" |
| #include "media/base/video_codecs.h" |
| #include "media/filters/source_buffer_parse_warnings.h" |
| |
| namespace media { |
| |
| |
| class ChunkDemuxerStream; |
| class FrameProcessor; |
| |
| // Contains state belonging to a source id. |
| class MEDIA_EXPORT SourceBufferState { |
| public: |
| // Callback signature used to create ChunkDemuxerStreams. |
| using CreateDemuxerStreamCB = |
| base::RepeatingCallback<ChunkDemuxerStream*(DemuxerStream::Type)>; |
| |
| using NewTextTrackCB = base::RepeatingCallback<void(ChunkDemuxerStream*, |
| const TextTrackConfig&)>; |
| |
| SourceBufferState(std::unique_ptr<StreamParser> stream_parser, |
| std::unique_ptr<FrameProcessor> frame_processor, |
| CreateDemuxerStreamCB create_demuxer_stream_cb, |
| MediaLog* media_log); |
| |
| SourceBufferState(const SourceBufferState&) = delete; |
| SourceBufferState& operator=(const SourceBufferState&) = delete; |
| |
| ~SourceBufferState(); |
| |
| void Init(StreamParser::InitCB init_cb, |
| const std::string& expected_codecs, |
| const StreamParser::EncryptedMediaInitDataCB& |
| encrypted_media_init_data_cb, |
| NewTextTrackCB new_text_track_cb); |
| |
| // Reconfigures this source buffer to use |new_stream_parser|. Caller must |
| // first ensure that ResetParserState() was done to flush any pending frames |
| // from the old stream parser. |
| void ChangeType(std::unique_ptr<StreamParser> new_stream_parser, |
| const std::string& new_expected_codecs); |
| |
| // Appends new data to the StreamParser. |
| // Returns true if the data was successfully appended. Returns false if an |
| // error occurred. |*timestamp_offset| is used and possibly updated by the |
| // append. |append_window_start| and |append_window_end| correspond to the MSE |
| // spec's similarly named source buffer attributes that are used in coded |
| // frame processing. |
| // AppendChunks appends the provided BufferQueue. |
| bool Append(const uint8_t* data, |
| size_t length, |
| base::TimeDelta append_window_start, |
| base::TimeDelta append_window_end, |
| base::TimeDelta* timestamp_offset); |
| bool AppendChunks(std::unique_ptr<StreamParser::BufferQueue> buffer_queue, |
| base::TimeDelta append_window_start, |
| base::TimeDelta append_window_end, |
| base::TimeDelta* timestamp_offset); |
| |
| // Aborts the current append sequence and resets the parser. |
| void ResetParserState(base::TimeDelta append_window_start, |
| base::TimeDelta append_window_end, |
| base::TimeDelta* timestamp_offset); |
| |
| // Calls Remove(|start|, |end|, |duration|) on all |
| // ChunkDemuxerStreams managed by this object. |
| void Remove(base::TimeDelta start, |
| base::TimeDelta end, |
| base::TimeDelta duration); |
| |
| // If the buffer is full, attempts to try to free up space, as specified in |
| // the "Coded Frame Eviction Algorithm" in the Media Source Extensions Spec. |
| // Returns false iff buffer is still full after running eviction. |
| // https://w3c.github.io/media-source/#sourcebuffer-coded-frame-eviction |
| bool EvictCodedFrames(base::TimeDelta media_time, size_t newDataSize); |
| |
| // Gets invoked when the system is experiencing memory pressure, i.e. there's |
| // not enough free memory. The |media_time| is the media playback position at |
| // the time of memory pressure notification (needed for accurate GC). The |
| // |memory_pressure_level| indicates memory pressure severity. The |
| // |force_instant_gc| is used to force the MSE garbage collection algorithm to |
| // be run right away, without waiting for the next append. |
| void OnMemoryPressure( |
| base::TimeDelta media_time, |
| base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level, |
| bool force_instant_gc); |
| |
| // Returns true if currently parsing a media segment, or false otherwise. |
| bool parsing_media_segment() const { return parsing_media_segment_; } |
| |
| // Returns the 'Generate Timestamps Flag' for this SourceBuffer's byte stream |
| // format parser as described in the MSE Byte Stream Format Registry. |
| bool generate_timestamps_flag() const { |
| return stream_parser_->GetGenerateTimestampsFlag(); |
| } |
| |
| // Sets |frame_processor_|'s sequence mode to |sequence_mode|. |
| void SetSequenceMode(bool sequence_mode); |
| |
| // Signals the coded frame processor to update its group start timestamp to be |
| // |timestamp_offset| if it is in sequence append mode. |
| void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset); |
| |
| // Returns the range of buffered data in this source, capped at |duration|. |
| // |ended| - Set to true if end of stream has been signaled and the special |
| // end of stream range logic needs to be executed. |
| Ranges<base::TimeDelta> GetBufferedRanges(base::TimeDelta duration, |
| bool ended) const; |
| |
| // Returns the highest PTS of currently buffered frames in this source, or |
| // base::TimeDelta() if none of the streams contain buffered data. |
| base::TimeDelta GetHighestPresentationTimestamp() const; |
| |
| // Returns the highest buffered duration across all streams managed |
| // by this object. |
| // Returns base::TimeDelta() if none of the streams contain buffered data. |
| base::TimeDelta GetMaxBufferedDuration() const; |
| |
| // Helper methods that call methods with similar names on all the |
| // ChunkDemuxerStreams managed by this object. |
| void StartReturningData(); |
| void AbortReads(); |
| void Seek(base::TimeDelta seek_time); |
| void CompletePendingReadIfPossible(); |
| void OnSetDuration(base::TimeDelta duration); |
| void MarkEndOfStream(); |
| void UnmarkEndOfStream(); |
| void Shutdown(); |
| // Sets the memory limit on each stream of a specific type. |
| // |memory_limit| is the maximum number of bytes each stream of type |type| |
| // is allowed to hold in its buffer. |
| void SetMemoryLimits(DemuxerStream::Type type, size_t memory_limit); |
| bool IsSeekWaitingForData() const; |
| |
| using RangesList = std::vector<Ranges<base::TimeDelta>>; |
| static Ranges<base::TimeDelta> ComputeRangesIntersection( |
| const RangesList& active_ranges, |
| bool ended); |
| |
| void SetTracksWatcher(Demuxer::MediaTracksUpdatedCB tracks_updated_cb); |
| |
| void SetParseWarningCallback(SourceBufferParseWarningCB parse_warning_cb); |
| |
| #if defined(STARBOARD) |
| void SetSourceBufferStreamMemoryLimit(size_t limit); |
| size_t GetSourceBufferStreamMemoryLimit(); |
| size_t stream_memory_limit_override_ = 0; |
| #endif // defined(STARBOARD) |
| private: |
| // State advances through this list to PARSER_INITIALIZED. |
| // The intent is to ensure at least one config is received prior to parser |
| // calling initialization callback, and that such initialization callback |
| // occurs at most once per parser. |
| // PENDING_PARSER_RECONFIG occurs if State had reached PARSER_INITIALIZED |
| // before changing to a new StreamParser in ChangeType(). In such case, State |
| // would then advance to PENDING_PARSER_REINIT, then PARSER_INITIALIZED upon |
| // the next initialization segment parsed, but would not run the |
| // initialization callback in this case (since such would already have |
| // occurred on the initial transition from PENDING_PARSER_INIT to |
| // PARSER_INITIALIZED.) |
| enum State { |
| UNINITIALIZED = 0, |
| PENDING_PARSER_CONFIG, |
| PENDING_PARSER_INIT, |
| PARSER_INITIALIZED, |
| PENDING_PARSER_RECONFIG, |
| PENDING_PARSER_REINIT |
| }; |
| |
| // Initializes |stream_parser_|. Also, updates |expected_audio_codecs| and |
| // |expected_video_codecs|. |
| void InitializeParser(const std::string& expected_codecs); |
| |
| // Called by the |stream_parser_| when a new initialization segment is |
| // encountered. |
| // Returns true on a successful call. Returns false if an error occurred while |
| // processing decoder configurations. |
| bool OnNewConfigs(std::string expected_codecs, |
| std::unique_ptr<MediaTracks> tracks, |
| const StreamParser::TextTrackConfigMap& text_configs); |
| |
| // Called by the |stream_parser_| at the beginning of a new media segment. |
| void OnNewMediaSegment(); |
| |
| // Called by the |stream_parser_| at the end of a media segment. |
| void OnEndOfMediaSegment(); |
| |
| // Called by the |stream_parser_| when new buffers have been parsed. |
| // It processes the new buffers using |frame_processor_|, which includes |
| // appending the processed frames to associated demuxer streams for each |
| // frame's track. |
| // Returns true on a successful call. Returns false if an error occurred while |
| // processing the buffers. |
| bool OnNewBuffers(const StreamParser::BufferQueueMap& buffer_queue_map); |
| |
| // Called when StreamParser encounters encrypted media init data. |
| void OnEncryptedMediaInitData(EmeInitDataType type, |
| const std::vector<uint8_t>& init_data); |
| |
| void OnSourceInitDone(const StreamParser::InitParameters& params); |
| |
| // Sets memory limits for all demuxer streams. |
| void SetStreamMemoryLimits(); |
| |
| // Tracks the number of MEDIA_LOGs emitted for segments missing expected audio |
| // or video blocks. Useful to prevent log spam. |
| int num_missing_track_logs_ = 0; |
| |
| // During Append(), if OnNewBuffers() coded frame processing updates the |
| // timestamp offset then |*timestamp_offset_during_append_| is also updated |
| // so Append()'s caller can know the new offset. This pointer is only non-NULL |
| // during the lifetime of an Append() call. |
| base::TimeDelta* timestamp_offset_during_append_; |
| |
| // During Append(), coded frame processing triggered by OnNewBuffers() |
| // requires these two attributes. These are only valid during the lifetime of |
| // an Append() call. |
| base::TimeDelta append_window_start_during_append_; |
| base::TimeDelta append_window_end_during_append_; |
| |
| // Keeps track of whether a media segment is being parsed. |
| bool parsing_media_segment_; |
| |
| // Valid only while |parsing_media_segment_| is true. These flags enable |
| // warning when the parsed media segment doesn't have frames for some track. |
| std::map<StreamParser::TrackId, bool> media_segment_has_data_for_track_; |
| |
| // The object used to parse appended data. |
| std::unique_ptr<StreamParser> stream_parser_; |
| |
| // Note that ChunkDemuxerStreams are created and owned by the parent |
| // ChunkDemuxer. They are not owned by |this|. |
| using DemuxerStreamMap = std::map<StreamParser::TrackId, ChunkDemuxerStream*>; |
| DemuxerStreamMap audio_streams_; |
| DemuxerStreamMap video_streams_; |
| DemuxerStreamMap text_streams_; |
| |
| std::unique_ptr<FrameProcessor> frame_processor_; |
| const CreateDemuxerStreamCB create_demuxer_stream_cb_; |
| MediaLog* media_log_; |
| |
| StreamParser::InitCB init_cb_; |
| StreamParser::EncryptedMediaInitDataCB encrypted_media_init_data_cb_; |
| NewTextTrackCB new_text_track_cb_; |
| |
| State state_; |
| |
| // During Append(), OnNewConfigs() will trigger the initialization segment |
| // received algorithm. Note, the MSE spec explicitly disallows this algorithm |
| // during an Abort(), since Abort() is allowed only to emit coded frames, and |
| // only if the parser is PARSING_MEDIA_SEGMENT (not an INIT segment). So we |
| // also have a flag here that indicates if Append is in progress and we can |
| // invoke this callback. |
| Demuxer::MediaTracksUpdatedCB init_segment_received_cb_; |
| bool append_in_progress_ = false; |
| bool first_init_segment_received_ = false; |
| bool encrypted_media_init_data_reported_ = false; |
| |
| std::vector<AudioCodec> expected_audio_codecs_; |
| std::vector<VideoCodec> expected_video_codecs_; |
| }; |
| |
| } // namespace media |
| |
| #endif // MEDIA_FILTERS_SOURCE_BUFFER_STATE_H_ |