Bug 1343461 - add a wrapper class to encapsulate rust/stagefright sample table. r=gerald
authorAlfredo.Yang <ayang@mozilla.com>
Wed, 01 Mar 2017 10:53:49 +0800
changeset 347469 b1c8b28b9fa2a8424db940d4b657eb59b3f01ff3
parent 347468 95c1e899eab6eadae8abc9981dd4dbf4e0ad516d
child 347470 2fcd6a97a1b82a8bdf46113f3e0b9a9e5fc0cf3c
push id31496
push usercbook@mozilla.com
push dateTue, 14 Mar 2017 13:21:57 +0000
treeherdermozilla-central@9a26ed658fdc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1343461
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1343461 - add a wrapper class to encapsulate rust/stagefright sample table. r=gerald MozReview-Commit-ID: 4UgToySaEmb
dom/media/fmp4/MP4Demuxer.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MP4Metadata.cpp
media/libstagefright/binding/include/mp4_demuxer/Index.h
media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
media/libstagefright/gtest/TestParser.cpp
--- a/dom/media/fmp4/MP4Demuxer.cpp
+++ b/dom/media/fmp4/MP4Demuxer.cpp
@@ -32,17 +32,17 @@ mozilla::LogModule* GetDemuxerLog()
 
 namespace mozilla {
 
 class MP4TrackDemuxer : public MediaTrackDemuxer
 {
 public:
   MP4TrackDemuxer(MP4Demuxer* aParent,
                   UniquePtr<TrackInfo>&& aInfo,
-                  const nsTArray<mp4_demuxer::Index::Indice>& indices);
+                  const mp4_demuxer::IndiceWrapper& aIndices);
 
   UniquePtr<TrackInfo> GetInfo() const override;
 
   RefPtr<SeekPromise> Seek(const media::TimeUnit& aTime) override;
 
   RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples = 1) override;
 
   void Reset() override;
@@ -147,33 +147,35 @@ MP4Demuxer::Init()
   }
 
   if (audioTrackCount != 0) {
     mAudioDemuxers.SetLength(audioTrackCount);
     for (size_t i = 0; i < audioTrackCount; i++) {
       UniquePtr<TrackInfo> info =
         metadata.GetTrackInfo(TrackInfo::kAudioTrack, i);
       if (info) {
-        FallibleTArray<mp4_demuxer::Index::Indice> indices;
-        if (metadata.ReadTrackIndex(indices, info->mTrackId)) {
-          mAudioDemuxers[i] = new MP4TrackDemuxer(this, Move(info), indices);
+        UniquePtr<mp4_demuxer::IndiceWrapper> indices =
+          metadata.GetTrackIndice(info->mTrackId);
+        if (indices) {
+          mAudioDemuxers[i] = new MP4TrackDemuxer(this, Move(info), *indices.get());
         }
       }
     }
   }
 
   if (videoTrackCount != 0) {
     mVideoDemuxers.SetLength(videoTrackCount);
     for (size_t i = 0; i < videoTrackCount; i++) {
       UniquePtr<TrackInfo> info =
         metadata.GetTrackInfo(TrackInfo::kVideoTrack, i);
       if (info) {
-        FallibleTArray<mp4_demuxer::Index::Indice> indices;
-        if (metadata.ReadTrackIndex(indices, info->mTrackId)) {
-          mVideoDemuxers[i] = new MP4TrackDemuxer(this, Move(info), indices);
+        UniquePtr<mp4_demuxer::IndiceWrapper> indices =
+          metadata.GetTrackIndice(info->mTrackId);
+        if (indices) {
+          mVideoDemuxers[i] = new MP4TrackDemuxer(this, Move(info), *indices.get());
         }
       }
     }
   }
 
   const mp4_demuxer::CryptoFile& cryptoFile = metadata.Crypto();
   if (cryptoFile.valid) {
     const nsTArray<mp4_demuxer::PsshInfo>& psshs = cryptoFile.pssh;
@@ -258,21 +260,21 @@ MP4Demuxer::GetCrypto()
     crypto.reset(new EncryptionInfo{});
     crypto->AddInitData(NS_LITERAL_STRING("cenc"), mCryptoInitData);
   }
   return crypto;
 }
 
 MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent,
                                  UniquePtr<TrackInfo>&& aInfo,
-                                 const nsTArray<mp4_demuxer::Index::Indice>& indices)
+                                 const mp4_demuxer::IndiceWrapper& aIndices)
   : mParent(aParent)
   , mStream(new mp4_demuxer::ResourceStream(mParent->mResource))
   , mInfo(Move(aInfo))
