Support MP4 to Mp4 Text
This change adds the missing code for passing mp4 text through the pipeline. This introduces the MuxerFactory to simplify creating muxers. Change-Id: Ic7be1a2e0ff4b720a01061edb43aded946d05a47
This commit is contained in:
parent
5f48cbb0c1
commit
37b5f401d1
|
@ -102,6 +102,73 @@ MediaContainerName GetOutputFormat(const StreamDescriptor& descriptor) {
|
||||||
return output_format;
|
return output_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To make it easier to create muxers, this factory allows for all
|
||||||
|
// configuration to be set at the factory level so that when a function
|
||||||
|
// needs a muxer, it can easily create one with local information.
|
||||||
|
class MuxerFactory {
|
||||||
|
public:
|
||||||
|
MuxerFactory(const PackagingParams& packaging_params)
|
||||||
|
: packaging_params_(packaging_params) {}
|
||||||
|
|
||||||
|
// For testing, if you need to replace the clock that muxers work with
|
||||||
|
// this will replace the clock for all muxers created after this call.
|
||||||
|
void OverrideClock(base::Clock* clock) { clock_ = clock; }
|
||||||
|
|
||||||
|
// Create a new muxer using the factory's settings for the given
|
||||||
|
// stream. |listener| is optional.
|
||||||
|
std::shared_ptr<Muxer> CreateMuxer(const StreamDescriptor& stream,
|
||||||
|
std::unique_ptr<MuxerListener> listener) {
|
||||||
|
const MediaContainerName format = GetOutputFormat(stream);
|
||||||
|
|
||||||
|
MuxerOptions options;
|
||||||
|
options.mp4_params = packaging_params_.mp4_output_params;
|
||||||
|
options.temp_dir = packaging_params_.temp_dir;
|
||||||
|
options.bandwidth = stream.bandwidth;
|
||||||
|
options.output_file_name = stream.output;
|
||||||
|
options.segment_template = stream.segment_template;
|
||||||
|
|
||||||
|
std::shared_ptr<Muxer> muxer;
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case CONTAINER_WEBM:
|
||||||
|
muxer = std::make_shared<webm::WebMMuxer>(options);
|
||||||
|
break;
|
||||||
|
case CONTAINER_MPEG2TS:
|
||||||
|
muxer = std::make_shared<mp2t::TsMuxer>(options);
|
||||||
|
break;
|
||||||
|
case CONTAINER_MOV:
|
||||||
|
muxer = std::make_shared<mp4::MP4Muxer>(options);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG(ERROR) << "Cannot support muxing to " << format;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!muxer) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We successfully created a muxer, then there is a couple settings
|
||||||
|
// we should set before returning it.
|
||||||
|
if (clock_) {
|
||||||
|
muxer->set_clock(clock_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listener) {
|
||||||
|
muxer->SetMuxerListener(std::move(listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
return muxer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MuxerFactory(const MuxerFactory&) = delete;
|
||||||
|
MuxerFactory& operator=(const MuxerFactory&) = delete;
|
||||||
|
|
||||||
|
PackagingParams packaging_params_;
|
||||||
|
base::Clock* clock_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
Status ValidateStreamDescriptor(bool dump_stream_info,
|
Status ValidateStreamDescriptor(bool dump_stream_info,
|
||||||
const StreamDescriptor& stream) {
|
const StreamDescriptor& stream) {
|
||||||
if (stream.input.empty()) {
|
if (stream.input.empty()) {
|
||||||
|
@ -318,51 +385,28 @@ std::unique_ptr<MuxerListener> CreateMuxerListener(
|
||||||
return std::move(combined_listener);
|
return std::move(combined_listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Muxer> CreateMuxer(const PackagingParams& packaging_params,
|
/// Create a new demuxer handler for the given stream. If a demuxer cannot be
|
||||||
const StreamDescriptor& stream,
|
/// created, an error will be returned. If a demuxer can be created, this
|
||||||
base::Clock* clock,
|
/// |new_demuxer| will be set and Status::OK will be returned.
|
||||||
std::unique_ptr<MuxerListener> listener) {
|
Status CreateDemuxer(const StreamDescriptor& stream,
|
||||||
const MediaContainerName format = GetOutputFormat(stream);
|
const PackagingParams& packaging_params,
|
||||||
|
std::shared_ptr<Demuxer>* new_demuxer) {
|
||||||
|
std::shared_ptr<Demuxer> demuxer = std::make_shared<Demuxer>(stream.input);
|
||||||
|
demuxer->set_dump_stream_info(packaging_params.test_params.dump_stream_info);
|
||||||
|
|
||||||
MuxerOptions options;
|
if (packaging_params.decryption_params.key_provider != KeyProvider::kNone) {
|
||||||
options.mp4_params = packaging_params.mp4_output_params;
|
std::unique_ptr<KeySource> decryption_key_source(
|
||||||
options.temp_dir = packaging_params.temp_dir;
|
CreateDecryptionKeySource(packaging_params.decryption_params));
|
||||||
options.bandwidth = stream.bandwidth;
|
if (!decryption_key_source) {
|
||||||
options.output_file_name = stream.output;
|
return Status(
|
||||||
options.segment_template = stream.segment_template;
|
error::INVALID_ARGUMENT,
|
||||||
|
"Must define decryption key source when defining key provider");
|
||||||
std::shared_ptr<Muxer> muxer;
|
}
|
||||||
|
demuxer->SetKeySource(std::move(decryption_key_source));
|
||||||
switch (format) {
|
|
||||||
case CONTAINER_WEBM:
|
|
||||||
muxer = std::make_shared<webm::WebMMuxer>(options);
|
|
||||||
break;
|
|
||||||
case CONTAINER_MPEG2TS:
|
|
||||||
muxer = std::make_shared<mp2t::TsMuxer>(options);
|
|
||||||
break;
|
|
||||||
case CONTAINER_MOV:
|
|
||||||
muxer = std::make_shared<mp4::MP4Muxer>(options);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG(ERROR) << "Cannot support muxing to " << format;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!muxer) {
|
*new_demuxer = std::move(demuxer);
|
||||||
return nullptr;
|
return Status::OK;
|
||||||
}
|
|
||||||
|
|
||||||
// We successfully created a muxer, then there is a couple settings
|
|
||||||
// we should set before returning it.
|
|
||||||
if (clock) {
|
|
||||||
muxer->set_clock(clock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listener) {
|
|
||||||
muxer->SetMuxerListener(std::move(listener));
|
|
||||||
}
|
|
||||||
|
|
||||||
return muxer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MediaHandler> CreateEncryptionHandler(
|
std::shared_ptr<MediaHandler> CreateEncryptionHandler(
|
||||||
|
@ -406,20 +450,59 @@ std::shared_ptr<MediaHandler> CreateEncryptionHandler(
|
||||||
return std::make_shared<EncryptionHandler>(encryption_params, key_source);
|
return std::make_shared<EncryptionHandler>(encryption_params, key_source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Status CreateMp4ToMp4TextJob(int stream_number,
|
||||||
|
const StreamDescriptor& stream,
|
||||||
|
const PackagingParams& packaging_params,
|
||||||
|
MuxerFactory* muxer_factory,
|
||||||
|
MpdNotifier* mpd_notifier,
|
||||||
|
hls::HlsNotifier* hls_notifier,
|
||||||
|
std::shared_ptr<OriginHandler>* root) {
|
||||||
|
Status status;
|
||||||
|
std::shared_ptr<Demuxer> demuxer;
|
||||||
|
|
||||||
|
status.Update(CreateDemuxer(stream, packaging_params, &demuxer));
|
||||||
|
if (!stream.language.empty()) {
|
||||||
|
demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MediaHandler> chunker(
|
||||||
|
new ChunkingHandler(packaging_params.chunking_params));
|
||||||
|
std::unique_ptr<MuxerListener> muxer_listener = CreateMuxerListener(
|
||||||
|
stream, stream_number, packaging_params.output_media_info, mpd_notifier,
|
||||||
|
hls_notifier);
|
||||||
|
std::shared_ptr<Muxer> muxer =
|
||||||
|
muxer_factory->CreateMuxer(stream, std::move(muxer_listener));
|
||||||
|
|
||||||
|
status.Update(chunker->AddHandler(std::move(muxer)));
|
||||||
|
status.Update(demuxer->SetHandler(stream.stream_selector, chunker));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
Status CreateTextJobs(
|
Status CreateTextJobs(
|
||||||
const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
|
const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
|
||||||
const PackagingParams& packaging_params,
|
const PackagingParams& packaging_params,
|
||||||
|
int* stream_number,
|
||||||
|
MuxerFactory* muxer_factory,
|
||||||
MpdNotifier* mpd_notifier,
|
MpdNotifier* mpd_notifier,
|
||||||
|
hls::HlsNotifier* hls_notifier,
|
||||||
JobManager* job_manager) {
|
JobManager* job_manager) {
|
||||||
DCHECK(job_manager);
|
DCHECK(job_manager);
|
||||||
|
|
||||||
for (const StreamDescriptor& stream : streams) {
|
for (const StreamDescriptor& stream : streams) {
|
||||||
const MediaContainerName output_format = GetOutputFormat(stream);
|
const MediaContainerName output_format = GetOutputFormat(stream);
|
||||||
|
|
||||||
|
// TODO(70990714): Support webvtt to mp4
|
||||||
if (output_format == CONTAINER_MOV) {
|
if (output_format == CONTAINER_MOV) {
|
||||||
// TODO(vaage): Complete this part of the text pipeline. This path will
|
std::shared_ptr<OriginHandler> root;
|
||||||
// be similar to the audio/video pipeline but with some components
|
Status status = CreateMp4ToMp4TextJob((*stream_number)++, stream,
|
||||||
// removed (e.g. trick play).
|
packaging_params, muxer_factory,
|
||||||
|
mpd_notifier, hls_notifier, &root);
|
||||||
|
|
||||||
|
if (!status.ok()) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
job_manager->Add("MP4 text job", std::move(root));
|
||||||
} else {
|
} else {
|
||||||
MediaInfo text_media_info;
|
MediaInfo text_media_info;
|
||||||
if (!StreamInfoToTextMediaInfo(stream, &text_media_info)) {
|
if (!StreamInfoToTextMediaInfo(stream, &text_media_info)) {
|
||||||
|
@ -448,11 +531,11 @@ Status CreateTextJobs(
|
||||||
}
|
}
|
||||||
|
|
||||||
Status CreateAudioVideoJobs(
|
Status CreateAudioVideoJobs(
|
||||||
int first_stream_number,
|
|
||||||
const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
|
const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
|
||||||
const PackagingParams& packaging_params,
|
const PackagingParams& packaging_params,
|
||||||
FakeClock* fake_clock,
|
int* stream_number,
|
||||||
KeySource* encryption_key_source,
|
KeySource* encryption_key_source,
|
||||||
|
MuxerFactory* muxer_factory,
|
||||||
MpdNotifier* mpd_notifier,
|
MpdNotifier* mpd_notifier,
|
||||||
hls::HlsNotifier* hls_notifier,
|
hls::HlsNotifier* hls_notifier,
|
||||||
JobManager* job_manager) {
|
JobManager* job_manager) {
|
||||||
|
@ -467,29 +550,12 @@ Status CreateAudioVideoJobs(
|
||||||
std::string previous_input;
|
std::string previous_input;
|
||||||
std::string previous_selector;
|
std::string previous_selector;
|
||||||
|
|
||||||
// -1 so that it will be back at |first_stream_number| on the first
|
|
||||||
// iteration.
|
|
||||||
int stream_number = first_stream_number - 1;
|
|
||||||
|
|
||||||
for (const StreamDescriptor& stream : streams) {
|
for (const StreamDescriptor& stream : streams) {
|
||||||
stream_number += 1;
|
|
||||||
|
|
||||||
// If we changed our input files, we need a new demuxer.
|
// If we changed our input files, we need a new demuxer.
|
||||||
if (previous_input != stream.input) {
|
if (previous_input != stream.input) {
|
||||||
demuxer = std::make_shared<Demuxer>(stream.input);
|
Status status = CreateDemuxer(stream, packaging_params, &demuxer);
|
||||||
|
if (!status.ok()) {
|
||||||
demuxer->set_dump_stream_info(
|
return status;
|
||||||
packaging_params.test_params.dump_stream_info);
|
|
||||||
if (packaging_params.decryption_params.key_provider !=
|
|
||||||
KeyProvider::kNone) {
|
|
||||||
std::unique_ptr<KeySource> decryption_key_source(
|
|
||||||
CreateDecryptionKeySource(packaging_params.decryption_params));
|
|
||||||
if (!decryption_key_source) {
|
|
||||||
return Status(
|
|
||||||
error::INVALID_ARGUMENT,
|
|
||||||
"Must define decryption key source when defining key provider");
|
|
||||||
}
|
|
||||||
demuxer->SetKeySource(std::move(decryption_key_source));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
job_manager->Add("RemuxJob", demuxer);
|
job_manager->Add("RemuxJob", demuxer);
|
||||||
|
@ -551,12 +617,10 @@ Status CreateAudioVideoJobs(
|
||||||
|
|
||||||
// Create the muxer (output) for this track.
|
// Create the muxer (output) for this track.
|
||||||
std::unique_ptr<MuxerListener> muxer_listener = CreateMuxerListener(
|
std::unique_ptr<MuxerListener> muxer_listener = CreateMuxerListener(
|
||||||
stream, stream_number, packaging_params.output_media_info, mpd_notifier,
|
stream, (*stream_number)++, packaging_params.output_media_info,
|
||||||
hls_notifier);
|
mpd_notifier, hls_notifier);
|
||||||
std::shared_ptr<Muxer> muxer = CreateMuxer(
|
std::shared_ptr<Muxer> muxer =
|
||||||
packaging_params, stream,
|
muxer_factory->CreateMuxer(stream, std::move(muxer_listener));
|
||||||
packaging_params.test_params.inject_fake_clock ? fake_clock : nullptr,
|
|
||||||
std::move(muxer_listener));
|
|
||||||
|
|
||||||
if (!muxer) {
|
if (!muxer) {
|
||||||
return Status(error::INVALID_ARGUMENT, "Failed to create muxer for " +
|
return Status(error::INVALID_ARGUMENT, "Failed to create muxer for " +
|
||||||
|
@ -615,17 +679,20 @@ Status CreateAllJobs(const std::vector<StreamDescriptor>& stream_descriptors,
|
||||||
std::sort(audio_video_streams.begin(), audio_video_streams.end(),
|
std::sort(audio_video_streams.begin(), audio_video_streams.end(),
|
||||||
media::StreamDescriptorCompareFn);
|
media::StreamDescriptorCompareFn);
|
||||||
|
|
||||||
|
MuxerFactory muxer_factory(packaging_params);
|
||||||
|
if (packaging_params.test_params.inject_fake_clock) {
|
||||||
|
muxer_factory.OverrideClock(fake_clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int stream_number = 0;
|
||||||
Status status;
|
Status status;
|
||||||
|
status.Update(CreateTextJobs(text_streams, packaging_params, &stream_number,
|
||||||
status.Update(CreateTextJobs(text_streams, packaging_params, mpd_notifier,
|
&muxer_factory, mpd_notifier, hls_notifier,
|
||||||
|
job_manager));
|
||||||
|
status.Update(CreateAudioVideoJobs(audio_video_streams, packaging_params,
|
||||||
|
&stream_number, encryption_key_source,
|
||||||
|
&muxer_factory, mpd_notifier, hls_notifier,
|
||||||
job_manager));
|
job_manager));
|
||||||
|
|
||||||
int stream_number = text_streams.size();
|
|
||||||
|
|
||||||
status.Update(CreateAudioVideoJobs(
|
|
||||||
stream_number, audio_video_streams, packaging_params, fake_clock,
|
|
||||||
encryption_key_source, mpd_notifier, hls_notifier, job_manager));
|
|
||||||
|
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue