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:
parent
4ecb567daf
commit
509963d60f
|
@ -39,6 +39,10 @@
|
||||||
#include "packager/media/formats/mp2t/ts_muxer.h"
|
#include "packager/media/formats/mp2t/ts_muxer.h"
|
||||||
#include "packager/media/formats/mp4/mp4_muxer.h"
|
#include "packager/media/formats/mp4/mp4_muxer.h"
|
||||||
#include "packager/media/formats/webm/webm_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/replicator/replicator.h"
|
||||||
#include "packager/media/trick_play/trick_play_handler.h"
|
#include "packager/media/trick_play/trick_play_handler.h"
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
|
@ -58,6 +62,19 @@ namespace {
|
||||||
|
|
||||||
const char kMediaInfoSuffix[] = ".media_info";
|
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
|
// TODO(rkuroiwa): Write TTML and WebVTT parser (demuxing) for a better check
|
||||||
// and for supporting live/segmenting (muxing). With a demuxer and a muxer,
|
// and for supporting live/segmenting (muxing). With a demuxer and a muxer,
|
||||||
// CreateAllJobs() shouldn't treat text as a special case.
|
// CreateAllJobs() shouldn't treat text as a special case.
|
||||||
|
@ -343,6 +360,28 @@ bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
|
||||||
return true;
|
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(
|
std::unique_ptr<MuxerListener> CreateMuxerListener(
|
||||||
const StreamDescriptor& stream,
|
const StreamDescriptor& stream,
|
||||||
int stream_number,
|
int stream_number,
|
||||||
|
@ -365,21 +404,8 @@ std::unique_ptr<MuxerListener> CreateMuxerListener(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hls_notifier) {
|
if (hls_notifier) {
|
||||||
// TODO(rkuroiwa): Do some smart stuff to group the audios, e.g. detect
|
combined_listener->AddListener(
|
||||||
// languages.
|
CreateHlsListener(stream, stream_number, hls_notifier));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::move(combined_listener);
|
return std::move(combined_listener);
|
||||||
|
@ -479,6 +505,60 @@ Status CreateMp4ToMp4TextJob(int stream_number,
|
||||||
return status;
|
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(
|
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,
|
||||||
|
@ -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) {
|
if (packaging_params.output_media_info) {
|
||||||
VodMediaInfoDumpMuxerListener::WriteMediaInfoToFile(
|
VodMediaInfoDumpMuxerListener::WriteMediaInfoToFile(
|
||||||
text_media_info, stream.output + kMediaInfoSuffix);
|
text_media_info, stream.output + kMediaInfoSuffix);
|
||||||
|
|
Loading…
Reference in New Issue