Renamed packager_main to single_packager.

Did some re-factoring to share code with upcoming (multi stream) packager.

Change-Id: I2b3845e48ba6aa63a95ecc276abcb52c8355d8d5
This commit is contained in:
Thomas Inskip 2014-05-08 14:02:36 -07:00
parent beaea71946
commit 7fe5b5171a
17 changed files with 483 additions and 299 deletions

View File

@ -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);

View File

@ -11,26 +11,9 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
DEFINE_bool(enable_fixed_key_encryption, DECLARE_bool(enable_fixed_key_encryption);
false, DECLARE_string(key_id);
"Enable encryption with fixed key."); DECLARE_string(key);
DEFINE_string(key_id, "", "Key id in hex string format."); DECLARE_string(pssh);
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);
#endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_ #endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_

67
app/muxer_flags.cc Normal file
View File

@ -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 <ContentProtection> "
"element which requires the schemeIdUri attribute. "
"Default value is Widevine PSSH system ID, and it is valid only "
"for ISO BMFF.");

View File

@ -11,80 +11,19 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
DEFINE_string(stream, DECLARE_double(clear_lead);
"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.");
DEFINE_bool(single_segment, DECLARE_bool(single_segment);
true, DECLARE_double(segment_duration);
"Generate a single segment for the media presentation. This option " DECLARE_bool(segment_sap_aligned);
"should be set for on demand profile."); DECLARE_double(fragment_duration);
DEFINE_double(segment_duration, DECLARE_bool(fragment_sap_aligned);
10.0f, DECLARE_bool(normalize_presentation_timestamp);
"Segment duration in seconds. If single_segment is specified, " DECLARE_int32(num_subsegments_per_sidx);
"this parameter sets the duration of a subsegment; otherwise, " DECLARE_string(temp_dir);
"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.");
// Flags for MuxerListener. // Flags for MuxerListener.
DEFINE_bool(output_media_info, DECLARE_bool(output_media_info);
true, DECLARE_string(scheme_id_uri);
"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 <ContentProtection> "
"element which requires the schemeIdUri attribute. "
"Default value is Widevine PSSH system ID, and it is valid only "
"for ISO BMFF.");
#endif // APP_MUXER_FLAGS_H_ #endif // APP_MUXER_FLAGS_H_

View File

