Bug 1195073: [webm] P6. Calculate cluster's end offset if its size is known in advance. r=kinetik.

This allows to detect the end of a webm media segment without having to wait for the start of a new one.
Also record where an init segment (EBML) starts as this will be required by the WebM ContainerParser.
This commit is contained in:
Jean-Yves Avenard 2015-08-23 20:46:08 +10:00
parent 98864bb30c
commit be2837a7a6
2 changed files with 52 additions and 8 deletions

View File

@ -34,6 +34,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
nsTArray<WebMTimeDataOffset>& aMapping,
ReentrantMonitor& aReentrantMonitor)
{
static const uint32_t EBML_ID = 0x1a45dfa3;
static const uint32_t SEGMENT_ID = 0x18538067;
static const uint32_t SEGINFO_ID = 0x1549a966;
static const uint32_t TRACKS_ID = 0x1654AE6B;
@ -102,6 +103,12 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
case CLUSTER_ID:
mClusterOffset = mCurrentOffset + (p - aBuffer) -
(mElement.mID.mLength + mElement.mSize.mLength);
// Handle "unknown" length;
if (mElement.mSize.mValue + 1 != uint64_t(1) << (mElement.mSize.mLength * 7)) {
mClusterEndOffset = mClusterOffset + mElement.mID.mLength + mElement.mSize.mLength + mElement.mSize.mValue;
} else {
mClusterEndOffset = -1;
}
mState = READ_ELEMENT_ID;
break;
case SIMPLEBLOCK_ID:
@ -119,6 +126,10 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
mSkipBytes = mElement.mSize.mValue;
mState = CHECK_INIT_FOUND;
break;
case EBML_ID:
mLastInitStartOffset = mCurrentOffset + (p - aBuffer) -
(mElement.mID.mLength + mElement.mSize.mLength);
/* FALLTHROUGH */
default:
mSkipBytes = mElement.mSize.mValue;
mState = SKIP_DATA;
@ -172,7 +183,8 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
MOZ_ASSERT(mGotTimecodeScale);
uint64_t absTimecode = mClusterTimecode + mBlockTimecode;
absTimecode *= mTimecodeScale;
WebMTimeDataOffset entry(endOffset, absTimecode, mClusterOffset);
WebMTimeDataOffset entry(endOffset, absTimecode, mLastInitStartOffset,
mClusterOffset, mClusterEndOffset);
aMapping.InsertElementAt(idx, entry);
}
}
@ -220,6 +232,16 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
mCurrentOffset += aLength;
}
int64_t
WebMBufferedParser::EndSegmentOffset(int64_t aOffset)
{
if (mLastInitStartOffset > aOffset || mClusterOffset > aOffset) {
return std::min(mLastInitStartOffset >= 0 ? mLastInitStartOffset : INT64_MAX,
mClusterOffset >= 0 ? mClusterOffset : INT64_MAX);
}
return mBlockEndOffset;
}
// 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.

View File

@ -17,8 +17,14 @@ namespace mozilla {
// that offset.
struct WebMTimeDataOffset
{
WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode, int64_t aSyncOffset)
: mEndOffset(aEndOffset), mSyncOffset(aSyncOffset), mTimecode(aTimecode)
WebMTimeDataOffset(int64_t aEndOffset, uint64_t aTimecode,
int64_t aInitOffset, int64_t aSyncOffset,
int64_t aClusterEndOffset)
: mEndOffset(aEndOffset)
, mInitOffset(aInitOffset)
, mSyncOffset(aSyncOffset)
, mClusterEndOffset(aClusterEndOffset)
, mTimecode(aTimecode)
{}
bool operator==(int64_t aEndOffset) const {
@ -34,7 +40,9 @@ struct WebMTimeDataOffset
}
int64_t mEndOffset;
int64_t mInitOffset;
int64_t mSyncOffset;
int64_t mClusterEndOffset;
uint64_t mTimecode;
};
@ -53,7 +61,9 @@ struct WebMBufferedParser
, mBlockEndOffset(-1)
, mState(READ_ELEMENT_ID)
, mVIntRaw(false)
, mLastInitStartOffset(-1)
, mClusterSyncPos(0)
, mClusterEndOffset(-1)
, mTimecodeScale(1000000)
, mGotTimecodeScale(false)
{
@ -89,21 +99,26 @@ 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);
// 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 with the stream. Updated in chunks as Append() consumes
// Current offset within the stream. Updated in chunks as Append() consumes
// data.
int64_t mCurrentOffset;
// Tracks element's end offset. This indicates the end of the init segment.
// Will only be set if a Segment Information has been found.
// Tracks element's end offset. This indicates the end of the first init
// segment. Will only be set if a Segment Information has been found.
int64_t mInitEndOffset;
// End offset of the last block.
// Will only be set if a full block has been parsed.
// End offset of the last block parsed.
// Will only be set if a complete block has been parsed.
int64_t mBlockEndOffset;
private:
@ -185,6 +200,10 @@ private:
bool mVIntRaw;
// EBML start offset. This indicates the start of the last init segment
// parsed. Will only be set if an EBML element has been found.
int64_t mLastInitStartOffset;
// Current match position within CLUSTER_SYNC_ID. Used to find sync
// within arbitrary data.
uint32_t mClusterSyncPos;
@ -205,6 +224,9 @@ private:
// been parsed.
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.