7#include <packager/media/formats/mp4/single_segment_segmenter.h>
11#include <absl/log/check.h>
13#include <packager/file/file_util.h>
14#include <packager/media/base/buffer_writer.h>
15#include <packager/media/base/muxer_options.h>
16#include <packager/media/event/progress_listener.h>
17#include <packager/media/formats/mp4/key_frame_info.h>
23SingleSegmentSegmenter::SingleSegmentSegmenter(
const MuxerOptions& options,
24 std::unique_ptr<FileType> ftyp,
25 std::unique_ptr<Movie> moov)
26 : Segmenter(options, std::move(ftyp), std::move(moov)) {}
28SingleSegmentSegmenter::~SingleSegmentSegmenter() {
30 temp_file_.release()->Close();
31 if (!temp_file_name_.empty()) {
32 if (!File::Delete(temp_file_name_.c_str()))
33 LOG(ERROR) <<
"Unable to delete temporary file " << temp_file_name_;
37bool SingleSegmentSegmenter::GetInitRange(
size_t* offset,
size_t* size) {
40 *size = ftyp()->ComputeSize() + moov()->ComputeSize();
44bool SingleSegmentSegmenter::GetIndexRange(
size_t* offset,
size_t* size) {
47 *offset = ftyp()->ComputeSize() + moov()->ComputeSize();
48 *size = options().mp4_params.generate_sidx_in_media_segments
49 ? vod_sidx_->ComputeSize()
54std::vector<Range> SingleSegmentSegmenter::GetSegmentRanges() {
55 std::vector<Range> ranges;
56 uint64_t next_offset = ftyp()->ComputeSize() + moov()->ComputeSize() +
57 (options().mp4_params.generate_sidx_in_media_segments
58 ? vod_sidx_->ComputeSize()
60 vod_sidx_->first_offset;
63 r.start = next_offset;
65 r.end = r.start + segment_reference.referenced_size - 1;
66 next_offset = r.end + 1;
72Status SingleSegmentSegmenter::DoInitialize() {
79 set_progress_target(progress_target() * 2);
82 return Status(error::FILE_FAILURE,
"Unable to create temporary file.");
83 temp_file_.reset(File::Open(temp_file_name_.c_str(),
"w"));
84 return temp_file_ ? Status::OK
85 : Status(error::FILE_FAILURE,
86 "Cannot open file to write " + temp_file_name_);
89Status SingleSegmentSegmenter::DoFinalize() {
96 if (!temp_file_.release()->Close()) {
99 "Cannot close the temp file " + temp_file_name_ +
100 ", possibly file permission issue or running out of disk space.");
103 std::unique_ptr<File, FileCloser> file(
104 File::Open(options().output_file_name.c_str(),
"w"));
106 return Status(error::FILE_FAILURE,
107 "Cannot open file to write " + options().output_file_name);
110 LOG(INFO) <<
"Update media header (moov) and rewrite the file to '"
111 << options().output_file_name <<
"'.";
114 std::unique_ptr<BufferWriter> buffer(
new BufferWriter());
115 ftyp()->Write(buffer.get());
116 moov()->Write(buffer.get());
118 if (options().mp4_params.generate_sidx_in_media_segments)
119 vod_sidx_->Write(buffer.get());
121 Status status = buffer->WriteToFile(file.get());
126 std::unique_ptr<File, FileCloser> temp_file(
127 File::Open(temp_file_name_.c_str(),
"r"));
128 if (temp_file == NULL) {
129 return Status(error::FILE_FAILURE,
130 "Cannot open file to read " + temp_file_name_);
134 const uint64_t re_segment_progress_target = progress_target() * 0.5;
136 const int kBufSize = 0x200000;
137 std::unique_ptr<uint8_t[]> buf(
new uint8_t[kBufSize]);
139 int64_t size = temp_file->Read(buf.get(), kBufSize);
142 }
else if (size < 0) {
143 return Status(error::FILE_FAILURE,
144 "Failed to read file " + temp_file_name_);
146 int64_t size_written = file->Write(buf.get(), size);
147 if (size_written != size) {
148 return Status(error::FILE_FAILURE,
149 "Failed to write file " + options().output_file_name);
151 UpdateProgress(
static_cast<double>(size) / temp_file->Size() *
152 re_segment_progress_target);
154 if (!temp_file.release()->Close()) {
155 return Status(error::FILE_FAILURE,
"Cannot close the temp file " +
156 temp_file_name_ +
" after reading.");
158 if (!file.release()->Close()) {
161 "Cannot close file " + options().output_file_name +
162 ", possibly file permission issue or running out of disk space.");
168Status SingleSegmentSegmenter::DoFinalizeSegment(int64_t segment_number) {
170 DCHECK(fragment_buffer());
174 std::vector<SegmentReference>& refs = sidx()->references;
175 SegmentReference& vod_ref = refs[0];
176 int64_t first_sap_time =
177 refs[0].sap_delta_time + refs[0].earliest_presentation_time;
178 for (uint32_t i = 1; i < refs.size(); ++i) {
179 vod_ref.referenced_size += refs[i].referenced_size;
183 vod_ref.subsegment_duration += refs[i].subsegment_duration;
184 vod_ref.earliest_presentation_time = std::min(
185 vod_ref.earliest_presentation_time, refs[i].earliest_presentation_time);
187 if (vod_ref.sap_type == SegmentReference::TypeUnknown &&
188 refs[i].sap_type != SegmentReference::TypeUnknown) {
189 vod_ref.sap_type = refs[i].sap_type;
191 refs[i].sap_delta_time + refs[i].earliest_presentation_time;
195 if (vod_ref.sap_type != SegmentReference::TypeUnknown) {
196 vod_ref.sap_delta_time =
197 first_sap_time - vod_ref.earliest_presentation_time;
201 if (vod_sidx_ == NULL) {
202 vod_sidx_.reset(
new SegmentIndex());
203 vod_sidx_->reference_id = sidx()->reference_id;
204 vod_sidx_->timescale = sidx()->timescale;
205 vod_sidx_->earliest_presentation_time = vod_ref.earliest_presentation_time;
207 vod_sidx_->references.push_back(vod_ref);
209 if (muxer_listener()) {
210 for (
const KeyFrameInfo& key_frame_info : key_frame_infos()) {
213 muxer_listener()->OnKeyFrame(key_frame_info.timestamp,
214 key_frame_info.start_byte_offset,
215 key_frame_info.size);
219 size_t segment_size = fragment_buffer()->Size();
220 Status status = fragment_buffer()->WriteToFile(temp_file_.get());
224 UpdateProgress(vod_ref.subsegment_duration);
225 if (muxer_listener()) {
226 muxer_listener()->OnSampleDurationReady(sample_duration());
227 muxer_listener()->OnNewSegment(
228 options().output_file_name, vod_ref.earliest_presentation_time,
229 vod_ref.subsegment_duration, segment_size, segment_number);
All the methods that are virtual are virtual for mocking.
bool TempFilePath(const std::string &temp_dir, std::string *temp_file_path)