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:
parent
2498da675a
commit
833f27f687
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
|
@ -127,8 +127,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue