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>
23 SingleSegmentSegmenter::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)) {}
28 SingleSegmentSegmenter::~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_;
37 bool SingleSegmentSegmenter::GetInitRange(
size_t* offset,
size_t* size) {
40 *size = ftyp()->ComputeSize() + moov()->ComputeSize();
44 bool 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()
54 std::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;
72 Status 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"));
86 : Status(error::FILE_FAILURE,
87 "Cannot open file to write " + temp_file_name_);
90 Status SingleSegmentSegmenter::DoFinalize() {
97 if (!temp_file_.release()->Close()) {
100 "Cannot close the temp file " + temp_file_name_ +
101 ", possibly file permission issue or running out of disk space.");
104 std::unique_ptr<File, FileCloser> file(
105 File::Open(options().output_file_name.c_str(),
"w"));
107 return Status(error::FILE_FAILURE,
108 "Cannot open file to write " + options().output_file_name);
111 LOG(INFO) <<
"Update media header (moov) and rewrite the file to '"
112 << options().output_file_name <<
"'.";
115 std::unique_ptr<BufferWriter> buffer(
new BufferWriter());
116 ftyp()->Write(buffer.get());
117 moov()->Write(buffer.get());
119 if (options().mp4_params.generate_sidx_in_media_segments)
120 vod_sidx_->Write(buffer.get());
122 Status status = buffer->WriteToFile(file.get());
127 std::unique_ptr<File, FileCloser> temp_file(
128 File::Open(temp_file_name_.c_str(),
"r"));
129 if (temp_file == NULL) {
130 return Status(error::FILE_FAILURE,
131 "Cannot open file to read " + temp_file_name_);
135 const uint64_t re_segment_progress_target = progress_target() * 0.5;
137 const int kBufSize = 0x200000;
138 std::unique_ptr<uint8_t[]> buf(
new uint8_t[kBufSize]);
140 int64_t size = temp_file->Read(buf.get(), kBufSize);
143 }
else if (size < 0) {
144 return Status(error::FILE_FAILURE,
145 "Failed to read file " + temp_file_name_);
147 int64_t size_written = file->Write(buf.get(), size);
148 if (size_written != size) {
149 return Status(error::FILE_FAILURE,
150 "Failed to write file " + options().output_file_name);
152 UpdateProgress(
static_cast<double>(size) / temp_file->Size() *
153 re_segment_progress_target);
155 if (!temp_file.release()->Close()) {
156 return Status(error::FILE_FAILURE,
"Cannot close the temp file " +
157 temp_file_name_ +
" after reading.");
159 if (!file.release()->Close()) {
162 "Cannot close file " + options().output_file_name +
163 ", possibly file permission issue or running out of disk space.");
169 Status SingleSegmentSegmenter::DoFinalizeSegment(int64_t segment_number) {
171 DCHECK(fragment_buffer());
175 std::vector<SegmentReference>& refs = sidx()->references;
176 SegmentReference& vod_ref = refs[0];
177 int64_t first_sap_time =
178 refs[0].sap_delta_time + refs[0].earliest_presentation_time;
179 for (uint32_t i = 1; i < refs.size(); ++i) {
180 vod_ref.referenced_size += refs[i].referenced_size;
184 vod_ref.subsegment_duration += refs[i].subsegment_duration;
185 vod_ref.earliest_presentation_time = std::min(
186 vod_ref.earliest_presentation_time, refs[i].earliest_presentation_time);
188 if (vod_ref.sap_type == SegmentReference::TypeUnknown &&
189 refs[i].sap_type != SegmentReference::TypeUnknown) {
190 vod_ref.sap_type = refs[i].sap_type;
192 refs[i].sap_delta_time + refs[i].earliest_presentation_time;
196 if (vod_ref.sap_type != SegmentReference::TypeUnknown) {
197 vod_ref.sap_delta_time =
198 first_sap_time - vod_ref.earliest_presentation_time;
202 if (vod_sidx_ == NULL) {
203 vod_sidx_.reset(
new SegmentIndex());
204 vod_sidx_->reference_id = sidx()->reference_id;
205 vod_sidx_->timescale = sidx()->timescale;
206 vod_sidx_->earliest_presentation_time = vod_ref.earliest_presentation_time;
208 vod_sidx_->references.push_back(vod_ref);
210 if (muxer_listener()) {
211 for (
const KeyFrameInfo& key_frame_info : key_frame_infos()) {
214 muxer_listener()->OnKeyFrame(key_frame_info.timestamp,
215 key_frame_info.start_byte_offset,
216 key_frame_info.size);
220 size_t segment_size = fragment_buffer()->Size();
221 Status status = fragment_buffer()->WriteToFile(temp_file_.get());
222 if (!status.ok())
return status;
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)