зеркало из https://github.com/mozilla/pjs.git
Bug 605457 - Remove concurrent use of Ogg stream hash table. r=cpearce a=roc
This commit is contained in:
Родитель
33c2068adb
Коммит
5309fd79ca
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче