Bug 1362440 - part2 : parsing entire content to decide whether it's media segment. draft
authorAlastor Wu <alwu@mozilla.com>
Mon, 30 Oct 2017 15:27:30 +0800
changeset 688588 13aeae76c15a4fd91dba0986154ea70dabd5947b
parent 688587 e8e9d1f2b605e213c873ca4a1280f7e5f494e63f
child 688589 b3298bc1c3e26948a94143586b3ac4c20ef2a2b3
push id86795
push useralwu@mozilla.com
push dateMon, 30 Oct 2017 09:49:00 +0000
bugs1362440
milestone58.0a1
Bug 1362440 - part2 : parsing entire content to decide whether it's media segment. The spec [1] defines what's the media segment, and the parser would return error if the format is not correct. [1] https://w3c.github.io/media-source/webm-byte-stream-format.html MozReview-Commit-ID: 4hq59Pywz2t
dom/media/mediasource/ContainerParser.cpp
dom/media/webm/WebMBufferedParser.cpp
dom/media/webm/WebMBufferedParser.h
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -155,41 +155,30 @@ public:
       return NS_OK;
     }
     return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
   }
 
   MediaResult IsMediaSegmentPresent(MediaByteBuffer* aData) override
   {
     ContainerParser::IsMediaSegmentPresent(aData);
-    // XXX: This is overly primitive, needs to collect data as it's appended
-    // to the SB and handle, rather than assuming everything is present in a
-    // single aData segment.
-    // 0x1a45dfa3 // EBML
-    // ...
-    // DocType == "webm"
-    // ...
-    // 0x18538067 // Segment (must be "unknown" size)
-    // 0x1549a966 // -> Segment Info
-    // 0x1654ae6b // -> One or more Tracks
-
-    // 0x1f43b675 // Cluster
     if (aData->Length() < 4) {
       return NS_ERROR_NOT_AVAILABLE;
     }
-    if ((*aData)[0] == 0x1f && (*aData)[1] == 0x43 && (*aData)[2] == 0xb6 &&
-        (*aData)[3] == 0x75) {
-      return NS_OK;
+
+    WebMBufferedParser parser(0);
+    nsTArray<WebMTimeDataOffset> mapping;
+    ReentrantMonitor dummy("dummy");
+    parser.AppendMediaSegmentOnly();
+    bool result = parser.Append(aData->Elements(), aData->Length(), mapping,
+                                dummy);
+    if (!result) {
+      return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
     }
-    // 0x1c53bb6b // Cues
-    if ((*aData)[0] == 0x1c && (*aData)[1] == 0x53 && (*aData)[2] == 0xbb &&
-        (*aData)[3] == 0x6b) {
-      return NS_OK;
-    }
-    return MediaResult(NS_ERROR_FAILURE, RESULT_DETAIL("Invalid webm content"));
+    return parser.GetClusterOffset() >= 0 ? NS_OK : NS_ERROR_NOT_AVAILABLE;
   }
 
   MediaResult ParseStartAndEndTimestamps(MediaByteBuffer* aData,
                                          int64_t& aStart,
                                          int64_t& aEnd) override
   {
     bool initSegment = NS_SUCCEEDED(IsInitSegmentPresent(aData));
 
--- a/dom/media/webm/WebMBufferedParser.cpp
+++ b/dom/media/webm/WebMBufferedParser.cpp
@@ -270,16 +270,22 @@ WebMBufferedParser::EndSegmentOffset(int
 {
   if (mLastInitStartOffset > aOffset || mClusterOffset > aOffset) {
     return std::min(mLastInitStartOffset >= 0 ? mLastInitStartOffset : INT64_MAX,
                     mClusterOffset >= 0 ? mClusterOffset : INT64_MAX);
   }
   return mBlockEndOffset;
 }
 
+int64_t
+WebMBufferedParser::GetClusterOffset() const
+{
+  return mClusterOffset;
+}
+
 // SyncOffsetComparator and TimeComparator are slightly confusing, in that
 // the nsTArray they're used with (mTimeMapping) is sorted by mEndOffset and
 // these comparators are used on the other fields of WebMTimeDataOffset.
 // This is only valid because timecodes are required to be monotonically
 // increasing within a file (thus establishing an ordering relationship with
 // mTimecode), and mEndOffset is derived from mSyncOffset.
 struct SyncOffsetComparator {
   bool Equals(const WebMTimeDataOffset& a, const int64_t& b) const {
--- a/dom/media/webm/WebMBufferedParser.h
+++ b/dom/media/webm/WebMBufferedParser.h
@@ -62,17 +62,17 @@ struct WebMBufferedParser
     , mState(READ_ELEMENT_ID)
     , mNextState(READ_ELEMENT_ID)
     , mVIntRaw(false)
     , mLastInitStartOffset(-1)
     , mClusterSyncPos(0)
     , mVIntLeft(0)
     , mBlockSize(0)
     , mClusterTimecode(0)
-    , mClusterOffset(0)
+    , mClusterOffset(-1)
     , mClusterEndOffset(-1)
     , mBlockOffset(0)
     , mBlockTimecode(0)
     , mBlockTimecodeLength(0)
     , mSkipBytes(0)
     , mTimecodeScale(1000000)
     , mGotTimecodeScale(false)
     , mGotClusterTimecode(false)
@@ -82,16 +82,22 @@ struct WebMBufferedParser
     }
   }
 
   uint32_t GetTimecodeScale() {
     MOZ_ASSERT(mGotTimecodeScale);
     return mTimecodeScale;
   }
 
+  // Use this function when we would only feed media segment for the parser.
+  void AppendMediaSegmentOnly()
+  {
+    mGotTimecodeScale = true;
+  }
+
   // If this parser is not expected to parse a segment info, it must be told
   // the appropriate timecode scale to use from elsewhere.
   void SetTimecodeScale(uint32_t aTimecodeScale) {
     mTimecodeScale = aTimecodeScale;
     mGotTimecodeScale = true;
   }
 
   // Steps the parser through aLength bytes of data.  Always consumes
@@ -110,16 +116,19 @@ struct WebMBufferedParser
     return mCurrentOffset < aOffset;
   }
 
   // Returns the start offset of the init (EBML) or media segment (Cluster)
   // following the aOffset position. If none were found, returns mBlockEndOffset.
   // This allows to determine the end of the interval containg aOffset.
   int64_t EndSegmentOffset(int64_t aOffset);
 
+  // Return the Cluster offset, return -1 if we can't find the Cluster.
+  int64_t GetClusterOffset() const;
+
   // The offset at which this parser started parsing.  Used to merge
   // adjacent parsers, in which case the later parser adopts the earlier
   // parser's mStartOffset.
   int64_t mStartOffset;
 
   // Current offset within the stream.  Updated in chunks as Append() consumes
   // data.
   int64_t mCurrentOffset;
@@ -227,17 +236,17 @@ private:
   // block is skipped once the block timecode has been parsed.
   uint64_t mBlockSize;
 
   // Cluster-level timecode.
   uint64_t mClusterTimecode;
 
   // Start offset of the cluster currently being parsed.  Used as the sync
   // point offset for the offset-to-time mapping as each block timecode is
-  // been parsed.
+  // been parsed. -1 if unknown.
   int64_t mClusterOffset;
 
   // End offset of the cluster currently being parsed. -1 if unknown.
   int64_t mClusterEndOffset;
 
   // Start offset of the block currently being parsed.  Used as the byte
   // offset for the offset-to-time mapping once the block timecode has been
   // parsed.