Make edash-packager outputs predictable for testing
- Added --iv to inject iv for fixed key encryption. - Added support for key rotation in fixed key encryption. - Added --use_fake_clock_for_muxer to set timestamp to 0 in the output. Also updates stream info dump message: - Modified pixel_width: %d\n pixel_height: %d to pixel aspect ratio: %d:%d - Removed language from video stream info. These flags should only be used for testing. Change-Id: Iedf8d6d6492226219f49fe44d932645f557010e4
This commit is contained in:
parent
7ac31f2111
commit
8c202047fb
|
@ -18,6 +18,10 @@ DEFINE_bool(enable_fixed_key_decryption,
|
||||||
"Enable decryption with fixed key.");
|
"Enable decryption with fixed key.");
|
||||||
DEFINE_string(key_id, "", "Key id in hex string format.");
|
DEFINE_string(key_id, "", "Key id in hex string format.");
|
||||||
DEFINE_string(key, "", "Key in hex string format.");
|
DEFINE_string(key, "", "Key in hex string format.");
|
||||||
|
DEFINE_string(iv,
|
||||||
|
"",
|
||||||
|
"Iv in hex string format. If not specified, a random iv will be "
|
||||||
|
"generated. This flag should only be used for testing.");
|
||||||
DEFINE_string(pssh, "", "PSSH in hex string format.");
|
DEFINE_string(pssh, "", "PSSH in hex string format.");
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
@ -38,6 +42,10 @@ bool ValidateFixedCryptoFlags() {
|
||||||
"key", FLAGS_key, fixed_crypto, false, fixed_crypto_label)) {
|
"key", FLAGS_key, fixed_crypto, false, fixed_crypto_label)) {
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
if (!ValidateFlag("iv", FLAGS_iv, FLAGS_enable_fixed_key_encryption, true,
|
||||||
|
"--enable_fixed_key_encryption")) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
// --pssh is associated with --enable_fix_key_encryption.
|
// --pssh is associated with --enable_fix_key_encryption.
|
||||||
if (!ValidateFlag("pssh",
|
if (!ValidateFlag("pssh",
|
||||||
|
|
|
@ -15,6 +15,7 @@ DECLARE_bool(enable_fixed_key_encryption);
|
||||||
DECLARE_bool(enable_fixed_key_decryption);
|
DECLARE_bool(enable_fixed_key_decryption);
|
||||||
DECLARE_string(key_id);
|
DECLARE_string(key_id);
|
||||||
DECLARE_string(key);
|
DECLARE_string(key);
|
||||||
|
DECLARE_string(iv);
|
||||||
DECLARE_string(pssh);
|
DECLARE_string(pssh);
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
// license that can be found in the LICENSE file or at
|
// license that can be found in the LICENSE file or at
|
||||||
// https://developers.google.com/open-source/licenses/bsd
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "packager/app/fixed_key_encryption_flags.h"
|
#include "packager/app/fixed_key_encryption_flags.h"
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include "packager/base/strings/string_split.h"
|
#include "packager/base/strings/string_split.h"
|
||||||
#include "packager/base/strings/stringprintf.h"
|
#include "packager/base/strings/stringprintf.h"
|
||||||
#include "packager/base/threading/simple_thread.h"
|
#include "packager/base/threading/simple_thread.h"
|
||||||
|
#include "packager/base/time/clock.h"
|
||||||
#include "packager/media/base/demuxer.h"
|
#include "packager/media/base/demuxer.h"
|
||||||
#include "packager/media/base/key_source.h"
|
#include "packager/media/base/key_source.h"
|
||||||
#include "packager/media/base/muxer_options.h"
|
#include "packager/media/base/muxer_options.h"
|
||||||
|
@ -29,6 +31,12 @@
|
||||||
#include "packager/mpd/base/mpd_builder.h"
|
#include "packager/mpd/base/mpd_builder.h"
|
||||||
#include "packager/mpd/base/simple_mpd_notifier.h"
|
#include "packager/mpd/base/simple_mpd_notifier.h"
|
||||||
|
|
||||||
|
DEFINE_bool(use_fake_clock_for_muxer,
|
||||||
|
false,
|
||||||
|
"Set to true to use a fake clock for muxer. With this flag set, "
|
||||||
|
"creation time and modification time in outputs are set to 0. "
|
||||||
|
"Should only be used for testing.");
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const char kUsage[] =
|
const char kUsage[] =
|
||||||
"Packager driver program. Sample Usage:\n"
|
"Packager driver program. Sample Usage:\n"
|
||||||
|
@ -66,6 +74,13 @@ enum ExitStatus {
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
// A fake clock that always return time 0 (epoch). Should only be used for
|
||||||
|
// testing.
|
||||||
|
class FakeClock : public base::Clock {
|
||||||
|
public:
|
||||||
|
virtual base::Time Now() OVERRIDE { return base::Time(); }
|
||||||
|
};
|
||||||
|
|
||||||
// Demux, Mux(es) and worker thread used to remux a source file/stream.
|
// Demux, Mux(es) and worker thread used to remux a source file/stream.
|
||||||
class RemuxJob : public base::SimpleThread {
|
class RemuxJob : public base::SimpleThread {
|
||||||
public:
|
public:
|
||||||
|
@ -99,6 +114,7 @@ class RemuxJob : public base::SimpleThread {
|
||||||
|
|
||||||
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
|
FakeClock* fake_clock,
|
||||||
KeySource* key_source,
|
KeySource* key_source,
|
||||||
MpdNotifier* mpd_notifier,
|
MpdNotifier* mpd_notifier,
|
||||||
std::vector<RemuxJob*>* remux_jobs) {
|
std::vector<RemuxJob*>* remux_jobs) {
|
||||||
|
@ -149,6 +165,8 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
DCHECK(!remux_jobs->empty());
|
DCHECK(!remux_jobs->empty());
|
||||||
|
|
||||||
scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(stream_muxer_options));
|
scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(stream_muxer_options));
|
||||||
|
if (FLAGS_use_fake_clock_for_muxer) muxer->set_clock(fake_clock);
|
||||||
|
|
||||||
if (key_source) {
|
if (key_source) {
|
||||||
muxer->SetKeySource(key_source,
|
muxer->SetKeySource(key_source,
|
||||||
FLAGS_max_sd_pixels,
|
FLAGS_max_sd_pixels,
|
||||||
|
@ -274,10 +292,9 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
||||||
|
|
||||||
std::vector<RemuxJob*> remux_jobs;
|
std::vector<RemuxJob*> remux_jobs;
|
||||||
STLElementDeleter<std::vector<RemuxJob*> > scoped_jobs_deleter(&remux_jobs);
|
STLElementDeleter<std::vector<RemuxJob*> > scoped_jobs_deleter(&remux_jobs);
|
||||||
if (!CreateRemuxJobs(stream_descriptors,
|
FakeClock fake_clock;
|
||||||
muxer_options,
|
if (!CreateRemuxJobs(stream_descriptors, muxer_options, &fake_clock,
|
||||||
encryption_key_source.get(),
|
encryption_key_source.get(), mpd_notifier.get(),
|
||||||
mpd_notifier.get(),
|
|
||||||
&remux_jobs)) {
|
&remux_jobs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ scoped_ptr<KeySource> CreateEncryptionKeySource() {
|
||||||
encryption_key_source = widevine_key_source.Pass();
|
encryption_key_source = widevine_key_source.Pass();
|
||||||
} else if (FLAGS_enable_fixed_key_encryption) {
|
} else if (FLAGS_enable_fixed_key_encryption) {
|
||||||
encryption_key_source = KeySource::CreateFromHexStrings(
|
encryption_key_source = KeySource::CreateFromHexStrings(
|
||||||
FLAGS_key_id, FLAGS_key, FLAGS_pssh, "");
|
FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv);
|
||||||
}
|
}
|
||||||
return encryption_key_source.Pass();
|
return encryption_key_source.Pass();
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,12 +142,6 @@ bool ValidateWidevineCryptoFlags() {
|
||||||
if (FLAGS_crypto_period_duration < 0) {
|
if (FLAGS_crypto_period_duration < 0) {
|
||||||
PrintError("--crypto_period_duration should not be negative.");
|
PrintError("--crypto_period_duration should not be negative.");
|
||||||
success = false;
|
success = false;
|
||||||
} else if (FLAGS_crypto_period_duration > 0 &&
|
|
||||||
!FLAGS_enable_widevine_encryption) {
|
|
||||||
PrintError(
|
|
||||||
"--crypto_period_duration should be specified only if "
|
|
||||||
"--enable_widevine_encryption.");
|
|
||||||
success = false;
|
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,12 +90,9 @@ bool AudioStreamInfo::IsValidConfig() const {
|
||||||
std::string AudioStreamInfo::ToString() const {
|
std::string AudioStreamInfo::ToString() const {
|
||||||
return base::StringPrintf(
|
return base::StringPrintf(
|
||||||
"%s codec: %s\n sample_bits: %d\n num_channels: %d\n "
|
"%s codec: %s\n sample_bits: %d\n num_channels: %d\n "
|
||||||
"sampling_frequency: %d\n",
|
"sampling_frequency: %d\n language: %s\n",
|
||||||
StreamInfo::ToString().c_str(),
|
StreamInfo::ToString().c_str(), AudioCodecToString(codec_).c_str(),
|
||||||
AudioCodecToString(codec_).c_str(),
|
sample_bits_, num_channels_, sampling_frequency_, language().c_str());
|
||||||
sample_bits_,
|
|
||||||
num_channels_,
|
|
||||||
sampling_frequency_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AudioStreamInfo::GetCodecString(AudioCodec codec,
|
std::string AudioStreamInfo::GetCodecString(AudioCodec codec,
|
||||||
|
|
|
@ -14,7 +14,8 @@ namespace {
|
||||||
const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6,
|
const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6,
|
||||||
0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc,
|
0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc,
|
||||||
0xd5, 0x1d, 0x21, 0xed};
|
0xd5, 0x1d, 0x21, 0xed};
|
||||||
const char kDefaultUUID[] = "";
|
// TODO(kqyang): Consider making it configurable.
|
||||||
|
const char kDefaultUUID[] = "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
|
||||||
const char kDefaultSystemName[] = "";
|
const char kDefaultSystemName[] = "";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -65,8 +66,27 @@ Status KeySource::GetKey(const std::vector<uint8_t>& key_id,
|
||||||
Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
||||||
TrackType track_type,
|
TrackType track_type,
|
||||||
EncryptionKey* key) {
|
EncryptionKey* key) {
|
||||||
NOTIMPLEMENTED();
|
*key = *encryption_key_;
|
||||||
return Status(error::UNIMPLEMENTED, "");
|
// A naive key rotation algorithm is implemented here by left rotating the
|
||||||
|
// key, key_id and pssh. Note that this implementation is only intended for
|
||||||
|
// testing purpose. The actual key rotation algorithm can be much more
|
||||||
|
// complicated.
|
||||||
|
LOG(WARNING)
|
||||||
|
<< "This naive key rotation algorithm should not be used in production.";
|
||||||
|
std::rotate(key->key_id.begin(),
|
||||||
|
key->key_id.begin() + (crypto_period_index % key->key_id.size()),
|
||||||
|
key->key_id.end());
|
||||||
|
std::rotate(key->key.begin(),
|
||||||
|
key->key.begin() + (crypto_period_index % key->key.size()),
|
||||||
|
key->key.end());
|
||||||
|
const size_t kPsshHeaderSize = 32u;
|
||||||
|
std::vector<uint8_t> pssh_data(key->pssh.begin() + kPsshHeaderSize,
|
||||||
|
key->pssh.end());
|
||||||
|
std::rotate(pssh_data.begin(),
|
||||||
|
pssh_data.begin() + (crypto_period_index % pssh_data.size()),
|
||||||
|
pssh_data.end());
|
||||||
|
key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||||
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string KeySource::UUID() {
|
std::string KeySource::UUID() {
|
||||||
|
|
|
@ -40,11 +40,11 @@ StreamInfo::~StreamInfo() {}
|
||||||
std::string StreamInfo::ToString() const {
|
std::string StreamInfo::ToString() const {
|
||||||
return base::StringPrintf(
|
return base::StringPrintf(
|
||||||
"type: %s\n codec_string: %s\n time_scale: %d\n duration: "
|
"type: %s\n codec_string: %s\n time_scale: %d\n duration: "
|
||||||
"%" PRIu64 " (%.1f seconds)\n language: %s\n is_encrypted: %s\n",
|
"%" PRIu64 " (%.1f seconds)\n is_encrypted: %s\n",
|
||||||
(stream_type_ == kStreamAudio ? "Audio" : "Video"),
|
(stream_type_ == kStreamAudio ? "Audio" : "Video"),
|
||||||
codec_string_.c_str(),
|
codec_string_.c_str(),
|
||||||
time_scale_, duration_,
|
time_scale_, duration_,
|
||||||
static_cast<double>(duration_) / time_scale_, language_.c_str(),
|
static_cast<double>(duration_) / time_scale_,
|
||||||
is_encrypted_ ? "true" : "false");
|
is_encrypted_ ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,13 +85,11 @@ bool VideoStreamInfo::IsValidConfig() const {
|
||||||
|
|
||||||
std::string VideoStreamInfo::ToString() const {
|
std::string VideoStreamInfo::ToString() const {
|
||||||
return base::StringPrintf(
|
return base::StringPrintf(
|
||||||
"%s codec: %s\n width: %d\n height: %d\n pixel_width: %d\n pixel_height: "
|
"%s codec: %s\n width: %d\n height: %d\n pixel aspect ratio: %d:%d\n "
|
||||||
"%d\n trick_play_rate: %d\n nalu_length_size: %d\n",
|
"trick_play_rate: %d\n nalu_length_size: %d\n",
|
||||||
StreamInfo::ToString().c_str(),
|
StreamInfo::ToString().c_str(), VideoCodecToString(codec_).c_str(),
|
||||||
VideoCodecToString(codec_).c_str(),
|
width_, height_, pixel_width_, pixel_height_, trick_play_rate_,
|
||||||
width_, height_,
|
nalu_length_size_);
|
||||||
pixel_width_, pixel_height_,
|
|
||||||
trick_play_rate_, nalu_length_size_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VideoStreamInfo::GetCodecString(VideoCodec codec,
|
std::string VideoStreamInfo::GetCodecString(VideoCodec codec,
|
||||||
|
|
Loading…
Reference in New Issue