Bug 1318792 - Adds support for sbgp and sgpd boxes occuring in the sampletable r?cpearce draft
authorJay Harris <jharris@mozilla.com>
Wed, 25 Jan 2017 11:35:16 +1300
changeset 466487 bd527345f5fd82b4c0feb0f47bf390ae8560f306
parent 466477 93a0a039791bf2690f8e7998b44d2e6a99d3eec7
child 466488 ff10217195d2338cbc258ff02c1cfad10b46c826
child 466930 264d838d7ad65aee37b027d20d1e087221631680
child 467010 eeb365a175d2d7aae47dbcf2f65cb304b85f1e1d
push id42917
push userbmo:jharris@mozilla.com
push dateThu, 26 Jan 2017 01:15:25 +0000
reviewerscpearce
bugs1318792
milestone53.0a1
Bug 1318792 - Adds support for sbgp and sgpd boxes occuring in the sampletable r?cpearce MozReview-Commit-ID: AWroyPEf4rD
dom/media/fmp4/MP4Demuxer.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -351,22 +351,25 @@ MP4TrackDemuxer::GetNextSample()
           // We could reject the sample now, however demuxer errors are fatal.
           // So we keep the invalid frame, relying on the H264 decoder to
           // handle the error later.
           // TODO: make demuxer errors non-fatal.
           break;
       }
     }
   }
+
   if (sample->mCrypto.mValid) {
     nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
     writer->mCrypto.mMode = mInfo->mCrypto.mMode;
-    writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
 
+    // Only use the default key parsed from the moov if we haven't already got
+    // one from the sample group description.
     if (writer->mCrypto.mKeyId.Length() == 0) {
+      writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize;
       writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId);
     }
   }
   return sample.forget();
 }
 
 RefPtr<MP4TrackDemuxer::SamplesPromise>
 MP4TrackDemuxer::GetSamples(int32_t aNumSamples)
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -136,16 +136,17 @@ already_AddRefed<MediaRawData> SampleIte
     ByteReader reader(cenc);
     writer->mCrypto.mValid = true;
     writer->mCrypto.mIVSize = ivSize;
 
     nsTArray<uint8_t> keyIdArray;
 
     CencSampleEncryptionInfoEntry* sampleInfo = GetSampleEncryptionEntry();
     if (sampleInfo) {
+      writer->mCrypto.mIVSize = sampleInfo->mIVSize;
       keyIdArray.AppendElements(sampleInfo->mKeyId);
     }
 
     writer->mCrypto.mKeyId = keyIdArray;
 
     if (!reader.ReadArray(writer->mCrypto.mIV, ivSize)) {
       return nullptr;
     }
@@ -174,50 +175,66 @@ already_AddRefed<MediaRawData> SampleIte
 }
 
 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
+    ? &currentMoof->mFragmentSampleToGroupEntries
+    : &mIndex->mMoofParser->mTrackSampleToGroupEntries;
+
   uint32_t seen = 0;
 
