hls_playlist/playlist.rs
1//! High level representations of extended M3U playlists.
2
3// Copyright 2024 Logan Wemyss
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17mod serialize;
18
19/// A playlist representing a list of renditions and variants of a given piece of media.
20#[derive(Debug, Clone, PartialEq, Default)]
21pub struct MultivariantPlaylist {
22 /// True if all media samples in a Media Segment can be decoded without information
23 /// from other segments.
24 pub is_independent_segments: bool,
25
26 /// A preferred point at which to start playing a Playlist.
27 pub start_offset: Option<StartOffset>,
28
29 /// A list of name value pairs where the name can be substituted for the
30 /// value (e.g. `{$<name>}`) in URI lines, quoted string attribute list
31 /// values, and hexadecimal-sequence attribute values.
32 pub variables: Vec<crate::DefinitionType>,
33
34 /// Groups of renditions that are all alternative renditions of the same content.
35 pub renditions_groups: Vec<RenditionGroup>,
36
37 /// A set of [`VariantStream`]s.
38 pub variant_streams: Vec<VariantStream>,
39
40 /// The `MediaPlaylist` files containing the I-frames of a multimedia
41 /// presentation.
42 pub i_frame_streams: Vec<IFrameStream>,
43
44 /// Arbitrary session data.
45 pub session_data: Vec<crate::SessionData>,
46
47 /// Encryption keys used in the `MediaPlaylist`s that should be preloaded.
48 pub session_key: Vec<crate::EncryptionMethod>,
49
50 /// Identifies a [`crate::steering_manifest::SteeringManifest`].
51 pub content_steering: Vec<crate::ContentSteering>,
52}
53
54/// Groups of renditions that are all alternative renditions of the same content.
55#[derive(Debug, Clone, PartialEq, Eq)]
56pub enum RenditionGroup {
57 /// A group of video renditions.
58 Video {
59 /// The group id for this group.
60 group_id: String,
61
62 /// All the renditions a part of this group.
63 renditions: Vec<VideoRendition>,
64 },
65
66 /// A group of audio renditions.
67 Audio {
68 /// The group id for this group.
69 group_id: String,
70
71 /// All the renditions a part of this group.
72 renditions: Vec<AudioRendition>,
73 },
74
75 /// A group of subtitle renditions.
76 Subtitles {
77 /// The group id for this group.
78 group_id: String,
79
80 /// All the renditions a part of this group.
81 renditions: Vec<SubtitleRendition>,
82 },
83
84 /// A group of closed caption renditions.
85 ClosedCaptions {
86 /// The group id for this group.
87 group_id: String,
88
89 /// All the renditions a part of this group.
90 renditions: Vec<ClosedCaptionRendition>,
91 },
92}
93
94/// A video rendition.
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct VideoRendition {
97 /// Information about this rendition.
98 pub info: RenditionInfo,
99
100 /// The URI that identifies the Media Playlist file.
101 pub uri: Option<String>,
102}
103
104/// A audio rendition.
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct AudioRendition {
107 /// The audio bit depth of the rendition.
108 pub bit_depth: Option<u64>,
109
110 /// The audio sample rate of the rendition.
111 pub sample_rate: Option<u64>,
112
113 /// Information about the audio channels in the rendition.
114 pub channels: Option<crate::AudioChannelInformation>,
115
116 /// Information about this rendition.
117 pub info: RenditionInfo,
118
119 /// The URI that identifies the Media Playlist file.
120 pub uri: Option<String>,
121}
122
123/// A subtitle rendition.
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub struct SubtitleRendition {
126 /// Information about this rendition.
127 pub info: RenditionInfo,
128
129 /// Indicates that the Rendition contains content that is
130 /// considered essential to play.
131 pub forced: bool,
132
133 /// The URI that identifies the Media Playlist file.
134 pub uri: String,
135}
136
137/// A closed caption rendition.
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct ClosedCaptionRendition {
140 pub in_stream_id: crate::InStreamId,
141
142 /// Information about this rendition.
143 pub info: RenditionInfo,
144}
145
146/// Information about a given rendition.
147#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct RenditionInfo {
149 /// A RFC5646 tag which identifies the primary language used in the Rendition.
150 pub language: Option<String>,
151
152 /// A RFC5646 tag which identifies a language that is associated with the Rendition.
153 pub assoc_language: Option<String>,
154
155 /// A human-readable description of the Rendition.
156 pub name: String,
157
158 /// The priority in which a given rendition should be chosen over another rendition.
159 pub priority: crate::RenditionPlaybackPriority,
160
161 /// Media Characteristic Tags that indicate individual characteristics of this Rendition.
162 pub characteristics: Vec<String>,
163
164 /// Allows the URI of a Rendition to change between two distinct downloads of
165 /// the `MultivariantPlaylist`.
166 pub stable_rendition_id: Option<String>,
167}
168
169/// A set of Renditions that can be combined to play the presentation.
170#[derive(Debug, Clone, PartialEq)]
171pub struct VariantStream {
172 /// Metadata for the stream.
173 pub stream_info: crate::StreamInf,
174
175 /// Describes the maximum frame rate for all the video in the
176 /// `VariantStream`.
177 pub frame_rate: Option<f64>,
178
179 /// The group id of the audio [`RenditionGroup`] that should be used when
180 /// playing the presentation.
181 pub audio_group_id: Option<String>,
182
183 /// The group id of the video [`RenditionGroup`] that should be used when
184 /// playing the presentation.
185 pub video_group_id: Option<String>,
186
187 /// The group id of the subtitle [`RenditionGroup`] that should be used when
188 /// playing the presentation.
189 pub subtitles_group_id: Option<String>,
190
191 /// The group id of the closed caption [`RenditionGroup`] that should be used when
192 /// playing the presentation.
193 pub closed_captions_group_id: Option<String>,
194
195 /// The `MediaPlaylist` that carries a Rendition of the Variant Stream.
196 pub uri: String,
197}
198
199/// Identifies a `MediaPlaylist` containing the I-frames of a multimedia
200/// presentation.
201#[derive(Debug, Clone, PartialEq)]
202pub struct IFrameStream {
203 /// The metadata for this stream.
204 pub stream_info: crate::StreamInf,
205
206 /// The group id of the video [`RenditionGroup`] that should be used when
207 /// playing the presentation.
208 pub video_group_id: Option<String>,
209
210 /// The URI that identifies the I-frame `MediaPlaylist` file.
211 pub uri: String,
212}
213
214/// A playlist representing a list of `MediaSegment`s and relevant information.
215#[allow(clippy::struct_excessive_bools)]
216#[derive(Debug, Clone, PartialEq, Default)]
217pub struct MediaPlaylist {
218 /// The `MediaSegments` representing segments of the media stream in order.
219 pub segments: Vec<MediaSegment>,
220
221 /// A preferred point at which to start playing a Playlist.
222 pub start_offset: Option<StartOffset>,
223
224 /// A list of name value pairs where the name can be substituted for the
225 /// value (e.g. `{$<name>}`) in URI lines, quoted string attribute list
226 /// values, and hexadecimal-sequence attribute values.
227 pub variables: Vec<crate::DefinitionType>,
228
229 /// True if all media samples in a Media Segment can be decoded without information
230 /// from other segments.
231 pub is_independent_segments: bool,
232
233 /// An upper bound on the duration of all Media
234 /// Segments in the Playlist. The duration of each Media Segment
235 /// in a Playlist file, when rounded to the nearest integer, MUST be
236 /// less than or equal to the Target Duration.
237 pub target_duration: u64,
238
239 /// The media sequence number of the first segment in [`MediaPlaylist::segments`].
240 pub first_media_sequence_number: u64,
241
242 /// Allows synchronization between different renditions of the same `VariantStream`
243 /// or different `VariantStream`s that have EXT-X-DISCONTINUITY tags in their
244 /// Media Playlists.
245 pub discontinuity_sequence_number: u64,
246
247 /// True if no more Media Segments will be added to the Media Playlist file.
248 pub finished: bool,
249
250 /// Whether or not the playlist is for a mutable append-only stream, or a
251 /// static immutable stream.
252 pub playlist_type: Option<crate::PlaylistType>,
253
254 /// If Some, indicates the server-recommended minimum distance from
255 /// the end of the Playlist at which clients should begin to play
256 /// or to which they should seek.
257 /// If None, this is set to `target_duration * 3`.
258 pub hold_back_seconds: Option<f64>,
259
260 /// True if each Media Segment in the Playlist describes a single I-frame.
261 pub iframes_only: bool,
262
263 /// `Some` if the server supports playlist delta updates.,
264 pub playlist_delta_updates_information: Option<crate::DeltaUpdateInfo>,
265
266 /// True if the server supports blocking playlist reloads.
267 pub supports_blocking_playlist_reloads: bool,
268
269 /// Information about the `PartialSegments` in this playlist.
270 pub part_information: Option<PartInformation>,
271
272 /// Information about the playlist that is not associated with
273 /// specific Media Segments.
274 pub metadata: MediaMetadata,
275}
276
277/// Information about `PartialSegments` in a given playlist.
278#[derive(Debug, Clone, PartialEq)]
279pub struct PartInformation {
280 /// Indicates the server-recommended minimum distance from
281 /// the end of the Playlist at which clients should begin to play
282 /// or to which they should seek when playing in Low-Latency Mode.
283 pub part_hold_back_seconds: f64,
284
285 /// An upper bound on the duration of all Partial Segments in the Playlist.
286 /// The duration of each Media Segment in a Playlist file, when rounded
287 /// to the nearest integer, MUST be less than or equal to the Target Duration.
288 pub part_target_duration: f64,
289}
290
291/// Information about the playlist that is not associated with
292/// specific Media Segments.
293#[derive(Debug, Clone, PartialEq, Default)]
294pub struct MediaMetadata {
295 /// A duration of time with specific attributes.
296 pub date_ranges: Vec<crate::DateRange>,
297
298 /// If Some, this indicates information about skipped `MediaSegments`.
299 /// If None, there are no skipped `MediaSegments`.
300 pub skip: Option<SkipInformation>,
301
302 /// Hints that the client should request a resource before
303 /// it is available to be delivered.
304 pub preload_hints: Vec<crate::PreloadHint>,
305
306 /// Information about an associated Renditions that is as up-to-date as
307 /// the Playlist that contains the report.
308 pub rendition_reports: Vec<crate::RenditionReport>,
309}
310
311/// Information about skipped `MediaSegments`.
312#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct SkipInformation {
314 /// The number of `MediaSegments` that have been skipped.
315 pub number_of_skipped_segments: u64,
316
317 /// The list of [`crate::DateRange`] IDs that have been removed
318 /// from the Playlist recently.
319 pub recently_removed_dataranges: Vec<String>,
320}
321
322/// A segment of the larger media file.
323#[derive(Debug, Clone, PartialEq)]
324pub struct MediaSegment {
325 /// The URI Identifying the media resource.
326 pub uri: String,
327
328 /// The duration of this `MediaSegment`.
329 pub duration_seconds: crate::FloatOrInteger,
330
331 /// An optional human-readable informative title of the Media Segment.
332 /// Empty string for no title.
333 pub title: String,
334
335 /// This may contain either a byte range or bitrate, but not both, because they are
336 /// mutually exclusive
337 pub byte_range_or_bitrate: Option<ByteRangeOrBitrate>,
338
339 /// True if `MediaSegment` is a discontinuity between the Media Segment
340 /// that follows it and the one that preceded it.
341 pub is_discontinuity: bool,
342
343 /// If Some, represents the encryption method used for this `MediaSegment`.
344 /// If None, no encryption is used.
345 pub encryption: Option<crate::EncryptionMethod>,
346
347 /// If Some, this `MediaSegment` requires a Media Initialization Section
348 /// and the value describes how to acquire it.
349 pub media_initialization_section: Option<MediaInitializationSection>,
350
351 /// If Some, the first sample of the `MediaSegment` is associated with this
352 /// time.
353 pub absolute_time: Option<chrono::DateTime<chrono::FixedOffset>>,
354
355 /// If true, this `MediaSegment` does not contain media data
356 /// and should not be loaded by clients.
357 pub is_gap: bool,
358
359 /// The partial segments for this `MediaSegment`.
360 pub parts: Vec<PartialSegment>,
361}
362
363/// A common sequence of bytes to initialize the parser before
364/// `MediaSegments` can be parsed.
365#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct MediaInitializationSection {
367 pub uri: String,
368 pub range: Option<crate::ByteRangeWithOffset>,
369}
370
371#[derive(Debug, Clone, PartialEq, Eq)]
372pub enum ByteRangeOrBitrate {
373 /// This `MediaSegment` is a sub-range of the resource
374 /// identified by its URI.
375 ByteRange(crate::ByteRange),
376
377 /// The approximate segment bit rate of this `MediaSegment`
378 /// in kbps.
379 Bitrate(u64),
380}
381
382/// A partial slice of a `MediaSegment.`
383#[derive(Debug, Clone, PartialEq)]
384pub struct PartialSegment {
385 /// The URI for this `PartialSegment`.
386 pub uri: String,
387
388 /// The duration of this `PartialSegment`.
389 pub duration_in_seconds: f64,
390
391 /// True if this `PartialSegment` contains an independent frame.
392 pub is_independent: bool,
393
394 /// Some if this `PartialSegment` is a sub-range of the resource specified by the URI.
395 pub byte_range: Option<crate::ByteRange>,
396
397 /// True if this `PartialSegment` is not available.
398 pub is_gap: bool,
399}
400
401/// A preferred point at which to start playing a Playlist.
402#[derive(Debug, Clone, PartialEq)]
403pub struct StartOffset {
404 /// A positive offset indicates a time offset from the beginning of the Playlist.
405 /// A negative offset indicates a negative time offset from the end of the last Media
406 /// Segment in the Playlist.
407 pub offset_in_seconds: f64,
408
409 /// If `true`, clients should start playback at the Media
410 /// Segment containing the [`StartOffset::offset_in_seconds`], but should not render
411 /// media samples in that segment whose presentation times are prior to the
412 /// [`StartOffset::offset_in_seconds`]. If `false`, clients should attempt to render
413 /// every media sample in that segment.
414 pub is_precise: bool,
415}