content/media/webm/WebMBufferedParser.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/webm/WebMBufferedParser.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,218 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +#if !defined(WebMBufferedParser_h_)
    1.10 +#define WebMBufferedParser_h_
    1.11 +
    1.12 +#include "nsISupportsImpl.h"
    1.13 +#include "nsTArray.h"
    1.14 +#include "mozilla/ReentrantMonitor.h"
    1.15 +
    1.16 +namespace mozilla {
    1.17 +
    1.18 +namespace dom {
    1.19 +class TimeRanges;
    1.20 +}
    1.21 +
    1.22 +// Stores a stream byte offset and the scaled timecode of the block at
    1.23 +// that offset.  The timecode must be scaled by the stream's timecode
    1.24 +// scale before use.
    1.25 +struct WebMTimeDataOffset
    1.26 +{
    1.27 +  WebMTimeDataOffset(int64_t aOffset, uint64_t aTimecode)
    1.28 +    : mOffset(aOffset), mTimecode(aTimecode)
    1.29 +  {}
    1.30 +
    1.31 +  bool operator==(int64_t aOffset) const {
    1.32 +    return mOffset == aOffset;
    1.33 +  }
    1.34 +
    1.35 +  bool operator<(int64_t aOffset) const {
    1.36 +    return mOffset < aOffset;
    1.37 +  }
    1.38 +
    1.39 +  int64_t mOffset;
    1.40 +  uint64_t mTimecode;
    1.41 +};
    1.42 +
    1.43 +// A simple WebM parser that produces data offset to timecode pairs as it
    1.44 +// consumes blocks.  A new parser is created for each distinct range of data
    1.45 +// received and begins parsing from the first WebM cluster within that
    1.46 +// range.  Old parsers are destroyed when their range merges with a later
    1.47 +// parser or an already parsed range.  The parser may start at any position
    1.48 +// within the stream.
    1.49 +struct WebMBufferedParser
    1.50 +{
    1.51 +  WebMBufferedParser(int64_t aOffset)
    1.52 +    : mStartOffset(aOffset), mCurrentOffset(aOffset), mState(CLUSTER_SYNC), mClusterIDPos(0)
    1.53 +  {}
    1.54 +
    1.55 +  // Steps the parser through aLength bytes of data.  Always consumes
    1.56 +  // aLength bytes.  Updates mCurrentOffset before returning.  Acquires
    1.57 +  // aReentrantMonitor before using aMapping.
    1.58 +  void Append(const unsigned char* aBuffer, uint32_t aLength,
    1.59 +              nsTArray<WebMTimeDataOffset>& aMapping,
    1.60 +              ReentrantMonitor& aReentrantMonitor);
    1.61 +
    1.62 +  bool operator==(int64_t aOffset) const {
    1.63 +    return mCurrentOffset == aOffset;
    1.64 +  }
    1.65 +
    1.66 +  bool operator<(int64_t aOffset) const {
    1.67 +    return mCurrentOffset < aOffset;
    1.68 +  }
    1.69 +
    1.70 +  // The offset at which this parser started parsing.  Used to merge
    1.71 +  // adjacent parsers, in which case the later parser adopts the earlier
    1.72 +  // parser's mStartOffset.
    1.73 +  int64_t mStartOffset;
    1.74 +
    1.75 +  // Current offset with the stream.  Updated in chunks as Append() consumes
    1.76 +  // data.
    1.77 +  int64_t mCurrentOffset;
    1.78 +
    1.79 +private:
    1.80 +  enum State {
    1.81 +    // Parser start state.  Scans forward searching for stream sync by
    1.82 +    // matching CLUSTER_ID with the curernt byte.  The match state is stored
    1.83 +    // in mClusterIDPos.  Once this reaches sizeof(CLUSTER_ID), stream may
    1.84 +    // have sync.  The parser then advances to read the cluster size and
    1.85 +    // timecode.
    1.86 +    CLUSTER_SYNC,
    1.87 +
    1.88 +    /*
    1.89 +      The the parser states below assume that CLUSTER_SYNC has found a valid
    1.90 +      sync point within the data.  If parsing fails in these states, the
    1.91 +      parser returns to CLUSTER_SYNC to find a new sync point.
    1.92 +    */
    1.93 +
    1.94 +    // Read the first byte of a variable length integer.  The first byte
    1.95 +    // encodes both the variable integer's length and part of the value.
    1.96 +    // The value read so far is stored in mVInt and the length is stored in
    1.97 +    // mVIntLength.  The number of bytes left to read is stored in
    1.98 +    // mVIntLeft.
    1.99 +    READ_VINT,
   1.100 +
   1.101 +    // Reads the remaining mVIntLeft bytes into mVInt.
   1.102 +    READ_VINT_REST,
   1.103 +
   1.104 +    // Check that the next element is TIMECODE_ID.  The cluster timecode is
   1.105 +    // required to be the first element in a cluster.  Advances to READ_VINT
   1.106 +    // to read the timecode's length into mVInt.
   1.107 +    TIMECODE_SYNC,
   1.108 +
   1.109 +    // mVInt holds the length of the variable length unsigned integer
   1.110 +    // containing the cluster timecode.  Read mVInt bytes into
   1.111 +    // mClusterTimecode.
   1.112 +    READ_CLUSTER_TIMECODE,
   1.113 +
   1.114 +    // Skips elements with a cluster until BLOCKGROUP_ID or SIMPLEBLOCK_ID
   1.115 +    // is found.  If BLOCKGROUP_ID is found, the parser returns to
   1.116 +    // ANY_BLOCK_ID searching for a BLOCK_ID.  Once a block or simpleblock
   1.117 +    // is found, the current data offset is stored in mBlockOffset.  If the
   1.118 +    // current byte is the beginning of a four byte variant integer, it
   1.119 +    // indicates the parser has reached a top-level element ID and the
   1.120 +    // parser returns to CLUSTER_SYNC.
   1.121 +    ANY_BLOCK_SYNC,
   1.122 +
   1.123 +    // Start reading a block.  Blocks and simpleblocks are parsed the same
   1.124 +    // way as the initial layouts are identical.  mBlockSize is initialized
   1.125 +    // from mVInt (holding the element size), and mBlockTimecode(Length) is
   1.126 +    // initialized for parsing.
   1.127 +    READ_BLOCK,
   1.128 +
   1.129 +    // Reads mBlockTimecodeLength bytes of data into mBlockTimecode.  When
   1.130 +    // mBlockTimecodeLength reaches 0, the timecode has been read.  The sum
   1.131 +    // of mClusterTimecode and mBlockTimecode is stored as a pair with
   1.132 +    // mBlockOffset into the offset-to-time map.
   1.133 +    READ_BLOCK_TIMECODE,
   1.134 +
   1.135 +    // Skip mSkipBytes of data before resuming parse at mNextState.
   1.136 +    SKIP_DATA,
   1.137 +
   1.138 +    // Skip the content of an element.  mVInt holds the element length.
   1.139 +    SKIP_ELEMENT
   1.140 +  };
   1.141 +
   1.142 +  // Current state machine action.
   1.143 +  State mState;
   1.144 +
   1.145 +  // Next state machine action.  SKIP_DATA and READ_VINT_REST advance to
   1.146 +  // mNextState when the current action completes.
   1.147 +  State mNextState;
   1.148 +
   1.149 +  // Match position within CLUSTER_ID.  Used to find sync within arbitrary
   1.150 +  // data.
   1.151 +  uint32_t mClusterIDPos;
   1.152 +
   1.153 +  // Variable length integer read from data.
   1.154 +  uint64_t mVInt;
   1.155 +
   1.156 +  // Encoding length of mVInt.  This is the total number of bytes used to
   1.157 +  // encoding mVInt's value.
   1.158 +  uint32_t mVIntLength;
   1.159 +
   1.160 +  // Number of bytes of mVInt left to read.  mVInt is complete once this
   1.161 +  // reaches 0.
   1.162 +  uint32_t mVIntLeft;
   1.163 +
   1.164 +  // Size of the block currently being parsed.  Any unused data within the
   1.165 +  // block is skipped once the block timecode has been parsed.
   1.166 +  uint64_t mBlockSize;
   1.167 +
   1.168 +  // Cluster-level timecode.
   1.169 +  uint64_t mClusterTimecode;
   1.170 +
   1.171 +  // Start offset of the block currently being parsed.  Used as the byte
   1.172 +  // offset for the offset-to-time mapping once the block timecode has been
   1.173 +  // parsed.
   1.174 +  int64_t mBlockOffset;
   1.175 +
   1.176 +  // Block-level timecode.  This is summed with mClusterTimecode to produce
   1.177 +  // an absolute timecode for the offset-to-time mapping.
   1.178 +  int16_t mBlockTimecode;
   1.179 +
   1.180 +  // Number of bytes of mBlockTimecode left to read.
   1.181 +  uint32_t mBlockTimecodeLength;
   1.182 +
   1.183 +  // Count of bytes left to skip before resuming parse at mNextState.
   1.184 +  // Mostly used to skip block payload data after reading a block timecode.
   1.185 +  uint32_t mSkipBytes;
   1.186 +};
   1.187 +
   1.188 +class WebMBufferedState MOZ_FINAL
   1.189 +{
   1.190 +  NS_INLINE_DECL_REFCOUNTING(WebMBufferedState)
   1.191 +
   1.192 +public:
   1.193 +  WebMBufferedState() : mReentrantMonitor("WebMBufferedState") {
   1.194 +    MOZ_COUNT_CTOR(WebMBufferedState);
   1.195 +  }
   1.196 +
   1.197 +  void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
   1.198 +  bool CalculateBufferedForRange(int64_t aStartOffset, int64_t aEndOffset,
   1.199 +                                 uint64_t* aStartTime, uint64_t* aEndTime);
   1.200 +  bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
   1.201 +
   1.202 +private:
   1.203 +  // Private destructor, to discourage deletion outside of Release():
   1.204 +  ~WebMBufferedState() {
   1.205 +    MOZ_COUNT_DTOR(WebMBufferedState);
   1.206 +  }
   1.207 +
   1.208 +  // Synchronizes access to the mTimeMapping array.
   1.209 +  ReentrantMonitor mReentrantMonitor;
   1.210 +
   1.211 +  // Sorted (by offset) map of data offsets to timecodes.  Populated
   1.212 +  // on the main thread as data is received and parsed by WebMBufferedParsers.
   1.213 +  nsTArray<WebMTimeDataOffset> mTimeMapping;
   1.214 +
   1.215 +  // Sorted (by offset) live parser instances.  Main thread only.
   1.216 +  nsTArray<WebMBufferedParser> mRangeParsers;
   1.217 +};
   1.218 +
   1.219 +} // namespace mozilla
   1.220 +
   1.221 +#endif

mercurial