Bug 1188804: [MSE] P1. Fix Is*SegmentPresent. r=kentuckyfriedtakahe
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 29 Jul 2015 15:15:23 +1000
changeset 286770 af0fcf52e4b7c10297d10aad1db80b8dc530e1ae
parent 286769 d1c3131176181e6caa840ad40f0de5ee22306510
child 286771 ce9a1842eae243ce24eaedf6cddb8d18f1e82053
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe
bugs1188804
milestone42.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 1188804: [MSE] P1. Fix Is*SegmentPresent. r=kentuckyfriedtakahe The name IsInitSegmentPresent and IsMediaSegmentPresent was misleading. As they are to return true only if data *starts* with such segment and not just contain.
dom/media/mediasource/ContainerParser.cpp
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -256,65 +256,96 @@ private:
 #ifdef MOZ_FMP4
 class MP4ContainerParser : public ContainerParser {
 public:
   explicit MP4ContainerParser(const nsACString& aType)
     : ContainerParser(aType)
     , mMonitor("MP4ContainerParser Index Monitor")
   {}
 
-  bool HasAtom(const mp4_demuxer::AtomType& aAtom, const MediaByteBuffer* aData) {
-    mp4_demuxer::ByteReader reader(aData);
-
-    while (reader.Remaining() >= 8) {
-      uint64_t size = reader.ReadU32();
-      const uint8_t* typec = reader.Peek(4);
-      uint32_t type = reader.ReadU32();
-      MSE_DEBUGV(MP4ContainerParser ,"Checking atom:'%c%c%c%c'",
-                typec[0], typec[1], typec[2], typec[3]);
-      if (mp4_demuxer::AtomType(type) == aAtom) {
-        reader.DiscardRemaining();
-        return true;
-      }
-      if (size == 1) {
-        // 64 bits size.
-        if (!reader.CanReadType<uint64_t>()) {
-          break;
-        }
-        size = reader.ReadU64();
-      } else if (size == 0) {
-        // Atom extends to the end of the buffer, it can't have what we're
-        // looking for.
-        break;
-      }
-      if (reader.Remaining() < size - 8) {
-        // Incomplete atom.
-        break;
-      }
-      reader.Read(size - 8);
-    }
-    reader.DiscardRemaining();
-    return false;
-  }
-
   bool IsInitSegmentPresent(MediaByteBuffer* aData) override
   {
     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.
-    return HasAtom(mp4_demuxer::AtomType("ftyp"), aData);
+    AtomParser parser(mType, aData);
+    return parser.StartWithInitSegment();
   }
 
   bool IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
-    ContainerParser::IsMediaSegmentPresent(aData);
-    return HasAtom(mp4_demuxer::AtomType("moof"), aData);
+    AtomParser parser(mType, aData);
+    return parser.StartWithMediaSegment();
   }
 
+private:
+  class AtomParser {
+  public:
+    AtomParser(const nsACString& aType, const MediaByteBuffer* aData)
+    {
+      const nsCString mType(aType); // for logging macro.
+      mp4_demuxer::ByteReader reader(aData);
+      mp4_demuxer::AtomType initAtom("ftyp");
+      mp4_demuxer::AtomType mediaAtom("moof");
+
+      while (reader.Remaining() >= 8) {
+        uint64_t size = reader.ReadU32();
+        const uint8_t* typec = reader.Peek(4);
+        uint32_t type = reader.ReadU32();
+        MSE_DEBUGV(AtomParser ,"Checking atom:'%c%c%c%c'",
+                   typec[0], typec[1], typec[2], typec[3]);
+        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 (size == 1) {
+          // 64 bits size.
+          if (!reader.CanReadType<uint64_t>()) {
+            break;
+          }
+          size = reader.ReadU64();
+        } else if (size == 0) {
+          // Atom extends to the end of the buffer, it can't have what we're
+          // looking for.
+          break;
+        }
+        if (reader.Remaining() < size - 8) {
+          // Incomplete atom.
+          break;
+        }
+        reader.Read(size - 8);
+      }
+      reader.DiscardRemaining();
+    }
+
+    bool StartWithInitSegment()
+    {
+      return mInitOffset.isSome() &&
+        (mMediaOffset.isNothing() || mInitOffset.ref() < mMediaOffset.ref());
+    }
+    bool StartWithMediaSegment()
+    {
+      return mMediaOffset.isSome() &&
+        (mInitOffset.isNothing() || mMediaOffset.ref() < mInitOffset.ref());
+    }
+  private:
+    Maybe<size_t> mInitOffset;
+    Maybe<size_t> mMediaOffset;
+  };
+
+public:
   bool ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                   int64_t& aStart, int64_t& aEnd) override
   {
     MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
                                    // but mParser requires us to hold a monitor.
     bool initSegment = IsInitSegmentPresent(aData);
     if (initSegment) {
       mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/mp4"));