-  , mIndex(new mp4_demuxer::Index(indices,
+  , mIndex(new mp4_demuxer::Index(aIndices,
                                   mStream,
                                   mInfo->mTrackId,
                                   mInfo->IsAudio()))
   , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex))
   , mNeedReIndex(true)
 {
   EnsureUpToDateIndex(); // Force update of index
 
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -1,15 +1,16 @@
 /* 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/. */
 
 #include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/Index.h"
 #include "mp4_demuxer/Interval.h"
+#include "mp4_demuxer/MP4Metadata.h"
 #include "mp4_demuxer/SinfParser.h"
 #include "nsAutoPtr.h"
 #include "mozilla/RefPtr.h"
 
 #include <algorithm>
 #include <limits>
 
 using namespace stagefright;
@@ -292,37 +293,41 @@ SampleIterator::GetNextKeyframeTime()
     if (sample->mSync) {
       return sample->mCompositionRange.start;
     }
     itr.Next();
   }
   return -1;
 }
 
-Index::Index(const nsTArray<Indice>& aIndex,
+Index::Index(const IndiceWrapper& aIndices,
              Stream* aSource,
              uint32_t aTrackId,
              bool aIsAudio)
   : mSource(aSource)
   , mIsAudio(aIsAudio)
 {
-  if (aIndex.IsEmpty()) {
+  if (!aIndices.Length()) {
     mMoofParser = new MoofParser(aSource, aTrackId, aIsAudio);
   } else {
-    if (!mIndex.SetCapacity(aIndex.Length(), fallible)) {
+    if (!mIndex.SetCapacity(aIndices.Length(), fallible)) {
       // OOM.
       return;
     }
     media::IntervalSet<int64_t> intervalTime;
     MediaByteRange intervalRange;
     bool haveSync = false;
     bool progressive = true;
     int64_t lastOffset = 0;
-    for (size_t i = 0; i < aIndex.Length(); i++) {
-      const Indice& indice = aIndex[i];
+    for (size_t i = 0; i < aIndices.Length(); i++) {
+      Indice indice;
+      if (!aIndices.GetIndice(i, indice)) {
+        // Out of index?
+        return;
+      }
       if (indice.sync || mIsAudio) {
         haveSync = true;
       }
       if (!haveSync) {
         continue;
       }
 
       Sample sample;
@@ -359,18 +364,22 @@ Index::Index(const nsTArray<Indice>& aIn
         intervalRange = MediaByteRange();
       }
       intervalTime += media::Interval<int64_t>(sample.mCompositionRange.start,
                                                sample.mCompositionRange.end);
       intervalRange = intervalRange.Span(sample.mByteRange);
     }
 
     if (mDataOffset.Length() && progressive) {
+      Indice indice;
+      if (!aIndices.GetIndice(aIndices.Length() - 1, indice)) {
+        return;
+      }
       auto& last = mDataOffset.LastElement();
-      last.mEndOffset = aIndex.LastElement().end_offset;
+      last.mEndOffset = indice.end_offset;
       last.mTime = Interval<int64_t>(intervalTime.GetStart(), intervalTime.GetEnd());
     } else {
       mDataOffset.Clear();
     }
   }
 }
 
 Index::~Index() {}
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -141,16 +141,97 @@ private:
   Maybe<uint32_t> TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
 
   CryptoFile mCrypto;
   RefPtr<Stream> mSource;
   RustStreamAdaptor mRustSource;
   mozilla::UniquePtr<mp4parse_parser, FreeMP4Parser> mRustParser;
 };
 
+class IndiceWrapperStagefright : public IndiceWrapper {
+public:
+  size_t Length() const override;
+
+  bool GetIndice(size_t aIndex, Index::Indice& aIndice) const override;
+
+  explicit IndiceWrapperStagefright(FallibleTArray<Index::Indice>& aIndice);
+
+protected:
+  FallibleTArray<Index::Indice> mIndice;
+};
+
+IndiceWrapperStagefright::IndiceWrapperStagefright(FallibleTArray<Index::Indice>& aIndice)
+{
+  mIndice.SwapElements(aIndice);
+}
+
+size_t
+IndiceWrapperStagefright::Length() const
+{
+  return mIndice.Length();
+}
+
+bool
+IndiceWrapperStagefright::GetIndice(size_t aIndex, Index::Indice& aIndice) const
+{
+  if (aIndex >= mIndice.Length()) {
+    MOZ_LOG(sLog, LogLevel::Error, ("Index overflow in indice"));
+    return false;
+  }
+
+  aIndice = mIndice[aIndex];
+  return true;
+}
+
+// the owner of mIndice is rust mp4 paser, so lifetime of this class
+// SHOULD NOT longer than rust parser.
+class IndiceWrapperRust : public IndiceWrapper
+{
+public:
+  size_t Length() const override;
+
+  bool GetIndice(size_t aIndex, Index::Indice& aIndice) const override;
+
+  explicit IndiceWrapperRust(mp4parse_byte_data& aRustIndice);
+
+protected:
+  UniquePtr<mp4parse_byte_data> mIndice;
+};
+
+IndiceWrapperRust::IndiceWrapperRust(mp4parse_byte_data& aRustIndice)
+  : mIndice(mozilla::MakeUnique<mp4parse_byte_data>())
+{
+  mIndice->length = aRustIndice.length;
+  mIndice->indices = aRustIndice.indices;
+}
+
+size_t
+IndiceWrapperRust::Length() const
+{
+  return mIndice->length;
+}
+
+bool
+IndiceWrapperRust::GetIndice(size_t aIndex, Index::Indice& aIndice) const
+{
+  if (aIndex >= mIndice->length) {
+    MOZ_LOG(sLog, LogLevel::Error, ("Index overflow in indice"));
+   return false;
+  }
+
+  const mp4parse_indice* indice = &mIndice->indices[aIndex];
+  aIndice.start_offset = indice->start_offset;
+  aIndice.end_offset = indice->end_offset;
+  aIndice.start_composition = indice->start_composition;
+  aIndice.end_composition = indice->end_composition;
+  aIndice.start_decode = indice->start_decode;
+  aIndice.sync = indice->sync;
+  return true;
+}
+
 MP4Metadata::MP4Metadata(Stream* aSource)
  : mStagefright(MakeUnique<MP4MetadataStagefright>(aSource))
  , mRust(MakeUnique<MP4MetadataRust>(aSource))
  , mPreferRust(false)
  , mReportedAudioTrackTelemetry(false)
  , mReportedVideoTrackTelemetry(false)
 #ifndef RELEASE_OR_BETA
  , mRustTestMode(MediaPrefs::RustTestMode())
@@ -329,39 +410,52 @@ MP4Metadata::Crypto() const
 
   if (mPreferRust) {
     return rustCrypto;
   }
 
   return crypto;
 }
 
-bool
-MP4Metadata::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
+mozilla::UniquePtr<IndiceWrapper>
+MP4Metadata::GetTrackIndice(mozilla::TrackID aTrackID)
 {
-  bool ret = mStagefright->ReadTrackIndex(aDest, aTrackID);
+  FallibleTArray<Index::Indice> indiceSF;
+  if(!mStagefright->ReadTrackIndex(indiceSF, aTrackID)) {
+    return nullptr;
+  }
+
+  mp4parse_byte_data indiceRust = {};
+  if ((mPreferRust || mRustTestMode) &&
+      !mRust->ReadTrackIndice(&indiceRust, aTrackID)) {
+    return nullptr;
+  }
 
 #ifndef RELEASE_OR_BETA
-  if (mRustTestMode && ret && mRust) {
-    mp4parse_byte_data data = {};
-    bool rustRet = mRust->ReadTrackIndice(&data, aTrackID);
-    MOZ_DIAGNOSTIC_ASSERT(rustRet);
-    MOZ_DIAGNOSTIC_ASSERT(data.length == aDest.Length());
-    for (uint32_t i = 0; i < data.length; i++) {
-      MOZ_DIAGNOSTIC_ASSERT(data.indices[i].start_offset == aDest[i].start_offset);
-      MOZ_DIAGNOSTIC_ASSERT(data.indices[i].end_offset == aDest[i].end_offset);
-      MOZ_DIAGNOSTIC_ASSERT(llabs(data.indices[i].start_composition - int64_t(aDest[i].start_composition)) <= 1);
-      MOZ_DIAGNOSTIC_ASSERT(llabs(data.indices[i].end_composition - int64_t(aDest[i].end_composition)) <= 1);
-      MOZ_DIAGNOSTIC_ASSERT(llabs(data.indices[i].start_decode - int64_t(aDest[i].start_decode)) <= 1);
-      MOZ_DIAGNOSTIC_ASSERT(data.indices[i].sync == aDest[i].sync);
+  if (mRustTestMode) {
+    MOZ_DIAGNOSTIC_ASSERT(indiceRust.length == indiceSF.Length());
+    for (uint32_t i = 0; i < indiceRust.length; i++) {
+      MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].start_offset == indiceSF[i].start_offset);
+      MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].end_offset == indiceSF[i].end_offset);
+      MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_composition - int64_t(indiceSF[i].start_composition)) <= 1);
+      MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].end_composition - int64_t(indiceSF[i].end_composition)) <= 1);
+      MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_decode - int64_t(indiceSF[i].start_decode)) <= 1);
+      MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].sync == indiceSF[i].sync);
     }
   }
 #endif
 
