mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-22 23:27:30 +09:00
[EME] Add support for sbgp and sgpd boxes in the traf box
This commit is contained in:
parent
6789cce7a5
commit
1ce79cb51e
5 changed files with 258 additions and 1 deletions
|
|
@ -350,7 +350,12 @@ MP4TrackDemuxer::GetNextSample()
|
||||||
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
|
||||||
writer->mCrypto.mMode = mInfo->mCrypto.mMode;
|
writer->mCrypto.mMode = mInfo->mCrypto.mMode;
|
||||||
writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
|
writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
|
||||||
writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
|
|
||||||
|
// The length of the key will be zero if no key was specified in the sample
|
||||||
|
// information, meaning we should fall back to the default key.
|
||||||
|
if (writer->mCrypto.mKeyId.Length() == 0) {
|
||||||
|
writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sample.forget();
|
return sample.forget();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,11 @@ already_AddRefed<MediaRawData> SampleIterator::GetNext()
|
||||||
writer->mCrypto.mValid = true;
|
writer->mCrypto.mValid = true;
|
||||||
writer->mCrypto.mIVSize = ivSize;
|
writer->mCrypto.mIVSize = ivSize;
|
||||||
|
|
||||||
|
CencSampleEncryptionInfoEntry* sampleInfo = GetSampleEncryptionEntry();
|
||||||
|
if (sampleInfo) {
|
||||||
|
writer->mCrypto.mKeyId.AppendElements(sampleInfo->mKeyId);
|
||||||
|
}
|
||||||
|
|
||||||
if (!reader.ReadArray(writer->mCrypto.mIV, ivSize)) {
|
if (!reader.ReadArray(writer->mCrypto.mIV, ivSize)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -170,6 +175,47 @@ already_AddRefed<MediaRawData> SampleIterator::GetNext()
|
||||||
return sample.forget();
|
return sample.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CencSampleEncryptionInfoEntry* SampleIterator::GetSampleEncryptionEntry()
|
||||||
|
{
|
||||||
|
nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs();
|
||||||
|
Moof* currentMoof = &moofs[mCurrentMoof];
|
||||||
|
SampleToGroupEntry* sampleToGroupEntry = nullptr;
|
||||||
|
|
||||||
|
uint32_t seen = 0;
|
||||||
|
|
||||||
|
for (SampleToGroupEntry& entry : currentMoof->mSampleToGroupEntries) {
|
||||||
|
if (seen + entry.mSampleCount > mCurrentSample) {
|
||||||
|
sampleToGroupEntry = &entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seen += entry.mSampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ISO-14496-12 Section 8.9.2.3 and 8.9.4 : group description index
|
||||||
|
// (1) ranges from 1 to the number of sample group entries in the track
|
||||||
|
// level SampleGroupDescription Box, or (2) takes the value 0 to
|
||||||
|
// indicate that this sample is a member of no group, in this case, the
|
||||||
|
// sample is associated with the default values specified in
|
||||||
|
// TrackEncryption Box, or (3) starts at 0x10001, i.e. the index value
|
||||||
|
// 1, with the value 1 in the top 16 bits, to reference fragment-local
|
||||||
|
// SampleGroupDescription Box.
|
||||||
|
|
||||||
|
if (!sampleToGroupEntry || sampleToGroupEntry->mGroupDescriptionIndex == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t group_index = sampleToGroupEntry->mGroupDescriptionIndex;
|
||||||
|
|
||||||
|
if (group_index > SampleToGroupEntry::kFragmentGroupDescriptionIndexBase) {
|
||||||
|
group_index -= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The group_index is one indexed
|
||||||
|
return group_index > currentMoof->mSampleEncryptionInfoEntries.Length()
|
||||||
|
? nullptr
|
||||||
|
: ¤tMoof->mSampleEncryptionInfoEntries.ElementAt(group_index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
Sample* SampleIterator::Get()
|
Sample* SampleIterator::Get()
|
||||||
{
|
{
|
||||||
if (!mIndex->mMoofParser) {
|
if (!mIndex->mMoofParser) {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ namespace mp4_demuxer
|
||||||
using namespace stagefright;
|
using namespace stagefright;
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
|
const uint32_t kKeyIdSize = 16;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MoofParser::RebuildFragmentedIndex(const MediaByteRangeSet& aByteRanges)
|
MoofParser::RebuildFragmentedIndex(const MediaByteRangeSet& aByteRanges)
|
||||||
{
|
{
|
||||||
|
|
@ -501,6 +503,18 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, S
|
||||||
} else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
|
} else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
|
||||||
if (box.IsType("tfdt")) {
|
if (box.IsType("tfdt")) {
|
||||||
tfdt = Tfdt(box);
|
tfdt = Tfdt(box);
|
||||||
|
} else if (box.IsType("sgpd")) {
|
||||||
|
Sgpd sgpd(box);
|
||||||
|
if (sgpd.IsValid() && sgpd.mGroupingType == "seig") {
|
||||||
|
mSampleEncryptionInfoEntries.Clear();
|
||||||
|
mSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
|
||||||
|
}
|
||||||
|
} else if (box.IsType("sbgp")) {
|
||||||
|
Sbgp sbgp(box);
|
||||||
|
if (sbgp.IsValid() && sbgp.mGroupingType == "seig") {
|
||||||
|
mSampleToGroupEntries.Clear();
|
||||||
|
mSampleToGroupEntries.AppendElements(sbgp.mEntries);
|
||||||
|
}
|
||||||
} else if (box.IsType("saiz")) {
|
} else if (box.IsType("saiz")) {
|
||||||
mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType));
|
mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType));
|
||||||
} else if (box.IsType("saio")) {
|
} else if (box.IsType("saio")) {
|
||||||
|
|
@ -1050,5 +1064,143 @@ Saio::Saio(Box& aBox, AtomType aDefaultType)
|
||||||
mValid = true;
|
mValid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sbgp::Sbgp(Box& aBox)
|
||||||
|
{
|
||||||
|
BoxReader reader(aBox);
|
||||||
|
|
||||||
|
if (!reader->CanReadType<uint32_t>()) {
|
||||||
|
LOG(Sbgp, "Incomplete Box (missing flags)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = reader->ReadU32();
|
||||||
|
const uint8_t version = flags >> 24;
|
||||||
|
flags = flags & 0xffffff;
|
||||||
|
|
||||||
|
// Make sure we have enough bytes to read as far as the count.
|
||||||
|
uint32_t need = (version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
|
||||||
|
if (reader->Remaining() < need) {
|
||||||
|
LOG(Sbgp, "Incomplete Box (have:%lld, need:%lld)",
|
||||||
|
(uint64_t)reader->Remaining(), (uint64_t)need);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGroupingType = reader->ReadU32();
|
||||||
|
|
||||||
|
if (version == 1) {
|
||||||
|
mGroupingTypeParam = reader->Read32();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count = reader->ReadU32();
|
||||||
|
|
||||||
|
// Make sure we can read all the entries.
|
||||||
|
need = sizeof(uint32_t) * 2 * count;
|
||||||
|
if (reader->Remaining() < need) {
|
||||||
|
LOG(Sbgp, "Incomplete Box (have:%lld, need:%lld). Failed to read entries",
|
||||||
|
(uint64_t)reader->Remaining(), (uint64_t)need);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
uint32_t sampleCount = reader->ReadU32();
|
||||||
|
uint32_t groupDescriptionIndex = reader->ReadU32();
|
||||||
|
|
||||||
|
SampleToGroupEntry entry(sampleCount, groupDescriptionIndex);
|
||||||
|
mEntries.AppendElement(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
mValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sgpd::Sgpd(Box& aBox)
|
||||||
|
{
|
||||||
|
BoxReader reader(aBox);
|
||||||
|
|
||||||
|
if (!reader->CanReadType<uint32_t>()) {
|
||||||
|
LOG(Sgpd, "Incomplete Box (missing flags)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t flags = reader->ReadU32();
|
||||||
|
const uint8_t version = flags >> 24;
|
||||||
|
flags = flags & 0xffffff;
|
||||||
|
|
||||||
|
uint32_t need = ((flags & 1) ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
|
||||||
|
if (reader->Remaining() < need) {
|
||||||
|
LOG(Sgpd, "Incomplete Box (have:%lld need:%lld)",
|
||||||
|
(uint64_t)reader->Remaining(), (uint64_t)need);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGroupingType = reader->ReadU32();
|
||||||
|
|
||||||
|
const uint32_t entrySize = sizeof(uint32_t) + kKeyIdSize;
|
||||||
|
uint32_t defaultLength = 0;
|
||||||
|
|
||||||
|
if (version == 1) {
|
||||||
|
defaultLength = reader->ReadU32();
|
||||||
|
if (defaultLength < entrySize && defaultLength != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count = reader->ReadU32();
|
||||||
|
|
||||||
|
// Make sure we have sufficient remaining bytes to read the entries.
|
||||||
|
need =
|
||||||
|
count * (sizeof(uint32_t) * (version == 1 && defaultLength == 0 ? 2 : 1) +
|
||||||
|
kKeyIdSize * sizeof(uint8_t));
|
||||||
|
if (reader->Remaining() < need) {
|
||||||
|
LOG(Sgpd, "Incomplete Box (have:%lld need:%lld). Failed to read entries",
|
||||||
|
(uint64_t)reader->Remaining(), (uint64_t)need);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
if (version == 1 && defaultLength == 0) {
|
||||||
|
uint32_t descriptionLength = reader->ReadU32();
|
||||||
|
if (descriptionLength < entrySize) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CencSampleEncryptionInfoEntry entry;
|
||||||
|
bool valid = entry.Init(reader);
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mEntries.AppendElement(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
mValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CencSampleEncryptionInfoEntry::Init(BoxReader& aReader)
|
||||||
|
{
|
||||||
|
// Skip a reserved byte.
|
||||||
|
aReader->ReadU8();
|
||||||
|
|
||||||
|
uint8_t possiblePatternInfo = aReader->ReadU8();
|
||||||
|
uint8_t flag = aReader->ReadU8();
|
||||||
|
|
||||||
|
mIVSize = aReader->ReadU8();
|
||||||
|
|
||||||
|
// Read the key id.
|
||||||
|
for (uint32_t i = 0; i < kKeyIdSize; ++i) {
|
||||||
|
mKeyId.AppendElement(aReader->ReadU8());
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsEncrypted = flag != 0;
|
||||||
|
|
||||||
|
if (mIsEncrypted) {
|
||||||
|
if (mIVSize != 8 && mIVSize != 16) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (mIVSize != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#undef LOG
|
#undef LOG
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,9 @@ public:
|
||||||
Microseconds GetNextKeyframeTime();
|
Microseconds GetNextKeyframeTime();
|
||||||
private:
|
private:
|
||||||
Sample* Get();
|
Sample* Get();
|
||||||
|
|
||||||
|
CencSampleEncryptionInfoEntry* GetSampleEncryptionEntry();
|
||||||
|
|
||||||
void Next();
|
void Next();
|
||||||
RefPtr<Index> mIndex;
|
RefPtr<Index> mIndex;
|
||||||
friend class Index;
|
friend class Index;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ typedef int64_t Microseconds;
|
||||||
|
|
||||||
class Box;
|
class Box;
|
||||||
class BoxContext;
|
class BoxContext;
|
||||||
|
class BoxReader;
|
||||||
class Moof;
|
class Moof;
|
||||||
|
|
||||||
class Mvhd : public Atom
|
class Mvhd : public Atom
|
||||||
|
|
@ -160,6 +161,53 @@ public:
|
||||||
FallibleTArray<uint64_t> mOffsets;
|
FallibleTArray<uint64_t> mOffsets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SampleToGroupEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const uint32_t kTrackGroupDescriptionIndexBase = 0;
|
||||||
|
static const uint32_t kFragmentGroupDescriptionIndexBase = 0x10000;
|
||||||
|
|
||||||
|
SampleToGroupEntry(uint32_t aSampleCount, uint32_t aGroupDescriptionIndex)
|
||||||
|
: mSampleCount(aSampleCount)
|
||||||
|
, mGroupDescriptionIndex(aGroupDescriptionIndex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mSampleCount;
|
||||||
|
uint32_t mGroupDescriptionIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sbgp final : public Atom // SampleToGroup box.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Sbgp(Box& aBox);
|
||||||
|
|
||||||
|
AtomType mGroupingType;
|
||||||
|
uint32_t mGroupingTypeParam;
|
||||||
|
nsTArray<SampleToGroupEntry> mEntries;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CencSampleEncryptionInfoEntry final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CencSampleEncryptionInfoEntry() { }
|
||||||
|
|
||||||
|
bool Init(BoxReader& aReader);
|
||||||
|
|
||||||
|
bool mIsEncrypted = false;
|
||||||
|
uint8_t mIVSize = 0;
|
||||||
|
nsTArray<uint8_t> mKeyId;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sgpd final : public Atom // SampleGroupDescription box.
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Sgpd(Box& aBox);
|
||||||
|
|
||||||
|
AtomType mGroupingType;
|
||||||
|
nsTArray<CencSampleEncryptionInfoEntry> mEntries;
|
||||||
|
};
|
||||||
|
|
||||||
class AuxInfo {
|
class AuxInfo {
|
||||||
public:
|
public:
|
||||||
AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio);
|
AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio);
|
||||||
|
|
@ -182,6 +230,9 @@ public:
|
||||||
Interval<Microseconds> mTimeRange;
|
Interval<Microseconds> mTimeRange;
|
||||||
FallibleTArray<Sample> mIndex;
|
FallibleTArray<Sample> mIndex;
|
||||||
|
|
||||||
|
nsTArray<CencSampleEncryptionInfoEntry> mSampleEncryptionInfoEntries;
|
||||||
|
nsTArray<SampleToGroupEntry> mSampleToGroupEntries;
|
||||||
|
|
||||||
nsTArray<Saiz> mSaizs;
|
nsTArray<Saiz> mSaizs;
|
||||||
nsTArray<Saio> mSaios;
|
nsTArray<Saio> mSaios;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue