Bug 1097375 - Implement MediaSource::setDuration. r=kinetik

--HG--
extra : rebase_source : 7e5f5387de5db3deccc6e74222b32f461359beb2
This commit is contained in:
Matt Woodrow 2014-11-12 17:11:33 +13:00
parent 16cff43fd3
commit b370384d2c
5 changed files with 83 additions and 30 deletions

View File

@ -166,7 +166,8 @@ MediaSource::Duration()
if (mReadyState == MediaSourceReadyState::Closed) {
return UnspecifiedNaN<double>();
}
return mDuration;
MOZ_ASSERT(mDecoder);
return mDecoder->GetMediaSourceDuration();
}
void
@ -183,7 +184,7 @@ MediaSource::SetDuration(double aDuration, ErrorResult& aRv)
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
DurationChange(aDuration, aRv);
mDecoder->SetMediaSourceDuration(aDuration);
}
already_AddRefed<SourceBuffer>
@ -271,7 +272,7 @@ MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, Er
mSourceBuffers->Ended();
mDecoder->Ended();
if (!aError.WasPassed()) {
DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
mDecoder->SetMediaSourceDuration(mSourceBuffers->GetHighestBufferedEndTime());
if (aRv.Failed()) {
return;
}
@ -336,7 +337,6 @@ MediaSource::Detach()
mDecoder = nullptr;
mFirstSourceBufferInitialized = false;
SetReadyState(MediaSourceReadyState::Closed);
mDuration = UnspecifiedNaN<double>();
if (mActiveSourceBuffers) {
mActiveSourceBuffers->Clear();
}
@ -347,7 +347,6 @@ MediaSource::Detach()
MediaSource::MediaSource(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
, mDuration(UnspecifiedNaN<double>())
, mDecoder(nullptr)
, mPrincipal(nullptr)
, mReadyState(MediaSourceReadyState::Closed)
@ -416,23 +415,19 @@ MediaSource::QueueAsyncSimpleEvent(const char* aName)
}
void
MediaSource::DurationChange(double aNewDuration, ErrorResult& aRv)
MediaSource::DurationChange(double aOldDuration, double aNewDuration)
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("MediaSource(%p)::DurationChange(aNewDuration=%f)", this, aNewDuration);
if (mDuration == aNewDuration) {
return;
}
double oldDuration = mDuration;
mDuration = aNewDuration;
if (aNewDuration < oldDuration) {
mSourceBuffers->Remove(aNewDuration, oldDuration, aRv);
if (aRv.Failed()) {
if (aNewDuration < aOldDuration) {
ErrorResult rv;
mSourceBuffers->Remove(aNewDuration, aOldDuration, rv);
if (rv.Failed()) {
return;
}
}
// TODO: If partial audio frames/text cues exist, clamp duration based on mSourceBuffers.
// TODO: Update media element's duration and run element's duration change algorithm.
}
void

View File

@ -120,12 +120,10 @@ private:
void DispatchSimpleEvent(const char* aName);
void QueueAsyncSimpleEvent(const char* aName);
void DurationChange(double aNewDuration, ErrorResult& aRv);
void DurationChange(double aOldDuration, double aNewDuration);
void InitializationEvent();
double mDuration;
nsRefPtr<SourceBufferList> mSourceBuffers;
nsRefPtr<SourceBufferList> mActiveSourceBuffers;

View File

@ -33,6 +33,7 @@ class SourceBufferDecoder;
MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
: mMediaSource(nullptr)
, mMediaSourceDuration(UnspecifiedNaN<double>())
{
Init(aElement);
}
@ -171,15 +172,74 @@ MediaSourceDecoder::IsExpectingMoreData()
return !mReader->IsEnded();
}
class DurationChangedRunnable : public nsRunnable {
public:
explicit DurationChangedRunnable(MediaSourceDecoder* aDecoder,
double aOldDuration,
double aNewDuration)
: mDecoder(aDecoder)
, mOldDuration(aOldDuration)
, mNewDuration(aNewDuration)
{ }
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
mDecoder->DurationChanged(mOldDuration, mNewDuration);
return NS_OK;
}
private:
RefPtr<MediaSourceDecoder> mDecoder;
double mOldDuration;
double mNewDuration;
};
void
MediaSourceDecoder::DurationChanged(double aOldDuration, double aNewDuration)
{
MOZ_ASSERT(NS_IsMainThread());
// Run the MediaSource duration changed algorithm
if (mMediaSource) {
mMediaSource->DurationChange(aOldDuration, aNewDuration);
}
// Run the MediaElement duration changed algorithm
MediaDecoder::DurationChanged();
}
void
MediaSourceDecoder::SetDecodedDuration(int64_t aDuration)
{
// Only use the decoded duration if one wasn't already
// set.
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (!mMediaSource || !IsNaN(mMediaSourceDuration)) {
return;
}
double duration = aDuration;
duration /= USECS_PER_S;
SetMediaSourceDuration(duration);
}
void
MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mMediaSource) {
return;
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
double oldDuration = mMediaSourceDuration;
mMediaSourceDuration = aDuration;
mDecoderStateMachine->SetDuration(aDuration * USECS_PER_S);
if (NS_IsMainThread()) {
DurationChanged(oldDuration, aDuration);
} else {
nsRefPtr<nsIRunnable> task =
new DurationChangedRunnable(this, oldDuration, aDuration);
NS_DispatchToMainThread(task);
}
ErrorResult dummy;
mMediaSource->DurationChange(aDuration, dummy);
}
double
MediaSourceDecoder::GetMediaSourceDuration()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mMediaSourceDuration;
}
void

View File

@ -54,7 +54,10 @@ public:
void Ended();
bool IsExpectingMoreData() MOZ_OVERRIDE;
void SetDecodedDuration(int64_t aDuration);
void SetMediaSourceDuration(double aDuration);
double GetMediaSourceDuration();
void DurationChanged(double aOldDuration, double aNewDuration);
// Called whenever a TrackBuffer has new data appended or a new decoder
// initializes. Safe to call from any thread.
@ -74,6 +77,9 @@ private:
// mMediaSource.
dom::MediaSource* mMediaSource;
nsRefPtr<MediaSourceReader> mReader;
// Protected by GetReentrantMonitor()
double mMediaSourceDuration;
};
} // namespace mozilla

View File

@ -630,13 +630,7 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
}
if (maxDuration != -1) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->SetMediaDuration(maxDuration);
nsRefPtr<nsIRunnable> task (
NS_NewRunnableMethodWithArg<double>(static_cast<MediaSourceDecoder*>(mDecoder),
&MediaSourceDecoder::SetMediaSourceDuration,
static_cast<double>(maxDuration) / USECS_PER_S));
NS_DispatchToMainThread(task);
static_cast<MediaSourceDecoder*>(mDecoder)->SetDecodedDuration(maxDuration);
}
*aInfo = mInfo;