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/path_service.h" 20 #include "packager/base/strings/string_util.h" 21 #include "packager/base/strings/stringprintf.h" 22 #include "packager/base/threading/simple_thread.h" 23 #include "packager/base/time/clock.h" 24 #include "packager/file/file.h" 25 #include "packager/hls/base/hls_notifier.h" 26 #include "packager/hls/base/simple_hls_notifier.h" 27 #include "packager/media/ad_cue_generator/ad_cue_generator.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/crypto/encryption_handler.h" 37 #include "packager/media/demuxer/demuxer.h" 38 #include "packager/media/event/muxer_listener_factory.h" 39 #include "packager/media/event/vod_media_info_dump_muxer_listener.h" 40 #include "packager/media/formats/webvtt/text_readers.h" 41 #include "packager/media/formats/webvtt/webvtt_output_handler.h" 42 #include "packager/media/formats/webvtt/webvtt_parser.h" 43 #include "packager/media/formats/webvtt/webvtt_segmenter.h" 44 #include "packager/media/formats/webvtt/webvtt_to_mp4_handler.h" 45 #include "packager/media/replicator/replicator.h" 46 #include "packager/media/trick_play/trick_play_handler.h" 47 #include "packager/mpd/base/media_info.pb.h" 48 #include "packager/mpd/base/mpd_builder.h" 49 #include "packager/mpd/base/simple_mpd_notifier.h" 50 #include "packager/version/version.h" 56 using media::KeySource;
57 using media::MuxerOptions;
62 const char kMediaInfoSuffix[] =
".media_info";
64 MuxerOptions CreateMuxerOptions(
const StreamDescriptor& stream,
65 const PackagingParams& params) {
68 options.mp4_params = params.mp4_output_params;
69 options.temp_dir = params.temp_dir;
70 options.bandwidth = stream.bandwidth;
71 options.output_file_name = stream.output;
72 options.segment_template = stream.segment_template;
77 MuxerListenerFactory::StreamData ToMuxerListenerData(
78 const StreamDescriptor& stream) {
79 MuxerListenerFactory::StreamData data;
80 data.media_info_output = stream.output;
81 data.hls_group_id = stream.hls_group_id;
82 data.hls_name = stream.hls_name;
83 data.hls_playlist_name = stream.hls_playlist_name;
84 data.hls_iframe_playlist_name = stream.hls_iframe_playlist_name;
91 std::string DetermineTextFileFormat(
const std::string& file) {
94 LOG(ERROR) <<
"Failed to open file " << file
95 <<
" to determine file format.";
98 MediaContainerName container_name = DetermineContainer(
99 reinterpret_cast<const uint8_t*>(content.data()), content.size());
100 if (container_name == CONTAINER_WEBVTT) {
102 }
else if (container_name == CONTAINER_TTML) {
109 MediaContainerName GetOutputFormat(
const StreamDescriptor& descriptor) {
110 MediaContainerName output_format = CONTAINER_UNKNOWN;
111 if (!descriptor.output_format.empty()) {
112 output_format = DetermineContainerFromFormatName(descriptor.output_format);
113 if (output_format == CONTAINER_UNKNOWN) {
114 LOG(ERROR) <<
"Unable to determine output format from '" 115 << descriptor.output_format <<
"'.";
118 const std::string& output_name = descriptor.output.empty()
119 ? descriptor.segment_template
121 if (output_name.empty())
122 return CONTAINER_UNKNOWN;
123 output_format = DetermineContainerFromFileName(output_name);
124 if (output_format == CONTAINER_UNKNOWN) {
125 LOG(ERROR) <<
"Unable to determine output format from '" << output_name
129 return output_format;
132 Status ValidateStreamDescriptor(
bool dump_stream_info,
133 const StreamDescriptor& stream) {
134 if (stream.input.empty()) {
135 return Status(error::INVALID_ARGUMENT,
"Stream input not specified.");
140 if (dump_stream_info && stream.output.empty() &&
141 stream.segment_template.empty()) {
145 if (stream.output.empty() && stream.segment_template.empty()) {
146 return Status(error::INVALID_ARGUMENT,
147 "Streams must specify 'output' or 'segment template'.");
151 if (stream.stream_selector.empty()) {
152 return Status(error::INVALID_ARGUMENT,
153 "Stream stream_selector not specified.");
157 if (stream.segment_template.length()) {
158 Status template_check = ValidateSegmentTemplate(stream.segment_template);
159 if (!template_check.ok()) {
160 return template_check;
166 const MediaContainerName output_format = GetOutputFormat(stream);
168 if (output_format == CONTAINER_UNKNOWN) {
169 return Status(error::INVALID_ARGUMENT,
"Unsupported output format.");
170 }
else if (output_format == MediaContainerName::CONTAINER_MPEG2TS) {
171 if (stream.segment_template.empty()) {
173 error::INVALID_ARGUMENT,
174 "Please specify 'segment_template'. Single file TS output is " 181 if (stream.output.length()) {
182 return Status(error::INVALID_ARGUMENT,
183 "All TS segments must be self-initializing. Stream " 184 "descriptors 'output' or 'init_segment' are not allowed.");
186 }
else if (output_format == CONTAINER_WEBVTT) {
189 if (stream.segment_template.length() && stream.output.length()) {
191 error::INVALID_ARGUMENT,
192 "Segmented WebVTT output cannot have an init segment. Do not specify " 193 "stream descriptors 'output' or 'init_segment' when using " 194 "'segment_template' with WebVtt.");
199 if (stream.segment_template.length() && stream.output.empty()) {
200 return Status(error::INVALID_ARGUMENT,
201 "Please specify 'init_segment'. All non-TS multi-segment " 202 "content must provide an init segment.");
209 Status ValidateParams(
const PackagingParams& packaging_params,
210 const std::vector<StreamDescriptor>& stream_descriptors) {
211 if (!packaging_params.chunking_params.segment_sap_aligned &&
212 packaging_params.chunking_params.subsegment_sap_aligned) {
213 return Status(error::INVALID_ARGUMENT,
214 "Setting segment_sap_aligned to false but " 215 "subsegment_sap_aligned to true is not allowed.");
218 if (stream_descriptors.empty()) {
219 return Status(error::INVALID_ARGUMENT,
220 "Stream descriptors cannot be empty.");
225 const bool on_demand_dash_profile =
226 stream_descriptors.begin()->segment_template.empty();
227 for (
const auto& descriptor : stream_descriptors) {
228 if (on_demand_dash_profile != descriptor.segment_template.empty()) {
229 return Status(error::INVALID_ARGUMENT,
230 "Inconsistent stream descriptor specification: " 231 "segment_template should be specified for none or all " 232 "stream descriptors.");
235 Status stream_check = ValidateStreamDescriptor(
236 packaging_params.test_params.dump_stream_info, descriptor);
238 if (!stream_check.ok()) {
243 if (packaging_params.output_media_info && !on_demand_dash_profile) {
245 return Status(error::UNIMPLEMENTED,
246 "--output_media_info is only supported for on-demand profile " 247 "(not using segment_template).");
253 bool StreamDescriptorCompareFn(
const StreamDescriptor& a,
254 const StreamDescriptor& b) {
255 if (a.input == b.input) {
256 if (a.stream_selector == b.stream_selector) {
259 if (a.trick_play_factor == 0 || b.trick_play_factor == 0) {
260 return a.trick_play_factor == 0;
262 return a.trick_play_factor > b.trick_play_factor;
265 return a.stream_selector < b.stream_selector;
269 return a.input < b.input;
274 class FakeClock :
public base::Clock {
276 base::Time Now()
override {
return base::Time(); }
279 bool StreamInfoToTextMediaInfo(
const StreamDescriptor& stream_descriptor,
280 MediaInfo* text_media_info) {
281 const std::string& language = stream_descriptor.language;
282 const std::string format = DetermineTextFileFormat(stream_descriptor.input);
283 if (format.empty()) {
284 LOG(ERROR) <<
"Failed to determine the text file format for " 285 << stream_descriptor.input;
289 text_media_info->set_media_file_name(stream_descriptor.output);
290 text_media_info->set_container_type(MediaInfo::CONTAINER_TEXT);
292 if (stream_descriptor.bandwidth != 0) {
293 text_media_info->set_bandwidth(stream_descriptor.bandwidth);
298 const int kDefaultTextBandwidth = 256;
299 text_media_info->set_bandwidth(kDefaultTextBandwidth);
302 MediaInfo::TextInfo* text_info = text_media_info->mutable_text_info();
303 text_info->set_format(format);
304 if (!language.empty())
305 text_info->set_language(language);
313 Status CreateDemuxer(
const StreamDescriptor& stream,
314 const PackagingParams& packaging_params,
315 std::shared_ptr<Demuxer>* new_demuxer) {
316 std::shared_ptr<Demuxer> demuxer = std::make_shared<Demuxer>(stream.input);
317 demuxer->set_dump_stream_info(packaging_params.test_params.dump_stream_info);
319 if (packaging_params.decryption_params.key_provider != KeyProvider::kNone) {
320 std::unique_ptr<KeySource> decryption_key_source(
321 CreateDecryptionKeySource(packaging_params.decryption_params));
322 if (!decryption_key_source) {
324 error::INVALID_ARGUMENT,
325 "Must define decryption key source when defining key provider");
327 demuxer->SetKeySource(std::move(decryption_key_source));
330 *new_demuxer = std::move(demuxer);
334 std::shared_ptr<MediaHandler> CreateEncryptionHandler(
335 const PackagingParams& packaging_params,
336 const StreamDescriptor& stream,
337 KeySource* key_source) {
338 if (stream.skip_encryption) {
347 EncryptionParams encryption_params = packaging_params.encryption_params;
352 if (GetOutputFormat(stream) == CONTAINER_MPEG2TS) {
353 VLOG(1) <<
"Use Apple Sample AES encryption for MPEG2TS.";
354 encryption_params.protection_scheme = kAppleSampleAesProtectionScheme;
357 if (!stream.drm_label.empty()) {
358 const std::string& drm_label = stream.drm_label;
359 encryption_params.stream_label_func =
360 [drm_label](
const EncryptionParams::EncryptedStreamAttributes&) {
363 }
else if (!encryption_params.stream_label_func) {
364 const int kDefaultMaxSdPixels = 768 * 576;
365 const int kDefaultMaxHdPixels = 1920 * 1080;
366 const int kDefaultMaxUhd1Pixels = 4096 * 2160;
367 encryption_params.stream_label_func = std::bind(
369 kDefaultMaxHdPixels, kDefaultMaxUhd1Pixels, std::placeholders::_1);
372 return std::make_shared<EncryptionHandler>(encryption_params, key_source);
375 Status CreateMp4ToMp4TextJob(
const StreamDescriptor& stream,
376 const PackagingParams& packaging_params,
377 std::unique_ptr<MuxerListener> muxer_listener,
378 MuxerFactory* muxer_factory,
379 std::shared_ptr<OriginHandler>* root) {
381 std::shared_ptr<Demuxer> demuxer;
383 status.Update(CreateDemuxer(stream, packaging_params, &demuxer));
384 if (!stream.language.empty()) {
385 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
388 std::shared_ptr<MediaHandler> chunker(
389 new ChunkingHandler(packaging_params.chunking_params));
390 std::shared_ptr<Muxer> muxer =
391 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
392 muxer->SetMuxerListener(std::move(muxer_listener));
394 status.Update(chunker->AddHandler(std::move(muxer)));
395 status.Update(demuxer->SetHandler(stream.stream_selector, chunker));
400 Status CreateHlsTextJob(
const StreamDescriptor& stream,
401 const PackagingParams& packaging_params,
402 std::unique_ptr<MuxerListener> muxer_listener,
403 JobManager* job_manager) {
404 DCHECK(muxer_listener);
407 if (stream.segment_template.empty()) {
408 return Status(error::INVALID_ARGUMENT,
409 "Cannot output text (" + stream.input +
410 ") to HLS with no segment template");
413 const float segment_length_in_seconds =
414 packaging_params.chunking_params.segment_duration_in_seconds;
415 const uint64_t segment_length_in_ms =
416 static_cast<uint64_t
>(segment_length_in_seconds * 1000);
421 MuxerOptions muxer_options = CreateMuxerOptions(stream, packaging_params);
422 muxer_options.bandwidth = stream.bandwidth ? stream.bandwidth : 256;
424 std::shared_ptr<WebVttSegmentedOutputHandler> output(
425 new WebVttSegmentedOutputHandler(muxer_options,
426 std::move(muxer_listener)));
428 std::unique_ptr<FileReader> reader;
430 if (!open_status.ok()) {
434 std::shared_ptr<OriginHandler> parser(
435 new WebVttParser(std::move(reader), stream.language));
436 std::shared_ptr<MediaHandler> segmenter(
437 new WebVttSegmenter(segment_length_in_ms));
441 status.Update(segmenter->AddHandler(std::move(output)));
442 status.Update(parser->AddHandler(std::move(segmenter)));
447 job_manager->Add(
"Segmented Text Job", std::move(parser));
451 Status CreateWebVttToMp4TextJob(
const StreamDescriptor& stream,
452 const PackagingParams& packaging_params,
453 std::unique_ptr<MuxerListener> muxer_listener,
454 MuxerFactory* muxer_factory,
455 std::shared_ptr<OriginHandler>* root) {
457 std::unique_ptr<FileReader> reader;
464 std::shared_ptr<OriginHandler> parser(
465 new WebVttParser(std::move(reader), stream.language));
466 std::shared_ptr<MediaHandler> text_to_mp4(
new WebVttToMp4Handler);
467 std::shared_ptr<MediaHandler> chunker(
468 new ChunkingHandler(packaging_params.chunking_params));
469 std::shared_ptr<Muxer> muxer =
470 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
471 muxer->SetMuxerListener(std::move(muxer_listener));
473 status.Update(chunker->AddHandler(std::move(muxer)));
474 status.Update(text_to_mp4->AddHandler(std::move(chunker)));
475 status.Update(parser->AddHandler(std::move(text_to_mp4)));
477 *root = std::move(parser);
482 Status CreateTextJobs(
483 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
484 const PackagingParams& packaging_params,
485 MuxerListenerFactory* muxer_listener_factory,
486 MuxerFactory* muxer_factory,
487 MpdNotifier* mpd_notifier,
488 JobManager* job_manager) {
489 DCHECK(muxer_listener_factory);
491 for (
const StreamDescriptor& stream : streams) {
492 if (GetOutputFormat(stream) == CONTAINER_MOV) {
493 std::unique_ptr<MuxerListener> muxer_listener =
494 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
496 std::shared_ptr<OriginHandler> root;
499 switch (DetermineContainerFromFileName(stream.input)) {
500 case CONTAINER_WEBVTT:
501 status.Update(CreateWebVttToMp4TextJob(stream, packaging_params,
502 std::move(muxer_listener),
503 muxer_factory, &root));
507 status.Update(CreateMp4ToMp4TextJob(stream, packaging_params,
508 std::move(muxer_listener),
509 muxer_factory, &root));
514 Status(error::INVALID_ARGUMENT,
515 "Text output format is not support for " + stream.input));
523 job_manager->Add(
"MP4 text job", std::move(root));
525 std::unique_ptr<MuxerListener> hls_listener =
526 muxer_listener_factory->CreateHlsListener(
527 ToMuxerListenerData(stream));
531 if (stream.segment_template.empty() || !stream.output.empty()) {
532 return Status(error::INVALID_ARGUMENT,
533 "segment_template needs to be specified for HLS text " 534 "output. Single file output is not supported yet.");
538 if (mpd_notifier && !stream.segment_template.empty()) {
539 return Status(error::INVALID_ARGUMENT,
540 "Cannot create text output for MPD with segment output.");
546 Status status = CreateHlsTextJob(stream, packaging_params,
547 std::move(hls_listener), job_manager);
553 if (!stream.output.empty()) {
554 if (!
File::Copy(stream.input.c_str(), stream.output.c_str())) {
557 &error,
"Failed to copy the input file (%s) to output file (%s).",
558 stream.input.c_str(), stream.output.c_str());
559 return Status(error::FILE_FAILURE, error);
562 MediaInfo text_media_info;
563 if (!StreamInfoToTextMediaInfo(stream, &text_media_info)) {
564 return Status(error::INVALID_ARGUMENT,
565 "Could not create media info for stream.");
572 if (mpd_notifier->NotifyNewContainer(text_media_info, &unused)) {
573 mpd_notifier->Flush();
575 return Status(error::PARSER_FAILURE,
576 "Failed to process text file " + stream.input);
580 if (packaging_params.output_media_info) {
582 text_media_info, stream.output + kMediaInfoSuffix);
591 Status CreateAudioVideoJobs(
592 const std::vector<std::reference_wrapper<const StreamDescriptor>>& streams,
593 const PackagingParams& packaging_params,
594 KeySource* encryption_key_source,
595 MuxerListenerFactory* muxer_listener_factory,
596 MuxerFactory* muxer_factory,
597 JobManager* job_manager) {
598 DCHECK(muxer_listener_factory);
599 DCHECK(muxer_factory);
603 std::shared_ptr<Demuxer> demuxer;
607 std::shared_ptr<MediaHandler> chunker;
608 bool is_wvm_file =
false;
611 std::shared_ptr<MediaHandler> replicator;
613 std::string previous_input;
614 std::string previous_selector;
616 for (
const StreamDescriptor& stream : streams) {
618 const bool new_input_file = stream.input != previous_input;
619 if (new_input_file) {
620 Status status = CreateDemuxer(stream, packaging_params, &demuxer);
625 job_manager->Add(
"RemuxJob", demuxer);
631 DetermineContainerFromFileName(stream.input) == CONTAINER_WVM;
634 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
638 if (!stream.language.empty()) {
639 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
642 const bool new_stream =
643 new_input_file || previous_selector != stream.stream_selector;
644 previous_input = stream.input;
645 previous_selector = stream.stream_selector;
649 if (stream.output.empty() && stream.segment_template.empty()) {
654 std::shared_ptr<MediaHandler> ad_cue_generator;
655 if (!packaging_params.ad_cue_generator_params.cue_points.empty()) {
656 ad_cue_generator = std::make_shared<AdCueGenerator>(
657 packaging_params.ad_cue_generator_params);
662 std::make_shared<ChunkingHandler>(packaging_params.chunking_params);
665 std::shared_ptr<MediaHandler> encryptor = CreateEncryptionHandler(
666 packaging_params, stream, encryption_key_source);
668 replicator = std::make_shared<Replicator>();
671 if (ad_cue_generator) {
673 demuxer->SetHandler(stream.stream_selector, ad_cue_generator));
674 status.Update(ad_cue_generator->AddHandler(chunker));
676 status.Update(demuxer->SetHandler(stream.stream_selector, chunker));
679 status.Update(chunker->AddHandler(encryptor));
680 status.Update(encryptor->AddHandler(replicator));
682 status.Update(chunker->AddHandler(replicator));
689 if (!stream.language.empty()) {
690 demuxer->SetLanguageOverride(stream.stream_selector, stream.language);
695 std::unique_ptr<MuxerListener> muxer_listener =
696 muxer_listener_factory->CreateListener(ToMuxerListenerData(stream));
697 std::shared_ptr<Muxer> muxer =
698 muxer_factory->CreateMuxer(GetOutputFormat(stream), stream);
699 muxer->SetMuxerListener(std::move(muxer_listener));
702 return Status(error::INVALID_ARGUMENT,
"Failed to create muxer for " +
704 stream.stream_selector);
707 std::shared_ptr<MediaHandler> trick_play;
708 if (stream.trick_play_factor) {
709 trick_play = std::make_shared<TrickPlayHandler>(stream.trick_play_factor);
714 status.Update(replicator->AddHandler(trick_play));
715 status.Update(trick_play->AddHandler(muxer));
717 status.Update(replicator->AddHandler(muxer));
728 Status CreateAllJobs(
const std::vector<StreamDescriptor>& stream_descriptors,
729 const PackagingParams& packaging_params,
730 MpdNotifier* mpd_notifier,
731 KeySource* encryption_key_source,
732 MuxerListenerFactory* muxer_listener_factory,
733 MuxerFactory* muxer_factory,
734 JobManager* job_manager) {
735 DCHECK(muxer_factory);
736 DCHECK(muxer_listener_factory);
740 std::vector<std::reference_wrapper<const StreamDescriptor>> text_streams;
741 std::vector<std::reference_wrapper<const StreamDescriptor>>
744 for (
const StreamDescriptor& stream : stream_descriptors) {
748 if (stream.stream_selector ==
"text") {
749 text_streams.push_back(stream);
751 audio_video_streams.push_back(stream);
757 std::sort(audio_video_streams.begin(), audio_video_streams.end(),
758 media::StreamDescriptorCompareFn);
761 status.Update(CreateTextJobs(text_streams, packaging_params,
762 muxer_listener_factory, muxer_factory,
763 mpd_notifier, job_manager));
764 status.Update(CreateAudioVideoJobs(
765 audio_video_streams, packaging_params, encryption_key_source,
766 muxer_listener_factory, muxer_factory, job_manager));
773 status.Update(job_manager->InitializeJobs());
781 struct Packager::PackagerInternal {
782 media::FakeClock fake_clock;
783 std::unique_ptr<KeySource> encryption_key_source;
784 std::unique_ptr<MpdNotifier> mpd_notifier;
785 std::unique_ptr<hls::HlsNotifier> hls_notifier;
786 BufferCallbackParams buffer_callback_params;
787 media::JobManager job_manager;
790 Packager::Packager() {}
792 Packager::~Packager() {}
796 const std::vector<StreamDescriptor>& stream_descriptors) {
798 static base::AtExitManager exit;
802 return Status(error::INVALID_ARGUMENT,
"Already initialized.");
805 media::ValidateParams(packaging_params, stream_descriptors);
806 if (!param_check.ok()) {
811 SetPackagerVersionForTesting(
815 std::unique_ptr<PackagerInternal>
internal(
new PackagerInternal);
819 internal->encryption_key_source = CreateEncryptionKeySource(
820 static_cast<media::FourCC>(
823 if (!internal->encryption_key_source)
824 return Status(error::INVALID_ARGUMENT,
"Failed to create key source.");
833 if (internal->buffer_callback_params.write_func) {
835 internal->buffer_callback_params, mpd_params.
mpd_output);
841 const bool on_demand_dash_profile =
842 stream_descriptors.begin()->segment_template.empty();
844 media::GetMpdOptions(on_demand_dash_profile, mpd_params);
846 if (!internal->mpd_notifier->Init()) {
847 LOG(ERROR) <<
"MpdNotifier failed to initialize.";
848 return Status(error::INVALID_ARGUMENT,
849 "Failed to initialize MpdNotifier.");
857 std::vector<StreamDescriptor> streams_for_jobs;
863 if (internal->buffer_callback_params.read_func) {
868 if (internal->buffer_callback_params.write_func) {
872 internal->buffer_callback_params, descriptor.segment_template);
880 error::INVALID_ARGUMENT,
881 "Unknown/invalid language specified: " + descriptor.language);
885 streams_for_jobs.push_back(copy);
895 internal->hls_notifier.get());
897 Status status = media::CreateAllJobs(
898 streams_for_jobs, packaging_params, internal->mpd_notifier.get(),
899 internal->encryption_key_source.get(), &muxer_listener_factory,
900 &muxer_factory, &
internal->job_manager);
906 internal_ = std::move(
internal);
912 return Status(error::INVALID_ARGUMENT,
"Not yet initialized.");
914 Status status = internal_->job_manager.RunJobs();
918 if (internal_->hls_notifier) {
919 if (!internal_->hls_notifier->Flush())
920 return Status(error::INVALID_ARGUMENT,
"Failed to flush Hls.");
922 if (internal_->mpd_notifier) {
923 if (!internal_->mpd_notifier->Flush())
924 return Status(error::INVALID_ARGUMENT,
"Failed to flush Mpd.");
931 LOG(INFO) <<
"Not yet initialized. Return directly.";
934 internal_->job_manager.CancelJobs();
938 return GetPackagerVersion();
946 if (stream_attributes.stream_type ==
947 EncryptionParams::EncryptedStreamAttributes::kAudio)
949 if (stream_attributes.stream_type ==
950 EncryptionParams::EncryptedStreamAttributes::kVideo) {
951 const int pixels = stream_attributes.oneof.video.width *
952 stream_attributes.oneof.video.height;
953 if (pixels <= max_sd_pixels)
955 if (pixels <= max_hd_pixels)
957 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)
static std::string DefaultStreamLabelFunction(int max_sd_pixels, int max_hd_pixels, int max_uhd1_pixels, const EncryptionParams::EncryptedStreamAttributes &stream_attributes)
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.
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.
void Cancel()
Cancel packaging. Note that it has to be called from another thread.