Backed out changeset 303ba353d785 (
bug 831224) for turning
bug 897108 permaorange
--- a/content/media/MediaDecoder.cpp
+++ b/content/media/MediaDecoder.cpp
@@ -627,17 +627,17 @@ nsresult MediaDecoder::Seek(double aTime
NS_ENSURE_SUCCESS(res, NS_OK);
res = seekable.Start(range + 1, &rightBound);
NS_ENSURE_SUCCESS(res, NS_OK);
double distanceLeft = Abs(leftBound - aTime);
double distanceRight = Abs(rightBound - aTime);
if (distanceLeft == distanceRight) {
distanceLeft = Abs(leftBound - mCurrentTime);
distanceRight = Abs(rightBound - mCurrentTime);
- }
+ }
aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
} else {
// Seek target is after the end last range in seekable data.
// Clamp the seek target to the end of the last seekable range.
res = seekable.End(length - 1, &aTime);
NS_ENSURE_SUCCESS(res, NS_OK);
}
} else {
--- a/content/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -451,22 +451,22 @@ public:
// Moves the decode head to aTime microseconds. aStartTime and aEndTime
// denote the start and end times of the media in usecs, and aCurrentTime
// is the current playback position in microseconds.
virtual nsresult Seek(int64_t aTime,
int64_t aStartTime,
int64_t aEndTime,
int64_t aCurrentTime) = 0;
-
+
// Called when the decode thread is started, before calling any other
// decode, read metadata, or seek functions. Do any thread local setup
// in this function.
virtual void OnDecodeThreadStart() {}
-
+
// Called when the decode thread is about to finish, after all calls to
// any other decode, read metadata, or seek functions. Any backend specific
// thread local tear down must be done in this function. Note that another
// decode thread could start up and run in future.
virtual void OnDecodeThreadFinish() {}
protected:
// Queue of audio frames. This queue is threadsafe, and is accessed from
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -135,33 +135,33 @@ private:
StateMachineTracker() :
mMonitor("media.statemachinetracker"),
mStateMachineCount(0),
mDecodeThreadCount(0),
mStateMachineThread(nullptr)
{
MOZ_COUNT_CTOR(StateMachineTracker);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
- }
-
+ }
+
~StateMachineTracker()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
MOZ_COUNT_DTOR(StateMachineTracker);
}
public:
// Access singleton instance. This is initially called on the main
// thread in the MediaDecoderStateMachine constructor resulting
// in the global object being created lazily. Non-main thread
// access always occurs after this and uses the monitor to
// safely access the decode thread counts.
static StateMachineTracker& Instance();
-
+
// Instantiate the global state machine thread if required.
// Call on main thread only.
void EnsureGlobalStateMachine();
// Destroy global state machine thread if required.
// Call on main thread only.
void CleanupGlobalStateMachine();
@@ -239,17 +239,17 @@ StateMachineTracker& StateMachineTracker
{
if (!sInstance) {
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
sInstance = new StateMachineTracker();
}
return *sInstance;
}
-void StateMachineTracker::EnsureGlobalStateMachine()
+void StateMachineTracker::EnsureGlobalStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mMonitor);
if (mStateMachineCount == 0) {
NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!");
DebugOnly<nsresult> rv = NS_NewNamedThread("Media State", &mStateMachineThread, nullptr);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't create media state machine thread");
}
@@ -446,17 +446,17 @@ MediaDecoderStateMachine::~MediaDecoderS
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 = nullptr;
mReader = nullptr;
-
+
StateMachineTracker::Instance().CleanupGlobalStateMachine();
#ifdef XP_WIN
timeEndPeriod(1);
#endif
}
bool MediaDecoderStateMachine::HasFutureAudio() const {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
@@ -485,17 +485,17 @@ int64_t MediaDecoderStateMachine::GetDec
}
return audioDecoded;
}
void MediaDecoderStateMachine::DecodeThreadRun()
{
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
mReader->OnDecodeThreadStart();
-
+
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mState == DECODER_STATE_DECODING_METADATA &&
NS_FAILED(DecodeMetadata())) {
NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
"Should be in shutdown state if metadata loading fails.");
LOG(PR_LOG_DEBUG, ("Decode metadata failed, shutting down decode thread"));
@@ -526,17 +526,17 @@ void MediaDecoderStateMachine::DecodeThr
} else if (mState == DECODER_STATE_DORMANT) {
mDecoder->GetReentrantMonitor().Wait();
}
}
mDecodeThreadIdle = true;
LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
}
-
+
mReader->OnDecodeThreadFinish();
}
void MediaDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
DecodedStreamData* aStream,
AudioSegment* aOutput)
{
NS_ASSERTION(OnDecodeThread() ||
@@ -1318,17 +1318,17 @@ void MediaDecoderStateMachine::StartPlay
NS_ASSERTION(!IsPlaying(), "Shouldn't be playing when StartPlayback() is called");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mDecoder->NotifyPlaybackStarted();
mPlayStartTime = TimeStamp::Now();
NS_ASSERTION(IsPlaying(), "Should report playing by end of StartPlayback()");
if (NS_FAILED(StartAudioThread())) {
- NS_WARNING("Failed to create audio thread");
+ NS_WARNING("Failed to create audio thread");
}
mDecoder->GetReentrantMonitor().NotifyAll();
}
void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime)
{
NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
"Should be on state machine thread.");
@@ -1695,17 +1695,17 @@ void MediaDecoderStateMachine::StopAudio
}
}
nsresult
MediaDecoderStateMachine::ScheduleDecodeThread()
{
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...
@@ -1826,17 +1826,17 @@ bool MediaDecoderStateMachine::HasLowUnd
}
int64_t MediaDecoderStateMachine::GetUndecodedData() const
{
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA,
"Must have loaded metadata for GetBuffered() to work");
TimeRanges buffered;
-
+
nsresult res = mDecoder->GetBuffered(&buffered);
NS_ENSURE_SUCCESS(res, 0);
double currentTime = GetCurrentTime();
nsIDOMTimeRanges* r = static_cast<nsIDOMTimeRanges*>(&buffered);
uint32_t length = 0;
res = r->GetLength(&length);
NS_ENSURE_SUCCESS(res, 0);
@@ -2196,17 +2196,17 @@ nsresult MediaDecoderStateMachine::RunSt
case DECODER_STATE_WAIT_FOR_RESOURCES: {
return NS_OK;
}
case DECODER_STATE_DECODING_METADATA: {
// Ensure we have a decode thread to decode metadata.
return ScheduleDecodeThread();
}
-
+
case DECODER_STATE_DECODING: {
if (mDecoder->GetState() != MediaDecoder::PLAY_STATE_PLAYING &&
IsPlaying())
{
// We're playing, but the element/decoder is in paused state. Stop
// playing! Note we do this before StopDecodeThread() below because
// that blocks this state machine's execution, and can cause a
// perceptible delay between the pause command, and playback actually
--- a/content/media/omx/OmxDecoder.h
+++ b/content/media/omx/OmxDecoder.h
@@ -194,17 +194,17 @@ public:
bool HasVideo() {
return mVideoSource != nullptr;
}
bool HasAudio() {
return mAudioSource != nullptr;
}
- bool ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs,
+ bool ReadVideo(VideoFrame *aFrame, int64_t aSeekTimeUs,
bool aKeyframeSkip = false,
bool aDoSeek = false);
bool ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs);
MediaResource *GetResource() {
return mResource;
}
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -149,20 +149,20 @@ var gPlayTests = [
{ name:"redirect.sjs?domain=mochi.test:8888&file=320x240.ogv",
type:"video/ogg", duration:0.266 },
// Test playback of a webm file
{ name:"seek.webm", type:"video/webm", duration:3.966 },
// Test playback of a WebM file with non-zero start time.
{ name:"split.webm", type:"video/webm", duration:1.967 },
-
+
// Test playback of a raw file
{ name:"seek.yuv", type:"video/x-raw-yuv", duration:1.833 },
-
+
// A really short, low sample rate, single channel file. This tests whether
// we can handle playing files when only push very little audio data to the
// hardware.
{ name:"spacestorm-1000Hz-100ms.ogg", type:"audio/ogg", duration:0.099 },
// Opus data in an ogg container
{ name:"detodos.opus", type:"audio/ogg; codecs=opus", duration:2.9135 },
@@ -558,55 +558,55 @@ const DEBUG_TEST_LOOP_FOREVER = false;
// Manages a run of media tests. Runs them in chunks in order to limit
// the number of media elements/threads running in parallel. This limits peak
// memory use, particularly on Linux x86 where thread stacks use 10MB of
// virtual address space.
// Usage:
// 1. Create a new MediaTestManager object.
// 2. Create a test startTest function. This takes a test object and a token,
// and performs anything necessary to start the test. The test object is an
-// element in one of the g*Tests above. Your startTest function must call
+// element in one of the g*Tests above. Your startTest function must call
// MediaTestManager.start(token) if it starts a test. The test object is
// guaranteed to be playable by our supported decoders; you don't need to
// check canPlayType.
// 3. When your tests finishes, call MediaTestManager.finished(), passing
// the token back to the manager. The manager may either start the next run
// or end the mochitest if all the tests are done.
function MediaTestManager() {
// Sets up a MediaTestManager to runs through the 'tests' array, which needs
// to be one of, or have the same fields as, the g*Test arrays of tests. Uses
- // the user supplied 'startTest' function to initialize the test. This
+ // the user supplied 'startTest' function to initialize the test. This
// function must accept two arguments, the test entry from the 'tests' array,
// and a token. Call MediaTestManager.started(token) if you start the test,
// and MediaTestManager.finished(token) when the test finishes. You don't have
// to start every test, but if you call started() you *must* call finish()
- // else you'll timeout.
+ // else you'll timeout.
this.runTests = function(tests, startTest) {
this.startTime = new Date();
SimpleTest.info("Started " + this.startTime + " (" + this.startTime.getTime()/1000 + "s)");
this.testNum = 0;
this.tests = tests;
this.startTest = startTest;
this.tokens = [];
this.isShutdown = false;
this.numTestsRunning = 0;
// Always wait for explicit finish.
SimpleTest.waitForExplicitFinish();
this.nextTest();
}
-
+
// Registers that the test corresponding to 'token' has been started.
// Don't call more than once per token.
this.started = function(token) {
this.tokens.push(token);
this.numTestsRunning++;
is(this.numTestsRunning, this.tokens.length, "[started " + token + "] Length of array should match number of running tests");
}
-
+
// Registers that the test corresponding to 'token' has finished. Call when
// you've finished your test. If all tests are complete this will finish the
// run, otherwise it may start up the next run. It's ok to call multiple times
// per token.
this.finished = function(token) {
var i = this.tokens.indexOf(token);
if (i != -1) {
// Remove the element from the list of running tests.
@@ -621,30 +621,30 @@ function MediaTestManager() {
// Starts the next batch of tests, or finishes if they're all done.
// Don't call this directly, call finished(token) when you're done.
this.nextTest = function() {
// Force a GC after every completed testcase. This ensures that any decoders
// with live threads waiting for the GC are killed promptly, to free up the
// thread stacks' address space.
SpecialPowers.forceGC();
-
+
while (this.testNum < this.tests.length && this.tokens.length < PARALLEL_TESTS) {
var test = this.tests[this.testNum];
var token = (test.name ? (test.name + "-"): "") + this.testNum;
this.testNum++;
if (DEBUG_TEST_LOOP_FOREVER && this.testNum == this.tests.length) {
this.testNum = 0;
}
-
+
// Ensure we can play the resource type.
if (test.type && !document.createElement('video').canPlayType(test.type))
continue;
-
+
// Do the init. This should start the test.
this.startTest(test, token);
}
if (this.testNum == this.tests.length &&
!DEBUG_TEST_LOOP_FOREVER &&
this.tokens.length == 0 &&
!this.isShutdown)