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