Define SampleEncryption 'senc' box
Issue #41 Change-Id: Ib28c079209f3a58ecd8d7b86d720a1c8c774b669
This commit is contained in:
parent
814d2414e3
commit
0c870b7c02
|
@ -13,7 +13,7 @@ namespace edash_packager {
|
|||
namespace media {
|
||||
namespace mp4 {
|
||||
|
||||
Box::Box() : atom_size(0) {}
|
||||
Box::Box() : box_size_(0) {}
|
||||
Box::~Box() {}
|
||||
|
||||
bool Box::Parse(BoxReader* reader) {
|
||||
|
@ -24,21 +24,21 @@ bool Box::Parse(BoxReader* reader) {
|
|||
|
||||
void Box::Write(BufferWriter* writer) {
|
||||
DCHECK(writer);
|
||||
// Compute and update atom_size.
|
||||
// Compute and update box size.
|
||||
uint32_t size = ComputeSize();
|
||||
DCHECK_EQ(size, this->atom_size);
|
||||
DCHECK_EQ(size, box_size_);
|
||||
|
||||
size_t buffer_size_before_write = writer->Size();
|
||||
BoxBuffer buffer(writer);
|
||||
CHECK(ReadWriteInternal(&buffer));
|
||||
DCHECK_EQ(this->atom_size, writer->Size() - buffer_size_before_write);
|
||||
DCHECK_EQ(box_size_, writer->Size() - buffer_size_before_write);
|
||||
}
|
||||
|
||||
void Box::WriteHeader(BufferWriter* writer) {
|
||||
DCHECK(writer);
|
||||
// Compute and update atom_size.
|
||||
// Compute and update box size.
|
||||
uint32_t size = ComputeSize();
|
||||
DCHECK_EQ(size, this->atom_size);
|
||||
DCHECK_EQ(size, box_size_);
|
||||
|
||||
size_t buffer_size_before_write = writer->Size();
|
||||
BoxBuffer buffer(writer);
|
||||
|
@ -47,8 +47,8 @@ void Box::WriteHeader(BufferWriter* writer) {
|
|||
}
|
||||
|
||||
uint32_t Box::ComputeSize() {
|
||||
this->atom_size = ComputeSizeInternal();
|
||||
return this->atom_size;
|
||||
box_size_ = ComputeSizeInternal();
|
||||
return box_size_;
|
||||
}
|
||||
|
||||
uint32_t Box::HeaderSize() const {
|
||||
|
@ -61,7 +61,7 @@ bool Box::ReadWriteHeaderInternal(BoxBuffer* buffer) {
|
|||
if (buffer->Reading()) {
|
||||
// Skip for read mode, which is handled already in BoxReader.
|
||||
} else {
|
||||
CHECK(buffer->ReadWriteUInt32(&this->atom_size));
|
||||
CHECK(buffer->ReadWriteUInt32(&box_size_));
|
||||
FourCC fourcc = BoxType();
|
||||
CHECK(buffer->ReadWriteFourCC(&fourcc));
|
||||
}
|
||||
|
|
|
@ -50,24 +50,28 @@ struct Box {
|
|||
/// @return box type.
|
||||
virtual FourCC BoxType() const = 0;
|
||||
|
||||
/// @return The size of result box including child boxes. Note that this
|
||||
// function expects that ComputeSize has been invoked already.
|
||||
uint32_t box_size() { return box_size_; }
|
||||
|
||||
protected:
|
||||
/// Read/write mp4 box header. Note that this function expects box size
|
||||
/// updated already.
|
||||
/// Read/write mp4 box header. Note that this function expects that
|
||||
/// ComputeSize has been invoked already.
|
||||
/// @return true on success, false otherwise.
|
||||
virtual bool ReadWriteHeaderInternal(BoxBuffer* buffer);
|
||||
|
||||
private:
|
||||
friend class BoxBuffer;
|
||||
// Read/write the mp4 box from/to BoxBuffer. Note that this function expects
|
||||
// box size updated already.
|
||||
// that ComputeSize has been invoked already.
|
||||
virtual bool ReadWriteInternal(BoxBuffer* buffer) = 0;
|
||||
// Compute the size of this box. A value of 0 should be returned if the box
|
||||
// should not be written. Note that this function won't update box size.
|
||||
virtual uint32_t ComputeSizeInternal() = 0;
|
||||
|
||||
// We don't support 64-bit atom sizes. 32-bit should be large enough for our
|
||||
// We don't support 64-bit box sizes. 32-bit should be large enough for our
|
||||
// current needs.
|
||||
uint32_t atom_size;
|
||||
uint32_t box_size_;
|
||||
|
||||
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
|
||||
// generated copy constructor and assignment operator.
|
||||
|
|
|
@ -167,7 +167,7 @@ class BoxBuffer {
|
|||
if (reader_)
|
||||
return reader_->ReadChild(box);
|
||||
// The box is mandatory, i.e. the box size should not be 0.
|
||||
DCHECK_NE(0u, box->atom_size);
|
||||
DCHECK_NE(0u, box->box_size());
|
||||
CHECK(box->ReadWriteInternal(this));
|
||||
return true;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ class BoxBuffer {
|
|||
if (reader_)
|
||||
return reader_->TryReadChild(box);
|
||||
// The box is optional, i.e. it can be skipped if the box size is 0.
|
||||
if (box->atom_size != 0)
|
||||
if (box->box_size() != 0)
|
||||
CHECK(box->ReadWriteInternal(this));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,12 @@ const char kVpcCompressorName[] = "\012VPC Coding";
|
|||
// at once.
|
||||
const int kCueSourceIdNotSet = -1;
|
||||
|
||||
// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
|
||||
// 64-bit (8-byte) or 128-bit (16-byte).
|
||||
bool IsIvSizeValid(size_t iv_size) {
|
||||
return iv_size == 8 || iv_size == 16;
|
||||
}
|
||||
|
||||
// Utility functions to check if the 64bit integers can fit in 32bit integer.
|
||||
bool IsFitIn32Bits(uint64_t a) {
|
||||
return a <= std::numeric_limits<uint32_t>::max();
|
||||
|
@ -183,6 +189,143 @@ uint32_t SampleAuxiliaryInformationSize::ComputeSizeInternal() {
|
|||
(default_sample_info_size == 0 ? sample_info_sizes.size() : 0);
|
||||
}
|
||||
|
||||
SampleEncryptionEntry::SampleEncryptionEntry() {}
|
||||
SampleEncryptionEntry::~SampleEncryptionEntry() {}
|
||||
|
||||
bool SampleEncryptionEntry::ReadWrite(uint8_t iv_size,
|
||||
bool has_subsamples,
|
||||
BoxBuffer* buffer) {
|
||||
DCHECK(IsIvSizeValid(iv_size));
|
||||
DCHECK(buffer);
|
||||
|
||||
RCHECK(buffer->ReadWriteVector(&initialization_vector, iv_size));
|
||||
|
||||
if (!has_subsamples) {
|
||||
subsamples.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t subsample_count = subsamples.size();
|
||||
RCHECK(buffer->ReadWriteUInt16(&subsample_count));
|
||||
RCHECK(subsample_count > 0);
|
||||
subsamples.resize(subsample_count);
|
||||
for (auto& subsample : subsamples) {
|
||||
RCHECK(buffer->ReadWriteUInt16(&subsample.clear_bytes) &&
|
||||
buffer->ReadWriteUInt32(&subsample.cipher_bytes));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SampleEncryptionEntry::ParseFromBuffer(uint8_t iv_size,
|
||||
bool has_subsamples,
|
||||
BufferReader* reader) {
|
||||
DCHECK(IsIvSizeValid(iv_size));
|
||||
DCHECK(reader);
|
||||
|
||||
initialization_vector.resize(iv_size);
|
||||
RCHECK(reader->ReadToVector(&initialization_vector, iv_size));
|
||||
|
||||
if (!has_subsamples) {
|
||||
subsamples.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t subsample_count;
|
||||
RCHECK(reader->Read2(&subsample_count));
|
||||
RCHECK(subsample_count > 0);
|
||||
subsamples.resize(subsample_count);
|
||||
for (auto& subsample : subsamples) {
|
||||
RCHECK(reader->Read2(&subsample.clear_bytes) &&
|
||||
reader->Read4(&subsample.cipher_bytes));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t SampleEncryptionEntry::ComputeSize() const {
|
||||
const uint32_t subsample_entry_size = sizeof(uint16_t) + sizeof(uint32_t);
|
||||
const uint16_t subsample_count = subsamples.size();
|
||||
return initialization_vector.size() +
|
||||
(subsample_count > 0 ? (sizeof(subsample_count) +
|
||||
subsample_entry_size * subsample_count)
|
||||
: 0);
|
||||
}
|
||||
|
||||
uint32_t SampleEncryptionEntry::GetTotalSizeOfSubsamples() const {
|
||||
uint32_t size = 0;
|
||||
for (uint32_t i = 0; i < subsamples.size(); ++i)
|
||||
size += subsamples[i].clear_bytes + subsamples[i].cipher_bytes;
|
||||
return size;
|
||||
}
|
||||
|
||||
SampleEncryption::SampleEncryption() : iv_size(0) {}
|
||||
SampleEncryption::~SampleEncryption() {}
|
||||
FourCC SampleEncryption::BoxType() const { return FOURCC_SENC; }
|
||||
|
||||
bool SampleEncryption::ReadWriteInternal(BoxBuffer* buffer) {
|
||||
RCHECK(ReadWriteHeaderInternal(buffer));
|
||||
|
||||
// If we don't know |iv_size|, store sample encryption data to parse later
|
||||
// after we know iv_size.
|
||||
if (buffer->Reading() && iv_size == 0) {
|
||||
RCHECK(buffer->ReadWriteVector(&sample_encryption_data,
|
||||
buffer->Size() - buffer->Pos()));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IsIvSizeValid(iv_size)) {
|
||||
LOG(ERROR) << "IV_size can only be 8 or 16, but seeing " << iv_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t sample_count = sample_encryption_entries.size();
|
||||
RCHECK(buffer->ReadWriteUInt32(&sample_count));
|
||||
|
||||
sample_encryption_entries.resize(sample_count);
|
||||
for (auto& sample_encryption_entry : sample_encryption_entries) {
|
||||
RCHECK(sample_encryption_entry.ReadWrite(
|
||||
iv_size, flags & kUseSubsampleEncryption, buffer));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t SampleEncryption::ComputeSizeInternal() {
|
||||
const uint32_t sample_count = sample_encryption_entries.size();
|
||||
if (sample_count == 0) {
|
||||
// Sample encryption box is optional. Skip it if it is empty.
|
||||
return 0;
|
||||
}
|
||||
|
||||
DCHECK(IsIvSizeValid(iv_size));
|
||||
uint32_t box_size = HeaderSize() + sizeof(sample_count);
|
||||
if (flags & kUseSubsampleEncryption) {
|
||||
for (const SampleEncryptionEntry& sample_encryption_entry :
|
||||
sample_encryption_entries) {
|
||||
box_size += sample_encryption_entry.ComputeSize();
|
||||
}
|
||||
} else {
|
||||
box_size += sample_count * iv_size;
|
||||
}
|
||||
return box_size;
|
||||
}
|
||||
|
||||
bool SampleEncryption::ParseFromSampleEncryptionData(
|
||||
size_t iv_size,
|
||||
std::vector<SampleEncryptionEntry>* sample_encryption_entries) const {
|
||||
DCHECK(IsIvSizeValid(iv_size));
|
||||
|
||||
BufferReader reader(vector_as_array(&sample_encryption_data),
|
||||
sample_encryption_data.size());
|
||||
uint32_t sample_count = 0;
|
||||
RCHECK(reader.Read4(&sample_count));
|
||||
|
||||
sample_encryption_entries->resize(sample_count);
|
||||
for (auto& sample_encryption_entry : *sample_encryption_entries) {
|
||||
RCHECK(sample_encryption_entry.ParseFromBuffer(
|
||||
iv_size, flags & kUseSubsampleEncryption, &reader));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
OriginalFormat::OriginalFormat() : format(FOURCC_NULL) {}
|
||||
OriginalFormat::~OriginalFormat() {}
|
||||
FourCC OriginalFormat::BoxType() const { return FOURCC_FRMA; }
|
||||
|
@ -1440,7 +1583,8 @@ bool Track::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
buffer->PrepareChildren() &&
|
||||
buffer->ReadWriteChild(&header) &&
|
||||
buffer->ReadWriteChild(&media) &&
|
||||
buffer->TryReadWriteChild(&edit));
|
||||
buffer->TryReadWriteChild(&edit) &&
|
||||
buffer->TryReadWriteChild(&sample_encryption));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1921,14 +2065,16 @@ bool TrackFragment::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
buffer->TryReadWriteChild(&sample_group_description));
|
||||
}
|
||||
return buffer->TryReadWriteChild(&auxiliary_size) &&
|
||||
buffer->TryReadWriteChild(&auxiliary_offset);
|
||||
buffer->TryReadWriteChild(&auxiliary_offset) &&
|
||||
buffer->TryReadWriteChild(&sample_encryption);
|
||||
}
|
||||
|
||||
uint32_t TrackFragment::ComputeSizeInternal() {
|
||||
uint32_t box_size =
|
||||
HeaderSize() + header.ComputeSize() + decode_time.ComputeSize() +
|
||||
sample_to_group.ComputeSize() + sample_group_description.ComputeSize() +
|
||||
auxiliary_size.ComputeSize() + auxiliary_offset.ComputeSize();
|
||||
auxiliary_size.ComputeSize() + auxiliary_offset.ComputeSize() +
|
||||
sample_encryption.ComputeSize();
|
||||
for (uint32_t i = 0; i < runs.size(); ++i)
|
||||
box_size += runs[i].ComputeSize();
|
||||
return box_size;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include "packager/media/base/decrypt_config.h"
|
||||
#include "packager/media/formats/mp4/aac_audio_specific_config.h"
|
||||
#include "packager/media/formats/mp4/box.h"
|
||||
#include "packager/media/formats/mp4/es_descriptor.h"
|
||||
|
@ -75,6 +76,60 @@ struct SampleAuxiliaryInformationSize : FullBox {
|
|||
std::vector<uint8_t> sample_info_sizes;
|
||||
};
|
||||
|
||||
struct SampleEncryptionEntry {
|
||||
SampleEncryptionEntry();
|
||||
~SampleEncryptionEntry();
|
||||
/// Read/Write SampleEncryptionEntry.
|
||||
/// @param iv_size specifies the size of initialization vector.
|
||||
/// @param has_subsamples indicates whether this sample encryption entry
|
||||
/// constains subsamples.
|
||||
/// @param buffer points to the box buffer for reading or writing.
|
||||
/// @return true on success, false otherwise.
|
||||
bool ReadWrite(uint8_t iv_size,
|
||||
bool has_subsamples,
|
||||
BoxBuffer* buffer);
|
||||
/// Parse SampleEncryptionEntry from buffer.
|
||||
/// @param iv_size specifies the size of initialization vector.
|
||||
/// @param has_subsamples indicates whether this sample encryption entry
|
||||
/// constains subsamples.
|
||||
/// @param reader points to the buffer reader. Cannot be NULL.
|
||||
/// @return true on success, false otherwise.
|
||||
bool ParseFromBuffer(uint8_t iv_size,
|
||||
bool has_subsamples,
|
||||
BufferReader* reader);
|
||||
/// @return The size of the structure in bytes when it is stored.
|
||||
uint32_t ComputeSize() const;
|
||||
/// @return The accumulated size of subsamples. Returns 0 if there is no
|
||||
/// subsamples.
|
||||
uint32_t GetTotalSizeOfSubsamples() const;
|
||||
|
||||
std::vector<uint8_t> initialization_vector;
|
||||
std::vector<SubsampleEntry> subsamples;
|
||||
};
|
||||
|
||||
struct SampleEncryption : FullBox {
|
||||
enum SampleEncryptionFlags {
|
||||
kUseSubsampleEncryption = 2,
|
||||
};
|
||||
|
||||
DECLARE_BOX_METHODS(SampleEncryption);
|
||||
/// Parse from @a sample_encryption_data.
|
||||
/// @param iv_size specifies the size of initialization vector.
|
||||
/// @param[out] sample_encryption_entries receives parsed sample encryption
|
||||
/// entries.
|
||||
/// @return true on success, false otherwise.
|
||||
bool ParseFromSampleEncryptionData(
|
||||
size_t iv_size,
|
||||
std::vector<SampleEncryptionEntry>* sample_encryption_entries) const;
|
||||
|
||||
/// We may not know @a iv_size before reading this box. In this case, we will
|
||||
/// store sample encryption data for parsing later when @a iv_size is known.
|
||||
std::vector<uint8_t> sample_encryption_data;
|
||||
|
||||
size_t iv_size;
|
||||
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
||||
};
|
||||
|
||||
struct OriginalFormat : Box {
|
||||
DECLARE_BOX_METHODS(OriginalFormat);
|
||||
|
||||
|
@ -258,6 +313,8 @@ struct SampleDescription : FullBox {
|
|||
DECLARE_BOX_METHODS(SampleDescription);
|
||||
|
||||
TrackType type;
|
||||
// TODO(kqyang): Clean up the code to have one single member, e.g. by creating
|
||||
// SampleEntry struct, std::vector<SampleEntry> sample_entries.
|
||||
std::vector<VideoSampleEntry> video_entries;
|
||||
std::vector<AudioSampleEntry> audio_entries;
|
||||
std::vector<WVTTSampleEntry> wvtt_entries;
|
||||
|
@ -428,6 +485,7 @@ struct Track : Box {
|
|||
TrackHeader header;
|
||||
Media media;
|
||||
Edit edit;
|
||||
SampleEncryption sample_encryption;
|
||||
};
|
||||
|
||||
struct MovieExtendsHeader : FullBox {
|
||||
|
@ -569,6 +627,7 @@ struct TrackFragment : Box {
|
|||
SampleGroupDescription sample_group_description;
|
||||
SampleAuxiliaryInformationSize auxiliary_size;
|
||||
SampleAuxiliaryInformationOffset auxiliary_offset;
|
||||
SampleEncryption sample_encryption;
|
||||
};
|
||||
|
||||
struct MovieFragment : Box {
|
||||
|
|
|
@ -13,6 +13,12 @@
|
|||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
inline bool operator==(const SubsampleEntry& lhs, const SubsampleEntry& rhs) {
|
||||
return lhs.clear_bytes == rhs.clear_bytes &&
|
||||
lhs.cipher_bytes == rhs.cipher_bytes;
|
||||
}
|
||||
|
||||
namespace mp4 {
|
||||
|
||||
inline bool operator==(const FileType& lhs, const FileType& rhs) {
|
||||
|
@ -38,6 +44,18 @@ inline bool operator==(const SampleAuxiliaryInformationSize& lhs,
|
|||
lhs.sample_info_sizes == rhs.sample_info_sizes;
|
||||
}
|
||||
|
||||
inline bool operator==(const SampleEncryptionEntry& lhs,
|
||||
const SampleEncryptionEntry& rhs) {
|
||||
return lhs.initialization_vector == rhs.initialization_vector &&
|
||||
lhs.subsamples == rhs.subsamples;
|
||||
}
|
||||
|
||||
inline bool operator==(const SampleEncryption& lhs,
|
||||
const SampleEncryption& rhs) {
|
||||
return lhs.iv_size == rhs.iv_size &&
|
||||
lhs.sample_encryption_entries == rhs.sample_encryption_entries;
|
||||
}
|
||||
|
||||
inline bool operator==(const OriginalFormat& lhs, const OriginalFormat& rhs) {
|
||||
return lhs.format == rhs.format;
|
||||
}
|
||||
|
@ -274,7 +292,7 @@ inline bool operator==(const Media& lhs, const Media& rhs) {
|
|||
|
||||
inline bool operator==(const Track& lhs, const Track& rhs) {
|
||||
return lhs.header == rhs.header && lhs.media == rhs.media &&
|
||||
lhs.edit == rhs.edit;
|
||||
lhs.edit == rhs.edit && lhs.sample_encryption == rhs.sample_encryption;
|
||||
}
|
||||
|
||||
inline bool operator==(const MovieExtendsHeader& lhs,
|
||||
|
@ -360,7 +378,8 @@ inline bool operator==(const TrackFragment& lhs, const TrackFragment& rhs) {
|
|||
return lhs.header == rhs.header && lhs.runs == rhs.runs &&
|
||||
lhs.decode_time == rhs.decode_time &&
|
||||
lhs.auxiliary_offset == rhs.auxiliary_offset &&
|
||||
lhs.auxiliary_size == rhs.auxiliary_size;
|
||||
lhs.auxiliary_size == rhs.auxiliary_size &&
|
||||
lhs.sample_encryption == rhs.sample_encryption;
|
||||
}
|
||||
|
||||
inline bool operator==(const MovieFragment& lhs, const MovieFragment& rhs) {
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace edash_packager {
|
|||
namespace media {
|
||||
namespace mp4 {
|
||||
namespace {
|
||||
const uint8_t kData8Bytes[] = {3, 4, 5, 6, 7, 8, 9, 0};
|
||||
const uint8_t kData16Bytes[] = {8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const uint8_t kData4[] = {1, 5, 4, 3, 15};
|
||||
const uint8_t kData8[] = {1, 8, 42, 98, 156};
|
||||
|
@ -161,6 +162,30 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
|||
saiz->sample_info_sizes.clear();
|
||||
}
|
||||
|
||||
void Fill(SampleEncryption* senc) {
|
||||
senc->iv_size = 8;
|
||||
senc->flags = SampleEncryption::kUseSubsampleEncryption;
|
||||
senc->sample_encryption_entries.resize(2);
|
||||
senc->sample_encryption_entries[0].initialization_vector.assign(
|
||||
kData8Bytes, kData8Bytes + arraysize(kData8Bytes));
|
||||
senc->sample_encryption_entries[0].subsamples.resize(2);
|
||||
senc->sample_encryption_entries[0].subsamples[0].clear_bytes = 17;
|
||||
senc->sample_encryption_entries[0].subsamples[0].cipher_bytes = 3456;
|
||||
senc->sample_encryption_entries[0].subsamples[1].clear_bytes = 1543;
|
||||
senc->sample_encryption_entries[0].subsamples[1].cipher_bytes = 0;
|
||||
senc->sample_encryption_entries[1] = senc->sample_encryption_entries[0];
|
||||
senc->sample_encryption_entries[1].subsamples[0].clear_bytes = 0;
|
||||
senc->sample_encryption_entries[1].subsamples[0].cipher_bytes = 15;
|
||||
senc->sample_encryption_entries[1].subsamples[1].clear_bytes = 1988;
|
||||
senc->sample_encryption_entries[1].subsamples[1].cipher_bytes = 8765;
|
||||
}
|
||||
|
||||
void Modify(SampleEncryption* senc) {
|
||||
senc->flags = 0;
|
||||
senc->sample_encryption_entries.resize(1);
|
||||
senc->sample_encryption_entries[0].subsamples.clear();
|
||||
}
|
||||
|
||||
void Fill(OriginalFormat* frma) { frma->format = FOURCC_AVC1; }
|
||||
|
||||
void Modify(OriginalFormat* frma) { frma->format = FOURCC_MP4A; }
|
||||
|
@ -817,6 +842,7 @@ class BoxDefinitionsTestGeneral : public testing::Test {
|
|||
|
||||
bool IsOptional(const SampleAuxiliaryInformationOffset* box) { return true; }
|
||||
bool IsOptional(const SampleAuxiliaryInformationSize* box) { return true; }
|
||||
bool IsOptional(const SampleEncryption* box) { return true; }
|
||||
bool IsOptional(const ProtectionSchemeInfo* box) { return true; }
|
||||
bool IsOptional(const EditList* box) { return true; }
|
||||
bool IsOptional(const Edit* box) { return true; }
|
||||
|
@ -1066,6 +1092,48 @@ TEST_F(BoxDefinitionsTest, TrackFragmentRun_NoSampleSize) {
|
|||
ASSERT_EQ(trun, trun_readback);
|
||||
}
|
||||
|
||||
TEST_F(BoxDefinitionsTest, SampleEncryptionIsOptional) {
|
||||
SampleEncryption senc;
|
||||
EXPECT_EQ(0u, senc.ComputeSize());
|
||||
}
|
||||
|
||||
TEST_F(BoxDefinitionsTest, SampleEncryptionWithIvKnownWhenReading) {
|
||||
SampleEncryption senc;
|
||||
Fill(&senc);
|
||||
senc.Write(buffer_.get());
|
||||
|
||||
SampleEncryption senc_readback;
|
||||
senc_readback.iv_size = senc.iv_size;
|
||||
|
||||
ASSERT_TRUE(ReadBack(&senc_readback));
|
||||
EXPECT_EQ(0u, senc_readback.sample_encryption_data.size());
|
||||
EXPECT_NE(0u, senc_readback.sample_encryption_entries.size());
|
||||
ASSERT_EQ(senc, senc_readback);
|
||||
|
||||
Modify(&senc);
|
||||
senc.Write(buffer_.get());
|
||||
ASSERT_TRUE(ReadBack(&senc_readback));
|
||||
ASSERT_EQ(senc, senc_readback);
|
||||
}
|
||||
|
||||
TEST_F(BoxDefinitionsTest, SampleEncryptionWithIvUnknownWhenReading) {
|
||||
SampleEncryption senc;
|
||||
Fill(&senc);
|
||||
senc.Write(buffer_.get());
|
||||
|
||||
SampleEncryption senc_readback;
|
||||
senc_readback.iv_size = 0;
|
||||
|
||||
ASSERT_TRUE(ReadBack(&senc_readback));
|
||||
EXPECT_NE(0u, senc_readback.sample_encryption_data.size());
|
||||
EXPECT_EQ(0u, senc_readback.sample_encryption_entries.size());
|
||||
|
||||
std::vector<SampleEncryptionEntry> sample_encryption_entries;
|
||||
ASSERT_TRUE(senc_readback.ParseFromSampleEncryptionData(
|
||||
senc.iv_size, &sample_encryption_entries));
|
||||
ASSERT_EQ(senc.sample_encryption_entries, sample_encryption_entries);
|
||||
}
|
||||
|
||||
} // namespace mp4
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -73,6 +73,7 @@ enum FourCC {
|
|||
FOURCC_SCHM = 0x7363686d,
|
||||
FOURCC_SDTP = 0x73647470,
|
||||
FOURCC_SEIG = 0x73656967,
|
||||
FOURCC_SENC = 0x73656e63,
|
||||
FOURCC_SGPD = 0x73677064,
|
||||
FOURCC_SIDX = 0x73696478,
|
||||
FOURCC_SINF = 0x73696e66,
|
||||
|
|
|
@ -74,8 +74,8 @@ class MP4MediaParser : public MediaParser {
|
|||
uint8_t* buffer,
|
||||
size_t buffer_size);
|
||||
|
||||
// To retain proper framing, each 'mdat' atom must be read; to limit memory
|
||||
// usage, the atom's data needs to be discarded incrementally as frames are
|
||||
// To retain proper framing, each 'mdat' box must be read; to limit memory
|
||||
// usage, the box's data needs to be discarded incrementally as frames are
|
||||
// extracted from the stream. This function discards data from the stream up
|
||||
// to |offset|, updating the |mdat_tail_| value so that framing can be
|
||||
// retained after all 'mdat' information has been read.
|
||||
|
|
|
@ -42,7 +42,7 @@ class MP4Muxer : public Muxer {
|
|||
Status DoAddSample(const MediaStream* stream,
|
||||
scoped_refptr<MediaSample> sample) override;
|
||||
|
||||
// Generate Audio/Video Track atom.
|
||||
// Generate Audio/Video Track box.
|
||||
void InitializeTrak(const StreamInfo* info, Track* trak);
|
||||
void GenerateAudioTrak(const AudioStreamInfo* audio_info,
|
||||
Track* trak,
|
||||
|
|
Loading…
Reference in New Issue