Create HLS Text Pipeline

Linked together all the handlers to create the HLS text pipeline.
This change does not include tests for the pipeline.

Bug: 36138902
Change-Id: I32e7a7cefae1e7c74ec6d0bdc6335c0d65e5e79c
This commit is contained in:
Aaron Vaage 2017-09-14 09:15:24 -07:00
parent 4ecb567daf
commit 509963d60f
1 changed files with 104 additions and 15 deletions

View File

@ -39,6 +39,10 @@
#include "packager/media/formats/mp2t/ts_muxer.h"
#include "packager/media/formats/mp4/mp4_muxer.h"
#include "packager/media/formats/webm/webm_muxer.h"
#include "packager/media/formats/webvtt/text_readers.h"
#include "packager/media/formats/webvtt/webvtt_output_handler.h"
#include "packager/media/formats/webvtt/webvtt_parser.h"
#include "packager/media/formats/webvtt/webvtt_segmenter.h"
#include "packager/media/replicator/replicator.h"
#include "packager/media/trick_play/trick_play_handler.h"
#include "packager/mpd/base/media_info.pb.h"
@ -58,6 +62,19 @@ namespace {
const char kMediaInfoSuffix[] = ".media_info";
MuxerOptions CreateMuxerOptions(const StreamDescriptor& stream,
const PackagingParams& params) {
MuxerOptions options;
options.mp4_params = params.mp4_output_params;
options.temp_dir = params.temp_dir;
options.bandwidth = stream.bandwidth;
options.output_file_name = stream.output;
options.segment_template = stream.segment_template;
return options;
}
// TODO(rkuroiwa): Write TTML and WebVTT parser (demuxing) for a better check
// and for supporting live/segmenting (muxing). With a demuxer and a muxer,
// CreateAllJobs() shouldn't treat text as a special case.
@ -343,6 +360,28 @@ bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
return true;
}
std::unique_ptr<MuxerListener> CreateHlsListener(const StreamDescriptor& stream,
int stream_number,
hls::HlsNotifier* notifier) {
DCHECK(notifier);
DCHECK_GE(stream_number, 0);
// TODO(rkuroiwa): Do some smart stuff to group the audios, e.g. detect
// languages.
std::string group_id = stream.hls_group_id;
std::string name = stream.hls_name;
std::string hls_playlist_name = stream.hls_playlist_name;
if (group_id.empty())
group_id = "audio";
if (name.empty())
name = base::StringPrintf("stream_%d", stream_number);
if (hls_playlist_name.empty())
hls_playlist_name = base::StringPrintf("stream_%d.m3u8", stream_number);
return std::unique_ptr<MuxerListener>(
new HlsNotifyMuxerListener(hls_playlist_name, name, group_id, notifier));
}
std::unique_ptr<MuxerListener> CreateMuxerListener(
const StreamDescriptor& stream,
int stream_number,
@ -365,21 +404,8 @@ std::unique_ptr<MuxerListener> CreateMuxerListener(
}
if (hls_notifier) {
// TODO(rkuroiwa): Do some smart stuff to group the audios, e.g. detect
// languages.
std::string group_id = stream.hls_group_id;
std::string name = stream.hls_name;
std::string hls_playlist_name = stream.hls_playlist_name;
if (group_id.empty())
group_id = "audio";
if (name.empty())
name = base::StringPrintf("stream_%d", stream_number);
if (hls_playlist_name.empty())
hls_playlist_name = base::StringPrintf("stream_%d.m3u8", stream_number);
std::unique_ptr<MuxerListener> listener(new HlsNotifyMuxerListener(
hls_playlist_name, name, group_id, hls_notifier));
combined_listener->AddListener(std::move(listener));
combined_listener->AddListener(
CreateHlsListener(stream, stream_number, hls_notifier));
}
return std::move(combined_listener);
@ -479,6 +505,60 @@ Status CreateMp4ToMp4TextJob(int stream_number,
return status;
}
Status CreateHlsTextJob(const StreamDescriptor& stream,
int stream_number,
const PackagingParams& packaging_params,
hls::HlsNotifier* notifier,
JobManager* job_manager) {
DCHECK(notifier);
DCHECK_GE(stream_number, 0);
if (stream.segment_template.empty()) {
return Status(error::INVALID_ARGUMENT,
"Cannot output text (" + stream.input +
") to HLS with no segment template");
}
const float segment_length_in_seconds =
packaging_params.chunking_params.segment_duration_in_seconds;
const uint64_t segment_length_in_ms =
static_cast<uint64_t>(segment_length_in_seconds * 1000);
// Text files are usually small and since the input is one file;
// there's no way for the player to do ranged requests. So set this
// value to something reasonable if it is missing.
MuxerOptions muxer_options = CreateMuxerOptions(stream, packaging_params);
muxer_options.bandwidth = stream.bandwidth ? stream.bandwidth : 256;
std::unique_ptr<MuxerListener> muxer_listener =
CreateHlsListener(stream, stream_number, notifier);
std::shared_ptr<WebVttSegmentedOutputHandler> output(
new WebVttSegmentedOutputHandler(muxer_options,
std::move(muxer_listener)));
std::unique_ptr<FileReader> reader;
Status open_status = FileReader::Open(stream.input, &reader);
if (!open_status.ok()) {
return open_status;
}
std::shared_ptr<OriginHandler> parser(new WebVttParser(std::move(reader)));
std::shared_ptr<MediaHandler> segmenter(
new WebVttSegmenter(segment_length_in_ms));
// Build in reverse to allow us to move the pointers.
Status status;
status.Update(segmenter->AddHandler(std::move(output)));
status.Update(parser->AddHandler(std::move(segmenter)));
if (!status.ok()) {
return status;
}
job_manager->Add("Segmented Text Job", std::move(parser));
return Status::OK;
}
Status CreateTextJobs(
const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
const PackagingParams& packaging_params,
@ -520,6 +600,15 @@ Status CreateTextJobs(
}
}
if (hls_notifier) {
Status status =
CreateHlsTextJob(stream, (*stream_number)++, packaging_params,
hls_notifier, job_manager);
if (!status.ok()) {
return status;
}
}
if (packaging_params.output_media_info) {
VodMediaInfoDumpMuxerListener::WriteMediaInfoToFile(
text_media_info, stream.output + kMediaInfoSuffix);