7 #include "packager/packager.h" 11 #include "packager/app/job_manager.h" 12 #include "packager/app/libcrypto_threading.h" 13 #include "packager/app/muxer_factory.h" 14 #include "packager/app/packager_util.h" 15 #include "packager/app/stream_descriptor.h" 16 #include "packager/base/at_exit.h" 17 #include "packager/base/files/file_path.h" 18 #include "packager/base/logging.h" 19 #include "packager/base/optional.h" 20 #include "packager/base/path_service.h" 21 #include "packager/base/strings/string_util.h" 22 #include "packager/base/strings/stringprintf.h" 23 #include "packager/base/threading/simple_thread.h" 24 #include "packager/base/time/clock.h" 25 #include "packager/file/file.h" 26 #include "packager/hls/base/hls_notifier.h" 27 #include "packager/hls/base/simple_hls_notifier.h" 28 #include "packager/media/base/container_names.h" 29 #include "packager/media/base/fourccs.h" 30 #include "packager/media/base/key_source.h" 31 #include "packager/media/base/language_utils.h" 32 #include "packager/media/base/muxer.h" 33 #include "packager/media/base/muxer_options.h" 34 #include "packager/media/base/muxer_util.h" 35 #include "packager/media/chunking/chunking_handler.h" 36 #include "packager/media/chunking/cue_alignment_handler.h" 37 #include "packager/media/chunking/text_chunker.h" 38 #include "packager/media/crypto/encryption_handler.h" 39 #include "packager/media/demuxer/demuxer.h" 40 #include "packager/media/event/muxer_listener_factory.h" 41 #include "packager/media/event/vod_media_info_dump_muxer_listener.h" 42 #include "packager/media/formats/webvtt/text_padder.h" 43 #include "packager/media/formats/webvtt/text_readers.h" 44 #include "packager/media/formats/webvtt/webvtt_parser.h" 45 #include "packager/media/formats/webvtt/webvtt_text_output_handler.h" 46 #include "packager/media/formats/webvtt/webvtt_to_mp4_handler.h" 47 #include "packager/media/replicator/replicator.h" 48 #include "packager/media/trick_play/trick_play_handler.h" 49 #include "packager/mpd/base/media_info.pb.h" 50 #include "packager/mpd/base/mpd_builder.h" 51 #include "packager/mpd/base/simple_mpd_notifier.h" 52 #include "packager/status_macros.h" 53 #include "packager/version/version.h" 59 using media::JobManager;
60 using media::KeySource;
61 using media::MuxerOptions;
62 using media::SyncPointQueue;
67 const char kMediaInfoSuffix[] =
".media_info";
69 MuxerOptions CreateMuxerOptions(
const StreamDescriptor& stream,
70 const PackagingParams& params) {
73 options.mp4_params = params.mp4_output_params;
74 options.temp_dir = params.temp_dir;
75 options.bandwidth = stream.bandwidth;
76 options.output_file_name = stream.output;
77 options.segment_template = stream.segment_template;
82 MuxerListenerFactory::StreamData ToMuxerListenerData(
83 const StreamDescriptor& stream) {
84 MuxerListenerFactory::StreamData data;
85 data.media_info_output = stream.output;
86 data.hls_group_id = stream.hls_group_id;
87 data.hls_name = stream.hls_name;
88 data.hls_playlist_name = stream.hls_playlist_name;
89 data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name;
96 bool DetermineTextFileCodec(
const std::string& file, std::string* out) {
101 LOG(ERROR) <<
"Failed to open file " << file
102 <<
" to determine file format.";
106 const uint8_t* content_data =
107 reinterpret_cast<const uint8_t*
>(content.data());
108 MediaContainerName container_name =
109 DetermineContainer(content_data, content.size());
111 if (container_name == CONTAINER_WEBVTT) {
116 if (container_name == CONTAINER_TTML) {
124 MediaContainerName GetOutputFormat(
const StreamDescriptor& descriptor) {
125 if (!descriptor.output_format.empty()) {
126 MediaContainerName format =
127 DetermineContainerFromFormatName(descriptor.output_format);
128 if (format == CONTAINER_UNKNOWN) {
129 LOG(ERROR) <<
"Unable to determine output format from '" 130 << descriptor.output_format <<
"'.";
135 base::Optional<MediaContainerName> format_from_output;
136 base::Optional<MediaContainerName> format_from_segment;
137 if (!descriptor.output.empty()) {
138 format_from_output = DetermineContainerFromFileName(descriptor.output);
139 if (format_from_output.value() == CONTAINER_UNKNOWN) {
140 LOG(ERROR) <<
"Unable to determine output format from '" 141 << descriptor.output <<
"'.";
144 if (!descriptor.segment_template.empty()) {
145 format_from_segment =
146 DetermineContainerFromFileName(descriptor.segment_template);
147 if (format_from_segment.value() == CONTAINER_UNKNOWN) {
148 LOG(ERROR) <<
"Unable to determine output format from '" 149 << descriptor.segment_template <<
"'.";
153 if (format_from_output && format_from_segment) {
154 if (format_from_output.value() != format_from_segment.value()) {
155 LOG(ERROR) <<
"Output format determined from '" << descriptor.output
156 <<
"' differs from output format determined from '" 157 << descriptor.segment_template <<
"'.";
158 return CONTAINER_UNKNOWN;
162 if (format_from_output)
163 return format_from_output.value();
164 if (format_from_segment)
165 return format_from_segment.value();
166 return CONTAINER_UNKNOWN;
169 Status ValidateStreamDescriptor(
bool dump_stream_info,
170 const StreamDescriptor& stream) {
171 if (stream.input.empty()) {
172 return Status(error::INVALID_ARGUMENT,
"Stream input not specified.");
177 if (dump_stream_info && stream.output.empty() &&
178 stream.segment_template.empty()) {
182 if (stream.output.empty() && stream.segment_template.empty()) {
183 return Status(error::INVALID_ARGUMENT,
184 "Streams must specify 'output' or 'segment template'.");
188 if (stream.stream_selector.empty()) {
189 return Status(error::INVALID_ARGUMENT,
190 "Stream stream_selector not specified.");
194 if (stream.segment_template.length()) {
195 RETURN_IF_ERROR(ValidateSegmentTemplate(stream.segment_template));
198 if (stream.output.find(
'$') != std::string::npos) {
202 RETURN_IF_ERROR(ValidateSegmentTemplate(stream.output));
207 const MediaContainerName output_format = GetOutputFormat(stream);
209 if (output_format == CONTAINER_UNKNOWN) {
210 return Status(error::INVALID_ARGUMENT,
"Unsupported output format.");
211 }
else if (output_format == MediaContainerName::CONTAINER_MPEG2TS) {
212 if (stream.segment_template.empty()) {
214 error::INVALID_ARGUMENT,
215 "Please specify 'segment_template'. Single file TS output is " 222 if (stream.output.length()) {
223 return Status(error::INVALID_ARGUMENT,
224 "All TS segments must be self-initializing. Stream " 225 "descriptors 'output' or 'init_segment' are not allowed.");
227 }
else if (output_format == CONTAINER_WEBVTT ||
228 output_format == CONTAINER_AAC || output_format == CONTAINER_AC3 ||
229 output_format == CONTAINER_EAC3) {
232 if (stream.segment_template.length() && stream.output.length()) {
234 error::INVALID_ARGUMENT,
235 "Segmented WebVTT or PackedAudio output cannot have an init segment. " 236 "Do not specify stream descriptors 'output' or 'init_segment' when " 237 "using 'segment_template'.");
242 if (stream.segment_template.length() && stream.output.empty()) {
243 return Status(error::INVALID_ARGUMENT,
244 "Please specify 'init_segment'. All non-TS multi-segment " 245 "content must provide an init segment.");
252 Status ValidateParams(
const PackagingParams& packaging_params,
253 const std::vector<StreamDescriptor>& stream_descriptors) {
254 if (!packaging_params.chunking_params.segment_sap_aligned &&
255 packaging_params.chunking_params.subsegment_sap_aligned) {
256 return Status(error::INVALID_ARGUMENT,
257 "Setting segment_sap_aligned to false but " 258 "subsegment_sap_aligned to true is not allowed.");
261 if (stream_descriptors.empty()) {
262 return Status(error::INVALID_ARGUMENT,
263 "Stream descriptors cannot be empty.");
268 const bool on_demand_dash_profile =
269 stream_descriptors.begin()->segment_template.empty();
270 for (
const auto& descriptor : stream_descriptors) {
271 if (on_demand_dash_profile != descriptor.segment_template.empty()) {
272 return Status(error::INVALID_ARGUMENT,
273 "Inconsistent stream descriptor specification: " 274 "segment_template should be specified for none or all " 275 "stream descriptors.");
278 RETURN_IF_ERROR(ValidateStreamDescriptor(
279 packaging_params.test_params.dump_stream_info, descriptor));
281 if (base::StartsWith(descriptor.input,
"udp://",
282 base::CompareCase::SENSITIVE)) {
283 const HlsParams& hls_params = packaging_params.hls_params;
284 if (!hls_params.master_playlist_output.empty() &&
285 hls_params.playlist_type == HlsPlaylistType::kVod) {
287 <<
"Seeing UDP input with HLS Playlist Type set to VOD. The " 288 "playlists will only be generated when UDP socket is closed. " 289 "If you want to do live packaging, --hls_playlist_type needs to " 297 if (packaging_params.output_media_info && !on_demand_dash_profile) {
299 return Status(error::UNIMPLEMENTED,
300 "--output_media_info is only supported for on-demand profile " 301 "(not using segment_template).");
307 bool StreamDescriptorCompareFn(
const StreamDescriptor& a,
308 const StreamDescriptor& b) {
309 if (a.input == b.input) {
310 if (a.stream_selector == b.stream_selector) {
313 if (a.trick_play_factor == 0 || b.trick_play_factor == 0) {
314 return a.trick_play_factor == 0;
316 return a.trick_play_factor > b.trick_play_factor;
319 return a.stream_selector < b.stream_selector;
323 return a.input < b.input;
328 class FakeClock :
public base::Clock {
330 base::Time Now()
override {
return base::Time(); }
333 bool StreamInfoToTextMediaInfo(
const StreamDescriptor& stream_descriptor,
334 MediaInfo* text_media_info) {
336 if (!DetermineTextFileCodec(stream_descriptor.input, &codec)) {
337 LOG(ERROR) <<
"Failed to determine the text file format for " 338 << stream_descriptor.input;
342 MediaInfo::TextInfo* text_info = text_media_info->mutable_text_info();
343 text_info->set_codec(codec);
345 const std::string& language = stream_descriptor.language;
346 if (!language.empty()) {
347 text_info->set_language(language);
350 text_media_info->set_media_file_name(stream_descriptor.output);
351 text_media_info->set_container_type(MediaInfo::CONTAINER_TEXT);
353 if (stream_descriptor.bandwidth != 0) {
354 text_media_info->set_bandwidth(stream_descriptor.bandwidth);
359 const int kDefaultTextBandwidth = 256;
360 text_media_info->set_bandwidth(kDefaultTextBandwidth);
369 Status CreateDemuxer(
const StreamDescriptor& stream,
370 const PackagingParams& packaging_params,
371 std::shared_ptr<Demuxer>* new_demuxer) {
372 std::shared_ptr<Demuxer> demuxer = std::make_shared<Demuxer>(stream.input);
373 demuxer->set_dump_stream_info(packaging_params.test_params.dump_stream_info);
375 if (packaging_params.decryption_params.key_provider != KeyProvider::kNone) {
376 std::unique_ptr<KeySource> decryption_key_source(
377 CreateDecryptionKeySource(packaging_params.decryption_params));
378 if (!decryption_key_source) {
380 error::INVALID_ARGUMENT,
381 "Must define decryption key source when defining key provider");
383 demuxer->SetKeySource(std::move(decryption_key_source));
386 *new_demuxer = std::move(demuxer);
390 std::shared_ptr<MediaHandler> CreateEncryptionHandler(
391 const PackagingParams& packaging_params,
392 const StreamDescriptor& stream,
393 KeySource* key_source) {
394 if (stream.skip_encryption) {
403 EncryptionParams encryption_params = packaging_params.encryption_params;
408 if (GetOutputFormat(stream) == CONTAINER_MPEG2TS ||
409 GetOutputFormat(stream) == CONTAINER_AAC ||
410 GetOutputFormat(stream) == CONTAINER_AC3 ||
411 GetOutputFormat(stream) == CONTAINER_EAC3) {
412 VLOG(1) <<
"Use Apple Sample AES encryption for MPEG2TS or Packed Audio.";
413 encryption_params.protection_scheme = kAppleSampleAesProtectionScheme;
416 if (!stream.drm_label.empty()) {
417 const std::string& drm_label = stream.drm_label;
418 encryption_params.stream_label_func =
419 [drm_label](
const EncryptionParams::EncryptedStreamAttributes&) {
422 }
else if (!encryption_params.stream_label_func) {
423 const int kDefaultMaxSdPixels = 768 * 576;
424 const int kDefaultMaxHdPixels = 1920 * 1080;
425 const int kDefaultMaxUhd1Pixels = 4096 * 2160;
426 encryption_params.stream_label_func = std::bind(
428 kDefaultMaxHdPixels, kDefaultMaxUhd1Pixels, std::placeholders::_1);
431 return std::make_shared<EncryptionHandler>(encryption_params, key_source);
434 std::unique_ptr<TextChunker> CreateTextChunker(
435 const ChunkingParams& chunking_params) {
436 const float segment_length_in_seconds =
437 chunking_params.segment_duration_in_seconds;
438 return std::unique_ptr<TextChunker>(
439 new TextChunker(segment_length_in_seconds));
442 Status CreateHlsTextJob(
const StreamDescriptor& stream,
443 const PackagingParams& packaging_params,
444 std::unique_ptr<MuxerListener> muxer_listener,
445 SyncPointQueue* sync_points,
446 JobManager* job_manager) {
447 DCHECK(muxer_listener);
450 if (stream.segment_template.empty()) {
451 return Status(error::INVALID_ARGUMENT,
452 "Cannot output text (" + stream.input +
453 ") to HLS with no segment template");
459 MuxerOptions muxer_options = CreateMuxerOptions(stream, packaging_params);
460 muxer_options.bandwidth = stream.bandwidth ? stream.bandwidth : 256;
462 auto output = std::make_shared<WebVttTextOutputHandler>(
463 muxer_options, std::move(muxer_listener));
465 std::unique_ptr<FileReader> reader;
468 const int64_t kNoDuration = 0;
470 std::make_shared<WebVttParser>(std::move(reader), stream.language);
471 auto padder = std::make_shared<TextPadder>(kNoDuration);
472 auto cue_aligner = sync_points
473 ? std::make_shared<CueAlignmentHandler>(sync_points)
475 auto chunker = CreateTextChunker(packaging_params.chunking_params);
477 job_manager->Add(
"Segmented Text Job", parser);
479 return MediaHandler::Chain({std::move(parser), std::move(padder),
480 std::move(cue_aligner), std::move(chunker),
484 Status CreateWebVttToMp4TextJob(
const StreamDescriptor& stream,
485 const PackagingParams& packaging_params,
486 std::unique_ptr<MuxerListener> muxer_listener,
487 SyncPointQueue* sync_points,
488 MuxerFactory* muxer_factory,
489 std::shared_ptr<OriginHandler>* root) {
490 std::unique_ptr<FileReader> reader;
493 const int64_t kNoDuration = 0;
495 std::make_shared<WebVttParser>(std::move(reader), stream.language);
496 auto padder = std::make_shared<TextPadder>(kNoDuration);
498 auto text_to_mp4 = std::make_shared<WebVttToMp4Handler>();
499 auto muxer = muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
500 muxer->SetMuxerListener(std::move(muxer_listener));
503 std::shared_ptr<MediaHandler> cue_aligner;
505 cue_aligner = std::make_shared<CueAlignmentHandler>(sync_points);
508 std::shared_ptr<MediaHandler> chunker =
509 CreateTextChunker(packaging_params.chunking_params);
513 return MediaHandler::Chain({std::move(parser), std::move(padder),
514 std::move(cue_aligner), std::move(chunker),
515 std::move(text_to_mp4), std::move(muxer)});
518 Status CreateTextJobs(
519 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
520 const PackagingParams& packaging_params,
521 SyncPointQueue* sync_points,
522 MuxerListenerFactory* muxer_listener_factory,
523 MuxerFactory* muxer_factory,
524 MpdNotifier* mpd_notifier,
525 JobManager* job_manager) {
526 DCHECK(muxer_listener_factory);
528 for (
const StreamDescriptor& stream : streams) {
534 const auto input_container = DetermineContainerFromFileName(stream.input);
535 const auto output_container = GetOutputFormat(stream);
537 if (input_container != CONTAINER_WEBVTT) {
538 return Status(error::INVALID_ARGUMENT,
539 "Text output format is not support for " + stream.input);
542 if (output_container == CONTAINER_MOV) {
543 std::unique_ptr<MuxerListener> muxer_listener =
544 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
546 std::shared_ptr<OriginHandler> root;
547 RETURN_IF_ERROR(CreateWebVttToMp4TextJob(
548 stream, packaging_params, std::move(muxer_listener), sync_points,
549 muxer_factory, &root));
551 job_manager->Add(
"MP4 text job", std::move(root));
553 std::unique_ptr<MuxerListener> hls_listener =
554 muxer_listener_factory->CreateHlsListener(
555 ToMuxerListenerData(stream));
559 if (stream.segment_template.empty() || !stream.output.empty()) {
560 return Status(error::INVALID_ARGUMENT,
561 "segment_template needs to be specified for HLS text " 562 "output. Single file output is not supported yet.");
566 if (mpd_notifier && !stream.segment_template.empty()) {
567 return Status(error::INVALID_ARGUMENT,
568 "Cannot create text output for MPD with segment output.");
574 RETURN_IF_ERROR(CreateHlsTextJob(stream, packaging_params,
575 std::move(hls_listener), sync_points,
579 if (!stream.output.empty()) {
580 if (!
File::Copy(stream.input.c_str(), stream.output.c_str())) {
583 &error,
"Failed to copy the input file (%s) to output file (%s).",
584 stream.input.c_str(), stream.output.c_str());
585 return Status(error::FILE_FAILURE, error);
588 MediaInfo text_media_info;
589 if (!StreamInfoToTextMediaInfo(stream, &text_media_info)) {
590 return Status(error::INVALID_ARGUMENT,
591 "Could not create media info for stream.");
598 if (mpd_notifier->NotifyNewContainer(text_media_info, &unused)) {
599 mpd_notifier->Flush();
601 return Status(error::PARSER_FAILURE,
602 "Failed to process text file " + stream.input);
606 if (packaging_params.output_media_info) {
608 text_media_info, stream.output + kMediaInfoSuffix);
617 Status CreateAudioVideoJobs(
618 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
619 const PackagingParams& packaging_params,
620 KeySource* encryption_key_source,
621 SyncPointQueue* sync_points,
622 MuxerListenerFactory* muxer_listener_factory,
623 MuxerFactory* muxer_factory,
624 JobManager* job_manager) {
625 DCHECK(muxer_listener_factory);
626 DCHECK(muxer_factory);
631 std::map<std::string, std::shared_ptr<Demuxer>> sources;
632 std::map<std::string, std::shared_ptr<MediaHandler>> cue_aligners;
634 for (
const StreamDescriptor& stream : streams) {
635 bool seen_input_before = sources.find(stream.input) != sources.end();
636 if (seen_input_before) {
641 CreateDemuxer(stream, packaging_params, &sources[stream.input]));
642 cue_aligners[stream.input] =
643 sync_points ? std::make_shared<CueAlignmentHandler>(sync_points)
647 for (
auto& source : sources) {
648 job_manager->Add(
"RemuxJob", source.second);
653 std::shared_ptr<MediaHandler> replicator;
655 std::string previous_input;
656 std::string previous_selector;
658 for (
const StreamDescriptor& stream : streams) {
660 auto& demuxer = sources[stream.input];
661 auto& cue_aligner = cue_aligners[stream.input];
663 const bool new_input_file = stream.input != previous_input;
664 const bool new_stream =
665 new_input_file || previous_selector != stream.stream_selector;
666 previous_input = stream.input;
667 previous_selector = stream.stream_selector;
671 if (stream.output.empty() && stream.segment_template.empty()) {
679 if (!stream.language.empty()) {
680 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
683 replicator = std::make_shared<Replicator>();
685 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
686 auto encryptor = CreateEncryptionHandler(packaging_params, stream,
687 encryption_key_source);
692 MediaHandler::Chain({cue_aligner, chunker, encryptor, replicator}));
694 demuxer->SetHandler(stream.stream_selector, cue_aligner));
696 RETURN_IF_ERROR(MediaHandler::Chain({chunker, encryptor, replicator}));
697 RETURN_IF_ERROR(demuxer->SetHandler(stream.stream_selector, chunker));
702 std::shared_ptr<Muxer> muxer =
703 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
705 return Status(error::INVALID_ARGUMENT,
"Failed to create muxer for " +
707 stream.stream_selector);
710 std::unique_ptr<MuxerListener> muxer_listener =
711 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
712 muxer->SetMuxerListener(std::move(muxer_listener));
715 std::shared_ptr<MediaHandler> trick_play =
716 stream.trick_play_factor
717 ? std::make_shared<TrickPlayHandler>(stream.trick_play_factor)
720 RETURN_IF_ERROR(MediaHandler::Chain({replicator, trick_play, muxer}));
726 Status CreateAllJobs(
const std::vector<StreamDescriptor>& stream_descriptors,
727 const PackagingParams& packaging_params,
728 MpdNotifier* mpd_notifier,
729 KeySource* encryption_key_source,
730 SyncPointQueue* sync_points,
731 MuxerListenerFactory* muxer_listener_factory,
732 MuxerFactory* muxer_factory,
733 JobManager* job_manager) {
734 DCHECK(muxer_factory);
735 DCHECK(muxer_listener_factory);
739 std::vector<std::reference_wrapper<const StreamDescriptor>> text_streams;
740 std::vector<std::reference_wrapper<const StreamDescriptor>>
743 for (
const StreamDescriptor& stream : stream_descriptors) {
747 if (stream.stream_selector ==
"text") {
748 text_streams.push_back(stream);
750 audio_video_streams.push_back(stream);
756 std::sort(audio_video_streams.begin(), audio_video_streams.end(),
757 media::StreamDescriptorCompareFn);
759 RETURN_IF_ERROR(CreateTextJobs(text_streams, packaging_params, sync_points,
760 muxer_listener_factory, muxer_factory,
761 mpd_notifier, job_manager));
762 RETURN_IF_ERROR(CreateAudioVideoJobs(
763 audio_video_streams, packaging_params, encryption_key_source, sync_points,
764 muxer_listener_factory, muxer_factory, job_manager));
767 return job_manager->InitializeJobs();
773 struct Packager::PackagerInternal {
774 media::FakeClock fake_clock;
775 std::unique_ptr<KeySource> encryption_key_source;
776 std::unique_ptr<MpdNotifier> mpd_notifier;
777 std::unique_ptr<hls::HlsNotifier> hls_notifier;
778 BufferCallbackParams buffer_callback_params;
779 std::unique_ptr<media::JobManager> job_manager;
782 Packager::Packager() {}
784 Packager::~Packager() {}
788 const std::vector<StreamDescriptor>& stream_descriptors) {
790 static base::AtExitManager exit;
794 return Status(error::INVALID_ARGUMENT,
"Already initialized.");
796 RETURN_IF_ERROR(media::ValidateParams(packaging_params, stream_descriptors));
799 SetPackagerVersionForTesting(
803 std::unique_ptr<PackagerInternal>
internal(
new PackagerInternal);
807 internal->encryption_key_source = CreateEncryptionKeySource(
808 static_cast<media::FourCC>(
811 if (!internal->encryption_key_source)
812 return Status(error::INVALID_ARGUMENT,
"Failed to create key source.");
821 if (internal->buffer_callback_params.write_func) {
823 internal->buffer_callback_params, mpd_params.
mpd_output);
836 const bool on_demand_dash_profile =
837 stream_descriptors.begin()->segment_template.empty();
838 const double target_segment_duration =
840 const MpdOptions mpd_options = media::GetMpdOptions(
841 on_demand_dash_profile, mpd_params, target_segment_duration);
843 if (!internal->mpd_notifier->Init()) {
844 LOG(ERROR) <<
"MpdNotifier failed to initialize.";
845 return Status(error::INVALID_ARGUMENT,
846 "Failed to initialize MpdNotifier.");
854 std::unique_ptr<SyncPointQueue> sync_points;
859 internal->job_manager.reset(
new JobManager(std::move(sync_points)));
861 std::vector<StreamDescriptor> streams_for_jobs;
867 if (internal->buffer_callback_params.read_func) {
872 if (internal->buffer_callback_params.write_func) {
876 internal->buffer_callback_params, descriptor.segment_template);
884 error::INVALID_ARGUMENT,
885 "Unknown/invalid language specified: " + descriptor.language);
889 streams_for_jobs.push_back(copy);
899 internal->hls_notifier.get());
901 RETURN_IF_ERROR(media::CreateAllJobs(
902 streams_for_jobs, packaging_params, internal->mpd_notifier.get(),
903 internal->encryption_key_source.get(),
904 internal->job_manager->sync_points(), &muxer_listener_factory,
905 &muxer_factory,
internal->job_manager.get()));
907 internal_ = std::move(
internal);
913 return Status(error::INVALID_ARGUMENT,
"Not yet initialized.");
915 RETURN_IF_ERROR(internal_->job_manager->RunJobs());
917 if (internal_->hls_notifier) {
918 if (!internal_->hls_notifier->Flush())
919 return Status(error::INVALID_ARGUMENT,
"Failed to flush Hls.");
921 if (internal_->mpd_notifier) {
922 if (!internal_->mpd_notifier->Flush())
923 return Status(error::INVALID_ARGUMENT,
"Failed to flush Mpd.");
930 LOG(INFO) <<
"Not yet initialized. Return directly.";
933 internal_->job_manager->CancelJobs();
937 return GetPackagerVersion();
945 if (stream_attributes.stream_type ==
946 EncryptionParams::EncryptedStreamAttributes::kAudio)
948 if (stream_attributes.stream_type ==
949 EncryptionParams::EncryptedStreamAttributes::kVideo) {
950 const int pixels = stream_attributes.oneof.video.width *
951 stream_attributes.oneof.video.height;
952 if (pixels <= max_sd_pixels)
954 if (pixels <= max_hd_pixels)
956 if (pixels <= max_uhd1_pixels)
BufferCallbackParams buffer_callback_params
Buffer callback params.
std::string master_playlist_output
HLS master playlist output path.
DASH MPD related parameters.
Defines a single input/output stream.
std::string input
Input/source media file path or network stream URL. Required.
HlsParams hls_params
HLS related parameters.
Status Initialize(const PackagingParams &packaging_params, const std::vector< StreamDescriptor > &stream_descriptors)
std::string default_language
static std::string DefaultStreamLabelFunction(int max_sd_pixels, int max_hd_pixels, int max_uhd1_pixels, const EncryptionParams::EncryptedStreamAttributes &stream_attributes)
ChunkingParams chunking_params
Chunking (segmentation) related parameters.
std::vector< Cuepoint > cue_points
List of cuepoints.
std::string LanguageToShortestForm(const std::string &language)
std::string segment_template
Specifies segment template. Can be empty.
static bool Copy(const char *from_file_name, const char *to_file_name)
static bool ReadFileToString(const char *file_name, std::string *contents)
All the methods that are virtual are virtual for mocking.
static std::string GetLibraryVersion()
std::string LanguageToISO_639_2(const std::string &language)
std::string injected_library_version
MpdParams mpd_params
DASH MPD related parameters.
AdCueGeneratorParams ad_cue_generator_params
Out of band cuepoint parameters.
EncryptionParams encryption_params
Encryption and Decryption Parameters.
std::string mpd_output
MPD output file path.
static std::string MakeCallbackFileName(const BufferCallbackParams &callback_params, const std::string &name)
Encrypted stream information that is used to determine stream label.
std::string default_language
double segment_duration_in_seconds
Segment duration in seconds.
void Cancel()
Cancel packaging. Note that it has to be called from another thread.