Bug 1400598 - P1. Stop parsing bytesteam as soon as we have found the necessary data. r?gerald draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sat, 16 Sep 2017 23:35:17 +0200
changeset 666042 1fa5f588ae47ba4311128956cf74074cf8f411ba
parent 666040 fcb1715484e3d293af81ab2451dabb971841762c
child 666060 39dbea1c45b89f66fe866c47230cbd2173eadebf
child 666061 a4c8ad11eab79ea9358bec9f3f9aa414bcdb9162
push id80254
push userbmo:jyavenard@mozilla.com
push dateSun, 17 Sep 2017 08:38:35 +0000
reviewersgerald
bugs1400598
milestone57.0a1
Bug 1400598 - P1. Stop parsing bytesteam as soon as we have found the necessary data. r?gerald MozReview-Commit-ID: 9APhbRHIMUP
dom/media/mediasource/ContainerParser.cpp
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -436,48 +436,58 @@ public:
   {
     ContainerParser::IsInitSegmentPresent(aData);
     // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
     // file is the 'ftyp' atom followed by a file type. We just check for a
     // vaguely valid 'ftyp' atom.
     if (aData->Length() < 8) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-    AtomParser parser(mType, aData);
+    AtomParser parser(mType, aData, AtomParser::StopAt::eInitSegment);
     if (!parser.IsValid()) {
       return MediaResult(
         NS_ERROR_FAILURE,
         RESULT_DETAIL("Invalid Top-Level Box:%s", parser.LastInvalidBox()));
     }
     return parser.StartWithInitSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
   MediaResult IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
     if (aData->Length() < 8) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-    AtomParser parser(mType, aData);
+    AtomParser parser(mType, aData, AtomParser::StopAt::eMediaSegment);
     if (!parser.IsValid()) {
       return MediaResult(
         NS_ERROR_FAILURE,
         RESULT_DETAIL("Invalid Box:%s", parser.LastInvalidBox()));
     }
     return parser.StartWithMediaSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
 private:
-  class AtomParser {
+  class AtomParser
+  {
   public:
-    AtomParser(const MediaContainerType& aType, const MediaByteBuffer* aData)
+    enum class StopAt
+    {
+      eInitSegment,
+      eMediaSegment,
+      eEnd
+    };
+
+    AtomParser(const MediaContainerType& aType, const MediaByteBuffer* aData,
+               StopAt aStop = StopAt::eEnd)
     {
       const MediaContainerType mType(aType); // for logging macro.
       mp4_demuxer::ByteReader reader(aData);
       mp4_demuxer::AtomType initAtom("moov");
       mp4_demuxer::AtomType mediaAtom("moof");
+      mp4_demuxer::AtomType dataAtom("mdat");
 
       // Valid top-level boxes defined in ISO/IEC 14496-12 (Table 1)
       static const mp4_demuxer::AtomType validBoxes[] = {
         "ftyp", "moov", // init segment
         "pdin", "free", "sidx", // optional prior moov box
         "styp", "moof", "mdat", // media segment
         "mfra", "skip", "meta", "meco", "ssix", "prft", // others.
         "pssh", // optional with encrypted EME, though ignored.
@@ -506,19 +516,19 @@ private:
         if (mInitOffset.isNothing() &&
             mp4_demuxer::AtomType(type) == initAtom) {
           mInitOffset = Some(reader.Offset());
         }
         if (mMediaOffset.isNothing() &&
             mp4_demuxer::AtomType(type) == mediaAtom) {
           mMediaOffset = Some(reader.Offset());
         }
-        if (mInitOffset.isSome() && mMediaOffset.isSome()) {
-          // We have everything we need.
-          break;
+        if (mDataOffset.isNothing() &&
+            mp4_demuxer::AtomType(type) == dataAtom) {
+          mDataOffset = Some(reader.Offset());
         }
         if (size == 1) {
           // 64 bits size.
           if (!reader.CanReadType<uint64_t>()) {
             break;
           }
           size = reader.ReadU64();
         } else if (size == 0) {
@@ -526,16 +536,30 @@ private:
           // looking for.
           break;
         }
         if (reader.Remaining() < size - 8) {
           // Incomplete atom.
           break;
         }
         reader.Read(size - 8);
+
+        if (aStop == StopAt::eInitSegment && (mInitOffset || mMediaOffset)) {
+          // When we're looking for an init segment, if we encountered a media
+          // segment, it we will need to be processed first. So we can stop
+          // right away if we have found a media segment.
+          break;
+        }
+        if (aStop == StopAt::eMediaSegment &&
+            (mInitOffset || (mMediaOffset && mDataOffset))) {
+          // When we're looking for a media segment, if we encountered an init
+          // segment, it we will need to be processed first. So we can stop
+          // right away if we have found an init segment.
+          break;
+        }
       }
     }
 
     bool StartWithInitSegment() const
     {
       return mInitOffset.isSome() &&
         (mMediaOffset.isNothing() || mInitOffset.ref() < mMediaOffset.ref());
     }
@@ -544,16 +568,17 @@ private:
       return mMediaOffset.isSome() &&
         (mInitOffset.isNothing() || mMediaOffset.ref() < mInitOffset.ref());
     }
     bool IsValid() const { return mValid; }
     const char* LastInvalidBox() const { return mLastInvalidBox; }
   private:
     Maybe<size_t> mInitOffset;
     Maybe<size_t> mMediaOffset;
+    Maybe<size_t> mDataOffset;
     bool mValid = true;
     char mLastInvalidBox[5];
   };
 
 public:
   MediaResult ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                          int64_t& aStart,
                                          int64_t& aEnd) override