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); MOZ_ALWAYS_TRUE(found); if (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(std::move(holder)); return promise; }
void DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo) { AssertOwnerThread(); MOZ_ASSERT(mStartTime.isNothing(), "playback already started."); mStartTime.emplace(aStartTime); mInfo = aInfo; mPlaying = true; ConnectListener(); class R : public Runnable { typedef MozPromiseHolder<GenericPromise> Promise; public: R(PlaybackInfoInit&& aInit, Promise&& aPromise, OutputStreamManager* aManager) : mInit(Move(aInit)), mOutputStreamManager(aManager) { mPromise = Move(aPromise); } NS_IMETHOD Run() override { MOZ_ASSERT(NS_IsMainThread()); // No need to create a source stream when there are no output streams. This // happens when RemoveOutput() is called immediately after StartPlayback(). if (!mOutputStreamManager->Graph()) { // Resolve the promise to indicate the end of playback. mPromise.Resolve(true, __func__); return NS_OK; } mData = MakeUnique<DecodedStreamData>( mOutputStreamManager, Move(mInit), Move(mPromise)); return NS_OK; } UniquePtr<DecodedStreamData> ReleaseData() { return Move(mData); } private: PlaybackInfoInit mInit; Promise mPromise; RefPtr<OutputStreamManager> mOutputStreamManager; UniquePtr<DecodedStreamData> mData; }; MozPromiseHolder<GenericPromise> promise; mFinishPromise = promise.Ensure(__func__); PlaybackInfoInit init { aStartTime, aInfo }; nsCOMPtr<nsIRunnable> r = new R(Move(init), Move(promise), mOutputStreamManager); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); SyncRunnable::DispatchToThread(mainThread, r); mData = static_cast<R*>(r.get())->ReleaseData(); if (mData) { mData->SetPlaying(mPlaying); SendData(); } }
RefPtr<GenericPromise> CheckTrackKeyFrame(MediaTrackDemuxer* aTrackDemuxer) { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); RefPtr<MediaTrackDemuxer> track = aTrackDemuxer; RefPtr<MP4DemuxerBinding> binding = this; int64_t time = -1; while (mIndex < mSamples.Length()) { uint32_t i = mIndex++; if (mSamples[i]->mKeyframe) { time = mSamples[i]->mTime; break; } } RefPtr<GenericPromise> p = mCheckTrackKeyFramePromise.Ensure(__func__); if (time == -1) { mCheckTrackKeyFramePromise.Resolve(true, __func__); return p; } DispatchTask( [track, time, binding] () { track->Seek(media::TimeUnit::FromMicroseconds(time))->Then(binding->mTaskQueue, __func__, [track, time, binding] () { track->GetSamples()->Then(binding->mTaskQueue, __func__, [track, time, binding] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) { EXPECT_EQ(time, aSamples->mSamples[0]->mTime); binding->CheckTrackKeyFrame(track); }, DO_FAIL ); }, DO_FAIL ); } ); return p; }
RefPtr<GenericPromise> CheckTrackSamples(MediaTrackDemuxer* aTrackDemuxer) { MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); RefPtr<MediaTrackDemuxer> track = aTrackDemuxer; RefPtr<MP4DemuxerBinding> binding = this; RefPtr<GenericPromise> p = mCheckTrackSamples.Ensure(__func__); DispatchTask( [track, binding] () { track->GetSamples()->Then(binding->mTaskQueue, __func__, [track, binding] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) { if (aSamples->mSamples.Length()) { binding->mSamples.AppendElements(aSamples->mSamples); binding->CheckTrackSamples(track); } }, [binding] (DemuxerFailureReason aReason) { if (aReason == DemuxerFailureReason::DEMUXER_ERROR) { EXPECT_TRUE(false); binding->mCheckTrackSamples.Reject(NS_ERROR_FAILURE, __func__); } else if (aReason == DemuxerFailureReason::END_OF_STREAM) { EXPECT_TRUE(binding->mSamples.Length() > 1); for (uint32_t i = 0; i < (binding->mSamples.Length() - 1); i++) { EXPECT_LT(binding->mSamples[i]->mTimecode, binding->mSamples[i + 1]->mTimecode); if (binding->mSamples[i]->mKeyframe) { binding->mKeyFrameTimecodes.AppendElement(binding->mSamples[i]->mTimecode); } } binding->mCheckTrackSamples.Resolve(true, __func__); } } ); } ); return p; }
void DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo) { AssertOwnerThread(); MOZ_ASSERT(mStartTime.isNothing(), "playback already started."); mStartTime.emplace(aStartTime); mInfo = aInfo; mPlaying = true; ConnectListener(); class R : public nsRunnable { typedef MozPromiseHolder<GenericPromise> Promise; typedef void(DecodedStream::*Method)(Promise&&); public: R(DecodedStream* aThis, Method aMethod, Promise&& aPromise) : mThis(aThis), mMethod(aMethod) { mPromise = Move(aPromise); } NS_IMETHOD Run() override { (mThis->*mMethod)(Move(mPromise)); return NS_OK; } private: nsRefPtr<DecodedStream> mThis; Method mMethod; Promise mPromise; }; MozPromiseHolder<GenericPromise> promise; mFinishPromise = promise.Ensure(__func__); nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(promise)); AbstractThread::MainThread()->Dispatch(r.forget()); }