tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebMBufferedParser.h (10766B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 #if !defined(WebMBufferedParser_h_)
      7 #  define WebMBufferedParser_h_
      8 
      9 #  include "MediaResource.h"
     10 #  include "MediaResult.h"
     11 #  include "mozilla/Mutex.h"
     12 #  include "nsISupportsImpl.h"
     13 #  include "nsTArray.h"
     14 
     15 namespace mozilla {
     16 
     17 // Stores a stream byte offset and the scaled timecode of the block at
     18 // that offset.
     19 struct WebMTimeDataOffset {
     20  WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode,
     21                     int64_t aInitOffset, int64_t aSyncOffset,
     22                     int64_t aClusterEndOffset)
     23      : mEndOffset(aEndOffset),
     24        mInitOffset(aInitOffset),
     25        mSyncOffset(aSyncOffset),
     26        mClusterEndOffset(aClusterEndOffset),
     27        mTimecode(aTimecode) {}
     28 
     29  bool operator==(int64_t aEndOffset) const { return mEndOffset == aEndOffset; }
     30 
     31  bool operator!=(int64_t aEndOffset) const { return mEndOffset != aEndOffset; }
     32 
     33  bool operator<(int64_t aEndOffset) const { return mEndOffset < aEndOffset; }
     34 
     35  int64_t mEndOffset;
     36  int64_t mInitOffset;
     37  int64_t mSyncOffset;
     38  int64_t mClusterEndOffset;
     39  // In nanoseconds
     40  uint64_t mTimecode;
     41 };
     42 
     43 // A simple WebM parser that produces data offset to timecode pairs as it
     44 // consumes blocks.  A new parser is created for each distinct range of data
     45 // received and begins parsing from the first WebM cluster within that
     46 // range.  Old parsers are destroyed when their range merges with a later
     47 // parser or an already parsed range.  The parser may start at any position
     48 // within the stream.
     49 struct WebMBufferedParser {
     50  explicit WebMBufferedParser(int64_t aOffset);
     51 
     52  uint32_t GetTimecodeScale() {
     53    MOZ_ASSERT(mGotTimecodeScale);
     54    return mTimecodeScale;
     55  }
     56 
     57  // Use this function when we would only feed media segment for the parser.
     58  void AppendMediaSegmentOnly() { mGotTimecodeScale = true; }
     59 
     60  // If this parser is not expected to parse a segment info, it must be told
     61  // the appropriate timecode scale to use from elsewhere.
     62  void SetTimecodeScale(uint32_t aTimecodeScale);
     63 
     64  // Steps the parser through aLength bytes of data.  Always consumes
     65  // aLength bytes.  Updates mCurrentOffset before returning.
     66  // Returns false if an error was encountered.
     67  MediaResult Append(const unsigned char* aBuffer, uint32_t aLength,
     68                     nsTArray<WebMTimeDataOffset>& aMapping);
     69 
     70  bool operator==(int64_t aOffset) const { return mCurrentOffset == aOffset; }
     71 
     72  bool operator<(int64_t aOffset) const { return mCurrentOffset < aOffset; }
     73 
     74  // Returns the start offset of the init (EBML) or media segment (Cluster)
     75  // following the aOffset position. If none were found, returns
     76  // mBlockEndOffset. This allows to determine the end of the interval containg
     77  // aOffset.
     78  int64_t EndSegmentOffset(int64_t aOffset);
     79 
     80  // Return the Cluster offset, return -1 if we can't find the Cluster.
     81  int64_t GetClusterOffset() const;
     82 
     83  // The offset at which this parser started parsing.  Used to merge
     84  // adjacent parsers, in which case the later parser adopts the earlier
     85  // parser's mStartOffset.
     86  int64_t mStartOffset;
     87 
     88  // Current offset within the stream.  Updated in chunks as Append() consumes
     89  // data.
     90  int64_t mCurrentOffset;
     91 
     92  // Tracks element's end offset. This indicates the end of the first init
     93  // segment. Will only be set if a Segment Information has been found.
     94  int64_t mInitEndOffset;
     95 
     96  // End offset of the last block parsed.
     97  // Will only be set if a complete block has been parsed.
     98  int64_t mBlockEndOffset;
     99 
    100 private:
    101  enum State {
    102    // Parser start state.  Expects to begin at a valid EBML element.  Move
    103    // to READ_VINT with mVIntRaw true, then return to READ_ELEMENT_SIZE.
    104    READ_ELEMENT_ID,
    105 
    106    // Store element ID read into mVInt into mElement.mID.  Move to
    107    // READ_VINT with mVIntRaw false, then return to PARSE_ELEMENT.
    108    READ_ELEMENT_SIZE,
    109 
    110    // Parser start state for parsers started at an arbitrary offset.  Scans
    111    // forward for the first cluster, then move to READ_ELEMENT_ID.
    112    FIND_CLUSTER_SYNC,
    113 
    114    // Simplistic core of the parser.  Does not pay attention to nesting of
    115    // elements.  Checks mElement for an element ID of interest, then moves
    116    // to the next state as determined by the element ID.
    117    PARSE_ELEMENT,
    118 
    119    // Read the first byte of a variable length integer.  The first byte
    120    // encodes both the variable integer's length and part of the value.
    121    // The value read so far is stored in mVInt.mValue and the length is
    122    // stored in mVInt.mLength.  The number of bytes left to read is stored
    123    // in mVIntLeft.
    124    READ_VINT,
    125 
    126    // Reads the remaining mVIntLeft bytes into mVInt.mValue.
    127    READ_VINT_REST,
    128 
    129    // mVInt holds the parsed timecode scale, store it in mTimecodeScale,
    130    // then return READ_ELEMENT_ID.
    131    READ_TIMECODESCALE,
    132 
    133    // mVInt holds the parsed cluster timecode, store it in
    134    // mClusterTimecode, then return to READ_ELEMENT_ID.
    135    READ_CLUSTER_TIMECODE,
    136 
    137    // mBlockTimecodeLength holds the remaining length of the block timecode
    138    // left to read.  Read each byte of the timecode into mBlockTimecode.
    139    // Once complete, calculate the scaled timecode from the cluster
    140    // timecode, block timecode, and timecode scale, and insert a
    141    // WebMTimeDataOffset entry into aMapping if one is not already present
    142    // for this offset.
    143    READ_BLOCK_TIMECODE,
    144 
    145    // mVInt holds the parsed EBMLMaxIdLength, store it in mEBMLMaxIdLength,
    146    // then return to READ_ELEMENT_ID.
    147    READ_EBML_MAX_ID_LENGTH,
    148 
    149    // mVInt holds the parsed EBMLMaxSizeLength, store it in mEBMLMaxSizeLength,
    150    // then return to READ_ELEMENT_ID.
    151    READ_EBML_MAX_SIZE_LENGTH,
    152 
    153    // Will skip the current tracks element and set mInitEndOffset if an init
    154    // segment has been found.
    155    // Currently, only assumes it's the end of the tracks element.
    156    CHECK_INIT_FOUND,
    157 
    158    // Skip mSkipBytes of data before resuming parse at mNextState.
    159    SKIP_DATA,
    160  };
    161 
    162  // Current state machine action.
    163  State mState;
    164 
    165  // Next state machine action.  SKIP_DATA and READ_VINT_REST advance to
    166  // mNextState when the current action completes.
    167  State mNextState;
    168 
    169  struct VInt {
    170    VInt() : mValue(0), mLength(0) {}
    171    uint64_t mValue;
    172    uint64_t mLength;
    173  };
    174 
    175  struct EBMLElement {
    176    uint64_t Length() { return mID.mLength + mSize.mLength; }
    177    VInt mID;
    178    VInt mSize;
    179  };
    180 
    181  EBMLElement mElement;
    182 
    183  VInt mVInt;
    184 
    185  bool mVIntRaw;
    186 
    187  // EBML start offset. This indicates the start of the last init segment
    188  // parsed. Will only be set if an EBML element has been found.
    189  int64_t mLastInitStartOffset;
    190 
    191  // EBML element size. This indicates the size of the body of the last init
    192  // segment parsed. Will only be set if an EBML element has been found.
    193  uint32_t mLastInitSize;
    194 
    195  // EBML max id length is the max number of bytes allowed for an element id
    196  // vint.
    197  uint8_t mEBMLMaxIdLength;
    198 
    199  // EBML max size length is the max number of bytes allowed for an element size
    200  // vint.
    201  uint8_t mEBMLMaxSizeLength;
    202 
    203  // Current match position within CLUSTER_SYNC_ID.  Used to find sync
    204  // within arbitrary data.
    205  uint32_t mClusterSyncPos;
    206 
    207  // Number of bytes of mVInt left to read.  mVInt is complete once this
    208  // reaches 0.
    209  uint32_t mVIntLeft;
    210 
    211  // Size of the block currently being parsed.  Any unused data within the
    212  // block is skipped once the block timecode has been parsed.
    213  uint64_t mBlockSize;
    214 
    215  // Cluster-level timecode.
    216  uint64_t mClusterTimecode;
    217 
    218  // Start offset of the cluster currently being parsed.  Used as the sync
    219  // point offset for the offset-to-time mapping as each block timecode is
    220  // been parsed. -1 if unknown.
    221  int64_t mClusterOffset;
    222 
    223  // End offset of the cluster currently being parsed. -1 if unknown.
    224  int64_t mClusterEndOffset;
    225 
    226  // Start offset of the block currently being parsed.  Used as the byte
    227  // offset for the offset-to-time mapping once the block timecode has been
    228  // parsed.
    229  int64_t mBlockOffset;
    230 
    231  // Block-level timecode.  This is summed with mClusterTimecode to produce
    232  // an absolute timecode for the offset-to-time mapping.
    233  int16_t mBlockTimecode;
    234 
    235  // Number of bytes of mBlockTimecode left to read.
    236  uint32_t mBlockTimecodeLength;
    237 
    238  // Count of bytes left to skip before resuming parse at mNextState.
    239  // Mostly used to skip block payload data after reading a block timecode.
    240  uint32_t mSkipBytes;
    241 
    242  // Timecode scale read from the segment info and used to scale absolute
    243  // timecodes.
    244  uint32_t mTimecodeScale;
    245 
    246  // True if we read the timecode scale from the segment info or have
    247  // confirmed that the default value is to be used.
    248  bool mGotTimecodeScale;
    249 
    250  // True if we've read the cluster time code.
    251  bool mGotClusterTimecode;
    252 };
    253 
    254 class WebMBufferedState final {
    255  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebMBufferedState)
    256 
    257 public:
    258  WebMBufferedState() : mMutex("WebMBufferedState") {
    259    MOZ_COUNT_CTOR(WebMBufferedState);
    260  }
    261 
    262  void NotifyDataArrived(const unsigned char* aBuffer, uint32_t aLength,
    263                         int64_t aOffset);
    264  void Reset();
    265  void UpdateIndex(const MediaByteRangeSet& aRanges, MediaResource* aResource);
    266  bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
    267                                 uint64_t* aStartTime, uint64_t* aEndTime);
    268 
    269  // Returns true if mTimeMapping is not empty and sets aOffset to
    270  // the latest offset for which decoding can resume without data
    271  // dependencies to arrive at aTime. aTime will be clamped to the start
    272  // of mTimeMapping if it is earlier than the first element, and to the end
    273  // if later than the last
    274  bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
    275 
    276  // Returns end offset of init segment or -1 if none found.
    277  int64_t GetInitEndOffset();
    278 
    279  // Returns start time
    280  bool GetStartTime(uint64_t* aTime);
    281 
    282  // Returns keyframe for time
    283  bool GetNextKeyframeTime(uint64_t aTime, uint64_t* aKeyframeTime);
    284 
    285 private:
    286  // Private destructor, to discourage deletion outside of Release():
    287  MOZ_COUNTED_DTOR(WebMBufferedState)
    288 
    289  // Synchronizes access to the mTimeMapping array.
    290  Mutex mMutex;
    291 
    292  // Sorted (by offset) map of data offsets to timecodes.  Populated
    293  // on the main thread as data is received and parsed by WebMBufferedParsers.
    294  nsTArray<WebMTimeDataOffset> mTimeMapping MOZ_GUARDED_BY(mMutex);
    295 
    296  // Sorted (by offset) live parser instances.  Main thread only.
    297  nsTArray<WebMBufferedParser> mRangeParsers;
    298 };
    299 
    300 }  // namespace mozilla
    301 
    302 #endif