Refactor ProtectionSystemSpecificInfo class to struct
This is in preparation of supporting entitlement license API, where common encryption server may return concatenated PSSHs directly. Refactored ProtectionSystemSpecificInfo into a struct containing concatenated PSSHs. This will make it easier to pass PSSHs around. Also, most of the time, users of ProtectionSystemSpecificInfo do not care what is in PSSH; so moved PSSH box parsing and building out of ProtectionSystemSpecificInfo. b/78171767 Change-Id: I1c4d5e7e23efd2f7d4b2b9704378323112e47f00
This commit is contained in:
parent
6b86b085b4
commit
b5a73fc1d5
|
@ -131,15 +131,16 @@ MediaInfo MakeMediaInfoPathsRelativeToPlaylist(
|
||||||
bool WidevinePsshToJson(const std::vector<uint8_t>& pssh_box,
|
bool WidevinePsshToJson(const std::vector<uint8_t>& pssh_box,
|
||||||
const std::vector<uint8_t>& key_id,
|
const std::vector<uint8_t>& key_id,
|
||||||
std::string* pssh_json) {
|
std::string* pssh_json) {
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
std::unique_ptr<media::PsshBoxBuilder> pssh_builder =
|
||||||
if (!pssh_info.Parse(pssh_box.data(), pssh_box.size())) {
|
media::PsshBoxBuilder::ParseFromBox(pssh_box.data(), pssh_box.size());
|
||||||
|
if (!pssh_builder) {
|
||||||
LOG(ERROR) << "Failed to parse PSSH box.";
|
LOG(ERROR) << "Failed to parse PSSH box.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
media::WidevinePsshData pssh_proto;
|
media::WidevinePsshData pssh_proto;
|
||||||
if (!pssh_proto.ParseFromArray(pssh_info.pssh_data().data(),
|
if (!pssh_proto.ParseFromArray(pssh_builder->pssh_data().data(),
|
||||||
pssh_info.pssh_data().size())) {
|
pssh_builder->pssh_data().size())) {
|
||||||
LOG(ERROR) << "Failed to parse protection_system_specific_data.";
|
LOG(ERROR) << "Failed to parse protection_system_specific_data.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,11 +493,11 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
|
||||||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||||
widevine_pssh_data_str.end());
|
widevine_pssh_data_str.end());
|
||||||
|
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
media::PsshBoxBuilder pssh_builder;
|
||||||
pssh_info.set_pssh_data(pssh_data);
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||||
widevine_system_id_.size());
|
widevine_system_id_.size());
|
||||||
pssh_info.add_key_id(any_key_id);
|
pssh_builder.add_key_id(any_key_id);
|
||||||
|
|
||||||
const char kExpectedJson[] =
|
const char kExpectedJson[] =
|
||||||
"{"
|
"{"
|
||||||
|
@ -508,7 +508,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
|
||||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||||
|
|
||||||
std::string expected_pssh_base64;
|
std::string expected_pssh_base64;
|
||||||
const std::vector<uint8_t> pssh_box = pssh_info.CreateBox();
|
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
|
||||||
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
||||||
&expected_pssh_base64);
|
&expected_pssh_base64);
|
||||||
|
|
||||||
|
@ -554,13 +554,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) {
|
||||||
std::string expected_json_base64;
|
std::string expected_json_base64;
|
||||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||||
|
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
media::PsshBoxBuilder pssh_builder;
|
||||||
pssh_info.set_pssh_data(pssh_data);
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||||
widevine_system_id_.size());
|
widevine_system_id_.size());
|
||||||
|
|
||||||
std::string expected_pssh_base64;
|
std::string expected_pssh_base64;
|
||||||
const std::vector<uint8_t> pssh_box = pssh_info.CreateBox();
|
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
|
||||||
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
||||||
&expected_pssh_base64);
|
&expected_pssh_base64);
|
||||||
|
|
||||||
|
@ -647,12 +647,12 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
|
||||||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||||
widevine_pssh_data_str.end());
|
widevine_pssh_data_str.end());
|
||||||
|
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
media::PsshBoxBuilder pssh_builder;
|
||||||
pssh_info.set_pssh_data(pssh_data);
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||||
widevine_system_id_.size());
|
widevine_system_id_.size());
|
||||||
pssh_info.add_key_id(first_keyid);
|
pssh_builder.add_key_id(first_keyid);
|
||||||
pssh_info.add_key_id(second_keyid);
|
pssh_builder.add_key_id(second_keyid);
|
||||||
|
|
||||||
const char kExpectedJson[] =
|
const char kExpectedJson[] =
|
||||||
"{"
|
"{"
|
||||||
|
@ -663,7 +663,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
|
||||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||||
|
|
||||||
std::string expected_pssh_base64;
|
std::string expected_pssh_base64;
|
||||||
const std::vector<uint8_t> pssh_box = pssh_info.CreateBox();
|
const std::vector<uint8_t> pssh_box = pssh_builder.CreateBox();
|
||||||
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
||||||
&expected_pssh_base64);
|
&expected_pssh_base64);
|
||||||
|
|
||||||
|
@ -762,14 +762,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineCencEncryptionScheme) {
|
||||||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||||
widevine_pssh_data_str.end());
|
widevine_pssh_data_str.end());
|
||||||
|
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
|
||||||
pssh_info.set_pssh_data(pssh_data);
|
|
||||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
|
||||||
widevine_system_id_.size());
|
|
||||||
pssh_info.add_key_id(any_key_id);
|
|
||||||
|
|
||||||
std::string expected_pssh_base64;
|
std::string expected_pssh_base64;
|
||||||
const std::vector<uint8_t> pssh_box = pssh_info.CreateBox();
|
const std::vector<uint8_t> pssh_box = {'p', 's', 's', 'h'};
|
||||||
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
base::Base64Encode(std::string(pssh_box.begin(), pssh_box.end()),
|
||||||
&expected_pssh_base64);
|
&expected_pssh_base64);
|
||||||
|
|
||||||
|
@ -814,11 +808,11 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
||||||
std::string expected_json_base64;
|
std::string expected_json_base64;
|
||||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||||
|
|
||||||
media::ProtectionSystemSpecificInfo pssh_info;
|
media::PsshBoxBuilder pssh_builder;
|
||||||
pssh_info.set_pssh_data(pssh_data);
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||||
widevine_system_id_.size());
|
widevine_system_id_.size());
|
||||||
pssh_info.add_key_id(any_key_id);
|
pssh_builder.add_key_id(any_key_id);
|
||||||
|
|
||||||
EXPECT_CALL(*mock_media_playlist,
|
EXPECT_CALL(*mock_media_playlist,
|
||||||
AddEncryptionInfo(
|
AddEncryptionInfo(
|
||||||
|
@ -835,7 +829,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
||||||
"WVwcm92aWRlciIJY29udGVudGlk"),
|
"WVwcm92aWRlciIJY29udGVudGlk"),
|
||||||
StrEq("0x11223344112233441122334411223344"), StrEq(""),
|
StrEq("0x11223344112233441122334411223344"), StrEq(""),
|
||||||
StrEq("urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"), StrEq("1")));
|
StrEq("urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"), StrEq("1")));
|
||||||
std::vector<uint8_t> pssh_as_vec = pssh_info.CreateBox();
|
std::vector<uint8_t> pssh_as_vec = pssh_builder.CreateBox();
|
||||||
std::string pssh_in_string(pssh_as_vec.begin(), pssh_as_vec.end());
|
std::string pssh_in_string(pssh_as_vec.begin(), pssh_as_vec.end());
|
||||||
std::string base_64_encoded_pssh;
|
std::string base_64_encoded_pssh;
|
||||||
base::Base64Encode(pssh_in_string, &base_64_encoded_pssh);
|
base::Base64Encode(pssh_in_string, &base_64_encoded_pssh);
|
||||||
|
@ -845,7 +839,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
||||||
EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
|
EXPECT_TRUE(notifier.NotifyEncryptionUpdate(
|
||||||
stream_id,
|
stream_id,
|
||||||
std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)),
|
std::vector<uint8_t>(kAnyKeyId, kAnyKeyId + arraysize(kAnyKeyId)),
|
||||||
widevine_system_id_, empty_iv, pssh_info.CreateBox()));
|
widevine_system_id_, empty_iv, pssh_builder.CreateBox()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWithoutStreamsRegistered) {
|
TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWithoutStreamsRegistered) {
|
||||||
|
|
|
@ -151,11 +151,13 @@ Status SetKeyInformationFromServerResponse(const std::string& response,
|
||||||
LOG(ERROR) << "Cannot parse pssh data, " << pssh_data_b64;
|
LOG(ERROR) << "Cannot parse pssh data, " << pssh_data_b64;
|
||||||
return Status(error::SERVER_ERROR, "Cannot parse pssh.");
|
return Status(error::SERVER_ERROR, "Cannot parse pssh.");
|
||||||
}
|
}
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
info.add_key_id(encryption_key->key_id);
|
PsshBoxBuilder pssh_builder;
|
||||||
info.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId));
|
pssh_builder.add_key_id(encryption_key->key_id);
|
||||||
info.set_pssh_data(pssh_data);
|
pssh_builder.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId));
|
||||||
encryption_key->key_system_info.push_back(info);
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
|
encryption_key->key_system_info.push_back(
|
||||||
|
{pssh_builder.system_id(), pssh_builder.CreateBox()});
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,81 +6,98 @@
|
||||||
|
|
||||||
#include "packager/media/base/protection_system_specific_info.h"
|
#include "packager/media/base/protection_system_specific_info.h"
|
||||||
|
|
||||||
|
#include "packager/media/base/buffer_reader.h"
|
||||||
#include "packager/media/base/buffer_writer.h"
|
#include "packager/media/base/buffer_writer.h"
|
||||||
#include "packager/media/base/fourccs.h"
|
#include "packager/media/base/fourccs.h"
|
||||||
#include "packager/media/base/rcheck.h"
|
#include "packager/media/base/rcheck.h"
|
||||||
|
|
||||||
|
#define RETURN_NULL_IF_FALSE(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) { \
|
||||||
|
LOG(ERROR) << "Failure while processing: " << #x; \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const size_t kSystemIdSize = 16u;
|
const size_t kSystemIdSize = 16u;
|
||||||
|
// 4-byte size, 4-byte fourcc, 4-byte version_and_flags.
|
||||||
|
const size_t kPsshBoxHeaderSize = 12u;
|
||||||
const size_t kKeyIdSize = 16u;
|
const size_t kKeyIdSize = 16u;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ProtectionSystemSpecificInfo::ProtectionSystemSpecificInfo()
|
|
||||||
: version_(0) {}
|
|
||||||
ProtectionSystemSpecificInfo::~ProtectionSystemSpecificInfo() {}
|
|
||||||
|
|
||||||
bool ProtectionSystemSpecificInfo::ParseBoxes(
|
bool ProtectionSystemSpecificInfo::ParseBoxes(
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
size_t data_size,
|
size_t data_size,
|
||||||
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes) {
|
std::vector<ProtectionSystemSpecificInfo>* pssh_infos) {
|
||||||
pssh_boxes->clear();
|
pssh_infos->clear();
|
||||||
BufferReader reader(data, data_size);
|
BufferReader reader(data, data_size);
|
||||||
while (reader.HasBytes(1)) {
|
while (reader.HasBytes(1)) {
|
||||||
size_t start_position = reader.pos();
|
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
RCHECK(reader.Read4(&size));
|
RCHECK(reader.Read4(&size));
|
||||||
RCHECK(reader.SkipBytes(size - 4));
|
RCHECK(reader.SkipBytes(size - 4));
|
||||||
|
RCHECK(size > kPsshBoxHeaderSize + kSystemIdSize);
|
||||||
|
|
||||||
pssh_boxes->push_back(ProtectionSystemSpecificInfo());
|
pssh_infos->push_back(
|
||||||
RCHECK(pssh_boxes->back().Parse(data + start_position, size));
|
{std::vector<uint8_t>(data + kPsshBoxHeaderSize,
|
||||||
|
data + kPsshBoxHeaderSize + kSystemIdSize),
|
||||||
|
std::vector<uint8_t>(data, data + size)});
|
||||||
|
|
||||||
|
data += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtectionSystemSpecificInfo::Parse(const uint8_t* data,
|
std::unique_ptr<PsshBoxBuilder> PsshBoxBuilder::ParseFromBox(
|
||||||
|
const uint8_t* data,
|
||||||
size_t data_size) {
|
size_t data_size) {
|
||||||
|
std::unique_ptr<PsshBoxBuilder> pssh_builder(new PsshBoxBuilder);
|
||||||
|
BufferReader reader(data, data_size);
|
||||||
|
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t box_type;
|
uint32_t box_type;
|
||||||
uint32_t version_and_flags;
|
uint32_t version_and_flags;
|
||||||
BufferReader reader(data, data_size);
|
RETURN_NULL_IF_FALSE(reader.Read4(&size));
|
||||||
|
RETURN_NULL_IF_FALSE(reader.Read4(&box_type));
|
||||||
|
RETURN_NULL_IF_FALSE(size == data_size);
|
||||||
|
RETURN_NULL_IF_FALSE(box_type == FOURCC_pssh);
|
||||||
|
RETURN_NULL_IF_FALSE(reader.Read4(&version_and_flags));
|
||||||
|
|
||||||
RCHECK(reader.Read4(&size));
|
pssh_builder->version_ = (version_and_flags >> 24);
|
||||||
RCHECK(reader.Read4(&box_type));
|
RETURN_NULL_IF_FALSE(pssh_builder->version_ < 2);
|
||||||
RCHECK(size == data_size);
|
|
||||||
RCHECK(box_type == FOURCC_pssh);
|
|
||||||
RCHECK(reader.Read4(&version_and_flags));
|
|
||||||
|
|
||||||
version_ = (version_and_flags >> 24);
|
RETURN_NULL_IF_FALSE(
|
||||||
RCHECK(version_ < 2);
|
reader.ReadToVector(&pssh_builder->system_id_, kSystemIdSize));
|
||||||
RCHECK(reader.ReadToVector(&system_id_, kSystemIdSize));
|
|
||||||
|
|
||||||
if (version_ == 1) {
|
if (pssh_builder->version_ == 1) {
|
||||||
uint32_t key_id_count;
|
uint32_t key_id_count;
|
||||||
RCHECK(reader.Read4(&key_id_count));
|
RETURN_NULL_IF_FALSE(reader.Read4(&key_id_count));
|
||||||
|
|
||||||
key_ids_.resize(key_id_count);
|
pssh_builder->key_ids_.resize(key_id_count);
|
||||||
for (uint32_t i = 0; i < key_id_count; i++) {
|
for (uint32_t i = 0; i < key_id_count; i++) {
|
||||||
RCHECK(reader.ReadToVector(&key_ids_[i], kKeyIdSize));
|
RETURN_NULL_IF_FALSE(
|
||||||
|
reader.ReadToVector(&pssh_builder->key_ids_[i], kKeyIdSize));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Consider parsing key IDs from Widevine PSSH data.
|
// TODO: Consider parsing key IDs from Widevine PSSH data.
|
||||||
uint32_t pssh_data_size;
|
uint32_t pssh_data_size;
|
||||||
RCHECK(reader.Read4(&pssh_data_size));
|
RETURN_NULL_IF_FALSE(reader.Read4(&pssh_data_size));
|
||||||
RCHECK(reader.ReadToVector(&pssh_data_, pssh_data_size));
|
RETURN_NULL_IF_FALSE(
|
||||||
|
reader.ReadToVector(&pssh_builder->pssh_data_, pssh_data_size));
|
||||||
|
|
||||||
// We should be at the end of the data. The reader should be initialized to
|
// We should be at the end of the data. The reader should be initialized to
|
||||||
// the data and size according to the size field of the box; therefore it
|
// the data and size according to the size field of the box; therefore it
|
||||||
// is an error if there are bytes remaining.
|
// is an error if there are bytes remaining.
|
||||||
RCHECK(!reader.HasBytes(1));
|
RETURN_NULL_IF_FALSE(!reader.HasBytes(1));
|
||||||
return true;
|
return pssh_builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ProtectionSystemSpecificInfo::CreateBox() const {
|
std::vector<uint8_t> PsshBoxBuilder::CreateBox() const {
|
||||||
DCHECK_EQ(kSystemIdSize, system_id_.size());
|
DCHECK_EQ(kSystemIdSize, system_id_.size());
|
||||||
|
|
||||||
const uint32_t box_type = FOURCC_pssh;
|
const uint32_t box_type = FOURCC_pssh;
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
#define PACKAGER_MEDIA_BASE_PROTECTION_SYSTEM_SPECIFIC_INFO_H_
|
#define PACKAGER_MEDIA_BASE_PROTECTION_SYSTEM_SPECIFIC_INFO_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/media/base/buffer_reader.h"
|
|
||||||
|
|
||||||
#define NO_PROTECTION_SYSTEM_FLAG 0x00
|
#define NO_PROTECTION_SYSTEM_FLAG 0x00
|
||||||
#define COMMON_PROTECTION_SYSTEM_FLAG 0x01
|
#define COMMON_PROTECTION_SYSTEM_FLAG 0x01
|
||||||
|
@ -21,10 +21,9 @@
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
class ProtectionSystemSpecificInfo {
|
struct ProtectionSystemSpecificInfo {
|
||||||
public:
|
std::vector<uint8_t> system_id;
|
||||||
ProtectionSystemSpecificInfo();
|
std::vector<uint8_t> psshs;
|
||||||
~ProtectionSystemSpecificInfo();
|
|
||||||
|
|
||||||
/// Parses multiple PSSH boxes from @a data. These boxes should be
|
/// Parses multiple PSSH boxes from @a data. These boxes should be
|
||||||
/// concatenated together. Any non-PSSH box is an error.
|
/// concatenated together. Any non-PSSH box is an error.
|
||||||
|
@ -33,10 +32,17 @@ class ProtectionSystemSpecificInfo {
|
||||||
const uint8_t* data,
|
const uint8_t* data,
|
||||||
size_t data_size,
|
size_t data_size,
|
||||||
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes);
|
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes);
|
||||||
|
};
|
||||||
|
|
||||||
|
class PsshBoxBuilder {
|
||||||
|
public:
|
||||||
|
PsshBoxBuilder() = default;
|
||||||
|
~PsshBoxBuilder() = default;
|
||||||
|
|
||||||
/// Parses the given PSSH box into this object.
|
/// Parses the given PSSH box into this object.
|
||||||
/// @return true on success; false on failure.
|
/// @return nullptr on failure.
|
||||||
bool Parse(const uint8_t* data, size_t data_size);
|
static std::unique_ptr<PsshBoxBuilder> ParseFromBox(const uint8_t* data,
|
||||||
|
size_t data_size);
|
||||||
|
|
||||||
/// Creates a PSSH box for the current data.
|
/// Creates a PSSH box for the current data.
|
||||||
std::vector<uint8_t> CreateBox() const;
|
std::vector<uint8_t> CreateBox() const;
|
||||||
|
@ -63,13 +69,13 @@ class ProtectionSystemSpecificInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t version_;
|
PsshBoxBuilder(const PsshBoxBuilder&) = delete;
|
||||||
|
PsshBoxBuilder& operator=(const PsshBoxBuilder&) = delete;
|
||||||
|
|
||||||
|
uint8_t version_ = 0;
|
||||||
std::vector<uint8_t> system_id_;
|
std::vector<uint8_t> system_id_;
|
||||||
std::vector<std::vector<uint8_t>> key_ids_;
|
std::vector<std::vector<uint8_t>> key_ids_;
|
||||||
std::vector<uint8_t> pssh_data_;
|
std::vector<uint8_t> pssh_data_;
|
||||||
|
|
||||||
// Don't use DISALLOW_COPY_AND_ASSIGN since the data stored here should be
|
|
||||||
// small, so the performance impact should be minimal.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -67,25 +67,37 @@ TEST_F(PsshTest, ParseBoxes_SupportsV0) {
|
||||||
std::vector<ProtectionSystemSpecificInfo> info;
|
std::vector<ProtectionSystemSpecificInfo> info;
|
||||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
||||||
v0_box_.data(), v0_box_.size(), &info));
|
v0_box_.data(), v0_box_.size(), &info));
|
||||||
ASSERT_EQ(1u, info.size());
|
|
||||||
|
|
||||||
ASSERT_EQ(0u, info[0].key_ids().size());
|
ASSERT_EQ(1u, info.size());
|
||||||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
EXPECT_EQ(test_system_id_, info[0].system_id);
|
||||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
|
||||||
EXPECT_EQ(0, info[0].pssh_box_version());
|
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||||
|
PsshBoxBuilder::ParseFromBox(info[0].psshs.data(), info[0].psshs.size());
|
||||||
|
ASSERT_TRUE(pssh_builder);
|
||||||
|
|
||||||
|
ASSERT_EQ(0u, pssh_builder->key_ids().size());
|
||||||
|
EXPECT_EQ(test_system_id_, pssh_builder->system_id());
|
||||||
|
EXPECT_EQ(test_pssh_data_, pssh_builder->pssh_data());
|
||||||
|
EXPECT_EQ(0, pssh_builder->pssh_box_version());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PsshTest, ParseBoxes_SupportsV1) {
|
TEST_F(PsshTest, ParseBoxes_SupportsV1) {
|
||||||
std::vector<ProtectionSystemSpecificInfo> info;
|
std::vector<ProtectionSystemSpecificInfo> info;
|
||||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
||||||
v1_box_.data(), v1_box_.size(), &info));
|
v1_box_.data(), v1_box_.size(), &info));
|
||||||
ASSERT_EQ(1u, info.size());
|
|
||||||
|
|
||||||
ASSERT_EQ(1u, info[0].key_ids().size());
|
ASSERT_EQ(1u, info.size());
|
||||||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
EXPECT_EQ(test_system_id_, info[0].system_id);
|
||||||
EXPECT_EQ(test_key_id_, info[0].key_ids()[0]);
|
|
||||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||||
EXPECT_EQ(1, info[0].pssh_box_version());
|
PsshBoxBuilder::ParseFromBox(info[0].psshs.data(), info[0].psshs.size());
|
||||||
|
ASSERT_TRUE(pssh_builder);
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, pssh_builder->key_ids().size());
|
||||||
|
EXPECT_EQ(test_system_id_, pssh_builder->system_id());
|
||||||
|
EXPECT_EQ(test_key_id_, pssh_builder->key_ids()[0]);
|
||||||
|
EXPECT_EQ(test_pssh_data_, pssh_builder->pssh_data());
|
||||||
|
EXPECT_EQ(1, pssh_builder->pssh_box_version());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
||||||
|
@ -95,45 +107,57 @@ TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
||||||
data.insert(data.end(), v1_box_.begin(), v1_box_.end());
|
data.insert(data.end(), v1_box_.begin(), v1_box_.end());
|
||||||
|
|
||||||
std::vector<ProtectionSystemSpecificInfo> info;
|
std::vector<ProtectionSystemSpecificInfo> info;
|
||||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(data.data(),
|
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(data.data(), data.size(),
|
||||||
data.size(), &info));
|
&info));
|
||||||
ASSERT_EQ(3u, info.size());
|
ASSERT_EQ(3u, info.size());
|
||||||
|
|
||||||
ASSERT_EQ(1u, info[0].key_ids().size());
|
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
PsshBoxBuilder::ParseFromBox(info[0].psshs.data(), info[0].psshs.size());
|
||||||
EXPECT_EQ(test_key_id_, info[0].key_ids()[0]);
|
ASSERT_TRUE(pssh_builder);
|
||||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
|
||||||
EXPECT_EQ(1, info[0].pssh_box_version());
|
|
||||||
|
|
||||||
ASSERT_EQ(0u, info[1].key_ids().size());
|
ASSERT_EQ(1u, pssh_builder->key_ids().size());
|
||||||
EXPECT_EQ(test_system_id_, info[1].system_id());
|
EXPECT_EQ(test_system_id_, pssh_builder->system_id());
|
||||||
EXPECT_EQ(test_pssh_data_, info[1].pssh_data());
|
EXPECT_EQ(test_key_id_, pssh_builder->key_ids()[0]);
|
||||||
EXPECT_EQ(0, info[1].pssh_box_version());
|
EXPECT_EQ(test_pssh_data_, pssh_builder->pssh_data());
|
||||||
|
EXPECT_EQ(1, pssh_builder->pssh_box_version());
|
||||||
|
|
||||||
ASSERT_EQ(1u, info[2].key_ids().size());
|
pssh_builder =
|
||||||
EXPECT_EQ(test_system_id_, info[2].system_id());
|
PsshBoxBuilder::ParseFromBox(info[1].psshs.data(), info[1].psshs.size());
|
||||||
EXPECT_EQ(test_key_id_, info[2].key_ids()[0]);
|
ASSERT_TRUE(pssh_builder);
|
||||||
EXPECT_EQ(test_pssh_data_, info[2].pssh_data());
|
|
||||||
EXPECT_EQ(1, info[2].pssh_box_version());
|
ASSERT_EQ(0u, pssh_builder->key_ids().size());
|
||||||
|
EXPECT_EQ(test_system_id_, pssh_builder->system_id());
|
||||||
|
EXPECT_EQ(test_pssh_data_, pssh_builder->pssh_data());
|
||||||
|
EXPECT_EQ(0, pssh_builder->pssh_box_version());
|
||||||
|
|
||||||
|
pssh_builder =
|
||||||
|
PsshBoxBuilder::ParseFromBox(info[2].psshs.data(), info[2].psshs.size());
|
||||||
|
ASSERT_TRUE(pssh_builder);
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, pssh_builder->key_ids().size());
|
||||||
|
EXPECT_EQ(test_system_id_, pssh_builder->system_id());
|
||||||
|
EXPECT_EQ(test_key_id_, pssh_builder->key_ids()[0]);
|
||||||
|
EXPECT_EQ(test_pssh_data_, pssh_builder->pssh_data());
|
||||||
|
EXPECT_EQ(1, pssh_builder->pssh_box_version());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PsshTest, CreateBox_MakesV0Boxes) {
|
TEST_F(PsshTest, CreateBox_MakesV0Boxes) {
|
||||||
ProtectionSystemSpecificInfo info;
|
PsshBoxBuilder pssh_builder;
|
||||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
pssh_builder.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||||
info.set_pssh_data(test_pssh_data_);
|
pssh_builder.set_pssh_data(test_pssh_data_);
|
||||||
info.set_pssh_box_version(0);
|
pssh_builder.set_pssh_box_version(0);
|
||||||
|
|
||||||
EXPECT_EQ(v0_box_, info.CreateBox());
|
EXPECT_EQ(v0_box_, pssh_builder.CreateBox());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PsshTest, CreateBox_MakesV1Boxes) {
|
TEST_F(PsshTest, CreateBox_MakesV1Boxes) {
|
||||||
ProtectionSystemSpecificInfo info;
|
PsshBoxBuilder pssh_builder;
|
||||||
info.add_key_id(test_key_id_);
|
pssh_builder.add_key_id(test_key_id_);
|
||||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
pssh_builder.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||||
info.set_pssh_data(test_pssh_data_);
|
pssh_builder.set_pssh_data(test_pssh_data_);
|
||||||
info.set_pssh_box_version(1);
|
pssh_builder.set_pssh_box_version(1);
|
||||||
|
|
||||||
EXPECT_EQ(v1_box_, info.CreateBox());
|
EXPECT_EQ(v1_box_, pssh_builder.CreateBox());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -8,6 +8,25 @@
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::vector<uint8_t> CreatePsshBox(
|
||||||
|
const std::vector<uint8_t>& system_id,
|
||||||
|
uint8_t version,
|
||||||
|
const std::vector<std::vector<uint8_t>>& key_ids,
|
||||||
|
const std::vector<uint8_t>& pssh_data) {
|
||||||
|
PsshBoxBuilder pssh_builder;
|
||||||
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
|
for (const std::vector<uint8_t>& key_id : key_ids) {
|
||||||
|
pssh_builder.add_key_id(key_id);
|
||||||
|
}
|
||||||
|
pssh_builder.set_pssh_box_version(version);
|
||||||
|
pssh_builder.set_system_id(system_id.data(), system_id.size());
|
||||||
|
|
||||||
|
return pssh_builder.CreateBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
PsshGenerator::PsshGenerator() {}
|
PsshGenerator::PsshGenerator() {}
|
||||||
|
|
||||||
|
@ -22,17 +41,9 @@ Status PsshGenerator::GeneratePsshFromKeyIds(
|
||||||
return Status(error::ENCRYPTION_FAILURE,
|
return Status(error::ENCRYPTION_FAILURE,
|
||||||
"Fail to generate PSSH data from multiple Key IDs.");
|
"Fail to generate PSSH data from multiple Key IDs.");
|
||||||
}
|
}
|
||||||
info->set_pssh_data(pssh_data.value());
|
info->system_id = SystemId();
|
||||||
|
info->psshs =
|
||||||
info->clear_key_ids();
|
CreatePsshBox(SystemId(), PsshBoxVersion(), key_ids, pssh_data.value());
|
||||||
for (const auto& key_id : key_ids) {
|
|
||||||
info->add_key_id(key_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
info->set_pssh_box_version(PsshBoxVersion());
|
|
||||||
const std::vector<uint8_t>& system_id = SystemId();
|
|
||||||
info->set_system_id(system_id.data(), system_id.size());
|
|
||||||
|
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,14 +57,9 @@ Status PsshGenerator::GeneratePsshFromKeyIdAndKey(
|
||||||
return Status(error::ENCRYPTION_FAILURE,
|
return Status(error::ENCRYPTION_FAILURE,
|
||||||
"Fail to generate PSSH data from Key ID and Key.");
|
"Fail to generate PSSH data from Key ID and Key.");
|
||||||
}
|
}
|
||||||
info->set_pssh_data(pssh_data.value());
|
info->system_id = SystemId();
|
||||||
|
info->psshs =
|
||||||
info->clear_key_ids();
|
CreatePsshBox(SystemId(), PsshBoxVersion(), {key_id}, pssh_data.value());
|
||||||
info->add_key_id(key_id);
|
|
||||||
info->set_pssh_box_version(PsshBoxVersion());
|
|
||||||
const std::vector<uint8_t>& system_id = SystemId();
|
|
||||||
info->set_system_id(system_id.data(), system_id.size());
|
|
||||||
|
|
||||||
return Status::OK;
|
return Status::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,65 +25,94 @@ const uint8_t kTestKey1[] = {'c', 'o', 'n', 't', 'e', 'n', 't', 'k',
|
||||||
const uint8_t kTestKeyId2[] = {'k', 'e', 'y', 'i', 'd', '2', '~', '~',
|
const uint8_t kTestKeyId2[] = {'k', 'e', 'y', 'i', 'd', '2', '~', '~',
|
||||||
'~', '~', '~', '~', '~', '~', '~', '~'};
|
'~', '~', '~', '~', '~', '~', '~', '~'};
|
||||||
|
|
||||||
const char kExpectedPlayReadyPsshData[] = {
|
const char kExpectedPlayReadyPssh[] = {
|
||||||
'\x6', '\x2', '\x0', '\x0', '\x1', '\x0', '\x1', '\x0', '\xfc', '\x1',
|
'\x0', '\x0', '\x2', '\x3A', 'p', 's', 's', 'h', '\x1',
|
||||||
'<', '\x0', 'W', '\x0', 'R', '\x0', 'M', '\x0', 'H', '\x0',
|
'\x0', '\x0', '\x0', '\x9A', '\x04', '\xf0', '\x79', '\x98', '\x40',
|
||||||
'E', '\x0', 'A', '\x0', 'D', '\x0', 'E', '\x0', 'R', '\x0',
|
'\x42', '\x86', '\xab', '\x92', '\xe6', '\x5b', '\xe0', '\x88', '\x5f',
|
||||||
' ', '\x0', 'x', '\x0', 'm', '\x0', 'l', '\x0', 'n', '\x0',
|
'\x95', '\x0', '\x0', '\x0', '\x1', 'k', 'e', 'y', 'i',
|
||||||
's', '\x0', '=', '\x0', '"', '\x0', 'h', '\x0', 't', '\x0',
|
'd', '1', '~', '~', '~', '~', '~', '~', '~',
|
||||||
't', '\x0', 'p', '\x0', ':', '\x0', '/', '\x0', '/', '\x0',
|
'~', '~', '~', '\x0', '\x0', '\x2', '\x6', '\x6', '\x2',
|
||||||
's', '\x0', 'c', '\x0', 'h', '\x0', 'e', '\x0', 'm', '\x0',
|
'\x0', '\x0', '\x1', '\x0', '\x1', '\x0', '\xfc', '\x1', '<',
|
||||||
'a', '\x0', 's', '\x0', '.', '\x0', 'm', '\x0', 'i', '\x0',
|
'\x0', 'W', '\x0', 'R', '\x0', 'M', '\x0', 'H', '\x0',
|
||||||
'c', '\x0', 'r', '\x0', 'o', '\x0', 's', '\x0', 'o', '\x0',
|
'E', '\x0', 'A', '\x0', 'D', '\x0', 'E', '\x0', 'R',
|
||||||
'f', '\x0', 't', '\x0', '.', '\x0', 'c', '\x0', 'o', '\x0',
|
'\x0', ' ', '\x0', 'x', '\x0', 'm', '\x0', 'l', '\x0',
|
||||||
'm', '\x0', '/', '\x0', 'D', '\x0', 'R', '\x0', 'M', '\x0',
|
'n', '\x0', 's', '\x0', '=', '\x0', '"', '\x0', 'h',
|
||||||
'/', '\x0', '2', '\x0', '0', '\x0', '0', '\x0', '7', '\x0',
|
'\x0', 't', '\x0', 't', '\x0', 'p', '\x0', ':', '\x0',
|
||||||
'/', '\x0', '0', '\x0', '3', '\x0', '/', '\x0', 'P', '\x0',
|
'/', '\x0', '/', '\x0', 's', '\x0', 'c', '\x0', 'h',
|
||||||
'l', '\x0', 'a', '\x0', 'y', '\x0', 'R', '\x0', 'e', '\x0',
|
'\x0', 'e', '\x0', 'm', '\x0', 'a', '\x0', 's', '\x0',
|
||||||
'a', '\x0', 'd', '\x0', 'y', '\x0', 'H', '\x0', 'e', '\x0',
|
'.', '\x0', 'm', '\x0', 'i', '\x0', 'c', '\x0', 'r',
|
||||||
'a', '\x0', 'd', '\x0', 'e', '\x0', 'r', '\x0', '"', '\x0',
|
'\x0', 'o', '\x0', 's', '\x0', 'o', '\x0', 'f', '\x0',
|
||||||
' ', '\x0', 'v', '\x0', 'e', '\x0', 'r', '\x0', 's', '\x0',
|
't', '\x0', '.', '\x0', 'c', '\x0', 'o', '\x0', 'm',
|
||||||
'i', '\x0', 'o', '\x0', 'n', '\x0', '=', '\x0', '"', '\x0',
|
'\x0', '/', '\x0', 'D', '\x0', 'R', '\x0', 'M', '\x0',
|
||||||
'4', '\x0', '.', '\x0', '0', '\x0', '.', '\x0', '0', '\x0',
|
'/', '\x0', '2', '\x0', '0', '\x0', '0', '\x0', '7',
|
||||||
'.', '\x0', '0', '\x0', '"', '\x0', '>', '\x0', '<', '\x0',
|
'\x0', '/', '\x0', '0', '\x0', '3', '\x0', '/', '\x0',
|
||||||
'D', '\x0', 'A', '\x0', 'T', '\x0', 'A', '\x0', '>', '\x0',
|
'P', '\x0', 'l', '\x0', 'a', '\x0', 'y', '\x0', 'R',
|
||||||
'<', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0', 'T', '\x0',
|
'\x0', 'e', '\x0', 'a', '\x0', 'd', '\x0', 'y', '\x0',
|
||||||
'E', '\x0', 'C', '\x0', 'T', '\x0', 'I', '\x0', 'N', '\x0',
|
'H', '\x0', 'e', '\x0', 'a', '\x0', 'd', '\x0', 'e',
|
||||||
'F', '\x0', 'O', '\x0', '>', '\x0', '<', '\x0', 'K', '\x0',
|
'\x0', 'r', '\x0', '"', '\x0', ' ', '\x0', 'v', '\x0',
|
||||||
'E', '\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0', 'N', '\x0',
|
'e', '\x0', 'r', '\x0', 's', '\x0', 'i', '\x0', 'o',
|
||||||
'>', '\x0', '1', '\x0', '6', '\x0', '<', '\x0', '/', '\x0',
|
'\x0', 'n', '\x0', '=', '\x0', '"', '\x0', '4', '\x0',
|
||||||
'K', '\x0', 'E', '\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0',
|
'.', '\x0', '0', '\x0', '.', '\x0', '0', '\x0', '.',
|
||||||
'N', '\x0', '>', '\x0', '<', '\x0', 'A', '\x0', 'L', '\x0',
|
'\x0', '0', '\x0', '"', '\x0', '>', '\x0', '<', '\x0',
|
||||||
'G', '\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', 'A', '\x0',
|
'D', '\x0', 'A', '\x0', 'T', '\x0', 'A', '\x0', '>',
|
||||||
'E', '\x0', 'S', '\x0', 'C', '\x0', 'T', '\x0', 'R', '\x0',
|
'\x0', '<', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0',
|
||||||
'<', '\x0', '/', '\x0', 'A', '\x0', 'L', '\x0', 'G', '\x0',
|
'T', '\x0', 'E', '\x0', 'C', '\x0', 'T', '\x0', 'I',
|
||||||
'I', '\x0', 'D', '\x0', '>', '\x0', '<', '\x0', '/', '\x0',
|
'\x0', 'N', '\x0', 'F', '\x0', 'O', '\x0', '>', '\x0',
|
||||||
'P', '\x0', 'R', '\x0', 'O', '\x0', 'T', '\x0', 'E', '\x0',
|
'<', '\x0', 'K', '\x0', 'E', '\x0', 'Y', '\x0', 'L',
|
||||||
'C', '\x0', 'T', '\x0', 'I', '\x0', 'N', '\x0', 'F', '\x0',
|
'\x0', 'E', '\x0', 'N', '\x0', '>', '\x0', '1', '\x0',
|
||||||
'O', '\x0', '>', '\x0', '<', '\x0', 'K', '\x0', 'I', '\x0',
|
'6', '\x0', '<', '\x0', '/', '\x0', 'K', '\x0', 'E',
|
||||||
'D', '\x0', '>', '\x0', 'a', '\x0', 'X', '\x0', 'l', '\x0',
|
'\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0', 'N', '\x0',
|
||||||
'l', '\x0', 'a', '\x0', 'z', '\x0', 'F', '\x0', 'k', '\x0',
|
'>', '\x0', '<', '\x0', 'A', '\x0', 'L', '\x0', 'G',
|
||||||
'f', '\x0', 'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0',
|
'\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', 'A', '\x0',
|
||||||
'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'n', '\x0',
|
'E', '\x0', 'S', '\x0', 'C', '\x0', 'T', '\x0', 'R',
|
||||||
'5', '\x0', '+', '\x0', 'f', '\x0', 'g', '\x0', '=', '\x0',
|
'\x0', '<', '\x0', '/', '\x0', 'A', '\x0', 'L', '\x0',
|
||||||
'=', '\x0', '<', '\x0', '/', '\x0', 'K', '\x0', 'I', '\x0',
|
'G', '\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', '<',
|
||||||
'D', '\x0', '>', '\x0', '<', '\x0', 'C', '\x0', 'H', '\x0',
|
'\x0', '/', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0',
|
||||||
'E', '\x0', 'C', '\x0', 'K', '\x0', 'S', '\x0', 'U', '\x0',
|
'T', '\x0', 'E', '\x0', 'C', '\x0', 'T', '\x0', 'I',
|
||||||
'M', '\x0', '>', '\x0', 'u', '\x0', 'F', '\x0', 'Y', '\x0',
|
'\x0', 'N', '\x0', 'F', '\x0', 'O', '\x0', '>', '\x0',
|
||||||
'/', '\x0', 'O', '\x0', 'i', '\x0', 'r', '\x0', 'Q', '\x0',
|
'<', '\x0', 'K', '\x0', 'I', '\x0', 'D', '\x0', '>',
|
||||||
'j', '\x0', '/', '\x0', 'U', '\x0', '=', '\x0', '<', '\x0',
|
'\x0', 'a', '\x0', 'X', '\x0', 'l', '\x0', 'l', '\x0',
|
||||||
'/', '\x0', 'C', '\x0', 'H', '\x0', 'E', '\x0', 'C', '\x0',
|
'a', '\x0', 'z', '\x0', 'F', '\x0', 'k', '\x0', 'f',
|
||||||
'K', '\x0', 'S', '\x0', 'U', '\x0', 'M', '\x0', '>', '\x0',
|
'\x0', 'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0',
|
||||||
'<', '\x0', '/', '\x0', 'D', '\x0', 'A', '\x0', 'T', '\x0',
|
'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'n',
|
||||||
'A', '\x0', '>', '\x0', '<', '\x0', '/', '\x0', 'W', '\x0',
|
'\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'g', '\x0',
|
||||||
'R', '\x0', 'M', '\x0', 'H', '\x0', 'E', '\x0', 'A', '\x0',
|
'=', '\x0', '=', '\x0', '<', '\x0', '/', '\x0', 'K',
|
||||||
'D', '\x0', 'E', '\x0', 'R', '\x0', '>', '\x0',
|
'\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', '<', '\x0',
|
||||||
|
'C', '\x0', 'H', '\x0', 'E', '\x0', 'C', '\x0', 'K',
|
||||||
|
'\x0', 'S', '\x0', 'U', '\x0', 'M', '\x0', '>', '\x0',
|
||||||
|
'u', '\x0', 'F', '\x0', 'Y', '\x0', '/', '\x0', 'O',
|
||||||
|
'\x0', 'i', '\x0', 'r', '\x0', 'Q', '\x0', 'j', '\x0',
|
||||||
|
'/', '\x0', 'U', '\x0', '=', '\x0', '<', '\x0', '/',
|
||||||
|
'\x0', 'C', '\x0', 'H', '\x0', 'E', '\x0', 'C', '\x0',
|
||||||
|
'K', '\x0', 'S', '\x0', 'U', '\x0', 'M', '\x0', '>',
|
||||||
|
'\x0', '<', '\x0', '/', '\x0', 'D', '\x0', 'A', '\x0',
|
||||||
|
'T', '\x0', 'A', '\x0', '>', '\x0', '<', '\x0', '/',
|
||||||
|
'\x0', 'W', '\x0', 'R', '\x0', 'M', '\x0', 'H', '\x0',
|
||||||
|
'E', '\x0', 'A', '\x0', 'D', '\x0', 'E', '\x0', 'R',
|
||||||
|
'\x0', '>', '\x0',
|
||||||
};
|
};
|
||||||
|
|
||||||
const char kExpectedWidevinePsshData[] = {
|
const char kExpectedCommonPssh[] = {
|
||||||
'\x12', '\x10', 'k', 'e', 'y', 'i', 'd', '1', '~', '~', '~', '~',
|
'\x0', '\x0', '\x0', '\x44', 'p', 's', 's', 'h', '\x1',
|
||||||
'~', '~', '~', '~', '~', '~', '\x12', '\x10', 'k', 'e', 'y', 'i',
|
'\x0', '\x0', '\x0', '\x10', '\x77', '\xEF', '\xEC', '\xC0', '\xB2',
|
||||||
'd', '2', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
|
'\x4D', '\x02', '\xAC', '\xE3', '\x3C', '\x1E', '\x52', '\xE2', '\xFB',
|
||||||
|
'\x4B', '\x0', '\x0', '\x0', '\x2', 'k', 'e', 'y', 'i',
|
||||||
|
'd', '1', '~', '~', '~', '~', '~', '~', '~',
|
||||||
|
'~', '~', '~', 'k', 'e', 'y', 'i', 'd', '2',
|
||||||
|
'~', '~', '~', '~', '~', '~', '~', '~', '~',
|
||||||
|
'~', '\x0', '\x0', '\x0', '\x0',
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const char kExpectedWidevinePssh[] = {
|
||||||
|
'\x0', '\x0', '\x0', '\x44', 'p', 's', 's', 'h', '\x0',
|
||||||
|
'\x0', '\x0', '\x0', '\xED', '\xEF', '\x8B', '\xA9', '\x79', '\xD6',
|
||||||
|
'\x4A', '\xCE', '\xA3', '\xC8', '\x27', '\xDC', '\xD5', '\x1D', '\x21',
|
||||||
|
'\xED', '\x0', '\x0', '\x0', '\x24', '\x12', '\x10', 'k', 'e',
|
||||||
|
'y', 'i', 'd', '1', '~', '~', '~', '~', '~',
|
||||||
|
'~', '~', '~', '~', '~', '\x12', '\x10', 'k', 'e',
|
||||||
|
'y', 'i', 'd', '2', '~', '~', '~', '~', '~',
|
||||||
|
'~', '~', '~', '~', '~',
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<uint8_t> GetTestKeyId1() {
|
std::vector<uint8_t> GetTestKeyId1() {
|
||||||
|
@ -99,12 +128,6 @@ std::vector<uint8_t> GetTestKeyId2() {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Folowing tests test PlayReady, RawKey and Widevine PSSH generators. Note
|
|
||||||
// that for each generator, it can generate PSSH from a pair of key id and key
|
|
||||||
// or multiple key ids. Since some of generating methods are not implemented yet
|
|
||||||
// (or not needed), tests make sure those methods return failure.
|
|
||||||
class PsshGeneratorTest : public ::testing::Test {};
|
|
||||||
|
|
||||||
// TODO(hmchen): move each PsshGenerateTest for each specific key system
|
// TODO(hmchen): move each PsshGenerateTest for each specific key system
|
||||||
// to each individual files (e.g., playready_pssh_generate_unittest.cc).
|
// to each individual files (e.g., playready_pssh_generate_unittest.cc).
|
||||||
TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIds) {
|
TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIds) {
|
||||||
|
@ -117,10 +140,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIds) {
|
||||||
playready_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
playready_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(hmchen): change the testing interface from
|
TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKey) {
|
||||||
// GeneratePsshDataFromKeyIdAndKey to GeneratePsshFromKeyIdAndKey, after the
|
|
||||||
// later one is not used as a static function.
|
|
||||||
TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIdAndKey) {
|
|
||||||
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(
|
||||||
|
@ -129,23 +149,22 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIdAndKey) {
|
||||||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
|
|
||||||
EXPECT_THAT(info.pssh_data(),
|
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedPlayReadyPssh),
|
||||||
ElementsAreArray(std::begin(kExpectedPlayReadyPsshData),
|
std::end(kExpectedPlayReadyPssh)));
|
||||||
std::end(kExpectedPlayReadyPsshData)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIds) {
|
TEST(PsshGeneratorTest, GenerateRawKeyPsshFromKeyIds) {
|
||||||
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
||||||
GetTestKeyId2()};
|
GetTestKeyId2()};
|
||||||
std::unique_ptr<RawKeyPsshGenerator> raw_key_pssh_generator(
|
std::unique_ptr<RawKeyPsshGenerator> raw_key_pssh_generator(
|
||||||
new RawKeyPsshGenerator());
|
new RawKeyPsshGenerator());
|
||||||
ProtectionSystemSpecificInfo info;
|
ProtectionSystemSpecificInfo info;
|
||||||
EXPECT_OK(raw_key_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
EXPECT_OK(raw_key_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||||
// Intentionally empty pssh data for raw key.
|
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedCommonPssh),
|
||||||
EXPECT_TRUE(info.pssh_data().empty());
|
std::end(kExpectedCommonPssh)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIdAndKey) {
|
TEST(PsshGeneratorTest, GenerateRawKeyPsshFromKeyIdAndKey) {
|
||||||
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<RawKeyPsshGenerator> raw_key_pssh_generator(
|
std::unique_ptr<RawKeyPsshGenerator> raw_key_pssh_generator(
|
||||||
|
@ -155,7 +174,7 @@ TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIdAndKey) {
|
||||||
kTestKeyId, kTestKey, &info));
|
kTestKeyId, kTestKey, &info));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PsshGeneratorTest, GenerateWidevinePsshDataFromKeyIds) {
|
TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIds) {
|
||||||
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
||||||
GetTestKeyId2()};
|
GetTestKeyId2()};
|
||||||
std::unique_ptr<WidevinePsshGenerator> widevine_pssh_generator(
|
std::unique_ptr<WidevinePsshGenerator> widevine_pssh_generator(
|
||||||
|
@ -164,12 +183,11 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshDataFromKeyIds) {
|
||||||
ASSERT_OK(
|
ASSERT_OK(
|
||||||
widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||||
|
|
||||||
EXPECT_THAT(info.pssh_data(),
|
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedWidevinePssh),
|
||||||
ElementsAreArray(std::begin(kExpectedWidevinePsshData),
|
std::end(kExpectedWidevinePssh)));
|
||||||
std::end(kExpectedWidevinePsshData)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PsshGeneratorTest, GenerateWidevinyPsshDataFromKeyIdAndKey) {
|
TEST(PsshGeneratorTest, GenerateWidevinyPsshFromKeyIdAndKey) {
|
||||||
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<WidevinePsshGenerator> widevine_pssh_generator(
|
std::unique_ptr<WidevinePsshGenerator> widevine_pssh_generator(
|
||||||
|
|
|
@ -80,10 +80,8 @@ TEST(RawKeySourceTest, Success) {
|
||||||
EXPECT_HEX_EQ(kKeyHex, key_from_drm_label.key);
|
EXPECT_HEX_EQ(kKeyHex, key_from_drm_label.key);
|
||||||
EXPECT_HEX_EQ(kIvHex, key_from_drm_label.iv);
|
EXPECT_HEX_EQ(kIvHex, key_from_drm_label.iv);
|
||||||
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
||||||
EXPECT_HEX_EQ(kPsshBox1Hex,
|
EXPECT_HEX_EQ(kPsshBox1Hex, key_from_drm_label.key_system_info[0].psshs);
|
||||||
key_from_drm_label.key_system_info[0].CreateBox());
|
EXPECT_HEX_EQ(kPsshBox2Hex, key_from_drm_label.key_system_info[1].psshs);
|
||||||
EXPECT_HEX_EQ(kPsshBox2Hex,
|
|
||||||
key_from_drm_label.key_system_info[1].CreateBox());
|
|
||||||
|
|
||||||
// Using Key ID.
|
// Using Key ID.
|
||||||
EncryptionKey key_from_key_id;
|
EncryptionKey key_from_key_id;
|
||||||
|
@ -98,10 +96,8 @@ TEST(RawKeySourceTest, Success) {
|
||||||
EXPECT_HEX_EQ(kKey2Hex, key_from_drm_label.key);
|
EXPECT_HEX_EQ(kKey2Hex, key_from_drm_label.key);
|
||||||
EXPECT_HEX_EQ(kIvHex, key_from_drm_label.iv);
|
EXPECT_HEX_EQ(kIvHex, key_from_drm_label.iv);
|
||||||
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
||||||
EXPECT_HEX_EQ(kPsshBox1Hex,
|
EXPECT_HEX_EQ(kPsshBox1Hex, key_from_drm_label.key_system_info[0].psshs);
|
||||||
key_from_drm_label.key_system_info[0].CreateBox());
|
EXPECT_HEX_EQ(kPsshBox2Hex, key_from_drm_label.key_system_info[1].psshs);
|
||||||
EXPECT_HEX_EQ(kPsshBox2Hex,
|
|
||||||
key_from_drm_label.key_system_info[1].CreateBox());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RawKeySourceTest, EmptyPssh) {
|
TEST(RawKeySourceTest, EmptyPssh) {
|
||||||
|
@ -122,7 +118,7 @@ TEST(RawKeySourceTest, EmptyPssh) {
|
||||||
EXPECT_HEX_EQ(kKeyHex, key.key);
|
EXPECT_HEX_EQ(kKeyHex, key.key);
|
||||||
EXPECT_HEX_EQ(kIvHex, key.iv);
|
EXPECT_HEX_EQ(kIvHex, key.iv);
|
||||||
ASSERT_EQ(1u, key.key_system_info.size());
|
ASSERT_EQ(1u, key.key_system_info.size());
|
||||||
EXPECT_HEX_EQ(kDefaultPsshBoxHex, key.key_system_info[0].CreateBox());
|
EXPECT_HEX_EQ(kDefaultPsshBoxHex, key.key_system_info[0].psshs);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(RawKeySourceTest, Failure) {
|
TEST(RawKeySourceTest, Failure) {
|
||||||
|
|
|
@ -179,13 +179,18 @@ Status WidevineKeySource::FetchKeys(EmeInitDataType init_data_type,
|
||||||
return Status(error::PARSER_FAILURE, "Error parsing the PSSH boxes.");
|
return Status(error::PARSER_FAILURE, "Error parsing the PSSH boxes.");
|
||||||
}
|
}
|
||||||
for (const auto& info : protection_systems_info) {
|
for (const auto& info : protection_systems_info) {
|
||||||
|
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||||
|
PsshBoxBuilder::ParseFromBox(info.psshs.data(), info.psshs.size());
|
||||||
|
if (!pssh_builder)
|
||||||
|
return Status(error::PARSER_FAILURE, "Error parsing the PSSH box.");
|
||||||
// Use Widevine PSSH if available otherwise construct a Widevine PSSH
|
// Use Widevine PSSH if available otherwise construct a Widevine PSSH
|
||||||
// from the first available key ids.
|
// from the first available key ids.
|
||||||
if (info.system_id() == widevine_system_id) {
|
if (info.system_id == widevine_system_id) {
|
||||||
pssh_data = info.pssh_data();
|
pssh_data = pssh_builder->pssh_data();
|
||||||
break;
|
break;
|
||||||
} else if (pssh_data.empty() && !info.key_ids().empty()) {
|
} else if (pssh_data.empty() && !pssh_builder->key_ids().empty()) {
|
||||||
pssh_data = GenerateWidevinePsshDataFromKeyIds(info.key_ids());
|
pssh_data =
|
||||||
|
GenerateWidevinePsshDataFromKeyIds(pssh_builder->key_ids());
|
||||||
// Continue to see if there is any Widevine PSSH. The KeyId generated
|
// Continue to see if there is any Widevine PSSH. The KeyId generated
|
||||||
// PSSH is only used if a Widevine PSSH could not be found.
|
// PSSH is only used if a Widevine PSSH could not be found.
|
||||||
continue;
|
continue;
|
||||||
|
@ -558,17 +563,19 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
||||||
if (!GetKeyIdFromTrack(*track_dict, &encryption_key->key_id))
|
if (!GetKeyIdFromTrack(*track_dict, &encryption_key->key_id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
info.add_key_id(encryption_key->key_id);
|
|
||||||
info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
|
|
||||||
info.set_pssh_box_version(0);
|
|
||||||
|
|
||||||
std::vector<uint8_t> pssh_data;
|
std::vector<uint8_t> pssh_data;
|
||||||
if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
|
if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
|
||||||
return false;
|
return false;
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
encryption_key->key_system_info.push_back(info);
|
PsshBoxBuilder pssh_builder;
|
||||||
|
pssh_builder.add_key_id(encryption_key->key_id);
|
||||||
|
pssh_builder.set_system_id(kWidevineSystemId,
|
||||||
|
arraysize(kWidevineSystemId));
|
||||||
|
pssh_builder.set_pssh_box_version(0);
|
||||||
|
pssh_builder.set_pssh_data(pssh_data);
|
||||||
|
|
||||||
|
encryption_key->key_system_info.push_back(
|
||||||
|
{pssh_builder.system_id(), pssh_builder.CreateBox()});
|
||||||
}
|
}
|
||||||
encryption_key_map[stream_label] = std::move(encryption_key);
|
encryption_key_map[stream_label] = std::move(encryption_key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,44 +217,29 @@ class WidevineKeySourceTest : public Test {
|
||||||
1 + (add_common_pssh_ ? 1 : 0) + (add_playready_pssh_ ? 1 : 0);
|
1 + (add_common_pssh_ ? 1 : 0) + (add_playready_pssh_ ? 1 : 0);
|
||||||
ASSERT_EQ(num_key_system_info, encryption_key.key_system_info.size());
|
ASSERT_EQ(num_key_system_info, encryption_key.key_system_info.size());
|
||||||
EXPECT_EQ(GetMockKeyId(stream_label), ToString(encryption_key.key_id));
|
EXPECT_EQ(GetMockKeyId(stream_label), ToString(encryption_key.key_id));
|
||||||
EXPECT_EQ(GetMockPsshData(),
|
|
||||||
ToString(encryption_key.key_system_info[0].pssh_data()));
|
const std::vector<uint8_t>& pssh =
|
||||||
|
encryption_key.key_system_info[0].psshs;
|
||||||
|
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||||
|
PsshBoxBuilder::ParseFromBox(pssh.data(), pssh.size());
|
||||||
|
ASSERT_TRUE(pssh_builder);
|
||||||
|
EXPECT_EQ(GetMockPsshData(), ToString(pssh_builder->pssh_data()));
|
||||||
|
|
||||||
if (add_common_pssh_) {
|
if (add_common_pssh_) {
|
||||||
// Each of the keys contains all the key IDs.
|
|
||||||
const std::vector<uint8_t> common_system_id(
|
const std::vector<uint8_t> common_system_id(
|
||||||
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
||||||
ASSERT_EQ(common_system_id,
|
ASSERT_EQ(common_system_id,
|
||||||
encryption_key.key_system_info[1].system_id());
|
encryption_key.key_system_info[1].system_id);
|
||||||
|
|
||||||
const std::vector<std::vector<uint8_t>>& key_ids =
|
|
||||||
encryption_key.key_system_info[1].key_ids();
|
|
||||||
ASSERT_EQ(arraysize(kStreamLabels), key_ids.size());
|
|
||||||
for (const std::string& stream_label : kStreamLabels) {
|
|
||||||
// Because they are stored in a std::set, the order may change.
|
|
||||||
const std::string key_id_str = GetMockKeyId(stream_label);
|
|
||||||
const std::vector<uint8_t> key_id(key_id_str.begin(),
|
|
||||||
key_id_str.end());
|
|
||||||
EXPECT_THAT(key_ids, testing::Contains(key_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_playready_pssh_) {
|
if (add_playready_pssh_) {
|
||||||
const std::vector<uint8_t> playready_system_id(
|
const std::vector<uint8_t> playready_system_id(
|
||||||
kPlayReadySystemId,
|
kPlayReadySystemId,
|
||||||
kPlayReadySystemId + arraysize(kPlayReadySystemId));
|
kPlayReadySystemId + arraysize(kPlayReadySystemId));
|
||||||
|
|
||||||
// PlayReady pssh index depends on if there has common pssh box.
|
// PlayReady pssh index depends on if there has common pssh box.
|
||||||
const uint8_t playready_index = 1 + (add_common_pssh_ ? 1 : 0);
|
const uint8_t playready_index = 1 + (add_common_pssh_ ? 1 : 0);
|
||||||
ASSERT_EQ(
|
ASSERT_EQ(playready_system_id,
|
||||||
playready_system_id,
|
encryption_key.key_system_info[playready_index].system_id);
|
||||||
encryption_key.key_system_info[playready_index].system_id());
|
|
||||||
const std::vector<std::vector<uint8_t>>& key_ids =
|
|
||||||
encryption_key.key_system_info[playready_index].key_ids();
|
|
||||||
|
|
||||||
// Each of the keys contains its corresponding key ID.
|
|
||||||
ASSERT_EQ(1u, key_ids.size());
|
|
||||||
EXPECT_EQ(ToString(key_ids[0]), GetMockKeyId(stream_label));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ void HlsNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
}
|
}
|
||||||
for (const ProtectionSystemSpecificInfo& info : key_system_infos) {
|
for (const ProtectionSystemSpecificInfo& info : key_system_infos) {
|
||||||
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
||||||
stream_id_, key_id, info.system_id(), iv, info.CreateBox());
|
stream_id_, key_id, info.system_id, iv, info.psshs);
|
||||||
LOG_IF(WARNING, !result) << "Failed to add encryption info.";
|
LOG_IF(WARNING, !result) << "Failed to add encryption info.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,7 @@ void HlsNotifyMuxerListener::OnEncryptionStart() {
|
||||||
|
|
||||||
for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) {
|
for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) {
|
||||||
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
||||||
stream_id_, next_key_id_, info.system_id(), next_iv_,
|
stream_id_, next_key_id_, info.system_id, next_iv_, info.psshs);
|
||||||
info.CreateBox());
|
|
||||||
LOG_IF(WARNING, !result) << "Failed to add encryption info";
|
LOG_IF(WARNING, !result) << "Failed to add encryption info";
|
||||||
}
|
}
|
||||||
next_key_id_.clear();
|
next_key_id_.clear();
|
||||||
|
|
|
@ -121,22 +121,12 @@ class HlsNotifyMuxerListenerTest : public ::testing::Test {
|
||||||
// Verify that NotifyEncryptionUpdate() is not called before OnMediaStart() is
|
// Verify that NotifyEncryptionUpdate() is not called before OnMediaStart() is
|
||||||
// called.
|
// called.
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyBeforeMediaStart) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyBeforeMediaStart) {
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
iv, key_system_infos);
|
iv, GetDefaultKeySystemInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
||||||
|
@ -158,22 +148,15 @@ TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
||||||
// OnEncryptionStart() should call MuxerListener::NotifyEncryptionUpdate() after
|
// OnEncryptionStart() should call MuxerListener::NotifyEncryptionUpdate() after
|
||||||
// OnEncryptionInfoReady() and OnMediaStart().
|
// OnEncryptionInfoReady() and OnMediaStart().
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
std::vector<uint8_t> system_id(kAnySystemId,
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
kAnySystemId + arraysize(kAnySystemId));
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
std::vector<uint8_t> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
iv, key_system_infos);
|
iv, {{system_id, pssh}});
|
||||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
@ -189,8 +172,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
||||||
MuxerListener::kContainerMpeg2ts);
|
MuxerListener::kContainerMpeg2ts);
|
||||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
EXPECT_CALL(mock_notifier_,
|
||||||
info.CreateBox()))
|
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
listener_.OnEncryptionStart();
|
listener_.OnEncryptionStart();
|
||||||
}
|
}
|
||||||
|
@ -199,22 +182,15 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
||||||
// HlsNotiifer::NotifyEncryptionUpdate() should be called by the end of
|
// HlsNotiifer::NotifyEncryptionUpdate() should be called by the end of
|
||||||
// OnMediaStart().
|
// OnMediaStart().
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
std::vector<uint8_t> system_id(kAnySystemId,
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
kAnySystemId + arraysize(kAnySystemId));
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
std::vector<uint8_t> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
iv, key_system_infos);
|
iv, {{system_id, pssh}});
|
||||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
@ -228,8 +204,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
|
||||||
// It doesn't really matter when this is called, could be called right away in
|
// It doesn't really matter when this is called, could be called right away in
|
||||||
// OnEncryptionStart() if that is possible. Just matters that it is called by
|
// OnEncryptionStart() if that is possible. Just matters that it is called by
|
||||||
// the time OnMediaStart() returns.
|
// the time OnMediaStart() returns.
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
EXPECT_CALL(mock_notifier_,
|
||||||
info.CreateBox()))
|
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
listener_.OnEncryptionStart();
|
listener_.OnEncryptionStart();
|
||||||
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
|
@ -239,22 +215,12 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
|
||||||
// NotifyEncryptionUpdate() should not be called if NotifyNewStream() fails in
|
// NotifyEncryptionUpdate() should not be called if NotifyNewStream() fails in
|
||||||
// OnMediaStart().
|
// OnMediaStart().
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, NoEncryptionUpdateIfNotifyNewStreamFails) {
|
TEST_F(HlsNotifyMuxerListenerTest, NoEncryptionUpdateIfNotifyNewStreamFails) {
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
iv, key_system_infos);
|
iv, GetDefaultKeySystemInfo());
|
||||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
EXPECT_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||||
|
@ -283,44 +249,27 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
|
||||||
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||||
MuxerListener::kContainerMpeg2ts);
|
MuxerListener::kContainerMpeg2ts);
|
||||||
|
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
std::vector<uint8_t> system_id(kAnySystemId,
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
kAnySystemId + arraysize(kAnySystemId));
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
std::vector<uint8_t> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
EXPECT_CALL(mock_notifier_,
|
||||||
info.CreateBox()))
|
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||||
.WillOnce(Return(true));
|
.WillOnce(Return(true));
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||||
iv, key_system_infos);
|
iv, {{system_id, pssh}});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that if protection scheme is specified in OnEncryptionInfoReady(),
|
// Verify that if protection scheme is specified in OnEncryptionInfoReady(),
|
||||||
// the information is copied to MediaInfo in OnMediaStart().
|
// the information is copied to MediaInfo in OnMediaStart().
|
||||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyWithProtectionScheme) {
|
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReadyWithProtectionScheme) {
|
||||||
ProtectionSystemSpecificInfo info;
|
|
||||||
std::vector<uint8_t> system_id(kAnySystemId,
|
|
||||||
kAnySystemId + arraysize(kAnySystemId));
|
|
||||||
info.set_system_id(system_id.data(), system_id.size());
|
|
||||||
std::vector<uint8_t> pssh_data(kAnyData, kAnyData + arraysize(kAnyData));
|
|
||||||
info.set_pssh_data(pssh_data);
|
|
||||||
|
|
||||||
std::vector<uint8_t> key_id(16, 0x05);
|
std::vector<uint8_t> key_id(16, 0x05);
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_infos;
|
|
||||||
key_system_infos.push_back(info);
|
|
||||||
|
|
||||||
std::vector<uint8_t> iv(16, 0x54);
|
std::vector<uint8_t> iv(16, 0x54);
|
||||||
|
|
||||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, key_id,
|
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, key_id,
|
||||||
iv, key_system_infos);
|
iv, GetDefaultKeySystemInfo());
|
||||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||||
|
|
||||||
ON_CALL(mock_notifier_,
|
ON_CALL(mock_notifier_,
|
||||||
|
|
|
@ -46,10 +46,9 @@ void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
DCHECK_EQ(protection_scheme, protection_scheme_);
|
DCHECK_EQ(protection_scheme, protection_scheme_);
|
||||||
|
|
||||||
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
||||||
std::string drm_uuid = internal::CreateUUIDString(info.system_id());
|
std::string drm_uuid = internal::CreateUUIDString(info.system_id);
|
||||||
std::vector<uint8_t> new_pssh = info.CreateBox();
|
|
||||||
bool updated = mpd_notifier_->NotifyEncryptionUpdate(
|
bool updated = mpd_notifier_->NotifyEncryptionUpdate(
|
||||||
notification_id_, drm_uuid, key_id, new_pssh);
|
notification_id_, drm_uuid, key_id, info.psshs);
|
||||||
LOG_IF(WARNING, !updated) << "Failed to update encryption info.";
|
LOG_IF(WARNING, !updated) << "Failed to update encryption info.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
struct MuxerOptions;
|
struct MuxerOptions;
|
||||||
class ProtectionSystemSpecificInfo;
|
struct ProtectionSystemSpecificInfo;
|
||||||
class StreamInfo;
|
class StreamInfo;
|
||||||
|
|
||||||
/// MuxerListener is an event handler that can be registered to a muxer.
|
/// MuxerListener is an event handler that can be registered to a muxer.
|
||||||
|
|
|
@ -217,10 +217,9 @@ void SetContentProtectionFields(
|
||||||
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
||||||
MediaInfo::ProtectedContent::ContentProtectionEntry* entry =
|
MediaInfo::ProtectedContent::ContentProtectionEntry* entry =
|
||||||
protected_content->add_content_protection_entry();
|
protected_content->add_content_protection_entry();
|
||||||
if (!info.system_id().empty())
|
entry->set_uuid(CreateUUIDString(info.system_id));
|
||||||
entry->set_uuid(CreateUUIDString(info.system_id()));
|
|
||||||
|
|
||||||
const std::vector<uint8_t> pssh = info.CreateBox();
|
const std::vector<uint8_t>& pssh = info.psshs;
|
||||||
entry->set_pssh(pssh.data(), pssh.size());
|
entry->set_pssh(pssh.data(), pssh.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,20 +94,13 @@ void SetDefaultMuxerOptions(MuxerOptions* muxer_options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProtectionSystemSpecificInfo> GetDefaultKeySystemInfo() {
|
std::vector<ProtectionSystemSpecificInfo> GetDefaultKeySystemInfo() {
|
||||||
const uint8_t kPsshData[] = {'p', 's', 's', 'h'};
|
|
||||||
const uint8_t kTestSystemId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
const uint8_t kTestSystemId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||||
0x0c, 0x0d, 0x0e, 0x0f};
|
0x0c, 0x0d, 0x0e, 0x0f};
|
||||||
|
return {{{std::begin(kTestSystemId), std::end(kTestSystemId)},
|
||||||
ProtectionSystemSpecificInfo info;
|
{std::begin(kExpectedDefaultPsshBox),
|
||||||
info.set_system_id(kTestSystemId, arraysize(kTestSystemId));
|
// -1 to remove the null terminator.
|
||||||
info.set_pssh_data(
|
std::end(kExpectedDefaultPsshBox) - 1}}};
|
||||||
std::vector<uint8_t>(kPsshData, kPsshData + arraysize(kPsshData)));
|
|
||||||
info.set_pssh_box_version(0);
|
|
||||||
|
|
||||||
std::vector<ProtectionSystemSpecificInfo> key_system_info;
|
|
||||||
key_system_info.push_back(info);
|
|
||||||
return key_system_info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
|
|
|
@ -21,12 +21,7 @@ namespace shaka {
|
||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
// A string containing the escaped PSSH box (for use with a MediaInfo proto).
|
const char kExpectedDefaultPsshBox[] = "expected_pssh_box";
|
||||||
// This is a full v0 PSSH box with the Widevine system ID and the PSSH data
|
|
||||||
// 'pssh'
|
|
||||||
const char kExpectedDefaultPsshBox[] =
|
|
||||||
"\\000\\000\\000$pssh\\000\\000\\000\\000\\000\\001\\002\\003\\004\\005"
|
|
||||||
"\\006\\007\\010\\t\\n\\013\\014\\r\\016\\017\\000\\000\\000\\004pssh";
|
|
||||||
const char kExpectedDefaultMediaInfo[] =
|
const char kExpectedDefaultMediaInfo[] =
|
||||||
"video_info {\n"
|
"video_info {\n"
|
||||||
" codec: 'avc1.010101'\n"
|
" codec: 'avc1.010101'\n"
|
||||||
|
|
|
@ -212,7 +212,7 @@ Status MP4Muxer::InitializeMuxer() {
|
||||||
streams()[i]->encryption_config().key_system_info;
|
streams()[i]->encryption_config().key_system_info;
|
||||||
moov->pssh.resize(key_system_info.size());
|
moov->pssh.resize(key_system_info.size());
|
||||||
for (size_t j = 0; j < key_system_info.size(); j++)
|
for (size_t j = 0; j < key_system_info.size(); j++)
|
||||||
moov->pssh[j].raw_box = key_system_info[j].CreateBox();
|
moov->pssh[j].raw_box = key_system_info[j].psshs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -275,7 +275,7 @@ void Segmenter::FinalizeFragmentForKeyRotation(
|
||||||
encryption_config.key_system_info;
|
encryption_config.key_system_info;
|
||||||
moof_->pssh.resize(system_info.size());
|
moof_->pssh.resize(system_info.size());
|
||||||
for (size_t i = 0; i < system_info.size(); i++)
|
for (size_t i = 0; i < system_info.size(); i++)
|
||||||
moof_->pssh[i].raw_box = system_info[i].CreateBox();
|
moof_->pssh[i].raw_box = system_info[i].psshs;
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING)
|
LOG(WARNING)
|
||||||
<< "Key rotation and no pssh in stream may not work well together.";
|
<< "Key rotation and no pssh in stream may not work well together.";
|
||||||
|
|
Loading…
Reference in New Issue