@ -10,27 +10,18 @@
#include "app/fixed_key_encryption_flags.h" #include "app/fixed_key_encryption_flags.h"
#include "app/muxer_flags.h" #include "app/muxer_flags.h"
#include "app/widevine_encryption_flags.h" #include "app/widevine_encryption_flags.h"
#include "base/file_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_number_conversions.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/media_stream.h"
#include "media/base/muxer.h"
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
#include "media/base/request_signer.h" #include "media/base/request_signer.h"
#include "media/base/stream_info.h" #include "media/base/stream_info.h"
#include "media/base/widevine_encryption_key_source.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.h"
#include "media/file/file_closer.h"
#include "media/formats/mp4/mp4_muxer.h"
DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info."); DEFINE_bool(dump_stream_info, false, "Dump demuxed stream info.");
namespace {
const char kUsage[] =
"Packager driver program. Sample Usage:\n%s <input> [flags]";
} // namespace
namespace media { namespace media {
@ -76,7 +67,7 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
} }
encryption_key_source.reset(new WidevineEncryptionKeySource( encryption_key_source.reset(new WidevineEncryptionKeySource(
FLAGS_server_url, FLAGS_key_server_url,
FLAGS_content_id, FLAGS_content_id,
signer.Pass(), signer.Pass(),
FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0)); FLAGS_crypto_period_duration == 0 ? kDisableKeyRotation : 0));
@ -98,19 +89,7 @@ bool GetMuxerOptions(MuxerOptions* muxer_options) {
muxer_options->normalize_presentation_timestamp = muxer_options->normalize_presentation_timestamp =
FLAGS_normalize_presentation_timestamp; FLAGS_normalize_presentation_timestamp;
muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; muxer_options->num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx;
muxer_options->output_file_name = FLAGS_output; muxer_options->temp_dir = FLAGS_temp_dir;
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();
}
return true; return true;
} }
@ -130,20 +109,22 @@ MediaStream* FindFirstAudioStream(const std::vector<MediaStream*>& streams) {
return FindFirstStreamOfType(streams, kStreamAudio); return FindFirstStreamOfType(streams, kStreamAudio);
} }
bool AddStreamToMuxer(const std::vector<MediaStream*>& streams, Muxer* muxer) { bool AddStreamToMuxer(const std::vector<MediaStream*>& streams,
const std::string& stream_selector,
Muxer* muxer) {
DCHECK(muxer); DCHECK(muxer);
MediaStream* stream = NULL; MediaStream* stream = NULL;
if (FLAGS_stream == "video") { if (stream_selector == "video") {
stream = FindFirstVideoStream(streams); stream = FindFirstVideoStream(streams);
} else if (FLAGS_stream == "audio") { } else if (stream_selector == "audio") {
stream = FindFirstAudioStream(streams); stream = FindFirstAudioStream(streams);
} else { } 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; size_t stream_id;
if (!base::StringToSizeT(FLAGS_stream, &stream_id) || if (!base::StringToSizeT(stream_selector, &stream_id) ||
stream_id >= streams.size()) { 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, " << "should be 'audio', 'video', or a number within [0, "
<< streams.size() - 1 << "]."; << streams.size() - 1 << "].";
return false; return false;
@ -152,93 +133,14 @@ bool AddStreamToMuxer(const std::vector<MediaStream*>& streams, Muxer* muxer) {
DCHECK(stream); 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. // stream does not exist in the input.
if (!stream) { if (!stream) {
LOG(ERROR) << "No " << FLAGS_stream << " stream found in the input."; LOG(ERROR) << "No " << stream_selector << " stream found in the input.";
return false; return false;
} }
muxer->AddStream(stream); muxer->AddStream(stream);
return true; 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> muxer(new mp4::MP4Muxer(muxer_options));
scoped_ptr<event::MuxerListener> muxer_listener;
scoped_ptr<File, FileCloser> 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<event::VodMediaInfoDumpMuxerListener> 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<EncryptionKeySource> 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 } // 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;
}

52
app/packager_common.h Normal file
View File

@ -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 <gflags/gflags.h>
#include <string>
#include <vector>
#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<MediaStream*>& 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<EncryptionKeySource> 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<MediaStream*>& streams,
const std::string& stream_selector,
Muxer* muxer);
} // namespace media
#endif // APP_PACKAGER_COMMON_H_

27
app/single_muxer_flags.cc Normal file
View File

@ -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$.");

18
app/single_muxer_flags.h Normal file
View File

@ -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 <gflags/gflags.h>
DECLARE_string(stream);
DECLARE_string(output);
DECLARE_string(segment_template);
#endif // APP_SINGLE_MUXER_FLAGS_H_

123
app/single_packager_main.cc Normal file
View File

@ -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 <iostream>
#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 <input> [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> muxer(new mp4::MP4Muxer(muxer_options));
scoped_ptr<event::MuxerListener> muxer_listener;
scoped_ptr<File, FileCloser> 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<event::VodMediaInfoDumpMuxerListener> 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<EncryptionKeySource> 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;
}

View File

@ -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

View File

@ -11,88 +11,14 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
#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_ #endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_

View File

@ -60,8 +60,8 @@ struct MuxerOptions {
/// Optional. /// Optional.
std::string segment_template; std::string segment_template;
/// Specify the temporary file for on demand media file creation. /// Specify temporary directory for intermediate files.
std::string temp_file_name; std::string temp_dir;
}; };
} // namespace media } // namespace media

View File

