Consolidate EncryptionParam and EncryptionOptions
Change-Id: I8a5b5c329d4731341a3184d50bed061aa00cdeda
This commit is contained in:
parent
e605203fa7
commit
c7c201b00c
|
@ -134,6 +134,27 @@ bool GetHlsPlaylistType(const std::string& playlist_type,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetProtectionScheme(uint32_t* protection_scheme) {
|
||||||
|
if (FLAGS_protection_scheme == "cenc") {
|
||||||
|
*protection_scheme = EncryptionParams::kProtectionSchemeCenc;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FLAGS_protection_scheme == "cbc1") {
|
||||||
|
*protection_scheme = EncryptionParams::kProtectionSchemeCbc1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FLAGS_protection_scheme == "cbcs") {
|
||||||
|
*protection_scheme = EncryptionParams::kProtectionSchemeCbcs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FLAGS_protection_scheme == "cens") {
|
||||||
|
*protection_scheme = EncryptionParams::kProtectionSchemeCens;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "Unrecognized protection_scheme " << FLAGS_protection_scheme;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
base::Optional<PackagingParams> GetPackagingParams() {
|
base::Optional<PackagingParams> GetPackagingParams() {
|
||||||
PackagingParams packaging_params;
|
PackagingParams packaging_params;
|
||||||
|
|
||||||
|
@ -166,12 +187,13 @@ base::Optional<PackagingParams> GetPackagingParams() {
|
||||||
|
|
||||||
if (encryption_params.key_provider != KeyProvider::kNone) {
|
if (encryption_params.key_provider != KeyProvider::kNone) {
|
||||||
encryption_params.clear_lead_in_seconds = FLAGS_clear_lead;
|
encryption_params.clear_lead_in_seconds = FLAGS_clear_lead;
|
||||||
encryption_params.protection_scheme = FLAGS_protection_scheme;
|
if (!GetProtectionScheme(&encryption_params.protection_scheme))
|
||||||
|
return base::nullopt;
|
||||||
encryption_params.crypto_period_duration_in_seconds =
|
encryption_params.crypto_period_duration_in_seconds =
|
||||||
FLAGS_crypto_period_duration;
|
FLAGS_crypto_period_duration;
|
||||||
encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption;
|
encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption;
|
||||||
encryption_params.stream_label_func = std::bind(
|
encryption_params.stream_label_func = std::bind(
|
||||||
&EncryptionParams::DefaultStreamLabelFunction, FLAGS_max_sd_pixels,
|
&Packager::DefaultStreamLabelFunction, FLAGS_max_sd_pixels,
|
||||||
FLAGS_max_hd_pixels, FLAGS_max_uhd1_pixels, std::placeholders::_1);
|
FLAGS_max_hd_pixels, FLAGS_max_uhd1_pixels, std::placeholders::_1);
|
||||||
}
|
}
|
||||||
switch (encryption_params.key_provider) {
|
switch (encryption_params.key_provider) {
|
||||||
|
|
|
@ -26,21 +26,6 @@ namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
FourCC GetProtectionScheme(const std::string& protection_scheme) {
|
|
||||||
if (protection_scheme == "cenc") {
|
|
||||||
return FOURCC_cenc;
|
|
||||||
} else if (protection_scheme == "cens") {
|
|
||||||
return FOURCC_cens;
|
|
||||||
} else if (protection_scheme == "cbc1") {
|
|
||||||
return FOURCC_cbc1;
|
|
||||||
} else if (protection_scheme == "cbcs") {
|
|
||||||
return FOURCC_cbcs;
|
|
||||||
} else {
|
|
||||||
LOG(ERROR) << "Unknown protection scheme: " << protection_scheme;
|
|
||||||
return FOURCC_NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<RequestSigner> CreateSigner(const WidevineSigner& signer) {
|
std::unique_ptr<RequestSigner> CreateSigner(const WidevineSigner& signer) {
|
||||||
|
@ -198,21 +183,6 @@ ChunkingOptions GetChunkingOptions(const ChunkingParams& chunking_params) {
|
||||||
return chunking_options;
|
return chunking_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
EncryptionOptions GetEncryptionOptions(
|
|
||||||
const EncryptionParams& encryption_params) {
|
|
||||||
EncryptionOptions encryption_options;
|
|
||||||
encryption_options.clear_lead_in_seconds =
|
|
||||||
encryption_params.clear_lead_in_seconds;
|
|
||||||
encryption_options.protection_scheme =
|
|
||||||
GetProtectionScheme(encryption_params.protection_scheme);
|
|
||||||
encryption_options.crypto_period_duration_in_seconds =
|
|
||||||
encryption_params.crypto_period_duration_in_seconds;
|
|
||||||
encryption_options.vp9_subsample_encryption =
|
|
||||||
encryption_params.vp9_subsample_encryption;
|
|
||||||
encryption_options.stream_label_func = encryption_params.stream_label_func;
|
|
||||||
return encryption_options;
|
|
||||||
}
|
|
||||||
|
|
||||||
MuxerOptions GetMuxerOptions(const std::string& temp_dir,
|
MuxerOptions GetMuxerOptions(const std::string& temp_dir,
|
||||||
const Mp4OutputParams& mp4_params) {
|
const Mp4OutputParams& mp4_params) {
|
||||||
MuxerOptions muxer_options;
|
MuxerOptions muxer_options;
|
||||||
|
|
|
@ -53,10 +53,6 @@ std::unique_ptr<KeySource> CreateDecryptionKeySource(
|
||||||
/// @return ChunkingOptions from provided command line options.
|
/// @return ChunkingOptions from provided command line options.
|
||||||
ChunkingOptions GetChunkingOptions(const ChunkingParams& chunking_params);
|
ChunkingOptions GetChunkingOptions(const ChunkingParams& chunking_params);
|
||||||
|
|
||||||
/// @return EncryptionOptions from provided command line options.
|
|
||||||
EncryptionOptions GetEncryptionOptions(
|
|
||||||
const EncryptionParams& encryption_params);
|
|
||||||
|
|
||||||
/// @return MuxerOptions from provided command line options.
|
/// @return MuxerOptions from provided command line options.
|
||||||
MuxerOptions GetMuxerOptions(const std::string& temp_dir,
|
MuxerOptions GetMuxerOptions(const std::string& temp_dir,
|
||||||
const Mp4OutputParams& mp4_params);
|
const Mp4OutputParams& mp4_params);
|
||||||
|
|
|
@ -31,7 +31,7 @@ const uint8_t kKeyRotationDefaultKeyId[] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Adds one or more subsamples to |*subsamples|. This may add more than one
|
// Adds one or more subsamples to |*decrypt_config|. This may add more than one
|
||||||
// if one of the values overflows the integer in the subsample.
|
// if one of the values overflows the integer in the subsample.
|
||||||
void AddSubsample(uint64_t clear_bytes,
|
void AddSubsample(uint64_t clear_bytes,
|
||||||
uint64_t cipher_bytes,
|
uint64_t cipher_bytes,
|
||||||
|
@ -77,15 +77,17 @@ std::string GetStreamLabelForEncryption(
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EncryptionHandler::EncryptionHandler(
|
EncryptionHandler::EncryptionHandler(const EncryptionParams& encryption_params,
|
||||||
const EncryptionOptions& encryption_options,
|
KeySource* key_source)
|
||||||
KeySource* key_source)
|
: encryption_params_(encryption_params),
|
||||||
: encryption_options_(encryption_options), key_source_(key_source) {}
|
protection_scheme_(
|
||||||
|
static_cast<FourCC>(encryption_params.protection_scheme)),
|
||||||
|
key_source_(key_source) {}
|
||||||
|
|
||||||
EncryptionHandler::~EncryptionHandler() {}
|
EncryptionHandler::~EncryptionHandler() {}
|
||||||
|
|
||||||
Status EncryptionHandler::InitializeInternal() {
|
Status EncryptionHandler::InitializeInternal() {
|
||||||
if (!encryption_options_.stream_label_func) {
|
if (!encryption_params_.stream_label_func) {
|
||||||
return Status(error::INVALID_ARGUMENT, "Stream label function not set.");
|
return Status(error::INVALID_ARGUMENT, "Stream label function not set.");
|
||||||
}
|
}
|
||||||
if (num_input_streams() != 1 || next_output_stream_index() != 1) {
|
if (num_input_streams() != 1 || next_output_stream_index() != 1) {
|
||||||
|
@ -134,17 +136,17 @@ Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining_clear_lead_ =
|
remaining_clear_lead_ =
|
||||||
encryption_options_.clear_lead_in_seconds * stream_info->time_scale();
|
encryption_params_.clear_lead_in_seconds * stream_info->time_scale();
|
||||||
crypto_period_duration_ =
|
crypto_period_duration_ =
|
||||||
encryption_options_.crypto_period_duration_in_seconds *
|
encryption_params_.crypto_period_duration_in_seconds *
|
||||||
stream_info->time_scale();
|
stream_info->time_scale();
|
||||||
codec_ = stream_info->codec();
|
codec_ = stream_info->codec();
|
||||||
nalu_length_size_ = GetNaluLengthSize(*stream_info);
|
nalu_length_size_ = GetNaluLengthSize(*stream_info);
|
||||||
stream_label_ = GetStreamLabelForEncryption(
|
stream_label_ = GetStreamLabelForEncryption(
|
||||||
*stream_info, encryption_options_.stream_label_func);
|
*stream_info, encryption_params_.stream_label_func);
|
||||||
switch (codec_) {
|
switch (codec_) {
|
||||||
case kCodecVP9:
|
case kCodecVP9:
|
||||||
if (encryption_options_.vp9_subsample_encryption)
|
if (encryption_params_.vp9_subsample_encryption)
|
||||||
vpx_parser_.reset(new VP9Parser);
|
vpx_parser_.reset(new VP9Parser);
|
||||||
break;
|
break;
|
||||||
case kCodecH264:
|
case kCodecH264:
|
||||||
|
@ -192,8 +194,7 @@ Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) {
|
||||||
return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
|
return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
|
||||||
|
|
||||||
stream_info->set_is_encrypted(true);
|
stream_info->set_is_encrypted(true);
|
||||||
stream_info->set_has_clear_lead(encryption_options_.clear_lead_in_seconds >
|
stream_info->set_has_clear_lead(encryption_params_.clear_lead_in_seconds > 0);
|
||||||
0);
|
|
||||||
stream_info->set_encryption_config(*encryption_config_);
|
stream_info->set_encryption_config(*encryption_config_);
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
@ -230,10 +231,10 @@ Status EncryptionHandler::ProcessMediaSample(MediaSample* sample) {
|
||||||
if (remaining_clear_lead_ > 0)
|
if (remaining_clear_lead_ > 0)
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
|
|
||||||
std::unique_ptr<DecryptConfig> decrypt_config(new DecryptConfig(
|
std::unique_ptr<DecryptConfig> decrypt_config(
|
||||||
encryption_config_->key_id, encryptor_->iv(),
|
new DecryptConfig(encryption_config_->key_id, encryptor_->iv(),
|
||||||
std::vector<SubsampleEntry>(), encryption_options_.protection_scheme,
|
std::vector<SubsampleEntry>(), protection_scheme_,
|
||||||
crypt_byte_block_, skip_byte_block_));
|
crypt_byte_block_, skip_byte_block_));
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (vpx_parser_) {
|
if (vpx_parser_) {
|
||||||
result = EncryptVpxFrame(vpx_frames, sample, decrypt_config.get());
|
result = EncryptVpxFrame(vpx_frames, sample, decrypt_config.get());
|
||||||
|
@ -262,7 +263,7 @@ Status EncryptionHandler::ProcessMediaSample(MediaSample* sample) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
|
Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
|
||||||
switch (encryption_options_.protection_scheme) {
|
switch (protection_scheme_) {
|
||||||
case kAppleSampleAesProtectionScheme: {
|
case kAppleSampleAesProtectionScheme: {
|
||||||
const size_t kH264LeadingClearBytesSize = 32u;
|
const size_t kH264LeadingClearBytesSize = 32u;
|
||||||
const size_t kSmallNalUnitSize = 32u + 16u;
|
const size_t kSmallNalUnitSize = 32u + 16u;
|
||||||
|
@ -323,7 +324,7 @@ Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
|
||||||
|
|
||||||
bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
|
bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
|
||||||
std::unique_ptr<AesCryptor> encryptor;
|
std::unique_ptr<AesCryptor> encryptor;
|
||||||
switch (encryption_options_.protection_scheme) {
|
switch (protection_scheme_) {
|
||||||
case FOURCC_cenc:
|
case FOURCC_cenc:
|
||||||
encryptor.reset(new AesCtrEncryptor);
|
encryptor.reset(new AesCtrEncryptor);
|
||||||
break;
|
break;
|
||||||
|
@ -363,8 +364,7 @@ bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
|
||||||
|
|
||||||
std::vector<uint8_t> iv = encryption_key.iv;
|
std::vector<uint8_t> iv = encryption_key.iv;
|
||||||
if (iv.empty()) {
|
if (iv.empty()) {
|
||||||
if (!AesCryptor::GenerateRandomIv(encryption_options_.protection_scheme,
|
if (!AesCryptor::GenerateRandomIv(protection_scheme_, &iv)) {
|
||||||
&iv)) {
|
|
||||||
LOG(ERROR) << "Failed to generate random iv.";
|
LOG(ERROR) << "Failed to generate random iv.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,7 @@ bool EncryptionHandler::CreateEncryptor(const EncryptionKey& encryption_key) {
|
||||||
encryptor_ = std::move(encryptor);
|
encryptor_ = std::move(encryptor);
|
||||||
|
|
||||||
encryption_config_.reset(new EncryptionConfig);
|
encryption_config_.reset(new EncryptionConfig);
|
||||||
encryption_config_->protection_scheme = encryption_options_.protection_scheme;
|
encryption_config_->protection_scheme = protection_scheme_;
|
||||||
encryption_config_->crypt_byte_block = crypt_byte_block_;
|
encryption_config_->crypt_byte_block = crypt_byte_block_;
|
||||||
encryption_config_->skip_byte_block = skip_byte_block_;
|
encryption_config_->skip_byte_block = skip_byte_block_;
|
||||||
if (encryptor_->use_constant_iv()) {
|
if (encryptor_->use_constant_iv()) {
|
||||||
|
@ -467,9 +467,9 @@ bool EncryptionHandler::EncryptNalFrame(MediaSample* sample,
|
||||||
// CMAF requires 'cenc' scheme BytesOfProtectedData SHALL be a multiple
|
// CMAF requires 'cenc' scheme BytesOfProtectedData SHALL be a multiple
|
||||||
// of 16 bytes; while 'cbcs' scheme BytesOfProtectedData SHALL start on
|
// of 16 bytes; while 'cbcs' scheme BytesOfProtectedData SHALL start on
|
||||||
// the first byte of video data following the slice header.
|
// the first byte of video data following the slice header.
|
||||||
if (encryption_options_.protection_scheme == FOURCC_cbc1 ||
|
if (protection_scheme_ == FOURCC_cbc1 ||
|
||||||
encryption_options_.protection_scheme == FOURCC_cens ||
|
protection_scheme_ == FOURCC_cens ||
|
||||||
encryption_options_.protection_scheme == FOURCC_cenc) {
|
protection_scheme_ == FOURCC_cenc) {
|
||||||
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
|
const uint16_t misalign_bytes = cipher_bytes % kCencBlockSize;
|
||||||
current_clear_bytes += misalign_bytes;
|
current_clear_bytes += misalign_bytes;
|
||||||
cipher_bytes -= misalign_bytes;
|
cipher_bytes -= misalign_bytes;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include "packager/media/base/key_source.h"
|
#include "packager/media/base/key_source.h"
|
||||||
#include "packager/media/base/media_handler.h"
|
#include "packager/media/base/media_handler.h"
|
||||||
#include "packager/packager.h"
|
#include "packager/media/public/crypto_params.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
@ -20,27 +20,9 @@ class VPxParser;
|
||||||
struct EncryptionKey;
|
struct EncryptionKey;
|
||||||
struct VPxFrameInfo;
|
struct VPxFrameInfo;
|
||||||
|
|
||||||
/// This structure defines encryption options.
|
|
||||||
struct EncryptionOptions {
|
|
||||||
/// Clear lead duration in seconds.
|
|
||||||
double clear_lead_in_seconds = 0;
|
|
||||||
/// The protection scheme: 'cenc', 'cens', 'cbc1', 'cbcs'.
|
|
||||||
FourCC protection_scheme = FOURCC_cenc;
|
|
||||||
/// Crypto period duration in seconds. A positive value means key rotation is
|
|
||||||
/// enabled, the key source must support key rotation in this case.
|
|
||||||
double crypto_period_duration_in_seconds = 0;
|
|
||||||
/// Enable/disable subsample encryption for VP9.
|
|
||||||
bool vp9_subsample_encryption = true;
|
|
||||||
/// Stream label function used to get the label of the encrypted stream. Must
|
|
||||||
/// be set.
|
|
||||||
std::function<std::string(
|
|
||||||
const EncryptionParams::EncryptedStreamAttributes& stream_attributes)>
|
|
||||||
stream_label_func;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EncryptionHandler : public MediaHandler {
|
class EncryptionHandler : public MediaHandler {
|
||||||
public:
|
public:
|
||||||
EncryptionHandler(const EncryptionOptions& encryption_options,
|
EncryptionHandler(const EncryptionParams& encryption_params,
|
||||||
KeySource* key_source);
|
KeySource* key_source);
|
||||||
|
|
||||||
~EncryptionHandler() override;
|
~EncryptionHandler() override;
|
||||||
|
@ -76,7 +58,8 @@ class EncryptionHandler : public MediaHandler {
|
||||||
void InjectVideoSliceHeaderParserForTesting(
|
void InjectVideoSliceHeaderParserForTesting(
|
||||||
std::unique_ptr<VideoSliceHeaderParser> header_parser);
|
std::unique_ptr<VideoSliceHeaderParser> header_parser);
|
||||||
|
|
||||||
const EncryptionOptions encryption_options_;
|
const EncryptionParams encryption_params_;
|
||||||
|
const FourCC protection_scheme_ = FOURCC_NULL;
|
||||||
KeySource* key_source_ = nullptr;
|
KeySource* key_source_ = nullptr;
|
||||||
std::string stream_label_;
|
std::string stream_label_;
|
||||||
// Current encryption config and encryptor.
|
// Current encryption config and encryptor.
|
||||||
|
|
|
@ -83,13 +83,13 @@ class MockVideoSliceHeaderParser : public VideoSliceHeaderParser {
|
||||||
|
|
||||||
class EncryptionHandlerTest : public MediaHandlerTestBase {
|
class EncryptionHandlerTest : public MediaHandlerTestBase {
|
||||||
public:
|
public:
|
||||||
void SetUp() override { SetUpEncryptionHandler(EncryptionOptions()); }
|
void SetUp() override { SetUpEncryptionHandler(EncryptionParams()); }
|
||||||
|
|
||||||
void SetUpEncryptionHandler(const EncryptionOptions& encryption_options) {
|
void SetUpEncryptionHandler(const EncryptionParams& encryption_params) {
|
||||||
EncryptionOptions new_encryption_options = encryption_options;
|
EncryptionParams new_encryption_params = encryption_params;
|
||||||
if (!encryption_options.stream_label_func) {
|
if (!encryption_params.stream_label_func) {
|
||||||
// Setup default stream label function.
|
// Setup default stream label function.
|
||||||
new_encryption_options.stream_label_func =
|
new_encryption_params.stream_label_func =
|
||||||
[](const EncryptionParams::EncryptedStreamAttributes&
|
[](const EncryptionParams::EncryptedStreamAttributes&
|
||||||
stream_attributes) {
|
stream_attributes) {
|
||||||
if (stream_attributes.stream_type ==
|
if (stream_attributes.stream_type ==
|
||||||
|
@ -100,7 +100,7 @@ class EncryptionHandlerTest : public MediaHandlerTestBase {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
encryption_handler_.reset(
|
encryption_handler_.reset(
|
||||||
new EncryptionHandler(new_encryption_options, &mock_key_source_));
|
new EncryptionHandler(new_encryption_params, &mock_key_source_));
|
||||||
SetUpGraph(1 /* one input */, 1 /* one output */, encryption_handler_);
|
SetUpGraph(1 /* one input */, 1 /* one output */, encryption_handler_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,11 +470,11 @@ class EncryptionHandlerEncryptionTest
|
||||||
|
|
||||||
TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithNoKeyRotation) {
|
TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithNoKeyRotation) {
|
||||||
const double kClearLeadInSeconds = 1.5 * kSegmentDuration / kTimeScale;
|
const double kClearLeadInSeconds = 1.5 * kSegmentDuration / kTimeScale;
|
||||||
EncryptionOptions encryption_options;
|
EncryptionParams encryption_params;
|
||||||
encryption_options.protection_scheme = protection_scheme_;
|
encryption_params.protection_scheme = protection_scheme_;
|
||||||
encryption_options.clear_lead_in_seconds = kClearLeadInSeconds;
|
encryption_params.clear_lead_in_seconds = kClearLeadInSeconds;
|
||||||
encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_;
|
encryption_params.vp9_subsample_encryption = vp9_subsample_encryption_;
|
||||||
SetUpEncryptionHandler(encryption_options);
|
SetUpEncryptionHandler(encryption_params);
|
||||||
|
|
||||||
const EncryptionKey mock_encryption_key = GetMockEncryptionKey();
|
const EncryptionKey mock_encryption_key = GetMockEncryptionKey();
|
||||||
EXPECT_CALL(mock_key_source_, GetKey(_, _))
|
EXPECT_CALL(mock_key_source_, GetKey(_, _))
|
||||||
|
@ -523,13 +523,13 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithKeyRotation) {
|
||||||
const int kSegmentsPerCryptoPeriod = 2; // 2 segments.
|
const int kSegmentsPerCryptoPeriod = 2; // 2 segments.
|
||||||
const double kCryptoPeriodDurationInSeconds =
|
const double kCryptoPeriodDurationInSeconds =
|
||||||
kSegmentsPerCryptoPeriod * kSegmentDuration / kTimeScale;
|
kSegmentsPerCryptoPeriod * kSegmentDuration / kTimeScale;
|
||||||
EncryptionOptions encryption_options;
|
EncryptionParams encryption_params;
|
||||||
encryption_options.protection_scheme = protection_scheme_;
|
encryption_params.protection_scheme = protection_scheme_;
|
||||||
encryption_options.clear_lead_in_seconds = kClearLeadInSeconds;
|
encryption_params.clear_lead_in_seconds = kClearLeadInSeconds;
|
||||||
encryption_options.crypto_period_duration_in_seconds =
|
encryption_params.crypto_period_duration_in_seconds =
|
||||||
kCryptoPeriodDurationInSeconds;
|
kCryptoPeriodDurationInSeconds;
|
||||||
encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_;
|
encryption_params.vp9_subsample_encryption = vp9_subsample_encryption_;
|
||||||
SetUpEncryptionHandler(encryption_options);
|
SetUpEncryptionHandler(encryption_params);
|
||||||
|
|
||||||
ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale)));
|
ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale)));
|
||||||
EXPECT_THAT(GetOutputStreamDataVector(),
|
EXPECT_THAT(GetOutputStreamDataVector(),
|
||||||
|
@ -582,10 +582,10 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithKeyRotation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(EncryptionHandlerEncryptionTest, Encrypt) {
|
TEST_P(EncryptionHandlerEncryptionTest, Encrypt) {
|
||||||
EncryptionOptions encryption_options;
|
EncryptionParams encryption_params;
|
||||||
encryption_options.protection_scheme = protection_scheme_;
|
encryption_params.protection_scheme = protection_scheme_;
|
||||||
encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_;
|
encryption_params.vp9_subsample_encryption = vp9_subsample_encryption_;
|
||||||
SetUpEncryptionHandler(encryption_options);
|
SetUpEncryptionHandler(encryption_params);
|
||||||
|
|
||||||
const EncryptionKey mock_encryption_key = GetMockEncryptionKey();
|
const EncryptionKey mock_encryption_key = GetMockEncryptionKey();
|
||||||
EXPECT_CALL(mock_key_source_, GetKey(_, _))
|
EXPECT_CALL(mock_key_source_, GetKey(_, _))
|
||||||
|
@ -653,15 +653,15 @@ class EncryptionHandlerTrackTypeTest : public EncryptionHandlerTest {
|
||||||
|
|
||||||
TEST_F(EncryptionHandlerTrackTypeTest, AudioTrackType) {
|
TEST_F(EncryptionHandlerTrackTypeTest, AudioTrackType) {
|
||||||
EncryptionParams::EncryptedStreamAttributes captured_stream_attributes;
|
EncryptionParams::EncryptedStreamAttributes captured_stream_attributes;
|
||||||
EncryptionOptions encryption_options;
|
EncryptionParams encryption_params;
|
||||||
encryption_options.stream_label_func =
|
encryption_params.stream_label_func =
|
||||||
[&captured_stream_attributes](
|
[&captured_stream_attributes](
|
||||||
const EncryptionParams::EncryptedStreamAttributes&
|
const EncryptionParams::EncryptedStreamAttributes&
|
||||||
stream_attributes) {
|
stream_attributes) {
|
||||||
captured_stream_attributes = stream_attributes;
|
captured_stream_attributes = stream_attributes;
|
||||||
return kAudioStreamLabel;
|
return kAudioStreamLabel;
|
||||||
};
|
};
|
||||||
SetUpEncryptionHandler(encryption_options);
|
SetUpEncryptionHandler(encryption_params);
|
||||||
EXPECT_CALL(mock_key_source_, GetKey(kAudioStreamLabel, _))
|
EXPECT_CALL(mock_key_source_, GetKey(kAudioStreamLabel, _))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<1>(GetMockEncryptionKey()), Return(Status::OK)));
|
DoAll(SetArgPointee<1>(GetMockEncryptionKey()), Return(Status::OK)));
|
||||||
|
@ -672,15 +672,15 @@ TEST_F(EncryptionHandlerTrackTypeTest, AudioTrackType) {
|
||||||
|
|
||||||
TEST_F(EncryptionHandlerTrackTypeTest, VideoTrackType) {
|
TEST_F(EncryptionHandlerTrackTypeTest, VideoTrackType) {
|
||||||
EncryptionParams::EncryptedStreamAttributes captured_stream_attributes;
|
EncryptionParams::EncryptedStreamAttributes captured_stream_attributes;
|
||||||
EncryptionOptions encryption_options;
|
EncryptionParams encryption_params;
|
||||||
encryption_options.stream_label_func =
|
encryption_params.stream_label_func =
|
||||||
[&captured_stream_attributes](
|
[&captured_stream_attributes](
|
||||||
const EncryptionParams::EncryptedStreamAttributes&
|
const EncryptionParams::EncryptedStreamAttributes&
|
||||||
stream_attributes) {
|
stream_attributes) {
|
||||||
captured_stream_attributes = stream_attributes;
|
captured_stream_attributes = stream_attributes;
|
||||||
return kSdVideoStreamLabel;
|
return kSdVideoStreamLabel;
|
||||||
};
|
};
|
||||||
SetUpEncryptionHandler(encryption_options);
|
SetUpEncryptionHandler(encryption_params);
|
||||||
EXPECT_CALL(mock_key_source_, GetKey(kSdVideoStreamLabel, _))
|
EXPECT_CALL(mock_key_source_, GetKey(kSdVideoStreamLabel, _))
|
||||||
.WillOnce(
|
.WillOnce(
|
||||||
DoAll(SetArgPointee<1>(GetMockEncryptionKey()), Return(Status::OK)));
|
DoAll(SetArgPointee<1>(GetMockEncryptionKey()), Return(Status::OK)));
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
// Copyright 2017 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
|
||||||
|
|
||||||
|
#ifndef PACKAGER_MEDIA_PUBLIC_CRYPTO_PARAMS_H_
|
||||||
|
#define PACKAGER_MEDIA_PUBLIC_CRYPTO_PARAMS_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace shaka {
|
||||||
|
|
||||||
|
/// Encryption / decryption key providers.
|
||||||
|
enum class KeyProvider {
|
||||||
|
kNone = 0,
|
||||||
|
kWidevine = 1,
|
||||||
|
kPlayready = 2,
|
||||||
|
kRawKey = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Signer credential for Widevine license server.
|
||||||
|
struct WidevineSigner {
|
||||||
|
/// Name of the signer / content provider.
|
||||||
|
std::string signer_name;
|
||||||
|
|
||||||
|
enum class SigningKeyType {
|
||||||
|
kNone,
|
||||||
|
kAes,
|
||||||
|
kRsa,
|
||||||
|
};
|
||||||
|
/// Specifies the signing key type, which determines whether AES or RSA key
|
||||||
|
/// are used to authenticate the signer. A type of 'kNone' is invalid.
|
||||||
|
SigningKeyType signing_key_type = SigningKeyType::kNone;
|
||||||
|
struct {
|
||||||
|
/// AES signing key.
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
/// AES signing IV.
|
||||||
|
std::vector<uint8_t> iv;
|
||||||
|
} aes;
|
||||||
|
struct {
|
||||||
|
/// RSA signing private key.
|
||||||
|
std::string key;
|
||||||
|
} rsa;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Widevine encryption parameters.
|
||||||
|
struct WidevineEncryptionParams {
|
||||||
|
/// Widevine license / key server URL.
|
||||||
|
std::string key_server_url;
|
||||||
|
/// Generates and includes an additional v1 PSSH box for the common system ID.
|
||||||
|
/// See: https://goo.gl/s8RIhr.
|
||||||
|
// TODO(kqyang): Move to EncryptionParams and support common PSSH generation
|
||||||
|
// in all key providers.
|
||||||
|
bool include_common_pssh = false;
|
||||||
|
/// Content identifier.
|
||||||
|
std::vector<uint8_t> content_id;
|
||||||
|
/// The name of a stored policy, which specifies DRM content rights.
|
||||||
|
std::string policy;
|
||||||
|
/// Signer credential for Widevine license / key server.
|
||||||
|
WidevineSigner signer;
|
||||||
|
/// Group identifier, if present licenses will belong to this group.
|
||||||
|
std::vector<uint8_t> group_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Playready encryption parameters.
|
||||||
|
/// Two different modes of playready key acquisition is supported:
|
||||||
|
/// (1) Fetch from a key server. `key_server_url` and `program_identifier` are
|
||||||
|
/// required. The presence of other parameters may be necessary depends
|
||||||
|
/// on server configuration.
|
||||||
|
/// (2) Provide the raw key directly. Both `key_id` and `key` are required.
|
||||||
|
/// We are planning to merge this mode with `RawKeyEncryptionParams`.
|
||||||
|
struct PlayreadyEncryptionParams {
|
||||||
|
/// Playready license / key server URL.
|
||||||
|
std::string key_server_url;
|
||||||
|
/// Playready program identifier.
|
||||||
|
std::string program_identifier;
|
||||||
|
/// Absolute path to the Certificate Authority file for the server cert in PEM
|
||||||
|
/// format.
|
||||||
|
std::string ca_file;
|
||||||
|
/// Absolute path to client certificate file.
|
||||||
|
std::string client_cert_file;
|
||||||
|
/// Absolute path to the private key file.
|
||||||
|
std::string client_cert_private_key_file;
|
||||||
|
/// Password to the private key file.
|
||||||
|
std::string client_cert_private_key_password;
|
||||||
|
|
||||||
|
// TODO(kqyang): move raw playready key generation to RawKey.
|
||||||
|
/// Provides a raw Playready KeyId.
|
||||||
|
std::vector<uint8_t> key_id;
|
||||||
|
/// Provides a raw Playready Key.
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Raw key encryption parameters, i.e. with key parameters provided.
|
||||||
|
struct RawKeyEncryptionParams {
|
||||||
|
/// An optional initialization vector. If not provided, a random `iv` will be
|
||||||
|
/// generated. Note that this parameter should only be used during testing.
|
||||||
|
std::vector<uint8_t> iv;
|
||||||
|
/// Inject a custom `pssh` or multiple concatenated `psshs`. If not provided,
|
||||||
|
/// a common system pssh will be generated.
|
||||||
|
std::vector<uint8_t> pssh;
|
||||||
|
|
||||||
|
using StreamLabel = std::string;
|
||||||
|
struct KeyPair {
|
||||||
|
std::vector<uint8_t> key_id;
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
};
|
||||||
|
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
|
||||||
|
/// default `KeyPair`, which applies to all the `StreamLabels` not present in
|
||||||
|
/// `key_map`.
|
||||||
|
std::map<StreamLabel, KeyPair> key_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Encryption parameters.
|
||||||
|
struct EncryptionParams {
|
||||||
|
/// Specifies the key provider, which determines which key provider is used
|
||||||
|
/// and which encryption params is valid. 'kNone' means not to encrypt the
|
||||||
|
/// streams.
|
||||||
|
KeyProvider key_provider = KeyProvider::kNone;
|
||||||
|
// Only one of the three fields is valid.
|
||||||
|
WidevineEncryptionParams widevine;
|
||||||
|
PlayreadyEncryptionParams playready;
|
||||||
|
RawKeyEncryptionParams raw_key;
|
||||||
|
|
||||||
|
/// Clear lead duration in seconds.
|
||||||
|
double clear_lead_in_seconds = 0;
|
||||||
|
/// The protection scheme: "cenc", "cens", "cbc1", "cbcs".
|
||||||
|
static constexpr uint32_t kProtectionSchemeCenc = 0x63656E63;
|
||||||
|
static constexpr uint32_t kProtectionSchemeCbc1 = 0x63626331;
|
||||||
|
static constexpr uint32_t kProtectionSchemeCens = 0x63656E73;
|
||||||
|
static constexpr uint32_t kProtectionSchemeCbcs = 0x63626373;
|
||||||
|
uint32_t protection_scheme = kProtectionSchemeCenc;
|
||||||
|
/// Crypto period duration in seconds. A positive value means key rotation is
|
||||||
|
/// enabled, the key provider must support key rotation in this case.
|
||||||
|
static constexpr double kNoKeyRotation = 0;
|
||||||
|
double crypto_period_duration_in_seconds = kNoKeyRotation;
|
||||||
|
/// Enable/disable subsample encryption for VP9.
|
||||||
|
bool vp9_subsample_encryption = true;
|
||||||
|
|
||||||
|
/// Encrypted stream information that is used to determine stream label.
|
||||||
|
struct EncryptedStreamAttributes {
|
||||||
|
enum StreamType {
|
||||||
|
kUnknown,
|
||||||
|
kVideo,
|
||||||
|
kAudio,
|
||||||
|
};
|
||||||
|
|
||||||
|
StreamType stream_type = kUnknown;
|
||||||
|
union OneOf {
|
||||||
|
OneOf() {}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
float frame_rate = 0;
|
||||||
|
int bit_depth = 0;
|
||||||
|
} video;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int number_of_channels = 0;
|
||||||
|
} audio;
|
||||||
|
} oneof;
|
||||||
|
};
|
||||||
|
/// Stream label function assigns a stream label to the stream to be
|
||||||
|
/// encrypted. Stream label is used to associate KeyPair with streams. Streams
|
||||||
|
/// with the same stream label always uses the same keyPair; Streams with
|
||||||
|
/// different stream label could use the same or different KeyPairs.
|
||||||
|
/// A default stream label function will be generated if not set.
|
||||||
|
std::function<std::string(const EncryptedStreamAttributes& stream_attributes)>
|
||||||
|
stream_label_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Widevine decryption parameters.
|
||||||
|
struct WidevineDecryptionParams {
|
||||||
|
/// Widevine license / key server URL.
|
||||||
|
std::string key_server_url;
|
||||||
|
/// Signer credential for Widevine license / key server.
|
||||||
|
WidevineSigner signer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Raw key decryption parameters, i.e. with key parameters provided.
|
||||||
|
struct RawKeyDecryptionParams {
|
||||||
|
using StreamLabel = std::string;
|
||||||
|
struct KeyPair {
|
||||||
|
std::vector<uint8_t> key_id;
|
||||||
|
std::vector<uint8_t> key;
|
||||||
|
};
|
||||||
|
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
|
||||||
|
/// default `KeyPair`, which applies to all the `StreamLabels` not present in
|
||||||
|
/// `key_map`.
|
||||||
|
std::map<StreamLabel, KeyPair> key_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Decryption parameters.
|
||||||
|
struct DecryptionParams {
|
||||||
|
/// Specifies the key provider, which determines which key provider is used
|
||||||
|
/// and which encryption params is valid. 'kNone' means not to decrypt the
|
||||||
|
/// streams.
|
||||||
|
KeyProvider key_provider = KeyProvider::kNone;
|
||||||
|
// Only one of the two fields is valid.
|
||||||
|
WidevineDecryptionParams widevine;
|
||||||
|
RawKeyDecryptionParams raw_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shaka
|
||||||
|
|
||||||
|
#endif // PACKAGER_MEDIA_PUBLIC_CRYPTO_PARAMS_H_
|
|
@ -316,7 +316,6 @@ std::shared_ptr<Muxer> CreateOutputMuxer(const MuxerOptions& options,
|
||||||
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
const PackagingParams& packaging_params,
|
const PackagingParams& packaging_params,
|
||||||
const ChunkingOptions& chunking_options,
|
const ChunkingOptions& chunking_options,
|
||||||
const EncryptionOptions& encryption_options,
|
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
FakeClock* fake_clock,
|
FakeClock* fake_clock,
|
||||||
KeySource* encryption_key_source,
|
KeySource* encryption_key_source,
|
||||||
|
@ -472,17 +471,25 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
|
|
||||||
Status status;
|
Status status;
|
||||||
if (encryption_key_source && !stream_iter->skip_encryption) {
|
if (encryption_key_source && !stream_iter->skip_encryption) {
|
||||||
auto new_encryption_options = encryption_options;
|
auto encryption_params = packaging_params.encryption_params;
|
||||||
// Use Sample AES in MPEG2TS.
|
// Use Sample AES in MPEG2TS.
|
||||||
// TODO(kqyang): Consider adding a new flag to enable Sample AES as we
|
// TODO(kqyang): Consider adding a new flag to enable Sample AES as we
|
||||||
// will support CENC in TS in the future.
|
// will support CENC in TS in the future.
|
||||||
if (output_format == CONTAINER_MPEG2TS) {
|
if (output_format == CONTAINER_MPEG2TS) {
|
||||||
VLOG(1) << "Use Apple Sample AES encryption for MPEG2TS.";
|
VLOG(1) << "Use Apple Sample AES encryption for MPEG2TS.";
|
||||||
new_encryption_options.protection_scheme =
|
encryption_params.protection_scheme =
|
||||||
kAppleSampleAesProtectionScheme;
|
kAppleSampleAesProtectionScheme;
|
||||||
}
|
}
|
||||||
|
if (!encryption_params.stream_label_func) {
|
||||||
|
const int kDefaultMaxSdPixels = 768 * 576;
|
||||||
|
const int kDefaultMaxHdPixels = 1920 * 1080;
|
||||||
|
const int kDefaultMaxUhd1Pixels = 4096 * 2160;
|
||||||
|
encryption_params.stream_label_func = std::bind(
|
||||||
|
&Packager::DefaultStreamLabelFunction, kDefaultMaxSdPixels,
|
||||||
|
kDefaultMaxHdPixels, kDefaultMaxUhd1Pixels, std::placeholders::_1);
|
||||||
|
}
|
||||||
handlers.emplace_back(
|
handlers.emplace_back(
|
||||||
new EncryptionHandler(new_encryption_options, encryption_key_source));
|
new EncryptionHandler(encryption_params, encryption_key_source));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If trick_play_handler is available, muxer should already be connected to
|
// If trick_play_handler is available, muxer should already be connected to
|
||||||
|
@ -544,24 +551,6 @@ Status RunRemuxJobs(const std::vector<std::unique_ptr<Job>>& jobs) {
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
||||||
std::string EncryptionParams::DefaultStreamLabelFunction(
|
|
||||||
int max_sd_pixels,
|
|
||||||
int max_hd_pixels,
|
|
||||||
int max_uhd1_pixels,
|
|
||||||
const EncryptedStreamAttributes& stream_attributes) {
|
|
||||||
if (stream_attributes.stream_type == EncryptedStreamAttributes::kAudio)
|
|
||||||
return "AUDIO";
|
|
||||||
if (stream_attributes.stream_type == EncryptedStreamAttributes::kVideo) {
|
|
||||||
const int pixels = stream_attributes.oneof.video.width *
|
|
||||||
stream_attributes.oneof.video.height;
|
|
||||||
if (pixels <= max_sd_pixels) return "SD";
|
|
||||||
if (pixels <= max_hd_pixels) return "HD";
|
|
||||||
if (pixels <= max_uhd1_pixels) return "UHD1";
|
|
||||||
return "UHD2";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Packager::PackagerInternal {
|
struct Packager::PackagerInternal {
|
||||||
media::FakeClock fake_clock;
|
media::FakeClock fake_clock;
|
||||||
std::unique_ptr<KeySource> encryption_key_source;
|
std::unique_ptr<KeySource> encryption_key_source;
|
||||||
|
@ -596,8 +585,6 @@ Status Packager::Initialize(
|
||||||
|
|
||||||
ChunkingOptions chunking_options =
|
ChunkingOptions chunking_options =
|
||||||
media::GetChunkingOptions(packaging_params.chunking_params);
|
media::GetChunkingOptions(packaging_params.chunking_params);
|
||||||
EncryptionOptions encryption_options =
|
|
||||||
media::GetEncryptionOptions(packaging_params.encryption_params);
|
|
||||||
MuxerOptions muxer_options = media::GetMuxerOptions(
|
MuxerOptions muxer_options = media::GetMuxerOptions(
|
||||||
packaging_params.temp_dir, packaging_params.mp4_output_params);
|
packaging_params.temp_dir, packaging_params.mp4_output_params);
|
||||||
|
|
||||||
|
@ -608,11 +595,10 @@ Status Packager::Initialize(
|
||||||
|
|
||||||
// Create encryption key source if needed.
|
// Create encryption key source if needed.
|
||||||
if (packaging_params.encryption_params.key_provider != KeyProvider::kNone) {
|
if (packaging_params.encryption_params.key_provider != KeyProvider::kNone) {
|
||||||
if (encryption_options.protection_scheme == media::FOURCC_NULL)
|
internal->encryption_key_source = CreateEncryptionKeySource(
|
||||||
return Status(error::INVALID_ARGUMENT, "Invalid protection scheme.");
|
static_cast<media::FourCC>(
|
||||||
internal->encryption_key_source =
|
packaging_params.encryption_params.protection_scheme),
|
||||||
CreateEncryptionKeySource(encryption_options.protection_scheme,
|
packaging_params.encryption_params);
|
||||||
packaging_params.encryption_params);
|
|
||||||
if (!internal->encryption_key_source)
|
if (!internal->encryption_key_source)
|
||||||
return Status(error::INVALID_ARGUMENT, "Failed to create key source.");
|
return Status(error::INVALID_ARGUMENT, "Failed to create key source.");
|
||||||
}
|
}
|
||||||
|
@ -651,7 +637,7 @@ Status Packager::Initialize(
|
||||||
stream_descriptor_list.insert(descriptor);
|
stream_descriptor_list.insert(descriptor);
|
||||||
if (!media::CreateRemuxJobs(
|
if (!media::CreateRemuxJobs(
|
||||||
stream_descriptor_list, packaging_params, chunking_options,
|
stream_descriptor_list, packaging_params, chunking_options,
|
||||||
encryption_options, muxer_options, &internal->fake_clock,
|
muxer_options, &internal->fake_clock,
|
||||||
internal->encryption_key_source.get(), internal->mpd_notifier.get(),
|
internal->encryption_key_source.get(), internal->mpd_notifier.get(),
|
||||||
internal->hls_notifier.get(), &internal->jobs)) {
|
internal->hls_notifier.get(), &internal->jobs)) {
|
||||||
return Status(error::INVALID_ARGUMENT, "Failed to create remux jobs.");
|
return Status(error::INVALID_ARGUMENT, "Failed to create remux jobs.");
|
||||||
|
@ -691,4 +677,24 @@ std::string Packager::GetLibraryVersion() {
|
||||||
return GetPackagerVersion();
|
return GetPackagerVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Packager::DefaultStreamLabelFunction(
|
||||||
|
int max_sd_pixels,
|
||||||
|
int max_hd_pixels,
|
||||||
|
int max_uhd1_pixels,
|
||||||
|
const EncryptionParams::EncryptedStreamAttributes& stream_attributes) {
|
||||||
|
if (stream_attributes.stream_type ==
|
||||||
|
EncryptionParams::EncryptedStreamAttributes::kAudio)
|
||||||
|
return "AUDIO";
|
||||||
|
if (stream_attributes.stream_type ==
|
||||||
|
EncryptionParams::EncryptedStreamAttributes::kVideo) {
|
||||||
|
const int pixels = stream_attributes.oneof.video.width *
|
||||||
|
stream_attributes.oneof.video.height;
|
||||||
|
if (pixels <= max_sd_pixels) return "SD";
|
||||||
|
if (pixels <= max_hd_pixels) return "HD";
|
||||||
|
if (pixels <= max_uhd1_pixels) return "UHD1";
|
||||||
|
return "UHD2";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace shaka
|
} // namespace shaka
|
||||||
|
|
|
@ -7,14 +7,12 @@
|
||||||
#ifndef PACKAGER_PACKAGER_H_
|
#ifndef PACKAGER_PACKAGER_H_
|
||||||
#define PACKAGER_PACKAGER_H_
|
#define PACKAGER_PACKAGER_H_
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <functional>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "packager/hls/public/hls_playlist_type.h"
|
#include "packager/hls/public/hls_playlist_type.h"
|
||||||
|
#include "packager/media/public/crypto_params.h"
|
||||||
#include "packager/status.h"
|
#include "packager/status.h"
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
|
@ -109,225 +107,6 @@ struct HlsParams {
|
||||||
double time_shift_buffer_depth = 0;
|
double time_shift_buffer_depth = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Encryption / decryption key providers.
|
|
||||||
enum class KeyProvider {
|
|
||||||
kNone = 0,
|
|
||||||
kWidevine = 1,
|
|
||||||
kPlayready = 2,
|
|
||||||
kRawKey = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Signer credential for Widevine license server.
|
|
||||||
struct WidevineSigner {
|
|
||||||
/// Name of the signer / content provider.
|
|
||||||
std::string signer_name;
|
|
||||||
|
|
||||||
enum class SigningKeyType {
|
|
||||||
kNone,
|
|
||||||
kAes,
|
|
||||||
kRsa,
|
|
||||||
};
|
|
||||||
/// Specifies the signing key type, which determines whether AES or RSA key
|
|
||||||
/// are used to authenticate the signer. A type of 'kNone' is invalid.
|
|
||||||
SigningKeyType signing_key_type = SigningKeyType::kNone;
|
|
||||||
struct {
|
|
||||||
/// AES signing key.
|
|
||||||
std::vector<uint8_t> key;
|
|
||||||
/// AES signing IV.
|
|
||||||
std::vector<uint8_t> iv;
|
|
||||||
} aes;
|
|
||||||
struct {
|
|
||||||
/// RSA signing private key.
|
|
||||||
std::string key;
|
|
||||||
} rsa;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Widevine encryption parameters.
|
|
||||||
struct WidevineEncryptionParams {
|
|
||||||
/// Widevine license / key server URL.
|
|
||||||
std::string key_server_url;
|
|
||||||
/// Generates and includes an additional v1 PSSH box for the common system ID.
|
|
||||||
/// See: https://goo.gl/s8RIhr.
|
|
||||||
// TODO(kqyang): Move to EncryptionParams and support common PSSH generation
|
|
||||||
// in all key providers.
|
|
||||||
bool include_common_pssh = false;
|
|
||||||
/// Content identifier.
|
|
||||||
std::vector<uint8_t> content_id;
|
|
||||||
/// The name of a stored policy, which specifies DRM content rights.
|
|
||||||
std::string policy;
|
|
||||||
/// Signer credential for Widevine license / key server.
|
|
||||||
WidevineSigner signer;
|
|
||||||
/// Group identifier, if present licenses will belong to this group.
|
|
||||||
std::vector<uint8_t> group_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Playready encryption parameters.
|
|
||||||
/// Two different modes of playready key acquisition is supported:
|
|
||||||
/// (1) Fetch from a key server. `key_server_url` and `program_identifier` are
|
|
||||||
/// required. The presence of other parameters may be necessary depends
|
|
||||||
/// on server configuration.
|
|
||||||
/// (2) Provide the raw key directly. Both `key_id` and `key` are required.
|
|
||||||
/// We are planning to merge this mode with `RawKeyEncryptionParams`.
|
|
||||||
struct PlayreadyEncryptionParams {
|
|
||||||
/// Playready license / key server URL.
|
|
||||||
std::string key_server_url;
|
|
||||||
/// Playready program identifier.
|
|
||||||
std::string program_identifier;
|
|
||||||
/// Absolute path to the Certificate Authority file for the server cert in PEM
|
|
||||||
/// format.
|
|
||||||
std::string ca_file;
|
|
||||||
/// Absolute path to client certificate file.
|
|
||||||
std::string client_cert_file;
|
|
||||||
/// Absolute path to the private key file.
|
|
||||||
std::string client_cert_private_key_file;
|
|
||||||
/// Password to the private key file.
|
|
||||||
std::string client_cert_private_key_password;
|
|
||||||
|
|
||||||
// TODO(kqyang): move raw playready key generation to RawKey.
|
|
||||||
/// Provides a raw Playready KeyId.
|
|
||||||
std::vector<uint8_t> key_id;
|
|
||||||
/// Provides a raw Playready Key.
|
|
||||||
std::vector<uint8_t> key;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Raw key encryption parameters, i.e. with key parameters provided.
|
|
||||||
struct RawKeyEncryptionParams {
|
|
||||||
/// An optional initialization vector. If not provided, a random `iv` will be
|
|
||||||
/// generated. Note that this parameter should only be used during testing.
|
|
||||||
std::vector<uint8_t> iv;
|
|
||||||
/// Inject a custom `pssh` or multiple concatenated `psshs`. If not provided,
|
|
||||||
/// a common system pssh will be generated.
|
|
||||||
std::vector<uint8_t> pssh;
|
|
||||||
|
|
||||||
using StreamLabel = std::string;
|
|
||||||
struct KeyPair {
|
|
||||||
std::vector<uint8_t> key_id;
|
|
||||||
std::vector<uint8_t> key;
|
|
||||||
};
|
|
||||||
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
|
|
||||||
/// default `KeyPair`, which applies to all the `StreamLabels` not present in
|
|
||||||
/// `key_map`.
|
|
||||||
std::map<StreamLabel, KeyPair> key_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Encryption parameters.
|
|
||||||
struct EncryptionParams {
|
|
||||||
/// Specifies the key provider, which determines which key provider is used
|
|
||||||
/// and which encryption params is valid. 'kNone' means not to encrypt the
|
|
||||||
/// streams.
|
|
||||||
KeyProvider key_provider = KeyProvider::kNone;
|
|
||||||
// Only one of the three fields is valid.
|
|
||||||
WidevineEncryptionParams widevine;
|
|
||||||
PlayreadyEncryptionParams playready;
|
|
||||||
RawKeyEncryptionParams raw_key;
|
|
||||||
|
|
||||||
/// Clear lead duration in seconds.
|
|
||||||
double clear_lead_in_seconds = 0;
|
|
||||||
/// The protection scheme: "cenc", "cens", "cbc1", "cbcs".
|
|
||||||
std::string protection_scheme = "cenc";
|
|
||||||
/// Crypto period duration in seconds. A positive value means key rotation is
|
|
||||||
/// enabled, the key provider must support key rotation in this case.
|
|
||||||
const double kNoKeyRotation = 0;
|
|
||||||
double crypto_period_duration_in_seconds = 0;
|
|
||||||
/// Enable/disable subsample encryption for VP9.
|
|
||||||
bool vp9_subsample_encryption = true;
|
|
||||||
|
|
||||||
/// Encrypted stream information that is used to determine stream label.
|
|
||||||
struct EncryptedStreamAttributes {
|
|
||||||
enum StreamType {
|
|
||||||
kUnknown,
|
|
||||||
kVideo,
|
|
||||||
kAudio,
|
|
||||||
};
|
|
||||||
|
|
||||||
StreamType stream_type = kUnknown;
|
|
||||||
union OneOf {
|
|
||||||
OneOf() {}
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int width = 0;
|
|
||||||
int height = 0;
|
|
||||||
float frame_rate = 0;
|
|
||||||
int bit_depth = 0;
|
|
||||||
} video;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int number_of_channels = 0;
|
|
||||||
} audio;
|
|
||||||
} oneof;
|
|
||||||
};
|
|
||||||
/// Default stream label function implementation.
|
|
||||||
/// @param max_sd_pixels The threshold to determine whether a video track
|
|
||||||
/// should be considered as SD. If the max pixels per
|
|
||||||
/// frame is no higher than max_sd_pixels, i.e. [0,
|
|
||||||
/// max_sd_pixels], it is SD.
|
|
||||||
/// @param max_hd_pixels: The threshold to determine whether a video track
|
|
||||||
/// should be considered as HD. If the max pixels per
|
|
||||||
/// frame is higher than max_sd_pixels, but no higher
|
|
||||||
/// than max_hd_pixels, i.e. (max_sd_pixels,
|
|
||||||
/// max_hd_pixels], it is HD.
|
|
||||||
/// @param max_uhd1_pixels: The threshold to determine whether a video track
|
|
||||||
/// should be considered as UHD1. If the max pixels
|
|
||||||
/// per frame is higher than max_hd_pixels, but no
|
|
||||||
/// higher than max_uhd1_pixels, i.e. (max_hd_pixels,
|
|
||||||
/// max_uhd1_pixels], it is UHD1. Otherwise it is
|
|
||||||
/// UHD2.
|
|
||||||
/// @param stream_info Encrypted stream info.
|
|
||||||
/// @return the stream label associated with `stream_info`. Can be "AUDIO",
|
|
||||||
/// "SD", "HD", "UHD1" or "UHD2".
|
|
||||||
static SHAKA_EXPORT std::string DefaultStreamLabelFunction(
|
|
||||||
int max_sd_pixels,
|
|
||||||
int max_hd_pixels,
|
|
||||||
int max_uhd1_pixels,
|
|
||||||
const EncryptedStreamAttributes& stream_attributes);
|
|
||||||
const int kDefaultMaxSdPixels = 768 * 576;
|
|
||||||
const int kDefaultMaxHdPixels = 1920 * 1080;
|
|
||||||
const int kDefaultMaxUhd1Pixels = 4096 * 2160;
|
|
||||||
/// Stream label function assigns a stream label to the stream to be
|
|
||||||
/// encrypted. Stream label is used to associate KeyPair with streams. Streams
|
|
||||||
/// with the same stream label always uses the same keyPair; Streams with
|
|
||||||
/// different stream label could use the same or different KeyPairs.
|
|
||||||
std::function<std::string(const EncryptedStreamAttributes& stream_attributes)>
|
|
||||||
stream_label_func =
|
|
||||||
std::bind(&EncryptionParams::DefaultStreamLabelFunction,
|
|
||||||
kDefaultMaxSdPixels,
|
|
||||||
kDefaultMaxHdPixels,
|
|
||||||
kDefaultMaxUhd1Pixels,
|
|
||||||
std::placeholders::_1);
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Widevine decryption parameters.
|
|
||||||
struct WidevineDecryptionParams {
|
|
||||||
/// Widevine license / key server URL.
|
|
||||||
std::string key_server_url;
|
|
||||||
/// Signer credential for Widevine license / key server.
|
|
||||||
WidevineSigner signer;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Raw key decryption parameters, i.e. with key parameters provided.
|
|
||||||
struct RawKeyDecryptionParams {
|
|
||||||
using StreamLabel = std::string;
|
|
||||||
struct KeyPair {
|
|
||||||
std::vector<uint8_t> key_id;
|
|
||||||
std::vector<uint8_t> key;
|
|
||||||
};
|
|
||||||
/// Defines the KeyPair for the streams. An empty `StreamLabel` indicates the
|
|
||||||
/// default `KeyPair`, which applies to all the `StreamLabels` not present in
|
|
||||||
/// `key_map`.
|
|
||||||
std::map<StreamLabel, KeyPair> key_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Decryption parameters.
|
|
||||||
struct DecryptionParams {
|
|
||||||
/// Specifies the key provider, which determines which key provider is used
|
|
||||||
/// and which encryption params is valid. 'kNone' means not to decrypt the
|
|
||||||
/// streams.
|
|
||||||
KeyProvider key_provider = KeyProvider::kNone;
|
|
||||||
// Only one of the two fields is valid.
|
|
||||||
WidevineDecryptionParams widevine;
|
|
||||||
RawKeyDecryptionParams raw_key;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parameters used for testing.
|
/// Parameters used for testing.
|
||||||
struct TestParams {
|
struct TestParams {
|
||||||
/// Whether to dump input stream info.
|
/// Whether to dump input stream info.
|
||||||
|
@ -440,6 +219,31 @@ class SHAKA_EXPORT Packager {
|
||||||
/// @return The version of the library.
|
/// @return The version of the library.
|
||||||
static std::string GetLibraryVersion();
|
static std::string GetLibraryVersion();
|
||||||
|
|
||||||
|
/// Default stream label function implementation.
|
||||||
|
/// @param max_sd_pixels The threshold to determine whether a video track
|
||||||
|
/// should be considered as SD. If the max pixels per
|
||||||
|
/// frame is no higher than max_sd_pixels, i.e. [0,
|
||||||
|
/// max_sd_pixels], it is SD.
|
||||||
|
/// @param max_hd_pixels The threshold to determine whether a video track
|
||||||
|
/// should be considered as HD. If the max pixels per
|
||||||
|
/// frame is higher than max_sd_pixels, but no higher
|
||||||
|
/// than max_hd_pixels, i.e. (max_sd_pixels,
|
||||||
|
/// max_hd_pixels], it is HD.
|
||||||
|
/// @param max_uhd1_pixels The threshold to determine whether a video track
|
||||||
|
/// should be considered as UHD1. If the max pixels
|
||||||
|
/// per frame is higher than max_hd_pixels, but no
|
||||||
|
/// higher than max_uhd1_pixels, i.e. (max_hd_pixels,
|
||||||
|
/// max_uhd1_pixels], it is UHD1. Otherwise it is
|
||||||
|
/// UHD2.
|
||||||
|
/// @param stream_info Encrypted stream info.
|
||||||
|
/// @return the stream label associated with `stream_info`. Can be "AUDIO",
|
||||||
|
/// "SD", "HD", "UHD1" or "UHD2".
|
||||||
|
static std::string DefaultStreamLabelFunction(
|
||||||
|
int max_sd_pixels,
|
||||||
|
int max_hd_pixels,
|
||||||
|
int max_uhd1_pixels,
|
||||||
|
const EncryptionParams::EncryptedStreamAttributes& stream_attributes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Packager(const Packager&) = delete;
|
Packager(const Packager&) = delete;
|
||||||
Packager& operator=(const Packager&) = delete;
|
Packager& operator=(const Packager&) = delete;
|
||||||
|
|
Loading…
Reference in New Issue