|
|
|
|
| 34 |
* the provisions above, a recipient may use your version of this file under |
34 |
* the provisions above, a recipient may use your version of this file under |
| 35 |
* the terms of any one of the MPL, the GPL or the LGPL. |
35 |
* the terms of any one of the MPL, the GPL or the LGPL. |
| 36 |
* |
36 |
* |
| 37 |
* ***** END LICENSE BLOCK ***** */ |
37 |
* ***** END LICENSE BLOCK ***** */ |
| 38 |
|
38 |
|
| 39 |
#include "nsAlgorithm.h" |
39 |
#include "nsAlgorithm.h" |
| 40 |
#include "nsWebMBufferedParser.h" |
40 |
#include "nsWebMBufferedParser.h" |
| 41 |
#include "nsTimeRanges.h" |
41 |
#include "nsTimeRanges.h" |
|
|
42 |
#include "nsThreadUtils.h" |
| 43 |
|
| 44 |
using mozilla::MonitorAutoEnter; |
| 42 |
|
45 |
|
| 43 |
static const double NS_PER_S = 1e9; |
46 |
static const double NS_PER_S = 1e9; |
| 44 |
static const double MS_PER_S = 1e3; |
47 |
static const double MS_PER_S = 1e3; |
| 45 |
|
48 |
|
| 46 |
static PRUint32 |
49 |
static PRUint32 |
| 47 |
VIntLength(unsigned char aFirstByte, PRUint32* aMask) |
50 |
VIntLength(unsigned char aFirstByte, PRUint32* aMask) |
| 48 |
{ |
51 |
{ |
| 49 |
PRUint32 count = 1; |
52 |
PRUint32 count = 1; |
|
Lines 58-75
VIntLength(unsigned char aFirstByte, PRU
|
Link Here
|
|---|
|
| 58 |
if (aMask) { |
61 |
if (aMask) { |
| 59 |
*aMask = mask; |
62 |
*aMask = mask; |
| 60 |
} |
63 |
} |
| 61 |
NS_ASSERTION(count >= 1 && count <= 8, "Insane VInt length."); |
64 |
NS_ASSERTION(count >= 1 && count <= 8, "Insane VInt length."); |
| 62 |
return count; |
65 |
return count; |
| 63 |
} |
66 |
} |
| 64 |
|
67 |
|
| 65 |
void nsWebMBufferedParser::Append(const unsigned char* aBuffer, PRUint32 aLength, |
68 |
void nsWebMBufferedParser::Append(const unsigned char* aBuffer, PRUint32 aLength, |
| 66 |
nsTArray<nsWebMTimeDataOffset>& aMapping) |
69 |
nsTArray<nsWebMTimeDataOffset>& aMapping, |
|
|
70 |
Monitor& aMonitor) |
| 67 |
{ |
71 |
{ |
|
|
72 |
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
| 73 |
|
| 68 |
static const unsigned char CLUSTER_ID[] = { 0x1f, 0x43, 0xb6, 0x75 }; |
74 |
static const unsigned char CLUSTER_ID[] = { 0x1f, 0x43, 0xb6, 0x75 }; |
| 69 |
static const unsigned char TIMECODE_ID = 0xe7; |
75 |
static const unsigned char TIMECODE_ID = 0xe7; |
| 70 |
static const unsigned char BLOCKGROUP_ID = 0xa0; |
76 |
static const unsigned char BLOCKGROUP_ID = 0xa0; |
| 71 |
static const unsigned char BLOCK_ID = 0xa1; |
77 |
static const unsigned char BLOCK_ID = 0xa1; |
| 72 |
static const unsigned char SIMPLEBLOCK_ID = 0xa3; |
78 |
static const unsigned char SIMPLEBLOCK_ID = 0xa3; |
| 73 |
|
79 |
|
| 74 |
const unsigned char* p = aBuffer; |
80 |
const unsigned char* p = aBuffer; |
| 75 |
|
81 |
|
|
Lines 162-181
void nsWebMBufferedParser::Append(const
|
Link Here
|
|---|
|
| 162 |
case READ_BLOCK_TIMECODE: |
168 |
case READ_BLOCK_TIMECODE: |
| 163 |
if (mBlockTimecodeLength) { |
169 |
if (mBlockTimecodeLength) { |
| 164 |
mBlockTimecode <<= 8; |
170 |
mBlockTimecode <<= 8; |
| 165 |
mBlockTimecode |= *p++; |
171 |
mBlockTimecode |= *p++; |
| 166 |
mBlockTimecodeLength -= 1; |
172 |
mBlockTimecodeLength -= 1; |
| 167 |
} else { |
173 |
} else { |
| 168 |
// It's possible we've parsed this data before, so avoid inserting |
174 |
// It's possible we've parsed this data before, so avoid inserting |
| 169 |
// duplicate nsWebMTimeDataOffset entries. |
175 |
// duplicate nsWebMTimeDataOffset entries. |
| 170 |
PRUint32 idx; |
176 |
{ |
| 171 |
if (!aMapping.GreatestIndexLtEq(mBlockOffset, idx)) { |
177 |
MonitorAutoEnter mon(aMonitor); |
| 172 |
nsWebMTimeDataOffset entry(mBlockOffset, mClusterTimecode + mBlockTimecode); |
178 |
PRUint32 idx; |
| 173 |
aMapping.InsertElementAt(idx, entry); |
179 |
if (!aMapping.GreatestIndexLtEq(mBlockOffset, idx)) { |
|
|
180 |
nsWebMTimeDataOffset entry(mBlockOffset, mClusterTimecode + mBlockTimecode); |
| 181 |
aMapping.InsertElementAt(idx, entry); |
| 182 |
} |
| 174 |
} |
183 |
} |
| 175 |
|
184 |
|
| 176 |
// Skip rest of block header and the block's payload. |
185 |
// Skip rest of block header and the block's payload. |
| 177 |
mBlockSize -= mVIntLength; |
186 |
mBlockSize -= mVIntLength; |
| 178 |
mBlockSize -= 2; |
187 |
mBlockSize -= 2; |
| 179 |
mSkipBytes = PRUint32(mBlockSize); |
188 |
mSkipBytes = PRUint32(mBlockSize); |
| 180 |
mState = SKIP_DATA; |
189 |
mState = SKIP_DATA; |
| 181 |
mNextState = ANY_BLOCK_SYNC; |
190 |
mNextState = ANY_BLOCK_SYNC; |
|
Lines 203-218
void nsWebMBufferedParser::Append(const
|
Link Here
|
|---|
|
| 203 |
mCurrentOffset += aLength; |
212 |
mCurrentOffset += aLength; |
| 204 |
} |
213 |
} |
| 205 |
|
214 |
|
| 206 |
void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered, |
215 |
void nsWebMBufferedState::CalculateBufferedForRange(nsTimeRanges* aBuffered, |
| 207 |
PRInt64 aStartOffset, PRInt64 aEndOffset, |
216 |
PRInt64 aStartOffset, PRInt64 aEndOffset, |
| 208 |
PRUint64 aTimecodeScale, |
217 |
PRUint64 aTimecodeScale, |
| 209 |
PRInt64 aStartTimeOffsetNS) |
218 |
PRInt64 aStartTimeOffsetNS) |
| 210 |
{ |
219 |
{ |
|
|
220 |
MonitorAutoEnter mon(mMonitor); |
| 221 |
|
| 211 |
// Find the first nsWebMTimeDataOffset at or after aStartOffset. |
222 |
// Find the first nsWebMTimeDataOffset at or after aStartOffset. |
| 212 |
PRUint32 start; |
223 |
PRUint32 start; |
| 213 |
mTimeMapping.GreatestIndexLtEq(aStartOffset, start); |
224 |
mTimeMapping.GreatestIndexLtEq(aStartOffset, start); |
| 214 |
if (start == mTimeMapping.Length()) { |
225 |
if (start == mTimeMapping.Length()) { |
| 215 |
return; |
226 |
return; |
| 216 |
} |
227 |
} |
| 217 |
|
228 |
|
| 218 |
// Find the first nsWebMTimeDataOffset at or before aEndOffset. |
229 |
// Find the first nsWebMTimeDataOffset at or before aEndOffset. |
|
Lines 246-261
void nsWebMBufferedState::CalculateBuffe
|
Link Here
|
|---|
|
| 246 |
|
257 |
|
| 247 |
double startTime = (mTimeMapping[start].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; |
258 |
double startTime = (mTimeMapping[start].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; |
| 248 |
double endTime = (mTimeMapping[end].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; |
259 |
double endTime = (mTimeMapping[end].mTimecode * aTimecodeScale - aStartTimeOffsetNS) / NS_PER_S; |
| 249 |
aBuffered->Add(startTime, endTime); |
260 |
aBuffered->Add(startTime, endTime); |
| 250 |
} |
261 |
} |
| 251 |
|
262 |
|
| 252 |
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) |
263 |
void nsWebMBufferedState::NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) |
| 253 |
{ |
264 |
{ |
|
|
265 |
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); |
| 254 |
PRUint32 idx; |
266 |
PRUint32 idx; |
| 255 |
if (!mRangeParsers.GreatestIndexLtEq(aOffset, idx)) { |
267 |
if (!mRangeParsers.GreatestIndexLtEq(aOffset, idx)) { |
| 256 |
// If the incoming data overlaps an already parsed range, adjust the |
268 |
// If the incoming data overlaps an already parsed range, adjust the |
| 257 |
// buffer so that we only reparse the new data. It's also possible to |
269 |
// buffer so that we only reparse the new data. It's also possible to |
| 258 |
// have an overlap where the end of the incoming data is within an |
270 |
// have an overlap where the end of the incoming data is within an |
| 259 |
// already parsed range, but we don't bother handling that other than by |
271 |
// already parsed range, but we don't bother handling that other than by |
| 260 |
// avoiding storing duplicate timecodes when the parser runs. |
272 |
// avoiding storing duplicate timecodes when the parser runs. |
| 261 |
if (idx != mRangeParsers.Length() && mRangeParsers[idx].mStartOffset <= aOffset) { |
273 |
if (idx != mRangeParsers.Length() && mRangeParsers[idx].mStartOffset <= aOffset) { |
|
Lines 269-285
void nsWebMBufferedState::NotifyDataArri
|
Link Here
|
|---|
|
| 269 |
NS_ASSERTION(adjust >= 0, "Overlap detection bug."); |
281 |
NS_ASSERTION(adjust >= 0, "Overlap detection bug."); |
| 270 |
aBuffer += adjust; |
282 |
aBuffer += adjust; |
| 271 |
aLength -= PRUint32(adjust); |
283 |
aLength -= PRUint32(adjust); |
| 272 |
} else { |
284 |
} else { |
| 273 |
mRangeParsers.InsertElementAt(idx, nsWebMBufferedParser(aOffset)); |
285 |
mRangeParsers.InsertElementAt(idx, nsWebMBufferedParser(aOffset)); |
| 274 |
} |
286 |
} |
| 275 |
} |
287 |
} |
| 276 |
|
288 |
|
| 277 |
mRangeParsers[idx].Append(reinterpret_cast<const unsigned char*>(aBuffer), aLength, mTimeMapping); |
289 |
mRangeParsers[idx].Append(reinterpret_cast<const unsigned char*>(aBuffer), |
|
|
290 |
aLength, |
| 291 |
mTimeMapping, |
| 292 |
mMonitor); |
| 278 |
|
293 |
|
| 279 |
// Merge parsers with overlapping regions and clean up the remnants. |
294 |
// Merge parsers with overlapping regions and clean up the remnants. |
| 280 |
PRUint32 i = 0; |
295 |
PRUint32 i = 0; |
| 281 |
while (i + 1 < mRangeParsers.Length()) { |
296 |
while (i + 1 < mRangeParsers.Length()) { |
| 282 |
if (mRangeParsers[i].mCurrentOffset >= mRangeParsers[i + 1].mStartOffset) { |
297 |
if (mRangeParsers[i].mCurrentOffset >= mRangeParsers[i + 1].mStartOffset) { |
| 283 |
mRangeParsers[i + 1].mStartOffset = mRangeParsers[i].mStartOffset; |
298 |
mRangeParsers[i + 1].mStartOffset = mRangeParsers[i].mStartOffset; |
| 284 |
mRangeParsers.RemoveElementAt(i); |
299 |
mRangeParsers.RemoveElementAt(i); |
| 285 |
} else { |
300 |
} else { |