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; 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) { mkvmuxer::int32 MkvWriter::Write(const void* buf, mkvmuxer::uint32 len) {
DCHECK(file_); DCHECK(file_);

View File

@ -28,6 +28,8 @@ class MkvWriter : public mkvmuxer::IMkvWriter {
/// @param name The path to the file to open. /// @param name The path to the file to open.
/// @return Whether the operation succeeded. /// @return Whether the operation succeeded.
Status Open(const std::string& name); 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. /// Writes out @a len bytes of @a buf.
/// @return 0 on success. /// @return 0 on success.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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