Bug 1362165: P7. Only complete appendBuffer once readyState has changed. r=jwwang

MSE specs require that the readyState be modified during either the Initialization Segment Received or the Coded Frame Processing algorithms.

At this stage, we only handle the Initialization Segment part (readyState moving from HAVE_NOTHING to HAVE_METADATA)

MozReview-Commit-ID: KBnnWuHJ6Om

--HG--
extra : rebase_source : a4450139762d5d033438fbee2ce560fe02ed6ffc
This commit is contained in:
Jean-Yves Avenard 2017-05-09 12:23:11 +02:00
Родитель 5c7678f322
Коммит a16fab66e4
5 изменённых файлов: 68 добавлений и 5 удалений

Просмотреть файл

@ -1658,6 +1658,9 @@ void HTMLMediaElement::ShutdownDecoder()
RemoveMediaElementFromURITable();
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
mWaitingForKeyListener.DisconnectIfExists();
if (mMediaSource) {
mMediaSource->CompletePendingTransactions();
}
mDecoder->Shutdown();
mDecoder = nullptr;
}
@ -5583,6 +5586,12 @@ HTMLMediaElement::UpdateReadyStateInternal()
MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
}
if (mMediaSource) {
// readyState has changed, assuming it's following the pending mediasource
// operations. Notify the Mediasource that the operations have completed.
mMediaSource->CompletePendingTransactions();
}
enum NextFrameStatus nextFrameStatus = NextFrameStatus();
if (nextFrameStatus == NEXT_FRAME_UNAVAILABLE ||
(nextFrameStatus == NEXT_FRAME_UNAVAILABLE_BUFFERING &&

Просмотреть файл

@ -12,6 +12,7 @@
#include "DecoderDoctorDiagnostics.h"
#include "MediaContainerType.h"
#include "MediaResult.h"
#include "MediaSourceDemuxer.h"
#include "MediaSourceUtils.h"
#include "SourceBuffer.h"
#include "SourceBufferList.h"
@ -255,11 +256,12 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv)
return sourceBuffer.forget();
}
void
RefPtr<MediaSource::ActiveCompletionPromise>
MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
{
MOZ_ASSERT(NS_IsMainThread());
mActiveSourceBuffers->ClearSimple();
bool initMissing = false;
bool found = false;
for (uint32_t i = 0; i < mSourceBuffers->Length(); i++) {
SourceBuffer* sourceBuffer = mSourceBuffers->IndexedGetter(i, found);
@ -268,8 +270,35 @@ MediaSource::SourceBufferIsActive(SourceBuffer* aSourceBuffer)
mActiveSourceBuffers->Append(aSourceBuffer);
} else if (sourceBuffer->IsActive()) {
mActiveSourceBuffers->AppendSimple(sourceBuffer);
} else {
// Some source buffers haven't yet received an init segment.
// There's nothing more we can do at this stage.
initMissing = true;
}
}
if (initMissing || !mDecoder) {
return ActiveCompletionPromise::CreateAndResolve(true, __func__);
}
mDecoder->NotifyInitDataArrived();
// Add our promise to the queue.
// It will be resolved once the HTMLMediaElement modifies its readyState.
MozPromiseHolder<ActiveCompletionPromise> holder;
RefPtr<ActiveCompletionPromise> promise = holder.Ensure(__func__);
mCompletionPromises.AppendElement(Move(holder));
return promise;
}
void
MediaSource::CompletePendingTransactions()
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("Resolving %u promises", unsigned(mCompletionPromises.Length()));
for (auto& promise : mCompletionPromises) {
promise.Resolve(true, __func__);
}
mCompletionPromises.Clear();
}
void
@ -433,6 +462,7 @@ void
MediaSource::Detach()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mCompletionPromises.IsEmpty());
MSE_DEBUG("mDecoder=%p owner=%p",
mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
if (!mDecoder) {

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/MozPromise.h"
#include "mozilla/dom/MediaSourceBinding.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionNoteChild.h"
@ -119,6 +120,9 @@ public:
return mAbstractMainThread;
}
// Resolve all CompletionPromise pending.
void CompletePendingTransactions();
private:
// SourceBuffer uses SetDuration and SourceBufferIsActive
friend class mozilla::dom::SourceBuffer;
@ -136,8 +140,14 @@ private:
// SetDuration with no checks.
void SetDuration(double aDuration);
typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true>
ActiveCompletionPromise;
// Mark SourceBuffer as active and rebuild ActiveSourceBuffers.
void SourceBufferIsActive(SourceBuffer* aSourceBuffer);
// Return a MozPromise that will be resolved once all related operations are
// completed, or can't progress any further.
// Such as, transition of readyState from HAVE_NOTHING to HAVE_METADATA.
RefPtr<ActiveCompletionPromise> SourceBufferIsActive(
SourceBuffer* aSourceBuffer);
RefPtr<SourceBufferList> mSourceBuffers;
RefPtr<SourceBufferList> mActiveSourceBuffers;
@ -154,6 +164,7 @@ private:
MediaSourceReadyState mReadyState;
Maybe<media::TimeInterval> mLiveSeekableRange;
nsTArray<MozPromiseHolder<ActiveCompletionPromise>> mCompletionPromises;
};
NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)

Просмотреть файл

@ -212,6 +212,7 @@ void
SourceBuffer::AbortBufferAppend()
{
if (mUpdating) {
mCompletionPromise.DisconnectIfExists();
if (mPendingAppend.Exists()) {
mPendingAppend.Disconnect();
mTrackBuffersManager->AbortAppendData();
@ -433,8 +434,16 @@ SourceBuffer::AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBuffe
if (aResult.first()) {
if (!mActive) {
mActive = true;
mMediaSource->SourceBufferIsActive(this);
mMediaSource->GetDecoder()->NotifyInitDataArrived();
MSE_DEBUG("Init segment received");
RefPtr<SourceBuffer> self = this;
mMediaSource->SourceBufferIsActive(this)
->Then(mAbstractMainThread, __func__,
[self, this]() {
MSE_DEBUG("Complete AppendBuffer operation");
mCompletionPromise.Complete();
StopUpdating();
})
->Track(mCompletionPromise);
}
}
if (mActive) {
@ -448,7 +457,9 @@ SourceBuffer::AppendDataCompletedWithSuccess(const SourceBufferTask::AppendBuffe
CheckEndTime();
StopUpdating();
if (!mCompletionPromise.Exists()) {
StopUpdating();
}
}
void

Просмотреть файл

@ -182,6 +182,8 @@ private:
const MediaContainerType mType;
RefPtr<TimeRanges> mBuffered;
MozPromiseRequestHolder<MediaSource::ActiveCompletionPromise> mCompletionPromise;
};
} // namespace dom