diff --git a/app/packager_main.cc b/app/packager_main.cc index 056ce61a72..b227febaa7 100644 --- a/app/packager_main.cc +++ b/app/packager_main.cc @@ -172,11 +172,7 @@ bool AddStreamToMuxer(const std::vector& streams, Muxer* muxer) { LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input."; return false; } - Status status = muxer->AddStream(stream); - if (!status.ok()) { - LOG(ERROR) << "Muxer failed to add stream: " << status.ToString(); - return false; - } + muxer->AddStream(stream); return true; } @@ -234,23 +230,12 @@ bool RunPackager(const std::string& input) { } muxer->SetEncryptorSource(encryptor_source.get(), FLAGS_clear_lead); - status = muxer->Initialize(); - if (!status.ok()) { - LOG(ERROR) << "Muxer failed to initialize: " << status.ToString(); - return false; - } - // Start remuxing process. status = demuxer.Run(); if (!status.ok()) { LOG(ERROR) << "Remuxing failed: " << status.ToString(); return false; } - status = muxer->Finalize(); - if (!status.ok()) { - LOG(ERROR) << "Muxer failed to finalize: " << status.ToString(); - return false; - } printf("Packaging completed successfully.\n"); return true; diff --git a/media/base/demuxer.cc b/media/base/demuxer.cc index ed19cf2e79..936bfac332 100644 --- a/media/base/demuxer.cc +++ b/media/base/demuxer.cc @@ -11,6 +11,7 @@ #include "base/stl_util.h" #include "media/base/container_names.h" #include "media/base/decryptor_source.h" +#include "media/base/media_sample.h" #include "media/base/media_stream.h" #include "media/base/stream_info.h" #include "media/file/file.h" @@ -37,13 +38,13 @@ Demuxer::~Demuxer() { } Status Demuxer::Initialize() { - DCHECK(media_file_ == NULL); + DCHECK(!media_file_); DCHECK(!init_event_received_); media_file_ = File::Open(file_name_.c_str(), "r"); - if (media_file_ == NULL) { + if (!media_file_) { return Status(error::FILE_FAILURE, - "Cannot open file for read " + file_name_); + "Cannot open file for reading " + file_name_); } // Determine media container. @@ -119,13 +120,25 @@ Status Demuxer::Run() { while ((status = Parse()).ok()) continue; - return status.Matches(Status(error::END_OF_STREAM, "")) ? Status::OK : status; + + if (status.error_code() == error::END_OF_STREAM) { + // Push EOS sample to muxer to indicate end of stream. + const scoped_refptr& sample = MediaSample::CreateEOSBuffer(); + for (std::vector::iterator it = streams_.begin(); + it != streams_.end(); + ++it) { + status = (*it)->PushSample(sample); + if (!status.ok()) + return status; + } + } + return status; } Status Demuxer::Parse() { - DCHECK(media_file_ != NULL); - DCHECK(parser_ != NULL); - DCHECK(buffer_ != NULL); + DCHECK(media_file_); + DCHECK(parser_); + DCHECK(buffer_); int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize); if (bytes_read <= 0) { diff --git a/media/base/muxer.cc b/media/base/muxer.cc index 62b2871a7f..d7cc3aa4f8 100644 --- a/media/base/muxer.cc +++ b/media/base/muxer.cc @@ -15,6 +15,7 @@ namespace media { Muxer::Muxer(const MuxerOptions& options) : options_(options), encryptor_source_(NULL), + initialized_(false), clear_lead_in_seconds_(0), muxer_listener_(NULL), clock_(NULL) {} @@ -27,10 +28,10 @@ void Muxer::SetEncryptorSource(EncryptorSource* encryptor_source, clear_lead_in_seconds_ = clear_lead_in_seconds; } -Status Muxer::AddStream(MediaStream* stream) { +void Muxer::AddStream(MediaStream* stream) { + DCHECK(stream); stream->Connect(this); streams_.push_back(stream); - return Status::OK; } Status Muxer::Run() { @@ -55,16 +56,36 @@ Status Muxer::Run() { status = AddSample(streams_[current_stream_id], sample); // Switch to next stream if the current stream is ready for fragmentation. - if (status.Matches(Status(error::FRAGMENT_FINALIZED, ""))) { + if (status.error_code() == error::FRAGMENT_FINALIZED) { current_stream_id = (current_stream_id + 1) % streams_.size(); status.Clear(); } } - return status.Matches(Status(error::END_OF_STREAM, "")) ? Status::OK : status; + // Finalize the muxer after reaching end of stream. + return status.error_code() == error::END_OF_STREAM ? Finalize() : status; } void Muxer::SetMuxerListener(media::event::MuxerListener* muxer_listener) { muxer_listener_ = muxer_listener; } +Status Muxer::AddSample(const MediaStream* stream, + scoped_refptr sample) { + DCHECK(std::find(streams_.begin(), streams_.end(), stream) != streams_.end()); + + if (!initialized_) { + Status status = Initialize(); + if (!status.ok()) + return status; + initialized_ = true; + } + if (sample->end_of_stream()) { + // EOS sample should be sent only when the sample was pushed from Demuxer + // to Muxer. In this case, there should be only one stream in Muxer. + DCHECK_EQ(1u, streams_.size()); + return Finalize(); + } + return DoAddSample(stream, sample); +} + } // namespace media diff --git a/media/base/muxer.h b/media/base/muxer.h index 88bc9f60a7..3d52bb80ad 100644 --- a/media/base/muxer.h +++ b/media/base/muxer.h @@ -38,26 +38,18 @@ class Muxer { explicit Muxer(const MuxerOptions& options); virtual ~Muxer(); - /// Set encryptor source. Should be called before calling Initialize(). - /// @param encryptor_source should not be NULL. + /// Set encryptor source. + /// @param encryptor_source points to the encryptor source to be injected. + /// Should not be NULL. + /// @param clear_lead_in_seconds specifies clear lead duration in seconds. void SetEncryptorSource(EncryptorSource* encryptor_source, double clear_lead_in_seconds); - /// Initialize the muxer. Must be called after connecting all the streams. - virtual Status Initialize() = 0; - - /// Final clean up. - virtual Status Finalize() = 0; - /// Add video/audio stream. - virtual Status AddStream(MediaStream* stream); - - /// Add new media sample. - virtual Status AddSample(const MediaStream* stream, - scoped_refptr sample) = 0; + void AddStream(MediaStream* stream); /// Drive the remuxing from muxer side (pull). - virtual Status Run(); + Status Run(); /// Set a MuxerListener event handler for this object. /// @param muxer_listener should not be NULL. @@ -83,9 +75,26 @@ class Muxer { base::Clock* clock() { return clock_; } private: + friend class MediaStream; // Needed to access AddSample. + + // Add new media sample. + Status AddSample(const MediaStream* stream, + scoped_refptr sample); + + // Initialize the muxer. + virtual Status Initialize() = 0; + + // Final clean up. + virtual Status Finalize() = 0; + + // AddSample implementation. + virtual Status DoAddSample(const MediaStream* stream, + scoped_refptr sample) = 0; + MuxerOptions options_; std::vector streams_; EncryptorSource* encryptor_source_; + bool initialized_; double clear_lead_in_seconds_; event::MuxerListener* muxer_listener_; diff --git a/media/mp4/mp4_muxer.cc b/media/mp4/mp4_muxer.cc index f02bc930ae..c336b6369c 100644 --- a/media/mp4/mp4_muxer.cc +++ b/media/mp4/mp4_muxer.cc @@ -127,8 +127,8 @@ Status MP4Muxer::Finalize() { return Status::OK; } -Status MP4Muxer::AddSample(const MediaStream* stream, - scoped_refptr sample) { +Status MP4Muxer::DoAddSample(const MediaStream* stream, + scoped_refptr sample) { DCHECK(segmenter_); return segmenter_->AddSample(stream, sample); } diff --git a/media/mp4/mp4_muxer.h b/media/mp4/mp4_muxer.h index b7db99ff66..10da781dd1 100644 --- a/media/mp4/mp4_muxer.h +++ b/media/mp4/mp4_muxer.h @@ -34,15 +34,13 @@ class MP4Muxer : public Muxer { explicit MP4Muxer(const MuxerOptions& options); virtual ~MP4Muxer(); - /// @name Muxer implementation overrides. - /// @{ + private: + // Muxer implementation overrides. virtual Status Initialize() OVERRIDE; virtual Status Finalize() OVERRIDE; - virtual Status AddSample(const MediaStream* stream, - scoped_refptr sample) OVERRIDE; - /// @} + virtual Status DoAddSample(const MediaStream* stream, + scoped_refptr sample) OVERRIDE; - private: // Generate Audio/Video Track atom. void InitializeTrak(const StreamInfo* info, Track* trak); void GenerateAudioTrak(const AudioStreamInfo* audio_info, diff --git a/media/test/packager_test.cc b/media/test/packager_test.cc index 958db235be..6c34ce8da8 100644 --- a/media/test/packager_test.cc +++ b/media/test/packager_test.cc @@ -157,12 +157,10 @@ void PackagerTestBasic::Remux(const std::string& input, new mp4::MP4Muxer(SetupOptions(video_output, single_segment))); muxer_video->set_clock(&fake_clock_); - ASSERT_OK(muxer_video->AddStream(FindFirstVideoStream(demuxer.streams()))); + muxer_video->AddStream(FindFirstVideoStream(demuxer.streams())); if (enable_encryption) muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); - - ASSERT_OK(muxer_video->Initialize()); } scoped_ptr muxer_audio; @@ -171,21 +169,14 @@ void PackagerTestBasic::Remux(const std::string& input, new mp4::MP4Muxer(SetupOptions(audio_output, single_segment))); muxer_audio->set_clock(&fake_clock_); - ASSERT_OK(muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams()))); + muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams())); if (enable_encryption) muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); - - ASSERT_OK(muxer_audio->Initialize()); } // Start remuxing process. ASSERT_OK(demuxer.Run()); - - if (muxer_video) - ASSERT_OK(muxer_video->Finalize()); - if (muxer_audio) - ASSERT_OK(muxer_audio->Finalize()); } TEST_P(PackagerTestBasic, MP4MuxerSingleSegmentUnencrypted) {