diff --git a/content/media/nsMediaCache.cpp b/content/media/nsMediaCache.cpp index f0a0b54a285..e1066cb2dbb 100644 --- a/content/media/nsMediaCache.cpp +++ b/content/media/nsMediaCache.cpp @@ -159,6 +159,9 @@ public: // call QueueUpdate(). void NoteBlockUsage(nsMediaCacheStream* aStream, PRInt32 aBlockIndex, nsMediaCacheStream::ReadMode aMode, TimeStamp aNow); + // Mark aStream as having the block, adding it as an owner. + void AddBlockOwnerAsReadahead(PRInt32 aBlockIndex, nsMediaCacheStream* aStream, + PRInt32 aStreamBlockIndex); // This queues a call to Update() on the main thread. void QueueUpdate(); @@ -840,6 +843,23 @@ nsMediaCache::RemoveBlockOwner(PRInt32 aBlockIndex, nsMediaCacheStream* aStream) } } +void +nsMediaCache::AddBlockOwnerAsReadahead(PRInt32 aBlockIndex, + nsMediaCacheStream* aStream, + PRInt32 aStreamBlockIndex) +{ + Block* block = &mIndex[aBlockIndex]; + if (block->mOwners.IsEmpty()) { + mFreeBlocks.RemoveBlock(aBlockIndex); + } + BlockOwner* bo = block->mOwners.AppendElement(); + bo->mStream = aStream; + bo->mStreamBlock = aStreamBlockIndex; + aStream->mBlocks[aStreamBlockIndex] = aBlockIndex; + bo->mClass = READAHEAD_BLOCK; + InsertReadaheadBlock(bo, aBlockIndex); +} + void nsMediaCache::FreeBlock(PRInt32 aBlock) { @@ -1996,9 +2016,44 @@ nsMediaCacheStream::Init() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + if (mInitialized) + return NS_OK; + InitMediaCache(); if (!gMediaCache) return NS_ERROR_FAILURE; gMediaCache->OpenStream(this); + mInitialized = PR_TRUE; + return NS_OK; +} + +nsresult +nsMediaCacheStream::InitAsClone(nsMediaCacheStream* aOriginal) +{ + if (mInitialized) + return NS_OK; + + nsresult rv = Init(); + if (NS_FAILED(rv)) + return rv; + + // Grab cache blocks from aOriginal as readahead blocks for our stream + nsAutoMonitor mon(gMediaCache->Monitor()); + + mPrincipal = aOriginal->mPrincipal; + mStreamLength = aOriginal->mStreamLength; + mIsSeekable = aOriginal->mIsSeekable; + + for (PRUint32 i = 0; i < aOriginal->mBlocks.Length(); ++i) { + PRInt32 cacheBlockIndex = aOriginal->mBlocks[i]; + if (cacheBlockIndex < 0) + continue; + + while (i >= mBlocks.Length()) { + mBlocks.AppendElement(-1); + } + gMediaCache->AddBlockOwnerAsReadahead(cacheBlockIndex, this, i); + } + return NS_OK; } diff --git a/content/media/nsMediaCache.h b/content/media/nsMediaCache.h index f2e53c0b6a7..b8da8edc19f 100644 --- a/content/media/nsMediaCache.h +++ b/content/media/nsMediaCache.h @@ -222,17 +222,24 @@ public: nsMediaCacheStream(nsMediaChannelStream* aClient) : mClient(aClient), mChannelOffset(0), mStreamOffset(0), mStreamLength(-1), mPlaybackBytesPerSecond(10000), - mPinCount(0), mCurrentMode(MODE_PLAYBACK), mClosed(PR_FALSE), + mPinCount(0), mCurrentMode(MODE_PLAYBACK), + mInitialized(PR_FALSE), mClosed(PR_FALSE), mIsSeekable(PR_FALSE), mCacheSuspended(PR_FALSE), mMetadataInPartialBlockBuffer(PR_FALSE), mUsingNullPrincipal(PR_FALSE) {} ~nsMediaCacheStream(); - // Set up this stream with the cache. Can fail on OOM. Must be called - // before other methods on this object; no other methods may be called - // if this fails. + // Set up this stream with the cache. Can fail on OOM. One + // of InitAsClone or Init must be called before any other method on + // this class. Does nothing if already initialized. nsresult Init(); + // Set up this stream with the cache, assuming it's for the same data + // as the aOriginal stream. Can fail on OOM. Exactly one + // of InitAsClone or Init must be called before any other method on + // this class. Does nothing if already initialized. + nsresult InitAsClone(nsMediaCacheStream* aOriginal); + // These are called on the main thread. // Tell us whether the stream is seekable or not. Non-seekable streams // will always pass 0 for aOffset to CacheClientSeek. This should only @@ -447,6 +454,8 @@ private: PRUint32 mPinCount; // The last reported read mode ReadMode mCurrentMode; + // Set to true when Init or InitAsClone has been called + PRPackedBool mInitialized; // Set to true when the stream has been closed either explicitly or // due to an internal cache error PRPackedBool mClosed; diff --git a/content/media/nsMediaStream.cpp b/content/media/nsMediaStream.cpp index dc463d1c584..4c1dd0b4499 100644 --- a/content/media/nsMediaStream.cpp +++ b/content/media/nsMediaStream.cpp @@ -452,7 +452,7 @@ nsMediaStream* nsMediaChannelStream::CloneData(nsMediaDecoder* aDecoder) nsMediaChannelStream* stream = new nsMediaChannelStream(aDecoder, nsnull, mURI); if (stream) { stream->RecreateChannel(); - // XXXroc need to clone mCacheStream's data here + stream->mCacheStream.InitAsClone(&mCacheStream); } return stream; } @@ -614,28 +614,6 @@ nsMediaChannelStream::CacheClientSeek(PRInt64 aOffset, PRBool aResume) return OpenChannel(nsnull); } -class SuspendedStatusChanged : public nsRunnable -{ -public: - SuspendedStatusChanged(nsMediaDecoder* aDecoder) : - mDecoder(aDecoder) - { - MOZ_COUNT_CTOR(SuspendedStatusChanged); - } - ~SuspendedStatusChanged() - { - MOZ_COUNT_DTOR(SuspendedStatusChanged); - } - - NS_IMETHOD Run() { - mDecoder->NotifySuspendedStatusChanged(); - return NS_OK; - } - -private: - nsRefPtr mDecoder; -}; - nsresult nsMediaChannelStream::CacheClientSuspend() { @@ -648,7 +626,8 @@ nsMediaChannelStream::CacheClientSuspend() // We have to spawn an event here since we're being called back from // a sensitive place in nsMediaCache, which doesn't want us to reenter // the decoder and cause deadlocks or other unpleasantness - nsCOMPtr event = new SuspendedStatusChanged(mDecoder); + nsCOMPtr event = + NS_NEW_RUNNABLE_METHOD(nsMediaDecoder, mDecoder, NotifySuspendedStatusChanged); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); return NS_OK; } @@ -665,7 +644,8 @@ nsMediaChannelStream::CacheClientResume() // We have to spawn an event here since we're being called back from // a sensitive place in nsMediaCache, which doesn't want us to reenter // the decoder and cause deadlocks or other unpleasantness - nsCOMPtr event = new SuspendedStatusChanged(mDecoder); + nsCOMPtr event = + NS_NEW_RUNNABLE_METHOD(nsMediaDecoder, mDecoder, NotifySuspendedStatusChanged); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); return NS_OK; }