Make Muxer::Initialize and Muxer::Finalize private

User should not need to care about how and when to call these APIs.
Internal code should call them automatically.

Change-Id: Ibc85a709d4e82ecc7b477986cabf09dcfc2e100c
This commit is contained in:
Kongqun Yang 2014-04-09 10:34:55 -07:00 committed by KongQun Yang
parent 2498da675a
commit 833f27f687
7 changed files with 77 additions and 60 deletions

View File

@ -172,11 +172,7 @@ bool AddStreamToMuxer(const std::vector<MediaStream*>& streams, Muxer* muxer) {
LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input."; LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input.";
return false; return false;
} }
Status status = muxer->AddStream(stream); muxer->AddStream(stream);
if (!status.ok()) {
LOG(ERROR) << "Muxer failed to add stream: " << status.ToString();
return false;
}
return true; return true;
} }
@ -234,23 +230,12 @@ bool RunPackager(const std::string& input) {
} }
muxer->SetEncryptorSource(encryptor_source.get(), FLAGS_clear_lead); 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. // Start remuxing process.
status = demuxer.Run(); status = demuxer.Run();
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Remuxing failed: " << status.ToString(); LOG(ERROR) << "Remuxing failed: " << status.ToString();
return false; return false;
} }
status = muxer->Finalize();
if (!status.ok()) {
LOG(ERROR) << "Muxer failed to finalize: " << status.ToString();
return false;
}
printf("Packaging completed successfully.\n"); printf("Packaging completed successfully.\n");
return true; return true;

View File

