2023-12-01 17:32:19 +00:00
|
|
|
// Copyright 2015 Google LLC. All rights reserved.
|
2015-10-28 17:23:08 +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
|
|
|
|
|
2017-12-20 00:56:36 +00:00
|
|
|
#ifndef PACKAGER_MEDIA_FORMATS_WEBM_SEGMENTER_H_
|
|
|
|
#define PACKAGER_MEDIA_FORMATS_WEBM_SEGMENTER_H_
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2016-08-17 17:41:40 +00:00
|
|
|
#include <memory>
|
2017-05-01 23:17:09 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <mkvmuxer/mkvmuxer.h>
|
|
|
|
|
|
|
|
#include <packager/macros/classes.h>
|
|
|
|
#include <packager/media/base/range.h>
|
|
|
|
#include <packager/media/formats/webm/mkv_writer.h>
|
|
|
|
#include <packager/media/formats/webm/seek_head.h>
|
|
|
|
#include <packager/status.h>
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2015-10-28 17:23:08 +00:00
|
|
|
namespace media {
|
|
|
|
|
|
|
|
struct MuxerOptions;
|
|
|
|
|
|
|
|
class AudioStreamInfo;
|
|
|
|
class MediaSample;
|
|
|
|
class MuxerListener;
|
|
|
|
class ProgressListener;
|
|
|
|
class StreamInfo;
|
|
|
|
class VideoStreamInfo;
|
|
|
|
|
|
|
|
namespace webm {
|
|
|
|
|
|
|
|
class Segmenter {
|
|
|
|
public:
|
|
|
|
explicit Segmenter(const MuxerOptions& options);
|
|
|
|
virtual ~Segmenter();
|
|
|
|
|
|
|
|
/// Initialize the segmenter.
|
|
|
|
/// Calling other public methods of this class without this method returning
|
|
|
|
/// Status::OK results in an undefined behavior.
|
2015-12-22 00:33:55 +00:00
|
|
|
/// @param info The stream info for the stream being segmented.
|
2015-10-28 17:23:08 +00:00
|
|
|
/// @param muxer_listener receives muxer events. Can be NULL.
|
|
|
|
/// @return OK on success, an error status otherwise.
|
2017-09-12 17:24:24 +00:00
|
|
|
Status Initialize(const StreamInfo& info,
|
2015-10-28 17:23:08 +00:00
|
|
|
ProgressListener* progress_listener,
|
2017-03-11 02:49:55 +00:00
|
|
|
MuxerListener* muxer_listener);
|
2015-10-28 17:23:08 +00:00
|
|
|
|
|
|
|
/// Finalize the segmenter.
|
|
|
|
/// @return OK on success, an error status otherwise.
|
|
|
|
Status Finalize();
|
|
|
|
|
|
|
|
/// Add sample to the indicated stream.
|
|
|
|
/// @param sample points to the sample to be added.
|
|
|
|
/// @return OK on success, an error status otherwise.
|
2017-09-12 17:24:24 +00:00
|
|
|
Status AddSample(const MediaSample& sample);
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2017-02-24 01:17:47 +00:00
|
|
|
/// Finalize the (sub)segment.
|
2021-08-04 18:56:44 +00:00
|
|
|
virtual Status FinalizeSegment(int64_t start_timestamp,
|
|
|
|
int64_t duration_timestamp,
|
2024-05-02 20:25:49 +00:00
|
|
|
bool is_subsegment,
|
|
|
|
int64_t segment_number) = 0;
|
2017-02-24 01:17:47 +00:00
|
|
|
|
2015-10-28 17:23:08 +00:00
|
|
|
/// @return true if there is an initialization range, while setting @a start
|
|
|
|
/// and @a end; or false if initialization range does not apply.
|
2016-04-15 23:00:27 +00:00
|
|
|
virtual bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) = 0;
|
2015-10-28 17:23:08 +00:00
|
|
|
|
|
|
|
/// @return true if there is an index byte range, while setting @a start
|
|
|
|
/// and @a end; or false if index byte range does not apply.
|
2016-04-15 23:00:27 +00:00
|
|
|
virtual bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) = 0;
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2017-05-01 23:17:09 +00:00
|
|
|
// Returns an empty vector if there are no specific ranges for the segments,
|
|
|
|
// e.g. the media is in multiple files.
|
|
|
|
// Otherwise, a vector of ranges for the media segments are returned.
|
|
|
|
virtual std::vector<Range> GetSegmentRanges() = 0;
|
|
|
|
|
2015-10-28 17:23:08 +00:00
|
|
|
/// @return The total length, in seconds, of segmented media files.
|
2017-05-13 00:02:12 +00:00
|
|
|
float GetDurationInSeconds() const;
|
2015-10-28 17:23:08 +00:00
|
|
|
|
|
|
|
protected:
|
2017-05-13 00:02:12 +00:00
|
|
|
/// Converts the given time in ISO BMFF timestamp to WebM timecode.
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t FromBmffTimestamp(int64_t bmff_timestamp);
|
2017-05-13 00:02:12 +00:00
|
|
|
/// Converts the given time in WebM timecode to ISO BMFF timestamp.
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t FromWebMTimecode(int64_t webm_timecode);
|
2015-10-28 17:23:08 +00:00
|
|
|
/// Writes the Segment header to @a writer.
|
|
|
|
Status WriteSegmentHeader(uint64_t file_size, MkvWriter* writer);
|
|
|
|
/// Creates a Cluster object with the given parameters.
|
2021-08-04 18:56:44 +00:00
|
|
|
Status SetCluster(int64_t start_webm_timecode,
|
2015-10-28 17:23:08 +00:00
|
|
|
uint64_t position,
|
|
|
|
MkvWriter* writer);
|
|
|
|
|
|
|
|
/// Update segmentation progress using ProgressListener.
|
|
|
|
void UpdateProgress(uint64_t progress);
|
|
|
|
void set_progress_target(uint64_t target) { progress_target_ = target; }
|
|
|
|
|
|
|
|
const MuxerOptions& options() const { return options_; }
|
|
|
|
mkvmuxer::Cluster* cluster() { return cluster_.get(); }
|
|
|
|
mkvmuxer::Cues* cues() { return &cues_; }
|
|
|
|
MuxerListener* muxer_listener() { return muxer_listener_; }
|
|
|
|
SeekHead* seek_head() { return &seek_head_; }
|
|
|
|
|
|
|
|
int track_id() const { return track_id_; }
|
|
|
|
uint64_t segment_payload_pos() const { return segment_payload_pos_; }
|
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t duration() const { return duration_; }
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2017-03-16 20:56:11 +00:00
|
|
|
virtual Status DoInitialize() = 0;
|
2015-10-28 17:23:08 +00:00
|
|
|
virtual Status DoFinalize() = 0;
|
|
|
|
|
|
|
|
private:
|
2017-09-12 17:24:24 +00:00
|
|
|
Status InitializeAudioTrack(const AudioStreamInfo& info,
|
2017-03-11 02:49:55 +00:00
|
|
|
mkvmuxer::AudioTrack* track);
|
2017-09-12 17:24:24 +00:00
|
|
|
Status InitializeVideoTrack(const VideoStreamInfo& info,
|
2017-03-11 02:49:55 +00:00
|
|
|
mkvmuxer::VideoTrack* track);
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2016-01-21 23:58:13 +00:00
|
|
|
// Writes the previous frame to the file.
|
|
|
|
Status WriteFrame(bool write_duration);
|
|
|
|
|
2017-02-24 01:17:47 +00:00
|
|
|
// This is called when there needs to be a new (sub)segment.
|
|
|
|
// In single-segment mode, a Cluster is a segment and there is no subsegment.
|
|
|
|
// In multi-segment mode, a new file is a segment and the clusters in the file
|
|
|
|
// are subsegments.
|
2021-08-04 18:56:44 +00:00
|
|
|
virtual Status NewSegment(int64_t start_timestamp, bool is_subsegment) = 0;
|
2016-01-21 23:58:13 +00:00
|
|
|
|
|
|
|
// Store the previous sample so we know which one is the last frame.
|
2017-09-12 17:24:24 +00:00
|
|
|
std::shared_ptr<const MediaSample> prev_sample_;
|
2016-01-21 23:58:13 +00:00
|
|
|
// The reference frame timestamp; used to populate the ReferenceBlock element
|
|
|
|
// when writing non-keyframe BlockGroups.
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t reference_frame_timestamp_ = 0;
|
2015-10-28 17:23:08 +00:00
|
|
|
|
|
|
|
const MuxerOptions& options_;
|
|
|
|
|
2016-08-17 17:41:40 +00:00
|
|
|
std::unique_ptr<mkvmuxer::Cluster> cluster_;
|
2015-10-28 17:23:08 +00:00
|
|
|
mkvmuxer::Cues cues_;
|
|
|
|
SeekHead seek_head_;
|
|
|
|
mkvmuxer::SegmentInfo segment_info_;
|
|
|
|
mkvmuxer::Tracks tracks_;
|
|
|
|
|
2017-02-24 01:17:47 +00:00
|
|
|
MuxerListener* muxer_listener_ = nullptr;
|
|
|
|
ProgressListener* progress_listener_ = nullptr;
|
|
|
|
uint64_t progress_target_ = 0;
|
|
|
|
uint64_t accumulated_progress_ = 0;
|
2024-02-28 23:53:06 +00:00
|
|
|
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t first_timestamp_ = 0;
|
2024-02-28 23:53:06 +00:00
|
|
|
int64_t sample_durations_[2] = {0, 0};
|
|
|
|
size_t num_samples_ = 0;
|
|
|
|
|
2015-10-28 17:23:08 +00:00
|
|
|
// The position (in bytes) of the start of the Segment payload in the init
|
|
|
|
// file. This is also the size of the header before the SeekHead.
|
2017-02-24 01:17:47 +00:00
|
|
|
uint64_t segment_payload_pos_ = 0;
|
|
|
|
|
|
|
|
// Indicate whether a new segment needed to be created, which is always true
|
|
|
|
// in the beginning.
|
|
|
|
bool new_segment_ = true;
|
|
|
|
// Indicate whether a new subsegment needed to be created.
|
|
|
|
bool new_subsegment_ = false;
|
|
|
|
int track_id_ = 0;
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2017-09-12 17:24:24 +00:00
|
|
|
// The subset of information that we need from StreamInfo
|
|
|
|
bool is_encrypted_ = false;
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t time_scale_ = 0;
|
|
|
|
int64_t duration_ = 0;
|
2017-09-12 17:24:24 +00:00
|
|
|
|
2015-10-28 17:23:08 +00:00
|
|
|
DISALLOW_COPY_AND_ASSIGN(Segmenter);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace webm
|
|
|
|
} // namespace media
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|
2015-10-28 17:23:08 +00:00
|
|
|
|
2017-12-20 00:56:36 +00:00
|
|
|
#endif // PACKAGER_MEDIA_FORMATS_WEBM_SEGMENTER_H_
|