Rewrite init segment in MultiSegmentSegmenter::DoFinalize

This is called when reaching end of the file of the media. The duration
of the media is updated.

Fixes #340.

Change-Id: I446f2d341b02125d4a7d8c958bda269b5403cb9c
This commit is contained in:
KongQun Yang 2018-03-05 09:44:22 -08:00
parent 76d68de6c1
commit b24a95b1aa
25 changed files with 34 additions and 33 deletions

View File

@ -11,6 +11,7 @@
#include "packager/base/strings/string_number_conversions.h" #include "packager/base/strings/string_number_conversions.h"
#include "packager/base/strings/string_util.h" #include "packager/base/strings/string_util.h"
#include "packager/file/file.h" #include "packager/file/file.h"
#include "packager/file/file_closer.h"
#include "packager/media/base/buffer_writer.h" #include "packager/media/base/buffer_writer.h"
#include "packager/media/base/muxer_options.h" #include "packager/media/base/muxer_options.h"
#include "packager/media/base/muxer_util.h" #include "packager/media/base/muxer_util.h"
@ -55,28 +56,15 @@ std::vector<Range> MultiSegmentSegmenter::GetSegmentRanges() {
} }
Status MultiSegmentSegmenter::DoInitialize() { Status MultiSegmentSegmenter::DoInitialize() {
DCHECK(ftyp()); return WriteInitSegment();
DCHECK(moov());
// Generate the output file with init segment.
File* file = File::Open(options().output_file_name.c_str(), "w");
if (file == NULL) {
return Status(error::FILE_FAILURE,
"Cannot open file for write " + options().output_file_name);
}
std::unique_ptr<BufferWriter> buffer(new BufferWriter);
ftyp()->Write(buffer.get());
moov()->Write(buffer.get());
Status status = buffer->WriteToFile(file);
if (!file->Close()) {
LOG(WARNING) << "Failed to close the file properly: "
<< options().output_file_name;
}
return status;
} }
Status MultiSegmentSegmenter::DoFinalize() { Status MultiSegmentSegmenter::DoFinalize() {
SetComplete(); // Update init segment with media duration set.
return Status::OK; Status status = WriteInitSegment();
if (status.ok())
SetComplete();
return status;
} }
Status MultiSegmentSegmenter::DoFinalizeSegment() { Status MultiSegmentSegmenter::DoFinalizeSegment() {
@ -140,29 +128,44 @@ Status MultiSegmentSegmenter::DoFinalizeSegment() {
return WriteSegment(); return WriteSegment();
} }
Status MultiSegmentSegmenter::WriteInitSegment() {
DCHECK(ftyp());
DCHECK(moov());
// Generate the output file with init segment.
std::unique_ptr<File, FileCloser> file(
File::Open(options().output_file_name.c_str(), "w"));
if (!file) {
return Status(error::FILE_FAILURE,
"Cannot open file for write " + options().output_file_name);
}
std::unique_ptr<BufferWriter> buffer(new BufferWriter);
ftyp()->Write(buffer.get());
moov()->Write(buffer.get());
return buffer->WriteToFile(file.get());
}
Status MultiSegmentSegmenter::WriteSegment() { Status MultiSegmentSegmenter::WriteSegment() {
DCHECK(sidx()); DCHECK(sidx());
DCHECK(fragment_buffer()); DCHECK(fragment_buffer());
DCHECK(styp_); DCHECK(styp_);
std::unique_ptr<BufferWriter> buffer(new BufferWriter()); std::unique_ptr<BufferWriter> buffer(new BufferWriter());
File* file; std::unique_ptr<File, FileCloser> file;
std::string file_name; std::string file_name;
if (options().segment_template.empty()) { if (options().segment_template.empty()) {
// Append the segment to output file if segment template is not specified. // Append the segment to output file if segment template is not specified.
file_name = options().output_file_name.c_str(); file_name = options().output_file_name.c_str();
file = File::Open(file_name.c_str(), "a"); file.reset(File::Open(file_name.c_str(), "a"));
if (file == NULL) { if (!file) {
return Status( return Status(error::FILE_FAILURE, "Cannot open file for append " +
error::FILE_FAILURE, options().output_file_name);
"Cannot open file for append " + options().output_file_name);
} }
} else { } else {
file_name = GetSegmentName(options().segment_template, file_name = GetSegmentName(options().segment_template,
sidx()->earliest_presentation_time, sidx()->earliest_presentation_time,
num_segments_++, options().bandwidth); num_segments_++, options().bandwidth);
file = File::Open(file_name.c_str(), "w"); file.reset(File::Open(file_name.c_str(), "w"));
if (file == NULL) { if (!file) {
return Status(error::FILE_FAILURE, return Status(error::FILE_FAILURE,
"Cannot open file for write " + file_name); "Cannot open file for write " + file_name);
} }
@ -177,7 +180,7 @@ Status MultiSegmentSegmenter::WriteSegment() {
const size_t segment_size = segment_header_size + fragment_buffer()->Size(); const size_t segment_size = segment_header_size + fragment_buffer()->Size();
DCHECK_NE(segment_size, 0u); DCHECK_NE(segment_size, 0u);
Status status = buffer->WriteToFile(file); Status status = buffer->WriteToFile(file.get());
if (status.ok()) { if (status.ok()) {
if (muxer_listener()) { if (muxer_listener()) {
for (const KeyFrameInfo& key_frame_info : key_frame_infos()) { for (const KeyFrameInfo& key_frame_info : key_frame_infos()) {
@ -187,12 +190,9 @@ Status MultiSegmentSegmenter::WriteSegment() {
key_frame_info.size); key_frame_info.size);
} }
} }
status = fragment_buffer()->WriteToFile(file); status = fragment_buffer()->WriteToFile(file.get());
} }
if (!file->Close())
LOG(WARNING) << "Failed to close the file properly: " << file_name;
if (!status.ok()) if (!status.ok())
return status; return status;

View File

@ -49,6 +49,7 @@ class MultiSegmentSegmenter : public Segmenter {
Status DoFinalizeSegment() override; Status DoFinalizeSegment() override;
// Write segment to file. // Write segment to file.
Status WriteInitSegment();
Status WriteSegment(); Status WriteSegment();
std::unique_ptr<SegmentType> styp_; std::unique_ptr<SegmentType> styp_;

View File

@ -101,7 +101,7 @@ Status Segmenter::Initialize(
Status Segmenter::Finalize() { Status Segmenter::Finalize() {
// Set movie duration. Note that the duration in mvhd, tkhd, mdhd should not // Set movie duration. Note that the duration in mvhd, tkhd, mdhd should not
// be touched, i.e. kept at 0. The updated moov box will be written to output // be touched, i.e. kept at 0. The updated moov box will be written to output
// file for VOD case only. // file for VOD and static live case only.
moov_->extends.header.fragment_duration = 0; moov_->extends.header.fragment_duration = 0;
for (size_t i = 0; i < stream_durations_.size(); ++i) { for (size_t i = 0; i < stream_durations_.size(); ++i) {
uint64_t duration = uint64_t duration =