mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug Bug 713381 - backout 38271572005b,d5ebbc25b4b8,6435f51dd10d. r=backout
This commit is contained in:
parent
c7db97f406
commit
feca30f47a
@ -1999,7 +1999,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
|
||||
LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
|
||||
|
||||
if (!decoder->Init(this)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get()));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -2011,7 +2010,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
|
||||
|
||||
nsMediaStream* stream = originalStream->CloneData(decoder);
|
||||
if (!stream) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -2019,7 +2017,6 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
|
||||
|
||||
nsresult rv = decoder->Load(stream, nsnull, aOriginal);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to load decoder/stream for decoder %p", this, decoder.get()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -193,7 +193,6 @@ nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
|
||||
|
||||
nsresult rv = aStream->Open(aStreamListener);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
|
||||
delete aStream;
|
||||
return rv;
|
||||
}
|
||||
@ -246,7 +245,6 @@ nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
NS_ASSERTION(mDecoderStateMachine,
|
||||
"Must have state machine to start state machine thread");
|
||||
NS_ENSURE_STATE(mDecoderStateMachine);
|
||||
|
||||
if (mShuttingDown)
|
||||
return NS_OK;
|
||||
@ -260,7 +258,6 @@ nsresult nsBuiltinDecoder::Play()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
NS_ASSERTION(mDecoderStateMachine != nsnull, "Should have state machine.");
|
||||
nsresult res = ScheduleStateMachineThread();
|
||||
NS_ENSURE_SUCCESS(res,res);
|
||||
if (mPlayState == PLAY_STATE_SEEKING) {
|
||||
@ -835,19 +832,29 @@ void nsBuiltinDecoder::ChangeState(PlayState aState)
|
||||
}
|
||||
|
||||
mPlayState = aState;
|
||||
if (mDecoderStateMachine) {
|
||||
switch (aState) {
|
||||
case PLAY_STATE_PLAYING:
|
||||
mDecoderStateMachine->Play();
|
||||
break;
|
||||
case PLAY_STATE_SEEKING:
|
||||
mDecoderStateMachine->Seek(mRequestedSeekTime);
|
||||
mRequestedSeekTime = -1.0;
|
||||
break;
|
||||
default:
|
||||
/* No action needed */
|
||||
break;
|
||||
}
|
||||
switch (aState) {
|
||||
case PLAY_STATE_PAUSED:
|
||||
/* No action needed */
|
||||
break;
|
||||
case PLAY_STATE_PLAYING:
|
||||
mDecoderStateMachine->Play();
|
||||
break;
|
||||
case PLAY_STATE_SEEKING:
|
||||
mDecoderStateMachine->Seek(mRequestedSeekTime);
|
||||
mRequestedSeekTime = -1.0;
|
||||
break;
|
||||
case PLAY_STATE_LOADING:
|
||||
/* No action needed */
|
||||
break;
|
||||
case PLAY_STATE_START:
|
||||
/* No action needed */
|
||||
break;
|
||||
case PLAY_STATE_ENDED:
|
||||
/* No action needed */
|
||||
break;
|
||||
case PLAY_STATE_SHUTDOWN:
|
||||
/* No action needed */
|
||||
break;
|
||||
}
|
||||
mReentrantMonitor.NotifyAll();
|
||||
}
|
||||
@ -966,9 +973,7 @@ void nsBuiltinDecoder::Resume(bool aForceBuffering)
|
||||
}
|
||||
if (aForceBuffering) {
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (mDecoderStateMachine) {
|
||||
mDecoderStateMachine->StartBuffering();
|
||||
}
|
||||
mDecoderStateMachine->StartBuffering();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "nsTimeRanges.h"
|
||||
#include "nsDeque.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StdInt.h"
|
||||
@ -230,17 +229,6 @@ public:
|
||||
return mStateMachineThread;
|
||||
}
|
||||
|
||||
// Requests that a decode thread be created for aStateMachine. The thread
|
||||
// may be created immediately, or after some delay, once a thread becomes
|
||||
// available. The request can be cancelled using CancelCreateDecodeThread().
|
||||
// It's the callers responsibility to not call this more than once for any
|
||||
// given state machine.
|
||||
nsresult RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
|
||||
|
||||
// Cancels a request made by RequestCreateDecodeThread to create a decode
|
||||
// thread for aStateMachine.
|
||||
nsresult CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
|
||||
|
||||
// Maximum number of active decode threads allowed. When more
|
||||
// than this number are active the thread creation will fail.
|
||||
static const PRUint32 MAX_DECODE_THREADS = 25;
|
||||
@ -250,17 +238,16 @@ public:
|
||||
// call with any other monitor held to avoid deadlock.
|
||||
PRUint32 GetDecodeThreadCount();
|
||||
|
||||
// Keep track of the fact that a decode thread was created.
|
||||
// Call on any thread. Holds the internal monitor so don't
|
||||
// call with any other monitor held to avoid deadlock.
|
||||
void NoteDecodeThreadCreated();
|
||||
|
||||
// Keep track of the fact that a decode thread was destroyed.
|
||||
// Call on any thread. Holds the internal monitor so don't
|
||||
// call with any other monitor held to avoid deadlock.
|
||||
void NoteDecodeThreadDestroyed();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Returns true if aStateMachine has a pending request for a
|
||||
// decode thread.
|
||||
bool IsQueued(nsBuiltinDecoderStateMachine* aStateMachine);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Holds global instance of StateMachineTracker.
|
||||
// Writable on main thread only.
|
||||
@ -284,10 +271,6 @@ private:
|
||||
// only, read from the decoder threads. Synchronized via
|
||||
// the mMonitor.
|
||||
nsIThread* mStateMachineThread;
|
||||
|
||||
// Queue of state machines waiting for decode threads. Entries at the front
|
||||
// get their threads first.
|
||||
nsDeque mPending;
|
||||
};
|
||||
|
||||
StateMachineTracker* StateMachineTracker::mInstance = nsnull;
|
||||
@ -313,23 +296,7 @@ void StateMachineTracker::EnsureGlobalStateMachine()
|
||||
}
|
||||
mStateMachineCount++;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool StateMachineTracker::IsQueued(nsBuiltinDecoderStateMachine* aStateMachine)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
PRInt32 size = mPending.GetSize();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
nsBuiltinDecoderStateMachine* m =
|
||||
static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
|
||||
if (m == aStateMachine) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void StateMachineTracker::CleanupGlobalStateMachine()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
@ -338,7 +305,6 @@ void StateMachineTracker::CleanupGlobalStateMachine()
|
||||
mStateMachineCount--;
|
||||
if (mStateMachineCount == 0) {
|
||||
LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
|
||||
NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mStateMachineThread);
|
||||
@ -353,22 +319,16 @@ void StateMachineTracker::CleanupGlobalStateMachine()
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachineTracker::NoteDecodeThreadCreated()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
++mDecodeThreadCount;
|
||||
}
|
||||
|
||||
void StateMachineTracker::NoteDecodeThreadDestroyed()
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
--mDecodeThreadCount;
|
||||
while (mDecodeThreadCount < MAX_DECODE_THREADS && mPending.GetSize() > 0) {
|
||||
nsBuiltinDecoderStateMachine* m =
|
||||
static_cast<nsBuiltinDecoderStateMachine*>(mPending.PopFront());
|
||||
nsresult rv;
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mMonitor);
|
||||
rv = m->StartDecodeThread();
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
++mDecodeThreadCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 StateMachineTracker::GetDecodeThreadCount()
|
||||
@ -377,45 +337,6 @@ PRUint32 StateMachineTracker::GetDecodeThreadCount()
|
||||
return mDecodeThreadCount;
|
||||
}
|
||||
|
||||
nsresult StateMachineTracker::CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine) {
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
PRInt32 size = mPending.GetSize();
|
||||
for (PRInt32 i = 0; i < size; ++i) {
|
||||
void* m = static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
|
||||
if (m == aStateMachine) {
|
||||
mPending.RemoveObjectAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(!IsQueued(aStateMachine), "State machine should no longer have queued request.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult StateMachineTracker::RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine)
|
||||
{
|
||||
NS_ENSURE_STATE(aStateMachine);
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
if (mPending.GetSize() > 0 || mDecodeThreadCount + 1 >= MAX_DECODE_THREADS) {
|
||||
// If there's already state machines in the queue, or we've exceeded the
|
||||
// limit, append the state machine to the queue of state machines waiting
|
||||
// for a decode thread. This ensures state machines already waiting get
|
||||
// their threads first.
|
||||
mPending.Push(aStateMachine);
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult rv;
|
||||
{
|
||||
ReentrantMonitorAutoExit exitMon(mMonitor);
|
||||
rv = aStateMachine->StartDecodeThread();
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
++mDecodeThreadCount;
|
||||
}
|
||||
NS_ASSERTION(mDecodeThreadCount <= MAX_DECODE_THREADS,
|
||||
"Should keep to thread limit!");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder,
|
||||
nsBuiltinDecoderReader* aReader,
|
||||
bool aRealTime) :
|
||||
@ -446,7 +367,6 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
|
||||
mDispatchedRunEvent(false),
|
||||
mDecodeThreadWaiting(false),
|
||||
mRealTime(aRealTime),
|
||||
mRequestedNewDecodeThread(false),
|
||||
mEventManager(aDecoder)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
|
||||
@ -466,10 +386,6 @@ nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
|
||||
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
|
||||
"Should not have a pending request for a new decode thread");
|
||||
NS_ASSERTION(!mRequestedNewDecodeThread,
|
||||
"Should not have (or flagged) a pending request for a new decode thread");
|
||||
if (mTimer)
|
||||
mTimer->Cancel();
|
||||
mTimer = nsnull;
|
||||
@ -1271,14 +1187,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
if (mRequestedNewDecodeThread) {
|
||||
// We've requested that the decode be created, but it hasn't been yet.
|
||||
// Cancel that request.
|
||||
NS_ASSERTION(!mDecodeThread,
|
||||
"Shouldn't have a decode thread until after request processed");
|
||||
StateMachineTracker::Instance().CancelCreateDecodeThread(this);
|
||||
mRequestedNewDecodeThread = false;
|
||||
}
|
||||
mStopDecodeThread = true;
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
if (mDecodeThread) {
|
||||
@ -1291,10 +1199,6 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
|
||||
mDecodeThread = nsnull;
|
||||
mDecodeThreadIdle = false;
|
||||
}
|
||||
NS_ASSERTION(!mRequestedNewDecodeThread,
|
||||
"Any pending requests for decode threads must be canceled and unflagged");
|
||||
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
|
||||
"Any pending requests for decode threads must be canceled");
|
||||
}
|
||||
|
||||
void nsBuiltinDecoderStateMachine::StopAudioThread()
|
||||
@ -1313,68 +1217,52 @@ void nsBuiltinDecoderStateMachine::StopAudioThread()
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBuiltinDecoderStateMachine::ScheduleDecodeThread()
|
||||
nsBuiltinDecoderStateMachine::StartDecodeThread()
|
||||
{
|
||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
|
||||
mStopDecodeThread = false;
|
||||
if (mState >= DECODER_STATE_COMPLETED) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (mDecodeThread) {
|
||||
NS_ASSERTION(!mRequestedNewDecodeThread,
|
||||
"Shouldn't have requested new decode thread when we have a decode thread");
|
||||
// We already have a decode thread...
|
||||
if (mDecodeThreadIdle) {
|
||||
// ... and it's not been shutdown yet, wake it up.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
|
||||
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
mDecodeThreadIdle = false;
|
||||
}
|
||||
return NS_OK;
|
||||
} else if (!mRequestedNewDecodeThread) {
|
||||
// We don't already have a decode thread, request a new one.
|
||||
mRequestedNewDecodeThread = true;
|
||||
PRUint32 count = 0;
|
||||
bool created = false;
|
||||
{
|
||||
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
|
||||
StateMachineTracker::Instance().RequestCreateDecodeThread(this);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsBuiltinDecoderStateMachine::StartDecodeThread()
|
||||
{
|
||||
NS_ASSERTION(StateMachineTracker::Instance().GetDecodeThreadCount() <
|
||||
StateMachineTracker::MAX_DECODE_THREADS,
|
||||
"Should not have reached decode thread limit");
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
|
||||
"Should not already have a pending request for a new decode thread.");
|
||||
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
|
||||
NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
|
||||
NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
|
||||
|
||||
mRequestedNewDecodeThread = false;
|
||||
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
|
||||
nsnull,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Give up, report error to media element.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::DecodeError);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
return rv;
|
||||
count = StateMachineTracker::Instance().GetDecodeThreadCount();
|
||||
}
|
||||
|
||||
mStopDecodeThread = false;
|
||||
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
|
||||
return NS_OK;
|
||||
|
||||
if (!mDecodeThread && count > StateMachineTracker::MAX_DECODE_THREADS) {
|
||||
// Have to run one iteration of the state machine loop to ensure the
|
||||
// shutdown state is processed.
|
||||
ScheduleStateMachine();
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mDecodeThread) {
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
|
||||
nsnull,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Have to run one iteration of the state machine loop to ensure the
|
||||
// shutdown state is processed.
|
||||
ScheduleStateMachine();
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
return rv;
|
||||
}
|
||||
created = true;
|
||||
}
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
|
||||
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
mDecodeThreadIdle = false;
|
||||
|
||||
if (created) {
|
||||
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
|
||||
StateMachineTracker::Instance().NoteDecodeThreadCreated();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1390,7 +1278,6 @@ nsBuiltinDecoderStateMachine::StartAudioThread()
|
||||
nsnull,
|
||||
MEDIA_THREAD_STACK_SIZE);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
|
||||
mState = DECODER_STATE_SHUTDOWN;
|
||||
return rv;
|
||||
}
|
||||
@ -1748,7 +1635,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
|
||||
|
||||
case DECODER_STATE_DECODING_METADATA: {
|
||||
// Ensure we have a decode thread to decode metadata.
|
||||
return ScheduleDecodeThread();
|
||||
return StartDecodeThread();
|
||||
}
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
@ -1772,7 +1659,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
|
||||
|
||||
// We're playing and/or our decode buffers aren't full. Ensure we have
|
||||
// an active decode thread.
|
||||
if (NS_FAILED(ScheduleDecodeThread())) {
|
||||
if (NS_FAILED(StartDecodeThread())) {
|
||||
NS_WARNING("Failed to start media decode thread!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -1837,7 +1724,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
|
||||
|
||||
case DECODER_STATE_SEEKING: {
|
||||
// Ensure we have a decode thread to perform the seek.
|
||||
return ScheduleDecodeThread();
|
||||
return StartDecodeThread();
|
||||
}
|
||||
|
||||
case DECODER_STATE_COMPLETED: {
|
||||
|
@ -253,12 +253,6 @@ public:
|
||||
// earlier, in which case the request is discarded.
|
||||
nsresult ScheduleStateMachine(PRInt64 aUsecs);
|
||||
|
||||
// Creates and starts a new decode thread. Don't call this directly,
|
||||
// request a new decode thread by calling
|
||||
// StateMachineTracker::RequestCreateDecodeThread().
|
||||
// The decoder monitor must not be held. Called on the state machine thread.
|
||||
nsresult StartDecodeThread();
|
||||
|
||||
// Timer function to implement ScheduleStateMachine(aUsecs).
|
||||
void TimeoutExpired();
|
||||
|
||||
@ -358,8 +352,7 @@ protected:
|
||||
// here. Called on the audio thread.
|
||||
PRUint32 PlayFromAudioQueue(PRUint64 aFrameOffset, PRUint32 aChannels);
|
||||
|
||||
// Stops the decode thread, and if we have a pending request for a new
|
||||
// decode thread it is canceled. The decoder monitor must be held with exactly
|
||||
// Stops the decode thread. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
void StopDecodeThread();
|
||||
|
||||
@ -367,11 +360,9 @@ protected:
|
||||
// one lock count. Called on the state machine thread.
|
||||
void StopAudioThread();
|
||||
|
||||
// Ensures the decode thread is running if it already exists, or requests
|
||||
// a new decode thread be started if there currently is no decode thread.
|
||||
// The decoder monitor must be held with exactly one lock count. Called on
|
||||
// the state machine thread.
|
||||
nsresult ScheduleDecodeThread();
|
||||
// Starts the decode thread. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
nsresult StartDecodeThread();
|
||||
|
||||
// Starts the audio thread. The decoder monitor must be held with exactly
|
||||
// one lock count. Called on the state machine thread.
|
||||
@ -634,10 +625,6 @@ protected:
|
||||
|
||||
// True is we are decoding a realtime stream, like a camera stream
|
||||
bool mRealTime;
|
||||
|
||||
// True if we've requested a new decode thread, but it has not yet been
|
||||
// created. Synchronized by the decoder monitor.
|
||||
bool mRequestedNewDecodeThread;
|
||||
|
||||
PRUint32 mBufferingWait;
|
||||
PRInt64 mLowDataThresholdUsecs;
|
||||
|
@ -150,7 +150,6 @@ _TEST_FILES = \
|
||||
test_source_write.html \
|
||||
test_standalone.html \
|
||||
test_timeupdate_small_files.html \
|
||||
test_too_many_elements.html \
|
||||
test_volume.html \
|
||||
test_video_to_canvas.html \
|
||||
use_large_cache.js \
|
||||
|
@ -8,4 +8,4 @@ load 493915-1.html
|
||||
skip-if(Android) load 495794-1.html
|
||||
load 492286-1.xhtml
|
||||
load 576612-1.html
|
||||
skip-if(Android) load 691096-1.html # Android sound API can't handle playing large number of sounds at once.
|
||||
load 691096-1.html
|
||||
|
@ -5,9 +5,9 @@
|
||||
// These are small test files, good for just seeing if something loads. We
|
||||
// really only need one test file per backend here.
|
||||
var gSmallTests = [
|
||||
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
|
||||
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
|
||||
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
|
||||
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
|
||||
{ name:"seek.webm", type:"video/webm", duration:3.966 },
|
||||
{ name:"bogus.duh", type:"bogus/duh" }
|
||||
];
|
||||
@ -299,14 +299,6 @@ function getPlayableVideo(candidates) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function getPlayableAudio(candidates) {
|
||||
var v = document.createElement("audio");
|
||||
var resources = candidates.filter(function(x){return /^audio/.test(x.type) && v.canPlayType(x.type);});
|
||||
if (resources.length > 0)
|
||||
return resources[0];
|
||||
return null;
|
||||
}
|
||||
|
||||
// Number of tests to run in parallel. Warning: Each media element requires
|
||||
// at least 3 threads (4 on Linux), and on Linux each thread uses 10MB of
|
||||
// virtual address space. Beware!
|
||||
|
@ -1,65 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=713381
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 713381</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="manifest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=713381">Mozilla Bug 713381</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 713381 **/
|
||||
|
||||
const num = 500;
|
||||
var ended = 0;
|
||||
|
||||
var finish = function(testNum) {
|
||||
return function() {
|
||||
ok(true, "Received ended event for instance " + testNum );
|
||||
ended++;
|
||||
if (ended == num) {
|
||||
ok(true, "Should receive ended events for all " + num + " elements.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var resource = getPlayableAudio(gSmallTests);
|
||||
|
||||
if (resource == null) {
|
||||
todo(false, "No types supported");
|
||||
} else {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
// Load the resource, and play it to ensure it's entirely downloaded.
|
||||
// Once it's played through, create a large number of audio elements which
|
||||
// are the same resource. These will share data with the other resource, and
|
||||
// so be really cheap to create.
|
||||
var res = new Audio(resource.name);
|
||||
res.addEventListener("ended",
|
||||
function() {
|
||||
for (var i=0; i<num; ++i) {
|
||||
var a = new Audio(resource.name);
|
||||
a.addEventListener("ended", finish(i), false);
|
||||
a.volume = 0.1;
|
||||
a.play();
|
||||
}
|
||||
}, false);
|
||||
res.play();
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -350,22 +350,6 @@ void* nsDeque::ObjectAt(PRInt32 aIndex) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
void* nsDeque::RemoveObjectAt(PRInt32 aIndex) {
|
||||
if ((aIndex<0) || (aIndex>=mSize)) {
|
||||
return 0;
|
||||
}
|
||||
void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
|
||||
|
||||
// "Shuffle down" all elements in the array by 1, overwritting the element
|
||||
// being removed.
|
||||
for (PRInt32 i=aIndex; i<mSize; i++) {
|
||||
mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
|
||||
}
|
||||
mSize--;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return an iterator pointing to
|
||||
* the beginning of the queue. Note that this
|
||||
|
@ -152,14 +152,6 @@ class NS_COM_GLUE nsDeque {
|
||||
*/
|
||||
void* ObjectAt(int aIndex) const;
|
||||
|
||||
/**
|
||||
* Removes and returns the i'th member from the deque.
|
||||
*
|
||||
* @param index of desired item
|
||||
* @return the element which was removed
|
||||
*/
|
||||
void* RemoveObjectAt(int aIndex);
|
||||
|
||||
/**
|
||||
* Remove all items from container without destroying them.
|
||||
*
|
||||
|
@ -89,7 +89,6 @@ CPP_UNIT_TESTS = \
|
||||
TestCOMArray.cpp \
|
||||
TestCOMPtr.cpp \
|
||||
TestCOMPtrEq.cpp \
|
||||
TestDeque.cpp \
|
||||
TestFile.cpp \
|
||||
TestHashtables.cpp \
|
||||
TestID.cpp \
|
||||
@ -110,6 +109,7 @@ endif
|
||||
#CPP_UNIT_TESTS += \
|
||||
# TestArray.cpp \
|
||||
# TestCRT.cpp \
|
||||
# TestDeque.cpp \
|
||||
# TestEncoding.cpp \
|
||||
# TestExpirationTracker.cpp \
|
||||
# TestPipes.cpp \
|
||||
|
@ -35,7 +35,6 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "TestHarness.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsCRT.h"
|
||||
#include <stdio.h>
|
||||
@ -45,12 +44,13 @@
|
||||
**************************************************************/
|
||||
class _TestDeque {
|
||||
public:
|
||||
int Test();
|
||||
private:
|
||||
int OriginalTest();
|
||||
int OriginalFlaw();
|
||||
int AssignFlaw();
|
||||
int TestRemove();
|
||||
_TestDeque() {
|
||||
SelfTest();
|
||||
}
|
||||
int SelfTest();
|
||||
nsresult OriginalTest();
|
||||
nsresult OriginalFlaw();
|
||||
nsresult AssignFlaw();
|
||||
};
|
||||
static _TestDeque sTestDeque;
|
||||
|
||||
@ -60,214 +60,96 @@ class _Dealloc: public nsDequeFunctor {
|
||||
}
|
||||
};
|
||||
|
||||
#define TEST(aCondition, aMsg) \
|
||||
if (!(aCondition)) { fail("TestDeque: "#aMsg); return 1; }
|
||||
|
||||
|
||||
/**
|
||||
* conduct automated self test for this class
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
*/
|
||||
int _TestDeque::Test() {
|
||||
int _TestDeque::SelfTest() {
|
||||
/* the old deque should have failed a bunch of these tests */
|
||||
int results=0;
|
||||
results+=OriginalTest();
|
||||
results+=OriginalFlaw();
|
||||
results+=AssignFlaw();
|
||||
results+=TestRemove();
|
||||
return results;
|
||||
}
|
||||
|
||||
int _TestDeque::OriginalTest() {
|
||||
const int size = 200;
|
||||
int ints[size];
|
||||
nsresult _TestDeque::OriginalTest() {
|
||||
int ints[200];
|
||||
int count=sizeof(ints)/sizeof(int);
|
||||
int i=0;
|
||||
int temp;
|
||||
int* temp;
|
||||
nsDeque theDeque(new _Dealloc); //construct a simple one...
|
||||
|
||||
// ints = [0...199]
|
||||
for (i=0;i<size;i++) { //initialize'em
|
||||
ints[i]=i;
|
||||
for (i=0;i<count;i++) { //initialize'em
|
||||
ints[i]=10*(1+i);
|
||||
}
|
||||
// queue = [0...69]
|
||||
for (i=0;i<70;i++) {
|
||||
theDeque.Push(&ints[i]);
|
||||
temp=*(int*)theDeque.Peek();
|
||||
TEST(temp == i, "Verify end after push #1");
|
||||
TEST(theDeque.GetSize() == i + 1, "Verify size after push #1");
|
||||
}
|
||||
TEST(theDeque.GetSize() == 70, "Verify overall size after pushes #1");
|
||||
// queue = [0...14]
|
||||
for (i=1;i<=55;i++) {
|
||||
temp=*(int*)theDeque.Pop();
|
||||
TEST(temp == 70-i, "Verify end after pop # 1");
|
||||
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop # 1");
|
||||
for (i=0;i<56;i++) {
|
||||
temp=(int*)theDeque.Pop();
|
||||
}
|
||||
TEST(theDeque.GetSize() == 15, "Verify overall size after pops");
|
||||
|
||||
// queue = [0...14,0...54]
|
||||
for (i=0;i<55;i++) {
|
||||
theDeque.Push(&ints[i]);
|
||||
temp=*(int*)theDeque.Peek();
|
||||
TEST(temp == i, "Verify end after push #2");
|
||||
TEST(theDeque.GetSize() == i + 15 + 1, "Verify size after push # 2");
|
||||
}
|
||||
TEST(theDeque.GetSize() == 70, "Verify size after end of all pushes #2");
|
||||
|
||||
// queue = [0...14,0...19]
|
||||
for (i=1;i<=35;i++) {
|
||||
temp=*(int*)theDeque.Pop();
|
||||
TEST(temp == 55-i, "Verify end after pop # 2");
|
||||
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop #2");
|
||||
for (i=0;i<35;i++) {
|
||||
temp=(int*)theDeque.Pop();
|
||||
}
|
||||
TEST(theDeque.GetSize() == 35, "Verify overall size after end of all pops #2");
|
||||
|
||||
// queue = [0...14,0...19,0...34]
|
||||
for (i=0;i<35;i++) {
|
||||
theDeque.Push(&ints[i]);
|
||||
temp = *(int*)theDeque.Peek();
|
||||
TEST(temp == i, "Verify end after push # 3");
|
||||
TEST(theDeque.GetSize() == 35 + 1 + i, "Verify size after push #3");
|
||||
}
|
||||
|
||||
// queue = [0...14,0...19]
|
||||
for (i=0;i<35;i++) {
|
||||
temp=*(int*)theDeque.Pop();
|
||||
TEST(temp == 34 - i, "Verify end after pop # 3");
|
||||
for (i=0;i<38;i++) {
|
||||
temp=(int*)theDeque.Pop();
|
||||
}
|
||||
|
||||
// queue = [0...14]
|
||||
for (i=0;i<20;i++) {
|
||||
temp=*(int*)theDeque.Pop();
|
||||
TEST(temp == 19 - i, "Verify end after pop # 4");
|
||||
}
|
||||
|
||||
// queue = []
|
||||
for (i=0;i<15;i++) {
|
||||
temp=*(int*)theDeque.Pop();
|
||||
TEST(temp == 14 - i, "Verify end after pop # 5");
|
||||
}
|
||||
|
||||
TEST(theDeque.GetSize() == 0, "Deque should finish empty.");
|
||||
|
||||
return 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int _TestDeque::OriginalFlaw() {
|
||||
nsresult _TestDeque::OriginalFlaw() {
|
||||
int ints[200];
|
||||
int i=0;
|
||||
int temp;
|
||||
nsDeque d(new _Dealloc);
|
||||
int* temp;
|
||||
nsDeque secondDeque(new _Dealloc);
|
||||
/**
|
||||
* Test 1. Origin near end, semi full, call Peek().
|
||||
* you start, mCapacity is 8
|
||||
*/
|
||||
printf("fill array\n");
|
||||
for (i=0; i<30; i++)
|
||||
ints[i]=i;
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
d.Push(&ints[i]);
|
||||
temp = *(int*)d.Peek();
|
||||
TEST(temp == i, "OriginalFlaw push #1");
|
||||
for (i=32; i; --i)
|
||||
ints[i]=i*3+10;
|
||||
printf("push 6 times\n");
|
||||
for (i=0; i<6; i++)
|
||||
secondDeque.Push(&ints[i]);
|
||||
printf("popfront 4 times:\n");
|
||||
for (i=4; i; --i) {
|
||||
temp=(int*)secondDeque.PopFront();
|
||||
printf("%d\t",*temp);
|
||||
}
|
||||
TEST(d.GetSize() == 6, "OriginalFlaw size check #1");
|
||||
printf("push 4 times\n");
|
||||
for (int j=4; j; --j)
|
||||
secondDeque.Push(&ints[++i]);
|
||||
printf("origin should now be about 4\n");
|
||||
printf("and size should be 6\n");
|
||||
printf("origin+size>capacity\n");
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
temp=*(int*)d.PopFront();
|
||||
TEST(temp == i, "PopFront test");
|
||||
}
|
||||
// d = [4,5]
|
||||
TEST(d.GetSize() == 2, "OriginalFlaw size check #2");
|
||||
/*<akk> Oh, I see ... it's a circular buffer */
|
||||
printf("but the old code wasn't behaving accordingly.\n");
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
d.Push(&ints[6 + i]);
|
||||
}
|
||||
// d = [4...9]
|
||||
/*right*/
|
||||
printf("we shouldn't crash or anything interesting, ");
|
||||
|
||||
for (i=4; i<=9; i++) {
|
||||
temp=*(int*)d.PopFront();
|
||||
TEST(temp == i, "OriginalFlaw empty check");
|
||||
}
|
||||
|
||||
return 0;
|
||||
temp=(int*)secondDeque.Peek();
|
||||
printf("peek: %d\n",*temp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int _TestDeque::AssignFlaw() {
|
||||
nsresult _TestDeque::AssignFlaw() {
|
||||
nsDeque src(new _Dealloc),dest(new _Dealloc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool VerifyContents(const nsDeque& aDeque, const int* aContents, int aLength) {
|
||||
for (int i=0; i<aLength; ++i) {
|
||||
if (*(int*)aDeque.ObjectAt(i) != aContents[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int _TestDeque::TestRemove() {
|
||||
nsDeque d;
|
||||
const int count = 10;
|
||||
int ints[count];
|
||||
for (int i=0; i<count; i++) {
|
||||
ints[i] = i;
|
||||
}
|
||||
|
||||
for (int i=0; i<6; i++) {
|
||||
d.Push(&ints[i]);
|
||||
}
|
||||
// d = [0...5]
|
||||
d.PopFront();
|
||||
d.PopFront();
|
||||
|
||||
// d = [2,5]
|
||||
for (int i=2; i<=5; i++) {
|
||||
int t = *(int*)d.ObjectAt(i-2);
|
||||
TEST(t == i, "Verify ObjectAt()");
|
||||
}
|
||||
|
||||
d.RemoveObjectAt(1);
|
||||
// d == [2,4,5]
|
||||
static const int t1[] = {2,4,5};
|
||||
TEST(VerifyContents(d, t1, 3), "verify contents t1");
|
||||
|
||||
d.PushFront(&ints[1]);
|
||||
d.PushFront(&ints[0]);
|
||||
d.PushFront(&ints[7]);
|
||||
d.PushFront(&ints[6]);
|
||||
// d == [6,7,0,1,2,4,5] // (0==mOrigin)
|
||||
static const int t2[] = {6,7,0,1,2,4,5};
|
||||
TEST(VerifyContents(d, t2, 7), "verify contents t2");
|
||||
|
||||
d.RemoveObjectAt(1);
|
||||
// d == [6,0,1,2,4,5] // (1==mOrigin)
|
||||
static const int t3[] = {6,0,1,2,4,5};
|
||||
TEST(VerifyContents(d, t3, 6), "verify contents t3");
|
||||
|
||||
d.RemoveObjectAt(5);
|
||||
// d == [6,0,1,2,4] // (1==mOrigin)
|
||||
static const int t4[] = {6,0,1,2,4};
|
||||
TEST(VerifyContents(d, t4, 5), "verify contents t4");
|
||||
|
||||
d.RemoveObjectAt(0);
|
||||
// d == [0,1,2,4] // (2==mOrigin)
|
||||
static const int t5[] = {0,1,2,4};
|
||||
TEST(VerifyContents(d, t5, 4), "verify contents t5");
|
||||
|
||||
|
||||
return 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int main (void) {
|
||||
ScopedXPCOM xpcom("TestTimers");
|
||||
NS_ENSURE_FALSE(xpcom.failed(), 1);
|
||||
|
||||
_TestDeque test;
|
||||
int result = test.Test();
|
||||
TEST(result == 0, "All tests pass");
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user