Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / hls_live_rendition.cc
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.
4
5 #include "media/filters/hls_live_rendition.h"
6
7 #include "base/task/bind_post_task.h"
8 #include "media/filters/hls_manifest_demuxer_engine.h"
9
10 namespace media {
11
12 HlsLiveRendition::~HlsLiveRendition() {
13   engine_host_->RemoveRole(role_);
14 }
15
16 HlsLiveRendition::HlsLiveRendition(ManifestDemuxerEngineHost* engine_host,
17                                    HlsRenditionHost* rendition_host,
18                                    std::string role,
19                                    scoped_refptr<hls::MediaPlaylist> playlist,
20                                    GURL media_playlist_uri)
21     : engine_host_(engine_host),
22       rendition_host_(rendition_host),
23       role_(std::move(role)),
24       media_playlist_uri_(std::move(media_playlist_uri)),
25       segment_duration_upper_limit_(playlist->GetTargetDuration()) {
26   AppendSegments(playlist.get());
27 }
28
29 absl::optional<base::TimeDelta> HlsLiveRendition::GetDuration() {
30   return absl::nullopt;
31 }
32
33 void HlsLiveRendition::CheckState(
34     base::TimeDelta media_time,
35     double playback_rate,
36     ManifestDemuxer::DelayCallback time_remaining_cb) {
37   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
38   if (is_stopped_for_shutdown_) {
39     std::move(time_remaining_cb).Run(kNoTimestamp);
40     return;
41   }
42
43   if (playback_rate != 1 && playback_rate != 0) {
44     // TODO(crbug.com/1266991): What should be done about non-paused,
45     // non-real-time playback? Anything above 1 would hit the end and constantly
46     // be in a state of demuxer underflow, and anything slower than 1 would
47     // eventually have so much data buffered that it would OOM.
48     engine_host_->OnError(DEMUXER_ERROR_COULD_NOT_PARSE);
49     return;
50   }
51
52   if (playback_rate != 0.0) {
53     has_ever_played_ = true;
54   }
55
56   if (playback_rate == 0.0 && has_ever_played_) {
57     require_seek_after_unpause_ = true;
58     ResetForPause();
59     std::move(time_remaining_cb).Run(kNoTimestamp);
60     return;
61   }
62
63   auto loaded_ranges = engine_host_->GetBufferedRanges(role_);
64   if (require_seek_after_unpause_) {
65     if (loaded_ranges.empty() && segments_.empty()) {
66       // There should be no loaded ranges or segments after resuming from a
67       // pause, so fetch some.
68       FetchManifestUpdates(base::Seconds(0), std::move(time_remaining_cb));
69       return;
70     }
71
72     if (loaded_ranges.empty()) {
73       // Now there are segments, but there is still no new content. Fetch and
74       // parse new content, before seeking.
75       ContinuePartialFetching(
76           base::BindOnce(std::move(time_remaining_cb), base::Seconds(0)));
77       return;
78     }
79
80     require_seek_after_unpause_ = false;
81     engine_host_->RequestSeek(std::get<0>(loaded_ranges.back()));
82
83     // When the pipeline seeks, it should re-enter this state checking loop.
84     std::move(time_remaining_cb).Run(kNoTimestamp);
85     return;
86   }
87
88   if (loaded_ranges.size() > 1) {
89     std::move(time_remaining_cb).Run(kNoTimestamp);
90     engine_host_->OnError(DEMUXER_ERROR_COULD_NOT_OPEN);
91     return;
92   }
93
94   if (loaded_ranges.empty()) {
95     if (segments_.empty()) {
96       // This is likely to happen right after the player has started playing,
97       // which means we need a full update on the manifest.
98       // TODO(crbug/1266991): Use the manifest frequency polling logic here too.
99       MaybeFetchManifestUpdates(base::Seconds(0), std::move(time_remaining_cb));
100       return;
101     }
102
103     ContinuePartialFetching(
104         base::BindOnce(std::move(time_remaining_cb), base::Seconds(0)));
105     return;
106   }
107
108   auto actual_buffer_time = std::get<1>(loaded_ranges.back()) - media_time;
109   auto ideal_buffer_time = GetForwardBufferSize();
110   if (actual_buffer_time > ideal_buffer_time) {
111     // clear content older than the current media time.
112     ClearOldData(media_time);
113
114     // Finally, in this downtime, try to fetch manifest data. This has to be
115     // done periodically to get new segments, and since there is a good buffer
116     // currently, its a good time to do that fetch. Manifest updates are usually
117     // small, and shouldn't cause the buffer to run out.
118     auto delay_time = ideal_buffer_time / 1.5;
119     MaybeFetchManifestUpdates(delay_time, std::move(time_remaining_cb));
120     return;
121   }
122
123   if (!partial_stream_ && segments_.empty()) {
124     // TODO(crbug/1266991) We've run out of segments, and will demuxer
125     // underflow shortly. This implies that the rendition should be
126     // reselected.
127     MaybeFetchManifestUpdates(base::Seconds(0), std::move(time_remaining_cb));
128     return;
129   }
130
131   ContinuePartialFetching(
132       base::BindOnce(std::move(time_remaining_cb), base::Seconds(0)));
133 }
134
135 void HlsLiveRendition::ContinuePartialFetching(base::OnceClosure cb) {
136   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
137   CHECK(!is_stopped_for_shutdown_);
138   if (partial_stream_) {
139     FetchMoreDataFromPendingStream(std::move(cb));
140     return;
141   }
142   if (!segments_.empty()) {
143     LoadSegment(*segments_.front(), std::move(cb));
144     segments_.pop();
145   }
146 }
147
148 ManifestDemuxer::SeekResponse HlsLiveRendition::Seek(base::TimeDelta time) {
149   return ManifestDemuxer::SeekState::kIsReady;
150 }
151
152 void HlsLiveRendition::StartWaitingForSeek() {
153   // Do nothing, seeking a live stream is not valid.
154 }
155
156 void HlsLiveRendition::Stop() {
157   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
158   partial_stream_ = nullptr;
159   is_stopped_for_shutdown_ = true;
160 }
161
162 base::TimeDelta HlsLiveRendition::GetForwardBufferSize() const {
163   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
164   CHECK(!is_stopped_for_shutdown_);
165   // Try to keep a buffer of at least 5x fetch time, or 3 seconds, whichever
166   // is longer. These numbers were picked based on trial and error to get a
167   // smooth stream.
168   if (fetch_time_.Count() == 0) {
169     return base::Seconds(10);
170   }
171   return std::max(base::Seconds(10), fetch_time_.Mean() * 5);
172 }
173
174 void HlsLiveRendition::LoadSegment(const hls::MediaSegment& segment,
175                                    base::OnceClosure cb) {
176   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
177   CHECK(!is_stopped_for_shutdown_);
178   rendition_host_->ReadFromUrl(
179       segment.GetUri(), /*read_chunked=*/true, segment.GetByteRange(),
180       base::BindOnce(&HlsLiveRendition::OnSegmentData,
181                      weak_factory_.GetWeakPtr(), std::move(cb),
182                      base::TimeTicks::Now()));
183 }
184
185 void HlsLiveRendition::FetchMoreDataFromPendingStream(base::OnceClosure cb) {
186   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
187   CHECK(!is_stopped_for_shutdown_);
188   CHECK(partial_stream_);
189   auto stream = std::move(partial_stream_);
190   rendition_host_->ReadStream(
191       std::move(stream), base::BindOnce(&HlsLiveRendition::OnSegmentData,
192                                         weak_factory_.GetWeakPtr(),
193                                         std::move(cb), base::TimeTicks::Now()));
194 }
195
196 void HlsLiveRendition::OnSegmentData(base::OnceClosure cb,
197                                      base::TimeTicks net_req_start,
198                                      HlsDataSourceProvider::ReadResult result) {
199   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
200
201   if (is_stopped_for_shutdown_) {
202     std::move(cb).Run();
203     return;
204   }
205
206   if (!result.has_value()) {
207     engine_host_->OnError(
208         {DEMUXER_ERROR_COULD_NOT_PARSE, std::move(result).error()});
209     return;
210   }
211
212   // Always ensure we are parsing the entirety of the data chunk received.
213   auto sequences_seen = last_sequence_number_ - first_sequence_number_;
214   auto parse_end = segment_duration_upper_limit_ * (sequences_seen + 1);
215   auto stream = std::move(result).value();
216
217   if (!engine_host_->AppendAndParseData(role_, base::TimeDelta(), parse_end,
218                                         &parse_offset_, stream->raw_data(),
219                                         stream->buffer_size())) {
220     engine_host_->OnError(DEMUXER_ERROR_COULD_NOT_PARSE);
221     return;
222   }
223
224   auto fetch_duration = base::TimeTicks::Now() - net_req_start;
225   // Adjust time based on a standard 4k download chunk.
226   auto scaled = (fetch_duration * stream->buffer_size()) / 4096;
227   fetch_time_.AddSample(scaled);
228
229   if (stream->CanReadMore()) {
230     stream->Clear();
231     partial_stream_ = std::move(stream);
232   }
233
234   std::move(cb).Run();
235 }
236
237 void HlsLiveRendition::AppendSegments(hls::MediaPlaylist* playlist) {
238   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
239   CHECK(!is_stopped_for_shutdown_);
240   last_download_time_ = base::TimeTicks::Now();
241   for (const auto& segment : playlist->GetSegments()) {
242     if (first_sequence_number_ == 0) {
243       first_sequence_number_ = segment->GetMediaSequenceNumber();
244     }
245     if (segment->GetMediaSequenceNumber() <= last_sequence_number_) {
246       continue;
247     }
248     last_sequence_number_ = segment->GetMediaSequenceNumber();
249     segments_.push(segment);
250   }
251 }
252
253 void HlsLiveRendition::MaybeFetchManifestUpdates(
254     base::TimeDelta delay,
255     ManifestDemuxer::DelayCallback cb) {
256   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
257   CHECK(!is_stopped_for_shutdown_);
258   // Section 6.3.4 of the spec states that:
259   // the client MUST wait for at least the target duration before attempting
260   // to reload the Playlist file again, measured from the last time the client
261   // began loading the Playlist file.
262   auto since_last_manifest = base::TimeTicks::Now() - last_download_time_;
263   auto update_after = segment_duration_upper_limit_ * (segments_.size() + 1);
264   if (since_last_manifest > update_after) {
265     FetchManifestUpdates(delay, std::move(cb));
266     return;
267   }
268   std::move(cb).Run(delay);
269 }
270
271 void HlsLiveRendition::FetchManifestUpdates(base::TimeDelta delay,
272                                             ManifestDemuxer::DelayCallback cb) {
273   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
274   CHECK(!is_stopped_for_shutdown_);
275   rendition_host_->ReadFromUrl(
276       media_playlist_uri_, /*read_chunked=*/false, absl::nullopt,
277       base::BindOnce(&HlsLiveRendition::OnManifestUpdates,
278                      weak_factory_.GetWeakPtr(), base::TimeTicks::Now(), delay,
279                      std::move(cb)));
280 }
281
282 void HlsLiveRendition::OnManifestUpdates(
283     base::TimeTicks download_start_time,
284     base::TimeDelta delay_time,
285     ManifestDemuxer::DelayCallback cb,
286     HlsDataSourceProvider::ReadResult result) {
287   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
288
289   if (is_stopped_for_shutdown_) {
290     std::move(cb).Run(base::Seconds(0));
291     return;
292   }
293
294   if (!result.has_value()) {
295     engine_host_->OnError(
296         {DEMUXER_ERROR_COULD_NOT_PARSE, std::move(result).error()});
297     return;
298   }
299
300   auto stream = std::move(result).value();
301   if (stream->CanReadMore()) {
302     // TODO(crbug/1266991): Log a large manifest warning.
303     rendition_host_->ReadStream(
304         std::move(stream),
305         base::BindOnce(&HlsLiveRendition::OnManifestUpdates,
306                        weak_factory_.GetWeakPtr(), download_start_time,
307                        delay_time, std::move(cb)));
308     return;
309   }
310   auto info = hls::Playlist::IdentifyPlaylist(stream->AsString());
311   if (!info.has_value()) {
312     engine_host_->OnError(
313         {DEMUXER_ERROR_COULD_NOT_PARSE, std::move(info).error()});
314     return;
315   }
316
317   auto playlist = rendition_host_->ParseMediaPlaylistFromStringSource(
318       stream->AsString(), media_playlist_uri_, (*info).version);
319   if (!playlist.has_value()) {
320     engine_host_->OnError(
321         {DEMUXER_ERROR_COULD_NOT_PARSE, std::move(playlist).error()});
322     return;
323   }
324
325   auto playlist_ptr = std::move(playlist).value();
326   AppendSegments(playlist_ptr.get());
327
328   base::TimeDelta fetch_time = base::TimeTicks::Now() - download_start_time;
329   std::move(cb).Run(std::max(base::Seconds(0), delay_time - fetch_time));
330 }
331
332 void HlsLiveRendition::ClearOldData(base::TimeDelta time) {
333   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
334   CHECK(!is_stopped_for_shutdown_);
335   // 5 seconds chosen mostly arbitrarily to keep some prior buffer while not
336   // keeping too much to cause memory issues.
337   if (time <= base::Seconds(5)) {
338     return;
339   }
340   engine_host_->Remove(role_, base::TimeDelta(), time - base::Seconds(5));
341 }
342
343 void HlsLiveRendition::ResetForPause() {
344   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
345   CHECK(!is_stopped_for_shutdown_);
346   segments_ = {};
347   last_sequence_number_ = first_sequence_number_;
348   partial_stream_ = nullptr;
349   auto loaded_ranges = engine_host_->GetBufferedRanges(role_);
350   if (!loaded_ranges.empty()) {
351     auto end_time = std::get<1>(loaded_ranges.back());
352     engine_host_->Remove(role_, base::TimeDelta(), end_time);
353   }
354 }
355
356 }  // namespace media