diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2018-08-05 11:35:53 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2018-08-05 11:35:53 +0200 |
commit | 6bd66b1728eeddb058066edda740aaeb2ceaec23 (patch) | |
tree | 985faf01c526763515731569fa01a99f4dbef36e /media | |
parent | e0a8dcfed131ffa58a5e2cb1d30fe48c745c2fdc (diff) | |
parent | 559824514dc95e02fbe81f1786e6ac13ee8e9d55 (diff) | |
download | UXP-6bd66b1728eeddb058066edda740aaeb2ceaec23.tar UXP-6bd66b1728eeddb058066edda740aaeb2ceaec23.tar.gz UXP-6bd66b1728eeddb058066edda740aaeb2ceaec23.tar.lz UXP-6bd66b1728eeddb058066edda740aaeb2ceaec23.tar.xz UXP-6bd66b1728eeddb058066edda740aaeb2ceaec23.zip |
Merge branch 'master' into js-modules
Diffstat (limited to 'media')
10 files changed, 795 insertions, 101 deletions
diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 9d6ab5028..eb039b5d6 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -143,6 +143,11 @@ already_AddRefed<MediaRawData> SampleIterator::GetNext() writer->mCrypto.mValid = true; writer->mCrypto.mIVSize = ivSize; + CencSampleEncryptionInfoEntry* sampleInfo = GetSampleEncryptionEntry(); + if (sampleInfo) { + writer->mCrypto.mKeyId.AppendElements(sampleInfo->mKeyId); + } + if (!reader.ReadArray(writer->mCrypto.mIV, ivSize)) { return nullptr; } @@ -170,6 +175,65 @@ already_AddRefed<MediaRawData> SampleIterator::GetNext() return sample.forget(); } +CencSampleEncryptionInfoEntry* SampleIterator::GetSampleEncryptionEntry() +{ + nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs(); + Moof* currentMoof = &moofs[mCurrentMoof]; + SampleToGroupEntry* sampleToGroupEntry = nullptr; + + // Default to using the sample to group entries for the fragment, otherwise + // fall back to the sample to group entries for the track. + nsTArray<SampleToGroupEntry>* sampleToGroupEntries = + currentMoof->mFragmentSampleToGroupEntries.Length() != 0 + ? ¤tMoof->mFragmentSampleToGroupEntries + : &mIndex->mMoofParser->mTrackSampleToGroupEntries; + + uint32_t seen = 0; + + for (SampleToGroupEntry& entry : *sampleToGroupEntries) { + 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. + + // According to the spec, ISO-14496-12, the sum of the sample counts in this + // box should be equal to the total number of samples, and, if less, the + // reader should behave as if an extra SampleToGroupEntry existed, with + // groupDescriptionIndex 0. + + if (!sampleToGroupEntry || sampleToGroupEntry->mGroupDescriptionIndex == 0) { + return nullptr; + } + + nsTArray<CencSampleEncryptionInfoEntry>* entries = + &mIndex->mMoofParser->mTrackSampleEncryptionInfoEntries; + + uint32_t groupIndex = sampleToGroupEntry->mGroupDescriptionIndex; + + // If the first bit is set to a one, then we should use the sample group + // descriptions from the fragment. + if (groupIndex > SampleToGroupEntry::kFragmentGroupDescriptionIndexBase) { + groupIndex -= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase; + entries = ¤tMoof->mFragmentSampleEncryptionInfoEntries; + } + + // The group_index is one based. + return groupIndex > entries->Length() + ? nullptr + : &entries->ElementAt(groupIndex - 1); +} + Sample* SampleIterator::Get() { if (!mIndex->mMoofParser) { diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index ced054282..771be3428 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -27,6 +27,8 @@ namespace mp4_demuxer using namespace stagefright; using namespace mozilla; +const uint32_t kKeyIdSize = 16; + bool MoofParser::RebuildFragmentedIndex(const MediaByteRangeSet& aByteRanges) { @@ -330,6 +332,18 @@ MoofParser::ParseStbl(Box& aBox) for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("stsd")) { ParseStsd(box); + } else if (box.IsType("sgpd")) { + Sgpd sgpd(box); + if (sgpd.IsValid() && sgpd.mGroupingType == "seig") { + mTrackSampleEncryptionInfoEntries.Clear(); + mTrackSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries); + } + } else if (box.IsType("sbgp")) { + Sbgp sbgp(box); + if (sbgp.IsValid() && sbgp.mGroupingType == "seig") { + mTrackSampleToGroupEntries.Clear(); + mTrackSampleToGroupEntries.AppendElements(sbgp.mEntries); + } } } } @@ -495,12 +509,25 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, S MOZ_ASSERT(aDecodeTime); Tfhd tfhd(aTrex); Tfdt tfdt; + for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("tfhd")) { tfhd = Tfhd(box, aTrex); } else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) { if (box.IsType("tfdt")) { tfdt = Tfdt(box); + } else if (box.IsType("sgpd")) { + Sgpd sgpd(box); + if (sgpd.IsValid() && sgpd.mGroupingType == "seig") { + mFragmentSampleEncryptionInfoEntries.Clear(); + mFragmentSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries); + } + } else if (box.IsType("sbgp")) { + Sbgp sbgp(box); + if (sbgp.IsValid() && sbgp.mGroupingType == "seig") { + mFragmentSampleToGroupEntries.Clear(); + mFragmentSampleToGroupEntries.AppendElements(sbgp.mEntries); + } } else if (box.IsType("saiz")) { mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType)); } else if (box.IsType("saio")) { @@ -550,14 +577,20 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, u LOG(Moof, "Incomplete Box (missing flags)"); return false; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return false; + } uint8_t version = flags >> 24; if (!reader->CanReadType<uint32_t>()) { LOG(Moof, "Incomplete Box (missing sampleCount)"); return false; } - uint32_t sampleCount = reader->ReadU32(); + uint32_t sampleCount; + if (!reader->ReadU32(sampleCount)) { + return false; + } if (sampleCount == 0) { return true; } @@ -577,9 +610,21 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, u return false; } - uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0); - uint32_t firstSampleFlags = - flags & 4 ? reader->ReadU32() : aTfhd.mDefaultSampleFlags; + uint64_t offset = aTfhd.mBaseDataOffset; + if (flags & 1) { + uint32_t baseOffset; + if (!reader->ReadU32(baseOffset)) { + return false; + } + offset += baseOffset; + } + uint32_t firstSampleFlags = aTfhd.mDefaultSampleFlags; + if (flags & 4) { + if (!reader->ReadU32(firstSampleFlags)) { + return false; + } + } + uint64_t decodeTime = *aDecodeTime; nsTArray<Interval<Microseconds>> timeRanges; @@ -589,16 +634,29 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, u } for (size_t i = 0; i < sampleCount; i++) { - uint32_t sampleDuration = - flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration; - uint32_t sampleSize = - flags & 0x200 ? reader->ReadU32() : aTfhd.mDefaultSampleSize; - uint32_t sampleFlags = - flags & 0x400 ? reader->ReadU32() - : i ? aTfhd.mDefaultSampleFlags : firstSampleFlags; + uint32_t sampleDuration = aTfhd.mDefaultSampleDuration; + if (flags & 0x100) { + if (!reader->ReadU32(sampleDuration)) { + return false; + } + } + uint32_t sampleSize = aTfhd.mDefaultSampleSize; + if (flags & 0x200) { + if (!reader->ReadU32(sampleSize)) { + return false; + } + } + uint32_t sampleFlags = i ? aTfhd.mDefaultSampleFlags : firstSampleFlags; + if (flags & 0x400) { + if (!reader->ReadU32(sampleFlags)) { + return false; + } + } int32_t ctsOffset = 0; if (flags & 0x800) { - ctsOffset = reader->Read32(); + if (!reader->Read32(ctsOffset)) { + return false; + } } Sample sample; @@ -635,7 +693,10 @@ Tkhd::Tkhd(Box& aBox) LOG(Tkhd, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; size_t need = 3*(version ? sizeof(int64_t) : sizeof(int32_t)) + 2*sizeof(int32_t); @@ -645,19 +706,30 @@ Tkhd::Tkhd(Box& aBox) return; } if (version == 0) { - mCreationTime = reader->ReadU32(); - mModificationTime = reader->ReadU32(); - mTrackId = reader->ReadU32(); - uint32_t reserved = reader->ReadU32(); + uint32_t createTime, modificationTime, trackId, reserved, duration; + if (!reader->ReadU32(createTime) || + !reader->ReadU32(modificationTime) || + !reader->ReadU32(trackId) || + !reader->ReadU32(reserved) || + !reader->ReadU32(duration)) { + return; + } NS_ASSERTION(!reserved, "reserved should be 0"); - mDuration = reader->ReadU32(); + mCreationTime = createTime; + mModificationTime = modificationTime; + mTrackId = trackId; + mDuration = duration; } else if (version == 1) { - mCreationTime = reader->ReadU64(); - mModificationTime = reader->ReadU64(); - mTrackId = reader->ReadU32(); - uint32_t reserved = reader->ReadU32(); + uint32_t trackId, reserved; + if (!reader->ReadU64(mCreationTime) || + !reader->ReadU64(mModificationTime) || + !reader->ReadU32(trackId) || + !reader->ReadU32(reserved) || + !reader->ReadU64(mDuration)) { + return; + } NS_ASSERTION(!reserved, "reserved should be 0"); - mDuration = reader->ReadU64(); + mTrackId = trackId; } // We don't care about whatever else may be in the box. mValid = true; @@ -670,10 +742,13 @@ Mvhd::Mvhd(Box& aBox) LOG(Mdhd, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; size_t need = - 3*(version ? sizeof(int64_t) : sizeof(int32_t)) + sizeof(uint32_t); + 3 * (version ? sizeof(int64_t) : sizeof(int32_t)) + sizeof(uint32_t); if (reader->Remaining() < need) { LOG(Mvhd, "Incomplete Box (have:%lld need:%lld)", (uint64_t)reader->Remaining(), (uint64_t)need); @@ -681,15 +756,23 @@ Mvhd::Mvhd(Box& aBox) } if (version == 0) { - mCreationTime = reader->ReadU32(); - mModificationTime = reader->ReadU32(); - mTimescale = reader->ReadU32(); - mDuration = reader->ReadU32(); + uint32_t createTime, modificationTime, duration; + if (!reader->ReadU32(createTime) || + !reader->ReadU32(modificationTime) || + !reader->ReadU32(mTimescale) || + !reader->ReadU32(duration)) { + return; + } + mCreationTime = createTime; + mModificationTime = modificationTime; + mDuration = duration; } else if (version == 1) { - mCreationTime = reader->ReadU64(); - mModificationTime = reader->ReadU64(); - mTimescale = reader->ReadU32(); - mDuration = reader->ReadU64(); + if (!reader->ReadU64(mCreationTime) || + !reader->ReadU64(mModificationTime) || + !reader->ReadU32(mTimescale) || + !reader->ReadU64(mDuration)) { + return; + } } else { return; } @@ -707,18 +790,19 @@ Mdhd::Mdhd(Box& aBox) Trex::Trex(Box& aBox) { BoxReader reader(aBox); - if (reader->Remaining() < 6*sizeof(uint32_t)) { + if (reader->Remaining() < 6 * sizeof(uint32_t)) { LOG(Trex, "Incomplete Box (have:%lld need:%lld)", (uint64_t)reader->Remaining(), (uint64_t)6*sizeof(uint32_t)); return; } - mFlags = reader->ReadU32(); - mTrackId = reader->ReadU32(); - mDefaultSampleDescriptionIndex = reader->ReadU32(); - mDefaultSampleDuration = reader->ReadU32(); - mDefaultSampleSize = reader->ReadU32(); - mDefaultSampleFlags = reader->ReadU32(); - mValid = true; + if (!reader->ReadU32(mFlags) || + !reader->ReadU32(mTrackId) || + !reader->ReadU32(mDefaultSampleDescriptionIndex) || + !reader->ReadU32(mDefaultSampleDuration) || + !reader->ReadU32(mDefaultSampleSize) || + !reader->ReadU32(mDefaultSampleFlags)) { + return; + } } Tfhd::Tfhd(Box& aBox, Trex& aTrex) @@ -733,7 +817,9 @@ Tfhd::Tfhd(Box& aBox, Trex& aTrex) LOG(Tfhd, "Incomplete Box (missing flags)"); return; } - mFlags = reader->ReadU32(); + if (!reader->ReadU32(mFlags)) { + return; + } size_t need = sizeof(uint32_t) /* trackid */; uint8_t flag[] = { 1, 2, 8, 0x10, 0x20, 0 }; uint8_t flagSize[] = { sizeof(uint64_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) }; @@ -747,20 +833,34 @@ Tfhd::Tfhd(Box& aBox, Trex& aTrex) (uint64_t)reader->Remaining(), (uint64_t)need); return; } - mTrackId = reader->ReadU32(); - mBaseDataOffset = - mFlags & 1 ? reader->ReadU64() : aBox.Parent()->Parent()->Offset(); + if (!reader->ReadU32(mTrackId)) { + return; + } + mBaseDataOffset = aBox.Parent()->Parent()->Offset(); + if (mFlags & 1) { + if (!reader->ReadU64(mBaseDataOffset)) { + return; + } + } if (mFlags & 2) { - mDefaultSampleDescriptionIndex = reader->ReadU32(); + if (!reader->ReadU32(mDefaultSampleDescriptionIndex)) { + return; + } } if (mFlags & 8) { - mDefaultSampleDuration = reader->ReadU32(); + if (!reader->ReadU32(mDefaultSampleDuration)) { + return; + } } if (mFlags & 0x10) { - mDefaultSampleSize = reader->ReadU32(); + if (!reader->ReadU32(mDefaultSampleSize)) { + return; + } } if (mFlags & 0x20) { - mDefaultSampleFlags = reader->ReadU32(); + if (!reader->ReadU32(mDefaultSampleFlags)) { + return; + } } mValid = true; } @@ -772,7 +872,10 @@ Tfdt::Tfdt(Box& aBox) LOG(Tfdt, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; size_t need = version ? sizeof(uint64_t) : sizeof(uint32_t) ; if (reader->Remaining() < need) { @@ -781,9 +884,15 @@ Tfdt::Tfdt(Box& aBox) return; } if (version == 0) { - mBaseMediaDecodeTime = reader->ReadU32(); + uint32_t baseDecodeTime; + if (!reader->ReadU32(baseDecodeTime)) { + return; + } + mBaseMediaDecodeTime = baseDecodeTime; } else if (version == 1) { - mBaseMediaDecodeTime = reader->ReadU64(); + if (!reader->ReadU64(mBaseMediaDecodeTime)) { + return; + } } mValid = true; } @@ -802,7 +911,10 @@ Edts::Edts(Box& aBox) LOG(Edts, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; size_t need = sizeof(uint32_t) + 2*(version ? sizeof(int64_t) : sizeof(uint32_t)); @@ -812,16 +924,27 @@ Edts::Edts(Box& aBox) return; } bool emptyEntry = false; - uint32_t entryCount = reader->ReadU32(); + uint32_t entryCount; + if (!reader->ReadU32(entryCount)) { + return; + } for (uint32_t i = 0; i < entryCount; i++) { uint64_t segment_duration; int64_t media_time; if (version == 1) { - segment_duration = reader->ReadU64(); - media_time = reader->Read64(); + if (!reader->ReadU64(segment_duration) || + !reader->Read64(media_time)) { + return; + } } else { - segment_duration = reader->ReadU32(); - media_time = reader->Read32(); + uint32_t duration; + int32_t time; + if (!reader->ReadU32(duration) || + !reader->Read32(time)) { + return; + } + segment_duration = duration; + media_time = time; } if (media_time == -1 && i) { LOG(Edts, "Multiple empty edit, not handled"); @@ -834,8 +957,12 @@ Edts::Edts(Box& aBox) } else { mMediaStart = media_time; } - reader->ReadU32(); // media_rate_integer and media_rate_fraction + // media_rate_integer and media_rate_fraction + if (!reader->Skip(4)) { + return; + } } + mValid = true; } Saiz::Saiz(Box& aBox, AtomType aDefaultType) @@ -847,7 +974,10 @@ Saiz::Saiz(Box& aBox, AtomType aDefaultType) LOG(Saiz, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; size_t need = ((flags & 1) ? 2*sizeof(uint32_t) : 0) + sizeof(uint8_t) + sizeof(uint32_t); @@ -857,11 +987,19 @@ Saiz::Saiz(Box& aBox, AtomType aDefaultType) return; } if (flags & 1) { - mAuxInfoType = reader->ReadU32(); - mAuxInfoTypeParameter = reader->ReadU32(); + uint32_t auxType; + if (!reader->ReadU32(auxType) || + !reader->ReadU32(mAuxInfoTypeParameter)) { + return; + } + mAuxInfoType = auxType; + } + uint8_t defaultSampleInfoSize; + uint32_t count; + if (!reader->ReadU8(defaultSampleInfoSize) || + !reader->ReadU32(count)) { + return; } - uint8_t defaultSampleInfoSize = reader->ReadU8(); - uint32_t count = reader->ReadU32(); if (defaultSampleInfoSize) { if (!mSampleInfoSize.SetLength(count, fallible)) { LOG(Saiz, "OOM"); @@ -886,19 +1024,29 @@ Saio::Saio(Box& aBox, AtomType aDefaultType) LOG(Saio, "Incomplete Box (missing flags)"); return; } - uint32_t flags = reader->ReadU32(); + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } uint8_t version = flags >> 24; - size_t need = ((flags & 1) ? (2*sizeof(uint32_t)) : 0) + sizeof(uint32_t); + size_t need = ((flags & 1) ? (2 * sizeof(uint32_t)) : 0) + sizeof(uint32_t); if (reader->Remaining() < need) { LOG(Saio, "Incomplete Box (have:%lld need:%lld)", (uint64_t)reader->Remaining(), (uint64_t)need); return; } if (flags & 1) { - mAuxInfoType = reader->ReadU32(); - mAuxInfoTypeParameter = reader->ReadU32(); + uint32_t auxType; + if (!reader->ReadU32(auxType) || + !reader->ReadU32(mAuxInfoTypeParameter)) { + return; + } + mAuxInfoType = auxType; + } + uint32_t count; + if (!reader->ReadU32(count)) { + return; } - size_t count = reader->ReadU32(); need = (version ? sizeof(uint64_t) : sizeof(uint32_t)) * count; if (reader->Remaining() < need) { LOG(Saio, "Incomplete Box (have:%lld need:%lld)", @@ -910,16 +1058,203 @@ Saio::Saio(Box& aBox, AtomType aDefaultType) return; } if (version == 0) { + uint32_t offset; for (size_t i = 0; i < count; i++) { - MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU32(), fallible)); + if (!reader->ReadU32(offset)) { + return; + } + MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible)); } } else { + uint64_t offset; for (size_t i = 0; i < count; i++) { - MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU64(), fallible)); + if (!reader->ReadU64(offset)) { + return; + } + MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible)); + } + } + mValid = true; +} + +Sbgp::Sbgp(Box& aBox) +{ + BoxReader reader(aBox); + + if (!reader->CanReadType<uint32_t>()) { + LOG(Sbgp, "Incomplete Box (missing flags)"); + return; + } + + uint32_t flags; + if (!reader->ReadU32(flags)) { + return; + } + 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; + } + + uint32_t groupType; + if (!reader->ReadU32(groupType)) { + return; + } + mGroupingType = groupType; + + if (version == 1) { + if (reader->ReadU32(mGroupingTypeParam)) { + false; + } + } + + uint32_t count; + if (!reader->ReadU32(count)) { + return; + } + + // 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; + uint32_t groupDescriptionIndex; + if (!reader->ReadU32(sampleCount) || + !reader->ReadU32(groupDescriptionIndex)) { + return; } + + 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; + if (!reader->ReadU32(flags)) { + return; + } + 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; + } + + uint32_t groupType; + if (!reader->ReadU32(groupType)) { + return; + } + mGroupingType = groupType; + + const uint32_t entrySize = sizeof(uint32_t) + kKeyIdSize; + uint32_t defaultLength = 0; + + if (version == 1) { + if (!reader->ReadU32(defaultLength)) { + return; + } + if (defaultLength < entrySize && defaultLength != 0) { + return; + } + } + + uint32_t count; + if (!reader->ReadU32(count)) { + return; + } + + // 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; + if (!reader->ReadU32(descriptionLength)) { + return; + } + 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. + uint8_t skip; + if (!aReader->ReadU8(skip)) { + return false; + } + + uint8_t possiblePatternInfo; + uint8_t flag; + if (!aReader->ReadU8(possiblePatternInfo) || + !aReader->ReadU8(flag) || + !aReader->ReadU8(mIVSize)) { + return false; + } + + // Read the key id. + uint8_t key; + for (uint32_t i = 0; i < kKeyIdSize; ++i) { + if (!aReader->ReadU8(key)) { + return false; + } + mKeyId.AppendElement(key); + } + + mIsEncrypted = flag != 0; + + if (mIsEncrypted) { + if (mIVSize != 8 && mIVSize != 16) { + return false; + } + } else if (mIVSize != 0) { + return false; + } + + return true; +} + #undef LOG } diff --git a/media/libstagefright/binding/SinfParser.cpp b/media/libstagefright/binding/SinfParser.cpp index 5cf3aa553..5f3a2889e 100644 --- a/media/libstagefright/binding/SinfParser.cpp +++ b/media/libstagefright/binding/SinfParser.cpp @@ -39,8 +39,13 @@ SinfParser::ParseSchm(Box& aBox) return; } - mozilla::Unused << reader->ReadU32(); // flags -- ignore - mSinf.mDefaultEncryptionType = reader->ReadU32(); + uint32_t type; + if (!reader->Skip(4) || + !reader->ReadU32(type)) { + NS_WARNING("Failed to parse schm data"); + return; + } + mSinf.mDefaultEncryptionType = type; } void @@ -62,11 +67,16 @@ SinfParser::ParseTenc(Box& aBox) return; } - mozilla::Unused << reader->ReadU32(); // flags -- ignore - - uint32_t isEncrypted = reader->ReadU24(); - mSinf.mDefaultIVSize = reader->ReadU8(); - memcpy(mSinf.mDefaultKeyID, reader->Read(16), 16); + uint32_t isEncrypted; + const uint8_t* key; + if (!reader->Skip(4) || // flags -- ignore + !reader->ReadU24(isEncrypted) || + !reader->ReadU8(mSinf.mDefaultIVSize) || + !reader->Read(16, &key)) { + NS_WARNING("Failed to parse tenc data"); + return; + } + memcpy(mSinf.mDefaultKeyID, key, 16); } } diff --git a/media/libstagefright/binding/include/mp4_demuxer/Box.h b/media/libstagefright/binding/include/mp4_demuxer/Box.h index f53404a1d..6612f6b49 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Box.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h @@ -12,7 +12,7 @@ #include "MediaResource.h" #include "mozilla/EndianUtils.h" #include "mp4_demuxer/AtomType.h" -#include "mp4_demuxer/ByteReader.h" +#include "mp4_demuxer/BufferReader.h" using namespace mozilla; @@ -73,11 +73,11 @@ public: , mReader(mBuffer.Elements(), mBuffer.Length()) { } - ByteReader* operator->() { return &mReader; } + BufferReader* operator->() { return &mReader; } private: nsTArray<uint8_t> mBuffer; - ByteReader mReader; + BufferReader mReader; }; } diff --git a/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h b/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h new file mode 100644 index 000000000..160c97fa0 --- /dev/null +++ b/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h @@ -0,0 +1,225 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BUFFER_READER_H_ +#define BUFFER_READER_H_ + +#include "mozilla/EndianUtils.h" +#include "mozilla/Vector.h" +#include "nsTArray.h" +#include "MediaData.h" + +namespace mp4_demuxer { + +class MOZ_RAII BufferReader +{ +public: + BufferReader() : mPtr(nullptr), mRemaining(0) {} + explicit BufferReader(const mozilla::Vector<uint8_t>& aData) + : mPtr(aData.begin()), mRemaining(aData.length()), mLength(aData.length()) + { + } + BufferReader(const uint8_t* aData, size_t aSize) + : mPtr(aData), mRemaining(aSize), mLength(aSize) + { + } + template<size_t S> + explicit BufferReader(const AutoTArray<uint8_t, S>& aData) + : mPtr(aData.Elements()), mRemaining(aData.Length()), mLength(aData.Length()) + { + } + explicit BufferReader(const nsTArray<uint8_t>& aData) + : mPtr(aData.Elements()), mRemaining(aData.Length()), mLength(aData.Length()) + { + } + explicit BufferReader(const mozilla::MediaByteBuffer* aData) + : mPtr(aData->Elements()), mRemaining(aData->Length()), mLength(aData->Length()) + { + } + + void SetData(const nsTArray<uint8_t>& aData) + { + MOZ_ASSERT(!mPtr && !mRemaining); + mPtr = aData.Elements(); + mRemaining = aData.Length(); + mLength = mRemaining; + } + + ~BufferReader() + { + } + + size_t Offset() const + { + return mLength - mRemaining; + } + + size_t Remaining() const { return mRemaining; } + + bool CanRead8() const { return mRemaining >= 1; } + + bool ReadU8(uint8_t& aU8) + { + const uint8_t* ptr; + if (!Read(1, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + aU8 = *ptr; + return true; + } + + bool CanRead16() { return mRemaining >= 2; } + + bool ReadU16(uint16_t& u16) + { + const uint8_t* ptr; + if (!Read(2, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + u16 = mozilla::BigEndian::readUint16(ptr); + return true; + } + + bool CanRead32() { return mRemaining >= 4; } + + bool ReadU32(uint32_t& u32) + { + const uint8_t* ptr; + if (!Read(4, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + u32 = mozilla::BigEndian::readUint32(ptr); + return true; + } + + bool Read32(int32_t& i32) + { + const uint8_t* ptr; + if (!Read(4, &ptr)) { + NS_WARNING("Failed to read data"); + return 0; + } + i32 = mozilla::BigEndian::readInt32(ptr); + return true; + } + + bool ReadU64(uint64_t& u64) + { + const uint8_t* ptr; + if (!Read(8, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + u64 = mozilla::BigEndian::readUint64(ptr); + return true; + } + + bool Read64(int64_t& i64) + { + const uint8_t* ptr; + if (!Read(8, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + i64 = mozilla::BigEndian::readInt64(ptr); + return true; + } + + bool ReadU24(uint32_t& u32) + { + const uint8_t* ptr; + if (!Read(3, &ptr)) { + NS_WARNING("Failed to read data"); + return false; + } + u32 = ptr[0] << 16 | ptr[1] << 8 | ptr[2]; + return true; + } + + bool Skip(size_t aCount) + { + const uint8_t* ptr; + if (!Read(aCount, &ptr)) { + NS_WARNING("Failed to skip data"); + return false; + } + return true; + } + + bool Read(size_t aCount, const uint8_t** aPtr) + { + if (aCount > mRemaining) { + mRemaining = 0; + return false; + } + mRemaining -= aCount; + + *aPtr = mPtr; + mPtr += aCount; + + return true; + } + + uint32_t Align() const + { + return 4 - ((intptr_t)mPtr & 3); + } + + template <typename T> bool CanReadType() const { return mRemaining >= sizeof(T); } + + template <typename T> T ReadType() + { + const uint8_t* ptr; + if (!Read(sizeof(T), &ptr)) { + NS_WARNING("ReadType failed"); + return 0; + } + return *reinterpret_cast<const T*>(ptr); + } + + template <typename T> + MOZ_MUST_USE bool ReadArray(nsTArray<T>& aDest, size_t aLength) + { + const uint8_t* ptr; + if (!Read(aLength * sizeof(T), &ptr)) { + NS_WARNING("ReadArray failed"); + return false; + } + + aDest.Clear(); + aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength); + return true; + } + + template <typename T> + MOZ_MUST_USE bool ReadArray(FallibleTArray<T>& aDest, size_t aLength) + { + const uint8_t* ptr; + if (!Read(aLength * sizeof(T), &ptr)) { + NS_WARNING("ReadArray failed"); + return false; + } + + aDest.Clear(); + if (!aDest.SetCapacity(aLength, mozilla::fallible)) { + return false; + } + MOZ_ALWAYS_TRUE(aDest.AppendElements(reinterpret_cast<const T*>(ptr), + aLength, + mozilla::fallible)); + return true; + } + +private: + const uint8_t* mPtr; + size_t mRemaining; + size_t mLength; +}; + +} // namespace mp4_demuxer + +#endif diff --git a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h index 9c7df04bd..f316daa41 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h +++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h @@ -63,7 +63,7 @@ public: { auto ptr = Read(1); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return *ptr; @@ -75,7 +75,7 @@ public: { auto ptr = Read(2); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::BigEndian::readUint16(ptr); @@ -85,7 +85,7 @@ public: { auto ptr = Read(2); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::LittleEndian::readInt16(ptr); @@ -95,7 +95,7 @@ public: { auto ptr = Read(3); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; @@ -110,7 +110,7 @@ public: { auto ptr = Read(3); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]); @@ -126,7 +126,7 @@ public: { auto ptr = Read(4); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::BigEndian::readUint32(ptr); @@ -136,7 +136,7 @@ public: { auto ptr = Read(4); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::BigEndian::readInt32(ptr); @@ -146,7 +146,7 @@ public: { auto ptr = Read(8); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::BigEndian::readUint64(ptr); @@ -156,7 +156,7 @@ public: { auto ptr = Read(8); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to read data"); return 0; } return mozilla::BigEndian::readInt64(ptr); @@ -192,7 +192,7 @@ public: { auto ptr = Peek(1); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return *ptr; @@ -202,7 +202,7 @@ public: { auto ptr = Peek(2); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return mozilla::BigEndian::readUint16(ptr); @@ -212,7 +212,7 @@ public: { auto ptr = Peek(3); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return ptr[0] << 16 | ptr[1] << 8 | ptr[2]; @@ -227,7 +227,7 @@ public: { auto ptr = Peek(4); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return mozilla::BigEndian::readUint32(ptr); @@ -237,7 +237,7 @@ public: { auto ptr = Peek(4); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return mozilla::BigEndian::readInt32(ptr); @@ -247,7 +247,7 @@ public: { auto ptr = Peek(8); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return mozilla::BigEndian::readUint64(ptr); @@ -257,7 +257,7 @@ public: { auto ptr = Peek(8); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("Failed to peek data"); return 0; } return mozilla::BigEndian::readInt64(ptr); @@ -274,7 +274,7 @@ public: const uint8_t* Seek(size_t aOffset) { if (aOffset >= mLength) { - MOZ_ASSERT(false); + NS_WARNING("Seek failed"); return nullptr; } @@ -301,7 +301,7 @@ public: { auto ptr = Read(sizeof(T)); if (!ptr) { - MOZ_ASSERT(false); + NS_WARNING("ReadType failed"); return 0; } return *reinterpret_cast<const T*>(ptr); @@ -312,6 +312,7 @@ public: { auto ptr = Read(aLength * sizeof(T)); if (!ptr) { + NS_WARNING("ReadArray failed"); return false; } @@ -325,6 +326,7 @@ public: { auto ptr = Read(aLength * sizeof(T)); if (!ptr) { + NS_WARNING("ReadArray failed"); return false; } diff --git a/media/libstagefright/binding/include/mp4_demuxer/Index.h b/media/libstagefright/binding/include/mp4_demuxer/Index.h index d566c9459..ca254f73d 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Index.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h @@ -32,6 +32,9 @@ public: Microseconds GetNextKeyframeTime(); private: Sample* Get(); + + CencSampleEncryptionInfoEntry* GetSampleEncryptionEntry(); + void Next(); RefPtr<Index> mIndex; friend class Index; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 814f806fc..bb895555c 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -17,6 +17,7 @@ typedef int64_t Microseconds; class Box; class BoxContext; +class BoxReader; class Moof; class Mvhd : public Atom @@ -160,6 +161,53 @@ public: 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 { public: AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio); @@ -182,6 +230,9 @@ public: Interval<Microseconds> mTimeRange; FallibleTArray<Sample> mIndex; + nsTArray<CencSampleEncryptionInfoEntry> mFragmentSampleEncryptionInfoEntries; + nsTArray<SampleToGroupEntry> mFragmentSampleToGroupEntries; + nsTArray<Saiz> mSaizs; nsTArray<Saio> mSaios; @@ -246,6 +297,10 @@ public: Tfdt mTfdt; Edts mEdts; Sinf mSinf; + + nsTArray<CencSampleEncryptionInfoEntry> mTrackSampleEncryptionInfoEntries; + nsTArray<SampleToGroupEntry> mTrackSampleToGroupEntries; + nsTArray<Moof>& Moofs() { return mMoofs; } private: void ScanForMetadata(mozilla::MediaByteRange& aFtyp, diff --git a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp index e881e0262..5667f04d8 100644 --- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp @@ -753,7 +753,6 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('m', 'o', 'o', 'f'): case FOURCC('t', 'r', 'a', 'f'): case FOURCC('m', 'f', 'r', 'a'): - case FOURCC('u', 'd', 't', 'a'): case FOURCC('i', 'l', 's', 't'): case FOURCC('s', 'i', 'n', 'f'): case FOURCC('s', 'c', 'h', 'i'): diff --git a/media/libstagefright/moz.build b/media/libstagefright/moz.build index c6072d840..5a8c9521a 100644 --- a/media/libstagefright/moz.build +++ b/media/libstagefright/moz.build @@ -53,6 +53,7 @@ EXPORTS.mp4_demuxer += [ 'binding/include/mp4_demuxer/Atom.h', 'binding/include/mp4_demuxer/AtomType.h', 'binding/include/mp4_demuxer/BitReader.h', + 'binding/include/mp4_demuxer/BufferReader.h', 'binding/include/mp4_demuxer/BufferStream.h', 'binding/include/mp4_demuxer/ByteReader.h', 'binding/include/mp4_demuxer/ByteWriter.h', |