2023-12-01 17:32:19 +00:00
|
|
|
// Copyright 2017 Google LLC. All rights reserved.
|
2017-12-13 01:26:37 +00:00
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
//
|
|
|
|
/// All the methods that are virtual are virtual for mocking.
|
|
|
|
|
2017-12-14 01:00:11 +00:00
|
|
|
#ifndef PACKAGER_MPD_BASE_REPRESENTATION_H_
|
|
|
|
#define PACKAGER_MPD_BASE_REPRESENTATION_H_
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <cstdint>
|
2017-12-13 01:26:37 +00:00
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <optional>
|
2017-12-13 01:26:37 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <packager/mpd/base/bandwidth_estimator.h>
|
|
|
|
#include <packager/mpd/base/media_info.pb.h>
|
|
|
|
#include <packager/mpd/base/segment_info.h>
|
|
|
|
#include <packager/mpd/base/xml/xml_node.h>
|
2020-11-10 00:32:58 +00:00
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
namespace shaka {
|
|
|
|
|
|
|
|
struct ContentProtectionElement;
|
2017-12-14 01:00:11 +00:00
|
|
|
struct MpdOptions;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
class RepresentationStateChangeListener {
|
|
|
|
public:
|
|
|
|
RepresentationStateChangeListener() {}
|
|
|
|
virtual ~RepresentationStateChangeListener() {}
|
|
|
|
|
|
|
|
/// Notifies the instance that a new (sub)segment was added to
|
|
|
|
/// the Representation.
|
|
|
|
/// @param start_time is the start time of the new segment.
|
|
|
|
/// @param duration is the duration of the new segment.
|
2018-06-22 01:14:34 +00:00
|
|
|
virtual void OnNewSegmentForRepresentation(int64_t start_time,
|
|
|
|
int64_t duration) = 0;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
/// Notifies the instance that the frame rate was set for the
|
|
|
|
/// Representation.
|
|
|
|
/// @param frame_duration is the duration of a frame.
|
|
|
|
/// @param timescale is the timescale of the Representation.
|
2021-08-04 18:56:44 +00:00
|
|
|
virtual void OnSetFrameRateForRepresentation(int32_t frame_duration,
|
|
|
|
int32_t timescale) = 0;
|
2017-12-13 01:26:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Representation class contains references to a single media stream, as
|
|
|
|
/// well as optional ContentProtection elements for that stream.
|
|
|
|
class Representation {
|
|
|
|
public:
|
|
|
|
enum SuppressFlag {
|
|
|
|
kSuppressWidth = 1,
|
|
|
|
kSuppressHeight = 2,
|
|
|
|
kSuppressFrameRate = 4,
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual ~Representation();
|
|
|
|
|
|
|
|
/// Tries to initialize the instance. If this does not succeed, the instance
|
|
|
|
/// should not be used.
|
|
|
|
/// @return true on success, false otherwise.
|
|
|
|
bool Init();
|
|
|
|
|
|
|
|
/// Add a ContenProtection element to the representation.
|
|
|
|
/// Representation does not add <ContentProtection> elements
|
|
|
|
/// automatically to itself even if @a media_info passed to
|
|
|
|
/// AdaptationSet::AddRepresentation() has @a media_info.protected_content
|
|
|
|
/// populated. This is because some MPDs should have the elements at
|
|
|
|
/// AdaptationSet level and some at Representation level.
|
|
|
|
/// @param element contains the ContentProtection element contents.
|
|
|
|
/// If @a element has {value, schemeIdUri} set and has
|
|
|
|
/// {“value”, “schemeIdUri”} as key for @a additional_attributes,
|
|
|
|
/// then the former is used.
|
|
|
|
virtual void AddContentProtectionElement(
|
|
|
|
const ContentProtectionElement& element);
|
|
|
|
|
|
|
|
/// Update the 'cenc:pssh' element for @a drm_uuid ContentProtection element.
|
|
|
|
/// If the element does not exist, this will add one.
|
|
|
|
/// @param drm_uuid is the UUID of the DRM for encryption.
|
|
|
|
/// @param pssh is the content of <cenc:pssh> element.
|
|
|
|
/// Note that DASH IF IOP mentions that this should be base64 encoded
|
|
|
|
/// string of the whole pssh box.
|
|
|
|
/// @attention This might get removed once DASH IF IOP specification makes a
|
|
|
|
/// a clear guideline on how to handle key rotation. Also to get
|
|
|
|
/// this working with shaka-player, this method *DOES NOT* update
|
|
|
|
/// the PSSH element. Instead, it removes the element regardless of
|
|
|
|
/// the content of @a pssh.
|
|
|
|
virtual void UpdateContentProtectionPssh(const std::string& drm_uuid,
|
|
|
|
const std::string& pssh);
|
|
|
|
|
|
|
|
/// Add a media (sub)segment to the representation.
|
|
|
|
/// AdaptationSet@{subsegmentAlignment,segmentAlignment} cannot be set
|
|
|
|
/// if this is not called for all Representations.
|
|
|
|
/// @param start_time is the start time for the (sub)segment, in units of the
|
|
|
|
/// stream's time scale.
|
|
|
|
/// @param duration is the duration of the segment, in units of the stream's
|
2021-09-03 16:57:43 +00:00
|
|
|
/// time scale. In the low latency case, this duration is that of the
|
|
|
|
/// first chunk because the full duration is not yet known.
|
|
|
|
/// @param size of the segment in bytes. In the low latency case, this size is
|
|
|
|
/// that of the
|
|
|
|
/// first chunk because the full size is not yet known.
|
2024-05-02 20:25:49 +00:00
|
|
|
/// @param segment_number is the current segment number.
|
2018-06-22 01:14:34 +00:00
|
|
|
virtual void AddNewSegment(int64_t start_time,
|
|
|
|
int64_t duration,
|
2024-05-02 20:25:49 +00:00
|
|
|
uint64_t size,
|
|
|
|
int64_t segment_number);
|
2017-12-13 01:26:37 +00:00
|
|
|
|
2021-09-03 16:57:43 +00:00
|
|
|
/// Update a media segment in the Representation.
|
|
|
|
/// In the low latency case, the segment duration will not be ready until the
|
|
|
|
/// entire segment has been processed. This allows setting the full duration
|
|
|
|
/// after the segment has been completed and the true duratio is known.
|
|
|
|
/// @param duration is the duration of the complete segment, in units of the
|
|
|
|
/// stream's
|
|
|
|
/// time scale.
|
|
|
|
/// @param size of the complete segment in bytes.
|
|
|
|
virtual void UpdateCompletedSegment(int64_t duration, uint64_t size);
|
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
/// Set the sample duration of this Representation.
|
|
|
|
/// Sample duration is not available right away especially for live. This
|
|
|
|
/// allows setting the sample duration after the Representation has been
|
|
|
|
/// initialized.
|
|
|
|
/// @param sample_duration is the duration of a sample.
|
2021-08-04 18:56:44 +00:00
|
|
|
virtual void SetSampleDuration(int32_t sample_duration);
|
2017-12-13 01:26:37 +00:00
|
|
|
|
2018-01-03 00:10:54 +00:00
|
|
|
/// @return MediaInfo for the Representation.
|
|
|
|
virtual const MediaInfo& GetMediaInfo() const;
|
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
/// @return Copy of <Representation>.
|
2023-12-01 17:32:19 +00:00
|
|
|
std::optional<xml::XmlNode> GetXml();
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
/// By calling this methods, the next time GetXml() is
|
|
|
|
/// called, the corresponding attributes will not be set.
|
|
|
|
/// For example, if SuppressOnce(kSuppressWidth) is called, then GetXml() will
|
|
|
|
/// return a <Representation> element without a @width attribute.
|
|
|
|
/// Note that it only applies to the next call to GetXml(), calling GetXml()
|
|
|
|
/// again without calling this methods will return a <Representation> element
|
|
|
|
/// with the attribute.
|
|
|
|
/// This may be called multiple times to set different (or the same) flags.
|
|
|
|
void SuppressOnce(SuppressFlag flag);
|
|
|
|
|
2018-01-29 18:37:50 +00:00
|
|
|
/// Set @presentationTimeOffset in SegmentBase / SegmentTemplate.
|
|
|
|
void SetPresentationTimeOffset(double presentation_time_offset);
|
|
|
|
|
2021-08-25 15:38:05 +00:00
|
|
|
/// Set @availabilityTimeOffset in SegmentTemplate.
|
|
|
|
/// This is necessary for Low Latency DASH streaming.
|
|
|
|
void SetAvailabilityTimeOffset();
|
|
|
|
|
|
|
|
/// Set @duration in SegmentTemplate.
|
|
|
|
/// This is necessary for Low Latency DASH streaming.
|
|
|
|
void SetSegmentDuration();
|
|
|
|
|
2018-01-29 18:37:50 +00:00
|
|
|
/// Gets the start and end timestamps in seconds.
|
|
|
|
/// @param start_timestamp_seconds contains the returned start timestamp in
|
|
|
|
/// seconds on success. It can be nullptr, which means that start
|
|
|
|
/// timestamp does not need to be returned.
|
|
|
|
/// @param end_timestamp_seconds contains the returned end timestamp in
|
|
|
|
/// seconds on success. It can be nullptr, which means that end
|
|
|
|
/// timestamp does not need to be returned.
|
2018-01-05 02:31:27 +00:00
|
|
|
/// @return true if successful, false otherwise.
|
2018-01-29 18:37:50 +00:00
|
|
|
bool GetStartAndEndTimestamps(double* start_timestamp_seconds,
|
|
|
|
double* end_timestamp_seconds) const;
|
2018-01-05 02:31:27 +00:00
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
/// @return ID number for <Representation>.
|
|
|
|
uint32_t id() const { return id_; }
|
|
|
|
|
2018-05-22 00:39:21 +00:00
|
|
|
void set_media_info(const MediaInfo& media_info) { media_info_ = media_info; }
|
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
protected:
|
|
|
|
/// @param media_info is a MediaInfo containing information on the media.
|
|
|
|
/// @a media_info.bandwidth is required for 'static' profile. If @a
|
|
|
|
/// media_info.bandwidth is not present in 'dynamic' profile, this
|
|
|
|
/// tries to estimate it using the info passed to AddNewSegment().
|
|
|
|
/// @param mpd_options is options for the entire MPD.
|
|
|
|
/// @param representation_id is the numeric ID for the <Representation>.
|
|
|
|
/// @param state_change_listener is an event handler for state changes to
|
|
|
|
/// the representation. If null, no event handler registered.
|
|
|
|
Representation(
|
|
|
|
const MediaInfo& media_info,
|
|
|
|
const MpdOptions& mpd_options,
|
|
|
|
uint32_t representation_id,
|
|
|
|
std::unique_ptr<RepresentationStateChangeListener> state_change_listener);
|
|
|
|
|
2018-01-03 00:10:54 +00:00
|
|
|
/// @param representation points to the original Representation to be cloned.
|
|
|
|
/// @param state_change_listener is an event handler for state changes to
|
|
|
|
/// the representation. If null, no event handler registered.
|
|
|
|
Representation(
|
|
|
|
const Representation& representation,
|
|
|
|
std::unique_ptr<RepresentationStateChangeListener> state_change_listener);
|
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
private:
|
|
|
|
Representation(const Representation&) = delete;
|
|
|
|
Representation& operator=(const Representation&) = delete;
|
|
|
|
|
|
|
|
friend class AdaptationSet;
|
2017-12-14 21:30:16 +00:00
|
|
|
friend class RepresentationTest;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
// Returns true if |media_info_| has required fields to generate a valid
|
|
|
|
// Representation. Otherwise returns false.
|
2018-01-24 23:26:37 +00:00
|
|
|
bool HasRequiredMediaInfoFields() const;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
2017-09-25 19:18:50 +00:00
|
|
|
// Add a SegmentInfo. This function may insert an adjusted SegmentInfo if
|
|
|
|
// |allow_approximate_segment_timeline_| is set.
|
2024-05-02 20:25:49 +00:00
|
|
|
void AddSegmentInfo(int64_t start_time,
|
|
|
|
int64_t duration,
|
|
|
|
int64_t segment_number);
|
2017-09-25 19:18:50 +00:00
|
|
|
|
2021-09-03 16:57:43 +00:00
|
|
|
// Update the current SegmentInfo. This method is used to update the duration
|
|
|
|
// value after a low latency segment is complete, and the full segment
|
|
|
|
// duration is known.
|
|
|
|
void UpdateSegmentInfo(int64_t duration);
|
|
|
|
|
2017-09-25 19:18:50 +00:00
|
|
|
// Check if two timestamps are approximately equal if
|
|
|
|
// |allow_approximate_segment_timeline_| is set; Otherwise check whether the
|
|
|
|
// two times match.
|
2018-06-22 01:14:34 +00:00
|
|
|
bool ApproximiatelyEqual(int64_t time1, int64_t time2) const;
|
2017-09-25 19:18:50 +00:00
|
|
|
|
|
|
|
// Return adjusted duration if |allow_aproximate_segment_timeline_or_duration|
|
|
|
|
// is set; otherwise duration is returned without adjustment.
|
2018-06-22 01:14:34 +00:00
|
|
|
int64_t AdjustDuration(int64_t duration) const;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
// Remove elements from |segment_infos_| for dynamic live profile. Increments
|
|
|
|
// |start_number_| by the number of segments removed.
|
|
|
|
void SlideWindow();
|
|
|
|
|
2019-03-22 00:12:30 +00:00
|
|
|
// Remove the first segment in |segment_info|.
|
|
|
|
void RemoveOldSegment(SegmentInfo* segment_info);
|
2018-04-04 23:17:59 +00:00
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
// Note: Because 'mimeType' is a required field for a valid MPD, these return
|
|
|
|
// strings.
|
|
|
|
std::string GetVideoMimeType() const;
|
|
|
|
std::string GetAudioMimeType() const;
|
|
|
|
std::string GetTextMimeType() const;
|
|
|
|
|
2019-03-26 22:16:30 +00:00
|
|
|
// Get Representation as string. For debugging.
|
|
|
|
std::string RepresentationAsString() const;
|
|
|
|
|
2017-12-13 01:26:37 +00:00
|
|
|
// Init() checks that only one of VideoInfo, AudioInfo, or TextInfo is set. So
|
|
|
|
// any logic using this can assume only one set.
|
|
|
|
MediaInfo media_info_;
|
|
|
|
std::list<ContentProtectionElement> content_protection_elements_;
|
2019-03-22 00:12:30 +00:00
|
|
|
|
|
|
|
int64_t current_buffer_depth_ = 0;
|
2018-01-03 00:10:54 +00:00
|
|
|
// TODO(kqyang): Address sliding window issue with multiple periods.
|
2017-12-13 01:26:37 +00:00
|
|
|
std::list<SegmentInfo> segment_infos_;
|
2018-04-17 22:03:02 +00:00
|
|
|
// A list to hold the file names of the segments to be removed temporarily.
|
|
|
|
// Once a file is actually removed, it is removed from the list.
|
2018-04-04 23:17:59 +00:00
|
|
|
std::list<std::string> segments_to_be_removed_;
|
2017-12-13 01:26:37 +00:00
|
|
|
|
|
|
|
const uint32_t id_;
|
|
|
|
std::string mime_type_;
|
|
|
|
std::string codecs_;
|
|
|
|
BandwidthEstimator bandwidth_estimator_;
|
|
|
|
const MpdOptions& mpd_options_;
|
|
|
|
|
|
|
|
// If this is not null, then Representation is responsible for calling the
|
|
|
|
// right methods at right timings.
|
|
|
|
std::unique_ptr<RepresentationStateChangeListener> state_change_listener_;
|
|
|
|
|
|
|
|
// Bit vector for tracking witch attributes should not be output.
|
2017-09-25 19:18:50 +00:00
|
|
|
int output_suppression_flags_ = 0;
|
|
|
|
|
|
|
|
// When set to true, allows segments to have slightly different durations (up
|
|
|
|
// to one sample).
|
|
|
|
const bool allow_approximate_segment_timeline_ = false;
|
|
|
|
// Segments with duration difference less than one frame duration are
|
|
|
|
// considered to have the same duration.
|
2021-08-04 18:56:44 +00:00
|
|
|
int32_t frame_duration_ = 0;
|
2017-12-13 01:26:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace shaka
|
2017-12-14 01:00:11 +00:00
|
|
|
|
|
|
|
#endif // PACKAGER_MPD_BASE_REPRESENTATION_H_
|