@ -11,6 +11,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "media/base/container_names.h" #include "media/base/container_names.h"
#include "media/base/decryptor_source.h" #include "media/base/decryptor_source.h"
#include "media/base/media_sample.h"
#include "media/base/media_stream.h" #include "media/base/media_stream.h"
#include "media/base/stream_info.h" #include "media/base/stream_info.h"
#include "media/file/file.h" #include "media/file/file.h"
@ -37,13 +38,13 @@ Demuxer::~Demuxer() {
} }
Status Demuxer::Initialize() { Status Demuxer::Initialize() {
DCHECK(media_file_ == NULL); DCHECK(!media_file_);
DCHECK(!init_event_received_); DCHECK(!init_event_received_);
media_file_ = File::Open(file_name_.c_str(), "r"); media_file_ = File::Open(file_name_.c_str(), "r");
if (media_file_ == NULL) { if (!media_file_) {
return Status(error::FILE_FAILURE, return Status(error::FILE_FAILURE,
"Cannot open file for read " + file_name_); "Cannot open file for reading " + file_name_);
} }
// Determine media container. // Determine media container.
@ -119,13 +120,25 @@ Status Demuxer::Run() {
while ((status = Parse()).ok()) while ((status = Parse()).ok())
continue; 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<MediaSample>& sample = MediaSample::CreateEOSBuffer();
for (std::vector<MediaStream*>::iterator it = streams_.begin();
it != streams_.end();
++it) {
status = (*it)->PushSample(sample);
if (!status.ok())
return status;
}
}
return status;
} }
Status Demuxer::Parse() { Status Demuxer::Parse() {
DCHECK(media_file_ != NULL); DCHECK(media_file_);
DCHECK(parser_ != NULL); DCHECK(parser_);
DCHECK(buffer_ != NULL); DCHECK(buffer_);
int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize); int64 bytes_read = media_file_->Read(buffer_.get(), kBufSize);
if (bytes_read <= 0) { if (bytes_read <= 0) {

View File

@ -15,6 +15,7 @@ namespace media {
Muxer::Muxer(const MuxerOptions& options) Muxer::Muxer(const MuxerOptions& options)
: options_(options), : options_(options),
encryptor_source_(NULL), encryptor_source_(NULL),
initialized_(false),
clear_lead_in_seconds_(0), clear_lead_in_seconds_(0),
muxer_listener_(NULL), muxer_listener_(NULL),
clock_(NULL) {} clock_(NULL) {}
@ -27,10 +28,10 @@ void Muxer::SetEncryptorSource(EncryptorSource* encryptor_source,
clear_lead_in_seconds_ = clear_lead_in_seconds; clear_lead_in_seconds_ = clear_lead_in_seconds;
} }
Status Muxer::AddStream(MediaStream* stream) { void Muxer::AddStream(MediaStream* stream) {
DCHECK(stream);
stream->Connect(this); stream->Connect(this);
streams_.push_back(stream); streams_.push_back(stream);
return Status::OK;
} }
Status Muxer::Run() { Status Muxer::Run() {
@ -55,16 +56,36 @@ Status Muxer::Run() {
status = AddSample(streams_[current_stream_id], sample); status = AddSample(streams_[current_stream_id], sample);
// Switch to next stream if the current stream is ready for fragmentation. // 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(); current_stream_id = (current_stream_id + 1) % streams_.size();
status.Clear(); 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) { void Muxer::SetMuxerListener(media::event::MuxerListener* muxer_listener) {
muxer_listener_ = muxer_listener; muxer_listener_ = muxer_listener;
} }
Status Muxer::AddSample(const MediaStream* stream,
scoped_refptr<MediaSample> 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 } // namespace media

View File

@ -38,26 +38,18 @@ class Muxer {
explicit Muxer(const MuxerOptions& options); explicit Muxer(const MuxerOptions& options);
virtual ~Muxer(); virtual ~Muxer();
/// Set encryptor source. Should be called before calling Initialize(). /// Set encryptor source.
/// @param encryptor_source should not be NULL. /// @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, void SetEncryptorSource(EncryptorSource* encryptor_source,
double clear_lead_in_seconds); 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. /// Add video/audio stream.
virtual Status AddStream(MediaStream* stream); void AddStream(MediaStream* stream);
/// Add new media sample.
virtual Status AddSample(const MediaStream* stream,
scoped_refptr<MediaSample> sample) = 0;
/// Drive the remuxing from muxer side (pull). /// Drive the remuxing from muxer side (pull).
virtual Status Run(); Status Run();
/// Set a MuxerListener event handler for this object. /// Set a MuxerListener event handler for this object.
/// @param muxer_listener should not be NULL. /// @param muxer_listener should not be NULL.
@ -83,9 +75,26 @@ class Muxer {
base::Clock* clock() { return clock_; } base::Clock* clock() { return clock_; }
private: private:
friend class MediaStream; // Needed to access AddSample.
// Add new media sample.
Status AddSample(const MediaStream* stream,
scoped_refptr<MediaSample> 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<MediaSample> sample) = 0;
MuxerOptions options_; MuxerOptions options_;
std::vector<MediaStream*> streams_; std::vector<MediaStream*> streams_;
EncryptorSource* encryptor_source_; EncryptorSource* encryptor_source_;
bool initialized_;
double clear_lead_in_seconds_; double clear_lead_in_seconds_;
event::MuxerListener* muxer_listener_; event::MuxerListener* muxer_listener_;

View File

@ -127,7 +127,7 @@ Status MP4Muxer::Finalize() {
return Status::OK; return Status::OK;
} }
Status MP4Muxer::AddSample(const MediaStream* stream, Status MP4Muxer::DoAddSample(const MediaStream* stream,
scoped_refptr<MediaSample> sample) { scoped_refptr<MediaSample> sample) {
DCHECK(segmenter_); DCHECK(segmenter_);
return segmenter_->AddSample(stream, sample); return segmenter_->AddSample(stream, sample);

View File

@ -34,15 +34,13 @@ class MP4Muxer : public Muxer {
explicit MP4Muxer(const MuxerOptions& options); explicit MP4Muxer(const MuxerOptions& options);
virtual ~MP4Muxer(); virtual ~MP4Muxer();
/// @name Muxer implementation overrides. private:
/// @{ // Muxer implementation overrides.
virtual Status Initialize() OVERRIDE; virtual Status Initialize() OVERRIDE;
virtual Status Finalize() OVERRIDE; virtual Status Finalize() OVERRIDE;
virtual Status AddSample(const MediaStream* stream, virtual Status DoAddSample(const MediaStream* stream,
scoped_refptr<MediaSample> sample) OVERRIDE; scoped_refptr<MediaSample> sample) OVERRIDE;
/// @}
private:
// Generate Audio/Video Track atom. // Generate Audio/Video Track atom.
void InitializeTrak(const StreamInfo* info, Track* trak); void InitializeTrak(const StreamInfo* info, Track* trak);
void GenerateAudioTrak(const AudioStreamInfo* audio_info, void GenerateAudioTrak(const AudioStreamInfo* audio_info,

View File

@ -157,12 +157,10 @@ void PackagerTestBasic::Remux(const std::string& input,
new mp4::MP4Muxer(SetupOptions(video_output, single_segment))); new mp4::MP4Muxer(SetupOptions(video_output, single_segment)));
muxer_video->set_clock(&fake_clock_); muxer_video->set_clock(&fake_clock_);
ASSERT_OK(muxer_video->AddStream(FindFirstVideoStream(demuxer.streams()))); muxer_video->AddStream(FindFirstVideoStream(demuxer.streams()));
if (enable_encryption) if (enable_encryption)
muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds);
ASSERT_OK(muxer_video->Initialize());
} }
scoped_ptr<Muxer> muxer_audio; scoped_ptr<Muxer> muxer_audio;
@ -171,21 +169,14 @@ void PackagerTestBasic::Remux(const std::string& input,
new mp4::MP4Muxer(SetupOptions(audio_output, single_segment))); new mp4::MP4Muxer(SetupOptions(audio_output, single_segment)));
muxer_audio->set_clock(&fake_clock_); muxer_audio->set_clock(&fake_clock_);
ASSERT_OK(muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams()))); muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams()));
if (enable_encryption) if (enable_encryption)
muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds); muxer_video->SetEncryptorSource(&encryptor_source, kClearLeadInSeconds);
ASSERT_OK(muxer_audio->Initialize());
} }
// Start remuxing process. // Start remuxing process.
ASSERT_OK(demuxer.Run()); ASSERT_OK(demuxer.Run());
if (muxer_video)
ASSERT_OK(muxer_video->Finalize());
if (muxer_audio)
ASSERT_OK(muxer_audio->Finalize());
} }
TEST_P(PackagerTestBasic, MP4MuxerSingleSegmentUnencrypted) { TEST_P(PackagerTestBasic, MP4MuxerSingleSegmentUnencrypted) {