void BenchmarkPlayback::DemuxNextSample() { MOZ_ASSERT(OnThread()); RefPtr<Benchmark> ref(mGlobalState); RefPtr<MediaTrackDemuxer::SamplesPromise> promise = mTrackDemuxer->GetSamples(); promise->Then( Thread(), __func__, [this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> aHolder) { mSamples.AppendElements(std::move(aHolder->mSamples)); if (ref->mParameters.mStopAtFrame && mSamples.Length() == ref->mParameters.mStopAtFrame.ref()) { InitDecoder(std::move(*mTrackDemuxer->GetInfo())); } else { Dispatch( NS_NewRunnableFunction("BenchmarkPlayback::DemuxNextSample", [this, ref]() { DemuxNextSample(); })); } }, [this, ref](const MediaResult& aError) { switch (aError.Code()) { case NS_ERROR_DOM_MEDIA_END_OF_STREAM: InitDecoder(std::move(*mTrackDemuxer->GetInfo())); break; default: Error(aError); break; } }); }
void BenchmarkPlayback::DemuxNextSample() { MOZ_ASSERT(OnThread()); RefPtr<Benchmark> ref(mMainThreadState); RefPtr<MediaTrackDemuxer::SamplesPromise> promise = mTrackDemuxer->GetSamples(); promise->Then( Thread(), __func__, [this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> aHolder) { mSamples.AppendElements(Move(aHolder->mSamples)); if (ref->mParameters.mStopAtFrame && mSamples.Length() == (size_t)ref->mParameters.mStopAtFrame.ref()) { InitDecoder(Move(*mTrackDemuxer->GetInfo())); } else { Dispatch(NS_NewRunnableFunction([this, ref]() { DemuxNextSample(); })); } }, [this, ref](DemuxerFailureReason aReason) { switch (aReason) { case DemuxerFailureReason::END_OF_STREAM: InitDecoder(Move(*mTrackDemuxer->GetInfo())); break; default: MainThreadShutdown(); } }); }
void BenchmarkPlayback::MainThreadShutdown() { MOZ_ASSERT(OnThread()); if (mDecoder) { mDecoder->Flush(); mDecoder->Shutdown(); mDecoder = nullptr; } mDecoderTaskQueue->BeginShutdown(); mDecoderTaskQueue->AwaitShutdownAndIdle(); mDecoderTaskQueue = nullptr; if (mTrackDemuxer) { mTrackDemuxer->Reset(); mTrackDemuxer->BreakCycles(); mTrackDemuxer = nullptr; } RefPtr<Benchmark> ref(mMainThreadState); Thread()->AsTaskQueue()->BeginShutdown()->Then( ref->Thread(), __func__, [ref]() { ref->Dispose(); }, []() { MOZ_CRASH("not reached"); }); }
void BenchmarkPlayback::InputExhausted() { MOZ_ASSERT(OnThread()); if (mFinished || mSampleIndex >= mSamples.Length()) { return; } RefPtr<Benchmark> ref(mMainThreadState); mDecoder->Decode(mSamples[mSampleIndex]) ->Then(Thread(), __func__, [ref, this](const MediaDataDecoder::DecodedData& aResults) { Output(aResults); InputExhausted(); }, [ref, this](const MediaResult& aError) { MainThreadShutdown(); }); mSampleIndex++; if (mSampleIndex == mSamples.Length()) { if (ref->mParameters.mStopAtFrame) { mSampleIndex = 0; } else { mDecoder->Drain()->Then( Thread(), __func__, [ref, this](const MediaDataDecoder::DecodedData& aResults) { mDrained = true; Output(aResults); }, [ref, this](const MediaResult& aError) { MainThreadShutdown(); }); } } }
void Benchmark::ReturnResult(uint32_t aDecodeFps) { MOZ_ASSERT(OnThread()); mPromise.ResolveIfExists(aDecodeFps, __func__); }
void Benchmark::Dispose() { MOZ_ASSERT(OnThread()); mKeepAliveUntilComplete = nullptr; mPromise.RejectIfExists(false, __func__); }
void BenchmarkPlayback::Error(const MediaResult& aError) { MOZ_ASSERT(OnThread()); RefPtr<Benchmark> ref(mGlobalState); GlobalShutdown(); ref->Dispatch( NS_NewRunnableFunction("BenchmarkPlayback::Error", [ref, aError]() { ref->ReturnError(aError); })); }
void BenchmarkPlayback::DemuxSamples() { MOZ_ASSERT(OnThread()); RefPtr<Benchmark> ref(mMainThreadState); mDemuxer->Init()->Then( Thread(), __func__, [this, ref](nsresult aResult) { MOZ_ASSERT(OnThread()); mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); if (!mTrackDemuxer) { MainThreadShutdown(); } DemuxNextSample(); }, [this, ref](DemuxerFailureReason aReason) { MainThreadShutdown(); }); }
RefPtr<Benchmark::BenchmarkPromise> Benchmark::Run() { MOZ_ASSERT(OnThread()); RefPtr<BenchmarkPromise> p = mPromise.Ensure(__func__); RefPtr<Benchmark> self = this; mPlaybackState.Dispatch( NS_NewRunnableFunction([self]() { self->mPlaybackState.DemuxSamples(); })); return p; }
void BenchmarkPlayback::DemuxSamples() { MOZ_ASSERT(OnThread()); RefPtr<Benchmark> ref(mGlobalState); mDemuxer->Init()->Then( Thread(), __func__, [this, ref](nsresult aResult) { MOZ_ASSERT(OnThread()); if (mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack)) { mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0); } else if (mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack)) { mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0); } if (!mTrackDemuxer) { Error(MediaResult(NS_ERROR_FAILURE, "Can't create track demuxer")); return; } DemuxNextSample(); }, [this, ref](const MediaResult& aError) { Error(aError); }); }
void BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo) { MOZ_ASSERT(OnThread()); RefPtr<PDMFactory> platform = new PDMFactory(); mDecoder = platform->CreateDecoder({aInfo, mDecoderTaskQueue}); if (!mDecoder) { Error(MediaResult(NS_ERROR_FAILURE, "Failed to create decoder")); return; } RefPtr<Benchmark> ref(mGlobalState); mDecoder->Init()->Then( Thread(), __func__, [this, ref](TrackInfo::TrackType aTrackType) { InputExhausted(); }, [this, ref](const MediaResult& aError) { Error(aError); }); }
bool GraphRunner::RunByGraphDriver(GraphDriver* aDriver) { if (!OnThread()) { return false; } if (auto audioDriver = aDriver->AsAudioCallbackDriver()) { return audioDriver->ThreadId() == mAudioDriverThreadId; } if (auto clockDriver = aDriver->AsSystemClockDriver()) { return clockDriver->Thread() == mClockDriverThread; } MOZ_CRASH("Unknown driver"); }
void BenchmarkPlayback::InputExhausted() { MOZ_ASSERT(OnThread()); MOZ_ASSERT(!mFinished); if (mSampleIndex >= mSamples.Length()) { Error(MediaResult(NS_ERROR_FAILURE, "Nothing left to decode")); return; } RefPtr<MediaRawData> sample = mSamples[mSampleIndex]; RefPtr<Benchmark> ref(mGlobalState); RefPtr<MediaDataDecoder::DecodePromise> p = mDecoder->Decode(sample); mSampleIndex++; if (mSampleIndex == mSamples.Length() && !ref->mParameters.mStopAtFrame) { // Complete current frame decode then drain if still necessary. p->Then(Thread(), __func__, [ref, this](MediaDataDecoder::DecodedData&& aResults) { Output(std::move(aResults)); if (!mFinished) { mDecoder->Drain()->Then( Thread(), __func__, [ref, this](MediaDataDecoder::DecodedData&& aResults) { mDrained = true; Output(std::move(aResults)); MOZ_ASSERT(mFinished, "We must be done now"); }, [ref, this](const MediaResult& aError) { Error(aError); }); } }, [ref, this](const MediaResult& aError) { Error(aError); }); } else { if (mSampleIndex == mSamples.Length() && ref->mParameters.mStopAtFrame) { mSampleIndex = 0; } // Continue decoding p->Then(Thread(), __func__, [ref, this](MediaDataDecoder::DecodedData&& aResults) { Output(std::move(aResults)); if (!mFinished) { InputExhausted(); } }, [ref, this](const MediaResult& aError) { Error(aError); }); } }
void BenchmarkPlayback::FinalizeShutdown() { MOZ_ASSERT(OnThread()); MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already"); MOZ_DIAGNOSTIC_ASSERT(mDecoderTaskQueue->IsEmpty()); mDecoderTaskQueue = nullptr; if (mTrackDemuxer) { mTrackDemuxer->Reset(); mTrackDemuxer->BreakCycles(); mTrackDemuxer = nullptr; } mDemuxer = nullptr; RefPtr<Benchmark> ref(mGlobalState); ref->Thread()->Dispatch(NS_NewRunnableFunction( "BenchmarkPlayback::FinalizeShutdown", [ref]() { ref->Dispose(); })); }
void BenchmarkPlayback::InputExhausted() { RefPtr<Benchmark> ref(mMainThreadState); Dispatch(NS_NewRunnableFunction([this, ref]() { MOZ_ASSERT(OnThread()); if (mFinished || mSampleIndex >= mSamples.Length()) { return; } mDecoder->Input(mSamples[mSampleIndex]); mSampleIndex++; if (mSampleIndex == mSamples.Length()) { if (ref->mParameters.mStopAtFrame) { mSampleIndex = 0; } else { mDecoder->Drain(); } } })); }
void BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo) { MOZ_ASSERT(OnThread()); RefPtr<PDMFactory> platform = new PDMFactory(); mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue, reinterpret_cast<MediaDataDecoderCallback*>(this) }); if (!mDecoder) { MainThreadShutdown(); return; } RefPtr<Benchmark> ref(mMainThreadState); mDecoder->Init()->Then( Thread(), __func__, [this, ref](TrackInfo::TrackType aTrackType) { InputExhausted(); }, [this, ref](MediaDataDecoder::DecoderFailureReason aReason) { MainThreadShutdown(); }); }
void BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo) { MOZ_ASSERT(OnThread()); RefPtr<PDMFactory> platform = new PDMFactory(); mDecoder = platform->CreateDecoder(aInfo, mDecoderTaskQueue, this); if (!mDecoder) { MainThreadShutdown(); return; } RefPtr<Benchmark> ref(mMainThreadState); mDecoder->Init()->Then( ref->Thread(), __func__, [this, ref](TrackInfo::TrackType aTrackType) { Dispatch(NS_NewRunnableFunction([this, ref]() { InputExhausted(); })); }, [this, ref](MediaDataDecoder::DecoderFailureReason aReason) { MainThreadShutdown(); }); }
void BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo) { MOZ_ASSERT(OnThread()); RefPtr<PDMFactory> platform = new PDMFactory(); mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue }); if (!mDecoder) { MainThreadShutdown(); return; } RefPtr<Benchmark> ref(mMainThreadState); mDecoder->Init()->Then( Thread(), __func__, [this, ref](TrackInfo::TrackType aTrackType) { InputExhausted(); }, [this, ref](const MediaResult& aError) { MainThreadShutdown(); }); }
void BenchmarkPlayback::GlobalShutdown() { MOZ_ASSERT(OnThread()); MOZ_ASSERT(!mFinished, "We've already shutdown"); mFinished = true; if (mDecoder) { RefPtr<Benchmark> ref(mGlobalState); mDecoder->Flush()->Then(Thread(), __func__, [ref, this]() { mDecoder->Shutdown()->Then( Thread(), __func__, [ref, this]() { FinalizeShutdown(); }, []() { MOZ_CRASH("not reached"); }); mDecoder = nullptr; }, []() { MOZ_CRASH("not reached"); }); } else { FinalizeShutdown(); } }
void BenchmarkPlayback::Output(MediaDataDecoder::DecodedData&& aResults) { MOZ_ASSERT(OnThread()); MOZ_ASSERT(!mFinished); RefPtr<Benchmark> ref(mGlobalState); mFrameCount += aResults.Length(); if (!mDecodeStartTime && mFrameCount >= ref->mParameters.mStartupFrame) { mDecodeStartTime = Some(TimeStamp::Now()); } TimeStamp now = TimeStamp::Now(); uint32_t frames = mFrameCount - ref->mParameters.mStartupFrame; TimeDuration elapsedTime = now - mDecodeStartTime.refOr(now); if (((frames == ref->mParameters.mFramesToMeasure) && mFrameCount > ref->mParameters.mStartupFrame && frames > 0) || elapsedTime >= ref->mParameters.mTimeout || mDrained) { uint32_t decodeFps = frames / elapsedTime.ToSeconds(); GlobalShutdown(); ref->Dispatch(NS_NewRunnableFunction( "BenchmarkPlayback::Output", [ref, decodeFps]() { ref->ReturnResult(decodeFps); })); } }
bool BenchmarkPlayback::OnReaderTaskQueue() { return OnThread(); }
void Benchmark::ReturnError(const MediaResult& aError) { MOZ_ASSERT(OnThread()); mPromise.RejectIfExists(aError, __func__); }
void Benchmark::Dispose() { MOZ_ASSERT(OnThread()); mKeepAliveUntilComplete = nullptr; }
void ParseThread(DWORD TID) { WAITCHAIN_NODE_INFO chain[WCT_MAX_NODE_COUNT]; DWORD dwNodesInChain; BOOL bDeadlock; dwNodesInChain = WCT_MAX_NODE_COUNT; DWORD dwNodeCount; /* Open thread wait chain session */ HWCT hWCTSession = OpenThreadWaitChainSession(0, NULL); /* Get the chain for the current thread * Retrieves the wait chain for the specified thread. * * WctHandle [in] * A handle to the WCT session created by * the OpenThreadWaitChainSession function. * * Context [in, optional] * A pointer to an application-defined context structure * to be passed to the callback function for an asynchronous session. * * Flags [in] * The wait chain retrieval options. * This parameter can be one of more of the following values. * Value Meaning * WCT_OUT_OF_PROC_COM_FLAG Enumerates all threads of an out-of-proc MTA * COM server to find the correct thread identifier. * * WCT_OUT_OF_PROC_CS_FLAG Retrieves critical-section information from other processes. * * WCT_OUT_OF_PROC_FLAG Follows the wait chain into other processes. * Otherwise, the function reports the first thread * in a different process but does not retrieve additional information. * ThreadId [in] * The identifier of the thread. * * NodeCount [in, out] * On input, a number from 1 to WCT_MAX_NODE_COUNT that specifies * the number of nodes in the wait chain. * On return, the number of nodes retrieved. * If the array cannot contain all the nodes of the wait chain, * the function fails, GetLastError returns ERROR_MORE_DATA, * and this parameter receives the number of array elements * required to contain all the nodes. * For asynchronous sessions, check the value that is passed to the callback function. * Do not free the variable until the callback function has returned. * * NodeInfoArray [out] * An array of WAITCHAIN_NODE_INFO structures that receives the wait chain. * For asynchronous sessions, check the value that is passed * to the callback function. Do not free the array until the callback function has returned. * * IsCycle [out] * If the function detects a deadlock, this variable is set to TRUE; * otherwise, it is set to FALSE. * For asynchronous sessions, check the value * that is passed to the callback function. * Do not free the variable until the callback function has returned. */ if (!GetThreadWaitChain( hWCTSession, NULL, WCTP_GETINFO_ALL_FLAGS, TID, &dwNodesInChain, chain, &bDeadlock)) { dwNodeCount = 0; /* Call onThread callback */ OnThread(TID, FALSE, 0); return; } // Start the chain processing for the current thread dwNodeCount = min(dwNodesInChain, WCT_MAX_NODE_COUNT); OnThread(TID, bDeadlock, dwNodesInChain); // For each node in the chain, call the virtual method with details for ( DWORD current = 0; current < min(dwNodesInChain, WCT_MAX_NODE_COUNT); current++ ) { OnChainNodeInfo(TID, current, chain[current]); } }