1 // Copyright 2023 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_HLS_MANIFEST_DEMUXER_ENGINE_H_
6 #define MEDIA_FILTERS_HLS_MANIFEST_DEMUXER_ENGINE_H_
10 #include "base/memory/scoped_refptr.h"
11 #include "base/task/sequenced_task_runner.h"
12 #include "base/threading/sequence_bound.h"
13 #include "base/time/time.h"
14 #include "media/base/media_export.h"
15 #include "media/base/media_log.h"
16 #include "media/base/media_track.h"
17 #include "media/base/pipeline_status.h"
18 #include "media/filters/hls_codec_detector.h"
19 #include "media/filters/hls_data_source_provider.h"
20 #include "media/filters/hls_demuxer_status.h"
21 #include "media/filters/hls_rendition.h"
22 #include "media/filters/manifest_demuxer.h"
23 #include "media/formats/hls/media_playlist.h"
24 #include "media/formats/hls/parse_status.h"
25 #include "media/formats/hls/rendition_selector.h"
26 #include "third_party/abseil-cpp/absl/types/optional.h"
30 // A HLS-Parser/Player implementation of ManifestDemuxer's Engine interface.
31 // This will use the HLS parsers and rendition selectors to fetch and parse
32 // playlists, followed by fetching and appending media segments.
33 class MEDIA_EXPORT HlsManifestDemuxerEngine : public ManifestDemuxer::Engine,
34 public HlsRenditionHost {
36 HlsManifestDemuxerEngine(base::SequenceBound<HlsDataSourceProvider> dsp,
37 scoped_refptr<base::SequencedTaskRunner> task_runner,
38 GURL root_playlist_uri,
40 ~HlsManifestDemuxerEngine() override;
42 // HlsRenditionHost implementation
43 std::string GetName() const override;
44 void Initialize(ManifestDemuxerEngineHost* host,
45 PipelineStatusCallback status_cb) override;
46 void OnTimeUpdate(base::TimeDelta time,
48 ManifestDemuxer::DelayCallback cb) override;
49 void Seek(base::TimeDelta time, ManifestDemuxer::SeekCallback cb) override;
50 void StartWaitingForSeek() override;
51 void AbortPendingReads() override;
52 bool IsSeekable() const override;
53 int64_t GetMemoryUsage() const override;
55 void ReadFromUrl(GURL uri,
57 absl::optional<hls::types::ByteRange> range,
58 HlsDataSourceProvider::ReadCb cb) override;
59 void ReadStream(std::unique_ptr<HlsDataSourceStream> stream,
60 HlsDataSourceProvider::ReadCb cb) override;
62 // Parses a playlist using the multivariant playlist, if it's being used.
63 hls::ParseStatus::Or<scoped_refptr<hls::MediaPlaylist>>
64 ParseMediaPlaylistFromStringSource(
65 base::StringPiece source,
67 hls::types::DecimalInteger version) override;
70 void AddRenditionForTesting(std::unique_ptr<HlsRendition> test_rendition);
71 void InitializeWithMockCodecDetectorForTesting(
72 ManifestDemuxerEngineHost* host,
73 PipelineStatusCallback cb,
74 std::unique_ptr<HlsCodecDetector> codec_detector);
77 struct PlaylistParseInfo {
78 PlaylistParseInfo(GURL uri,
79 std::vector<std::string> codecs,
81 bool allow_multivariant_playlist = false);
82 PlaylistParseInfo(const PlaylistParseInfo& copy);
85 // The url that this media playlist came from. We might need to update it
86 // if its a live playlist, so it's vital to keep it around.
89 // Any detected codecs associated with this stream.
90 std::vector<std::string> codecs;
92 // The name given to this stream in chunk demuxer.
95 // Only root playlists are allowed to be multivariant.
96 bool allow_multivariant_playlist;
99 // Call the `CheckState` method of each rendition recursively and
100 // asynchronously while also maintaining the correct delay time.
101 // `media_time` and `playback_rate` represent the state of the playing media
102 // `cb` allows requesting a delay time until the next CheckState call,
103 // `rendition_index` is the index into `renditions_` that should be
104 // asynchronously checked next, and `response_time` is what the previously
105 // checked renditions requested for a delay time. The ultimate response to
106 // `cb` should be the lowest of all requested delays, adjusted for the time
107 // taken to calculate later delays, e.g.:
108 // Rendition1 requests 5 seconds, takes 2 seconds
109 // Rendition2 requests 4 seconds, takes 1.5 seconds
110 // Rendition3 requests kNoTimestamp, takes 1 second
111 // First the 5 second response is carried forward, then after the second
112 // response is acquired, the lesser of (5 - 1.5) and 4 is selected, so 3.5
113 // seconds is carried forward as a delay time. Finally after the kNoTimestamp
114 // response is acquired, the duration is once again subtracted and a final
115 // delay time of 2.5 seconds is returned via cb.
116 void CheckStateAtIndex(base::TimeDelta media_time,
117 double playback_rate,
118 ManifestDemuxer::DelayCallback cb,
119 size_t rendition_index,
120 absl::optional<base::TimeDelta> response_time);
122 // Helper for `CheckStateAtIndex` to be bound for Rendition::CheckState
125 base::TimeTicks call_start,
126 absl::optional<base::TimeDelta> prior_delay,
127 base::OnceCallback<void(absl::optional<base::TimeDelta>)> cb,
128 base::TimeDelta delay_time);
130 // Helpers to call |PlayerImplDemuxer::OnDemuxerError|.
131 void Abort(HlsDemuxerStatus status);
132 void Abort(hls::ParseStatus status);
133 void Abort(HlsDataSourceProvider::ReadStatus status);
135 // Read the entire contents of a data source stream before calling cb.
136 void ReadUntilExhausted(HlsDataSourceProvider::ReadCb cb,
137 HlsDataSourceProvider::ReadResult result);
139 void ParsePlaylist(PipelineStatusCallback parse_complete_cb,
140 PlaylistParseInfo parse_info,
141 HlsDataSourceProvider::ReadResult m_stream);
143 void OnMultivariantPlaylist(
144 PipelineStatusCallback parse_complete_cb,
145 scoped_refptr<hls::MultivariantPlaylist> playlist);
146 void SetStreams(std::vector<PlaylistParseInfo> playlists,
147 PipelineStatusCallback cb,
148 PipelineStatus exit_on_error);
150 void OnMediaPlaylist(PipelineStatusCallback parse_complete_cb,
151 PlaylistParseInfo parse_info,
152 scoped_refptr<hls::MediaPlaylist> playlist);
153 void DetermineStreamContainerAndCodecs(
154 hls::MediaPlaylist* playlist,
155 HlsDemuxerStatusCb<HlsCodecDetector::ContainerAndCodecs> container_cb);
156 void OnPlaylistContainerDetermined(
157 PipelineStatusCallback parse_complete_cb,
158 PlaylistParseInfo parse_info,
159 scoped_refptr<hls::MediaPlaylist> playlist,
160 HlsDemuxerStatus::Or<HlsCodecDetector::ContainerAndCodecs> maybe_info);
161 void PeekFirstSegment(
162 HlsDemuxerStatusCb<HlsCodecDetector::ContainerAndCodecs> cb,
163 HlsDataSourceProvider::ReadResult maybe_stream);
165 void OnChunkDemuxerParseWarning(std::string role,
166 SourceBufferParseWarning warning);
167 void OnChunkDemuxerTracksChanged(std::string role,
168 std::unique_ptr<MediaTracks> tracks);
169 void ContinueSeekInternal(base::TimeDelta time,
170 ManifestDemuxer::SeekCallback cb);
172 void InitializeWithCodecDetector(
173 ManifestDemuxerEngineHost* host,
174 PipelineStatusCallback status_cb,
175 std::unique_ptr<HlsCodecDetector> codec_detector);
177 base::SequenceBound<HlsDataSourceProvider> data_source_provider_;
178 scoped_refptr<base::SequencedTaskRunner> media_task_runner_;
180 // root playlist, either multivariant or media.
181 GURL root_playlist_uri_;
183 std::unique_ptr<MediaLog> media_log_;
184 raw_ptr<ManifestDemuxerEngineHost> host_
185 GUARDED_BY_CONTEXT(media_sequence_checker_) = nullptr;
187 // The codec detector is a reusable way for determining codecs in a media
189 std::unique_ptr<HlsCodecDetector> codec_detector_
190 GUARDED_BY_CONTEXT(media_sequence_checker_);
192 // If the root playlist is multivariant, we need to store it for parsing the
193 // dependant media playlists.
194 scoped_refptr<hls::MultivariantPlaylist> multivariant_root_
195 GUARDED_BY_CONTEXT(media_sequence_checker_);
196 std::unique_ptr<hls::RenditionSelector> rendition_selector_
197 GUARDED_BY_CONTEXT(media_sequence_checker_);
199 // Multiple renditions are allowed, and have to be synchronized.
200 std::vector<std::unique_ptr<HlsRendition>> renditions_
201 GUARDED_BY_CONTEXT(media_sequence_checker_);
203 // When renditions are added, this ensures that they are all of the same
204 // liveness, and allows access to the liveness check later.
205 absl::optional<bool> is_seekable_ = absl::nullopt;
207 // Preferences for selecting optimal renditions. Storing them allows them
208 // to be changed later due to network constraints or user changes.
209 hls::RenditionSelector::VideoPlaybackPreferences video_preferences_
210 GUARDED_BY_CONTEXT(media_sequence_checker_) = {absl::nullopt,
212 hls::RenditionSelector::AudioPlaybackPreferences audio_preferences_
213 GUARDED_BY_CONTEXT(media_sequence_checker_) = {absl::nullopt,
216 // Ensure that safe member fields are only accessed on the media sequence.
217 SEQUENCE_CHECKER(media_sequence_checker_);
219 base::WeakPtrFactory<HlsManifestDemuxerEngine> weak_factory_{this};
224 #endif // MEDIA_FILTERS_HLS_MANIFEST_DEMUXER_ENGINE_H_