From 2ef100e87d9cf3de728f4802e4a8bc0e6bab472a Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Fri, 15 Apr 2016 16:00:27 -0700 Subject: [PATCH] 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 --- packager/media/formats/webm/mkv_writer.cc | 8 ++++++++ packager/media/formats/webm/mkv_writer.h | 2 ++ .../formats/webm/multi_segment_segmenter.cc | 12 +++++++----- .../formats/webm/multi_segment_segmenter.h | 4 ++-- packager/media/formats/webm/segmenter.h | 4 ++-- .../formats/webm/single_segment_segmenter.cc | 17 +++++++++-------- .../formats/webm/single_segment_segmenter.h | 10 ++++++---- .../webm/two_pass_single_segment_segmenter.cc | 6 +++--- packager/media/formats/webm/webm_muxer.cc | 8 ++++---- 9 files changed, 43 insertions(+), 28 deletions(-) diff --git a/packager/media/formats/webm/mkv_writer.cc b/packager/media/formats/webm/mkv_writer.cc index 634c4d5800..0918388096 100644 --- a/packager/media/formats/webm/mkv_writer.cc +++ b/packager/media/formats/webm/mkv_writer.cc @@ -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_); diff --git a/packager/media/formats/webm/mkv_writer.h b/packager/media/formats/webm/mkv_writer.h index 8705a3cc59..9371cfb348 100644 --- a/packager/media/formats/webm/mkv_writer.h +++ b/packager/media/formats/webm/mkv_writer.h @@ -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. diff --git a/packager/media/formats/webm/multi_segment_segmenter.cc b/packager/media/formats/webm/multi_segment_segmenter.cc index 3d6dbba8c9..a31a295efe 100644 --- a/packager/media/formats/webm/multi_segment_segmenter.cc +++ b/packager/media/formats/webm/multi_segment_segmenter.cc @@ -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 writer) { } Status MultiSegmentSegmenter::DoFinalize() { - return FinalizeSegment(); + Status status = FinalizeSegment(); + status.Update(writer_->Close()); + return status; } Status MultiSegmentSegmenter::FinalizeSegment() { diff --git a/packager/media/formats/webm/multi_segment_segmenter.h b/packager/media/formats/webm/multi_segment_segmenter.h index 74015630ab..147c408775 100644 --- a/packager/media/formats/webm/multi_segment_segmenter.h +++ b/packager/media/formats/webm/multi_segment_segmenter.h @@ -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: diff --git a/packager/media/formats/webm/segmenter.h b/packager/media/formats/webm/segmenter.h index 987e4b900b..148a5fc1bc 100644 --- a/packager/media/formats/webm/segmenter.h +++ b/packager/media/formats/webm/segmenter.h @@ -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; diff --git a/packager/media/formats/webm/single_segment_segmenter.cc b/packager/media/formats/webm/single_segment_segmenter.cc index 71eab2e3d0..65b4b42d04 100644 --- a/packager/media/formats/webm/single_segment_segmenter.cc +++ b/packager/media/formats/webm/single_segment_segmenter.cc @@ -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; } diff --git a/packager/media/formats/webm/single_segment_segmenter.h b/packager/media/formats/webm/single_segment_segmenter.h index a53e85b2b9..1b8a9e215d 100644 --- a/packager/media/formats/webm/single_segment_segmenter.h +++ b/packager/media/formats/webm/single_segment_segmenter.h @@ -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 writer) { writer_ = writer.Pass(); } // Segmenter implementation overrides. @@ -50,8 +51,9 @@ class SingleSegmentSegmenter : public Segmenter { Status NewSegment(uint64_t start_timescale) override; scoped_ptr 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); }; diff --git a/packager/media/formats/webm/two_pass_single_segment_segmenter.cc b/packager/media/formats/webm/two_pass_single_segment_segmenter.cc index 4f2541d4c7..9f589adf5f 100644 --- a/packager/media/formats/webm/two_pass_single_segment_segmenter.cc +++ b/packager/media/formats/webm/two_pass_single_segment_segmenter.cc @@ -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( diff --git a/packager/media/formats/webm/webm_muxer.cc b/packager/media/formats/webm/webm_muxer.cc index af342f6ddd..5b31c74b7c 100644 --- a/packager/media/formats/webm/webm_muxer.cc +++ b/packager/media/formats/webm/webm_muxer.cc @@ -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);