diff --git a/app/fixed_key_encryption_flags.cc b/app/fixed_key_encryption_flags.cc new file mode 100644 index 0000000000..7abf39a77b --- /dev/null +++ b/app/fixed_key_encryption_flags.cc @@ -0,0 +1,31 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines command line flags for fixed key encryption. + +#include "app/fixed_key_encryption_flags.h" + +DEFINE_bool(enable_fixed_key_encryption, + false, + "Enable encryption with fixed key."); +DEFINE_string(key_id, "", "Key id in hex string format."); +DEFINE_string(key, "", "Key in hex string format."); +DEFINE_string(pssh, "", "PSSH in hex string format."); + +static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name, + const std::string& flag_value) { + return FLAGS_enable_fixed_key_encryption ? !flag_value.empty() : true; +} + +static bool dummy_key_id_validator = + google::RegisterFlagValidator(&FLAGS_key_id, + &IsNotEmptyWithFixedKeyEncryption); +static bool dummy_key_validator = + google::RegisterFlagValidator(&FLAGS_key, + &IsNotEmptyWithFixedKeyEncryption); +static bool dummy_pssh_validator = + google::RegisterFlagValidator(&FLAGS_pssh, + &IsNotEmptyWithFixedKeyEncryption); diff --git a/app/fixed_key_encryption_flags.h b/app/fixed_key_encryption_flags.h index 0a898812d6..c6e97bc62e 100644 --- a/app/fixed_key_encryption_flags.h +++ b/app/fixed_key_encryption_flags.h @@ -11,26 +11,9 @@ #include -DEFINE_bool(enable_fixed_key_encryption, - false, - "Enable encryption with fixed key."); -DEFINE_string(key_id, "", "Key id in hex string format."); -DEFINE_string(key, "", "Key in hex string format."); -DEFINE_string(pssh, "", "PSSH in hex string format."); - -static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name, - const std::string& flag_value) { - return FLAGS_enable_fixed_key_encryption ? !flag_value.empty() : true; -} - -static bool dummy_key_id_validator = - google::RegisterFlagValidator(&FLAGS_key_id, - &IsNotEmptyWithFixedKeyEncryption); -static bool dummy_key_validator = - google::RegisterFlagValidator(&FLAGS_key, - &IsNotEmptyWithFixedKeyEncryption); -static bool dummy_pssh_validator = - google::RegisterFlagValidator(&FLAGS_pssh, - &IsNotEmptyWithFixedKeyEncryption); +DECLARE_bool(enable_fixed_key_encryption); +DECLARE_string(key_id); +DECLARE_string(key); +DECLARE_string(pssh); #endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_ diff --git a/app/muxer_flags.cc b/app/muxer_flags.cc new file mode 100644 index 0000000000..18f87b11c3 --- /dev/null +++ b/app/muxer_flags.cc @@ -0,0 +1,67 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines Muxer flags. + +#include "app/muxer_flags.h" + +DEFINE_double(clear_lead, + 10.0, + "Clear lead in seconds if encryption is enabled."); + +DEFINE_bool(single_segment, + true, + "Generate a single segment for the media presentation. This option " + "should be set for on demand profile."); +DEFINE_double(segment_duration, + 10.0f, + "Segment duration in seconds. If single_segment is specified, " + "this parameter sets the duration of a subsegment; otherwise, " + "this parameter sets the duration of a segment. Actual segment " + "durations may not be exactly as requested."); +DEFINE_bool(segment_sap_aligned, + true, + "Force segments to begin with stream access points."); +DEFINE_double(fragment_duration, + 2.0f, + "Fragment duration in seconds. Should not be larger than " + "the segment duration. Actual fragment durations may not be " + "exactly as requested."); +DEFINE_bool(fragment_sap_aligned, + true, + "Force fragments to begin with stream access points. This flag " + "implies segment_sap_aligned."); +DEFINE_bool(normalize_presentation_timestamp, + true, + "Set to true to normalize the presentation timestamps to start" + "from zero."); +DEFINE_int32(num_subsegments_per_sidx, + 1, + "For ISO BMFF only. Set the number of subsegments in each " + "SIDX box. If 0, a single SIDX box is used per segment; if " + "-1, no SIDX box is used; Otherwise, the muxer packs N " + "subsegments in the root SIDX of the segment, with " + "segment_duration/N/fragment_duration fragments per " + "subsegment."); +DEFINE_string(temp_dir, + "", + "Specify a directory in which to store temporary (intermediate) " + " files. Used only if single_segment=true."); + +// Flags for MuxerListener. +DEFINE_bool(output_media_info, + true, + "Create a human readable format of MediaInfo. The output file name " + "will be the name specified by output flag, suffixed with " + "'.media_info'."); +DEFINE_string(scheme_id_uri, + "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", + "This flag only applies if output_media_info is true. This value " + "will be set in MediaInfo if the stream is encrypted. " + "If the stream is encrypted, MPD requires a " + "element which requires the schemeIdUri attribute. " + "Default value is Widevine PSSH system ID, and it is valid only " + "for ISO BMFF."); diff --git a/app/muxer_flags.h b/app/muxer_flags.h index 3313e72df1..4886899234 100644 --- a/app/muxer_flags.h +++ b/app/muxer_flags.h @@ -11,80 +11,19 @@ #include -DEFINE_string(stream, - "video", - "Add the specified stream to muxer. Allowed values, 'video' - " - "the first video stream; or 'audio' - the first audio stream; or " - "zero based stream id."); -DEFINE_double(clear_lead, - 10.0, - "Clear lead in seconds if encryption is enabled."); +DECLARE_double(clear_lead); -DEFINE_bool(single_segment, - true, - "Generate a single segment for the media presentation. This option " - "should be set for on demand profile."); -DEFINE_double(segment_duration, - 10.0f, - "Segment duration in seconds. If single_segment is specified, " - "this parameter sets the duration of a subsegment; otherwise, " - "this parameter sets the duration of a segment. Actual segment " - "durations may not be exactly as requested."); -DEFINE_bool(segment_sap_aligned, - true, - "Force segments to begin with stream access points."); -DEFINE_double(fragment_duration, - 2.0f, - "Fragment duration in seconds. Should not be larger than " - "the segment duration. Actual fragment durations may not be " - "exactly as requested."); -DEFINE_bool(fragment_sap_aligned, - true, - "Force fragments to begin with stream access points. This flag " - "implies segment_sap_aligned."); -DEFINE_bool(normalize_presentation_timestamp, - true, - "Set to true to normalize the presentation timestamps to start" - "from zero."); -DEFINE_int32(num_subsegments_per_sidx, - 1, - "For ISO BMFF only. Set the number of subsegments in each " - "SIDX box. If 0, a single SIDX box is used per segment; if " - "-1, no SIDX box is used; Otherwise, the muxer packs N " - "subsegments in the root SIDX of the segment, with " - "segment_duration/N/fragment_duration fragments per " - "subsegment."); -DEFINE_string(output, - "", - "Output file path. If segment_template is not specified, " - "the muxer generates this single output file with all " - "segments concatenated; Otherwise, it specifies the " - "initialization segment name."); -DEFINE_string(segment_template, - "", - "Output segment name pattern for generated segments. It " - "can furthermore be configured using a subset of " - "SegmentTemplate identifiers: $Number$, $Bandwidth$ and " - "$Time$."); -DEFINE_string(temp_file, - "", - "Specify a temporary file for on demand media file creation. If " - "not specified, a new file will be created in an OS-dependent " - "temporary directory."); +DECLARE_bool(single_segment); +DECLARE_double(segment_duration); +DECLARE_bool(segment_sap_aligned); +DECLARE_double(fragment_duration); +DECLARE_bool(fragment_sap_aligned); +DECLARE_bool(normalize_presentation_timestamp); +DECLARE_int32(num_subsegments_per_sidx); +DECLARE_string(temp_dir); // Flags for MuxerListener. -DEFINE_bool(output_media_info, - true, - "Create a human readable format of MediaInfo. The output file name " - "will be the name specified by output flag, suffixed with " - "'.media_info'."); -DEFINE_string(scheme_id_uri, - "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed", - "This flag only applies if output_media_info is true. This value " - "will be set in MediaInfo if the stream is encrypted. " - "If the stream is encrypted, MPD requires a " - "element which requires the schemeIdUri attribute. " - "Default value is Widevine PSSH system ID, and it is valid only " - "for ISO BMFF."); +DECLARE_bool(output_media_info); +DECLARE_string(scheme_id_uri); #endif // APP_MUXER_FLAGS_H_ diff --git a/app/packager_main.cc b/app/packager_common.cc similarity index 55% rename from app/packager_main.cc rename to app/packager_common.cc index 6da383466f..fbf314d74b 100644 --- a/app/packager_main.cc +++ b/app/packager_common.cc @@ -10,27 +10,18 @@ #include "app/fixed_key_encryption_flags.h" #include "app/muxer_flags.h" #include "app/widevine_encryption_flags.h" -#include "base/file_util.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "media/base/demuxer.h" #include "media/base/media_stream.h" +#include "media/base/muxer.h" #include "media/base/muxer_options.h" #include "media/base/request_signer.h" #include "media/base/stream_info.h" #include "media/base/widevine_encryption_key_source.h" -#include "media/event/vod_media_info_dump_muxer_listener.h" #include "media/file/file.h" -#include "media/file/file_closer.h" -#include "media/formats/mp4/mp4_muxer.h" DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info."); -namespace { -const char kUsage[] = - "Packager driver program. Sample Usage:\n%s [flags]"; -} // namespace namespace media { @@ -76,7 +67,7 @@ scoped_ptr CreateEncryptionKeySource() { } encryption_key_source.reset(new WidevineEncryptionKeySource( - FLAGS_server_url, + FLAGS_key_server_url, FLAGS_content_id, signer.Pass(), FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0)); @@ -98,19 +89,7 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) { muxer_options->normalize_presentation_timestamp = FLAGS_normalize_presentation_timestamp; muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; - muxer_options->output_file_name = FLAGS_output; - muxer_options->segment_template = FLAGS_segment_template; - muxer_options->temp_file_name = FLAGS_temp_file; - - // Create a temp file if needed. - if (muxer_options->single_segment && muxer_options->temp_file_name.empty()) { - base::FilePath path; - if (!base::CreateTemporaryFile(&path)) { - LOG(ERROR) << "Failed to create a temporary file."; - return false; - } - muxer_options->temp_file_name = path.value(); - } + muxer_options->temp_dir = FLAGS_temp_dir; return true; } @@ -130,20 +109,22 @@ MediaStream* FindFirstAudioStream(const std::vector& streams) { return FindFirstStreamOfType(streams, kStreamAudio); } -bool AddStreamToMuxer(const std::vector& streams, Muxer* muxer) { +bool AddStreamToMuxer(const std::vector& streams, + const std::string& stream_selector, + Muxer* muxer) { DCHECK(muxer); MediaStream* stream = NULL; - if (FLAGS_stream == "video") { + if (stream_selector == "video") { stream = FindFirstVideoStream(streams); - } else if (FLAGS_stream == "audio") { + } else if (stream_selector == "audio") { stream = FindFirstAudioStream(streams); } else { - // Expect FLAGS_stream to be a zero based stream id. + // Expect stream_selector to be a zero based stream id. size_t stream_id; - if (!base::StringToSizeT(FLAGS_stream, &stream_id) || + if (!base::StringToSizeT(stream_selector, &stream_id) || stream_id >= streams.size()) { - LOG(ERROR) << "Invalid argument --stream=" << FLAGS_stream << "; " + LOG(ERROR) << "Invalid argument --stream=" << stream_selector << "; " << "should be 'audio', 'video', or a number within [0, " << streams.size() - 1 << "]."; return false; @@ -152,93 +133,14 @@ bool AddStreamToMuxer(const std::vector& streams, Muxer* muxer) { DCHECK(stream); } - // This could occur only if FLAGS_stream=audio|video and the corresponding + // This could occur only if stream_selector=audio|video and the corresponding // stream does not exist in the input. if (!stream) { - LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input."; + LOG(ERROR) << "No " << stream_selector << " stream found in the input."; return false; } muxer->AddStream(stream); return true; } -bool RunPackager(const std::string& input) { - Status status; - - // Setup and initialize Demuxer. - Demuxer demuxer(input, NULL); - status = demuxer.Initialize(); - if (!status.ok()) { - LOG(ERROR) << "Demuxer failed to initialize: " << status.ToString(); - return false; - } - - if (FLAGS_dump_stream_info) - DumpStreamInfo(demuxer.streams()); - - if (FLAGS_output.empty()) { - if (!FLAGS_dump_stream_info) - LOG(WARNING) << "No output specified. Exiting."; - return true; - } - - // Setup muxer. - MuxerOptions muxer_options; - if (!GetMuxerOptions(&muxer_options)) - return false; - - scoped_ptr muxer(new mp4::MP4Muxer(muxer_options)); - scoped_ptr muxer_listener; - scoped_ptr mpd_file; - if (FLAGS_output_media_info) { - std::string output_mpd_file_name = FLAGS_output + ".media_info"; - mpd_file.reset(File::Open(output_mpd_file_name.c_str(), "w")); - if (!mpd_file) { - LOG(ERROR) << "Failed to open " << output_mpd_file_name; - return false; - } - - scoped_ptr media_info_muxer_listener( - new event::VodMediaInfoDumpMuxerListener(mpd_file.get())); - media_info_muxer_listener->SetContentProtectionSchemeIdUri( - FLAGS_scheme_id_uri); - muxer_listener = media_info_muxer_listener.Pass(); - muxer->SetMuxerListener(muxer_listener.get()); - } - - if (!AddStreamToMuxer(demuxer.streams(), muxer.get())) - return false; - - scoped_ptr encryption_key_source; - if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) { - encryption_key_source = CreateEncryptionKeySource(); - if (!encryption_key_source) - return false; - muxer->SetEncryptionKeySource(encryption_key_source.get(), - FLAGS_max_sd_pixels, - FLAGS_clear_lead, - FLAGS_crypto_period_duration); - } - - // Start remuxing process. - status = demuxer.Run(); - if (!status.ok()) { - LOG(ERROR) << "Remuxing failed: " << status.ToString(); - return false; - } - - printf("Packaging completed successfully.\n"); - return true; -} - } // namespace media - -int main(int argc, char** argv) { - google::SetUsageMessage(base::StringPrintf(kUsage, argv[0])); - google::ParseCommandLineFlags(&argc, &argv, true); - if (argc < 2) { - google::ShowUsageWithFlags(argv[0]); - return 1; - } - return media::RunPackager(argv[1]) ? 0 : 1; -} diff --git a/app/packager_common.h b/app/packager_common.h new file mode 100644 index 0000000000..40517b8898 --- /dev/null +++ b/app/packager_common.h @@ -0,0 +1,52 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Functionality common to single and multiple file packager. + +#ifndef APP_PACKAGER_COMMON_H_ +#define APP_PACKAGER_COMMON_H_ + +#include +#include +#include + +#include "base/memory/scoped_ptr.h" + +DECLARE_bool(dump_stream_info); + +namespace media { + +class EncryptionKeySource; +class MediaInfo; +class MediaStream; +class Muxer; +class MuxerOptions; + +/// Print all the stream info for the provided strings to standard output. +void DumpStreamInfo(const std::vector& streams); + +/// Create EncryptionKeySource based on provided command line options. +/// @return A scoped_ptr containig a new EncryptionKeySource, or NULL if +/// encryption is not required. +scoped_ptr CreateEncryptionKeySource(); + +/// Fill MuxerOptions members using provided command line options. +bool GetMuxerOptions(MuxerOptions* muxer_options); + +/// Select and add a stream from a provided set to a muxer. +/// @param streams contains the set of MediaStreams from which to select. +/// @param stream_selector is a string containing one of the following values: +/// "audio" to select the first audio track, "video" to select the first +/// video track, or a decimal number indicating which track number to +/// select (start at "1"). +/// @return true if successful, false otherwise. +bool AddStreamToMuxer(const std::vector& streams, + const std::string& stream_selector, + Muxer* muxer); + +} // namespace media + +#endif // APP_PACKAGER_COMMON_H_ diff --git a/app/single_muxer_flags.cc b/app/single_muxer_flags.cc new file mode 100644 index 0000000000..bd691a6f7b --- /dev/null +++ b/app/single_muxer_flags.cc @@ -0,0 +1,27 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines Muxer flags. + +#include "app/muxer_flags.h" + +DEFINE_string(stream, + "video", + "Add the specified stream to muxer. Allowed values, 'video' - " + "the first video stream; or 'audio' - the first audio stream; or " + "zero based stream id."); +DEFINE_string(output, + "", + "Output file path. If segment_template is not specified, " + "the muxer generates this single output file with all " + "segments concatenated; Otherwise, it specifies the " + "initialization segment name."); +DEFINE_string(segment_template, + "", + "Output segment name pattern for generated segments. It " + "can furthermore be configured using a subset of " + "SegmentTemplate identifiers: $Number$, $Bandwidth$ and " + "$Time$."); diff --git a/app/single_muxer_flags.h b/app/single_muxer_flags.h new file mode 100644 index 0000000000..e40f43de05 --- /dev/null +++ b/app/single_muxer_flags.h @@ -0,0 +1,18 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines Single muxer flags. + +#ifndef APP_SINGLE_MUXER_FLAGS_H_ +#define APP_SINGLE_MUXER_FLAGS_H_ + +#include + +DECLARE_string(stream); +DECLARE_string(output); +DECLARE_string(segment_template); + +#endif // APP_SINGLE_MUXER_FLAGS_H_ diff --git a/app/single_packager_main.cc b/app/single_packager_main.cc new file mode 100644 index 0000000000..2a62b97150 --- /dev/null +++ b/app/single_packager_main.cc @@ -0,0 +1,123 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include + +#include "app/fixed_key_encryption_flags.h" +#include "app/packager_common.h" +#include "app/muxer_flags.h" +#include "app/single_muxer_flags.h" +#include "app/widevine_encryption_flags.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "media/base/demuxer.h" +#include "media/base/encryption_key_source.h" +#include "media/base/muxer_options.h" +#include "media/event/vod_media_info_dump_muxer_listener.h" +#include "media/file/file.h" +#include "media/file/file_closer.h" +#include "media/formats/mp4/mp4_muxer.h" + +namespace { +const char kUsage[] = + "Packager driver program. Sample Usage:\n%s [flags]"; +} // namespace + +namespace media { + +bool GetSingleMuxerOptions(MuxerOptions* muxer_options) { + DCHECK(muxer_options); + + if (!GetMuxerOptions(muxer_options)) + return false; + + muxer_options->output_file_name = FLAGS_output; + muxer_options->segment_template = FLAGS_segment_template; + + return true; +} + +bool RunPackager(const std::string& input) { + Status status; + + // Setup and initialize Demuxer. + Demuxer demuxer(input, NULL); + status = demuxer.Initialize(); + if (!status.ok()) { + LOG(ERROR) << "Demuxer failed to initialize: " << status.ToString(); + return false; + } + + if (FLAGS_dump_stream_info) + DumpStreamInfo(demuxer.streams()); + + if (FLAGS_output.empty()) { + if (!FLAGS_dump_stream_info) + LOG(WARNING) << "No output specified. Exiting."; + return true; + } + + // Setup muxer. + MuxerOptions muxer_options; + if (!GetSingleMuxerOptions(&muxer_options)) + return false; + + scoped_ptr muxer(new mp4::MP4Muxer(muxer_options)); + scoped_ptr muxer_listener; + scoped_ptr mpd_file; + if (FLAGS_output_media_info) { + std::string output_mpd_file_name = FLAGS_output + ".media_info"; + mpd_file.reset(File::Open(output_mpd_file_name.c_str(), "w")); + if (!mpd_file) { + LOG(ERROR) << "Failed to open " << output_mpd_file_name; + return false; + } + + scoped_ptr media_info_muxer_listener( + new event::VodMediaInfoDumpMuxerListener(mpd_file.get())); + media_info_muxer_listener->SetContentProtectionSchemeIdUri( + FLAGS_scheme_id_uri); + muxer_listener = media_info_muxer_listener.Pass(); + muxer->SetMuxerListener(muxer_listener.get()); + } + + if (!AddStreamToMuxer(demuxer.streams(), FLAGS_stream, muxer.get())) + return false; + + scoped_ptr encryption_key_source; + if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) { + encryption_key_source = CreateEncryptionKeySource(); + if (!encryption_key_source) + return false; + muxer->SetEncryptionKeySource(encryption_key_source.get(), + FLAGS_max_sd_pixels, + FLAGS_clear_lead, + FLAGS_crypto_period_duration); + } + + // Start remuxing process. + status = demuxer.Run(); + if (!status.ok()) { + LOG(ERROR) << "Remuxing failed: " << status.ToString(); + return false; + } + + printf("Packaging completed successfully.\n"); + return true; +} + +} // namespace media + +int main(int argc, char** argv) { + google::SetUsageMessage(base::StringPrintf(kUsage, argv[0])); + google::ParseCommandLineFlags(&argc, &argv, true); + if (argc < 2) { + google::ShowUsageWithFlags(argv[0]); + return 1; + } + return media::RunPackager(argv[1]) ? 0 : 1; +} diff --git a/app/widevine_encryption_flags.cc b/app/widevine_encryption_flags.cc new file mode 100644 index 0000000000..a69ef465ac --- /dev/null +++ b/app/widevine_encryption_flags.cc @@ -0,0 +1,98 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines command line flags for widevine_encryption. + +#include "app/widevine_encryption_flags.h" + +#include "base/strings/string_number_conversions.h" + +DEFINE_bool(enable_widevine_encryption, + false, + "Enable encryption with Widevine license server/proxy. User should " + "provide either AES signing key (--aes_signing_key, " + "--aes_signing_iv) or RSA signing key (--rsa_signing_key_path)."); +DEFINE_string(key_server_url, "", "Key server url."); +DEFINE_string(content_id, "", "Content Id."); +DEFINE_int32(max_sd_pixels, + 768 * 576, + "If the video track has more pixels per frame than max_sd_pixels, " + "it is considered as HD, SD otherwise. Default: 768 * 576."); +DEFINE_string(signer, "", "The name of the signer."); +DEFINE_string(aes_signing_key, + "", + "AES signing key in hex string. --aes_signing_iv is required. " + "Exclusive with --rsa_signing_key_path."); +DEFINE_string(aes_signing_iv, + "", + "AES signing iv in hex string."); +DEFINE_string(rsa_signing_key_path, + "", + "Stores PKCS#1 RSA private key for request signing. Exclusive " + "with --aes_signing_key."); +DEFINE_int32(crypto_period_duration, + 0, + "Crypto period duration in seconds. If it is non-zero, key " + "rotation is enabled."); + +namespace { + +static bool IsNotEmptyWithWidevineEncryption(const char* flag_name, + const std::string& flag_value) { + return FLAGS_enable_widevine_encryption ? !flag_value.empty() : true; +} + +static bool IsPositive(const char* flag_name, int flag_value) { + return flag_value > 0; +} + +static bool VerifyAesRsaKey(const char* flag_name, + const std::string& flag_value) { + if (!FLAGS_enable_widevine_encryption) + return true; + const std::string flag_name_str = flag_name; + if (flag_name_str == "aes_signing_iv") { + if (!FLAGS_aes_signing_key.empty() && flag_value.empty()) { + fprintf(stderr, + "ERROR: --aes_signing_iv is required for --aes_signing_key.\n"); + return false; + } + } else if (flag_name_str == "rsa_signing_key_path") { + if (FLAGS_aes_signing_key.empty() && flag_value.empty()) { + fprintf(stderr, + "ERROR: --aes_signing_key or --rsa_signing_key_path is " + "required.\n"); + return false; + } + if (!FLAGS_aes_signing_key.empty() && !flag_value.empty()) { + fprintf(stderr, + "ERROR: --aes_signing_key and --rsa_signing_key_path are " + "exclusive.\n"); + return false; + } + } + return true; +} + +bool dummy_key_server_url_validator = + google::RegisterFlagValidator(&FLAGS_key_server_url, + &IsNotEmptyWithWidevineEncryption); +bool dummy_content_id_validator = + google::RegisterFlagValidator(&FLAGS_content_id, + &IsNotEmptyWithWidevineEncryption); +bool dummy_track_type_validator = + google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive); +bool dummy_signer_validator = + google::RegisterFlagValidator(&FLAGS_signer, + &IsNotEmptyWithWidevineEncryption); +bool dummy_aes_iv_validator = + google::RegisterFlagValidator(&FLAGS_aes_signing_iv, + &VerifyAesRsaKey); +bool dummy_rsa_key_file_validator = + google::RegisterFlagValidator(&FLAGS_rsa_signing_key_path, + &VerifyAesRsaKey); + +} // anonymous namespace diff --git a/app/widevine_encryption_flags.h b/app/widevine_encryption_flags.h index d1bdd756e3..3c7cb1e2cc 100644 --- a/app/widevine_encryption_flags.h +++ b/app/widevine_encryption_flags.h @@ -11,88 +11,14 @@ #include -#include "base/strings/string_number_conversions.h" +DECLARE_bool(enable_widevine_encryption); +DECLARE_string(key_server_url); +DECLARE_string(content_id); +DECLARE_int32(max_sd_pixels); +DECLARE_string(signer); +DECLARE_string(aes_signing_key); +DECLARE_string(aes_signing_iv); +DECLARE_string(rsa_signing_key_path); +DECLARE_int32(crypto_period_duration); -DEFINE_bool(enable_widevine_encryption, - false, - "Enable encryption with Widevine license server/proxy. User should " - "provide either AES signing key (--aes_signing_key, " - "--aes_signing_iv) or RSA signing key (--rsa_signing_key_path)."); -DEFINE_string(server_url, "", "License server url."); -DEFINE_string(content_id, "", "Content Id."); -DEFINE_int32(max_sd_pixels, - 768 * 576, - "If the video track has more pixels per frame than max_sd_pixels, " - "it is considered as HD, SD otherwise. Default: 768 * 576."); -DEFINE_string(signer, "", "The name of the signer."); -DEFINE_string(aes_signing_key, - "", - "AES signing key in hex string. --aes_signing_iv is required. " - "Exclusive with --rsa_signing_key_path."); -DEFINE_string(aes_signing_iv, - "", - "AES signing iv in hex string."); -DEFINE_string(rsa_signing_key_path, - "", - "Stores PKCS#1 RSA private key for request signing. Exclusive " - "with --aes_signing_key."); -DEFINE_int32(crypto_period_duration, - 0, - "Crypto period duration in seconds. If it is non-zero, key " - "rotation is enabled."); - -static bool IsNotEmptyWithWidevineEncryption(const char* flag_name, - const std::string& flag_value) { - return FLAGS_enable_widevine_encryption ? !flag_value.empty() : true; -} - -static bool IsPositive(const char* flag_name, int flag_value) { - return flag_value > 0; -} - -static bool VerifyAesRsaKey(const char* flag_name, - const std::string& flag_value) { - if (!FLAGS_enable_widevine_encryption) - return true; - const std::string flag_name_str = flag_name; - if (flag_name_str == "aes_signing_iv") { - if (!FLAGS_aes_signing_key.empty() && flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_iv is required for --aes_signing_key.\n"); - return false; - } - } else if (flag_name_str == "rsa_signing_key_path") { - if (FLAGS_aes_signing_key.empty() && flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_key or --rsa_signing_key_path is " - "required.\n"); - return false; - } - if (!FLAGS_aes_signing_key.empty() && !flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_key and --rsa_signing_key_path are " - "exclusive.\n"); - return false; - } - } - return true; -} - -static bool dummy_server_url_validator = - google::RegisterFlagValidator(&FLAGS_server_url, - &IsNotEmptyWithWidevineEncryption); -static bool dummy_content_id_validator = - google::RegisterFlagValidator(&FLAGS_content_id, - &IsNotEmptyWithWidevineEncryption); -static bool dummy_track_type_validator = - google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive); -static bool dummy_signer_validator = - google::RegisterFlagValidator(&FLAGS_signer, - &IsNotEmptyWithWidevineEncryption); -static bool dummy_aes_iv_validator = - google::RegisterFlagValidator(&FLAGS_aes_signing_iv, - &VerifyAesRsaKey); -static bool dummy_rsa_key_file_validator = - google::RegisterFlagValidator(&FLAGS_rsa_signing_key_path, - &VerifyAesRsaKey); #endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_ diff --git a/media/base/muxer_options.h b/media/base/muxer_options.h index 0046d843bc..4f8793090d 100644 --- a/media/base/muxer_options.h +++ b/media/base/muxer_options.h @@ -60,8 +60,8 @@ struct MuxerOptions { /// Optional. std::string segment_template; - /// Specify the temporary file for on demand media file creation. - std::string temp_file_name; + /// Specify temporary directory for intermediate files. + std::string temp_dir; }; } // namespace media diff --git a/media/event/vod_media_info_dump_muxer_listener_unittest.cc b/media/event/vod_media_info_dump_muxer_listener_unittest.cc index 88c7dc4425..24451331ad 100644 --- a/media/event/vod_media_info_dump_muxer_listener_unittest.cc +++ b/media/event/vod_media_info_dump_muxer_listener_unittest.cc @@ -117,7 +117,7 @@ void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) { muxer_options->num_subsegments_per_sidx = 0; muxer_options->output_file_name = "test_output_file_name.mp4"; muxer_options->segment_template.clear(); - muxer_options->temp_file_name.clear(); + muxer_options->temp_dir.clear(); } void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) { diff --git a/media/formats/mp4/single_segment_segmenter.cc b/media/formats/mp4/single_segment_segmenter.cc index 816775c2a0..96668d7f64 100644 --- a/media/formats/mp4/single_segment_segmenter.cc +++ b/media/formats/mp4/single_segment_segmenter.cc @@ -6,6 +6,7 @@ #include "media/formats/mp4/single_segment_segmenter.h" +#include "base/file_util.h" #include "media/base/buffer_writer.h" #include "media/base/media_stream.h" #include "media/base/muxer_options.h" @@ -37,11 +38,20 @@ bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) { } Status SingleSegmentSegmenter::DoInitialize() { - temp_file_.reset(File::Open(options().temp_file_name.c_str(), "w")); + base::FilePath temp_file_path; + if (options().temp_dir.empty() ? + !base::CreateTemporaryFile(&temp_file_path) : + !base::CreateTemporaryFileInDir(base::FilePath(options().temp_dir), + &temp_file_path)) { + return Status(error::FILE_FAILURE, "Unable to create temporary file."); + } + temp_file_name_ = temp_file_path.value(); + + temp_file_.reset(File::Open(temp_file_name_.c_str(), "w")); return temp_file_ ? Status::OK : Status(error::FILE_FAILURE, - "Cannot open file to write " + options().temp_file_name); + "Cannot open file to write " + temp_file_name_); } Status SingleSegmentSegmenter::DoFinalize() { @@ -53,7 +63,7 @@ Status SingleSegmentSegmenter::DoFinalize() { // Close the temp file to prepare for reading later. if (!temp_file_.release()->Close()) { return Status(error::FILE_FAILURE, - "Cannot close the temp file " + options().temp_file_name); + "Cannot close the temp file " + temp_file_name_); } scoped_ptr file( @@ -74,10 +84,10 @@ Status SingleSegmentSegmenter::DoFinalize() { // Load the temp file and write to output file. scoped_ptr temp_file( - File::Open(options().temp_file_name.c_str(), "r")); + File::Open(temp_file_name_.c_str(), "r")); if (temp_file == NULL) { return Status(error::FILE_FAILURE, - "Cannot open file to read " + options().temp_file_name); + "Cannot open file to read " + temp_file_name_); } const int kBufSize = 0x40000; // 256KB. @@ -86,7 +96,7 @@ Status SingleSegmentSegmenter::DoFinalize() { int64 size = temp_file->Read(buf.get(), kBufSize); if (size <= 0) { return Status(error::FILE_FAILURE, - "Failed to read file " + options().temp_file_name); + "Failed to read file " + temp_file_name_); } int64 size_written = file->Write(buf.get(), size); if (size_written != size) { diff --git a/media/formats/mp4/single_segment_segmenter.h b/media/formats/mp4/single_segment_segmenter.h index 2c7f655c4b..48de80aa65 100644 --- a/media/formats/mp4/single_segment_segmenter.h +++ b/media/formats/mp4/single_segment_segmenter.h @@ -44,6 +44,7 @@ class SingleSegmentSegmenter : public Segmenter { virtual Status DoFinalizeSegment() OVERRIDE; scoped_ptr vod_sidx_; + std::string temp_file_name_; scoped_ptr temp_file_; DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter); diff --git a/media/test/packager_test.cc b/media/test/packager_test.cc index 693e77b5b6..25a7b9aff9 100644 --- a/media/test/packager_test.cc +++ b/media/test/packager_test.cc @@ -140,7 +140,7 @@ MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output, options.output_file_name = GetFullPath(output); options.segment_template = GetFullPath(kSegmentTemplate); - options.temp_file_name = GetFullPath(output + ".temp"); + options.temp_dir = test_directory_.value(); return options; } diff --git a/packager.gyp b/packager.gyp index db3596010b..7928daed49 100644 --- a/packager.gyp +++ b/packager.gyp @@ -16,12 +16,19 @@ }, 'targets': [ { - 'target_name': 'packager_main', + 'target_name': 'single_packager', 'type': 'executable', 'sources': [ + 'app/fixed_key_encryption_flags.cc', 'app/fixed_key_encryption_flags.h', + 'app/packager_common.cc', + 'app/packager_common.h', + 'app/muxer_flags.cc', 'app/muxer_flags.h', - 'app/packager_main.cc', + 'app/single_muxer_flags.cc', + 'app/single_muxer_flags.h', + 'app/single_packager_main.cc', + 'app/widevine_encryption_flags.cc', 'app/widevine_encryption_flags.h', ], 'dependencies': [