[go: nahoru, domu]

blob: aa00bafd321f2779e62bf9b861a983d28f06d8af [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_FORMATS_HLS_MEDIA_PLAYLIST_H_
#define MEDIA_FORMATS_HLS_MEDIA_PLAYLIST_H_
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "base/types/pass_key.h"
#include "media/base/media_export.h"
#include "media/formats/hls/parse_status.h"
#include "media/formats/hls/playlist.h"
#include "media/formats/hls/tags.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace media::hls {
class MediaSegment;
class MultivariantPlaylist;
class MEDIA_EXPORT MediaPlaylist final : public Playlist {
public:
// Several values in HLS are based on the playlist's target duration, to avoid
// overflow issues we limit this to a large value.
static constexpr base::TimeDelta kMaxTargetDuration =
base::TimeDelta::FiniteMax() / 10;
// This structure describes information about partial segments in the
// playlist.
struct PartialSegmentInfo {
// The maximum duration of any partial segment. Each partial
// segment must be at least 85% of this, except for any where
// `HasDiscontinuity() == true` or the final partial segment of a parent
// segment.
base::TimeDelta target_duration;
};
struct CtorArgs;
explicit MediaPlaylist(base::PassKey<MediaPlaylist>, CtorArgs);
MediaPlaylist(const MediaPlaylist&) = delete;
MediaPlaylist(MediaPlaylist&&) = delete;
MediaPlaylist& operator=(const MediaPlaylist&) = delete;
MediaPlaylist& operator=(MediaPlaylist&&) = delete;
// `Playlist` implementation
Kind GetKind() const override;
// Returns all segments in this playlist, in chronological order. This vector
// may be copied independently of this Playlist.
const std::vector<scoped_refptr<MediaSegment>>& GetSegments() const {
return segments_;
}
// Returns the target duration (maximum length of any segment, rounded to the
// nearest integer) for this playlist.
base::TimeDelta GetTargetDuration() const { return target_duration_; }
// Returns the sum of the duration of all segments in this playlist.
// Computed via the 'EXTINF' attribute, so may be slightly longer than the
// actual duration.
base::TimeDelta GetComputedDuration() const { return computed_duration_; }
// Returns the type of this playlist (as specified by the
// 'EXT-X-PLAYLIST-TYPE' tag). If this is present, then the server must follow
// the constraints detailed on `PlaylistType` when the playlist is reloaded.
// If this property is absent, that implies that the server may append new
// segments to the end or remove old segments from the beginning of this
// playlist upon reloading.
absl::optional<PlaylistType> GetPlaylistType() const {
return playlist_type_;
}
// Returns information about partial segments in this playlist. This will be
// non-empty if this playlist contains at least one partial segment, and may
// be empty if this playlist contains no partial segments.
absl::optional<PartialSegmentInfo> GetPartialSegmentInfo() const {
return partial_segment_info_;
}
// Returns whether this playlist contained the 'EXT-X-ENDLIST' tag. This
// indicates, in the cause of EVENT or live playlists, that no further
// segments will be appended in future updates.
bool IsEndList() const { return end_list_; }
// Indicates that this playlist contained the 'EXT-X-I-FRAMES-ONLY tag.
// This means that each media segment in this playlist contains a single
// I-frame, and that the media segment duration should be interpreted as the
// time between that I-frame and the following one, or the end of the
// presentation.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.6
bool IsIFramesOnly() const { return i_frames_only_; }
// The presence of the EXT-X-MEDIA-SEQUENCE tag is a hint that, in the case of
// live playlists, media segments may become unavailable after the time this
// playlist was loaded + the duration of this playlist.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#:~:text=nominal%20playback%20rate).-,If,-the%20Media%20Playlist
bool HasMediaSequenceTag() const { return has_media_sequence_tag_; }
// If present, this represents that the server can produce playlist delta
// updates. The value represents the distance from the end of the
// playlist beyond which media segments and their associated tags can be
// skipped.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.1
absl::optional<base::TimeDelta> GetSkipBoundary() const {
return skip_boundary_;
}
// Returns whether the server can produce playlist delta updates that skip
// EXT-X-DATERANGE tags.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.1
bool CanSkipDateRanges() const { return can_skip_dateranges_; }
// Returns the server-recommended minimum distance from the end
// of the playlist at which clients should begin live playback.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.8:~:text=SKIP%2DUNTIL%20attribute.-,HOLD%2DBACK,-The%20value%20is
base::TimeDelta GetHoldBackDistance() const { return hold_back_distance_; }
// Returns the server-recommended minimum distance from the end
// of the playlist at which clients should begin live playback when playing in
// low-latency mode.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.3.8:~:text=any%20Media%20Playlist.-,PART%2DHOLD%2DBACK,-The%20value%20is
absl::optional<base::TimeDelta> GetPartHoldBackDistance() const {
return part_hold_back_distance_;
}
// Returns whether the server supports blocking playlist reloads.
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-6.2.5.2
bool CanBlockReload() const { return can_block_reload_; }
// Attempts to parse the media playlist represented by `source`. `uri` must be
// a valid, non-empty GURL referring to the URI of this playlist.
// `version` is the HLS version expected to be given by a
// `EXT-X-VERSION` tag in this playlist (or `Playlist::kDefaultVersion` if
// none), which may be determined via `Playlist::IdentifyPlaylist`, or from a
// previous version of this playlist. If this playlist was found through a
// multivariant playlist, `parent_playlist` must point to that playlist in
// order to support persistent properties and imported variables. Otherwise,
// it should be `nullptr`. If `source` is invalid, this returns an error.
// Otherwise, the parsed playlist is returned.
static ParseStatus::Or<scoped_refptr<MediaPlaylist>> Parse(
base::StringPiece source,
GURL uri,
types::DecimalInteger version,
const MultivariantPlaylist* parent_playlist);
private:
~MediaPlaylist() override;
base::TimeDelta target_duration_;
absl::optional<PartialSegmentInfo> partial_segment_info_;
std::vector<scoped_refptr<MediaSegment>> segments_;
base::TimeDelta computed_duration_;
absl::optional<PlaylistType> playlist_type_;
bool end_list_;
bool i_frames_only_;
bool has_media_sequence_tag_;
bool can_skip_dateranges_;
bool can_block_reload_;
absl::optional<base::TimeDelta> skip_boundary_;
base::TimeDelta hold_back_distance_;
absl::optional<base::TimeDelta> part_hold_back_distance_;
};
} // namespace media::hls
#endif // MEDIA_FORMATS_HLS_MEDIA_PLAYLIST_H_