Add support for v1 PSSH boxes.
This moves pssh parsing to its own class in media base. This type can be used to parse and generate pssh boxes. This new type also supports both v0 an v1 boxes. This also modifies the pssh box definition to only have the |raw_box| and moves all pssh parsing and handling into mp4 media parser. A follow-up change will replace the remaining usages of 'raw' pssh box data with the new type. Issue #88 Change-Id: Ic2436ecb5df8b3558b81e600dc095b0efd122ab1
This commit is contained in:
parent
0ca1160474
commit
9d67f545ed
|
@ -61,6 +61,8 @@
|
||||||
'offset_byte_queue.cc',
|
'offset_byte_queue.cc',
|
||||||
'offset_byte_queue.h',
|
'offset_byte_queue.h',
|
||||||
'producer_consumer_queue.h',
|
'producer_consumer_queue.h',
|
||||||
|
'protection_system_specific_info.cc',
|
||||||
|
'protection_system_specific_info.h',
|
||||||
'request_signer.cc',
|
'request_signer.cc',
|
||||||
'request_signer.h',
|
'request_signer.h',
|
||||||
'rsa_key.cc',
|
'rsa_key.cc',
|
||||||
|
@ -116,6 +118,7 @@
|
||||||
'muxer_util_unittest.cc',
|
'muxer_util_unittest.cc',
|
||||||
'offset_byte_queue_unittest.cc',
|
'offset_byte_queue_unittest.cc',
|
||||||
'producer_consumer_queue_unittest.cc',
|
'producer_consumer_queue_unittest.cc',
|
||||||
|
'protection_system_specific_info_unittest.cc',
|
||||||
'rsa_key_unittest.cc',
|
'rsa_key_unittest.cc',
|
||||||
'status_test_util_unittest.cc',
|
'status_test_util_unittest.cc',
|
||||||
'status_unittest.cc',
|
'status_unittest.cc',
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include "packager/media/base/protection_system_specific_info.h"
|
||||||
|
|
||||||
|
#include "packager/media/base/buffer_writer.h"
|
||||||
|
// Header-only files:
|
||||||
|
#include "packager/media/formats/mp4/fourccs.h"
|
||||||
|
#include "packager/media/formats/mp4/rcheck.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const size_t kSystemIdSize = 16u;
|
||||||
|
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) {
|
||||||
|
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));
|
||||||
|
|
||||||
|
pssh_boxes->emplace_back();
|
||||||
|
RCHECK(pssh_boxes->back().Parse(data + start_position, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProtectionSystemSpecificInfo::Parse(const uint8_t* data,
|
||||||
|
size_t data_size) {
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t box_type;
|
||||||
|
uint32_t version_and_flags;
|
||||||
|
BufferReader reader(data, data_size);
|
||||||
|
|
||||||
|
RCHECK(reader.Read4(&size));
|
||||||
|
RCHECK(reader.Read4(&box_type));
|
||||||
|
RCHECK(size == data_size);
|
||||||
|
RCHECK(box_type == mp4::FOURCC_PSSH);
|
||||||
|
RCHECK(reader.Read4(&version_and_flags));
|
||||||
|
|
||||||
|
version_ = (version_and_flags >> 24);
|
||||||
|
RCHECK(version_ < 2);
|
||||||
|
RCHECK(reader.ReadToVector(&system_id_, kSystemIdSize));
|
||||||
|
|
||||||
|
if (version_ == 1) {
|
||||||
|
uint32_t key_id_count;
|
||||||
|
RCHECK(reader.Read4(&key_id_count));
|
||||||
|
|
||||||
|
key_ids_.resize(key_id_count);
|
||||||
|
for (uint32_t i = 0; i < key_id_count; i++) {
|
||||||
|
RCHECK(reader.ReadToVector(&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));
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ProtectionSystemSpecificInfo::CreateBox() const {
|
||||||
|
DCHECK_EQ(kSystemIdSize, system_id_.size());
|
||||||
|
|
||||||
|
const uint32_t box_type = mp4::FOURCC_PSSH;
|
||||||
|
const uint32_t version_and_flags = (static_cast<uint32_t>(version_) << 24);
|
||||||
|
const uint32_t pssh_data_size = pssh_data_.size();
|
||||||
|
|
||||||
|
const uint32_t key_id_count = key_ids_.size();
|
||||||
|
const uint32_t key_ids_size =
|
||||||
|
sizeof(key_id_count) + kKeyIdSize * key_id_count;
|
||||||
|
const uint32_t extra_size = version_ == 1 ? key_ids_size : 0;
|
||||||
|
|
||||||
|
const uint32_t total_size =
|
||||||
|
sizeof(total_size) + sizeof(box_type) + sizeof(version_and_flags) +
|
||||||
|
kSystemIdSize + extra_size + sizeof(pssh_data_size) + pssh_data_size;
|
||||||
|
|
||||||
|
BufferWriter writer;
|
||||||
|
writer.AppendInt(total_size);
|
||||||
|
writer.AppendInt(box_type);
|
||||||
|
writer.AppendInt(version_and_flags);
|
||||||
|
writer.AppendVector(system_id_);
|
||||||
|
if (version_ == 1) {
|
||||||
|
writer.AppendInt(key_id_count);
|
||||||
|
for (size_t i = 0; i < key_id_count; i++) {
|
||||||
|
DCHECK_EQ(kKeyIdSize, key_ids_[i].size());
|
||||||
|
writer.AppendVector(key_ids_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.AppendInt(pssh_data_size);
|
||||||
|
writer.AppendVector(pssh_data_);
|
||||||
|
|
||||||
|
DCHECK_EQ(total_size, writer.Size());
|
||||||
|
return std::vector<uint8_t>(writer.Buffer(), writer.Buffer() + writer.Size());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
|
@ -0,0 +1,75 @@
|
||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#ifndef MEDIA_BASE_PSSH_H_
|
||||||
|
#define MEDIA_BASE_PSSH_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "packager/base/logging.h"
|
||||||
|
#include "packager/media/base/buffer_reader.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
class ProtectionSystemSpecificInfo {
|
||||||
|
public:
|
||||||
|
ProtectionSystemSpecificInfo();
|
||||||
|
~ProtectionSystemSpecificInfo();
|
||||||
|
|
||||||
|
/// Parses multiple PSSH boxes from @a data. These boxes should be
|
||||||
|
/// concatenated together. Any non-PSSH box is an error.
|
||||||
|
/// @return true on success; false on failure.
|
||||||
|
static bool ParseBoxes(
|
||||||
|
const uint8_t* data,
|
||||||
|
size_t data_size,
|
||||||
|
std::vector<ProtectionSystemSpecificInfo>* pssh_boxes);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
/// Creates a PSSH box for the current data.
|
||||||
|
std::vector<uint8_t> CreateBox() const;
|
||||||
|
|
||||||
|
uint8_t version() const { return version_; }
|
||||||
|
const std::vector<uint8_t>& system_id() const { return system_id_; }
|
||||||
|
const std::vector<std::vector<uint8_t>>& key_ids() const { return key_ids_; }
|
||||||
|
const std::vector<uint8_t>& pssh_data() const { return pssh_data_; }
|
||||||
|
|
||||||
|
void set_version(uint8_t version) {
|
||||||
|
DCHECK_LT(version, 2);
|
||||||
|
version_ = version;
|
||||||
|
}
|
||||||
|
void set_system_id(const std::vector<uint8_t>& system_id) {
|
||||||
|
DCHECK_EQ(16u, system_id.size());
|
||||||
|
system_id_ = system_id;
|
||||||
|
}
|
||||||
|
void add_key_id(const std::vector<uint8_t>& key_id) {
|
||||||
|
DCHECK_EQ(16u, key_id.size());
|
||||||
|
key_ids_.push_back(key_id);
|
||||||
|
}
|
||||||
|
void clear_key_ids() { key_ids_.clear(); }
|
||||||
|
void set_pssh_data(const std::vector<uint8_t>& pssh_data) {
|
||||||
|
pssh_data_ = pssh_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t version_;
|
||||||
|
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
|
||||||
|
} // namespace edash_packager
|
||||||
|
|
||||||
|
#endif // MEDIA_BASE_PSSH_H_
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file or at
|
||||||
|
// https://developers.google.com/open-source/licenses/bsd
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "packager/base/macros.h"
|
||||||
|
#include "packager/media/base/protection_system_specific_info.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const uint8_t kV0BoxArray[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x21, 'p', 's', 's', 'h', // Header
|
||||||
|
0x00, 0x00, 0x00, 0x00, // Version = 0, flags = 0
|
||||||
|
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, // System ID
|
||||||
|
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
||||||
|
0x00, 0x00, 0x00, 0x01, // Data size(1)
|
||||||
|
0xFF
|
||||||
|
};
|
||||||
|
const uint8_t kV1BoxArray[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x35, 'p', 's', 's', 'h', // Header
|
||||||
|
0x01, 0x00, 0x00, 0x00, // Version = 1, flags = 0
|
||||||
|
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, // System ID
|
||||||
|
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
||||||
|
0x00, 0x00, 0x00, 0x01, // KID_count(1)
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // First KID
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, // Data size(1)
|
||||||
|
0xFF
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t kTestSystemIdArray[] = {
|
||||||
|
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, // System ID
|
||||||
|
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
||||||
|
};
|
||||||
|
const uint8_t kTestKeyIdArray[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // First KID
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
const uint8_t kTestPsshDataArray[] = {0xFF};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class PsshTest : public ::testing::Test {
|
||||||
|
public:
|
||||||
|
PsshTest()
|
||||||
|
: v0_box_(kV0BoxArray, kV0BoxArray + arraysize(kV0BoxArray)),
|
||||||
|
v1_box_(kV1BoxArray, kV1BoxArray + arraysize(kV1BoxArray)),
|
||||||
|
test_system_id_(kTestSystemIdArray,
|
||||||
|
kTestSystemIdArray + arraysize(kTestSystemIdArray)),
|
||||||
|
test_key_id_(kTestKeyIdArray,
|
||||||
|
kTestKeyIdArray + arraysize(kTestKeyIdArray)),
|
||||||
|
test_pssh_data_(kTestPsshDataArray,
|
||||||
|
kTestPsshDataArray + arraysize(kTestPsshDataArray)) {}
|
||||||
|
|
||||||
|
const std::vector<uint8_t> v0_box_;
|
||||||
|
const std::vector<uint8_t> v1_box_;
|
||||||
|
const std::vector<uint8_t> test_system_id_;
|
||||||
|
const std::vector<uint8_t> test_key_id_;
|
||||||
|
const std::vector<uint8_t> test_pssh_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
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].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].version());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
data.insert(data.end(), v1_box_.begin(), v1_box_.end());
|
||||||
|
data.insert(data.end(), v0_box_.begin(), v0_box_.end());
|
||||||
|
data.insert(data.end(), v1_box_.begin(), v1_box_.end());
|
||||||
|
|
||||||
|
std::vector<ProtectionSystemSpecificInfo> 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].version());
|
||||||
|
|
||||||
|
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].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].version());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PsshTest, CreateBox_MakesV0Boxes) {
|
||||||
|
ProtectionSystemSpecificInfo info;
|
||||||
|
info.set_system_id(test_system_id_);
|
||||||
|
info.set_pssh_data(test_pssh_data_);
|
||||||
|
info.set_version(0);
|
||||||
|
|
||||||
|
EXPECT_EQ(v0_box_, info.CreateBox());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PsshTest, CreateBox_MakesV1Boxes) {
|
||||||
|
ProtectionSystemSpecificInfo info;
|
||||||
|
info.add_key_id(test_key_id_);
|
||||||
|
info.set_system_id(test_system_id_);
|
||||||
|
info.set_pssh_data(test_pssh_data_);
|
||||||
|
info.set_version(1);
|
||||||
|
|
||||||
|
EXPECT_EQ(v1_box_, info.CreateBox());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
|
@ -158,35 +158,20 @@ ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {}
|
||||||
FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; }
|
FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; }
|
||||||
|
|
||||||
bool ProtectionSystemSpecificHeader::ReadWriteInternal(BoxBuffer* buffer) {
|
bool ProtectionSystemSpecificHeader::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
if (!buffer->Reading() && !raw_box.empty()) {
|
|
||||||
// Write the raw box directly.
|
|
||||||
buffer->writer()->AppendVector(raw_box);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t size = data.size();
|
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer) &&
|
|
||||||
buffer->ReadWriteVector(&system_id, 16) &&
|
|
||||||
buffer->ReadWriteUInt32(&size) &&
|
|
||||||
buffer->ReadWriteVector(&data, size));
|
|
||||||
|
|
||||||
if (buffer->Reading()) {
|
if (buffer->Reading()) {
|
||||||
// Copy the entire box, including the header, for passing to EME as
|
|
||||||
// initData.
|
|
||||||
DCHECK(raw_box.empty());
|
|
||||||
BoxReader* reader = buffer->reader();
|
BoxReader* reader = buffer->reader();
|
||||||
DCHECK(reader);
|
DCHECK(reader);
|
||||||
raw_box.assign(reader->data(), reader->data() + reader->size());
|
raw_box.assign(reader->data(), reader->data() + reader->size());
|
||||||
|
} else {
|
||||||
|
DCHECK(!raw_box.empty());
|
||||||
|
buffer->writer()->AppendVector(raw_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ProtectionSystemSpecificHeader::ComputeSizeInternal() {
|
uint32_t ProtectionSystemSpecificHeader::ComputeSizeInternal() {
|
||||||
if (!raw_box.empty()) {
|
|
||||||
return raw_box.size();
|
return raw_box.size();
|
||||||
} else {
|
|
||||||
return HeaderSize() + system_id.size() + sizeof(uint32_t) + data.size();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
|
SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
|
||||||
|
|
|
@ -57,8 +57,6 @@ struct SegmentType : FileType {
|
||||||
struct ProtectionSystemSpecificHeader : FullBox {
|
struct ProtectionSystemSpecificHeader : FullBox {
|
||||||
DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader);
|
DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader);
|
||||||
|
|
||||||
std::vector<uint8_t> system_id;
|
|
||||||
std::vector<uint8_t> data;
|
|
||||||
std::vector<uint8_t> raw_box;
|
std::vector<uint8_t> raw_box;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ inline bool operator==(const FileType& lhs, const FileType& rhs) {
|
||||||
|
|
||||||
inline bool operator==(const ProtectionSystemSpecificHeader& lhs,
|
inline bool operator==(const ProtectionSystemSpecificHeader& lhs,
|
||||||
const ProtectionSystemSpecificHeader& rhs) {
|
const ProtectionSystemSpecificHeader& rhs) {
|
||||||
return lhs.system_id == rhs.system_id && lhs.data == rhs.data;
|
return lhs.raw_box == rhs.raw_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator==(const SampleAuxiliaryInformationOffset& lhs,
|
inline bool operator==(const SampleAuxiliaryInformationOffset& lhs,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "packager/base/memory/scoped_ptr.h"
|
#include "packager/base/memory/scoped_ptr.h"
|
||||||
|
#include "packager/media/base/protection_system_specific_info.h"
|
||||||
#include "packager/media/base/buffer_writer.h"
|
#include "packager/media/base/buffer_writer.h"
|
||||||
#include "packager/media/formats/mp4/box_definitions.h"
|
#include "packager/media/formats/mp4/box_definitions.h"
|
||||||
#include "packager/media/formats/mp4/box_definitions_comparison.h"
|
#include "packager/media/formats/mp4/box_definitions_comparison.h"
|
||||||
|
@ -25,6 +26,9 @@ const uint8_t kData8[] = {1, 8, 42, 98, 156};
|
||||||
const uint16_t kData16[] = {1, 15, 45, 768, 60000};
|
const uint16_t kData16[] = {1, 15, 45, 768, 60000};
|
||||||
const uint32_t kData32[] = {1, 24, 99, 1234, 9000000};
|
const uint32_t kData32[] = {1, 24, 99, 1234, 9000000};
|
||||||
const uint64_t kData64[] = {1, 9000000, 12345678901234ULL, 56780909090900ULL};
|
const uint64_t kData64[] = {1, 9000000, 12345678901234ULL, 56780909090900ULL};
|
||||||
|
const uint8_t kPsshBox[] = {0, 0, 0, 0x22, 'p', 's', 's', 'h', 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 2, 0xf0, 0x00};
|
||||||
const TrackType kSampleDescriptionTrackType = kVideo;
|
const TrackType kSampleDescriptionTrackType = kVideo;
|
||||||
|
|
||||||
// 4-byte FourCC + 4-bytes size.
|
// 4-byte FourCC + 4-bytes size.
|
||||||
|
@ -143,14 +147,11 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fill(ProtectionSystemSpecificHeader* pssh) {
|
void Fill(ProtectionSystemSpecificHeader* pssh) {
|
||||||
pssh->system_id.assign(kData16Bytes,
|
pssh->raw_box.assign(kPsshBox, kPsshBox + arraysize(kPsshBox));
|
||||||
kData16Bytes + arraysize(kData16Bytes));
|
|
||||||
pssh->data.assign(kData8, kData8 + arraysize(kData8));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Modify(ProtectionSystemSpecificHeader* pssh) {
|
void Modify(ProtectionSystemSpecificHeader* pssh) {
|
||||||
pssh->system_id[2] *= 3;
|
pssh->raw_box[32] *= 3;
|
||||||
pssh->data.assign(kData4, kData4 + arraysize(kData4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fill(SampleAuxiliaryInformationOffset* saio) {
|
void Fill(SampleAuxiliaryInformationOffset* saio) {
|
||||||
|
@ -918,6 +919,7 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
||||||
bool IsOptional(const AC3Specific* box) { return true; }
|
bool IsOptional(const AC3Specific* box) { return true; }
|
||||||
bool IsOptional(const EC3Specific* box) { return true; }
|
bool IsOptional(const EC3Specific* box) { return true; }
|
||||||
// Recommended, but optional.
|
// Recommended, but optional.
|
||||||
|
bool IsOptional(const ProtectionSystemSpecificHeader* box) { return true; }
|
||||||
bool IsOptional(const WebVTTSourceLabelBox* box) { return true; }
|
bool IsOptional(const WebVTTSourceLabelBox* box) { return true; }
|
||||||
bool IsOptional(const CompositionTimeToSample* box) { return true; }
|
bool IsOptional(const CompositionTimeToSample* box) { return true; }
|
||||||
bool IsOptional(const SyncSample* box) { return true; }
|
bool IsOptional(const SyncSample* box) { return true; }
|
||||||
|
@ -1136,26 +1138,6 @@ TEST_F(BoxDefinitionsTest, EC3SampleEntry) {
|
||||||
ASSERT_EQ(entry, entry_readback);
|
ASSERT_EQ(entry, entry_readback);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoxDefinitionsTest, ProtectionSystemSpecificHeader) {
|
|
||||||
ProtectionSystemSpecificHeader pssh;
|
|
||||||
Fill(&pssh);
|
|
||||||
pssh.Write(this->buffer_.get());
|
|
||||||
|
|
||||||
ProtectionSystemSpecificHeader pssh_readback;
|
|
||||||
ASSERT_TRUE(ReadBack(&pssh_readback));
|
|
||||||
ASSERT_EQ(pssh, pssh_readback);
|
|
||||||
|
|
||||||
pssh_readback.raw_box[15] += 1;
|
|
||||||
pssh_readback.Write(this->buffer_.get());
|
|
||||||
|
|
||||||
ProtectionSystemSpecificHeader pssh_readback2;
|
|
||||||
ASSERT_TRUE(ReadBack(&pssh_readback2));
|
|
||||||
|
|
||||||
// If raw_box is set, raw_box will be written instead.
|
|
||||||
ASSERT_FALSE(pssh_readback == pssh_readback2);
|
|
||||||
ASSERT_EQ(pssh_readback.raw_box, pssh_readback2.raw_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(BoxDefinitionsTest, CompactSampleSize_FieldSize16) {
|
TEST_F(BoxDefinitionsTest, CompactSampleSize_FieldSize16) {
|
||||||
CompactSampleSize stz2;
|
CompactSampleSize stz2;
|
||||||
stz2.field_size = 16;
|
stz2.field_size = 16;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "packager/media/base/key_source.h"
|
#include "packager/media/base/key_source.h"
|
||||||
#include "packager/media/base/macros.h"
|
#include "packager/media/base/macros.h"
|
||||||
#include "packager/media/base/media_sample.h"
|
#include "packager/media/base/media_sample.h"
|
||||||
|
#include "packager/media/base/protection_system_specific_info.h"
|
||||||
#include "packager/media/base/video_stream_info.h"
|
#include "packager/media/base/video_stream_info.h"
|
||||||
#include "packager/media/file/file.h"
|
#include "packager/media/file/file.h"
|
||||||
#include "packager/media/file/file_closer.h"
|
#include "packager/media/file/file_closer.h"
|
||||||
|
@ -584,8 +585,10 @@ bool MP4MediaParser::FetchKeysIfNecessary(
|
||||||
base::HexStringToBytes(kWidevineKeySystemId, &widevine_system_id);
|
base::HexStringToBytes(kWidevineKeySystemId, &widevine_system_id);
|
||||||
for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
|
for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
|
||||||
headers.begin(); iter != headers.end(); ++iter) {
|
headers.begin(); iter != headers.end(); ++iter) {
|
||||||
if (iter->system_id == widevine_system_id) {
|
ProtectionSystemSpecificInfo info;
|
||||||
Status status = decryption_key_source_->FetchKeys(iter->data);
|
RCHECK(info.Parse(iter->raw_box.data(), iter->raw_box.size()));
|
||||||
|
if (info.system_id() == widevine_system_id) {
|
||||||
|
Status status = decryption_key_source_->FetchKeys(info.pssh_data());
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
LOG(ERROR) << "Error fetching decryption keys: " << status;
|
LOG(ERROR) << "Error fetching decryption keys: " << status;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -24,7 +24,6 @@ namespace mp4 {
|
||||||
class Segmenter;
|
class Segmenter;
|
||||||
|
|
||||||
struct ProtectionSchemeInfo;
|
struct ProtectionSchemeInfo;
|
||||||
struct ProtectionSystemSpecificHeader;
|
|
||||||
struct Track;
|
struct Track;
|
||||||
|
|
||||||
/// Implements MP4 Muxer for ISO-BMFF. Please refer to ISO/IEC 14496-12: ISO
|
/// Implements MP4 Muxer for ISO-BMFF. Please refer to ISO/IEC 14496-12: ISO
|
||||||
|
|
Loading…
Reference in New Issue