-  return ret;
+  UniquePtr<IndiceWrapper> indice;
+  if (mPreferRust) {
+    indice = mozilla::MakeUnique<IndiceWrapperRust>(indiceRust);
+  } else {
+    indice = mozilla::MakeUnique<IndiceWrapperStagefright>(indiceSF);
+  }
+
+  return indice;
 }
 
 static inline bool
 ConvertIndex(FallibleTArray<Index::Indice>& aDest,
              const nsTArray<stagefright::MediaSource::Indice>& aIndex,
              int64_t aMediaTime)
 {
   if (!aDest.SetCapacity(aIndex.Length(), mozilla::fallible)) {
--- a/media/libstagefright/binding/include/mp4_demuxer/Index.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h
@@ -14,16 +14,17 @@
 #include "nsISupportsImpl.h"
 
 template<class T> class nsAutoPtr;
 
 namespace mp4_demuxer
 {
 
 class Index;
+class IndiceWrapper;
 
 typedef int64_t Microseconds;
 
 class SampleIterator
 {
 public:
   explicit SampleIterator(Index* aIndex);
   already_AddRefed<mozilla::MediaRawData> GetNext();
@@ -87,17 +88,17 @@ public:
     };
 
     uint32_t mIndex;
     int64_t mStartOffset;
     int64_t mEndOffset;
     Interval<Microseconds> mTime;
   };
 
-  Index(const nsTArray<Indice>& aIndex,
+  Index(const IndiceWrapper& aIndices,
         Stream* aSource,
         uint32_t aTrackId,
         bool aIsAudio);
 
   void UpdateMoofIndex(const mozilla::MediaByteRangeSet& aByteRanges);
   Microseconds GetEndCompositionIfBuffered(
     const mozilla::MediaByteRangeSet& aByteRanges);
   mozilla::media::TimeIntervals ConvertByteRangesToTimeRanges(
--- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -6,38 +6,50 @@
 #define MP4METADATA_H_
 
 #include "mozilla/UniquePtr.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "mp4_demuxer/Index.h"
 #include "MediaData.h"
 #include "MediaInfo.h"
 #include "Stream.h"
+#include "mp4parse.h"
 
 namespace mp4_demuxer
 {
 
 class MP4MetadataStagefright;
 class MP4MetadataRust;
 
+class IndiceWrapper {
+public:
+  virtual size_t Length() const = 0;
+
+  // TODO: Index::Indice is from stagefright, we should use another struct once
+  //       stagefrigth is removed.
+  virtual bool GetIndice(size_t aIndex, Index::Indice& aIndice) const = 0;
+
+  virtual ~IndiceWrapper() {}
+};
+
 class MP4Metadata
 {
 public:
   explicit MP4Metadata(Stream* aSource);
   ~MP4Metadata();
 
   static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
   uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
   mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                                                       size_t aTrackNumber) const;
   bool CanSeek() const;
 
   const CryptoFile& Crypto() const;
 
-  bool ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
+  mozilla::UniquePtr<IndiceWrapper> GetTrackIndice(mozilla::TrackID aTrackID);
 
 private:
   UniquePtr<MP4MetadataStagefright> mStagefright;
   UniquePtr<MP4MetadataRust> mRust;
   mutable bool mPreferRust;
   mutable bool mReportedAudioTrackTelemetry;
   mutable bool mReportedVideoTrackTelemetry;
 #ifndef RELEASE_OR_BETA
--- a/media/libstagefright/gtest/TestParser.cpp
+++ b/media/libstagefright/gtest/TestParser.cpp
@@ -231,39 +231,45 @@ TEST(stagefright_MPEG4Metadata, test_cas
       ASSERT_TRUE(!!trackInfo);
       const VideoInfo* videoInfo = trackInfo->GetAsVideoInfo();
       ASSERT_TRUE(!!videoInfo);
       EXPECT_TRUE(videoInfo->IsValid());
       EXPECT_TRUE(videoInfo->IsVideo());
       EXPECT_EQ(testFiles[test].mVideoDuration, videoInfo->mDuration);
       EXPECT_EQ(testFiles[test].mWidth, videoInfo->mDisplay.width);
       EXPECT_EQ(testFiles[test].mHeight, videoInfo->mDisplay.height);
-      FallibleTArray<mp4_demuxer::Index::Indice> indices;
-      EXPECT_TRUE(metadata.ReadTrackIndex(indices, videoInfo->mTrackId));
-      for (const mp4_demuxer::Index::Indice& indice : indices) {
-        EXPECT_TRUE(indice.start_offset <= indice.end_offset);
-        EXPECT_TRUE(indice.start_composition <= indice.end_composition);
+
+      UniquePtr<IndiceWrapper> indices = metadata.GetTrackIndice(videoInfo->mTrackId);
+      EXPECT_TRUE(!!indices);
+      for (size_t i = 0; i < indices->Length(); i++) {
+        Index::Indice data;
+        EXPECT_TRUE(indices->GetIndice(i, data));
+        EXPECT_TRUE(data.start_offset <= data.end_offset);
+        EXPECT_TRUE(data.start_composition <= data.end_composition);
       }
     }
     trackInfo = metadata.GetTrackInfo(TrackInfo::kAudioTrack, 0);
     if (testFiles[test].mNumberAudioTracks == 0) {
       EXPECT_TRUE(!trackInfo);
     } else {
       ASSERT_TRUE(!!trackInfo);
       const AudioInfo* audioInfo = trackInfo->GetAsAudioInfo();
       ASSERT_TRUE(!!audioInfo);
       EXPECT_TRUE(audioInfo->IsValid());
       EXPECT_TRUE(audioInfo->IsAudio());
       EXPECT_EQ(testFiles[test].mAudioDuration, audioInfo->mDuration);
       EXPECT_EQ(testFiles[test].mAudioProfile, audioInfo->mProfile);
-      FallibleTArray<mp4_demuxer::Index::Indice> indices;
-      EXPECT_TRUE(metadata.ReadTrackIndex(indices, audioInfo->mTrackId));
-      for (const mp4_demuxer::Index::Indice& indice : indices) {
-        EXPECT_TRUE(indice.start_offset <= indice.end_offset);
-        EXPECT_TRUE(indice.start_composition <= indice.end_composition);
+
+      UniquePtr<IndiceWrapper> indices = metadata.GetTrackIndice(audioInfo->mTrackId);
+      EXPECT_TRUE(!!indices);
+      for (size_t i = 0; i < indices->Length(); i++) {
+        Index::Indice data;
+        EXPECT_TRUE(indices->GetIndice(i, data));
+        EXPECT_TRUE(data.start_offset <= data.end_offset);
+        EXPECT_TRUE(data.start_composition <= data.end_composition);
       }
     }
     EXPECT_FALSE(metadata.GetTrackInfo(TrackInfo::kTextTrack, 0));
     EXPECT_FALSE(metadata.GetTrackInfo(static_cast<TrackInfo::TrackType>(-1), 0));
     // We can see anywhere in any MPEG4.
     EXPECT_TRUE(metadata.CanSeek());
     EXPECT_EQ(testFiles[test].mHasCrypto, metadata.Crypto().valid);
   }