Close files in Finalize for WebM segmenters.

Now Finalize() will close all the files used by the segmenters.  This
is important to allow WebMMuxer::FireOnMediaEndEvent to get the
correct size of the media file.

This also changes the WebM muxer to use 64-bit numbers for the init
and index ranges to correctly support >4GB files.

b/28194272

Change-Id: Ia84e4a4b0756f89644efea99a1a51968b22a1338
This commit is contained in:
Jacob Trimble 2016-04-15 16:00:27 -07:00
parent a50b5787dc
commit a80e16bab0
9 changed files with 43 additions and 28 deletions

View File

@ -26,6 +26,14 @@ Status MkvWriter::Open(const std::string& name) {
return Status::OK;
}
Status MkvWriter::Close() {
const std::string file_name = file_->file_name();
if (!file_.release()->Close()) {
return Status(error::FILE_FAILURE, "Cannot close file " + file_name);
}
return Status::OK;
}
mkvmuxer::int32 MkvWriter::Write(const void* buf, mkvmuxer::uint32 len) {
DCHECK(file_);

View File

@ -28,6 +28,8 @@ class MkvWriter : public mkvmuxer::IMkvWriter {
/// @param name The path to the file to open.
/// @return Whether the operation succeeded.
Status Open(const std::string& name);
/// Closes the file. MUST call Open before calling any other methods.
Status Close();
/// Writes out @a len bytes of @a buf.
/// @return 0 on success.

View File

@ -21,13 +21,13 @@ MultiSegmentSegmenter::MultiSegmentSegmenter(const MuxerOptions& options)
MultiSegmentSegmenter::~MultiSegmentSegmenter() {}
bool MultiSegmentSegmenter::GetInitRangeStartAndEnd(uint32_t* start,
uint32_t* end) {
bool MultiSegmentSegmenter::GetInitRangeStartAndEnd(uint64_t* start,
uint64_t* end) {
return false;
}
bool MultiSegmentSegmenter::GetIndexRangeStartAndEnd(uint32_t* start,
uint32_t* end) {
bool MultiSegmentSegmenter::GetIndexRangeStartAndEnd(uint64_t* start,
uint64_t* end) {
return false;
}
@ -37,7 +37,9 @@ Status MultiSegmentSegmenter::DoInitialize(scoped_ptr<MkvWriter> writer) {
}
Status MultiSegmentSegmenter::DoFinalize() {
return FinalizeSegment();
Status status = FinalizeSegment();
status.Update(writer_->Close());
return status;
}
Status MultiSegmentSegmenter::FinalizeSegment() {

View File

@ -29,8 +29,8 @@ class MultiSegmentSegmenter : public Segmenter {
/// @name Segmenter implementation overrides.
/// @{
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) override;
bool GetIndexRangeStartAndEnd(uint32_t* start, uint32_t* end) override;
bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
/// @}
protected:

View File

@ -69,11 +69,11 @@ class Segmenter {
/// @return true if there is an initialization range, while setting @a start
/// and @a end; or false if initialization range does not apply.
virtual bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) = 0;
virtual bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) = 0;
/// @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.
virtual bool GetIndexRangeStartAndEnd(uint32_t* start, uint32_t* end) = 0;
virtual bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) = 0;
/// @return The total length, in seconds, of segmented media files.
float GetDuration() const;

View File

@ -36,11 +36,12 @@ Status SingleSegmentSegmenter::DoFinalize() {
if (!cues()->Write(writer_.get()))
return Status(error::FILE_FAILURE, "Error writing Cues data.");
uint64_t file_size = writer_->Position();
// The WebM index is at the end of the file.
index_end_ = writer_->Position() - 1;
writer_->Position(0);
Status status = WriteSegmentHeader(file_size, writer_.get());
writer_->Position(file_size);
Status status = WriteSegmentHeader(index_end_ + 1, writer_.get());
status.Update(writer_->Close());
return status;
}
@ -66,8 +67,8 @@ Status SingleSegmentSegmenter::NewSegment(uint64_t start_timescale) {
return SetCluster(start_webm_timecode, position, writer_.get());
}
bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint32_t* start,
uint32_t* end) {
bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint64_t* start,
uint64_t* end) {
// The init range is the header, from the start of the file to the size of
// the header.
*start = 0;
@ -75,12 +76,12 @@ bool SingleSegmentSegmenter::GetInitRangeStartAndEnd(uint32_t* start,
return true;
}
bool SingleSegmentSegmenter::GetIndexRangeStartAndEnd(uint32_t* start,
uint32_t* end) {
bool SingleSegmentSegmenter::GetIndexRangeStartAndEnd(uint64_t* start,
uint64_t* end) {
// The index is the Cues element, which is always placed at the end of the
// file.
*start = index_start_;
*end = writer_->file()->Size() - 1;
*end = index_end_;
return true;
}

View File

@ -30,14 +30,15 @@ class SingleSegmentSegmenter : public Segmenter {
/// @name Segmenter implementation overrides.
/// @{
bool GetInitRangeStartAndEnd(uint32_t* start, uint32_t* end) override;
bool GetIndexRangeStartAndEnd(uint32_t* start, uint32_t* end) override;
bool GetInitRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
bool GetIndexRangeStartAndEnd(uint64_t* start, uint64_t* end) override;
/// @}
protected:
MkvWriter* writer() { return writer_.get(); }
void set_init_end(uint64_t end) { init_end_ = end; }
void set_index_start(uint64_t start) { index_start_ = start; }
void set_index_end(uint64_t end) { index_end_ = end; }
void set_writer(scoped_ptr<MkvWriter> writer) { writer_ = writer.Pass(); }
// Segmenter implementation overrides.
@ -50,8 +51,9 @@ class SingleSegmentSegmenter : public Segmenter {
Status NewSegment(uint64_t start_timescale) override;
scoped_ptr<MkvWriter> writer_;
uint32_t init_end_;
uint32_t index_start_;
uint64_t init_end_;
uint64_t index_start_;
uint64_t index_end_;
DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter);
};

View File

@ -127,9 +127,9 @@ Status TwoPassSingleSegmentSegmenter::DoFinalize() {
LOG(WARNING) << "Unable to delete temporary file " << temp_file_name_;
}
// Set the writer back to the real file so GetIndexRangeStartAndEnd works.
set_writer(real_writer_.Pass());
return Status::OK;
// The WebM index is at the end of the file.
set_index_end(real_writer_->file()->Size() - 1);
return real_writer_->Close();
}
bool TwoPassSingleSegmentSegmenter::CopyFileWithClusterRewrite(

View File

@ -97,13 +97,13 @@ void WebMMuxer::FireOnMediaEndEvent() {
if (!muxer_listener())
return;
uint32_t init_range_start = 0;
uint32_t init_range_end = 0;
uint64_t init_range_start = 0;
uint64_t init_range_end = 0;
const bool has_init_range =
segmenter_->GetInitRangeStartAndEnd(&init_range_start, &init_range_end);
uint32_t index_range_start = 0;
uint32_t index_range_end = 0;
uint64_t index_range_start = 0;
uint64_t index_range_end = 0;
const bool has_index_range = segmenter_->GetIndexRangeStartAndEnd(
&index_range_start, &index_range_end);