Bug 605457 - Remove concurrent use of Ogg stream hash table. r=cpearce a=roc

This commit is contained in:
Matthew Gregan 2010-12-17 14:39:01 +13:00
Родитель 33c2068adb
Коммит 5309fd79ca
4 изменённых файлов: 99 добавлений и 13 удалений

Просмотреть файл

@ -233,18 +233,36 @@ nsTheoraState::DecodeHeader(ogg_packet* aPacket)
PRInt64
nsTheoraState::Time(PRInt64 granulepos) {
if (granulepos < 0 || !mActive || mInfo.fps_numerator == 0) {
if (!mActive) {
return -1;
}
return nsTheoraState::Time(&mInfo, granulepos);
}
# define TH_VERSION_CHECK(_info,_maj,_min,_sub) \
((_info)->version_major>(_maj)||(_info)->version_major==(_maj)&& \
((_info)->version_minor>(_min)||(_info)->version_minor==(_min)&& \
(_info)->version_subminor>=(_sub)))
PRInt64 nsTheoraState::Time(th_info* aInfo, PRInt64 aGranulepos)
{
if (aGranulepos < 0 || aInfo->fps_numerator == 0) {
return -1;
}
PRInt64 t = 0;
PRInt64 frameno = th_granule_frame(mCtx, granulepos);
// Implementation of th_granule_frame inlined here to operate
// on the th_info structure instead of the theora_state.
int shift = aInfo->keyframe_granule_shift;
ogg_int64_t iframe = aGranulepos >> shift;
ogg_int64_t pframe = aGranulepos - (iframe << shift);
PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1);
if (!AddOverflow(frameno, 1, t))
return -1;
if (!MulOverflow(t, 1000, t))
return -1;
if (!MulOverflow(t, mInfo.fps_denominator, t))
if (!MulOverflow(t, aInfo->fps_denominator, t))
return -1;
return t / mInfo.fps_numerator;
return t / aInfo->fps_numerator;
}
PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
@ -373,12 +391,21 @@ PRBool nsVorbisState::Init()
PRInt64 nsVorbisState::Time(PRInt64 granulepos)
{
if (granulepos == -1 || !mActive || mDsp.vi->rate == 0) {
if (!mActive) {
return -1;
}
return nsVorbisState::Time(&mInfo, granulepos);
}
PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos)
{
if (aGranulepos == -1 || aInfo->rate == 0) {
return -1;
}
PRInt64 t = 0;
MulOverflow(1000, granulepos, t);
return t / mDsp.vi->rate;
MulOverflow(1000, aGranulepos, t);
return t / aInfo->rate;
}
nsSkeletonState::nsSkeletonState(ogg_page* aBosPage)

Просмотреть файл

@ -163,6 +163,9 @@ public:
virtual PRBool Init();
virtual nsresult Reset();
// Returns the end time that a granulepos represents.
static PRInt64 Time(vorbis_info* aInfo, PRInt64 aGranulePos);
vorbis_info mInfo;
vorbis_comment mComment;
vorbis_dsp_state mDsp;
@ -184,6 +187,9 @@ public:
// from any given interframe.
PRInt64 MaxKeyframeOffset();
// Returns the end time that a granulepos represents.
static PRInt64 Time(th_info* aInfo, PRInt64 aGranulePos);
th_info mInfo;
th_comment mComment;
th_setup_info *mSetup;

Просмотреть файл

@ -102,6 +102,8 @@ nsOggReader::nsOggReader(nsBuiltinDecoder* aDecoder)
mTheoraState(nsnull),
mVorbisState(nsnull),
mSkeletonState(nsnull),
mVorbisSerial(0),
mTheoraSerial(0),
mPageOffset(0),
mTheoraGranulepos(-1),
mVorbisGranulepos(-1)
@ -204,6 +206,7 @@ nsresult nsOggReader::ReadMetadata()
PRBool r = mCodecStates.Put(serial, codecState);
NS_ASSERTION(r, "Failed to insert into mCodecStates");
bitstreams.AppendElement(codecState);
mKnownStreams.AppendElement(serial);
if (codecState &&
codecState->GetType() == nsOggCodecState::TYPE_VORBIS &&
!mVorbisState)
@ -335,6 +338,18 @@ nsresult nsOggReader::ReadMetadata()
}
}
// Copy Vorbis and Theora info data for time computations on other threads.
if (mVorbisState) {
memcpy(&mVorbisInfo, &mVorbisState->mInfo, sizeof(mVorbisInfo));
mVorbisInfo.codec_setup = NULL;
mVorbisSerial = mVorbisState->mSerial;
}
if (mTheoraState) {
memcpy(&mTheoraInfo, &mTheoraState->mInfo, sizeof(mTheoraInfo));
mTheoraSerial = mTheoraState->mSerial;
}
LOG(PR_LOG_DEBUG, ("Done loading headers, data offset %lld", mDataOffset));
return NS_OK;
@ -1601,14 +1616,17 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
}
PRUint32 serial = ogg_page_serialno(&page);
nsOggCodecState* codecState = nsnull;
mCodecStates.Get(serial, &codecState);
if (codecState && codecState->mActive) {
startTime = codecState->Time(granulepos) - aStartTime;
if (serial == mVorbisSerial) {
startTime = nsVorbisState::Time(&mVorbisInfo, granulepos) - aStartTime;
NS_ASSERTION(startTime > 0, "Must have positive start time");
}
else if(codecState) {
// Page is for an inactive stream, skip it.
else if (serial == mTheoraSerial) {
startTime = nsTheoraState::Time(&mTheoraInfo, granulepos) - aStartTime;
NS_ASSERTION(startTime > 0, "Must have positive start time");
}
else if (IsKnownStream(serial)) {
// Stream is not the theora or vorbis stream we're playing,
// but is one that we have header data for.
startOffset += page.header_len + page.body_len;
continue;
}
@ -1639,3 +1657,18 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime)
return NS_OK;
}
PRBool nsOggReader::IsKnownStream(PRUint32 aSerial)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
for (PRUint32 i = 0; i < mKnownStreams.Length(); i++) {
PRUint32 serial = mKnownStreams[i];
if (serial == aSerial) {
return PR_TRUE;
}
}
return PR_FALSE;
}

Просмотреть файл

@ -181,10 +181,20 @@ private:
const ByteRange& aRange,
PRUint32 aFuzz);
// Returns true if the serial number is for a stream we encountered
// while reading metadata. Call on the main thread only.
PRBool IsKnownStream(PRUint32 aSerial);
private:
// Maps Ogg serialnos to nsOggStreams.
nsClassHashtable<nsUint32HashKey, nsOggCodecState> mCodecStates;
// Array of serial numbers of streams that were encountered during
// initial metadata load. Written on state machine thread during
// metadata loading and read on the main thread only after metadata
// is loaded.
nsAutoTArray<PRUint32,4> mKnownStreams;
// Decode state of the Theora bitstream we're decoding, if we have video.
nsTheoraState* mTheoraState;
@ -197,6 +207,16 @@ private:
// Ogg decoding state.
ogg_sync_state mOggState;
// Vorbis/Theora data used to compute timestamps. This is written on the
// decoder thread and read on the main thread. All reading on the
// main thread must be done after metadataloaded. We can't use the
// existing data in the codec states due to threading issues.
// See bug 605457.
PRUint32 mVorbisSerial;
PRUint32 mTheoraSerial;
vorbis_info mVorbisInfo;
th_info mTheoraInfo;
// The offset of the end of the last page we've read, or the start of
// the page we're about to read.
PRInt64 mPageOffset;