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/ad_cue_generator/ad_cue_generator.h" 29 #include "packager/media/base/container_names.h" 30 #include "packager/media/base/fourccs.h" 31 #include "packager/media/base/key_source.h" 32 #include "packager/media/base/language_utils.h" 33 #include "packager/media/base/muxer.h" 34 #include "packager/media/base/muxer_options.h" 35 #include "packager/media/base/muxer_util.h" 36 #include "packager/media/chunking/chunking_handler.h" 37 #include "packager/media/chunking/cue_alignment_handler.h" 38 #include "packager/media/chunking/text_chunker.h" 39 #include "packager/media/crypto/encryption_handler.h" 40 #include "packager/media/demuxer/demuxer.h" 41 #include "packager/media/event/muxer_listener_factory.h" 42 #include "packager/media/event/vod_media_info_dump_muxer_listener.h" 43 #include "packager/media/formats/webvtt/text_padder.h" 44 #include "packager/media/formats/webvtt/text_readers.h" 45 #include "packager/media/formats/webvtt/webvtt_output_handler.h" 46 #include "packager/media/formats/webvtt/webvtt_parser.h" 47 #include "packager/media/formats/webvtt/webvtt_to_mp4_handler.h" 48 #include "packager/media/replicator/replicator.h" 49 #include "packager/media/trick_play/trick_play_handler.h" 50 #include "packager/mpd/base/media_info.pb.h" 51 #include "packager/mpd/base/mpd_builder.h" 52 #include "packager/mpd/base/simple_mpd_notifier.h" 53 #include "packager/status_macros.h" 54 #include "packager/version/version.h" 60 using media::JobManager;
61 using media::KeySource;
62 using media::MuxerOptions;
63 using media::SyncPointQueue;
68 const char kMediaInfoSuffix[] =
".media_info";
71 std::initializer_list<std::shared_ptr<MediaHandler>> list) {
72 std::shared_ptr<MediaHandler> previous;
74 for (
auto& next : list) {
81 RETURN_IF_ERROR(previous->AddHandler(next));
84 previous = std::move(next);
90 MuxerOptions CreateMuxerOptions(
const StreamDescriptor& stream,
91 const PackagingParams& params) {
94 options.mp4_params = params.mp4_output_params;
95 options.temp_dir = params.temp_dir;
96 options.bandwidth = stream.bandwidth;
97 options.output_file_name = stream.output;
98 options.segment_template = stream.segment_template;
103 MuxerListenerFactory::StreamData ToMuxerListenerData(
104 const StreamDescriptor& stream) {
105 MuxerListenerFactory::StreamData data;
106 data.media_info_output = stream.output;
107 data.hls_group_id = stream.hls_group_id;
108 data.hls_name = stream.hls_name;
109 data.hls_playlist_name = stream.hls_playlist_name;
110 data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name;
117 bool DetermineTextFileCodec(
const std::string& file, std::string* out) {
122 LOG(ERROR) <<
"Failed to open file " << file
123 <<
" to determine file format.";
127 const uint8_t* content_data =
128 reinterpret_cast<const uint8_t*
>(content.data());
129 MediaContainerName container_name =
130 DetermineContainer(content_data, content.size());
132 if (container_name == CONTAINER_WEBVTT) {
137 if (container_name == CONTAINER_TTML) {
145 MediaContainerName GetOutputFormat(
const StreamDescriptor& descriptor) {
146 if (!descriptor.output_format.empty()) {
147 MediaContainerName format =
148 DetermineContainerFromFormatName(descriptor.output_format);
149 if (format == CONTAINER_UNKNOWN) {
150 LOG(ERROR) <<
"Unable to determine output format from '" 151 << descriptor.output_format <<
"'.";
156 base::Optional<MediaContainerName> format_from_output;
157 base::Optional<MediaContainerName> format_from_segment;
158 if (!descriptor.output.empty()) {
159 format_from_output = DetermineContainerFromFileName(descriptor.output);
160 if (format_from_output.value() == CONTAINER_UNKNOWN) {
161 LOG(ERROR) <<
"Unable to determine output format from '" 162 << descriptor.output <<
"'.";
165 if (!descriptor.segment_template.empty()) {
166 format_from_segment =
167 DetermineContainerFromFileName(descriptor.segment_template);
168 if (format_from_segment.value() == CONTAINER_UNKNOWN) {
169 LOG(ERROR) <<
"Unable to determine output format from '" 170 << descriptor.segment_template <<
"'.";
174 if (format_from_output && format_from_segment) {
175 if (format_from_output.value() != format_from_segment.value()) {
176 LOG(ERROR) <<
"Output format determined from '" << descriptor.output
177 <<
"' differs from output format determined from '" 178 << descriptor.segment_template <<
"'.";
179 return CONTAINER_UNKNOWN;
183 if (format_from_output)
184 return format_from_output.value();
185 if (format_from_segment)
186 return format_from_segment.value();
187 return CONTAINER_UNKNOWN;
190 Status ValidateStreamDescriptor(
bool dump_stream_info,
191 const StreamDescriptor& stream) {
192 if (stream.input.empty()) {
193 return Status(error::INVALID_ARGUMENT,
"Stream input not specified.");
198 if (dump_stream_info && stream.output.empty() &&
199 stream.segment_template.empty()) {
203 if (stream.output.empty() && stream.segment_template.empty()) {
204 return Status(error::INVALID_ARGUMENT,
205 "Streams must specify 'output' or 'segment template'.");
209 if (stream.stream_selector.empty()) {
210 return Status(error::INVALID_ARGUMENT,
211 "Stream stream_selector not specified.");
215 if (stream.segment_template.length()) {
216 Status template_check = ValidateSegmentTemplate(stream.segment_template);
217 if (!template_check.ok()) {
218 return template_check;
224 const MediaContainerName output_format = GetOutputFormat(stream);
226 if (output_format == CONTAINER_UNKNOWN) {
227 return Status(error::INVALID_ARGUMENT,
"Unsupported output format.");
228 }
else if (output_format == MediaContainerName::CONTAINER_MPEG2TS) {
229 if (stream.segment_template.empty()) {
231 error::INVALID_ARGUMENT,
232 "Please specify 'segment_template'. Single file TS output is " 239 if (stream.output.length()) {
240 return Status(error::INVALID_ARGUMENT,
241 "All TS segments must be self-initializing. Stream " 242 "descriptors 'output' or 'init_segment' are not allowed.");
244 }
else if (output_format == CONTAINER_WEBVTT ||
245 output_format == CONTAINER_AAC || output_format == CONTAINER_AC3 ||
246 output_format == CONTAINER_EAC3) {
249 if (stream.segment_template.length() && stream.output.length()) {
251 error::INVALID_ARGUMENT,
252 "Segmented WebVTT or PackedAudio output cannot have an init segment. " 253 "Do not specify stream descriptors 'output' or 'init_segment' when " 254 "using 'segment_template'.");
259 if (stream.segment_template.length() && stream.output.empty()) {
260 return Status(error::INVALID_ARGUMENT,
261 "Please specify 'init_segment'. All non-TS multi-segment " 262 "content must provide an init segment.");
269 Status ValidateParams(
const PackagingParams& packaging_params,
270 const std::vector<StreamDescriptor>& stream_descriptors) {
271 if (!packaging_params.chunking_params.segment_sap_aligned &&
272 packaging_params.chunking_params.subsegment_sap_aligned) {
273 return Status(error::INVALID_ARGUMENT,
274 "Setting segment_sap_aligned to false but " 275 "subsegment_sap_aligned to true is not allowed.");
278 if (stream_descriptors.empty()) {
279 return Status(error::INVALID_ARGUMENT,
280 "Stream descriptors cannot be empty.");
285 const bool on_demand_dash_profile =
286 stream_descriptors.begin()->segment_template.empty();
287 for (
const auto& descriptor : stream_descriptors) {
288 if (on_demand_dash_profile != descriptor.segment_template.empty()) {
289 return Status(error::INVALID_ARGUMENT,
290 "Inconsistent stream descriptor specification: " 291 "segment_template should be specified for none or all " 292 "stream descriptors.");
295 Status stream_check = ValidateStreamDescriptor(
296 packaging_params.test_params.dump_stream_info, descriptor);
298 if (!stream_check.ok()) {
303 if (packaging_params.output_media_info && !on_demand_dash_profile) {
305 return Status(error::UNIMPLEMENTED,
306 "--output_media_info is only supported for on-demand profile " 307 "(not using segment_template).");
313 bool StreamDescriptorCompareFn(
const StreamDescriptor& a,
314 const StreamDescriptor& b) {
315 if (a.input == b.input) {
316 if (a.stream_selector == b.stream_selector) {
319 if (a.trick_play_factor == 0 || b.trick_play_factor == 0) {
320 return a.trick_play_factor == 0;
322 return a.trick_play_factor > b.trick_play_factor;
325 return a.stream_selector < b.stream_selector;
329 return a.input < b.input;
334 class FakeClock :
public base::Clock {
336 base::Time Now()
override {
return base::Time(); }
339 bool StreamInfoToTextMediaInfo(
const StreamDescriptor& stream_descriptor,
340 MediaInfo* text_media_info) {
342 if (!DetermineTextFileCodec(stream_descriptor.input, &codec)) {
343 LOG(ERROR) <<
"Failed to determine the text file format for " 344 << stream_descriptor.input;
348 MediaInfo::TextInfo* text_info = text_media_info->mutable_text_info();
349 text_info->set_codec(codec);
351 const std::string& language = stream_descriptor.language;
352 if (!language.empty()) {
353 text_info->set_language(language);
356 text_media_info->set_media_file_name(stream_descriptor.output);
357 text_media_info->set_container_type(MediaInfo::CONTAINER_TEXT);
359 if (stream_descriptor.bandwidth != 0) {
360 text_media_info->set_bandwidth(stream_descriptor.bandwidth);
365 const int kDefaultTextBandwidth = 256;
366 text_media_info->set_bandwidth(kDefaultTextBandwidth);
375 Status CreateDemuxer(
const StreamDescriptor& stream,
376 const PackagingParams& packaging_params,
377 std::shared_ptr<Demuxer>* new_demuxer) {
378 std::shared_ptr<Demuxer> demuxer = std::make_shared<Demuxer>(stream.input);
379 demuxer->set_dump_stream_info(packaging_params.test_params.dump_stream_info);
381 if (packaging_params.decryption_params.key_provider != KeyProvider::kNone) {
382 std::unique_ptr<KeySource> decryption_key_source(
383 CreateDecryptionKeySource(packaging_params.decryption_params));
384 if (!decryption_key_source) {
386 error::INVALID_ARGUMENT,
387 "Must define decryption key source when defining key provider");
389 demuxer->SetKeySource(std::move(decryption_key_source));
392 *new_demuxer = std::move(demuxer);
396 std::shared_ptr<MediaHandler> CreateEncryptionHandler(
397 const PackagingParams& packaging_params,
398 const StreamDescriptor& stream,
399 KeySource* key_source) {
400 if (stream.skip_encryption) {
409 EncryptionParams encryption_params = packaging_params.encryption_params;
414 if (GetOutputFormat(stream) == CONTAINER_MPEG2TS ||
415 GetOutputFormat(stream) == CONTAINER_AAC ||
416 GetOutputFormat(stream) == CONTAINER_AC3 ||
417 GetOutputFormat(stream) == CONTAINER_EAC3) {
418 VLOG(1) <<
"Use Apple Sample AES encryption for MPEG2TS or Packed Audio.";
419 encryption_params.protection_scheme = kAppleSampleAesProtectionScheme;
422 if (!stream.drm_label.empty()) {
423 const std::string& drm_label = stream.drm_label;
424 encryption_params.stream_label_func =
425 [drm_label](
const EncryptionParams::EncryptedStreamAttributes&) {
428 }
else if (!encryption_params.stream_label_func) {
429 const int kDefaultMaxSdPixels = 768 * 576;
430 const int kDefaultMaxHdPixels = 1920 * 1080;
431 const int kDefaultMaxUhd1Pixels = 4096 * 2160;
432 encryption_params.stream_label_func = std::bind(
434 kDefaultMaxHdPixels, kDefaultMaxUhd1Pixels, std::placeholders::_1);
437 return std::make_shared<EncryptionHandler>(encryption_params, key_source);
440 Status CreateMp4ToMp4TextJob(
const StreamDescriptor& stream,
441 const PackagingParams& packaging_params,
442 std::unique_ptr<MuxerListener> muxer_listener,
443 SyncPointQueue* sync_points,
444 MuxerFactory* muxer_factory,
445 std::shared_ptr<OriginHandler>* root) {
452 std::shared_ptr<Demuxer> demuxer;
453 RETURN_IF_ERROR(CreateDemuxer(stream, packaging_params, &demuxer));
454 if (!stream.language.empty()) {
455 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
459 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
460 std::shared_ptr<Muxer> muxer =
461 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
462 muxer->SetMuxerListener(std::move(muxer_listener));
464 RETURN_IF_ERROR(chunker->AddHandler(std::move(muxer)));
466 demuxer->SetHandler(stream.stream_selector, std::move(chunker)));
471 Status CreateHlsTextJob(
const StreamDescriptor& stream,
472 const PackagingParams& packaging_params,
473 std::unique_ptr<MuxerListener> muxer_listener,
474 SyncPointQueue* sync_points,
475 JobManager* job_manager) {
476 DCHECK(muxer_listener);
479 if (stream.segment_template.empty()) {
480 return Status(error::INVALID_ARGUMENT,
481 "Cannot output text (" + stream.input +
482 ") to HLS with no segment template");
485 const float segment_length_in_seconds =
486 packaging_params.chunking_params.segment_duration_in_seconds;
487 const uint64_t segment_length_in_ms =
488 static_cast<uint64_t
>(segment_length_in_seconds * 1000);
493 MuxerOptions muxer_options = CreateMuxerOptions(stream, packaging_params);
494 muxer_options.bandwidth = stream.bandwidth ? stream.bandwidth : 256;
496 auto output = std::make_shared<WebVttSegmentedOutputHandler>(
497 muxer_options, std::move(muxer_listener));
499 std::unique_ptr<FileReader> reader;
502 const int64_t kNoDuration = 0;
504 std::make_shared<WebVttParser>(std::move(reader), stream.language);
505 auto padder = std::make_shared<TextPadder>(kNoDuration);
506 auto cue_aligner = sync_points
507 ? std::make_shared<CueAlignmentHandler>(sync_points)
509 auto chunker = std::make_shared<TextChunker>(segment_length_in_ms);
512 ChainHandlers({parser, std::move(padder), std::move(cue_aligner),
513 std::move(chunker), std::move(output)}));
515 job_manager->Add(
"Segmented Text Job", std::move(parser));
520 Status CreateWebVttToMp4TextJob(
const StreamDescriptor& stream,
521 const PackagingParams& packaging_params,
522 std::unique_ptr<MuxerListener> muxer_listener,
523 SyncPointQueue* sync_points,
524 MuxerFactory* muxer_factory,
525 std::shared_ptr<OriginHandler>* root) {
528 std::unique_ptr<FileReader> reader;
531 const int64_t kNoDuration = 0;
533 std::make_shared<WebVttParser>(std::move(reader), stream.language);
534 auto padder = std::make_shared<TextPadder>(kNoDuration);
535 auto text_to_mp4 = std::make_shared<WebVttToMp4Handler>();
537 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
538 auto muxer = muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
539 muxer->SetMuxerListener(std::move(muxer_listener));
542 ChainHandlers({parser, std::move(padder), std::move(text_to_mp4),
543 std::move(chunker), std::move(muxer)}));
544 *root = std::move(parser);
549 Status CreateTextJobs(
550 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
551 const PackagingParams& packaging_params,
552 SyncPointQueue* sync_points,
553 MuxerListenerFactory* muxer_listener_factory,
554 MuxerFactory* muxer_factory,
555 MpdNotifier* mpd_notifier,
556 JobManager* job_manager) {
557 DCHECK(muxer_listener_factory);
559 for (
const StreamDescriptor& stream : streams) {
560 if (GetOutputFormat(stream) == CONTAINER_MOV) {
561 std::unique_ptr<MuxerListener> muxer_listener =
562 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
564 std::shared_ptr<OriginHandler> root;
567 switch (DetermineContainerFromFileName(stream.input)) {
568 case CONTAINER_WEBVTT:
569 status.Update(CreateWebVttToMp4TextJob(
570 stream, packaging_params, std::move(muxer_listener), sync_points,
571 muxer_factory, &root));
575 status.Update(CreateMp4ToMp4TextJob(
576 stream, packaging_params, std::move(muxer_listener), sync_points,
577 muxer_factory, &root));
582 Status(error::INVALID_ARGUMENT,
583 "Text output format is not support for " + stream.input));
591 job_manager->Add(
"MP4 text job", std::move(root));
593 std::unique_ptr<MuxerListener> hls_listener =
594 muxer_listener_factory->CreateHlsListener(
595 ToMuxerListenerData(stream));
599 if (stream.segment_template.empty() || !stream.output.empty()) {
600 return Status(error::INVALID_ARGUMENT,
601 "segment_template needs to be specified for HLS text " 602 "output. Single file output is not supported yet.");
606 if (mpd_notifier && !stream.segment_template.empty()) {
607 return Status(error::INVALID_ARGUMENT,
608 "Cannot create text output for MPD with segment output.");
615 CreateHlsTextJob(stream, packaging_params, std::move(hls_listener),
616 sync_points, job_manager);
622 if (!stream.output.empty()) {
623 if (!
File::Copy(stream.input.c_str(), stream.output.c_str())) {
626 &error,
"Failed to copy the input file (%s) to output file (%s).",
627 stream.input.c_str(), stream.output.c_str());
628 return Status(error::FILE_FAILURE, error);
631 MediaInfo text_media_info;
632 if (!StreamInfoToTextMediaInfo(stream, &text_media_info)) {
633 return Status(error::INVALID_ARGUMENT,
634 "Could not create media info for stream.");
641 if (mpd_notifier->NotifyNewContainer(text_media_info, &unused)) {
642 mpd_notifier->Flush();
644 return Status(error::PARSER_FAILURE,
645 "Failed to process text file " + stream.input);
649 if (packaging_params.output_media_info) {
651 text_media_info, stream.output + kMediaInfoSuffix);
660 Status CreateAudioVideoJobs(
661 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
662 const PackagingParams& packaging_params,
663 KeySource* encryption_key_source,
664 SyncPointQueue* sync_points,
665 MuxerListenerFactory* muxer_listener_factory,
666 MuxerFactory* muxer_factory,
667 JobManager* job_manager) {
668 DCHECK(muxer_listener_factory);
669 DCHECK(muxer_factory);
674 std::map<std::string, std::shared_ptr<Demuxer>> sources;
675 std::map<std::string, std::shared_ptr<MediaHandler>> cue_aligners;
677 for (
const StreamDescriptor& stream : streams) {
678 bool seen_input_before = sources.find(stream.input) != sources.end();
679 if (seen_input_before) {
684 CreateDemuxer(stream, packaging_params, &sources[stream.input]));
685 cue_aligners[stream.input] =
686 sync_points ? std::make_shared<CueAlignmentHandler>(sync_points)
690 for (
auto& source : sources) {
691 job_manager->Add(
"RemuxJob", source.second);
696 std::shared_ptr<MediaHandler> replicator;
698 std::string previous_input;
699 std::string previous_selector;
701 for (
const StreamDescriptor& stream : streams) {
703 auto& demuxer = sources[stream.input];
704 auto& cue_aligner = cue_aligners[stream.input];
706 const bool new_input_file = stream.input != previous_input;
707 const bool new_stream =
708 new_input_file || previous_selector != stream.stream_selector;
709 previous_input = stream.input;
710 previous_selector = stream.stream_selector;
714 if (stream.output.empty() && stream.segment_template.empty()) {
722 if (!stream.language.empty()) {
723 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
726 replicator = std::make_shared<Replicator>();
728 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
729 auto encryptor = CreateEncryptionHandler(packaging_params, stream,
730 encryption_key_source);
735 ChainHandlers({cue_aligner, chunker, encryptor, replicator}));
737 demuxer->SetHandler(stream.stream_selector, cue_aligner));
739 RETURN_IF_ERROR(ChainHandlers({chunker, encryptor, replicator}));
740 RETURN_IF_ERROR(demuxer->SetHandler(stream.stream_selector, chunker));
745 std::shared_ptr<Muxer> muxer =
746 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
748 return Status(error::INVALID_ARGUMENT,
"Failed to create muxer for " +
750 stream.stream_selector);
753 std::unique_ptr<MuxerListener> muxer_listener =
754 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
755 muxer->SetMuxerListener(std::move(muxer_listener));
758 std::shared_ptr<MediaHandler> trick_play =
759 stream.trick_play_factor
760 ? std::make_shared<TrickPlayHandler>(stream.trick_play_factor)
763 RETURN_IF_ERROR(ChainHandlers({replicator, trick_play, muxer}));
769 Status CreateAllJobs(
const std::vector<StreamDescriptor>& stream_descriptors,
770 const PackagingParams& packaging_params,
771 MpdNotifier* mpd_notifier,
772 KeySource* encryption_key_source,
773 SyncPointQueue* sync_points,
774 MuxerListenerFactory* muxer_listener_factory,
775 MuxerFactory* muxer_factory,
776 JobManager* job_manager) {
777 DCHECK(muxer_factory);
778 DCHECK(muxer_listener_factory);
782 std::vector<std::reference_wrapper<const StreamDescriptor>> text_streams;
783 std::vector<std::reference_wrapper<const StreamDescriptor>>
786 for (
const StreamDescriptor& stream : stream_descriptors) {
790 if (stream.stream_selector ==
"text") {
791 text_streams.push_back(stream);
793 audio_video_streams.push_back(stream);
799 std::sort(audio_video_streams.begin(), audio_video_streams.end(),
800 media::StreamDescriptorCompareFn);
802 RETURN_IF_ERROR(CreateTextJobs(text_streams, packaging_params, sync_points,
803 muxer_listener_factory, muxer_factory,
804 mpd_notifier, job_manager));
805 RETURN_IF_ERROR(CreateAudioVideoJobs(
806 audio_video_streams, packaging_params, encryption_key_source, sync_points,
807 muxer_listener_factory, muxer_factory, job_manager));
810 return job_manager->InitializeJobs();
816 struct Packager::PackagerInternal {
817 media::FakeClock fake_clock;
818 std::unique_ptr<KeySource> encryption_key_source;
819 std::unique_ptr<MpdNotifier> mpd_notifier;
820 std::unique_ptr<hls::HlsNotifier> hls_notifier;
821 BufferCallbackParams buffer_callback_params;
822 std::unique_ptr<media::JobManager> job_manager;
825 Packager::Packager() {}
827 Packager::~Packager() {}
831 const std::vector<StreamDescriptor>& stream_descriptors) {
833 static base::AtExitManager exit;
837 return Status(error::INVALID_ARGUMENT,
"Already initialized.");
840 media::ValidateParams(packaging_params, stream_descriptors);
841 if (!param_check.ok()) {
846 SetPackagerVersionForTesting(
850 std::unique_ptr<PackagerInternal>
internal(
new PackagerInternal);
854 internal->encryption_key_source = CreateEncryptionKeySource(
855 static_cast<media::FourCC>(
858 if (!internal->encryption_key_source)
859 return Status(error::INVALID_ARGUMENT,
"Failed to create key source.");
868 if (internal->buffer_callback_params.write_func) {
870 internal->buffer_callback_params, mpd_params.
mpd_output);
883 const bool on_demand_dash_profile =
884 stream_descriptors.begin()->segment_template.empty();
885 const double target_segment_duration =
887 const MpdOptions mpd_options = media::GetMpdOptions(
888 on_demand_dash_profile, mpd_params, target_segment_duration);
890 if (!internal->mpd_notifier->Init()) {
891 LOG(ERROR) <<
"MpdNotifier failed to initialize.";
892 return Status(error::INVALID_ARGUMENT,
893 "Failed to initialize MpdNotifier.");
901 std::unique_ptr<SyncPointQueue> sync_points;
906 internal->job_manager.reset(
new JobManager(std::move(sync_points)));
908 std::vector<StreamDescriptor> streams_for_jobs;
914 if (internal->buffer_callback_params.read_func) {
919 if (internal->buffer_callback_params.write_func) {
923 internal->buffer_callback_params, descriptor.segment_template);
931 error::INVALID_ARGUMENT,
932 "Unknown/invalid language specified: " + descriptor.language);
936 streams_for_jobs.push_back(copy);
946 internal->hls_notifier.get());
948 Status status = media::CreateAllJobs(
949 streams_for_jobs, packaging_params, internal->mpd_notifier.get(),
950 internal->encryption_key_source.get(),
951 internal->job_manager->sync_points(), &muxer_listener_factory,
952 &muxer_factory,
internal->job_manager.get());
958 internal_ = std::move(
internal);
964 return Status(error::INVALID_ARGUMENT,
"Not yet initialized.");
966 Status status = internal_->job_manager->RunJobs();
970 if (internal_->hls_notifier) {
971 if (!internal_->hls_notifier->Flush())
972 return Status(error::INVALID_ARGUMENT,
"Failed to flush Hls.");
974 if (internal_->mpd_notifier) {
975 if (!internal_->mpd_notifier->Flush())
976 return Status(error::INVALID_ARGUMENT,
"Failed to flush Mpd.");
983 LOG(INFO) <<
"Not yet initialized. Return directly.";
986 internal_->job_manager->CancelJobs();
990 return GetPackagerVersion();
998 if (stream_attributes.stream_type ==
999 EncryptionParams::EncryptedStreamAttributes::kAudio)
1001 if (stream_attributes.stream_type ==
1002 EncryptionParams::EncryptedStreamAttributes::kVideo) {
1003 const int pixels = stream_attributes.oneof.video.width *
1004 stream_attributes.oneof.video.height;
1005 if (pixels <= max_sd_pixels)
1007 if (pixels <= max_hd_pixels)
1009 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.