Add flag for extra PlayReady header data.
Fixes #756 Change-Id: I4fa6328480130675a0257fd2c6663d91729cf72c
This commit is contained in:
parent
665e784cbd
commit
1911c1beaa
|
@ -27,6 +27,9 @@ DEFINE_int32(
|
||||||
"Apply to video streams with 'cbcs' and 'cens' protection schemes only; "
|
"Apply to video streams with 'cbcs' and 'cens' protection schemes only; "
|
||||||
"ignored otherwise.");
|
"ignored otherwise.");
|
||||||
DEFINE_bool(vp9_subsample_encryption, true, "Enable VP9 subsample encryption.");
|
DEFINE_bool(vp9_subsample_encryption, true, "Enable VP9 subsample encryption.");
|
||||||
|
DEFINE_string(playready_extra_header_data,
|
||||||
|
"",
|
||||||
|
"Extra XML data to add to PlayReady headers.");
|
||||||
|
|
||||||
bool ValueNotGreaterThanTen(const char* flagname, int32_t value) {
|
bool ValueNotGreaterThanTen(const char* flagname, int32_t value) {
|
||||||
if (value > 10) {
|
if (value > 10) {
|
||||||
|
@ -40,5 +43,17 @@ bool ValueNotGreaterThanTen(const char* flagname, int32_t value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ValueIsXml(const char* flagname, const std::string& value) {
|
||||||
|
if (value.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (value[0] != '<' || value[value.size() - 1] != '>') {
|
||||||
|
fprintf(stderr, "ERROR: %s must be valid XML.\n", flagname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_validator(crypt_byte_block, &ValueNotGreaterThanTen);
|
DEFINE_validator(crypt_byte_block, &ValueNotGreaterThanTen);
|
||||||
DEFINE_validator(skip_byte_block, &ValueNotGreaterThanTen);
|
DEFINE_validator(skip_byte_block, &ValueNotGreaterThanTen);
|
||||||
|
DEFINE_validator(playready_extra_header_data, &ValueIsXml);
|
||||||
|
|
|
@ -16,5 +16,6 @@ DECLARE_string(protection_scheme);
|
||||||
DECLARE_int32(crypt_byte_block);
|
DECLARE_int32(crypt_byte_block);
|
||||||
DECLARE_int32(skip_byte_block);
|
DECLARE_int32(skip_byte_block);
|
||||||
DECLARE_bool(vp9_subsample_encryption);
|
DECLARE_bool(vp9_subsample_encryption);
|
||||||
|
DECLARE_string(playready_extra_header_data);
|
||||||
|
|
||||||
#endif // PACKAGER_APP_CRYPTO_FLAGS_H_
|
#endif // PACKAGER_APP_CRYPTO_FLAGS_H_
|
||||||
|
|
|
@ -351,6 +351,8 @@ base::Optional<PackagingParams> GetPackagingParams() {
|
||||||
encryption_params.stream_label_func = std::bind(
|
encryption_params.stream_label_func = std::bind(
|
||||||
&Packager::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);
|
||||||
|
encryption_params.playready_extra_header_data =
|
||||||
|
FLAGS_playready_extra_header_data;
|
||||||
}
|
}
|
||||||
switch (encryption_params.key_provider) {
|
switch (encryption_params.key_provider) {
|
||||||
case KeyProvider::kWidevine: {
|
case KeyProvider::kWidevine: {
|
||||||
|
|
|
@ -32,7 +32,7 @@ const std::string kPlayHeaderObject_4_0 =
|
||||||
"version=\"4.0.0.0\"><DATA>"
|
"version=\"4.0.0.0\"><DATA>"
|
||||||
"<PROTECTINFO><KEYLEN>16</KEYLEN><ALGID>AESCTR</ALGID></PROTECTINFO>"
|
"<PROTECTINFO><KEYLEN>16</KEYLEN><ALGID>AESCTR</ALGID></PROTECTINFO>"
|
||||||
"<KID>$0</KID><CHECKSUM>$1</CHECKSUM>"
|
"<KID>$0</KID><CHECKSUM>$1</CHECKSUM>"
|
||||||
"</DATA></WRMHEADER>";
|
"</DATA>$2</WRMHEADER>";
|
||||||
|
|
||||||
// For PlayReady clients 4.0+ that support CBC keys.
|
// For PlayReady clients 4.0+ that support CBC keys.
|
||||||
const std::string kPlayHeaderObject_4_3 =
|
const std::string kPlayHeaderObject_4_3 =
|
||||||
|
@ -40,7 +40,7 @@ const std::string kPlayHeaderObject_4_3 =
|
||||||
"xmlns=\"http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader\" "
|
"xmlns=\"http://schemas.microsoft.com/DRM/2007/03/PlayReadyHeader\" "
|
||||||
"version=\"4.3.0.0\"><DATA><PROTECTINFO><KIDS>"
|
"version=\"4.3.0.0\"><DATA><PROTECTINFO><KIDS>"
|
||||||
"<KID ALGID=\"AESCBC\" VALUE=\"$0\"></KID>"
|
"<KID ALGID=\"AESCBC\" VALUE=\"$0\"></KID>"
|
||||||
"</KIDS></PROTECTINFO></DATA></WRMHEADER>";
|
"</KIDS></PROTECTINFO></DATA>$1</WRMHEADER>";
|
||||||
|
|
||||||
// Converts the key_id's endianness.
|
// Converts the key_id's endianness.
|
||||||
std::vector<uint8_t> ConvertGuidEndianness(const std::vector<uint8_t>& input) {
|
std::vector<uint8_t> ConvertGuidEndianness(const std::vector<uint8_t>& input) {
|
||||||
|
@ -64,6 +64,7 @@ std::vector<uint8_t> ConvertGuidEndianness(const std::vector<uint8_t>& input) {
|
||||||
// https://docs.microsoft.com/en-us/playready/specifications/playready-header-specification
|
// https://docs.microsoft.com/en-us/playready/specifications/playready-header-specification
|
||||||
Status GeneratePlayReadyPsshData(const std::vector<uint8_t>& key_id,
|
Status GeneratePlayReadyPsshData(const std::vector<uint8_t>& key_id,
|
||||||
const std::vector<uint8_t>& key,
|
const std::vector<uint8_t>& key,
|
||||||
|
const std::string& extra_header_data,
|
||||||
const FourCC protection_scheme,
|
const FourCC protection_scheme,
|
||||||
std::vector<uint8_t>* output) {
|
std::vector<uint8_t>* output) {
|
||||||
CHECK(output);
|
CHECK(output);
|
||||||
|
@ -92,6 +93,8 @@ Status GeneratePlayReadyPsshData(const std::vector<uint8_t>& key_id,
|
||||||
playready_header = kPlayHeaderObject_4_3;
|
playready_header = kPlayHeaderObject_4_3;
|
||||||
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$0",
|
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$0",
|
||||||
base64_key_id);
|
base64_key_id);
|
||||||
|
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$1",
|
||||||
|
extra_header_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FOURCC_cenc:
|
case FOURCC_cenc:
|
||||||
|
@ -101,6 +104,8 @@ Status GeneratePlayReadyPsshData(const std::vector<uint8_t>& key_id,
|
||||||
base64_key_id);
|
base64_key_id);
|
||||||
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$1",
|
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$1",
|
||||||
base64_checksum);
|
base64_checksum);
|
||||||
|
base::ReplaceFirstSubstringAfterOffset(&playready_header, 0, "$2",
|
||||||
|
extra_header_data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -151,10 +156,13 @@ Status GeneratePlayReadyPsshData(const std::vector<uint8_t>& key_id,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PlayReadyPsshGenerator::PlayReadyPsshGenerator(FourCC protection_scheme)
|
PlayReadyPsshGenerator::PlayReadyPsshGenerator(
|
||||||
|
const std::string& extra_header_data,
|
||||||
|
FourCC protection_scheme)
|
||||||
: PsshGenerator(std::vector<uint8_t>(std::begin(kPlayReadySystemId),
|
: PsshGenerator(std::vector<uint8_t>(std::begin(kPlayReadySystemId),
|
||||||
std::end(kPlayReadySystemId)),
|
std::end(kPlayReadySystemId)),
|
||||||
kPlayReadyPsshBoxVersion),
|
kPlayReadyPsshBoxVersion),
|
||||||
|
extra_header_data_(extra_header_data),
|
||||||
protection_scheme_(protection_scheme) {}
|
protection_scheme_(protection_scheme) {}
|
||||||
|
|
||||||
PlayReadyPsshGenerator::~PlayReadyPsshGenerator() {}
|
PlayReadyPsshGenerator::~PlayReadyPsshGenerator() {}
|
||||||
|
@ -168,8 +176,8 @@ PlayReadyPsshGenerator::GeneratePsshDataFromKeyIdAndKey(
|
||||||
const std::vector<uint8_t>& key_id,
|
const std::vector<uint8_t>& key_id,
|
||||||
const std::vector<uint8_t>& key) const {
|
const std::vector<uint8_t>& key) const {
|
||||||
std::vector<uint8_t> pssh_data;
|
std::vector<uint8_t> pssh_data;
|
||||||
Status status =
|
Status status = GeneratePlayReadyPsshData(key_id, key, extra_header_data_,
|
||||||
GeneratePlayReadyPsshData(key_id, key, protection_scheme_, &pssh_data);
|
protection_scheme_, &pssh_data);
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
LOG(ERROR) << status.ToString();
|
LOG(ERROR) << status.ToString();
|
||||||
return base::nullopt;
|
return base::nullopt;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef MEDIA_BASE_PLAYREADY_PSSH_GENERATOR_H_
|
#ifndef MEDIA_BASE_PLAYREADY_PSSH_GENERATOR_H_
|
||||||
#define MEDIA_BASE_PLAYREADY_PSSH_GENERATOR_H_
|
#define MEDIA_BASE_PLAYREADY_PSSH_GENERATOR_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "packager/media/base/fourccs.h"
|
#include "packager/media/base/fourccs.h"
|
||||||
#include "packager/media/base/pssh_generator.h"
|
#include "packager/media/base/pssh_generator.h"
|
||||||
|
|
||||||
|
@ -15,7 +17,8 @@ namespace media {
|
||||||
|
|
||||||
class PlayReadyPsshGenerator : public PsshGenerator {
|
class PlayReadyPsshGenerator : public PsshGenerator {
|
||||||
public:
|
public:
|
||||||
explicit PlayReadyPsshGenerator(FourCC protection_scheme);
|
explicit PlayReadyPsshGenerator(const std::string& extra_header_data,
|
||||||
|
FourCC protection_scheme);
|
||||||
~PlayReadyPsshGenerator() override;
|
~PlayReadyPsshGenerator() override;
|
||||||
|
|
||||||
/// @name PsshGenerator implemetation overrides.
|
/// @name PsshGenerator implemetation overrides.
|
||||||
|
@ -36,7 +39,8 @@ class PlayReadyPsshGenerator : public PsshGenerator {
|
||||||
const std::vector<uint8_t>& key_id,
|
const std::vector<uint8_t>& key_id,
|
||||||
const std::vector<uint8_t>& key) const override;
|
const std::vector<uint8_t>& key) const override;
|
||||||
|
|
||||||
FourCC protection_scheme_ = FOURCC_NULL;
|
const std::string extra_header_data_;
|
||||||
|
const FourCC protection_scheme_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -182,6 +182,8 @@ const char kExpectedWidevinePsshCbcs[] = {
|
||||||
'\x9B', '\x06',
|
'\x9B', '\x06',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char kPlayReadyExtraHeaderData[] = "";
|
||||||
|
|
||||||
std::vector<uint8_t> GetTestKeyId1() {
|
std::vector<uint8_t> GetTestKeyId1() {
|
||||||
return std::vector<uint8_t>(std::begin(kTestKeyId1), std::end(kTestKeyId1));
|
return std::vector<uint8_t>(std::begin(kTestKeyId1), std::end(kTestKeyId1));
|
||||||
}
|
}
|
||||||
|
@ -201,7 +203,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIds) {
|
||||||
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
||||||
GetTestKeyId2()};
|
GetTestKeyId2()};
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_cenc));
|
new PlayReadyPsshGenerator(kPlayReadyExtraHeaderData, FOURCC_cenc));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_NOT_OK(
|
EXPECT_NOT_OK(
|
||||||
playready_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
playready_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||||
|
@ -212,7 +214,7 @@ TEST(PsshGeneratorTest,
|
||||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_NULL));
|
new PlayReadyPsshGenerator(kPlayReadyExtraHeaderData, FOURCC_NULL));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_NOT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_NOT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
@ -222,7 +224,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKeyUsingCenc) {
|
||||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_cenc));
|
new PlayReadyPsshGenerator(kPlayReadyExtraHeaderData, FOURCC_cenc));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
@ -236,7 +238,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKeyUsingCens) {
|
||||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_cens));
|
new PlayReadyPsshGenerator("", FOURCC_cens));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
@ -250,7 +252,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKeyUsingCbc1) {
|
||||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_cbc1));
|
new PlayReadyPsshGenerator("", FOURCC_cbc1));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
@ -264,7 +266,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKeyUsingCbcs) {
|
||||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||||
new PlayReadyPsshGenerator(FOURCC_cbcs));
|
new PlayReadyPsshGenerator(kPlayReadyExtraHeaderData, FOURCC_cbcs));
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
|
|
@ -81,6 +81,7 @@ void FillPsshGenerators(
|
||||||
if (has_flag(encryption_params.protection_systems,
|
if (has_flag(encryption_params.protection_systems,
|
||||||
ProtectionSystem::kPlayReady)) {
|
ProtectionSystem::kPlayReady)) {
|
||||||
pssh_generators->emplace_back(new PlayReadyPsshGenerator(
|
pssh_generators->emplace_back(new PlayReadyPsshGenerator(
|
||||||
|
encryption_params.playready_extra_header_data,
|
||||||
static_cast<FourCC>(encryption_params.protection_scheme)));
|
static_cast<FourCC>(encryption_params.protection_scheme)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,8 @@ struct EncryptionParams {
|
||||||
|
|
||||||
/// The protection systems to generate, multiple can be OR'd together.
|
/// The protection systems to generate, multiple can be OR'd together.
|
||||||
ProtectionSystem protection_systems;
|
ProtectionSystem protection_systems;
|
||||||
|
/// Extra XML data to add to PlayReady data.
|
||||||
|
std::string playready_extra_header_data;
|
||||||
|
|
||||||
/// Clear lead duration in seconds.
|
/// Clear lead duration in seconds.
|
||||||
double clear_lead_in_seconds = 0;
|
double clear_lead_in_seconds = 0;
|
||||||
|
|
Loading…
Reference in New Issue