From de44f0f3fe21ededd0a71d3b89cf4ae4bdd75d79 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 1 Apr 2011 11:10:49 +1300 Subject: [PATCH] Bug 641718 - Convert to using microseconds for internal video timestamps. r=kinetik --- .../html/content/src/nsHTMLMediaElement.cpp | 2 +- content/media/VideoUtils.cpp | 16 +- content/media/VideoUtils.h | 16 +- .../media/nsAudioAvailableEventManager.cpp | 6 +- content/media/nsAudioStream.cpp | 8 +- content/media/nsAudioStream.h | 2 +- content/media/nsBuiltinDecoder.cpp | 10 +- content/media/nsBuiltinDecoder.h | 7 +- content/media/nsBuiltinDecoderReader.h | 18 +- .../media/nsBuiltinDecoderStateMachine.cpp | 154 +++++++++--------- content/media/nsBuiltinDecoderStateMachine.h | 60 +++---- content/media/nsMediaCache.cpp | 6 +- content/media/nsMediaDecoder.h | 4 +- content/media/nsMediaStream.cpp | 2 +- content/media/nsMediaStream.h | 4 +- content/media/ogg/nsOggCodecState.cpp | 53 ++---- content/media/ogg/nsOggCodecState.h | 11 +- content/media/ogg/nsOggReader.cpp | 29 ++-- content/media/ogg/nsOggReader.h | 18 +- content/media/raw/nsRawReader.cpp | 12 +- content/media/test/test_seekLies.html | 2 +- content/media/wave/nsWaveReader.cpp | 41 ++--- content/media/wave/nsWaveReader.h | 6 +- content/media/webm/nsWebMBufferedParser.cpp | 1 - content/media/webm/nsWebMReader.cpp | 53 +++--- content/media/webm/nsWebMReader.h | 8 +- 26 files changed, 266 insertions(+), 283 deletions(-) diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 98b66ee16cd9..8e9bd2c17a37 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -1820,7 +1820,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal) double duration = aOriginal->GetDuration(); if (duration >= 0) { - decoder->SetDuration(PRInt64(NS_round(duration * 1000))); + decoder->SetDuration(duration); decoder->SetSeekable(aOriginal->GetSeekable()); } diff --git a/content/media/VideoUtils.cpp b/content/media/VideoUtils.cpp index 88bbe0a9696f..76b8166eceb8 100644 --- a/content/media/VideoUtils.cpp +++ b/content/media/VideoUtils.cpp @@ -175,24 +175,24 @@ PRBool MulOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult) { return PR_TRUE; } -// Converts from number of audio samples to milliseconds, given the specified +// Converts from number of audio samples to microseconds, given the specified // audio rate. -PRBool SamplesToMs(PRInt64 aSamples, PRUint32 aRate, PRInt64& aOutMs) +PRBool SamplesToUsecs(PRInt64 aSamples, PRUint32 aRate, PRInt64& aOutUsecs) { PRInt64 x; - if (!MulOverflow(aSamples, 1000, x)) + if (!MulOverflow(aSamples, USECS_PER_S, x)) return PR_FALSE; - aOutMs = x / aRate; + aOutUsecs = x / aRate; return PR_TRUE; } -// Converts from milliseconds to number of audio samples, given the specified +// Converts from microseconds to number of audio samples, given the specified // audio rate. -PRBool MsToSamples(PRInt64 aMs, PRUint32 aRate, PRInt64& aOutSamples) +PRBool UsecsToSamples(PRInt64 aUsecs, PRUint32 aRate, PRInt64& aOutSamples) { PRInt64 x; - if (!MulOverflow(aMs, aRate, x)) + if (!MulOverflow(aUsecs, aRate, x)) return PR_FALSE; - aOutSamples = x / 1000; + aOutSamples = x / USECS_PER_S; return PR_TRUE; } diff --git a/content/media/VideoUtils.h b/content/media/VideoUtils.h index 5dc0237fce77..497db6a6db16 100644 --- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -126,16 +126,22 @@ PRBool AddOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult); // in an integer overflow. PRBool MulOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult); -// Converts from number of audio samples (aSamples) to milliseconds, given -// the specified audio rate (aRate). Stores result in aOutMs. Returns PR_TRUE +// Converts from number of audio samples (aSamples) to microseconds, given +// the specified audio rate (aRate). Stores result in aOutUsecs. Returns PR_TRUE // if the operation succeeded, or PR_FALSE if there was an integer overflow // while calulating the conversion. -PRBool SamplesToMs(PRInt64 aSamples, PRUint32 aRate, PRInt64& aOutMs); +PRBool SamplesToUsecs(PRInt64 aSamples, PRUint32 aRate, PRInt64& aOutUsecs); -// Converts from milliseconds (aMs) to number of audio samples, given the +// Converts from microseconds (aUsecs) to number of audio samples, given the // specified audio rate (aRate). Stores the result in aOutSamples. Returns // PR_TRUE if the operation succeeded, or PR_FALSE if there was an integer // overflow while calulating the conversion. -PRBool MsToSamples(PRInt64 aMs, PRUint32 aRate, PRInt64& aOutSamples); +PRBool UsecsToSamples(PRInt64 aUsecs, PRUint32 aRate, PRInt64& aOutSamples); + +// Number of microseconds per second. 1e6. +#define USECS_PER_S 1000000 + +// Number of microseconds per millisecond. +#define USECS_PER_MS 1000 #endif diff --git a/content/media/nsAudioAvailableEventManager.cpp b/content/media/nsAudioAvailableEventManager.cpp index 0f821e26b289..e3e27a93575e 100644 --- a/content/media/nsAudioAvailableEventManager.cpp +++ b/content/media/nsAudioAvailableEventManager.cpp @@ -39,8 +39,8 @@ #include "nsTArray.h" #include "nsAudioAvailableEventManager.h" +#include "VideoUtils.h" -#define MILLISECONDS_PER_SECOND 1000.0f #define MAX_PENDING_EVENTS 100 using namespace mozilla; @@ -106,7 +106,7 @@ void nsAudioAvailableEventManager::DispatchPendingEvents(PRUint64 aCurrentTime) while (mPendingEvents.Length() > 0) { nsAudioAvailableEventRunner* e = (nsAudioAvailableEventRunner*)mPendingEvents[0].get(); - if (e->mTime * MILLISECONDS_PER_SECOND > aCurrentTime) { + if (e->mTime * USECS_PER_S > aCurrentTime) { break; } nsCOMPtr event = mPendingEvents[0]; @@ -227,7 +227,7 @@ void nsAudioAvailableEventManager::Drain(PRUint64 aEndTime) (mSignalBufferLength - mSignalBufferPosition) * sizeof(float)); // Force this last event to go now. - float time = (aEndTime / MILLISECONDS_PER_SECOND) - + float time = (aEndTime / static_cast(USECS_PER_S)) - (mSignalBufferPosition / mSamplesPerSecond); nsCOMPtr lastEvent = new nsAudioAvailableEventRunner(mDecoder, mSignalBuffer.forget(), diff --git a/content/media/nsAudioStream.cpp b/content/media/nsAudioStream.cpp index c5fe5e4c90b8..781bfbb27774 100644 --- a/content/media/nsAudioStream.cpp +++ b/content/media/nsAudioStream.cpp @@ -53,6 +53,7 @@ using namespace mozilla::dom; #include "nsAutoPtr.h" #include "nsAudioStream.h" #include "nsAlgorithm.h" +#include "VideoUtils.h" extern "C" { #include "sydneyaudio/sydney_audio.h" } @@ -76,7 +77,6 @@ PRLogModuleInfo* gAudioStreamLog = nsnull; #endif #define FAKE_BUFFER_SIZE 176400 -#define MILLISECONDS_PER_SECOND 1000 class nsAudioStreamLocal : public nsAudioStream { @@ -555,7 +555,7 @@ PRInt64 nsAudioStreamLocal::GetPosition() { PRInt64 sampleOffset = GetSampleOffset(); if (sampleOffset >= 0) { - return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels); + return ((USECS_PER_S * sampleOffset) / mRate / mChannels); } return -1; } @@ -724,7 +724,7 @@ PRInt64 nsAudioStreamRemote::GetPosition() { PRInt64 sampleOffset = GetSampleOffset(); if (sampleOffset >= 0) { - return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels); + return ((USECS_PER_S * sampleOffset) / mRate / mChannels); } return 0; } @@ -740,7 +740,7 @@ nsAudioStreamRemote::GetSampleOffset() return 0; PRInt64 time = mAudioChild->GetLastKnownSampleOffsetTime(); - PRInt64 result = offset + (mRate * mChannels * (PR_IntervalNow() - time) / MILLISECONDS_PER_SECOND); + PRInt64 result = offset + (mRate * mChannels * (PR_IntervalNow() - time) / USECS_PER_S); return result; } diff --git a/content/media/nsAudioStream.h b/content/media/nsAudioStream.h index d78789925790..d1ff0a5557ff 100644 --- a/content/media/nsAudioStream.h +++ b/content/media/nsAudioStream.h @@ -107,7 +107,7 @@ public: // Resume audio playback virtual void Resume() = 0; - // Return the position in milliseconds of the sample being played by the + // Return the position in microseconds of the sample being played by the // audio hardware. virtual PRInt64 GetPosition() = 0; diff --git a/content/media/nsBuiltinDecoder.cpp b/content/media/nsBuiltinDecoder.cpp index 3b53f0cdf756..966152cfa147 100644 --- a/content/media/nsBuiltinDecoder.cpp +++ b/content/media/nsBuiltinDecoder.cpp @@ -83,7 +83,7 @@ double nsBuiltinDecoder::GetDuration() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); if (mDuration >= 0) { - return static_cast(mDuration) / 1000.0; + return static_cast(mDuration) / static_cast(USECS_PER_S); } return std::numeric_limits::quiet_NaN(); } @@ -524,7 +524,7 @@ double nsBuiltinDecoder::ComputePlaybackRate(PRPackedBool* aReliable) PRInt64 length = mStream ? mStream->GetLength() : -1; if (mDuration >= 0 && length >= 0) { *aReliable = PR_TRUE; - return double(length)*1000.0/mDuration; + return length * static_cast(USECS_PER_S) / mDuration; } return mPlaybackStatistics.GetRateAtLastStop(aReliable); } @@ -800,15 +800,15 @@ void nsBuiltinDecoder::DurationChanged() UpdatePlaybackRate(); if (mElement && oldDuration != mDuration) { - LOG(PR_LOG_DEBUG, ("%p duration changed to %lldms", this, mDuration)); + LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration)); mElement->DispatchEvent(NS_LITERAL_STRING("durationchange")); } } -void nsBuiltinDecoder::SetDuration(PRInt64 aDuration) +void nsBuiltinDecoder::SetDuration(double aDuration) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); - mDuration = aDuration; + mDuration = static_cast(NS_round(aDuration * static_cast(USECS_PER_S))); MonitorAutoEnter mon(mMonitor); if (mDecoderStateMachine) { diff --git a/content/media/nsBuiltinDecoder.h b/content/media/nsBuiltinDecoder.h index 94c501794994..37653fb339da 100644 --- a/content/media/nsBuiltinDecoder.h +++ b/content/media/nsBuiltinDecoder.h @@ -250,13 +250,14 @@ public: virtual void Shutdown() = 0; // Called from the main thread to get the duration. The decoder monitor - // must be obtained before calling this. It is in units of milliseconds. + // must be obtained before calling this. It is in units of microseconds. virtual PRInt64 GetDuration() = 0; // Called from the main thread to set the duration of the media resource // if it is able to be obtained via HTTP headers. Called from the // state machine thread to set the duration if it is obtained from the // media metadata. The decoder monitor must be obtained before calling this. + // aDuration is in microseconds. virtual void SetDuration(PRInt64 aDuration) = 0; // Functions used by assertions to ensure we're calling things @@ -383,10 +384,10 @@ class nsBuiltinDecoder : public nsMediaDecoder // Call on the main thread only. virtual PRBool IsEnded() const; - // Set the duration of the media resource in units of milliseconds. + // Set the duration of the media resource in units of seconds. // This is called via a channel listener if it can pick up the duration // from a content header. Must be called from the main thread only. - virtual void SetDuration(PRInt64 aDuration); + virtual void SetDuration(double aDuration); // Set a flag indicating whether seeking is supported virtual void SetSeekable(PRBool aSeekable); diff --git a/content/media/nsBuiltinDecoderReader.h b/content/media/nsBuiltinDecoderReader.h index a9673d8abb8c..e7ce6732fcba 100644 --- a/content/media/nsBuiltinDecoderReader.h +++ b/content/media/nsBuiltinDecoderReader.h @@ -179,8 +179,8 @@ public: // chunk ends. const PRInt64 mOffset; - PRInt64 mTime; // Start time of samples in ms. - const PRInt64 mDuration; // In ms. + PRInt64 mTime; // Start time of samples in usecs. + const PRInt64 mDuration; // In usecs. const PRUint32 mSamples; const PRUint32 mChannels; nsAutoArrayPtr mAudioData; @@ -241,10 +241,10 @@ public: // Approximate byte offset of the end of the frame in the media. PRInt64 mOffset; - // Start time of frame in milliseconds. + // Start time of frame in microseconds. PRInt64 mTime; - // End time of frame in milliseconds; + // End time of frame in microseconds; PRInt64 mEndTime; // Codec specific internal time code. For Ogg based codecs this is the @@ -387,7 +387,7 @@ template class MediaQueue : private nsDeque { mEndOfStream = PR_TRUE; } - // Returns the approximate number of milliseconds of samples in the queue. + // Returns the approximate number of microseconds of samples in the queue. PRInt64 Duration() { MonitorAutoEnter mon(mMonitor); if (GetSize() < 2) { @@ -457,9 +457,9 @@ public: // This will not read past aEndOffset. Returns -1 on failure. virtual PRInt64 FindEndTime(PRInt64 aEndOffset); - // Moves the decode head to aTime milliseconds. aStartTime and aEndTime - // denote the start and end times of the media in ms, and aCurrentTime - // is the current playback position in ms. + // 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(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, @@ -485,7 +485,7 @@ public: protected: // Pumps the decode until we reach frames/samples required to play at - // time aTarget (ms). + // time aTarget (usecs). nsresult DecodeToTarget(PRInt64 aTarget); // Reader decode function. Matches DecodeVideoFrame() and diff --git a/content/media/nsBuiltinDecoderStateMachine.cpp b/content/media/nsBuiltinDecoderStateMachine.cpp index 8f96bd0fd4c3..47177a0a3401 100644 --- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -68,17 +68,17 @@ extern PRLogModuleInfo* gBuiltinDecoderLog; #define BUFFERING_MIN_RATE 50000 #define BUFFERING_RATE(x) ((x)< BUFFERING_MIN_RATE ? BUFFERING_MIN_RATE : (x)) -// If audio queue has less than this many ms of decoded audio, we won't risk +// If audio queue has less than this many usecs of decoded audio, we won't risk // trying to decode the video, we'll skip decoding video up to the next // keyframe. We may increase this value for an individual decoder if we // encounter video frames which take a long time to decode. -static const PRUint32 LOW_AUDIO_MS = 300; +static const PRUint32 LOW_AUDIO_USECS = 300000; -// If more than this many ms of decoded audio is queued, we'll hold off +// If more than this many usecs of decoded audio is queued, we'll hold off // decoding more audio. If we increase the low audio threshold (see -// LOW_AUDIO_MS above) we'll also increase this value to ensure it's not +// LOW_AUDIO_USECS above) we'll also increase this value to ensure it's not // less than the low audio threshold. -const PRInt64 AMPLE_AUDIO_MS = 1000; +const PRInt64 AMPLE_AUDIO_USECS = 1000000; // Maximum number of bytes we'll allocate and write at once to the audio // hardware when the audio stream contains missing samples and we're @@ -98,9 +98,9 @@ static const PRUint32 LOW_VIDEO_FRAMES = 1; static const PRUint32 AMPLE_VIDEO_FRAMES = 10; // Arbitrary "frame duration" when playing only audio. -static const int AUDIO_DURATION_MS = 40; +static const int AUDIO_DURATION_USECS = 40000; -// If we increase our "low audio threshold" (see LOW_AUDIO_MS above), we +// If we increase our "low audio threshold" (see LOW_AUDIO_USECS above), we // use this as a factor in all our calculations. Increasing this will cause // us to be more likely to increase our low audio threshold, and to // increase it by more. @@ -110,16 +110,16 @@ static const int THRESHOLD_FACTOR = 2; // ourselves to be running low on undecoded data. We determine how much // undecoded data we have remaining using the reader's GetBuffered() // implementation. -static const PRInt64 LOW_DATA_THRESHOLD_MS = 5000; +static const PRInt64 LOW_DATA_THRESHOLD_USECS = 5000000; -// LOW_DATA_THRESHOLD_MS needs to be greater than AMPLE_AUDIO_MS, otherwise +// LOW_DATA_THRESHOLD_USECS needs to be greater than AMPLE_AUDIO_USECS, otherwise // the skip-to-keyframe logic can activate when we're running low on data. -PR_STATIC_ASSERT(LOW_DATA_THRESHOLD_MS > AMPLE_AUDIO_MS); +PR_STATIC_ASSERT(LOW_DATA_THRESHOLD_USECS > AMPLE_AUDIO_USECS); -// Amount of excess ms of data to add in to the "should we buffer" calculation. -static const PRUint32 EXHAUSTED_DATA_MARGIN_MS = 60; +// Amount of excess usecs of data to add in to the "should we buffer" calculation. +static const PRUint32 EXHAUSTED_DATA_MARGIN_USECS = 60000; -// If we enter buffering within QUICK_BUFFER_THRESHOLD_MS seconds of starting +// If we enter buffering within QUICK_BUFFER_THRESHOLD_USECS seconds of starting // decoding, we'll enter "quick buffering" mode, which exits a lot sooner than // normal buffering mode. This exists so that if the decode-ahead exhausts the // downloaded data while decode/playback is just starting up (for example @@ -128,24 +128,24 @@ static const PRUint32 EXHAUSTED_DATA_MARGIN_MS = 60; // for buffering. We may actually be able to playback in this case, so exit // buffering early and try to play. If it turns out we can't play, we'll fall // back to buffering normally. -static const PRUint32 QUICK_BUFFER_THRESHOLD_MS = 2000; +static const PRUint32 QUICK_BUFFER_THRESHOLD_USECS = 2000000; // If we're quick buffering, we'll remain in buffering mode while we have less than -// QUICK_BUFFERING_LOW_DATA_MS of decoded data available. -static const PRUint32 QUICK_BUFFERING_LOW_DATA_MS = 1000; +// QUICK_BUFFERING_LOW_DATA_USECS of decoded data available. +static const PRUint32 QUICK_BUFFERING_LOW_DATA_USECS = 1000000; -// If QUICK_BUFFERING_LOW_DATA_MS is > AMPLE_AUDIO_MS, we won't exit +// If QUICK_BUFFERING_LOW_DATA_USECS is > AMPLE_AUDIO_USECS, we won't exit // quick buffering in a timely fashion, as the decode pauses when it -// reaches AMPLE_AUDIO_MS decoded data, and thus we'll never reach -// QUICK_BUFFERING_LOW_DATA_MS. -PR_STATIC_ASSERT(QUICK_BUFFERING_LOW_DATA_MS <= AMPLE_AUDIO_MS); +// reaches AMPLE_AUDIO_USECS decoded data, and thus we'll never reach +// QUICK_BUFFERING_LOW_DATA_USECS. +PR_STATIC_ASSERT(QUICK_BUFFERING_LOW_DATA_USECS <= AMPLE_AUDIO_USECS); -static TimeDuration MsToDuration(PRInt64 aMs) { - return TimeDuration::FromMilliseconds(static_cast(aMs)); +static TimeDuration UsecsToDuration(PRInt64 aUsecs) { + return TimeDuration::FromMilliseconds(static_cast(aUsecs) / USECS_PER_MS); } -static PRInt64 DurationToMs(TimeDuration aDuration) { - return static_cast(aDuration.ToSeconds() * 1000); +static PRInt64 DurationToUsecs(TimeDuration aDuration) { + return static_cast(aDuration.ToSeconds() * USECS_PER_S); } class nsAudioMetadataEventRunner : public nsRunnable @@ -214,7 +214,7 @@ PRBool nsBuiltinDecoderStateMachine::HasFutureAudio() const { // we've completely decoded all audio (but not finished playing it yet // as per 1). return !mAudioCompleted && - (AudioDecodedMs() > LOW_AUDIO_MS || mReader->mAudioQueue.IsFinished()); + (AudioDecodedUsecs() > LOW_AUDIO_USECS || mReader->mAudioQueue.IsFinished()); } PRBool nsBuiltinDecoderStateMachine::HaveNextFrameData() const { @@ -252,19 +252,19 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() // no longer be considered to be "pumping video". const unsigned videoPumpThreshold = AMPLE_VIDEO_FRAMES / 2; - // After the audio decode fills with more than audioPumpThresholdMs ms + // After the audio decode fills with more than audioPumpThreshold usecs // of decoded audio, we'll start to check whether the audio or video decode // is falling behind. - const unsigned audioPumpThresholdMs = LOW_AUDIO_MS * 2; + const unsigned audioPumpThreshold = LOW_AUDIO_USECS * 2; // Our local low audio threshold. We may increase this if we're slow to // decode video frames, in order to reduce the chance of audio underruns. - PRInt64 lowAudioThreshold = LOW_AUDIO_MS; + PRInt64 lowAudioThreshold = LOW_AUDIO_USECS; // Our local ample audio threshold. If we increase lowAudioThreshold, we'll // also increase this too appropriately (we don't want lowAudioThreshold to // be greater than ampleAudioThreshold, else we'd stop decoding!). - PRInt64 ampleAudioThreshold = AMPLE_AUDIO_MS; + PRInt64 ampleAudioThreshold = AMPLE_AUDIO_USECS; MediaQueue& videoQueue = mReader->mVideoQueue; MediaQueue& audioQueue = mReader->mAudioQueue; @@ -291,7 +291,7 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() // We don't want to consider skipping to the next keyframe if we've // only just started up the decode loop, so wait until we've decoded // some audio data before enabling the keyframe skip logic on audio. - if (audioPump && GetDecodedAudioDuration() >= audioPumpThresholdMs) { + if (audioPump && GetDecodedAudioDuration() >= audioPumpThreshold) { audioPump = PR_FALSE; } @@ -330,11 +330,11 @@ void nsBuiltinDecoderStateMachine::DecodeLoop() videoPlaying = mReader->DecodeVideoFrame(skipToNextKeyframe, currentTime); decodeTime = TimeStamp::Now() - start; } - if (THRESHOLD_FACTOR * DurationToMs(decodeTime) > lowAudioThreshold && + if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > lowAudioThreshold && !HasLowUndecodedData()) { lowAudioThreshold = - NS_MIN(THRESHOLD_FACTOR * DurationToMs(decodeTime), AMPLE_AUDIO_MS); + NS_MIN(THRESHOLD_FACTOR * DurationToUsecs(decodeTime), AMPLE_AUDIO_USECS); ampleAudioThreshold = NS_MAX(THRESHOLD_FACTOR * lowAudioThreshold, ampleAudioThreshold); LOG(PR_LOG_DEBUG, @@ -476,7 +476,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() // Calculate the number of samples that have been pushed onto the audio // hardware. PRInt64 playedSamples = 0; - if (!MsToSamples(audioStartTime, rate, playedSamples)) { + if (!UsecsToSamples(audioStartTime, rate, playedSamples)) { NS_WARNING("Int overflow converting playedSamples"); break; } @@ -488,7 +488,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() // Calculate the timestamp of the next chunk of audio in numbers of // samples. PRInt64 sampleTime = 0; - if (!MsToSamples(s->mTime, rate, sampleTime)) { + if (!UsecsToSamples(s->mTime, rate, sampleTime)) { NS_WARNING("Int overflow converting sampleTime"); break; } @@ -511,18 +511,18 @@ void nsBuiltinDecoderStateMachine::AudioLoop() } { MonitorAutoEnter mon(mDecoder->GetMonitor()); - PRInt64 playedMs; - if (!SamplesToMs(audioDuration, rate, playedMs)) { - NS_WARNING("Int overflow calculating playedMs"); + PRInt64 playedUsecs; + if (!SamplesToUsecs(audioDuration, rate, playedUsecs)) { + NS_WARNING("Int overflow calculating playedUsecs"); break; } - if (!AddOverflow(audioStartTime, playedMs, mAudioEndTime)) { + if (!AddOverflow(audioStartTime, playedUsecs, mAudioEndTime)) { NS_WARNING("Int overflow calculating audio end time"); break; } PRInt64 audioAhead = mAudioEndTime - GetMediaTime(); - if (audioAhead > AMPLE_AUDIO_MS && + if (audioAhead > AMPLE_AUDIO_USECS && audioDuration - samplesAtLastSleep > minWriteSamples) { samplesAtLastSleep = audioDuration; @@ -530,7 +530,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop() // significant amount ahead of the playback position. The decode // thread will be going to sleep, so we won't get any new samples // anyway, so sleep until we need to push to the hardware again. - Wait(AMPLE_AUDIO_MS / 2); + Wait(AMPLE_AUDIO_USECS / 2); // Kick the decode thread; since above we only do a NotifyAll when // we pop an audio chunk of the queue, the decoder won't wake up if // we've got no more decoded chunks to push to the hardware. We can @@ -561,8 +561,8 @@ void nsBuiltinDecoderStateMachine::AudioLoop() mState != DECODER_STATE_SEEKING && mState != DECODER_STATE_SHUTDOWN) { - const PRInt64 DRAIN_BLOCK_MS = 100; - Wait(NS_MIN(mAudioEndTime - position, DRAIN_BLOCK_MS)); + const PRInt64 DRAIN_BLOCK_USECS = 100000; + Wait(NS_MIN(mAudioEndTime - position, DRAIN_BLOCK_USECS)); oldPosition = position; position = GetMediaTime(); } @@ -685,7 +685,7 @@ void nsBuiltinDecoderStateMachine::StopPlayback(eStopMode aMode) // audio thread can block in the write, and we deadlock trying to acquire // the audio monitor upon resume playback. if (IsPlaying()) { - mPlayDuration += TimeStamp::Now() - mPlayStartTime; + mPlayDuration += DurationToUsecs(TimeStamp::Now() - mPlayStartTime); mPlayStartTime = TimeStamp(); } if (HasAudio()) { @@ -801,7 +801,7 @@ double nsBuiltinDecoderStateMachine::GetCurrentTime() const OnDecodeThread(), "Should be on main, decode, or state machine thread."); - return static_cast(mCurrentFrameTime) / 1000.0; + return static_cast(mCurrentFrameTime) / static_cast(USECS_PER_S); } PRInt64 nsBuiltinDecoderStateMachine::GetDuration() @@ -895,7 +895,7 @@ void nsBuiltinDecoderStateMachine::Seek(double aTime) "We shouldn't already be seeking"); NS_ASSERTION(mState >= DECODER_STATE_DECODING, "We should have loaded metadata"); - double t = aTime * 1000.0; + double t = aTime * static_cast(USECS_PER_S); if (t > PR_INT64_MAX) { // Prevent integer overflow. return; @@ -967,10 +967,10 @@ nsBuiltinDecoderStateMachine::StartDecodeThreads() return NS_OK; } -PRInt64 nsBuiltinDecoderStateMachine::AudioDecodedMs() const +PRInt64 nsBuiltinDecoderStateMachine::AudioDecodedUsecs() const { NS_ASSERTION(HasAudio(), - "Should only call AudioDecodedMs() when we have audio"); + "Should only call AudioDecodedUsecs() when we have audio"); // The amount of audio we have decoded is the amount of audio data we've // already decoded and pushed to the hardware, plus the amount of audio // data waiting to be pushed to the hardware. @@ -978,7 +978,7 @@ PRInt64 nsBuiltinDecoderStateMachine::AudioDecodedMs() const return pushed + mReader->mAudioQueue.Duration(); } -PRBool nsBuiltinDecoderStateMachine::HasLowDecodedData(PRInt64 aAudioMs) const +PRBool nsBuiltinDecoderStateMachine::HasLowDecodedData(PRInt64 aAudioUsecs) const { mDecoder->GetMonitor().AssertCurrentThreadIn(); // We consider ourselves low on decoded data if we're low on audio, @@ -987,7 +987,7 @@ PRBool nsBuiltinDecoderStateMachine::HasLowDecodedData(PRInt64 aAudioMs) const // we've not decoded to the end of the video stream. return ((HasAudio() && !mReader->mAudioQueue.IsFinished() && - AudioDecodedMs() < aAudioMs) + AudioDecodedUsecs() < aAudioUsecs) || (!HasAudio() && HasVideo() && @@ -997,7 +997,7 @@ PRBool nsBuiltinDecoderStateMachine::HasLowDecodedData(PRInt64 aAudioMs) const PRBool nsBuiltinDecoderStateMachine::HasLowUndecodedData() const { - return GetUndecodedData() < LOW_DATA_THRESHOLD_MS; + return GetUndecodedData() < LOW_DATA_THRESHOLD_USECS; } PRInt64 nsBuiltinDecoderStateMachine::GetUndecodedData() const @@ -1025,7 +1025,7 @@ PRInt64 nsBuiltinDecoderStateMachine::GetUndecodedData() const NS_ENSURE_SUCCESS(res, 0); if (start <= currentTime && end >= currentTime) { - return static_cast((end - currentTime) * 1000); + return static_cast((end - currentTime) * USECS_PER_S); } } return 0; @@ -1078,7 +1078,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() !mSeekable || mEndTime != -1, "Active seekable media should have end time"); NS_ASSERTION(!mSeekable || GetDuration() != -1, "Seekable media should have duration"); - LOG(PR_LOG_DEBUG, ("%p Media goes from %lldms to %lldms (duration %lldms) seekable=%d", + LOG(PR_LOG_DEBUG, ("%p Media goes from %lld to %lld (duration %lld) seekable=%d", mDecoder, mStartTime, mEndTime, GetDuration(), mSeekable)); if (mState == DECODER_STATE_SHUTDOWN) @@ -1179,7 +1179,7 @@ nsresult nsBuiltinDecoderStateMachine::Run() "Seek target should lie inside the first audio block after seek"); PRInt64 startTime = (audio && audio->mTime < seekTime) ? audio->mTime : seekTime; mAudioStartTime = startTime; - mPlayDuration = MsToDuration(startTime - mStartTime); + mPlayDuration = startTime - mStartTime; if (HasVideo()) { nsAutoPtr video(mReader->mVideoQueue.PeekFront()); if (video) { @@ -1212,12 +1212,12 @@ nsresult nsBuiltinDecoderStateMachine::Run() nsCOMPtr stopEvent; if (GetMediaTime() == mEndTime) { - LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lldms) to COMPLETED", + LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to COMPLETED", mDecoder, seekTime)); stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStoppedAtEnd); mState = DECODER_STATE_COMPLETED; } else { - LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lldms) to DECODING", + LOG(PR_LOG_DEBUG, ("%p Changed state from SEEKING (to %lld) to DECODING", mDecoder, seekTime)); stopEvent = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::SeekingStopped); StartDecoding(); @@ -1253,18 +1253,18 @@ nsresult nsBuiltinDecoderStateMachine::Run() PRBool isLiveStream = mDecoder->GetCurrentStream()->GetLength() == -1; if ((isLiveStream || !mDecoder->CanPlayThrough()) && elapsed < TimeDuration::FromSeconds(BUFFERING_WAIT) && - (mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_MS) - : (GetUndecodedData() < BUFFERING_WAIT * 1000)) && + (mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS) + : (GetUndecodedData() < BUFFERING_WAIT * USECS_PER_S)) && !stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) && !stream->IsSuspended()) { LOG(PR_LOG_DEBUG, ("Buffering: %.3lfs/%ds, timeout in %.3lfs %s", - GetUndecodedData() / 1000.0, + GetUndecodedData() / static_cast(USECS_PER_S), BUFFERING_WAIT, BUFFERING_WAIT - elapsed.ToSeconds(), (mQuickBuffering ? "(quick exit)" : ""))); - Wait(1000); + Wait(USECS_PER_S); if (mState == DECODER_STATE_SHUTDOWN) continue; } else { @@ -1387,7 +1387,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() // audio clock. Just wait and then return, to give the audio clock time // to tick. This should really wait for a specific signal from the audio // thread rather than polling after a sleep. See bug 568431 comment 4. - Wait(AUDIO_DURATION_MS); + Wait(AUDIO_DURATION_USECS); return; } @@ -1396,18 +1396,18 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() // audio, or don't have audio, use the system clock. PRInt64 clock_time = -1; if (!IsPlaying()) { - clock_time = DurationToMs(mPlayDuration) + mStartTime; + clock_time = mPlayDuration + mStartTime; } else { PRInt64 audio_time = GetAudioClock(); if (HasAudio() && !mAudioCompleted && audio_time != -1) { clock_time = audio_time; // Resync against the audio clock, while we're trusting the // audio clock. This ensures no "drift", particularly on Linux. - mPlayDuration = MsToDuration(clock_time - mStartTime); + mPlayDuration = clock_time - mStartTime; mPlayStartTime = TimeStamp::Now(); } else { // Sound is disabled on this system. Sync to the system clock. - clock_time = DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration); + clock_time = DurationToUsecs(TimeStamp::Now() - mPlayStartTime) + mPlayDuration; // Ensure the clock can never go backwards. NS_ASSERTION(mCurrentFrameTime <= clock_time, "Clock should go forwards"); clock_time = NS_MAX(mCurrentFrameTime, clock_time) + mStartTime; @@ -1416,7 +1416,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() // Skip frames up to the frame at the playback position, and figure out // the time remaining until it's time to display the next frame. - PRInt64 remainingTime = AUDIO_DURATION_MS; + PRInt64 remainingTime = AUDIO_DURATION_USECS; NS_ASSERTION(clock_time >= mStartTime, "Should have positive clock time."); nsAutoPtr currentFrame; if (mReader->mVideoQueue.GetSize() > 0) { @@ -1434,8 +1434,8 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() // present the next frame. if (frame && !currentFrame) { PRInt64 now = IsPlaying() - ? DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration) - : DurationToMs(mPlayDuration); + ? (DurationToUsecs(TimeStamp::Now() - mPlayStartTime) + mPlayDuration) + : mPlayDuration; remainingTime = frame->mTime - mStartTime - now; } } @@ -1445,7 +1445,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() nsMediaStream* stream = mDecoder->GetCurrentStream(); if (mState == DECODER_STATE_DECODING && mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING && - HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_MS) && + HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) && !stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) && !stream->IsSuspended() && (JustExitedQuickBuffering() || HasLowUndecodedData())) @@ -1466,8 +1466,8 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() if (currentFrame) { // Decode one frame and display it. - TimeStamp presTime = mPlayStartTime - mPlayDuration + - MsToDuration(currentFrame->mTime - mStartTime); + TimeStamp presTime = mPlayStartTime - UsecsToDuration(mPlayDuration) + + UsecsToDuration(currentFrame->mTime - mStartTime); NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time"); { nsIntSize display = mInfo.mDisplay; @@ -1480,7 +1480,7 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() } } mDecoder->GetFrameStatistics().NotifyPresentedFrame(); - PRInt64 now = DurationToMs(TimeStamp::Now() - mPlayStartTime + mPlayDuration); + PRInt64 now = DurationToUsecs(TimeStamp::Now() - mPlayStartTime) + mPlayDuration; remainingTime = currentFrame->mEndTime - mStartTime - now; currentFrame = nsnull; } @@ -1526,9 +1526,9 @@ void nsBuiltinDecoderStateMachine::AdvanceFrame() } } -void nsBuiltinDecoderStateMachine::Wait(PRInt64 aMs) { +void nsBuiltinDecoderStateMachine::Wait(PRInt64 aUsecs) { mDecoder->GetMonitor().AssertCurrentThreadIn(); - TimeStamp end = TimeStamp::Now() + MsToDuration(aMs); + TimeStamp end = TimeStamp::Now() + UsecsToDuration(aUsecs); TimeStamp now; while ((now = TimeStamp::Now()) < end && mState != DECODER_STATE_SHUTDOWN && @@ -1538,8 +1538,6 @@ void nsBuiltinDecoderStateMachine::Wait(PRInt64 aMs) { if (ms == 0 || ms > PR_UINT32_MAX) { break; } - NS_ASSERTION(ms <= aMs && ms > 0, - "nsBuiltinDecoderStateMachine::Wait interval very wrong!"); mDecoder->GetMonitor().Wait(PR_MillisecondsToInterval(static_cast(ms))); } } @@ -1571,7 +1569,7 @@ VideoData* nsBuiltinDecoderStateMachine::FindStartTime() // first acutal audio sample we have, we'll inject silence during playback // to ensure the audio starts at the correct time. mAudioStartTime = mStartTime; - LOG(PR_LOG_DEBUG, ("%p Media start time is %lldms", mDecoder, mStartTime)); + LOG(PR_LOG_DEBUG, ("%p Media start time is %lld", mDecoder, mStartTime)); return v; } @@ -1596,7 +1594,7 @@ void nsBuiltinDecoderStateMachine::FindEndTime() mEndTime = endTime; } - LOG(PR_LOG_DEBUG, ("%p Media end time is %lldms", mDecoder, mEndTime)); + LOG(PR_LOG_DEBUG, ("%p Media end time is %lld", mDecoder, mEndTime)); } void nsBuiltinDecoderStateMachine::UpdateReadyState() { @@ -1650,7 +1648,7 @@ PRBool nsBuiltinDecoderStateMachine::JustExitedQuickBuffering() { return !mDecodeStartTime.IsNull() && mQuickBuffering && - (TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromSeconds(QUICK_BUFFER_THRESHOLD_MS); + (TimeStamp::Now() - mDecodeStartTime) < TimeDuration::FromSeconds(QUICK_BUFFER_THRESHOLD_USECS); } void nsBuiltinDecoderStateMachine::StartBuffering() @@ -1663,7 +1661,7 @@ void nsBuiltinDecoderStateMachine::StartBuffering() // when the download speed is similar to the decode speed. mQuickBuffering = !JustExitedQuickBuffering() && - decodeDuration < TimeDuration::FromMilliseconds(QUICK_BUFFER_THRESHOLD_MS); + decodeDuration < UsecsToDuration(QUICK_BUFFER_THRESHOLD_USECS); mBufferingStart = TimeStamp::Now(); // We need to tell the element that buffering has started. diff --git a/content/media/nsBuiltinDecoderStateMachine.h b/content/media/nsBuiltinDecoderStateMachine.h index b9f59fdc9fa2..25e9afaa71be 100644 --- a/content/media/nsBuiltinDecoderStateMachine.h +++ b/content/media/nsBuiltinDecoderStateMachine.h @@ -249,23 +249,23 @@ public: protected: - // Returns PR_TRUE if we'v got less than aAudioMs ms of decoded and playable - // data. The decoder monitor must be held. - PRBool HasLowDecodedData(PRInt64 aAudioMs) const; + // Returns PR_TRUE if we've got less than aAudioUsecs microseconds of decoded + // and playable data. The decoder monitor must be held. + PRBool HasLowDecodedData(PRInt64 aAudioUsecs) const; // Returns PR_TRUE if we're running low on data which is not yet decoded. // The decoder monitor must be held. PRBool HasLowUndecodedData() const; - // Returns the number of milliseconds of undecoded data available for + // Returns the number of microseconds of undecoded data available for // decoding. The decoder monitor must be held. PRInt64 GetUndecodedData() const; - // Returns the number of unplayed ms of audio we've got decoded and/or + // Returns the number of unplayed usecs of audio we've got decoded and/or // pushed to the hardware waiting to play. This is how much audio we can // play without having to run the audio decoder. The decoder monitor // must be held. - PRInt64 AudioDecodedMs() const; + PRInt64 AudioDecodedUsecs() const; // Returns PR_TRUE when there's decoded audio waiting to play. // The decoder monitor must be held. @@ -274,13 +274,13 @@ protected: // Returns PR_TRUE if we recently exited "quick buffering" mode. PRBool JustExitedQuickBuffering(); - // Waits on the decoder Monitor for aMs. If the decoder monitor is awoken - // by a Notify() call, we'll continue waiting, unless we've moved into - // shutdown state. This enables us to ensure that we wait for a specified - // time, and that the myriad of Notify()s we do an the decoder monitor - // don't cause the audio thread to be starved. The decoder monitor must - // be locked. - void Wait(PRInt64 aMs); + // Waits on the decoder Monitor for aUsecs microseconds. If the decoder + // monitor is awoken by a Notify() call, we'll continue waiting, unless + // we've moved into shutdown state. This enables us to ensure that we + // wait for a specified time, and that the myriad of Notify()s we do an + // the decoder monitor don't cause the audio thread to be starved. The + // decoder monitor must be locked. + void Wait(PRInt64 aUsecs); // Dispatches an asynchronous event to update the media element's ready state. void UpdateReadyState(); @@ -330,7 +330,8 @@ protected: // hardware. This ensures that the playback position advances smoothly, and // guarantees that we don't try to allocate an impossibly large chunk of // memory in order to play back silence. Called on the audio thread. - PRUint32 PlaySilence(PRUint32 aSamples, PRUint32 aChannels, + PRUint32 PlaySilence(PRUint32 aSamples, + PRUint32 aChannels, PRUint64 aSampleOffset); // Pops an audio chunk from the front of the audio queue, and pushes its @@ -388,9 +389,9 @@ protected: return mStartTime + mCurrentFrameTime; } - // Returns an upper bound on the number of milliseconds of audio that is - // decoded and playable. This is the sum of the number of ms of audio which - // is decoded and in the reader's audio queue, and the ms of unplayed audio + // Returns an upper bound on the number of microseconds of audio that is + // decoded and playable. This is the sum of the number of usecs of audio which + // is decoded and in the reader's audio queue, and the usecs of unplayed audio // which has been pushed to the audio hardware for playback. Note that after // calling this, the audio hardware may play some of the audio pushed to // hardware, so this can only be used as a upper bound. The decoder monitor @@ -426,25 +427,25 @@ protected: // playback position is therefore |Now() - mPlayStartTime + // mPlayDuration|, which must be adjusted by mStartTime if used with media // timestamps. Accessed only via the state machine thread. - TimeDuration mPlayDuration; + PRInt64 mPlayDuration; // Time that buffering started. Used for buffering timeout and only // accessed on the state machine thread. This is null while we're not // buffering. TimeStamp mBufferingStart; - // Start time of the media, in milliseconds. This is the presentation + // Start time of the media, in microseconds. This is the presentation // time of the first sample decoded from the media, and is used to calculate // duration and as a bounds for seeking. Accessed on state machine and // main thread. Access controlled by decoder monitor. PRInt64 mStartTime; - // Time of the last page in the media, in milliseconds. This is the + // Time of the last page in the media, in microseconds. This is the // end time of the last sample in the media. Accessed on state // machine and main thread. Access controlled by decoder monitor. PRInt64 mEndTime; - // Position to seek to in milliseconds when the seek state transition occurs. + // Position to seek to in microseconds when the seek state transition occurs. // The decoder monitor lock must be obtained before reading or writing // this value. Accessed on main and state machine thread. PRInt64 mSeekTime; @@ -459,24 +460,25 @@ protected: // in the play state machine's destructor. nsAutoPtr mReader; - // The time of the current frame in milliseconds. This is referenced from + // The time of the current frame in microseconds. This is referenced from // 0 which is the initial playback position. Set by the state machine // thread, and read-only from the main thread to get the current // time value. Synchronised via decoder monitor. PRInt64 mCurrentFrameTime; - // The presentation time of the first audio sample that was played. We can - // add this to the audio stream position to determine the current audio time. - // Accessed on audio and state machine thread. Synchronized by decoder monitor. + // The presentation time of the first audio sample that was played in + // microseconds. We can add this to the audio stream position to determine + // the current audio time. Accessed on audio and state machine thread. + // Synchronized by decoder monitor. PRInt64 mAudioStartTime; // The end time of the last audio sample that's been pushed onto the audio - // hardware. This will approximately be the end time of the audio stream, - // unless another sample is pushed to the hardware. + // hardware in microseconds. This will approximately be the end time of the + // audio stream, unless another sample is pushed to the hardware. PRInt64 mAudioEndTime; - // The presentation end time of the last video frame which has been displayed. - // Accessed from the state machine thread. + // The presentation end time of the last video frame which has been displayed + // in microseconds. Accessed from the state machine thread. PRInt64 mVideoFrameEndTime; // Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written diff --git a/content/media/nsMediaCache.cpp b/content/media/nsMediaCache.cpp index 19c53790df1b..0d04abb0077d 100644 --- a/content/media/nsMediaCache.cpp +++ b/content/media/nsMediaCache.cpp @@ -740,7 +740,7 @@ static PRInt32 GetMaxBlocks() // to the pref are applied. // Cache size is in KB PRInt32 cacheSize = nsContentUtils::GetIntPref("media.cache_size", 500*1024); - PRInt64 maxBlocks = PRInt64(cacheSize)*1024/nsMediaCache::BLOCK_SIZE; + PRInt64 maxBlocks = static_cast(cacheSize)*1024/nsMediaCache::BLOCK_SIZE; maxBlocks = PR_MAX(maxBlocks, 1); return PRInt32(PR_MIN(maxBlocks, PR_INT32_MAX)); } @@ -1032,7 +1032,7 @@ nsMediaCache::PredictNextUse(TimeStamp aNow, PRInt32 aBlock) case PLAYED_BLOCK: // This block should be managed in LRU mode, and we should impose // a "replay delay" to reflect the likelihood of replay happening - NS_ASSERTION(PRInt64(bo->mStreamBlock)*BLOCK_SIZE < + NS_ASSERTION(static_cast(bo->mStreamBlock)*BLOCK_SIZE < bo->mStream->mStreamOffset, "Played block after the current stream position?"); prediction = aNow - bo->mLastUseTime + @@ -1040,7 +1040,7 @@ nsMediaCache::PredictNextUse(TimeStamp aNow, PRInt32 aBlock) break; case READAHEAD_BLOCK: { PRInt64 bytesAhead = - PRInt64(bo->mStreamBlock)*BLOCK_SIZE - bo->mStream->mStreamOffset; + static_cast(bo->mStreamBlock)*BLOCK_SIZE - bo->mStream->mStreamOffset; NS_ASSERTION(bytesAhead >= 0, "Readahead block before the current stream position?"); PRInt64 millisecondsAhead = diff --git a/content/media/nsMediaDecoder.h b/content/media/nsMediaDecoder.h index 6e2d7cefdb9c..7187c35a1e69 100644 --- a/content/media/nsMediaDecoder.h +++ b/content/media/nsMediaDecoder.h @@ -282,10 +282,10 @@ public: // Return the frame decode/paint related statistics. FrameStatistics& GetFrameStatistics() { return mFrameStats; } - // Set the duration of the media resource in units of milliseconds. + // Set the duration of the media resource in units of seconds. // This is called via a channel listener if it can pick up the duration // from a content header. Must be called from the main thread only. - virtual void SetDuration(PRInt64 aDuration) = 0; + virtual void SetDuration(double aDuration) = 0; // Set a flag indicating whether seeking is supported virtual void SetSeekable(PRBool aSeekable) = 0; diff --git a/content/media/nsMediaStream.cpp b/content/media/nsMediaStream.cpp index e31eb620159b..30c97be9e039 100644 --- a/content/media/nsMediaStream.cpp +++ b/content/media/nsMediaStream.cpp @@ -221,7 +221,7 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest) if (NS_SUCCEEDED(rv)) { double duration = durationText.ToDouble(&ec); if (ec == NS_OK && duration >= 0) { - mDecoder->SetDuration(PRInt64(NS_round(duration*1000))); + mDecoder->SetDuration(duration); } } } diff --git a/content/media/nsMediaStream.h b/content/media/nsMediaStream.h index 4c4632cfc48b..1f47eb70e8f9 100644 --- a/content/media/nsMediaStream.h +++ b/content/media/nsMediaStream.h @@ -107,7 +107,7 @@ public: *aReliable = seconds >= 1.0; if (seconds <= 0.0) return 0.0; - return double(mAccumulatedBytes)/seconds; + return static_cast(mAccumulatedBytes)/seconds; } double GetRate(TimeStamp aNow, PRPackedBool* aReliable) { TimeDuration time = mAccumulatedTime; @@ -118,7 +118,7 @@ public: *aReliable = seconds >= 3.0; if (seconds <= 0.0) return 0.0; - return double(mAccumulatedBytes)/seconds; + return static_cast(mAccumulatedBytes)/seconds; } private: PRInt64 mAccumulatedBytes; diff --git a/content/media/ogg/nsOggCodecState.cpp b/content/media/ogg/nsOggCodecState.cpp index 02c27ab0a409..ef62b915ab0d 100644 --- a/content/media/ogg/nsOggCodecState.cpp +++ b/content/media/ogg/nsOggCodecState.cpp @@ -126,7 +126,6 @@ nsTheoraState::nsTheoraState(ogg_page* aBosPage) : nsOggCodecState(aBosPage), mSetup(0), mCtx(0), - mFrameDuration(0), mPixelAspectRatio(0) { MOZ_COUNT_CTOR(nsTheoraState); @@ -146,22 +145,9 @@ PRBool nsTheoraState::Init() { if (!mActive) return PR_FALSE; - PRInt64 n = mInfo.fps_numerator; - PRInt64 d = mInfo.fps_denominator; + PRInt64 n = mInfo.aspect_numerator; + PRInt64 d = mInfo.aspect_denominator; - PRInt64 f; - if (!MulOverflow(1000, d, f)) { - return mActive = PR_FALSE; - } - f /= n; - if (f > PR_UINT32_MAX) { - return mActive = PR_FALSE; - } - mFrameDuration = static_cast(f); - - n = mInfo.aspect_numerator; - - d = mInfo.aspect_denominator; mPixelAspectRatio = (n == 0 || d == 0) ? 1.0f : static_cast(n) / static_cast(d); @@ -244,7 +230,7 @@ PRInt64 nsTheoraState::Time(th_info* aInfo, PRInt64 aGranulepos) PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1); if (!AddOverflow(frameno, 1, t)) return -1; - if (!MulOverflow(t, 1000, t)) + if (!MulOverflow(t, USECS_PER_S, t)) return -1; if (!MulOverflow(t, aInfo->fps_denominator, t)) return -1; @@ -257,7 +243,7 @@ PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) { } PRInt64 t = 0; PRInt64 frameno = th_granule_frame(mCtx, granulepos); - if (!MulOverflow(frameno, 1000, t)) + if (!MulOverflow(frameno, USECS_PER_S, t)) return -1; if (!MulOverflow(t, mInfo.fps_denominator, t)) return -1; @@ -267,25 +253,22 @@ PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) { PRInt64 nsTheoraState::MaxKeyframeOffset() { - // Determine the maximum time in milliseconds by which a key frame could + // Determine the maximum time in microseconds by which a key frame could // offset for the theora bitstream. Theora granulepos encode time as: // ((key_frame_number << granule_shift) + frame_offset). // Therefore the maximum possible time by which any frame could be offset // from a keyframe is the duration of (1 << granule_shift) - 1) frames. PRInt64 frameDuration; - PRInt64 keyframeDiff; - - PRInt64 shift = mInfo.keyframe_granule_shift; - + // Max number of frames keyframe could possibly be offset. - keyframeDiff = (1 << shift) - 1; + PRInt64 keyframeDiff = (1 << mInfo.keyframe_granule_shift) - 1; - // Length of frame in ms. + // Length of frame in usecs. PRInt64 d = 0; // d will be 0 if multiplication overflows. - MulOverflow(1000, mInfo.fps_denominator, d); + MulOverflow(USECS_PER_S, mInfo.fps_denominator, d); frameDuration = d / mInfo.fps_numerator; - // Total time in ms keyframe can be offset from any given frame. + // Total time in usecs keyframe can be offset from any given frame. return frameDuration * keyframeDiff; } @@ -390,7 +373,7 @@ PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos) return -1; } PRInt64 t = 0; - MulOverflow(1000, aGranulepos, t); + MulOverflow(USECS_PER_S, aGranulepos, t); return t / aInfo->rate; } @@ -522,7 +505,7 @@ PRBool nsSkeletonState::DecodeIndex(ogg_packet* aPacket) // Extract the start time. n = LEInt64(p + INDEX_FIRST_NUMER_OFFSET); PRInt64 t; - if (!MulOverflow(n, 1000, t)) { + if (!MulOverflow(n, USECS_PER_S, t)) { return (mActive = PR_FALSE); } else { startTime = t / timeDenom; @@ -530,7 +513,7 @@ PRBool nsSkeletonState::DecodeIndex(ogg_packet* aPacket) // Extract the end time. n = LEInt64(p + INDEX_LAST_NUMER_OFFSET); - if (!MulOverflow(n, 1000, t)) { + if (!MulOverflow(n, USECS_PER_S, t)) { return (mActive = PR_FALSE); } else { endTime = t / timeDenom; @@ -590,11 +573,11 @@ PRBool nsSkeletonState::DecodeIndex(ogg_packet* aPacket) { return (mActive = PR_FALSE); } - PRInt64 timeMs = 0; - if (!MulOverflow(time, 1000, timeMs)) + PRInt64 timeUsecs = 0; + if (!MulOverflow(time, USECS_PER_S, timeUsecs)) return mActive = PR_FALSE; - timeMs /= timeDenom; - keyPoints->Add(offset, timeMs); + timeUsecs /= timeDenom; + keyPoints->Add(offset, timeUsecs); numKeyPointsRead++; } @@ -713,7 +696,7 @@ PRBool nsSkeletonState::DecodeHeader(ogg_packet* aPacket) // presentation time exists in all versions. PRInt64 n = LEInt64(aPacket->packet + SKELETON_PRESENTATION_TIME_NUMERATOR_OFFSET); PRInt64 d = LEInt64(aPacket->packet + SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET); - mPresentationTime = d == 0 ? 0 : (static_cast(n) / static_cast(d)) * 1000; + mPresentationTime = d == 0 ? 0 : (static_cast(n) / static_cast(d)) * USECS_PER_S; mVersion = SKELETON_VERSION(verMajor, verMinor); if (mVersion < SKELETON_VERSION(4,0) || diff --git a/content/media/ogg/nsOggCodecState.h b/content/media/ogg/nsOggCodecState.h index e45ff33eb559..20121cec57da 100644 --- a/content/media/ogg/nsOggCodecState.h +++ b/content/media/ogg/nsOggCodecState.h @@ -183,7 +183,7 @@ public: virtual PRInt64 StartTime(PRInt64 granulepos); virtual PRBool Init(); - // Returns the maximum number of milliseconds which a keyframe can be offset + // Returns the maximum number of microseconds which a keyframe can be offset // from any given interframe. PRInt64 MaxKeyframeOffset(); @@ -195,9 +195,6 @@ public: th_setup_info *mSetup; th_dec_ctx* mCtx; - // Frame duration in ms. - PRUint32 mFrameDuration; - float mPixelAspectRatio; }; @@ -233,7 +230,7 @@ public: // Offset from start of segment/link-in-the-chain in bytes. PRInt64 mOffset; - // Presentation time in ms. + // Presentation time in usecs. PRInt64 mTime; PRBool IsNull() { @@ -320,10 +317,10 @@ private: return mKeyPoints.Length(); } - // Presentation time of the first sample in this stream in ms. + // Presentation time of the first sample in this stream in usecs. const PRInt64 mStartTime; - // End time of the last sample in this stream in ms. + // End time of the last sample in this stream in usecs. const PRInt64 mEndTime; private: diff --git a/content/media/ogg/nsOggReader.cpp b/content/media/ogg/nsOggReader.cpp index 598d9f9b59ab..bc71749cbb6b 100644 --- a/content/media/ogg/nsOggReader.cpp +++ b/content/media/ogg/nsOggReader.cpp @@ -68,15 +68,15 @@ extern PRLogModuleInfo* gBuiltinDecoderLog; // position, we'll just decode forwards rather than performing a bisection // search. If we have Theora video we use the maximum keyframe interval as // this value, rather than SEEK_DECODE_MARGIN. This makes small seeks faster. -#define SEEK_DECODE_MARGIN 2000 +#define SEEK_DECODE_MARGIN 2000000 -// The number of milliseconds of "fuzz" we use in a bisection search over +// The number of microseconds of "fuzz" we use in a bisection search over // HTTP. When we're seeking with fuzz, we'll stop the search if a bisection -// lands between the seek target and SEEK_FUZZ_MS milliseconds before the +// lands between the seek target and SEEK_FUZZ_USECS microseconds before the // seek target. This is becaue it's usually quicker to just keep downloading // from an exisiting connection than to do another bisection inside that // small range, which would open a new HTTP connetion. -#define SEEK_FUZZ_MS 500 +#define SEEK_FUZZ_USECS 500000 enum PageSyncResult { PAGE_SYNC_ERROR = 1, @@ -390,8 +390,7 @@ nsresult nsOggReader::DecodeVorbis(nsTArray >& aChunks, } PRInt64 duration = mVorbisState->Time((PRInt64)samples); - PRInt64 startTime = (mVorbisGranulepos != -1) ? - mVorbisState->Time(mVorbisGranulepos) : -1; + PRInt64 startTime = mVorbisState->Time(mVorbisGranulepos); SoundData* s = new SoundData(mPageOffset, startTime, duration, @@ -544,9 +543,8 @@ nsresult nsOggReader::DecodeTheora(nsTArray >& aFrames, if (ret != 0 && ret != TH_DUPFRAME) { return NS_ERROR_FAILURE; } - PRInt64 time = (aPacket->granulepos != -1) - ? mTheoraState->StartTime(aPacket->granulepos) : -1; - PRInt64 endTime = time != -1 ? time + mTheoraState->mFrameDuration : -1; + PRInt64 time = mTheoraState->StartTime(aPacket->granulepos); + PRInt64 endTime = mTheoraState->Time(aPacket->granulepos); if (ret == TH_DUPFRAME) { VideoData* v = VideoData::CreateDuplicate(mPageOffset, time, @@ -699,7 +697,7 @@ PRBool nsOggReader::DecodeVideoFrame(PRBool &aKeyframeSkip, th_granule_frame(mTheoraState->mCtx, granulepos) + 1, "Granulepos calculation is incorrect!"); frames[i]->mTime = mTheoraState->StartTime(granulepos); - frames[i]->mEndTime = frames[i]->mTime + mTheoraState->mFrameDuration; + frames[i]->mEndTime = mTheoraState->Time(granulepos); NS_ASSERTION(frames[i]->mEndTime >= frames[i]->mTime, "Frame must start before it ends."); frames[i]->mTimecode = granulepos; succGranulepos = granulepos; @@ -1246,7 +1244,7 @@ nsresult nsOggReader::SeekInBufferedRange(PRInt64 aTarget, aStartTime, aEndTime, PR_FALSE); - res = SeekBisection(keyframeTime, k, SEEK_FUZZ_MS); + res = SeekBisection(keyframeTime, k, SEEK_FUZZ_USECS); NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); } @@ -1272,7 +1270,7 @@ nsresult nsOggReader::SeekInUnbuffered(PRInt64 aTarget, LOG(PR_LOG_DEBUG, ("%p Seeking in unbuffered data to %lldms using bisection search", mDecoder, aTarget)); // If we've got an active Theora bitstream, determine the maximum possible - // time in ms which a keyframe could be before a given interframe. We + // time in usecs which a keyframe could be before a given interframe. We // subtract this from our seek target, seek to the new target, and then // will decode forward to the original seek target. We should encounter a // keyframe in that interval. This prevents us from needing to run two @@ -1291,7 +1289,7 @@ nsresult nsOggReader::SeekInUnbuffered(PRInt64 aTarget, // Minimize the bisection search space using the known timestamps from the // buffered ranges. SeekRange k = SelectSeekRange(aRanges, seekTarget, aStartTime, aEndTime, PR_FALSE); - nsresult res = SeekBisection(seekTarget, k, SEEK_FUZZ_MS); + nsresult res = SeekBisection(seekTarget, k, SEEK_FUZZ_USECS); NS_ASSERTION(mTheoraGranulepos == -1, "SeekBisection must reset Theora decode"); NS_ASSERTION(mVorbisGranulepos == -1, "SeekBisection must reset Vorbis decode"); return res; @@ -1775,9 +1773,8 @@ nsresult nsOggReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime) // find an end time. PRInt64 endTime = FindEndTime(startOffset, endOffset, PR_TRUE, &state); if (endTime != -1) { - endTime -= aStartTime; - aBuffered->Add(static_cast(startTime) / 1000.0, - static_cast(endTime) / 1000.0); + aBuffered->Add(startTime / static_cast(USECS_PER_S), + (endTime - aStartTime) / static_cast(USECS_PER_S)); } } } diff --git a/content/media/ogg/nsOggReader.h b/content/media/ogg/nsOggReader.h index ae412c0085d5..725f02db2633 100644 --- a/content/media/ogg/nsOggReader.h +++ b/content/media/ogg/nsOggReader.h @@ -104,8 +104,8 @@ private: // Returns PR_TRUE if we should decode up to the seek target rather than // seeking to the target using a bisection search or index-assisted seek. - // We should do this if the seek target (aTarget, in ms), lies not too far - // ahead of the current playback position (aCurrentTime, in ms). + // We should do this if the seek target (aTarget, in usecs), lies not too far + // ahead of the current playback position (aCurrentTime, in usecs). PRBool CanDecodeToTarget(PRInt64 aTarget, PRInt64 aCurrentTime); @@ -152,10 +152,10 @@ private: } PRInt64 mOffsetStart, mOffsetEnd; // in bytes. - PRInt64 mTimeStart, mTimeEnd; // in ms. + PRInt64 mTimeStart, mTimeEnd; // in usecs. }; - // Seeks to aTarget ms in the buffered range aRange using bisection search, + // Seeks to aTarget usecs in the buffered range aRange using bisection search, // or to the keyframe prior to aTarget if we have video. aStartTime must be // the presentation time at the start of media, and aEndTime the time at // end of media. aRanges must be the time/byte ranges buffered in the media @@ -166,7 +166,7 @@ private: const nsTArray& aRanges, const SeekRange& aRange); - // Seeks to before aTarget ms in media using bisection search. If the media + // Seeks to before aTarget usecs in media using bisection search. If the media // has video, this will seek to before the keyframe required to render the // media at aTarget. Will use aRanges in order to narrow the bisection // search space. aStartTime must be the presentation time at the start of @@ -208,11 +208,11 @@ private: PRBool ReadOggPacket(nsOggCodecState* aCodecState, ogg_packet* aPacket); // Performs a seek bisection to move the media stream's read cursor to the - // last ogg page boundary which has end time before aTarget ms on both the + // last ogg page boundary which has end time before aTarget usecs on both the // Theora and Vorbis bitstreams. Limits its search to data inside aRange; // i.e. it will only read inside of the aRange's start and end offsets. - // aFuzz is the number of ms of leniency we'll allow; we'll terminate the - // seek when we land in the range (aTime - aFuzz, aTime) ms. + // aFuzz is the number of usecs of leniency we'll allow; we'll terminate the + // seek when we land in the range (aTime - aFuzz, aTime) usecs. nsresult SeekBisection(PRInt64 aTarget, const SeekRange& aRange, PRUint32 aFuzz); @@ -228,7 +228,7 @@ private: nsresult GetSeekRanges(nsTArray& aRanges); // Returns the range in which you should perform a seek bisection if - // you wish to seek to aTarget ms, given the known (buffered) byte ranges + // you wish to seek to aTarget usecs, given the known (buffered) byte ranges // in aRanges. If aExact is PR_TRUE, we only return an exact copy of a // range in which aTarget lies, or a null range if aTarget isn't contained // in any of the (buffered) ranges. Otherwise, when aExact is PR_FALSE, diff --git a/content/media/raw/nsRawReader.cpp b/content/media/raw/nsRawReader.cpp index b5cffd1c31ff..ee30c89bb6b6 100644 --- a/content/media/raw/nsRawReader.cpp +++ b/content/media/raw/nsRawReader.cpp @@ -129,7 +129,7 @@ nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo) if (length != -1) { mozilla::MonitorAutoExit autoExitMonitor(mMonitor); mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); - mDecoder->GetStateMachine()->SetDuration(1000 * + mDecoder->GetStateMachine()->SetDuration(USECS_PER_S * (length - sizeof(nsRawVideoHeader)) / (mFrameSize * mFrameRate)); } @@ -184,7 +184,7 @@ PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, if (!mFrameSize) return PR_FALSE; // Metadata read failed. We should refuse to play. - PRInt64 currentFrameTime = 1000 * mCurrentFrame / mFrameRate; + PRInt64 currentFrameTime = USECS_PER_S * mCurrentFrame / mFrameRate; PRUint32 length = mFrameSize - sizeof(nsRawPacketHeader); nsAutoPtr buffer(new PRUint8[length]); @@ -212,7 +212,7 @@ PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, break; mCurrentFrame++; - currentFrameTime += 1000.0 / mFrameRate; + currentFrameTime += static_cast(USECS_PER_S) / mFrameRate; } VideoData::YCbCrBuffer b; @@ -237,7 +237,7 @@ PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, mDecoder->GetImageContainer(), -1, currentFrameTime, - currentFrameTime + (1000 / mFrameRate), + currentFrameTime + (USECS_PER_S / mFrameRate), b, 1, // In raw video every frame is a keyframe -1); @@ -247,7 +247,7 @@ PRBool nsRawReader::DecodeVideoFrame(PRBool &aKeyframeSkip, mVideoQueue.Push(v); mCurrentFrame++; decoded++; - currentFrameTime += 1000 / mFrameRate; + currentFrameTime += USECS_PER_S / mFrameRate; return PR_TRUE; } @@ -264,7 +264,7 @@ nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRUint32 frame = mCurrentFrame; if (aTime >= UINT_MAX) return NS_ERROR_FAILURE; - mCurrentFrame = aTime * mFrameRate / 1000; + mCurrentFrame = aTime * mFrameRate / USECS_PER_S; PRUint32 offset; if (!MulOverflow32(mCurrentFrame, mFrameSize, offset)) diff --git a/content/media/test/test_seekLies.html b/content/media/test/test_seekLies.html index 8c30ddd1feaa..13447cb499d9 100644 --- a/content/media/test/test_seekLies.html +++ b/content/media/test/test_seekLies.html @@ -13,7 +13,7 @@ function on_metadataloaded() { var v = document.getElementById('v'); var d = Math.round(v.duration*1000); - ok(d == 3999, "Checking duration: " + d); + ok(d == 4000, "Checking duration: " + d); SimpleTest.finish(); } diff --git a/content/media/wave/nsWaveReader.cpp b/content/media/wave/nsWaveReader.cpp index d7b384fe79b8..d4fceec68e91 100644 --- a/content/media/wave/nsWaveReader.cpp +++ b/content/media/wave/nsWaveReader.cpp @@ -171,9 +171,8 @@ nsresult nsWaveReader::ReadMetadata(nsVideoInfo* aInfo) MonitorAutoExit exitReaderMon(mMonitor); MonitorAutoEnter decoderMon(mDecoder->GetMonitor()); - float d = floorf(BytesToTime(GetDataLength() * 1000)); - NS_ASSERTION(d <= PR_INT64_MAX, "Duration overflow"); - mDecoder->GetStateMachine()->SetDuration(static_cast(d)); + mDecoder->GetStateMachine()->SetDuration( + static_cast(BytesToTime(GetDataLength()) * USECS_PER_S)); return NS_OK; } @@ -229,16 +228,18 @@ PRBool nsWaveReader::DecodeAudioData() } } - float posTime = BytesToTime(pos); - float readSizeTime = BytesToTime(readSize); - NS_ASSERTION(posTime <= PR_INT64_MAX / 1000, "posTime overflow"); - NS_ASSERTION(readSizeTime <= PR_INT64_MAX / 1000, "readSizeTime overflow"); + double posTime = BytesToTime(pos); + double readSizeTime = BytesToTime(readSize); + NS_ASSERTION(posTime <= PR_INT64_MAX / USECS_PER_S, "posTime overflow"); + NS_ASSERTION(readSizeTime <= PR_INT64_MAX / USECS_PER_S, "readSizeTime overflow"); NS_ASSERTION(samples < PR_INT32_MAX, "samples overflow"); - mAudioQueue.Push(new SoundData(pos, static_cast(posTime * 1000), - static_cast(readSizeTime * 1000), + mAudioQueue.Push(new SoundData(pos, + static_cast(posTime * USECS_PER_S), + static_cast(readSizeTime * USECS_PER_S), static_cast(samples), - sampleBuffer.forget(), mChannels)); + sampleBuffer.forget(), + mChannels)); return PR_TRUE; } @@ -258,15 +259,15 @@ nsresult nsWaveReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTim MonitorAutoEnter mon(mMonitor); NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread."); - LOG(PR_LOG_DEBUG, ("%p About to seek to %lldms", mDecoder, aTarget)); + LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget)); if (NS_FAILED(ResetDecode())) { return NS_ERROR_FAILURE; } - float d = BytesToTime(GetDataLength()); - NS_ASSERTION(d < PR_INT64_MAX / 1000, "Duration overflow"); - PRInt64 duration = static_cast(d) * 1000; - PRInt64 seekTime = NS_MIN(aTarget, duration); - PRInt64 position = RoundDownToSample(static_cast(TimeToBytes(seekTime) / 1000.f)); + double d = BytesToTime(GetDataLength()); + NS_ASSERTION(d < PR_INT64_MAX / USECS_PER_S, "Duration overflow"); + PRInt64 duration = static_cast(d * USECS_PER_S); + double seekTime = NS_MIN(aTarget, duration) / static_cast(USECS_PER_S); + PRInt64 position = RoundDownToSample(static_cast(TimeToBytes(seekTime))); NS_ASSERTION(PR_INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek"); position += mWavePCMOffset; return mDecoder->GetCurrentStream()->Seek(nsISeekableStream::NS_SEEK_SET, position); @@ -281,8 +282,8 @@ nsresult nsWaveReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime) NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); - aBuffered->Add(floorf(BytesToTime(startOffset - mWavePCMOffset) * 1000.f) / 1000.0, - floorf(BytesToTime(endOffset - mWavePCMOffset) * 1000.f) / 1000.0); + aBuffered->Add(BytesToTime(startOffset - mWavePCMOffset), + BytesToTime(endOffset - mWavePCMOffset)); startOffset = mDecoder->GetCurrentStream()->GetNextCachedData(endOffset); } return NS_OK; @@ -508,7 +509,7 @@ nsWaveReader::FindDataOffset() return PR_TRUE; } -float +double nsWaveReader::BytesToTime(PRInt64 aBytes) const { NS_ABORT_IF_FALSE(aBytes >= 0, "Must be >= 0"); @@ -516,7 +517,7 @@ nsWaveReader::BytesToTime(PRInt64 aBytes) const } PRInt64 -nsWaveReader::TimeToBytes(float aTime) const +nsWaveReader::TimeToBytes(double aTime) const { NS_ABORT_IF_FALSE(aTime >= 0.0f, "Must be >= 0"); return RoundDownToSample(PRInt64(aTime * mSampleRate * mSampleSize)); diff --git a/content/media/wave/nsWaveReader.h b/content/media/wave/nsWaveReader.h index a5a9a6e07651..fbf615b7506a 100644 --- a/content/media/wave/nsWaveReader.h +++ b/content/media/wave/nsWaveReader.h @@ -76,13 +76,13 @@ private: // Returns the number of seconds that aBytes represents based on the // current audio parameters. e.g. 176400 bytes is 1 second at 16-bit - // stereo 44.1kHz. The time is rounded to the nearest millisecond. - float BytesToTime(PRInt64 aBytes) const; + // stereo 44.1kHz. The time is rounded to the nearest microsecond. + double BytesToTime(PRInt64 aBytes) const; // Returns the number of bytes that aTime represents based on the current // audio parameters. e.g. 1 second is 176400 bytes at 16-bit stereo // 44.1kHz. - PRInt64 TimeToBytes(float aTime) const; + PRInt64 TimeToBytes(double aTime) const; // Rounds aBytes down to the nearest complete sample. Assumes beginning // of byte range is already sample aligned by caller. diff --git a/content/media/webm/nsWebMBufferedParser.cpp b/content/media/webm/nsWebMBufferedParser.cpp index 02349080d75d..0f724e37ecb6 100644 --- a/content/media/webm/nsWebMBufferedParser.cpp +++ b/content/media/webm/nsWebMBufferedParser.cpp @@ -44,7 +44,6 @@ using mozilla::MonitorAutoEnter; static const double NS_PER_S = 1e9; -static const double MS_PER_S = 1e3; static PRUint32 VIntLength(unsigned char aFirstByte, PRUint32* aMask) diff --git a/content/media/webm/nsWebMReader.cpp b/content/media/webm/nsWebMReader.cpp index 9a62ac531d21..06742f702306 100644 --- a/content/media/webm/nsWebMReader.cpp +++ b/content/media/webm/nsWebMReader.cpp @@ -65,14 +65,13 @@ extern PRLogModuleInfo* gBuiltinDecoderLog; #define SEEK_LOG(type, msg) #endif -static const unsigned NS_PER_MS = 1000000; +static const unsigned NS_PER_USEC = 1000; static const double NS_PER_S = 1e9; -static const double MS_PER_S = 1e3; -// If a seek request is within SEEK_DECODE_MARGIN milliseconds of the +// If a seek request is within SEEK_DECODE_MARGIN microseconds of the // current time, decode ahead from the current frame rather than performing // a full seek. -static const int SEEK_DECODE_MARGIN = 250; +static const int SEEK_DECODE_MARGIN = 250000; NS_SPECIALIZE_TEMPLATE class nsAutoRefTraits : public nsPointerRefTraits @@ -136,7 +135,7 @@ nsWebMReader::nsWebMReader(nsBuiltinDecoder* aDecoder) mChannels(0), mVideoTrack(0), mAudioTrack(0), - mAudioStartMs(-1), + mAudioStartUsec(-1), mAudioSamples(0), mHasVideo(PR_FALSE), mHasAudio(PR_FALSE) @@ -184,7 +183,7 @@ nsresult nsWebMReader::Init(nsBuiltinDecoderReader* aCloneDonor) nsresult nsWebMReader::ResetDecode() { mAudioSamples = 0; - mAudioStartMs = -1; + mAudioStartUsec = -1; nsresult res = NS_OK; if (NS_FAILED(nsBuiltinDecoderReader::ResetDecode())) { res = NS_ERROR_FAILURE; @@ -229,7 +228,7 @@ nsresult nsWebMReader::ReadMetadata(nsVideoInfo* aInfo) if (r == 0) { MonitorAutoExit exitReaderMon(mMonitor); MonitorAutoEnter decoderMon(mDecoder->GetMonitor()); - mDecoder->GetStateMachine()->SetDuration(duration / NS_PER_MS); + mDecoder->GetStateMachine()->SetDuration(duration / NS_PER_USEC); } unsigned int ntracks = 0; @@ -435,23 +434,23 @@ PRBool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset) } const PRUint32 rate = mVorbisDsp.vi->rate; - PRUint64 tstamp_ms = tstamp / NS_PER_MS; - if (mAudioStartMs == -1) { + PRUint64 tstamp_usecs = tstamp / NS_PER_USEC; + if (mAudioStartUsec == -1) { // This is the first audio chunk. Assume the start time of our decode // is the start of this chunk. - mAudioStartMs = tstamp_ms; + mAudioStartUsec = tstamp_usecs; } // If there's a gap between the start of this sound chunk and the end of // the previous sound chunk, we need to increment the packet count so that // the vorbis decode doesn't use data from before the gap to help decode // from after the gap. PRInt64 tstamp_samples = 0; - if (!MsToSamples(tstamp_ms, rate, tstamp_samples)) { + if (!UsecsToSamples(tstamp_usecs, rate, tstamp_samples)) { NS_WARNING("Int overflow converting WebM timestamp to samples"); return PR_FALSE; } PRInt64 decoded_samples = 0; - if (!MsToSamples(mAudioStartMs, rate, decoded_samples)) { + if (!UsecsToSamples(mAudioStartUsec, rate, decoded_samples)) { NS_WARNING("Int overflow converting WebM start time to samples"); return PR_FALSE; } @@ -461,13 +460,13 @@ PRBool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset) } if (tstamp_samples > decoded_samples) { #ifdef DEBUG - PRInt64 ms = 0; - LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lldms, %lld samples, in audio stream\n", - SamplesToMs(tstamp_samples - decoded_samples, rate, ms) ? ms: -1, + PRInt64 usecs = 0; + LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld samples, in audio stream\n", + SamplesToUsecs(tstamp_samples - decoded_samples, rate, usecs) ? usecs: -1, tstamp_samples - decoded_samples)); #endif mPacketCount++; - mAudioStartMs = tstamp_ms; + mAudioStartUsec = tstamp_usecs; mAudioSamples = 0; } @@ -503,17 +502,17 @@ PRBool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset) } PRInt64 duration = 0; - if (!SamplesToMs(samples, rate, duration)) { + if (!SamplesToUsecs(samples, rate, duration)) { NS_WARNING("Int overflow converting WebM audio duration"); return PR_FALSE; } PRInt64 total_duration = 0; - if (!SamplesToMs(total_samples, rate, total_duration)) { + if (!SamplesToUsecs(total_samples, rate, total_duration)) { NS_WARNING("Int overflow converting WebM audio total_duration"); return PR_FALSE; } - PRInt64 time = tstamp_ms + total_duration; + PRInt64 time = tstamp_usecs + total_duration; total_samples += samples; SoundData* s = new SoundData(aOffset, time, @@ -668,11 +667,11 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, if (endTime == -1) { return PR_FALSE; } - next_tstamp = endTime * NS_PER_MS; + next_tstamp = endTime * NS_PER_USEC; } } - PRInt64 tstamp_ms = tstamp / NS_PER_MS; + PRInt64 tstamp_usecs = tstamp / NS_PER_USEC; for (PRUint32 i = 0; i < count; ++i) { unsigned char* data; size_t length; @@ -685,7 +684,7 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, memset(&si, 0, sizeof(si)); si.sz = sizeof(si); vpx_codec_peek_stream_info(&vpx_codec_vp8_dx_algo, data, length, &si); - if (aKeyframeSkip && (!si.is_kf || tstamp_ms < aTimeThreshold)) { + if (aKeyframeSkip && (!si.is_kf || tstamp_usecs < aTimeThreshold)) { // Skipping to next keyframe... parsed++; // Assume 1 frame per chunk. continue; @@ -702,7 +701,7 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, // If the timestamp of the video frame is less than // the time threshold required then it is not added // to the video queue and won't be displayed. - if (tstamp_ms < aTimeThreshold) { + if (tstamp_usecs < aTimeThreshold) { parsed++; // Assume 1 frame per chunk. continue; } @@ -733,8 +732,8 @@ PRBool nsWebMReader::DecodeVideoFrame(PRBool &aKeyframeSkip, VideoData *v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), holder->mOffset, - tstamp_ms, - next_tstamp / NS_PER_MS, + tstamp_usecs, + next_tstamp / NS_PER_USEC, b, si.is_kf, -1); @@ -774,7 +773,7 @@ nsresult nsWebMReader::Seek(PRInt64 aTarget, PRInt64 aStartTime, PRInt64 aEndTim return NS_ERROR_FAILURE; } PRUint32 trackToSeek = mHasVideo ? mVideoTrack : mAudioTrack; - int r = nestegg_track_seek(mContext, trackToSeek, aTarget * NS_PER_MS); + int r = nestegg_track_seek(mContext, trackToSeek, aTarget * NS_PER_USEC); if (r != 0) { return NS_ERROR_FAILURE; } @@ -803,7 +802,7 @@ nsresult nsWebMReader::GetBuffered(nsTimeRanges* aBuffered, PRInt64 aStartTime) nsresult res = stream->GetCachedRanges(ranges); NS_ENSURE_SUCCESS(res, res); - PRInt64 startTimeOffsetNS = aStartTime * NS_PER_MS; + PRInt64 startTimeOffsetNS = aStartTime * NS_PER_USEC; for (PRUint32 index = 0; index < ranges.Length(); index++) { mBufferedState->CalculateBufferedForRange(aBuffered, ranges[index].mStart, diff --git a/content/media/webm/nsWebMReader.h b/content/media/webm/nsWebMReader.h index 37a99dd06f9c..e08ab1a81e57 100644 --- a/content/media/webm/nsWebMReader.h +++ b/content/media/webm/nsWebMReader.h @@ -192,8 +192,8 @@ private: // Returns PR_TRUE if we should decode up to the seek target rather than // seeking to the target using an index-assisted seek. We should do this - // if the seek target (aTarget, in ms), lies not too far ahead of the - // current playback position (aCurrentTime, in ms). + // if the seek target (aTarget, in usecs), lies not too far ahead of the + // current playback position (aCurrentTime, in usecs). PRBool CanDecodeToTarget(PRInt64 aTarget, PRInt64 aCurrentTime); private: @@ -221,8 +221,8 @@ private: PRUint32 mVideoTrack; PRUint32 mAudioTrack; - // Time in ms of the start of the first audio sample we've decoded. - PRInt64 mAudioStartMs; + // Time in microseconds of the start of the first audio sample we've decoded. + PRInt64 mAudioStartUsec; // Number of samples we've decoded since decoding began at mAudioStartMs. PRUint64 mAudioSamples;