@ -117,7 +117,7 @@ void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
muxer_options->num_subsegments_per_sidx = 0; muxer_options->num_subsegments_per_sidx = 0;
muxer_options->output_file_name = "test_output_file_name.mp4"; muxer_options->output_file_name = "test_output_file_name.mp4";
muxer_options->segment_template.clear(); muxer_options->segment_template.clear();
muxer_options->temp_file_name.clear(); muxer_options->temp_dir.clear();
} }
void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) { void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) {

View File

@ -6,6 +6,7 @@
#include "media/formats/mp4/single_segment_segmenter.h" #include "media/formats/mp4/single_segment_segmenter.h"
#include "base/file_util.h"
#include "media/base/buffer_writer.h" #include "media/base/buffer_writer.h"
#include "media/base/media_stream.h" #include "media/base/media_stream.h"
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
@ -37,11 +38,20 @@ bool SingleSegmentSegmenter::GetIndexRange(size_t* offset, size_t* size) {
} }
Status SingleSegmentSegmenter::DoInitialize() { 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_ return temp_file_
? Status::OK ? Status::OK
: Status(error::FILE_FAILURE, : Status(error::FILE_FAILURE,
"Cannot open file to write " + options().temp_file_name); "Cannot open file to write " + temp_file_name_);
} }
Status SingleSegmentSegmenter::DoFinalize() { Status SingleSegmentSegmenter::DoFinalize() {
@ -53,7 +63,7 @@ Status SingleSegmentSegmenter::DoFinalize() {
// Close the temp file to prepare for reading later. // Close the temp file to prepare for reading later.
if (!temp_file_.release()->Close()) { if (!temp_file_.release()->Close()) {
return Status(error::FILE_FAILURE, 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, FileCloser> file( scoped_ptr<File, FileCloser> file(
@ -74,10 +84,10 @@ Status SingleSegmentSegmenter::DoFinalize() {
// Load the temp file and write to output file. // Load the temp file and write to output file.
scoped_ptr<File, FileCloser> temp_file( scoped_ptr<File, FileCloser> temp_file(
File::Open(options().temp_file_name.c_str(), "r")); File::Open(temp_file_name_.c_str(), "r"));
if (temp_file == NULL) { if (temp_file == NULL) {
return Status(error::FILE_FAILURE, 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. const int kBufSize = 0x40000; // 256KB.
@ -86,7 +96,7 @@ Status SingleSegmentSegmenter::DoFinalize() {
int64 size = temp_file->Read(buf.get(), kBufSize); int64 size = temp_file->Read(buf.get(), kBufSize);
if (size <= 0) { if (size <= 0) {
return Status(error::FILE_FAILURE, 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); int64 size_written = file->Write(buf.get(), size);
if (size_written != size) { if (size_written != size) {

View File

@ -44,6 +44,7 @@ class SingleSegmentSegmenter : public Segmenter {
virtual Status DoFinalizeSegment() OVERRIDE; virtual Status DoFinalizeSegment() OVERRIDE;
scoped_ptr<SegmentIndex> vod_sidx_; scoped_ptr<SegmentIndex> vod_sidx_;
std::string temp_file_name_;
scoped_ptr<File, FileCloser> temp_file_; scoped_ptr<File, FileCloser> temp_file_;
DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter); DISALLOW_COPY_AND_ASSIGN(SingleSegmentSegmenter);

View File

@ -140,7 +140,7 @@ MuxerOptions PackagerTestBasic::SetupOptions(const std::string& output,
options.output_file_name = GetFullPath(output); options.output_file_name = GetFullPath(output);
options.segment_template = GetFullPath(kSegmentTemplate); options.segment_template = GetFullPath(kSegmentTemplate);
options.temp_file_name = GetFullPath(output + ".temp"); options.temp_dir = test_directory_.value();
return options; return options;
} }

View File

@ -16,12 +16,19 @@
}, },
'targets': [ 'targets': [
{ {
'target_name': 'packager_main', 'target_name': 'single_packager',
'type': 'executable', 'type': 'executable',
'sources': [ 'sources': [
'app/fixed_key_encryption_flags.cc',
'app/fixed_key_encryption_flags.h', 'app/fixed_key_encryption_flags.h',
'app/packager_common.cc',
'app/packager_common.h',
'app/muxer_flags.cc',
'app/muxer_flags.h', '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', 'app/widevine_encryption_flags.h',
], ],
'dependencies': [ 'dependencies': [