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,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
std::string* pssh_json) {
|
||||
media::ProtectionSystemSpecificInfo pssh_info;
|
||||
if (!pssh_info.Parse(pssh_box.data(), pssh_box.size())) {
|
||||
std::unique_ptr<media::PsshBoxBuilder> pssh_builder =
|
||||
media::PsshBoxBuilder::ParseFromBox(pssh_box.data(), pssh_box.size());
|
||||
if (!pssh_builder) {
|
||||
LOG(ERROR) << "Failed to parse PSSH box.";
|
||||
return false;
|
||||
}
|
||||
|
||||
media::WidevinePsshData pssh_proto;
|
||||
if (!pssh_proto.ParseFromArray(pssh_info.pssh_data().data(),
|
||||
pssh_info.pssh_data().size())) {
|
||||
if (!pssh_proto.ParseFromArray(pssh_builder->pssh_data().data(),
|
||||
pssh_builder->pssh_data().size())) {
|
||||
LOG(ERROR) << "Failed to parse protection_system_specific_data.";
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -493,11 +493,11 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
|
|||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||
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(),
|
||||
media::PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.set_pssh_data(pssh_data);
|
||||
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||
widevine_system_id_.size());
|
||||
pssh_info.add_key_id(any_key_id);
|
||||
pssh_builder.add_key_id(any_key_id);
|
||||
|
||||
const char kExpectedJson[] =
|
||||
"{"
|
||||
|
@ -508,7 +508,7 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevine) {
|
|||
base::Base64Encode(kExpectedJson, &expected_json_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()),
|
||||
&expected_pssh_base64);
|
||||
|
||||
|
@ -554,13 +554,13 @@ TEST_F(SimpleHlsNotifierTest, NotifyEncryptionUpdateWidevineNoKeyidsInPssh) {
|
|||
std::string expected_json_base64;
|
||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||
|
||||
media::ProtectionSystemSpecificInfo pssh_info;
|
||||
pssh_info.set_pssh_data(pssh_data);
|
||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
||||
media::PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.set_pssh_data(pssh_data);
|
||||
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||
widevine_system_id_.size());
|
||||
|
||||
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()),
|
||||
&expected_pssh_base64);
|
||||
|
||||
|
@ -647,12 +647,12 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
|
|||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||
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(),
|
||||
media::PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.set_pssh_data(pssh_data);
|
||||
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||
widevine_system_id_.size());
|
||||
pssh_info.add_key_id(first_keyid);
|
||||
pssh_info.add_key_id(second_keyid);
|
||||
pssh_builder.add_key_id(first_keyid);
|
||||
pssh_builder.add_key_id(second_keyid);
|
||||
|
||||
const char kExpectedJson[] =
|
||||
"{"
|
||||
|
@ -663,7 +663,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineMultipleKeyIdsNoContentIdInPssh) {
|
|||
base::Base64Encode(kExpectedJson, &expected_json_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()),
|
||||
&expected_pssh_base64);
|
||||
|
||||
|
@ -762,14 +762,8 @@ TEST_F(SimpleHlsNotifierTest, WidevineCencEncryptionScheme) {
|
|||
std::vector<uint8_t> pssh_data(widevine_pssh_data_str.begin(),
|
||||
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;
|
||||
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()),
|
||||
&expected_pssh_base64);
|
||||
|
||||
|
@ -814,11 +808,11 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
|||
std::string expected_json_base64;
|
||||
base::Base64Encode(kExpectedJson, &expected_json_base64);
|
||||
|
||||
media::ProtectionSystemSpecificInfo pssh_info;
|
||||
pssh_info.set_pssh_data(pssh_data);
|
||||
pssh_info.set_system_id(widevine_system_id_.data(),
|
||||
media::PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.set_pssh_data(pssh_data);
|
||||
pssh_builder.set_system_id(widevine_system_id_.data(),
|
||||
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,
|
||||
AddEncryptionInfo(
|
||||
|
@ -835,7 +829,7 @@ TEST_F(SimpleHlsNotifierTest, WidevineNotifyEncryptionUpdateEmptyIv) {
|
|||
"WVwcm92aWRlciIJY29udGVudGlk"),
|
||||
StrEq("0x11223344112233441122334411223344"), StrEq(""),
|
||||
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 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(
|
||||
stream_id,
|
||||
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) {
|
||||
|
|
|
@ -151,11 +151,13 @@ Status SetKeyInformationFromServerResponse(const std::string& response,
|
|||
LOG(ERROR) << "Cannot parse pssh data, " << pssh_data_b64;
|
||||
return Status(error::SERVER_ERROR, "Cannot parse pssh.");
|
||||
}
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(encryption_key->key_id);
|
||||
info.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId));
|
||||
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(kPlayReadySystemId, arraysize(kPlayReadySystemId));
|
||||
pssh_builder.set_pssh_data(pssh_data);
|
||||
encryption_key->key_system_info.push_back(
|
||||
{pssh_builder.system_id(), pssh_builder.CreateBox()});
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,81 +6,98 @@
|
|||
|
||||
#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/fourccs.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 media {
|
||||
|
||||
namespace {
|
||||
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;
|
||||
} // namespace
|
||||
|
||||
ProtectionSystemSpecificInfo::ProtectionSystemSpecificInfo()
|
||||
: version_(0) {}
|
||||
ProtectionSystemSpecificInfo::~ProtectionSystemSpecificInfo() {}
|
||||
|
||||
bool ProtectionSystemSpecificInfo::ParseBoxes(
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes) {
|
||||
pssh_boxes->clear();
|
||||
std::vector<ProtectionSystemSpecificInfo>* pssh_infos) {
|
||||
pssh_infos->clear();
|
||||
BufferReader reader(data, data_size);
|
||||
while (reader.HasBytes(1)) {
|
||||
size_t start_position = reader.pos();
|
||||
uint32_t size;
|
||||
RCHECK(reader.Read4(&size));
|
||||
RCHECK(reader.SkipBytes(size - 4));
|
||||
RCHECK(size > kPsshBoxHeaderSize + kSystemIdSize);
|
||||
|
||||
pssh_boxes->push_back(ProtectionSystemSpecificInfo());
|
||||
RCHECK(pssh_boxes->back().Parse(data + start_position, size));
|
||||
pssh_infos->push_back(
|
||||
{std::vector<uint8_t>(data + kPsshBoxHeaderSize,
|
||||
data + kPsshBoxHeaderSize + kSystemIdSize),
|
||||
std::vector<uint8_t>(data, data + size)});
|
||||
|
||||
data += size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProtectionSystemSpecificInfo::Parse(const uint8_t* data,
|
||||
std::unique_ptr<PsshBoxBuilder> PsshBoxBuilder::ParseFromBox(
|
||||
const uint8_t* data,
|
||||
size_t data_size) {
|
||||
std::unique_ptr<PsshBoxBuilder> pssh_builder(new PsshBoxBuilder);
|
||||
BufferReader reader(data, data_size);
|
||||
|
||||
uint32_t size;
|
||||
uint32_t box_type;
|
||||
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));
|
||||
RCHECK(reader.Read4(&box_type));
|
||||
RCHECK(size == data_size);
|
||||
RCHECK(box_type == FOURCC_pssh);
|
||||
RCHECK(reader.Read4(&version_and_flags));
|
||||
pssh_builder->version_ = (version_and_flags >> 24);
|
||||
RETURN_NULL_IF_FALSE(pssh_builder->version_ < 2);
|
||||
|
||||
version_ = (version_and_flags >> 24);
|
||||
RCHECK(version_ < 2);
|
||||
RCHECK(reader.ReadToVector(&system_id_, kSystemIdSize));
|
||||
RETURN_NULL_IF_FALSE(
|
||||
reader.ReadToVector(&pssh_builder->system_id_, kSystemIdSize));
|
||||
|
||||
if (version_ == 1) {
|
||||
if (pssh_builder->version_ == 1) {
|
||||
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++) {
|
||||
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.
|
||||
uint32_t pssh_data_size;
|
||||
RCHECK(reader.Read4(&pssh_data_size));
|
||||
RCHECK(reader.ReadToVector(&pssh_data_, pssh_data_size));
|
||||
RETURN_NULL_IF_FALSE(reader.Read4(&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
|
||||
// the data and size according to the size field of the box; therefore it
|
||||
// is an error if there are bytes remaining.
|
||||
RCHECK(!reader.HasBytes(1));
|
||||
return true;
|
||||
RETURN_NULL_IF_FALSE(!reader.HasBytes(1));
|
||||
return pssh_builder;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ProtectionSystemSpecificInfo::CreateBox() const {
|
||||
std::vector<uint8_t> PsshBoxBuilder::CreateBox() const {
|
||||
DCHECK_EQ(kSystemIdSize, system_id_.size());
|
||||
|
||||
const uint32_t box_type = FOURCC_pssh;
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
#define PACKAGER_MEDIA_BASE_PROTECTION_SYSTEM_SPECIFIC_INFO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/buffer_reader.h"
|
||||
|
||||
#define NO_PROTECTION_SYSTEM_FLAG 0x00
|
||||
#define COMMON_PROTECTION_SYSTEM_FLAG 0x01
|
||||
|
@ -21,10 +21,9 @@
|
|||
namespace shaka {
|
||||
namespace media {
|
||||
|
||||
class ProtectionSystemSpecificInfo {
|
||||
public:
|
||||
ProtectionSystemSpecificInfo();
|
||||
~ProtectionSystemSpecificInfo();
|
||||
struct ProtectionSystemSpecificInfo {
|
||||
std::vector<uint8_t> system_id;
|
||||
std::vector<uint8_t> psshs;
|
||||
|
||||
/// Parses multiple PSSH boxes from @a data. These boxes should be
|
||||
/// concatenated together. Any non-PSSH box is an error.
|
||||
|
@ -33,10 +32,17 @@ class ProtectionSystemSpecificInfo {
|
|||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes);
|
||||
};
|
||||
|
||||
class PsshBoxBuilder {
|
||||
public:
|
||||
PsshBoxBuilder() = default;
|
||||
~PsshBoxBuilder() = default;
|
||||
|
||||
/// Parses the given PSSH box into this object.
|
||||
/// @return true on success; false on failure.
|
||||
bool Parse(const uint8_t* data, size_t data_size);
|
||||
/// @return nullptr on failure.
|
||||
static std::unique_ptr<PsshBoxBuilder> ParseFromBox(const uint8_t* data,
|
||||
size_t data_size);
|
||||
|
||||
/// Creates a PSSH box for the current data.
|
||||
std::vector<uint8_t> CreateBox() const;
|
||||
|
@ -63,13 +69,13 @@ class ProtectionSystemSpecificInfo {
|
|||
}
|
||||
|
||||
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<std::vector<uint8_t>> key_ids_;
|
||||
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
|
||||
|
|
|
@ -67,25 +67,37 @@ TEST_F(PsshTest, ParseBoxes_SupportsV0) {
|
|||
std::vector<ProtectionSystemSpecificInfo> info;
|
||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
||||
v0_box_.data(), v0_box_.size(), &info));
|
||||
ASSERT_EQ(1u, info.size());
|
||||
|
||||
ASSERT_EQ(0u, info[0].key_ids().size());
|
||||
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());
|
||||
ASSERT_EQ(1u, info.size());
|
||||
EXPECT_EQ(test_system_id_, info[0].system_id);
|
||||
|
||||
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) {
|
||||
std::vector<ProtectionSystemSpecificInfo> info;
|
||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(
|
||||
v1_box_.data(), v1_box_.size(), &info));
|
||||
ASSERT_EQ(1u, info.size());
|
||||
|
||||
ASSERT_EQ(1u, info[0].key_ids().size());
|
||||
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());
|
||||
EXPECT_EQ(1, info[0].pssh_box_version());
|
||||
ASSERT_EQ(1u, info.size());
|
||||
EXPECT_EQ(test_system_id_, info[0].system_id);
|
||||
|
||||
std::unique_ptr<PsshBoxBuilder> pssh_builder =
|
||||
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) {
|
||||
|
@ -95,45 +107,57 @@ TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
|||
data.insert(data.end(), v1_box_.begin(), v1_box_.end());
|
||||
|
||||
std::vector<ProtectionSystemSpecificInfo> info;
|
||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(data.data(),
|
||||
data.size(), &info));
|
||||
ASSERT_TRUE(ProtectionSystemSpecificInfo::ParseBoxes(data.data(), data.size(),
|
||||
&info));
|
||||
ASSERT_EQ(3u, info.size());
|
||||
|
||||
ASSERT_EQ(1u, info[0].key_ids().size());
|
||||
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());
|
||||
EXPECT_EQ(1, 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, info[1].key_ids().size());
|
||||
EXPECT_EQ(test_system_id_, info[1].system_id());
|
||||
EXPECT_EQ(test_pssh_data_, info[1].pssh_data());
|
||||
EXPECT_EQ(0, info[1].pssh_box_version());
|
||||
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());
|
||||
|
||||
ASSERT_EQ(1u, info[2].key_ids().size());
|
||||
EXPECT_EQ(test_system_id_, info[2].system_id());
|
||||
EXPECT_EQ(test_key_id_, info[2].key_ids()[0]);
|
||||
EXPECT_EQ(test_pssh_data_, info[2].pssh_data());
|
||||
EXPECT_EQ(1, info[2].pssh_box_version());
|
||||
pssh_builder =
|
||||
PsshBoxBuilder::ParseFromBox(info[1].psshs.data(), info[1].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());
|
||||
|
||||
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) {
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
info.set_pssh_data(test_pssh_data_);
|
||||
info.set_pssh_box_version(0);
|
||||
PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
pssh_builder.set_pssh_data(test_pssh_data_);
|
||||
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) {
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(test_key_id_);
|
||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
info.set_pssh_data(test_pssh_data_);
|
||||
info.set_pssh_box_version(1);
|
||||
PsshBoxBuilder pssh_builder;
|
||||
pssh_builder.add_key_id(test_key_id_);
|
||||
pssh_builder.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
pssh_builder.set_pssh_data(test_pssh_data_);
|
||||
pssh_builder.set_pssh_box_version(1);
|
||||
|
||||
EXPECT_EQ(v1_box_, info.CreateBox());
|
||||
EXPECT_EQ(v1_box_, pssh_builder.CreateBox());
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -8,6 +8,25 @@
|
|||
|
||||
namespace shaka {
|
||||
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() {}
|
||||
|
||||
|
@ -22,17 +41,9 @@ Status PsshGenerator::GeneratePsshFromKeyIds(
|
|||
return Status(error::ENCRYPTION_FAILURE,
|
||||
"Fail to generate PSSH data from multiple Key IDs.");
|
||||
}
|
||||
info->set_pssh_data(pssh_data.value());
|
||||
|
||||
info->clear_key_ids();
|
||||
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());
|
||||
|
||||
info->system_id = SystemId();
|
||||
info->psshs =
|
||||
CreatePsshBox(SystemId(), PsshBoxVersion(), key_ids, pssh_data.value());
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
@ -46,14 +57,9 @@ Status PsshGenerator::GeneratePsshFromKeyIdAndKey(
|
|||
return Status(error::ENCRYPTION_FAILURE,
|
||||
"Fail to generate PSSH data from Key ID and Key.");
|
||||
}
|
||||
info->set_pssh_data(pssh_data.value());
|
||||
|
||||
info->clear_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());
|
||||
|
||||
info->system_id = SystemId();
|
||||
info->psshs =
|
||||
CreatePsshBox(SystemId(), PsshBoxVersion(), {key_id}, pssh_data.value());
|
||||
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 char kExpectedPlayReadyPsshData[] = {
|
||||
'\x6', '\x2', '\x0', '\x0', '\x1', '\x0', '\x1', '\x0', '\xfc', '\x1',
|
||||
'<', '\x0', 'W', '\x0', 'R', '\x0', 'M', '\x0', 'H', '\x0',
|
||||
'E', '\x0', 'A', '\x0', 'D', '\x0', 'E', '\x0', 'R', '\x0',
|
||||
' ', '\x0', 'x', '\x0', 'm', '\x0', 'l', '\x0', 'n', '\x0',
|
||||
's', '\x0', '=', '\x0', '"', '\x0', 'h', '\x0', 't', '\x0',
|
||||
't', '\x0', 'p', '\x0', ':', '\x0', '/', '\x0', '/', '\x0',
|
||||
's', '\x0', 'c', '\x0', 'h', '\x0', 'e', '\x0', 'm', '\x0',
|
||||
'a', '\x0', 's', '\x0', '.', '\x0', 'm', '\x0', 'i', '\x0',
|
||||
'c', '\x0', 'r', '\x0', 'o', '\x0', 's', '\x0', 'o', '\x0',
|
||||
'f', '\x0', 't', '\x0', '.', '\x0', 'c', '\x0', 'o', '\x0',
|
||||
'm', '\x0', '/', '\x0', 'D', '\x0', 'R', '\x0', 'M', '\x0',
|
||||
'/', '\x0', '2', '\x0', '0', '\x0', '0', '\x0', '7', '\x0',
|
||||
'/', '\x0', '0', '\x0', '3', '\x0', '/', '\x0', 'P', '\x0',
|
||||
'l', '\x0', 'a', '\x0', 'y', '\x0', 'R', '\x0', 'e', '\x0',
|
||||
'a', '\x0', 'd', '\x0', 'y', '\x0', 'H', '\x0', 'e', '\x0',
|
||||
'a', '\x0', 'd', '\x0', 'e', '\x0', 'r', '\x0', '"', '\x0',
|
||||
' ', '\x0', 'v', '\x0', 'e', '\x0', 'r', '\x0', 's', '\x0',
|
||||
'i', '\x0', 'o', '\x0', 'n', '\x0', '=', '\x0', '"', '\x0',
|
||||
'4', '\x0', '.', '\x0', '0', '\x0', '.', '\x0', '0', '\x0',
|
||||
'.', '\x0', '0', '\x0', '"', '\x0', '>', '\x0', '<', '\x0',
|
||||
'D', '\x0', 'A', '\x0', 'T', '\x0', 'A', '\x0', '>', '\x0',
|
||||
'<', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0', 'T', '\x0',
|
||||
'E', '\x0', 'C', '\x0', 'T', '\x0', 'I', '\x0', 'N', '\x0',
|
||||
'F', '\x0', 'O', '\x0', '>', '\x0', '<', '\x0', 'K', '\x0',
|
||||
'E', '\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0', 'N', '\x0',
|
||||
'>', '\x0', '1', '\x0', '6', '\x0', '<', '\x0', '/', '\x0',
|
||||
'K', '\x0', 'E', '\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0',
|
||||
'N', '\x0', '>', '\x0', '<', '\x0', 'A', '\x0', 'L', '\x0',
|
||||
'G', '\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', 'A', '\x0',
|
||||
'E', '\x0', 'S', '\x0', 'C', '\x0', 'T', '\x0', 'R', '\x0',
|
||||
'<', '\x0', '/', '\x0', 'A', '\x0', 'L', '\x0', 'G', '\x0',
|
||||
'I', '\x0', 'D', '\x0', '>', '\x0', '<', '\x0', '/', '\x0',
|
||||
'P', '\x0', 'R', '\x0', 'O', '\x0', 'T', '\x0', 'E', '\x0',
|
||||
'C', '\x0', 'T', '\x0', 'I', '\x0', 'N', '\x0', 'F', '\x0',
|
||||
'O', '\x0', '>', '\x0', '<', '\x0', 'K', '\x0', 'I', '\x0',
|
||||
'D', '\x0', '>', '\x0', 'a', '\x0', 'X', '\x0', 'l', '\x0',
|
||||
'l', '\x0', 'a', '\x0', 'z', '\x0', 'F', '\x0', 'k', '\x0',
|
||||
'f', '\x0', 'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0',
|
||||
'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'n', '\x0',
|
||||
'5', '\x0', '+', '\x0', 'f', '\x0', 'g', '\x0', '=', '\x0',
|
||||
'=', '\x0', '<', '\x0', '/', '\x0', 'K', '\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 kExpectedPlayReadyPssh[] = {
|
||||
'\x0', '\x0', '\x2', '\x3A', 'p', 's', 's', 'h', '\x1',
|
||||
'\x0', '\x0', '\x0', '\x9A', '\x04', '\xf0', '\x79', '\x98', '\x40',
|
||||
'\x42', '\x86', '\xab', '\x92', '\xe6', '\x5b', '\xe0', '\x88', '\x5f',
|
||||
'\x95', '\x0', '\x0', '\x0', '\x1', 'k', 'e', 'y', 'i',
|
||||
'd', '1', '~', '~', '~', '~', '~', '~', '~',
|
||||
'~', '~', '~', '\x0', '\x0', '\x2', '\x6', '\x6', '\x2',
|
||||
'\x0', '\x0', '\x1', '\x0', '\x1', '\x0', '\xfc', '\x1', '<',
|
||||
'\x0', 'W', '\x0', 'R', '\x0', 'M', '\x0', 'H', '\x0',
|
||||
'E', '\x0', 'A', '\x0', 'D', '\x0', 'E', '\x0', 'R',
|
||||
'\x0', ' ', '\x0', 'x', '\x0', 'm', '\x0', 'l', '\x0',
|
||||
'n', '\x0', 's', '\x0', '=', '\x0', '"', '\x0', 'h',
|
||||
'\x0', 't', '\x0', 't', '\x0', 'p', '\x0', ':', '\x0',
|
||||
'/', '\x0', '/', '\x0', 's', '\x0', 'c', '\x0', 'h',
|
||||
'\x0', 'e', '\x0', 'm', '\x0', 'a', '\x0', 's', '\x0',
|
||||
'.', '\x0', 'm', '\x0', 'i', '\x0', 'c', '\x0', 'r',
|
||||
'\x0', 'o', '\x0', 's', '\x0', 'o', '\x0', 'f', '\x0',
|
||||
't', '\x0', '.', '\x0', 'c', '\x0', 'o', '\x0', 'm',
|
||||
'\x0', '/', '\x0', 'D', '\x0', 'R', '\x0', 'M', '\x0',
|
||||
'/', '\x0', '2', '\x0', '0', '\x0', '0', '\x0', '7',
|
||||
'\x0', '/', '\x0', '0', '\x0', '3', '\x0', '/', '\x0',
|
||||
'P', '\x0', 'l', '\x0', 'a', '\x0', 'y', '\x0', 'R',
|
||||
'\x0', 'e', '\x0', 'a', '\x0', 'd', '\x0', 'y', '\x0',
|
||||
'H', '\x0', 'e', '\x0', 'a', '\x0', 'd', '\x0', 'e',
|
||||
'\x0', 'r', '\x0', '"', '\x0', ' ', '\x0', 'v', '\x0',
|
||||
'e', '\x0', 'r', '\x0', 's', '\x0', 'i', '\x0', 'o',
|
||||
'\x0', 'n', '\x0', '=', '\x0', '"', '\x0', '4', '\x0',
|
||||
'.', '\x0', '0', '\x0', '.', '\x0', '0', '\x0', '.',
|
||||
'\x0', '0', '\x0', '"', '\x0', '>', '\x0', '<', '\x0',
|
||||
'D', '\x0', 'A', '\x0', 'T', '\x0', 'A', '\x0', '>',
|
||||
'\x0', '<', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0',
|
||||
'T', '\x0', 'E', '\x0', 'C', '\x0', 'T', '\x0', 'I',
|
||||
'\x0', 'N', '\x0', 'F', '\x0', 'O', '\x0', '>', '\x0',
|
||||
'<', '\x0', 'K', '\x0', 'E', '\x0', 'Y', '\x0', 'L',
|
||||
'\x0', 'E', '\x0', 'N', '\x0', '>', '\x0', '1', '\x0',
|
||||
'6', '\x0', '<', '\x0', '/', '\x0', 'K', '\x0', 'E',
|
||||
'\x0', 'Y', '\x0', 'L', '\x0', 'E', '\x0', 'N', '\x0',
|
||||
'>', '\x0', '<', '\x0', 'A', '\x0', 'L', '\x0', 'G',
|
||||
'\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', 'A', '\x0',
|
||||
'E', '\x0', 'S', '\x0', 'C', '\x0', 'T', '\x0', 'R',
|
||||
'\x0', '<', '\x0', '/', '\x0', 'A', '\x0', 'L', '\x0',
|
||||
'G', '\x0', 'I', '\x0', 'D', '\x0', '>', '\x0', '<',
|
||||
'\x0', '/', '\x0', 'P', '\x0', 'R', '\x0', 'O', '\x0',
|
||||
'T', '\x0', 'E', '\x0', 'C', '\x0', 'T', '\x0', 'I',
|
||||
'\x0', 'N', '\x0', 'F', '\x0', 'O', '\x0', '>', '\x0',
|
||||
'<', '\x0', 'K', '\x0', 'I', '\x0', 'D', '\x0', '>',
|
||||
'\x0', 'a', '\x0', 'X', '\x0', 'l', '\x0', 'l', '\x0',
|
||||
'a', '\x0', 'z', '\x0', 'F', '\x0', 'k', '\x0', 'f',
|
||||
'\x0', 'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0',
|
||||
'n', '\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'n',
|
||||
'\x0', '5', '\x0', '+', '\x0', 'f', '\x0', 'g', '\x0',
|
||||
'=', '\x0', '=', '\x0', '<', '\x0', '/', '\x0', 'K',
|
||||
'\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[] = {
|
||||
'\x12', '\x10', 'k', 'e', 'y', 'i', 'd', '1', '~', '~', '~', '~',
|
||||
'~', '~', '~', '~', '~', '~', '\x12', '\x10', 'k', 'e', 'y', 'i',
|
||||
'd', '2', '~', '~', '~', '~', '~', '~', '~', '~', '~', '~',
|
||||
const char kExpectedCommonPssh[] = {
|
||||
'\x0', '\x0', '\x0', '\x44', 'p', 's', 's', 'h', '\x1',
|
||||
'\x0', '\x0', '\x0', '\x10', '\x77', '\xEF', '\xEC', '\xC0', '\xB2',
|
||||
'\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() {
|
||||
|
@ -99,12 +128,6 @@ std::vector<uint8_t> GetTestKeyId2() {
|
|||
}
|
||||
} // 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
|
||||
// to each individual files (e.g., playready_pssh_generate_unittest.cc).
|
||||
TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIds) {
|
||||
|
@ -117,10 +140,7 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIds) {
|
|||
playready_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||
}
|
||||
|
||||
// TODO(hmchen): change the testing interface from
|
||||
// GeneratePsshDataFromKeyIdAndKey to GeneratePsshFromKeyIdAndKey, after the
|
||||
// later one is not used as a static function.
|
||||
TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIdAndKey) {
|
||||
TEST(PsshGeneratorTest, GeneratePlayReadyPsshFromKeyIdAndKey) {
|
||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||
|
@ -129,23 +149,22 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIdAndKey) {
|
|||
EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey(
|
||||
kTestKeyId, kTestKey, &info));
|
||||
|
||||
EXPECT_THAT(info.pssh_data(),
|
||||
ElementsAreArray(std::begin(kExpectedPlayReadyPsshData),
|
||||
std::end(kExpectedPlayReadyPsshData)));
|
||||
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedPlayReadyPssh),
|
||||
std::end(kExpectedPlayReadyPssh)));
|
||||
}
|
||||
|
||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIds) {
|
||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshFromKeyIds) {
|
||||
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
||||
GetTestKeyId2()};
|
||||
std::unique_ptr<RawKeyPsshGenerator> raw_key_pssh_generator(
|
||||
new RawKeyPsshGenerator());
|
||||
ProtectionSystemSpecificInfo info;
|
||||
EXPECT_OK(raw_key_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||
// Intentionally empty pssh data for raw key.
|
||||
EXPECT_TRUE(info.pssh_data().empty());
|
||||
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedCommonPssh),
|
||||
std::end(kExpectedCommonPssh)));
|
||||
}
|
||||
|
||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIdAndKey) {
|
||||
TEST(PsshGeneratorTest, GenerateRawKeyPsshFromKeyIdAndKey) {
|
||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||
std::unique_ptr<RawKeyPsshGenerator> raw_key_pssh_generator(
|
||||
|
@ -155,7 +174,7 @@ TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIdAndKey) {
|
|||
kTestKeyId, kTestKey, &info));
|
||||
}
|
||||
|
||||
TEST(PsshGeneratorTest, GenerateWidevinePsshDataFromKeyIds) {
|
||||
TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIds) {
|
||||
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
|
||||
GetTestKeyId2()};
|
||||
std::unique_ptr<WidevinePsshGenerator> widevine_pssh_generator(
|
||||
|
@ -164,12 +183,11 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshDataFromKeyIds) {
|
|||
ASSERT_OK(
|
||||
widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info));
|
||||
|
||||
EXPECT_THAT(info.pssh_data(),
|
||||
ElementsAreArray(std::begin(kExpectedWidevinePsshData),
|
||||
std::end(kExpectedWidevinePsshData)));
|
||||
EXPECT_THAT(info.psshs, ElementsAreArray(std::begin(kExpectedWidevinePssh),
|
||||
std::end(kExpectedWidevinePssh)));
|
||||
}
|
||||
|
||||
TEST(PsshGeneratorTest, GenerateWidevinyPsshDataFromKeyIdAndKey) {
|
||||
TEST(PsshGeneratorTest, GenerateWidevinyPsshFromKeyIdAndKey) {
|
||||
const std::vector<uint8_t> kTestKeyId = GetTestKeyId1();
|
||||
const std::vector<uint8_t> kTestKey = GetTestKey1();
|
||||
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(kIvHex, key_from_drm_label.iv);
|
||||
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
||||
EXPECT_HEX_EQ(kPsshBox1Hex,
|
||||
key_from_drm_label.key_system_info[0].CreateBox());
|
||||
EXPECT_HEX_EQ(kPsshBox2Hex,
|
||||
key_from_drm_label.key_system_info[1].CreateBox());
|
||||
EXPECT_HEX_EQ(kPsshBox1Hex, key_from_drm_label.key_system_info[0].psshs);
|
||||
EXPECT_HEX_EQ(kPsshBox2Hex, key_from_drm_label.key_system_info[1].psshs);
|
||||
|
||||
// Using 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(kIvHex, key_from_drm_label.iv);
|
||||
ASSERT_EQ(2u, key_from_drm_label.key_system_info.size());
|
||||
EXPECT_HEX_EQ(kPsshBox1Hex,
|
||||
key_from_drm_label.key_system_info[0].CreateBox());
|
||||
EXPECT_HEX_EQ(kPsshBox2Hex,
|
||||
key_from_drm_label.key_system_info[1].CreateBox());
|
||||
EXPECT_HEX_EQ(kPsshBox1Hex, key_from_drm_label.key_system_info[0].psshs);
|
||||
EXPECT_HEX_EQ(kPsshBox2Hex, key_from_drm_label.key_system_info[1].psshs);
|
||||
}
|
||||
|
||||
TEST(RawKeySourceTest, EmptyPssh) {
|
||||
|
@ -122,7 +118,7 @@ TEST(RawKeySourceTest, EmptyPssh) {
|
|||
EXPECT_HEX_EQ(kKeyHex, key.key);
|
||||
EXPECT_HEX_EQ(kIvHex, key.iv);
|
||||
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) {
|
||||
|
|
|
@ -179,13 +179,18 @@ Status WidevineKeySource::FetchKeys(EmeInitDataType init_data_type,
|
|||
return Status(error::PARSER_FAILURE, "Error parsing the PSSH boxes.");
|
||||
}
|
||||
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
|
||||
// from the first available key ids.
|
||||
if (info.system_id() == widevine_system_id) {
|
||||
pssh_data = info.pssh_data();
|
||||
if (info.system_id == widevine_system_id) {
|
||||
pssh_data = pssh_builder->pssh_data();
|
||||
break;
|
||||
} else if (pssh_data.empty() && !info.key_ids().empty()) {
|
||||
pssh_data = GenerateWidevinePsshDataFromKeyIds(info.key_ids());
|
||||
} else if (pssh_data.empty() && !pssh_builder->key_ids().empty()) {
|
||||
pssh_data =
|
||||
GenerateWidevinePsshDataFromKeyIds(pssh_builder->key_ids());
|
||||
// Continue to see if there is any Widevine PSSH. The KeyId generated
|
||||
// PSSH is only used if a Widevine PSSH could not be found.
|
||||
continue;
|
||||
|
@ -558,17 +563,19 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
|||
if (!GetKeyIdFromTrack(*track_dict, &encryption_key->key_id))
|
||||
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;
|
||||
if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -217,44 +217,29 @@ class WidevineKeySourceTest : public Test {
|
|||
1 + (add_common_pssh_ ? 1 : 0) + (add_playready_pssh_ ? 1 : 0);
|
||||
ASSERT_EQ(num_key_system_info, encryption_key.key_system_info.size());
|
||||
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_) {
|
||||
// Each of the keys contains all the key IDs.
|
||||
const std::vector<uint8_t> common_system_id(
|
||||
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
||||
ASSERT_EQ(common_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));
|
||||
}
|
||||
encryption_key.key_system_info[1].system_id);
|
||||
}
|
||||
|
||||
if (add_playready_pssh_) {
|
||||
const std::vector<uint8_t> playready_system_id(
|
||||
kPlayReadySystemId,
|
||||
kPlayReadySystemId + arraysize(kPlayReadySystemId));
|
||||
|
||||
// PlayReady pssh index depends on if there has common pssh box.
|
||||
const uint8_t playready_index = 1 + (add_common_pssh_ ? 1 : 0);
|
||||
ASSERT_EQ(
|
||||
playready_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));
|
||||
ASSERT_EQ(playready_system_id,
|
||||
encryption_key.key_system_info[playready_index].system_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ void HlsNotifyMuxerListener::OnEncryptionInfoReady(
|
|||
}
|
||||
for (const ProtectionSystemSpecificInfo& info : key_system_infos) {
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,7 @@ void HlsNotifyMuxerListener::OnEncryptionStart() {
|
|||
|
||||
for (const ProtectionSystemSpecificInfo& info : next_key_system_infos_) {
|
||||
const bool result = hls_notifier_->NotifyEncryptionUpdate(
|
||||
stream_id_, next_key_id_, info.system_id(), next_iv_,
|
||||
info.CreateBox());
|
||||
stream_id_, next_key_id_, info.system_id, next_iv_, info.psshs);
|
||||
LOG_IF(WARNING, !result) << "Failed to add encryption info";
|
||||
}
|
||||
next_key_id_.clear();
|
||||
|
|
|
@ -121,22 +121,12 @@ class HlsNotifyMuxerListenerTest : public ::testing::Test {
|
|||
// Verify that NotifyEncryptionUpdate() is not called before OnMediaStart() is
|
||||
// called.
|
||||
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<ProtectionSystemSpecificInfo> key_system_infos;
|
||||
key_system_infos.push_back(info);
|
||||
|
||||
std::vector<uint8_t> iv(16, 0x54);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, GetDefaultKeySystemInfo());
|
||||
}
|
||||
|
||||
TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
||||
|
@ -158,22 +148,15 @@ TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) {
|
|||
// OnEncryptionStart() should call MuxerListener::NotifyEncryptionUpdate() after
|
||||
// OnEncryptionInfoReady() and OnMediaStart().
|
||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
||||
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> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||
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);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, {{system_id, pssh}});
|
||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||
|
||||
ON_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||
|
@ -189,8 +172,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
|||
MuxerListener::kContainerMpeg2ts);
|
||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
||||
info.CreateBox()))
|
||||
EXPECT_CALL(mock_notifier_,
|
||||
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||
.WillOnce(Return(true));
|
||||
listener_.OnEncryptionStart();
|
||||
}
|
||||
|
@ -199,22 +182,15 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStart) {
|
|||
// HlsNotiifer::NotifyEncryptionUpdate() should be called by the end of
|
||||
// OnMediaStart().
|
||||
TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionStartBeforeMediaStart) {
|
||||
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> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||
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);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, {{system_id, pssh}});
|
||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||
|
||||
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
|
||||
// OnEncryptionStart() if that is possible. Just matters that it is called by
|
||||
// the time OnMediaStart() returns.
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
||||
info.CreateBox()))
|
||||
EXPECT_CALL(mock_notifier_,
|
||||
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||
.WillOnce(Return(true));
|
||||
listener_.OnEncryptionStart();
|
||||
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
|
||||
// OnMediaStart().
|
||||
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<ProtectionSystemSpecificInfo> key_system_infos;
|
||||
key_system_infos.push_back(info);
|
||||
|
||||
std::vector<uint8_t> iv(16, 0x54);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, _, _, _, _)).Times(0);
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, GetDefaultKeySystemInfo());
|
||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyNewStream(_, _, _, _, _))
|
||||
|
@ -283,44 +249,27 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) {
|
|||
listener_.OnMediaStart(muxer_options, *video_stream_info, 90000,
|
||||
MuxerListener::kContainerMpeg2ts);
|
||||
|
||||
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> pssh(kAnyData, kAnyData + arraysize(kAnyData));
|
||||
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);
|
||||
|
||||
EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv,
|
||||
info.CreateBox()))
|
||||
EXPECT_CALL(mock_notifier_,
|
||||
NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh))
|
||||
.WillOnce(Return(true));
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, {{system_id, pssh}});
|
||||
}
|
||||
|
||||
// Verify that if protection scheme is specified in OnEncryptionInfoReady(),
|
||||
// the information is copied to MediaInfo in OnMediaStart().
|
||||
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<ProtectionSystemSpecificInfo> key_system_infos;
|
||||
key_system_infos.push_back(info);
|
||||
|
||||
std::vector<uint8_t> iv(16, 0x54);
|
||||
|
||||
listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, key_id,
|
||||
iv, key_system_infos);
|
||||
iv, GetDefaultKeySystemInfo());
|
||||
::testing::Mock::VerifyAndClearExpectations(&mock_notifier_);
|
||||
|
||||
ON_CALL(mock_notifier_,
|
||||
|
|
|
@ -46,10 +46,9 @@ void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
|||
DCHECK_EQ(protection_scheme, protection_scheme_);
|
||||
|
||||
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
||||
std::string drm_uuid = internal::CreateUUIDString(info.system_id());
|
||||
std::vector<uint8_t> new_pssh = info.CreateBox();
|
||||
std::string drm_uuid = internal::CreateUUIDString(info.system_id);
|
||||
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.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace shaka {
|
|||
namespace media {
|
||||
|
||||
struct MuxerOptions;
|
||||
class ProtectionSystemSpecificInfo;
|
||||
struct ProtectionSystemSpecificInfo;
|
||||
class StreamInfo;
|
||||
|
||||
/// 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) {
|
||||
MediaInfo::ProtectedContent::ContentProtectionEntry* 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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,20 +94,13 @@ void SetDefaultMuxerOptions(MuxerOptions* muxer_options) {
|
|||
}
|
||||
|
||||
std::vector<ProtectionSystemSpecificInfo> GetDefaultKeySystemInfo() {
|
||||
const uint8_t kPsshData[] = {'p', 's', 's', 'h'};
|
||||
const uint8_t kTestSystemId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f};
|
||||
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.set_system_id(kTestSystemId, arraysize(kTestSystemId));
|
||||
info.set_pssh_data(
|
||||
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;
|
||||
return {{{std::begin(kTestSystemId), std::end(kTestSystemId)},
|
||||
{std::begin(kExpectedDefaultPsshBox),
|
||||
// -1 to remove the null terminator.
|
||||
std::end(kExpectedDefaultPsshBox) - 1}}};
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -21,12 +21,7 @@ namespace shaka {
|
|||
|
||||
namespace media {
|
||||
|
||||
// A string containing the escaped PSSH box (for use with a MediaInfo proto).
|
||||
// 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 kExpectedDefaultPsshBox[] = "expected_pssh_box";
|
||||
const char kExpectedDefaultMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1.010101'\n"
|
||||
|
|
|
@ -212,7 +212,7 @@ Status MP4Muxer::InitializeMuxer() {
|
|||
streams()[i]->encryption_config().key_system_info;
|
||||
moov->pssh.resize(key_system_info.size());
|
||||
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;
|
||||
moof_->pssh.resize(system_info.size());
|
||||
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 {
|
||||
LOG(WARNING)
|
||||
<< "Key rotation and no pssh in stream may not work well together.";
|
||||
|
|
Loading…
Reference in New Issue