-  for (uint32_t i = 0; i < currentMoof->mSampleToGroupEntries.Length(); ++i) {
-    SampleToGroupEntry* entry = &currentMoof->mSampleToGroupEntries.ElementAt(i);
+  for (uint32_t i = 0; i < sampleToGroupEntries->Length(); ++i) {
+    SampleToGroupEntry* entry = &sampleToGroupEntries->ElementAt(i);
     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;
   }
 
-  uint32_t group_index = sampleToGroupEntry->mGroupDescriptionIndex;
+  nsTArray<CencSampleEncryptionInfoEntry>* entries = &mIndex->mMoofParser->mTrackSampleEncryptionInfoEntries;
+
+  uint32_t groupIndex = sampleToGroupEntry->mGroupDescriptionIndex;
 
-  if (group_index > SampleToGroupEntry::kFragmentGroupDescriptionIndexBase) {
-    group_index -= SampleToGroupEntry::kFragmentGroupDescriptionIndexBase;
+  // 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 = &currentMoof->mFragmentSampleEncryptionInfoEntries;
   }
 
-  // The group_index is one indexed
-  return group_index > currentMoof->mSampleEncryptionInfoEntries.Length()
+  // The group_index is one based.
+  return groupIndex > entries->Length()
     ? nullptr
-    : &currentMoof->mSampleEncryptionInfoEntries.ElementAt(group_index - 1);
+    : &entries->ElementAt(groupIndex - 1);
 }
 
 Sample* SampleIterator::Get()
 {
   if (!mIndex->mMoofParser) {
     MOZ_ASSERT(!mCurrentMoof);
     return mCurrentSample < mIndex->mIndex.Length()
       ? &mIndex->mIndex[mCurrentSample]
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -312,16 +312,28 @@ MoofParser::ParseMinf(Box& aBox)
 }
 
 void
 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.mGroupingType == "seig") {
+        mTrackSampleEncryptionInfoEntries.Clear();
+        mTrackSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
+      }
+    } else if (box.IsType("sbgp")) {
+      Sbgp sbgp(box);
+      if (sbgp.mGroupingType == "seig") {
+        mTrackSampleToGroupEntries.Clear();
+        mTrackSampleToGroupEntries.AppendElements(sbgp.mEntries);
+      }
     }
   }
 }
 
 void
 MoofParser::ParseStsd(Box& aBox)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
@@ -477,33 +489,34 @@ Moof::ProcessCenc()
 }
 
 void
 Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
 {
   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.mGroupingType == "seig") {
-          mSampleEncryptionInfoEntries.Clear();
-          mSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
+          mFragmentSampleEncryptionInfoEntries.Clear();
+          mFragmentSampleEncryptionInfoEntries.AppendElements(sgpd.mEntries);
         }
       } else if (box.IsType("sbgp")) {
         Sbgp sbgp(box);
         if (sbgp.mGroupingType == "seig") {
-          mSampleToGroupEntries.Clear();
-          mSampleToGroupEntries.AppendElements(sbgp.mEntries);
+          mFragmentSampleToGroupEntries.Clear();
+          mFragmentSampleToGroupEntries.AppendElements(sbgp.mEntries);
         }
       } else if (box.IsType("saiz")) {
         mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType));
       } else if (box.IsType("saio")) {
         mSaios.AppendElement(Saio(box, aSinf.mDefaultEncryptionType));
       }
     }
   }
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -222,18 +222,18 @@ public:
   bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
   void FixRounding(const Moof& aMoof);
 
   mozilla::MediaByteRange mRange;
   mozilla::MediaByteRange mMdatRange;
   Interval<Microseconds> mTimeRange;
   FallibleTArray<Sample> mIndex;
 
-  nsTArray<CencSampleEncryptionInfoEntry> mSampleEncryptionInfoEntries;
-  nsTArray<SampleToGroupEntry> mSampleToGroupEntries;
+  nsTArray<CencSampleEncryptionInfoEntry> mFragmentSampleEncryptionInfoEntries;
+  nsTArray<SampleToGroupEntry> mFragmentSampleToGroupEntries;
 
   nsTArray<Saiz> mSaizs;
   nsTArray<Saio> mSaios;
 
 private:
     // aDecodeTime is updated to the end of the parsed TRAF on return.
   void ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio);
   // aDecodeTime is updated to the end of the parsed TRUN on return.
@@ -285,16 +285,20 @@ public:
   uint64_t mOffset;
   nsTArray<uint64_t> mMoofOffsets;
   Mvhd mMvhd;
   Mdhd mMdhd;
   Trex mTrex;
   Tfdt mTfdt;
   Edts mEdts;
   Sinf mSinf;
+
+  nsTArray<CencSampleEncryptionInfoEntry> mTrackSampleEncryptionInfoEntries;
+  nsTArray<SampleToGroupEntry> mTrackSampleToGroupEntries;
+
   nsTArray<Moof>& Moofs() { return mMoofs; }
 private:
   void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
                        mozilla::MediaByteRange& aMoov);
   nsTArray<Moof> mMoofs;
   nsTArray<MediaByteRange> mMediaRanges;
   bool mIsAudio;
   uint64_t mLastDecodeTime;