Bug 1934014 - Remove decoder benchmark machinery. r=media-playback-reviewers,aosmond
Differential Revision: https://phabricator.services.mozilla.com/D230546
This commit is contained in:
@@ -17,7 +17,6 @@
|
||||
#include "mozilla/AppShutdown.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BackgroundHangMonitor.h"
|
||||
#include "mozilla/BenchmarkStorageChild.h"
|
||||
#include "mozilla/FOGIPC.h"
|
||||
#include "GMPServiceChild.h"
|
||||
#include "Geolocation.h"
|
||||
@@ -2008,16 +2007,6 @@ bool ContentChild::DeallocPMediaChild(media::PMediaChild* aActor) {
|
||||
return media::DeallocPMediaChild(aActor);
|
||||
}
|
||||
|
||||
PBenchmarkStorageChild* ContentChild::AllocPBenchmarkStorageChild() {
|
||||
return BenchmarkStorageChild::Instance();
|
||||
}
|
||||
|
||||
bool ContentChild::DeallocPBenchmarkStorageChild(
|
||||
PBenchmarkStorageChild* aActor) {
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
PWebrtcGlobalChild* ContentChild::AllocPWebrtcGlobalChild() {
|
||||
auto* child = new WebrtcGlobalChild();
|
||||
|
||||
@@ -50,7 +50,6 @@ class nsIOpenWindowInfo;
|
||||
namespace mozilla {
|
||||
class RemoteSpellcheckEngineChild;
|
||||
class ChildProfilerController;
|
||||
class BenchmarkStorageChild;
|
||||
|
||||
namespace ipc {
|
||||
class UntypedEndpoint;
|
||||
@@ -232,10 +231,6 @@ class ContentChild final : public PContentChild,
|
||||
|
||||
bool DeallocPMediaChild(PMediaChild* aActor);
|
||||
|
||||
PBenchmarkStorageChild* AllocPBenchmarkStorageChild();
|
||||
|
||||
bool DeallocPBenchmarkStorageChild(PBenchmarkStorageChild* aActor);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyEmptyHTTPCache();
|
||||
|
||||
mozilla::ipc::IPCResult RecvRegisterChrome(
|
||||
|
||||
@@ -48,7 +48,6 @@
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/ClipboardContentAnalysisParent.h"
|
||||
#include "mozilla/BasePrincipal.h"
|
||||
#include "mozilla/BenchmarkStorageParent.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/ClipboardReadRequestParent.h"
|
||||
@@ -328,9 +327,6 @@
|
||||
# include "nsIRemoteAgent.h"
|
||||
#endif
|
||||
|
||||
// For VP9Benchmark::sBenchmarkFpsPref
|
||||
#include "Benchmark.h"
|
||||
|
||||
#include "mozilla/RemoteDecodeUtils.h"
|
||||
#include "nsIToolkitProfileService.h"
|
||||
#include "nsIToolkitProfile.h"
|
||||
@@ -4445,16 +4441,6 @@ bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
|
||||
return media::DeallocPMediaParent(aActor);
|
||||
}
|
||||
|
||||
PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
|
||||
return new BenchmarkStorageParent;
|
||||
}
|
||||
|
||||
bool ContentParent::DeallocPBenchmarkStorageParent(
|
||||
PBenchmarkStorageParent* aActor) {
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
already_AddRefed<PSpeechSynthesisParent>
|
||||
ContentParent::AllocPSpeechSynthesisParent() {
|
||||
@@ -5621,18 +5607,6 @@ mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvNotifyBenchmarkResult(
|
||||
const nsAString& aCodecName, const uint32_t& aDecodeFPS)
|
||||
|
||||
{
|
||||
if (aCodecName.EqualsLiteral("VP9")) {
|
||||
Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
|
||||
Preferences::SetUint(VP9Benchmark::sBenchmarkFpsVersionCheck,
|
||||
VP9Benchmark::sBenchmarkVersionID);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
|
||||
const nsACString& aScope, nsIPrincipal* aPrincipal,
|
||||
const nsAString& aMessageId) {
|
||||
|
||||
@@ -80,7 +80,6 @@ class SandboxBrokerPolicyFactory;
|
||||
#endif
|
||||
|
||||
class PreallocatedProcessManagerImpl;
|
||||
class BenchmarkStorageParent;
|
||||
|
||||
using mozilla::loader::PScriptCacheParent;
|
||||
|
||||
@@ -951,10 +950,6 @@ class ContentParent final : public PContentParent,
|
||||
|
||||
bool DeallocPMediaParent(PMediaParent* aActor);
|
||||
|
||||
PBenchmarkStorageParent* AllocPBenchmarkStorageParent();
|
||||
|
||||
bool DeallocPBenchmarkStorageParent(PBenchmarkStorageParent* aActor);
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
already_AddRefed<PSpeechSynthesisParent> AllocPSpeechSynthesisParent();
|
||||
|
||||
@@ -1152,9 +1147,6 @@ class ContentParent final : public PContentParent,
|
||||
mozilla::ipc::IPCResult RecvGetHyphDict(
|
||||
nsIURI* aURIParams, mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
|
||||
const uint32_t& aDecodeFPS);
|
||||
|
||||
mozilla::ipc::IPCResult RecvNotifyPushObservers(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsAString& aMessageId);
|
||||
|
||||
@@ -47,7 +47,6 @@ include protocol PRemoteWorkerService;
|
||||
include protocol PProfiler;
|
||||
include protocol PScriptCache;
|
||||
include protocol PSessionStorageObserver;
|
||||
include protocol PBenchmarkStorage;
|
||||
include CrashReporterInitArgs;
|
||||
include DOMTypes;
|
||||
include WindowGlobalTypes;
|
||||
@@ -508,7 +507,6 @@ sync protocol PContent
|
||||
manages PURLClassifierLocalByName;
|
||||
manages PScriptCache;
|
||||
manages PSessionStorageObserver;
|
||||
manages PBenchmarkStorage;
|
||||
|
||||
// Depending on exactly how the new browser is being created, it might be
|
||||
// created from either the child or parent process!
|
||||
@@ -1135,8 +1133,6 @@ parent:
|
||||
|
||||
async PSessionStorageObserver();
|
||||
|
||||
async PBenchmarkStorage();
|
||||
|
||||
// Services remoting
|
||||
|
||||
async StartVisitedQueries(nullable nsIURI[] uri);
|
||||
@@ -1550,12 +1546,6 @@ parent:
|
||||
bool aUserActivation,
|
||||
bool aTextDirectiveUserActivation);
|
||||
|
||||
/**
|
||||
* Tell the parent that a decoder's' benchmark has been completed.
|
||||
* The result can then be stored in permanent storage.
|
||||
*/
|
||||
async NotifyBenchmarkResult(nsString aCodecName, uint32_t aDecodeFPS);
|
||||
|
||||
/**
|
||||
* Notify `push-message` observers without data in the parent.
|
||||
*/
|
||||
|
||||
@@ -1,394 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "Benchmark.h"
|
||||
|
||||
#include "BufferMediaResource.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "PDMFactory.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SharedThreadPool.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
|
||||
#ifndef MOZ_WIDGET_ANDROID
|
||||
# include "WebMSample.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Update this version number to force re-running the benchmark. Such as when
|
||||
// an improvement to FFVP9 or LIBVPX is deemed worthwhile.
|
||||
const uint32_t VP9Benchmark::sBenchmarkVersionID = 5;
|
||||
|
||||
const char* VP9Benchmark::sBenchmarkFpsPref = "media.benchmark.vp9.fps";
|
||||
const char* VP9Benchmark::sBenchmarkFpsVersionCheck =
|
||||
"media.benchmark.vp9.versioncheck";
|
||||
bool VP9Benchmark::sHasRunTest = false;
|
||||
|
||||
// static
|
||||
bool VP9Benchmark::ShouldRun() {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// Assume that the VP9 software decoder will always be too slow.
|
||||
return false;
|
||||
#else
|
||||
# if defined(MOZ_APPLEMEDIA)
|
||||
const nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
|
||||
nsString vendorID, deviceID;
|
||||
gfxInfo->GetAdapterVendorID(vendorID);
|
||||
// We won't run the VP9 benchmark on mac using an Intel GPU as performance are
|
||||
// poor, see bug 1404042.
|
||||
if (vendorID.EqualsLiteral("0x8086")) {
|
||||
return false;
|
||||
}
|
||||
// Fall Through
|
||||
# endif
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
uint32_t VP9Benchmark::MediaBenchmarkVp9Fps() {
|
||||
if (!ShouldRun()) {
|
||||
return 0;
|
||||
}
|
||||
return StaticPrefs::media_benchmark_vp9_fps();
|
||||
}
|
||||
|
||||
// static
|
||||
bool VP9Benchmark::IsVP9DecodeFast(bool aDefault) {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
return false;
|
||||
#else
|
||||
if (!ShouldRun()) {
|
||||
return false;
|
||||
}
|
||||
static StaticMutex sMutex MOZ_UNANNOTATED;
|
||||
uint32_t decodeFps = StaticPrefs::media_benchmark_vp9_fps();
|
||||
uint32_t hadRecentUpdate = StaticPrefs::media_benchmark_vp9_versioncheck();
|
||||
bool needBenchmark;
|
||||
{
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
needBenchmark = !sHasRunTest &&
|
||||
(decodeFps == 0 || hadRecentUpdate != sBenchmarkVersionID);
|
||||
sHasRunTest = true;
|
||||
}
|
||||
|
||||
if (needBenchmark) {
|
||||
RefPtr<WebMDemuxer> demuxer = new WebMDemuxer(
|
||||
new BufferMediaResource(sWebMSample, sizeof(sWebMSample)));
|
||||
RefPtr<Benchmark> estimiser = new Benchmark(
|
||||
demuxer,
|
||||
{StaticPrefs::media_benchmark_frames(), // frames to measure
|
||||
1, // start benchmarking after decoding this frame.
|
||||
8, // loop after decoding that many frames.
|
||||
TimeDuration::FromMilliseconds(
|
||||
StaticPrefs::media_benchmark_timeout())});
|
||||
estimiser->Run()->Then(
|
||||
AbstractThread::MainThread(), __func__,
|
||||
[](uint32_t aDecodeFps) {
|
||||
if (XRE_IsContentProcess()) {
|
||||
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
|
||||
if (contentChild) {
|
||||
contentChild->SendNotifyBenchmarkResult(u"VP9"_ns, aDecodeFps);
|
||||
}
|
||||
} else {
|
||||
Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps);
|
||||
Preferences::SetUint(sBenchmarkFpsVersionCheck,
|
||||
sBenchmarkVersionID);
|
||||
}
|
||||
},
|
||||
[]() {});
|
||||
}
|
||||
|
||||
if (decodeFps == 0) {
|
||||
return aDefault;
|
||||
}
|
||||
|
||||
return decodeFps >= StaticPrefs::media_benchmark_vp9_threshold();
|
||||
#endif
|
||||
}
|
||||
|
||||
Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
|
||||
: QueueObject(
|
||||
TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
|
||||
"Benchmark::QueueObject")),
|
||||
mParameters(aParameters),
|
||||
mPlaybackState(this, aDemuxer) {
|
||||
MOZ_COUNT_CTOR(Benchmark);
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark() { MOZ_COUNT_DTOR(Benchmark); }
|
||||
|
||||
RefPtr<Benchmark::BenchmarkPromise> Benchmark::Run() {
|
||||
RefPtr<Benchmark> self = this;
|
||||
mKeepAliveUntilComplete = this;
|
||||
return InvokeAsync(Thread(), __func__, [self] {
|
||||
RefPtr<BenchmarkPromise> p = self->mPromise.Ensure(__func__);
|
||||
self->mPlaybackState.Dispatch(NS_NewRunnableFunction(
|
||||
"Benchmark::Run", [self]() { self->mPlaybackState.DemuxSamples(); }));
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
void Benchmark::ReturnResult(uint32_t aDecodeFps) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mPromise.ResolveIfExists(aDecodeFps, __func__);
|
||||
}
|
||||
|
||||
void Benchmark::ReturnError(const MediaResult& aError) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mPromise.RejectIfExists(aError, __func__);
|
||||
}
|
||||
|
||||
void Benchmark::Dispose() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mKeepAliveUntilComplete = nullptr;
|
||||
}
|
||||
|
||||
void Benchmark::Init() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
gfxVars::Initialize();
|
||||
}
|
||||
|
||||
BenchmarkPlayback::BenchmarkPlayback(Benchmark* aGlobalState,
|
||||
MediaDataDemuxer* aDemuxer)
|
||||
: QueueObject(
|
||||
TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
|
||||
"BenchmarkPlayback::QueueObject")),
|
||||
mGlobalState(aGlobalState),
|
||||
mDecoderTaskQueue(TaskQueue::Create(
|
||||
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
|
||||
"BenchmarkPlayback::mDecoderTaskQueue")),
|
||||
mDemuxer(aDemuxer),
|
||||
mSampleIndex(0),
|
||||
mFrameCount(0),
|
||||
mFinished(false),
|
||||
mDrained(false) {}
|
||||
|
||||
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::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(aHolder->GetMovableSamples());
|
||||
if (ref->mParameters.mStopAtFrame &&
|
||||
mSamples.Length() == ref->mParameters.mStopAtFrame.ref()) {
|
||||
InitDecoder(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(mTrackDemuxer->GetInfo());
|
||||
break;
|
||||
default:
|
||||
Error(aError);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::InitDecoder(UniquePtr<TrackInfo>&& aInfo) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
if (!aInfo) {
|
||||
Error(MediaResult(NS_ERROR_FAILURE, "Invalid TrackInfo"));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PDMFactory> platform = new PDMFactory();
|
||||
mInfo = std::move(aInfo);
|
||||
RefPtr<Benchmark> ref(mGlobalState);
|
||||
platform->CreateDecoder(CreateDecoderParams{*mInfo})
|
||||
->Then(
|
||||
Thread(), __func__,
|
||||
[this, ref](RefPtr<MediaDataDecoder>&& aDecoder) {
|
||||
mDecoder = new MediaDataDecoderProxy(
|
||||
aDecoder.forget(), do_AddRef(mDecoderTaskQueue.get()));
|
||||
mDecoder->Init()->Then(
|
||||
Thread(), __func__,
|
||||
[this, ref](TrackInfo::TrackType aTrackType) {
|
||||
InputExhausted();
|
||||
},
|
||||
[this, ref](const MediaResult& aError) { Error(aError); });
|
||||
},
|
||||
[this, ref](const MediaResult& aError) { Error(aError); });
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::FinalizeShutdown() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
MOZ_ASSERT(mFinished, "GlobalShutdown must have been run");
|
||||
MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already");
|
||||
MOZ_ASSERT(!mDemuxer, "mDemuxer must have been shutdown already");
|
||||
MOZ_DIAGNOSTIC_ASSERT(mDecoderTaskQueue->IsEmpty());
|
||||
mDecoderTaskQueue = nullptr;
|
||||
|
||||
RefPtr<Benchmark> ref(mGlobalState);
|
||||
ref->Thread()->Dispatch(NS_NewRunnableFunction(
|
||||
"BenchmarkPlayback::FinalizeShutdown", [ref]() { ref->Dispose(); }));
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::GlobalShutdown() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
MOZ_ASSERT(!mFinished, "We've already shutdown");
|
||||
|
||||
mFinished = true;
|
||||
|
||||
if (mTrackDemuxer) {
|
||||
mTrackDemuxer->Reset();
|
||||
mTrackDemuxer->BreakCycles();
|
||||
mTrackDemuxer = nullptr;
|
||||
}
|
||||
mDemuxer = nullptr;
|
||||
|
||||
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;
|
||||
mInfo = 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); }));
|
||||
}
|
||||
}
|
||||
|
||||
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::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); });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,119 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_BENCHMARK_H
|
||||
#define MOZILLA_BENCHMARK_H
|
||||
|
||||
#include "MediaDataDemuxer.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "QueueObject.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class TaskQueue;
|
||||
class Benchmark;
|
||||
|
||||
class BenchmarkPlayback : public QueueObject {
|
||||
friend class Benchmark;
|
||||
BenchmarkPlayback(Benchmark* aGlobalState, MediaDataDemuxer* aDemuxer);
|
||||
void DemuxSamples();
|
||||
void DemuxNextSample();
|
||||
void GlobalShutdown();
|
||||
void InitDecoder(UniquePtr<TrackInfo>&& aInfo);
|
||||
|
||||
void Output(MediaDataDecoder::DecodedData&& aResults);
|
||||
void Error(const MediaResult& aError);
|
||||
void InputExhausted();
|
||||
|
||||
// Shutdown trackdemuxer and demuxer if any and shutdown the task queues.
|
||||
void FinalizeShutdown();
|
||||
|
||||
Atomic<Benchmark*> mGlobalState;
|
||||
|
||||
RefPtr<TaskQueue> mDecoderTaskQueue;
|
||||
RefPtr<MediaDataDecoder> mDecoder;
|
||||
|
||||
// Object only accessed on Thread()
|
||||
RefPtr<MediaDataDemuxer> mDemuxer;
|
||||
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
|
||||
nsTArray<RefPtr<MediaRawData>> mSamples;
|
||||
UniquePtr<TrackInfo> mInfo;
|
||||
size_t mSampleIndex;
|
||||
Maybe<TimeStamp> mDecodeStartTime;
|
||||
uint32_t mFrameCount;
|
||||
bool mFinished;
|
||||
bool mDrained;
|
||||
};
|
||||
|
||||
// Init() must have been called at least once prior on the
|
||||
// main thread.
|
||||
class Benchmark : public QueueObject {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Benchmark)
|
||||
|
||||
struct Parameters {
|
||||
Parameters()
|
||||
: mFramesToMeasure(UINT32_MAX),
|
||||
mStartupFrame(1),
|
||||
mTimeout(TimeDuration::Forever()) {}
|
||||
|
||||
Parameters(uint32_t aFramesToMeasure, uint32_t aStartupFrame,
|
||||
uint32_t aStopAtFrame, const TimeDuration& aTimeout)
|
||||
: mFramesToMeasure(aFramesToMeasure),
|
||||
mStartupFrame(aStartupFrame),
|
||||
mStopAtFrame(Some(aStopAtFrame)),
|
||||
mTimeout(aTimeout) {}
|
||||
|
||||
const uint32_t mFramesToMeasure;
|
||||
const uint32_t mStartupFrame;
|
||||
const Maybe<uint32_t> mStopAtFrame;
|
||||
const TimeDuration mTimeout;
|
||||
};
|
||||
|
||||
typedef MozPromise<uint32_t, MediaResult, /* IsExclusive = */ true>
|
||||
BenchmarkPromise;
|
||||
|
||||
explicit Benchmark(MediaDataDemuxer* aDemuxer,
|
||||
const Parameters& aParameters = Parameters());
|
||||
RefPtr<BenchmarkPromise> Run();
|
||||
|
||||
// Must be called on the main thread.
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
friend class BenchmarkPlayback;
|
||||
virtual ~Benchmark();
|
||||
void ReturnResult(uint32_t aDecodeFps);
|
||||
void ReturnError(const MediaResult& aError);
|
||||
void Dispose();
|
||||
const Parameters mParameters;
|
||||
RefPtr<Benchmark> mKeepAliveUntilComplete;
|
||||
BenchmarkPlayback mPlaybackState;
|
||||
MozPromiseHolder<BenchmarkPromise> mPromise;
|
||||
};
|
||||
|
||||
class VP9Benchmark {
|
||||
public:
|
||||
static bool IsVP9DecodeFast(bool aDefault = false);
|
||||
static const char* sBenchmarkFpsPref;
|
||||
static const char* sBenchmarkFpsVersionCheck;
|
||||
static const uint32_t sBenchmarkVersionID;
|
||||
static bool sHasRunTest;
|
||||
// Return the value of media.benchmark.vp9.fps preference (which will be 0 if
|
||||
// not known)
|
||||
static uint32_t MediaBenchmarkVp9Fps();
|
||||
|
||||
private:
|
||||
static bool ShouldRun();
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "AudioDeviceInfo.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "DecoderBenchmark.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaDecoderStateMachineBase.h"
|
||||
#include "MediaFormatReader.h"
|
||||
@@ -239,7 +238,6 @@ MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
|
||||
mOwner(aInit.mOwner),
|
||||
mAbstractMainThread(aInit.mOwner->AbstractMainThread()),
|
||||
mFrameStats(new FrameStatistics()),
|
||||
mDecoderBenchmark(new DecoderBenchmark()),
|
||||
mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer()),
|
||||
mMinimizePreroll(aInit.mMinimizePreroll),
|
||||
mFiredMetadataLoaded(false),
|
||||
@@ -546,29 +544,6 @@ void MediaDecoder::OnSecondaryVideoContainerInstalled(
|
||||
GetOwner()->OnSecondaryVideoContainerInstalled(aSecondaryVideoContainer);
|
||||
}
|
||||
|
||||
void MediaDecoder::OnStoreDecoderBenchmark(const VideoInfo& aInfo) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
int32_t videoFrameRate = aInfo.GetFrameRate().ref();
|
||||
|
||||
if (mFrameStats && videoFrameRate) {
|
||||
DecoderBenchmarkInfo benchmarkInfo{
|
||||
aInfo.mMimeType,
|
||||
aInfo.mDisplay.width,
|
||||
aInfo.mDisplay.height,
|
||||
videoFrameRate,
|
||||
BitDepthForColorDepth(aInfo.mColorDepth),
|
||||
};
|
||||
|
||||
LOG("Store benchmark: Video width=%d, height=%d, frameRate=%d, content "
|
||||
"type = %s\n",
|
||||
benchmarkInfo.mWidth, benchmarkInfo.mHeight, benchmarkInfo.mFrameRate,
|
||||
benchmarkInfo.mContentType.BeginReading());
|
||||
|
||||
mDecoderBenchmark->Store(benchmarkInfo, mFrameStats);
|
||||
}
|
||||
}
|
||||
|
||||
void MediaDecoder::ShutdownInternal() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mVideoFrameContainer = nullptr;
|
||||
@@ -630,9 +605,6 @@ void MediaDecoder::SetStateMachineParameters() {
|
||||
mDecoderStateMachine->OnSecondaryVideoContainerInstalled().Connect(
|
||||
mAbstractMainThread, this,
|
||||
&MediaDecoder::OnSecondaryVideoContainerInstalled);
|
||||
mOnStoreDecoderBenchmark = mReader->OnStoreDecoderBenchmark().Connect(
|
||||
mAbstractMainThread, this, &MediaDecoder::OnStoreDecoderBenchmark);
|
||||
|
||||
mOnEncrypted = mReader->OnEncrypted().Connect(
|
||||
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::DispatchEncrypted);
|
||||
mOnWaitingForKey = mReader->OnWaitingForKey().Connect(
|
||||
@@ -656,7 +628,6 @@ void MediaDecoder::DisconnectEvents() {
|
||||
mOnNextFrameStatus.Disconnect();
|
||||
mOnTrackInfoUpdated.Disconnect();
|
||||
mOnSecondaryVideoContainerInstalled.Disconnect();
|
||||
mOnStoreDecoderBenchmark.Disconnect();
|
||||
}
|
||||
|
||||
RefPtr<ShutdownPromise> MediaDecoder::ShutdownStateMachine() {
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace mozilla {
|
||||
|
||||
class AbstractThread;
|
||||
class DOMMediaStream;
|
||||
class DecoderBenchmark;
|
||||
class ProcessedMediaTrack;
|
||||
class FrameStatistics;
|
||||
class VideoFrameContainer;
|
||||
@@ -562,8 +561,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||
void OnSecondaryVideoContainerInstalled(
|
||||
const RefPtr<VideoFrameContainer>& aSecondaryVideoContainer);
|
||||
|
||||
void OnStoreDecoderBenchmark(const VideoInfo& aInfo);
|
||||
|
||||
void FinishShutdown();
|
||||
|
||||
void ConnectMirrors(MediaDecoderStateMachineBase* aObject);
|
||||
@@ -607,9 +604,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||
// Counters related to decode and presentation of frames.
|
||||
const RefPtr<FrameStatistics> mFrameStats;
|
||||
|
||||
// Store a benchmark of the decoder based on FrameStatistics.
|
||||
RefPtr<DecoderBenchmark> mDecoderBenchmark;
|
||||
|
||||
RefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||
|
||||
// True if the decoder has been directed to minimize its preroll before
|
||||
@@ -674,7 +668,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||
MediaEventListener mOnNextFrameStatus;
|
||||
MediaEventListener mOnTrackInfoUpdated;
|
||||
MediaEventListener mOnSecondaryVideoContainerInstalled;
|
||||
MediaEventListener mOnStoreDecoderBenchmark;
|
||||
|
||||
// True if we have suspended video decoding.
|
||||
bool mIsVideoDecodingSuspended = false;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#ifdef MOZ_AV1
|
||||
# include "AOMDecoder.h"
|
||||
#endif
|
||||
#include "DecoderBenchmark.h"
|
||||
#include "MediaData.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "MediaInfo.h"
|
||||
@@ -483,10 +482,6 @@ void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {
|
||||
ownerData.mDecoder.get());
|
||||
mOwner->SetVideoDecodeThreshold();
|
||||
mOwner->ScheduleUpdate(aTrack);
|
||||
if (aTrack == TrackInfo::kVideoTrack) {
|
||||
DecoderBenchmark::CheckVersion(
|
||||
ownerData.GetCurrentInfo()->mMimeType);
|
||||
}
|
||||
if (aTrack == TrackInfo::kAudioTrack) {
|
||||
ownerData.mProcessName = ownerData.mDecoder->GetProcessName();
|
||||
ownerData.mCodecName = ownerData.mDecoder->GetCodecName();
|
||||
@@ -1021,19 +1016,6 @@ void MediaFormatReader::ShutdownDecoder(TrackType aTrack) {
|
||||
decoder.ShutdownDecoder();
|
||||
}
|
||||
|
||||
void MediaFormatReader::NotifyDecoderBenchmarkStore() {
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
if (!StaticPrefs::media_mediacapabilities_from_database()) {
|
||||
return;
|
||||
}
|
||||
auto& decoder = GetDecoderData(TrackInfo::kVideoTrack);
|
||||
if (decoder.GetCurrentInfo() && decoder.GetCurrentInfo()->GetAsVideoInfo()) {
|
||||
VideoInfo info = *(decoder.GetCurrentInfo()->GetAsVideoInfo());
|
||||
info.SetFrameRate(static_cast<int32_t>(ceil(decoder.mMeanRate.Mean())));
|
||||
mOnStoreDecoderBenchmark.Notify(std::move(info));
|
||||
}
|
||||
}
|
||||
|
||||
void MediaFormatReader::NotifyTrackInfoUpdated() {
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
if (mWorkingInfoChanged) {
|
||||
@@ -2200,11 +2182,6 @@ void MediaFormatReader::HandleDemuxedSamples(
|
||||
PROFILER_MARKER_TEXT("StreamID Change", MEDIA_PLAYBACK, {}, markerString);
|
||||
LOG("%s", markerString.get());
|
||||
|
||||
if (aTrack == TrackInfo::kVideoTrack) {
|
||||
// We are about to create a new decoder thus the benchmark,
|
||||
// up to this point, is stored.
|
||||
NotifyDecoderBenchmarkStore();
|
||||
}
|
||||
decoder.mNextStreamSourceID.reset();
|
||||
decoder.mLastStreamSourceID = info->GetID();
|
||||
decoder.mInfo = info;
|
||||
@@ -2500,10 +2477,6 @@ void MediaFormatReader::Update(TrackType aTrack) {
|
||||
} else if (decoder.HasCompletedDrain()) {
|
||||
if (decoder.mDemuxEOS) {
|
||||
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
|
||||
if (aTrack == TrackInfo::kVideoTrack) {
|
||||
// End of video, store the benchmark of the decoder.
|
||||
NotifyDecoderBenchmarkStore();
|
||||
}
|
||||
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||
} else if (decoder.mWaitingForDataStartTime) {
|
||||
if (decoder.mDrainState == DrainState::DrainCompleted &&
|
||||
|
||||
@@ -250,10 +250,6 @@ class MediaFormatReader final
|
||||
|
||||
MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
|
||||
|
||||
MediaEventSource<VideoInfo>& OnStoreDecoderBenchmark() {
|
||||
return mOnStoreDecoderBenchmark;
|
||||
}
|
||||
|
||||
MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() {
|
||||
return mTrackInfoUpdatedEvent;
|
||||
}
|
||||
@@ -346,11 +342,6 @@ class MediaFormatReader final
|
||||
|
||||
size_t SizeOfQueue(TrackType aTrack);
|
||||
|
||||
// Fire a new OnStoreDecoderBenchmark event that will create new
|
||||
// storage of the decoder benchmark.
|
||||
// This is called only on TaskQueue.
|
||||
void NotifyDecoderBenchmarkStore();
|
||||
|
||||
void NotifyTrackInfoUpdated();
|
||||
|
||||
enum class DrainState {
|
||||
@@ -879,8 +870,6 @@ class MediaFormatReader final
|
||||
|
||||
MediaEventProducer<MediaResult> mOnDecodeWarning;
|
||||
|
||||
MediaEventProducer<VideoInfo> mOnStoreDecoderBenchmark;
|
||||
|
||||
MediaEventProducer<VideoInfo, AudioInfo> mTrackInfoUpdatedEvent;
|
||||
|
||||
RefPtr<FrameStatistics> mFrameStats;
|
||||
|
||||
22788
dom/media/WebMSample.h
22788
dom/media/WebMSample.h
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
wget http://people.mozilla.org/~ajones/frame-drop-test/bbb-31.webm -O bbb-31.webm
|
||||
ffmpeg -i bbb-31.webm -frames:v 8 -codec copy -map 0:0 sWebMSample.webm -y
|
||||
mv sWebMSample.webm sWebMSample
|
||||
xxd -i sWebMSample |head --lines=-1 | sed 's/unsigned char/static const uint8_t/' > ../WebMSample.h
|
||||
rm sWebMSample
|
||||
rm bbb-31.webm
|
||||
@@ -4,7 +4,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ADTSDemuxer.h"
|
||||
#include "Benchmark.h"
|
||||
#include "BufferMediaResource.h"
|
||||
#include "FlacDemuxer.h"
|
||||
#include "FuzzingInterface.h"
|
||||
@@ -16,9 +15,96 @@
|
||||
#include "systemservices/MediaUtils.h"
|
||||
#include "WaveDemuxer.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#include "QueueObject.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "mozilla/TaskQueue.h"
|
||||
#include "PDMFactory.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
class Benchmark;
|
||||
|
||||
class BenchmarkPlayback : public QueueObject {
|
||||
friend class Benchmark;
|
||||
BenchmarkPlayback(Benchmark* aGlobalState, MediaDataDemuxer* aDemuxer);
|
||||
void DemuxSamples();
|
||||
void DemuxNextSample();
|
||||
void GlobalShutdown();
|
||||
void InitDecoder(UniquePtr<TrackInfo>&& aInfo);
|
||||
|
||||
void Output(MediaDataDecoder::DecodedData&& aResults);
|
||||
void Error(const MediaResult& aError);
|
||||
void InputExhausted();
|
||||
|
||||
// Shutdown trackdemuxer and demuxer if any and shutdown the task queues.
|
||||
void FinalizeShutdown();
|
||||
|
||||
Atomic<Benchmark*> mGlobalState;
|
||||
|
||||
RefPtr<TaskQueue> mDecoderTaskQueue;
|
||||
RefPtr<MediaDataDecoder> mDecoder;
|
||||
|
||||
// Object only accessed on Thread()
|
||||
RefPtr<MediaDataDemuxer> mDemuxer;
|
||||
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
|
||||
nsTArray<RefPtr<MediaRawData>> mSamples;
|
||||
UniquePtr<TrackInfo> mInfo;
|
||||
size_t mSampleIndex;
|
||||
Maybe<TimeStamp> mDecodeStartTime;
|
||||
uint32_t mFrameCount;
|
||||
bool mFinished;
|
||||
bool mDrained;
|
||||
};
|
||||
|
||||
// Init() must have been called at least once prior on the
|
||||
// main thread.
|
||||
class Benchmark : public QueueObject {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Benchmark)
|
||||
|
||||
struct Parameters {
|
||||
Parameters()
|
||||
: mFramesToMeasure(UINT32_MAX),
|
||||
mStartupFrame(1),
|
||||
mTimeout(TimeDuration::Forever()) {}
|
||||
|
||||
Parameters(uint32_t aFramesToMeasure, uint32_t aStartupFrame,
|
||||
uint32_t aStopAtFrame, const TimeDuration& aTimeout)
|
||||
: mFramesToMeasure(aFramesToMeasure),
|
||||
mStartupFrame(aStartupFrame),
|
||||
mStopAtFrame(Some(aStopAtFrame)),
|
||||
mTimeout(aTimeout) {}
|
||||
|
||||
const uint32_t mFramesToMeasure;
|
||||
const uint32_t mStartupFrame;
|
||||
const Maybe<uint32_t> mStopAtFrame;
|
||||
const TimeDuration mTimeout;
|
||||
};
|
||||
|
||||
typedef MozPromise<uint32_t, MediaResult, /* IsExclusive = */ true>
|
||||
BenchmarkPromise;
|
||||
|
||||
explicit Benchmark(MediaDataDemuxer* aDemuxer,
|
||||
const Parameters& aParameters = Parameters());
|
||||
RefPtr<BenchmarkPromise> Run();
|
||||
|
||||
// Must be called on the main thread.
|
||||
static void Init();
|
||||
|
||||
private:
|
||||
friend class BenchmarkPlayback;
|
||||
virtual ~Benchmark();
|
||||
void ReturnResult(uint32_t aDecodeFps);
|
||||
void ReturnError(const MediaResult& aError);
|
||||
void Dispose();
|
||||
const Parameters mParameters;
|
||||
RefPtr<Benchmark> mKeepAliveUntilComplete;
|
||||
BenchmarkPlayback mPlaybackState;
|
||||
MozPromiseHolder<BenchmarkPromise> mPromise;
|
||||
};
|
||||
|
||||
class FuzzRunner {
|
||||
public:
|
||||
explicit FuzzRunner(Benchmark* aBenchmark) : mBenchmark(aBenchmark) {}
|
||||
@@ -28,7 +114,7 @@ class FuzzRunner {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
bool done = false;
|
||||
|
||||
mBenchmark->Init();
|
||||
Benchmark::Init();
|
||||
mBenchmark->Run()->Then(
|
||||
// Non DocGroup-version of AbstractThread::MainThread() is fine for
|
||||
// testing.
|
||||
@@ -37,13 +123,279 @@ class FuzzRunner {
|
||||
|
||||
// Wait until benchmark completes.
|
||||
SpinEventLoopUntil("FuzzRunner::Run"_ns, [&]() { return done; });
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Benchmark> mBenchmark;
|
||||
};
|
||||
|
||||
Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
|
||||
: QueueObject(
|
||||
TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
|
||||
"Benchmark::QueueObject")),
|
||||
mParameters(aParameters),
|
||||
mPlaybackState(this, aDemuxer) {
|
||||
MOZ_COUNT_CTOR(Benchmark);
|
||||
}
|
||||
|
||||
Benchmark::~Benchmark() { MOZ_COUNT_DTOR(Benchmark); }
|
||||
|
||||
RefPtr<Benchmark::BenchmarkPromise> Benchmark::Run() {
|
||||
RefPtr<Benchmark> self = this;
|
||||
mKeepAliveUntilComplete = this;
|
||||
return InvokeAsync(Thread(), __func__, [self] {
|
||||
RefPtr<BenchmarkPromise> p = self->mPromise.Ensure(__func__);
|
||||
self->mPlaybackState.Dispatch(NS_NewRunnableFunction(
|
||||
"Benchmark::Run", [self]() { self->mPlaybackState.DemuxSamples(); }));
|
||||
return p;
|
||||
});
|
||||
}
|
||||
|
||||
void Benchmark::ReturnResult(uint32_t aDecodeFps) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mPromise.ResolveIfExists(aDecodeFps, __func__);
|
||||
}
|
||||
|
||||
void Benchmark::ReturnError(const MediaResult& aError) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mPromise.RejectIfExists(aError, __func__);
|
||||
}
|
||||
|
||||
void Benchmark::Dispose() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
mKeepAliveUntilComplete = nullptr;
|
||||
}
|
||||
|
||||
void Benchmark::Init() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mozilla::gfx::gfxVars::Initialize();
|
||||
}
|
||||
|
||||
BenchmarkPlayback::BenchmarkPlayback(Benchmark* aGlobalState,
|
||||
MediaDataDemuxer* aDemuxer)
|
||||
: QueueObject(
|
||||
TaskQueue::Create(GetMediaThreadPool(MediaThreadType::SUPERVISOR),
|
||||
"BenchmarkPlayback::QueueObject")),
|
||||
mGlobalState(aGlobalState),
|
||||
mDecoderTaskQueue(TaskQueue::Create(
|
||||
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
|
||||
"BenchmarkPlayback::mDecoderTaskQueue")),
|
||||
mDemuxer(aDemuxer),
|
||||
mSampleIndex(0),
|
||||
mFrameCount(0),
|
||||
mFinished(false),
|
||||
mDrained(false) {}
|
||||
|
||||
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::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(aHolder->GetMovableSamples());
|
||||
if (ref->mParameters.mStopAtFrame &&
|
||||
mSamples.Length() == ref->mParameters.mStopAtFrame.ref()) {
|
||||
InitDecoder(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(mTrackDemuxer->GetInfo());
|
||||
break;
|
||||
default:
|
||||
Error(aError);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::InitDecoder(UniquePtr<TrackInfo>&& aInfo) {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
if (!aInfo) {
|
||||
Error(MediaResult(NS_ERROR_FAILURE, "Invalid TrackInfo"));
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PDMFactory> platform = new PDMFactory();
|
||||
mInfo = std::move(aInfo);
|
||||
RefPtr<Benchmark> ref(mGlobalState);
|
||||
platform->CreateDecoder(CreateDecoderParams{*mInfo})
|
||||
->Then(
|
||||
Thread(), __func__,
|
||||
[this, ref](RefPtr<MediaDataDecoder>&& aDecoder) {
|
||||
mDecoder = new MediaDataDecoderProxy(
|
||||
aDecoder.forget(), do_AddRef(mDecoderTaskQueue.get()));
|
||||
mDecoder->Init()->Then(
|
||||
Thread(), __func__,
|
||||
[this, ref](TrackInfo::TrackType aTrackType) {
|
||||
InputExhausted();
|
||||
},
|
||||
[this, ref](const MediaResult& aError) { Error(aError); });
|
||||
},
|
||||
[this, ref](const MediaResult& aError) { Error(aError); });
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::FinalizeShutdown() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
MOZ_ASSERT(mFinished, "GlobalShutdown must have been run");
|
||||
MOZ_ASSERT(!mDecoder, "mDecoder must have been shutdown already");
|
||||
MOZ_ASSERT(!mDemuxer, "mDemuxer must have been shutdown already");
|
||||
MOZ_DIAGNOSTIC_ASSERT(mDecoderTaskQueue->IsEmpty());
|
||||
mDecoderTaskQueue = nullptr;
|
||||
|
||||
RefPtr<Benchmark> ref(mGlobalState);
|
||||
ref->Thread()->Dispatch(NS_NewRunnableFunction(
|
||||
"BenchmarkPlayback::FinalizeShutdown", [ref]() { ref->Dispose(); }));
|
||||
}
|
||||
|
||||
void BenchmarkPlayback::GlobalShutdown() {
|
||||
MOZ_ASSERT(OnThread());
|
||||
|
||||
MOZ_ASSERT(!mFinished, "We've already shutdown");
|
||||
|
||||
mFinished = true;
|
||||
|
||||
if (mTrackDemuxer) {
|
||||
mTrackDemuxer->Reset();
|
||||
mTrackDemuxer->BreakCycles();
|
||||
mTrackDemuxer = nullptr;
|
||||
}
|
||||
mDemuxer = nullptr;
|
||||
|
||||
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;
|
||||
mInfo = 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); }));
|
||||
}
|
||||
}
|
||||
|
||||
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::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); });
|
||||
}
|
||||
}
|
||||
|
||||
#define MOZ_MEDIA_FUZZER(_name) \
|
||||
static int FuzzingRunMedia##_name(const uint8_t* data, size_t size) { \
|
||||
if (!size) { \
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/BenchmarkStorageParent.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using ::testing::Return;
|
||||
using namespace mozilla;
|
||||
|
||||
TEST(BenchmarkStorage, MovingAverage)
|
||||
{
|
||||
int32_t av = 0;
|
||||
int32_t win = 0;
|
||||
int32_t val = 100;
|
||||
BenchmarkStorageParent::MovingAverage(av, win, val);
|
||||
EXPECT_EQ(av, val) << "1st average";
|
||||
EXPECT_EQ(win, 1) << "1st window";
|
||||
|
||||
av = 50;
|
||||
win = 1;
|
||||
val = 100;
|
||||
BenchmarkStorageParent::MovingAverage(av, win, val);
|
||||
EXPECT_EQ(av, 75) << "2nd average";
|
||||
EXPECT_EQ(win, 2) << "2nd window";
|
||||
|
||||
av = 100;
|
||||
win = 9;
|
||||
val = 90;
|
||||
BenchmarkStorageParent::MovingAverage(av, win, val);
|
||||
EXPECT_EQ(av, 99) << "9th average";
|
||||
EXPECT_EQ(win, 10) << "9th window";
|
||||
|
||||
av = 90;
|
||||
win = 19;
|
||||
val = 90;
|
||||
BenchmarkStorageParent::MovingAverage(av, win, val);
|
||||
EXPECT_EQ(av, 90) << "19th average";
|
||||
EXPECT_EQ(win, 20) << "19th window";
|
||||
|
||||
av = 90;
|
||||
win = 20;
|
||||
val = 100;
|
||||
BenchmarkStorageParent::MovingAverage(av, win, val);
|
||||
EXPECT_EQ(av, 91) << "20th average";
|
||||
EXPECT_EQ(win, 20) << "20th window";
|
||||
}
|
||||
|
||||
TEST(BenchmarkStorage, ParseStoredValue)
|
||||
{
|
||||
int32_t win = 0;
|
||||
int32_t score = BenchmarkStorageParent::ParseStoredValue(1100, win);
|
||||
EXPECT_EQ(win, 1) << "Window";
|
||||
EXPECT_EQ(score, 100) << "Score/Percentage";
|
||||
|
||||
win = 0;
|
||||
score = BenchmarkStorageParent::ParseStoredValue(10099, win);
|
||||
EXPECT_EQ(win, 10) << "Window";
|
||||
EXPECT_EQ(score, 99) << "Score/Percentage";
|
||||
|
||||
win = 0;
|
||||
score = BenchmarkStorageParent::ParseStoredValue(15038, win);
|
||||
EXPECT_EQ(win, 15) << "Window";
|
||||
EXPECT_EQ(score, 38) << "Score/Percentage";
|
||||
|
||||
win = 0;
|
||||
score = BenchmarkStorageParent::ParseStoredValue(20099, win);
|
||||
EXPECT_EQ(win, 20) << "Window";
|
||||
EXPECT_EQ(score, 99) << "Score/Percentage";
|
||||
}
|
||||
|
||||
TEST(BenchmarkStorage, PrepareStoredValue)
|
||||
{
|
||||
int32_t stored_value = BenchmarkStorageParent::PrepareStoredValue(80, 1);
|
||||
EXPECT_EQ(stored_value, 1080) << "Window";
|
||||
|
||||
stored_value = BenchmarkStorageParent::PrepareStoredValue(100, 6);
|
||||
EXPECT_EQ(stored_value, 6100) << "Window";
|
||||
|
||||
stored_value = BenchmarkStorageParent::PrepareStoredValue(1, 10);
|
||||
EXPECT_EQ(stored_value, 10001) << "Window";
|
||||
|
||||
stored_value = BenchmarkStorageParent::PrepareStoredValue(88, 13);
|
||||
EXPECT_EQ(stored_value, 13088) << "Window";
|
||||
|
||||
stored_value = BenchmarkStorageParent::PrepareStoredValue(100, 20);
|
||||
EXPECT_EQ(stored_value, 20100) << "Window";
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DecoderBenchmark.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using ::testing::Return;
|
||||
using namespace mozilla;
|
||||
|
||||
TEST(DecoderBenchmark, CreateKey)
|
||||
{
|
||||
DecoderBenchmarkInfo info{"video/av1"_ns, 1, 1, 1, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info),
|
||||
"ResolutionLevel0-FrameRateLevel0-8bit"_ns)
|
||||
<< "Min level";
|
||||
|
||||
DecoderBenchmarkInfo info1{"video/av1"_ns, 5000, 5000, 100, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info1),
|
||||
"ResolutionLevel7-FrameRateLevel4-8bit"_ns)
|
||||
<< "Max level";
|
||||
|
||||
DecoderBenchmarkInfo info2{"video/av1"_ns, 854, 480, 30, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info2),
|
||||
"ResolutionLevel3-FrameRateLevel2-8bit"_ns)
|
||||
<< "On the top of 4th resolution level";
|
||||
|
||||
DecoderBenchmarkInfo info3{"video/av1"_ns, 1270, 710, 24, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info3),
|
||||
"ResolutionLevel4-FrameRateLevel1-8bit"_ns)
|
||||
<< "Closer to 5th resolution level - bellow";
|
||||
|
||||
DecoderBenchmarkInfo info4{"video/av1"_ns, 1290, 730, 24, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info4),
|
||||
"ResolutionLevel4-FrameRateLevel1-8bit"_ns)
|
||||
<< "Closer to 5th resolution level - above";
|
||||
|
||||
DecoderBenchmarkInfo info5{"video/av1"_ns, 854, 480, 20, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info5),
|
||||
"ResolutionLevel3-FrameRateLevel1-8bit"_ns)
|
||||
<< "Closer to 2nd frame rate level - bellow";
|
||||
|
||||
DecoderBenchmarkInfo info6{"video/av1"_ns, 854, 480, 26, 8};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info6),
|
||||
"ResolutionLevel3-FrameRateLevel1-8bit"_ns)
|
||||
<< "Closer to 2nd frame rate level - above";
|
||||
|
||||
DecoderBenchmarkInfo info7{"video/av1"_ns, 1280, 720, 24, 10};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info7),
|
||||
"ResolutionLevel4-FrameRateLevel1-non8bit"_ns)
|
||||
<< "Bit depth 10 bits";
|
||||
|
||||
DecoderBenchmarkInfo info8{"video/av1"_ns, 1280, 720, 24, 12};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info8),
|
||||
"ResolutionLevel4-FrameRateLevel1-non8bit"_ns)
|
||||
<< "Bit depth 12 bits";
|
||||
|
||||
DecoderBenchmarkInfo info9{"video/av1"_ns, 1280, 720, 24, 16};
|
||||
EXPECT_EQ(KeyUtil::CreateKey(info9),
|
||||
"ResolutionLevel4-FrameRateLevel1-non8bit"_ns)
|
||||
<< "Bit depth 16 bits";
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/KeyValueStorage.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "GMPTestMonitor.h"
|
||||
|
||||
using ::testing::Return;
|
||||
using namespace mozilla;
|
||||
|
||||
TEST(TestKeyValueStorage, BasicPutGet)
|
||||
{
|
||||
auto kvs = MakeRefPtr<KeyValueStorage>();
|
||||
|
||||
nsCString name("database_name");
|
||||
nsCString key("key1");
|
||||
int32_t value = 100;
|
||||
|
||||
GMPTestMonitor mon;
|
||||
|
||||
kvs->Put(name, key, value)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](bool) { return kvs->Get(name, key); },
|
||||
[](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Put promise has been rejected";
|
||||
return KeyValueStorage::GetPromise::CreateAndReject(rv, __func__);
|
||||
})
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](int32_t aValue) {
|
||||
EXPECT_EQ(aValue, value) << "Values are the same";
|
||||
mon.SetFinished();
|
||||
},
|
||||
[&](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Get Promise has been rejected";
|
||||
mon.SetFinished();
|
||||
});
|
||||
|
||||
mon.AwaitFinished();
|
||||
}
|
||||
|
||||
TEST(TestKeyValueStorage, GetNonExistedKey)
|
||||
{
|
||||
auto kvs = MakeRefPtr<KeyValueStorage>();
|
||||
|
||||
nsCString name("database_name");
|
||||
nsCString key("NonExistedKey");
|
||||
|
||||
GMPTestMonitor mon;
|
||||
|
||||
kvs->Get(name, key)->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&mon](int32_t aValue) {
|
||||
EXPECT_EQ(aValue, -1) << "When key does not exist return -1";
|
||||
mon.SetFinished();
|
||||
},
|
||||
[&mon](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Get Promise has been rejected";
|
||||
mon.SetFinished();
|
||||
});
|
||||
|
||||
mon.AwaitFinished();
|
||||
}
|
||||
|
||||
TEST(TestKeyValueStorage, Clear)
|
||||
{
|
||||
auto kvs = MakeRefPtr<KeyValueStorage>();
|
||||
|
||||
nsCString name("database_name");
|
||||
nsCString key("key1");
|
||||
int32_t value = 100;
|
||||
|
||||
GMPTestMonitor mon;
|
||||
|
||||
kvs->Put(name, key, value)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](bool) { return kvs->Clear(name); },
|
||||
[](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Put promise has been rejected";
|
||||
return GenericPromise::CreateAndReject(rv, __func__);
|
||||
})
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](bool) { return kvs->Get(name, key); },
|
||||
[](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Clear promise has been rejected";
|
||||
return KeyValueStorage::GetPromise::CreateAndReject(rv, __func__);
|
||||
})
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[&](int32_t aValue) {
|
||||
EXPECT_EQ(aValue, -1) << "After clear the key does not exist";
|
||||
mon.SetFinished();
|
||||
},
|
||||
[&](nsresult rv) {
|
||||
EXPECT_TRUE(false) << "Get Promise has been rejected";
|
||||
mon.SetFinished();
|
||||
});
|
||||
|
||||
mon.AwaitFinished();
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "Benchmark.h"
|
||||
#include "MockMediaResource.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaContainerType.h"
|
||||
#include "MP4Demuxer.h"
|
||||
#include "MP4Decoder.h"
|
||||
#include "WebMDecoder.h"
|
||||
#include "WebMDemuxer.h"
|
||||
#include "mozilla/AbstractThread.h"
|
||||
#include "mozilla/gtest/MozAssertions.h"
|
||||
#include "mozilla/SpinEventLoopUntil.h"
|
||||
#include "nsMimeTypes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
class BenchmarkRunner {
|
||||
public:
|
||||
explicit BenchmarkRunner(Benchmark* aBenchmark) : mBenchmark(aBenchmark) {}
|
||||
|
||||
uint32_t Run() {
|
||||
bool done = false;
|
||||
uint32_t result = 0;
|
||||
|
||||
mBenchmark->Init();
|
||||
mBenchmark->Run()->Then(
|
||||
// Non DocGroup-version of AbstractThread::MainThread() is fine for
|
||||
// testing.
|
||||
AbstractThread::MainThread(), __func__,
|
||||
[&](uint32_t aDecodeFps) {
|
||||
result = aDecodeFps;
|
||||
done = true;
|
||||
},
|
||||
[&]() { done = true; });
|
||||
|
||||
// Wait until benchmark completes.
|
||||
SpinEventLoopUntil("BenchmarkRunner::Run"_ns, [&]() { return done; });
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<Benchmark> mBenchmark;
|
||||
};
|
||||
|
||||
TEST(MediaDataDecoder, H264)
|
||||
{
|
||||
if (!MP4Decoder::IsSupportedType(MediaContainerType(MEDIAMIMETYPE(VIDEO_MP4)),
|
||||
/* DecoderDoctorDiagnostics* */ nullptr)) {
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
RefPtr<MockMediaResource> resource = new MockMediaResource("gizmo.mp4");
|
||||
nsresult rv = resource->Open();
|
||||
EXPECT_NS_SUCCEEDED(rv);
|
||||
|
||||
BenchmarkRunner runner(new Benchmark(new MP4Demuxer(resource)));
|
||||
EXPECT_GT(runner.Run(), 0u);
|
||||
}
|
||||
}
|
||||
|
||||
// Decoding AV1 via. ffvpx is supported on Linux only.
|
||||
#if defined(MOZ_AV1) && defined(MOZ_WIDGET_GTK) && !defined(MOZ_FFVPX_AUDIOONLY)
|
||||
TEST(MediaDataDecoder, AV1)
|
||||
{
|
||||
if (!MP4Decoder::IsSupportedType(MediaContainerType(MEDIAMIMETYPE(VIDEO_MP4)),
|
||||
/* DecoderDoctorDiagnostics* */ nullptr)) {
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
RefPtr<MockMediaResource> resource = new MockMediaResource("av1.mp4");
|
||||
nsresult rv = resource->Open();
|
||||
EXPECT_NS_SUCCEEDED(rv);
|
||||
|
||||
BenchmarkRunner runner(new Benchmark(new MP4Demuxer(resource)));
|
||||
EXPECT_GT(runner.Run(), 0u);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(MediaDataDecoder, VP9)
|
||||
{
|
||||
if (!WebMDecoder::IsSupportedType(
|
||||
MediaContainerType(MEDIAMIMETYPE(VIDEO_WEBM)))) {
|
||||
EXPECT_TRUE(true);
|
||||
} else {
|
||||
RefPtr<MockMediaResource> resource = new MockMediaResource("vp9cake.webm");
|
||||
nsresult rv = resource->Open();
|
||||
EXPECT_NS_SUCCEEDED(rv);
|
||||
|
||||
BenchmarkRunner runner(new Benchmark(new WebMDemuxer(resource)));
|
||||
EXPECT_GT(runner.Run(), 0u);
|
||||
}
|
||||
}
|
||||
@@ -36,22 +36,18 @@ UNIFIED_SOURCES += [
|
||||
"TestAudioSinkWrapper.cpp",
|
||||
"TestAudioTrackEncoder.cpp",
|
||||
"TestAudioTrackGraph.cpp",
|
||||
"TestBenchmarkStorage.cpp",
|
||||
"TestBitWriter.cpp",
|
||||
"TestBlankVideoDataCreator.cpp",
|
||||
"TestBufferReader.cpp",
|
||||
"TestCubebInputStream.cpp",
|
||||
"TestDataMutex.cpp",
|
||||
"TestDecoderBenchmark.cpp",
|
||||
"TestDeviceInputTrack.cpp",
|
||||
"TestDriftCompensation.cpp",
|
||||
"TestGMPUtils.cpp",
|
||||
"TestGroupId.cpp",
|
||||
"TestImageConversion.cpp",
|
||||
"TestIntervalSet.cpp",
|
||||
"TestKeyValueStorage.cpp",
|
||||
"TestMediaCodecsSupport.cpp",
|
||||
"TestMediaDataDecoder.cpp",
|
||||
"TestMediaDataEncoder.cpp",
|
||||
"TestMediaEventSource.cpp",
|
||||
"TestMediaInfo.cpp",
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BenchmarkStorageChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static PBenchmarkStorageChild* sChild = nullptr;
|
||||
|
||||
/* static */
|
||||
PBenchmarkStorageChild* BenchmarkStorageChild::Instance() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!sChild) {
|
||||
sChild = new BenchmarkStorageChild();
|
||||
PContentChild* contentChild = dom::ContentChild::GetSingleton();
|
||||
MOZ_ASSERT(contentChild);
|
||||
if (!contentChild->SendPBenchmarkStorageConstructor()) {
|
||||
MOZ_CRASH("SendPBenchmarkStorageConstructor failed");
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(sChild);
|
||||
return sChild;
|
||||
}
|
||||
|
||||
BenchmarkStorageChild::~BenchmarkStorageChild() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (sChild == this) {
|
||||
sChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,28 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef include_dom_media_mediacapabilities_BenchmarkStorageChild_h
|
||||
#define include_dom_media_mediacapabilities_BenchmarkStorageChild_h
|
||||
|
||||
#include "mozilla/PBenchmarkStorageChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class BenchmarkStorageChild : public PBenchmarkStorageChild {
|
||||
public:
|
||||
/* Singleton class to avoid recreating the protocol every time we need access
|
||||
* to the storage. */
|
||||
static PBenchmarkStorageChild* Instance();
|
||||
|
||||
~BenchmarkStorageChild();
|
||||
|
||||
private:
|
||||
BenchmarkStorageChild() = default;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include_dom_media_mediacapabilities_BenchmarkStorageChild_h
|
||||
@@ -1,130 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BenchmarkStorageParent.h"
|
||||
#include "KeyValueStorage.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* Moving average window size. */
|
||||
const int32_t AVG_WINDOW = 20;
|
||||
/* Calculate the moving average for the new value aValue for the current window
|
||||
* aWindow and the already existing average aAverage. When the method returns
|
||||
* aAverage will contain the new average and aWindow will contain the new
|
||||
* window.*/
|
||||
void BenchmarkStorageParent::MovingAverage(int32_t& aAverage, int32_t& aWindow,
|
||||
const int32_t aValue) {
|
||||
if (aWindow < AVG_WINDOW) {
|
||||
aAverage = (aAverage * aWindow + aValue) / (aWindow + 1);
|
||||
aWindow++;
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aWindow == AVG_WINDOW);
|
||||
aAverage = (aAverage - aAverage / aWindow) + (aValue / aWindow);
|
||||
}
|
||||
|
||||
/* In order to decrease the number of times the database is accessed when the
|
||||
* moving average is stored or retrieved we use the same value to store _both_
|
||||
* the window and the average. The range of the average is limited since it is
|
||||
* a percentage (0-100), and the range of the window is limited
|
||||
* (1-20). Thus the number that is stored in the database is in the form
|
||||
* (digits): WWAAA. For example, the value stored when an average(A) of 88
|
||||
* corresponds to a window(W) 7 is 7088. The average of 100 that corresponds to
|
||||
* a window of 20 is 20100. The following methods are helpers to extract or
|
||||
* construct the stored value according to the above. */
|
||||
|
||||
/* Stored value will be in the form WWAAA(19098). We need to extract the window
|
||||
* (19) and the average score (98). The aValue will
|
||||
* be parsed, the aWindow will contain the window (of the moving average) and
|
||||
* the return value will contain the average itself. */
|
||||
int32_t BenchmarkStorageParent::ParseStoredValue(int32_t aValue,
|
||||
int32_t& aWindow) {
|
||||
MOZ_ASSERT(aValue > 999);
|
||||
MOZ_ASSERT(aValue < 100000);
|
||||
|
||||
int32_t score = aValue % 1000;
|
||||
aWindow = (aValue / 1000) % 100;
|
||||
return score;
|
||||
}
|
||||
|
||||
int32_t BenchmarkStorageParent::PrepareStoredValue(int32_t aScore,
|
||||
int32_t aWindow) {
|
||||
MOZ_ASSERT(aScore >= 0);
|
||||
MOZ_ASSERT(aScore <= 100);
|
||||
MOZ_ASSERT(aWindow > 0);
|
||||
MOZ_ASSERT(aWindow < 21);
|
||||
|
||||
return aWindow * 1000 + aScore;
|
||||
}
|
||||
|
||||
BenchmarkStorageParent::BenchmarkStorageParent()
|
||||
: mStorage(new KeyValueStorage) {}
|
||||
|
||||
IPCResult BenchmarkStorageParent::RecvPut(const nsCString& aDbName,
|
||||
const nsCString& aKey,
|
||||
const int32_t& aValue) {
|
||||
// In order to calculate and store the new moving average, we need to get the
|
||||
// stored value and window first, to calculate the new score and window, and
|
||||
// then to store the new aggregated value.
|
||||
mStorage->Get(aDbName, aKey)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[storage = mStorage, aDbName, aKey, aValue](int32_t aResult) {
|
||||
int32_t window = 0;
|
||||
int32_t average = 0;
|
||||
if (aResult >= 0) {
|
||||
// The key found.
|
||||
average = ParseStoredValue(aResult, window);
|
||||
}
|
||||
MovingAverage(average, window, aValue);
|
||||
int32_t newValue = PrepareStoredValue(average, window);
|
||||
// Avoid storing if the values are the same. This is an optimization
|
||||
// to minimize the disk usage.
|
||||
if (aResult != newValue) {
|
||||
storage->Put(aDbName, aKey, newValue);
|
||||
}
|
||||
},
|
||||
[](nsresult rv) { /*do nothing*/ });
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult BenchmarkStorageParent::RecvGet(const nsCString& aDbName,
|
||||
const nsCString& aKey,
|
||||
GetResolver&& aResolve) {
|
||||
mStorage->Get(aDbName, aKey)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[aResolve](int32_t aResult) {
|
||||
int32_t window = 0; // not used
|
||||
aResolve(aResult < 0 ? -1 : ParseStoredValue(aResult, window));
|
||||
},
|
||||
[aResolve](nsresult rv) { aResolve(-1); });
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
IPCResult BenchmarkStorageParent::RecvCheckVersion(const nsCString& aDbName,
|
||||
int32_t aVersion) {
|
||||
mStorage->Get(aDbName, "Version"_ns)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[storage = mStorage, aDbName, aVersion](int32_t aResult) {
|
||||
if (aVersion != aResult) {
|
||||
storage->Clear(aDbName)->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[storage, aDbName, aVersion](bool) {
|
||||
storage->Put(aDbName, "Version"_ns, aVersion);
|
||||
},
|
||||
[](nsresult rv) { /*do nothing*/ });
|
||||
}
|
||||
},
|
||||
[](nsresult rv) { /*do nothing*/ });
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
}; // namespace mozilla
|
||||
@@ -1,43 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef include_dom_media_mediacapabilities_BenchmarkStorageParent_h
|
||||
#define include_dom_media_mediacapabilities_BenchmarkStorageParent_h
|
||||
|
||||
#include "mozilla/PBenchmarkStorageParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
class KeyValueStorage;
|
||||
|
||||
using mozilla::ipc::IPCResult;
|
||||
|
||||
class BenchmarkStorageParent : public PBenchmarkStorageParent {
|
||||
friend class PBenchmarkStorageParent;
|
||||
|
||||
public:
|
||||
BenchmarkStorageParent();
|
||||
|
||||
IPCResult RecvPut(const nsCString& aDbName, const nsCString& aKey,
|
||||
const int32_t& aValue);
|
||||
|
||||
IPCResult RecvGet(const nsCString& aDbName, const nsCString& aKey,
|
||||
GetResolver&& aResolve);
|
||||
|
||||
IPCResult RecvCheckVersion(const nsCString& aDbName, int32_t aVersion);
|
||||
|
||||
/* Helper methods exposed here to be tested via gtest. */
|
||||
static void MovingAverage(int32_t& aAverage, int32_t& aWindow,
|
||||
const int32_t aValue);
|
||||
static int32_t ParseStoredValue(int32_t aValue, int32_t& aWindow);
|
||||
static int32_t PrepareStoredValue(int32_t aScore, int32_t aWindow);
|
||||
|
||||
private:
|
||||
RefPtr<KeyValueStorage> mStorage;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include_dom_media_mediacapabilities_BenchmarkStorageParent_h
|
||||
@@ -1,243 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DecoderBenchmark.h"
|
||||
#include "mozilla/BenchmarkStorageChild.h"
|
||||
#include "mozilla/media/MediaUtils.h"
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void DecoderBenchmark::StoreScore(const nsACString& aDecoderName,
|
||||
const nsACString& aKey,
|
||||
RefPtr<FrameStatistics> aStats) {
|
||||
FrameStatisticsData statsData = aStats->GetFrameStatisticsData();
|
||||
uint64_t totalFrames = FrameStatistics::GetTotalFrames(statsData);
|
||||
uint64_t droppedFrames = FrameStatistics::GetDroppedFrames(statsData);
|
||||
|
||||
MOZ_ASSERT(droppedFrames <= totalFrames);
|
||||
MOZ_ASSERT(totalFrames >= mLastTotalFrames);
|
||||
MOZ_ASSERT(droppedFrames >= mLastDroppedFrames);
|
||||
|
||||
uint64_t diffTotalFrames = totalFrames - mLastTotalFrames;
|
||||
uint64_t diffDroppedFrames = droppedFrames - mLastDroppedFrames;
|
||||
|
||||
/* Update now in case the method returns at the if check bellow. */
|
||||
mLastTotalFrames = totalFrames;
|
||||
mLastDroppedFrames = droppedFrames;
|
||||
|
||||
/* A minimum number of 10 frames is required to store the score. */
|
||||
if (diffTotalFrames < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t percentage =
|
||||
100 - 100 * float(diffDroppedFrames) / float(diffTotalFrames);
|
||||
|
||||
MOZ_ASSERT(percentage >= 0);
|
||||
|
||||
Put(aDecoderName, aKey, percentage);
|
||||
}
|
||||
|
||||
void DecoderBenchmark::Put(const nsACString& aDecoderName,
|
||||
const nsACString& aKey, int32_t aValue) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
const nsCString name(aDecoderName);
|
||||
const nsCString key(aKey);
|
||||
BenchmarkStorageChild::Instance()->SendPut(name, key, aValue);
|
||||
}
|
||||
|
||||
RefPtr<BenchmarkScorePromise> DecoderBenchmark::GetScore(
|
||||
const nsACString& aDecoderName, const nsACString& aKey) {
|
||||
if (NS_IsMainThread()) {
|
||||
return Get(aDecoderName, aKey);
|
||||
}
|
||||
|
||||
RefPtr<DecoderBenchmark> self = this;
|
||||
const nsCString decoderName(aDecoderName);
|
||||
const nsCString key(aKey);
|
||||
return InvokeAsync(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self, decoderName, key] { return self->Get(decoderName, key); });
|
||||
}
|
||||
|
||||
RefPtr<BenchmarkScorePromise> DecoderBenchmark::Get(
|
||||
const nsACString& aDecoderName, const nsACString& aKey) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
const nsCString name(aDecoderName);
|
||||
const nsCString key(aKey);
|
||||
return BenchmarkStorageChild::Instance()->SendGet(name, key)->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[](int32_t aResult) {
|
||||
return BenchmarkScorePromise::CreateAndResolve(aResult, __func__);
|
||||
},
|
||||
[](ipc::ResponseRejectReason&&) {
|
||||
return BenchmarkScorePromise::CreateAndReject(NS_ERROR_FAILURE,
|
||||
__func__);
|
||||
});
|
||||
}
|
||||
|
||||
/* The key string consists of the video properties resolution, framerate,
|
||||
* and bitdepth. There are various levels for each of them. The key is
|
||||
* formated by the closest level, for example, a video with width=1920,
|
||||
* height=1080, frameRate=24, and bitdepth=8bit will have the key:
|
||||
* "ResolutionLevel5-FrameRateLevel1-8bit". */
|
||||
|
||||
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* Keep them sorted */
|
||||
const uint32_t PixelLevels[] = {
|
||||
/* 256x144 =*/36864,
|
||||
/* 426x240 =*/102240,
|
||||
/* 640x360 =*/230400,
|
||||
/* 854x480 =*/409920,
|
||||
/* 1280x720 =*/921600,
|
||||
/* 1920x1080 =*/2073600,
|
||||
/* 2560x1440 =*/3686400,
|
||||
/* 3840x2160 =*/8294400,
|
||||
};
|
||||
const size_t PixelLevelsSize = NELEMS(PixelLevels);
|
||||
|
||||
const uint32_t FrameRateLevels[] = {
|
||||
15, 24, 30, 50, 60,
|
||||
};
|
||||
const size_t FrameRateLevelsSize = NELEMS(FrameRateLevels);
|
||||
|
||||
/* static */
|
||||
nsCString KeyUtil::FindLevel(const uint32_t aLevels[], const size_t length,
|
||||
uint32_t aValue) {
|
||||
MOZ_ASSERT(aValue);
|
||||
if (aValue <= aLevels[0]) {
|
||||
return "Level0"_ns;
|
||||
}
|
||||
nsAutoCString level("Level");
|
||||
size_t lastIndex = length - 1;
|
||||
if (aValue >= aLevels[lastIndex]) {
|
||||
level.AppendInt(static_cast<uint32_t>(lastIndex));
|
||||
return std::move(level);
|
||||
}
|
||||
for (size_t i = 0; i < lastIndex; ++i) {
|
||||
if (aValue >= aLevels[i + 1]) {
|
||||
continue;
|
||||
}
|
||||
if (aValue - aLevels[i] < aLevels[i + 1] - aValue) {
|
||||
level.AppendInt(static_cast<uint32_t>(i));
|
||||
return std::move(level);
|
||||
}
|
||||
level.AppendInt(static_cast<uint32_t>(i + 1));
|
||||
return std::move(level);
|
||||
}
|
||||
MOZ_CRASH("Array is not sorted");
|
||||
return ""_ns;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsCString KeyUtil::BitDepthToStr(uint8_t aBitDepth) {
|
||||
switch (aBitDepth) {
|
||||
case 8: // ColorDepth::COLOR_8
|
||||
return "-8bit"_ns;
|
||||
case 10: // ColorDepth::COLOR_10
|
||||
case 12: // ColorDepth::COLOR_12
|
||||
case 16: // ColorDepth::COLOR_16
|
||||
return "-non8bit"_ns;
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("invalid color depth value");
|
||||
return ""_ns;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsCString KeyUtil::CreateKey(const DecoderBenchmarkInfo& aBenchInfo) {
|
||||
nsAutoCString key("Resolution");
|
||||
key.Append(FindLevel(PixelLevels, PixelLevelsSize,
|
||||
aBenchInfo.mWidth * aBenchInfo.mHeight));
|
||||
|
||||
key.Append("-FrameRate");
|
||||
key.Append(
|
||||
FindLevel(FrameRateLevels, FrameRateLevelsSize, aBenchInfo.mFrameRate));
|
||||
|
||||
key.Append(BitDepthToStr(aBenchInfo.mBitDepth));
|
||||
|
||||
return std::move(key);
|
||||
}
|
||||
|
||||
void DecoderBenchmark::Store(const DecoderBenchmarkInfo& aBenchInfo,
|
||||
RefPtr<FrameStatistics> aStats) {
|
||||
if (!XRE_IsContentProcess()) {
|
||||
NS_WARNING(
|
||||
"Storing a benchmark is only allowed only from the content process.");
|
||||
return;
|
||||
}
|
||||
StoreScore(aBenchInfo.mContentType, KeyUtil::CreateKey(aBenchInfo), aStats);
|
||||
}
|
||||
|
||||
/* static */
|
||||
RefPtr<BenchmarkScorePromise> DecoderBenchmark::Get(
|
||||
const DecoderBenchmarkInfo& aBenchInfo) {
|
||||
if (!XRE_IsContentProcess()) {
|
||||
NS_WARNING(
|
||||
"Getting a benchmark is only allowed only from the content process.");
|
||||
return BenchmarkScorePromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
// There is no need for any of the data members to query the database, thus
|
||||
// it can be a static method.
|
||||
auto bench = MakeRefPtr<DecoderBenchmark>();
|
||||
return bench->GetScore(aBenchInfo.mContentType,
|
||||
KeyUtil::CreateKey(aBenchInfo));
|
||||
}
|
||||
|
||||
static nsTHashMap<nsCStringHashKey, int32_t> DecoderVersionTable() {
|
||||
nsTHashMap<nsCStringHashKey, int32_t> decoderVersionTable;
|
||||
|
||||
/*
|
||||
* For the decoders listed here, the benchmark version number will be checked.
|
||||
* If the version number does not exist in the database or is different than
|
||||
* the version number listed here, all the benchmark entries for this decoder
|
||||
* will be erased. An example of assigning the version number `1` for AV1
|
||||
* decoder is:
|
||||
*
|
||||
* decoderVersionTable.InsertOrUpdate("video/av1"_ns, 1);
|
||||
*
|
||||
* For the decoders not listed here the `CheckVersion` method exits early, to
|
||||
* avoid sending unecessary IPC messages.
|
||||
*/
|
||||
|
||||
return decoderVersionTable;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void DecoderBenchmark::CheckVersion(const nsACString& aDecoderName) {
|
||||
if (!XRE_IsContentProcess()) {
|
||||
NS_WARNING(
|
||||
"Checking version is only allowed only from the content process.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StaticPrefs::media_mediacapabilities_from_database()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString name(aDecoderName);
|
||||
int32_t version;
|
||||
if (!DecoderVersionTable().Get(name, &version)) {
|
||||
// A version is not set for that decoder ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
BenchmarkStorageChild::Instance()->SendCheckVersion(name, version);
|
||||
return;
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rv =
|
||||
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
|
||||
"DecoderBenchmark::CheckVersion", [name, version]() {
|
||||
BenchmarkStorageChild::Instance()->SendCheckVersion(name, version);
|
||||
}));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,77 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef MOZILLA_DECODER_BENCHMARK_H
|
||||
#define MOZILLA_DECODER_BENCHMARK_H
|
||||
|
||||
#include "FrameStatistics.h"
|
||||
#include "mozilla/BenchmarkStorageChild.h"
|
||||
#include "mozilla/KeyValueStorage.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
typedef KeyValueStorage::GetPromise BenchmarkScorePromise;
|
||||
|
||||
struct DecoderBenchmarkInfo final {
|
||||
const nsCString mContentType;
|
||||
const int32_t mWidth;
|
||||
const int32_t mHeight;
|
||||
const int32_t mFrameRate;
|
||||
const uint32_t mBitDepth;
|
||||
};
|
||||
|
||||
class DecoderBenchmark final {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecoderBenchmark)
|
||||
|
||||
public:
|
||||
void Store(const DecoderBenchmarkInfo& aBenchInfo,
|
||||
RefPtr<FrameStatistics> aStats);
|
||||
|
||||
static RefPtr<BenchmarkScorePromise> Get(
|
||||
const DecoderBenchmarkInfo& aBenchInfo);
|
||||
|
||||
/* For the specific decoder, specified by aDecoderName, it compares the
|
||||
* version number, from a static list of versions, to the version number
|
||||
* found in the database. If those numbers are different all benchmark
|
||||
* entries for that decoder are deleted. */
|
||||
static void CheckVersion(const nsACString& aDecoderName);
|
||||
|
||||
private:
|
||||
void StoreScore(const nsACString& aDecoderName, const nsACString& aKey,
|
||||
RefPtr<FrameStatistics> aStats);
|
||||
|
||||
RefPtr<BenchmarkScorePromise> GetScore(const nsACString& aDecoderName,
|
||||
const nsACString& aKey);
|
||||
|
||||
void Put(const nsACString& aDecoderName, const nsACString& aKey,
|
||||
int32_t aValue);
|
||||
|
||||
RefPtr<BenchmarkScorePromise> Get(const nsACString& aDecoderName,
|
||||
const nsACString& aKey);
|
||||
~DecoderBenchmark() = default;
|
||||
|
||||
// Keep the last TotalFrames and DroppedFrames from FrameStatistics.
|
||||
// FrameStatistics keep an ever-increasing counter across the entire video and
|
||||
// even when there are resolution changes. This code is called whenever there
|
||||
// is a resolution change and we need to calculate the benchmark since the
|
||||
// last call.
|
||||
uint64_t mLastTotalFrames = 0;
|
||||
uint64_t mLastDroppedFrames = 0;
|
||||
};
|
||||
|
||||
class KeyUtil {
|
||||
public:
|
||||
static nsCString CreateKey(const DecoderBenchmarkInfo& aBenchInfo);
|
||||
|
||||
private:
|
||||
static nsCString BitDepthToStr(uint8_t aBitDepth);
|
||||
static nsCString FindLevel(const uint32_t aLevels[], const size_t length,
|
||||
uint32_t aValue);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_DECODER_BENCHMARK_H
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "AllocationPolicy.h"
|
||||
#include "Benchmark.h"
|
||||
#include "DecoderBenchmark.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "MediaRecorder.h"
|
||||
@@ -463,7 +461,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
||||
return AllocationWrapper::CreateDecoder(params, sVideoAllocPolicy)
|
||||
->Then(
|
||||
taskQueue, __func__,
|
||||
[taskQueue, frameRate, shouldResistFingerprinting,
|
||||
[taskQueue, shouldResistFingerprinting,
|
||||
config = std::move(config)](
|
||||
AllocationWrapper::AllocateDecoderPromise::
|
||||
ResolveOrRejectValue&& aValue) mutable {
|
||||
@@ -477,7 +475,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
||||
// efficient.
|
||||
RefPtr<CapabilitiesPromise> p = decoder->Init()->Then(
|
||||
taskQueue, __func__,
|
||||
[taskQueue, decoder, frameRate,
|
||||
[taskQueue, decoder,
|
||||
shouldResistFingerprinting,
|
||||
config = std::move(config)](
|
||||
MediaDataDecoder::InitPromise::
|
||||
@@ -494,39 +492,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
||||
p = CapabilitiesPromise::CreateAndResolve(std::move(info), __func__);
|
||||
} else {
|
||||
MOZ_ASSERT(config->IsVideo());
|
||||
if (StaticPrefs::media_mediacapabilities_from_database()) {
|
||||
nsAutoCString reason;
|
||||
bool powerEfficient =
|
||||
decoder->IsHardwareAccelerated(reason);
|
||||
|
||||
int32_t videoFrameRate = std::clamp<int32_t>(frameRate, 1, INT32_MAX);
|
||||
|
||||
DecoderBenchmarkInfo benchmarkInfo{
|
||||
config->mMimeType,
|
||||
config->GetAsVideoInfo()->mImage.width,
|
||||
config->GetAsVideoInfo()->mImage.height,
|
||||
videoFrameRate, 8};
|
||||
|
||||
p = DecoderBenchmark::Get(benchmarkInfo)->Then(
|
||||
GetMainThreadSerialEventTarget(),
|
||||
__func__,
|
||||
[powerEfficient](int32_t score) {
|
||||
// score < 0 means no entry found.
|
||||
bool smooth = score < 0 || score >
|
||||
StaticPrefs::
|
||||
media_mediacapabilities_drop_threshold();
|
||||
MediaCapabilitiesDecodingInfo info;
|
||||
info.mSupported = true;
|
||||
info.mSmooth = smooth;
|
||||
info.mPowerEfficient = powerEfficient;
|
||||
return CapabilitiesPromise::
|
||||
CreateAndResolve(std::move(info), __func__);
|
||||
},
|
||||
[](nsresult rv) {
|
||||
return CapabilitiesPromise::
|
||||
CreateAndReject(rv, __func__);
|
||||
});
|
||||
} else if (config->GetAsVideoInfo()->mImage.height < 480) {
|
||||
if (config->GetAsVideoInfo()->mImage.height < 480) {
|
||||
// Assume that we can do stuff at 480p or less in
|
||||
// a power efficient manner and smoothly. If
|
||||
// greater than 480p we assume that if the video
|
||||
@@ -543,28 +509,6 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
||||
bool smooth = true;
|
||||
bool powerEfficient =
|
||||
decoder->IsHardwareAccelerated(reason);
|
||||
if (!powerEfficient &&
|
||||
VPXDecoder::IsVP9(config->mMimeType)) {
|
||||
smooth = VP9Benchmark::IsVP9DecodeFast(
|
||||
true /* default */);
|
||||
uint32_t fps =
|
||||
VP9Benchmark::MediaBenchmarkVp9Fps();
|
||||
if (!smooth && fps > 0) {
|
||||
// The VP9 estimizer decode a 1280x720 video.
|
||||
// Let's adjust the result for the resolution
|
||||
// and frame rate of what we actually want. If
|
||||
// the result is twice that we need we assume
|
||||
// it will be smooth.
|
||||
const auto& videoConfig =
|
||||
*config->GetAsVideoInfo();
|
||||
double needed = ((1280.0 * 720.0) /
|
||||
(videoConfig.mImage.width *
|
||||
videoConfig.mImage.height) *
|
||||
fps) /
|
||||
frameRate;
|
||||
smooth = needed > 2;
|
||||
}
|
||||
}
|
||||
MediaCapabilitiesDecodingInfo info;
|
||||
info.mSupported = true;
|
||||
info.mSmooth = smooth;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PContent;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
[ManualDealloc]
|
||||
async protocol PBenchmarkStorage
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
async Put(nsCString aDbName, nsCString aKey, int32_t aValue);
|
||||
async Get(nsCString aDbName, nsCString aKey) returns(int32_t aValue);
|
||||
async CheckVersion(nsCString aDbName, int32_t aVersion);
|
||||
async __delete__();
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -7,26 +7,10 @@ EXPORTS.mozilla.dom += [
|
||||
"MediaCapabilities.h",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"BenchmarkStorageChild.h",
|
||||
"BenchmarkStorageParent.h",
|
||||
"KeyValueStorage.h",
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
"DecoderBenchmark.h",
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"BenchmarkStorageChild.cpp",
|
||||
"BenchmarkStorageParent.cpp",
|
||||
"DecoderBenchmark.cpp",
|
||||
"KeyValueStorage.cpp",
|
||||
"MediaCapabilities.cpp",
|
||||
]
|
||||
|
||||
IPDL_SOURCES += ["PBenchmarkStorage.ipdl"]
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "MediaSource.h"
|
||||
|
||||
#include "AsyncEventRunner.h"
|
||||
#include "Benchmark.h"
|
||||
#include "DecoderDoctorDiagnostics.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "MP4Decoder.h"
|
||||
@@ -80,10 +79,10 @@ static bool IsVP9Forced(DecoderDoctorDiagnostics* aDiagnostics) {
|
||||
MediaContainerType(MEDIAMIMETYPE(VIDEO_MP4)), aDiagnostics);
|
||||
bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast() ||
|
||||
return !mp4supported || !hwsupported ||
|
||||
java::HardwareCodecCapabilityUtils::HasHWVP9(false /* aIsEncoder */);
|
||||
#else
|
||||
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast();
|
||||
return !mp4supported || !hwsupported;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,6 @@ EXPORTS += [
|
||||
"AudioSegment.h",
|
||||
"AudioStream.h",
|
||||
"BackgroundVideoDecodingPermissionObserver.h",
|
||||
"Benchmark.h",
|
||||
"BitReader.h",
|
||||
"BitWriter.h",
|
||||
"BufferMediaResource.h",
|
||||
@@ -263,7 +262,6 @@ UNIFIED_SOURCES += [
|
||||
"AudioTrackList.cpp",
|
||||
"BackgroundVideoDecodingPermissionObserver.cpp",
|
||||
"BaseMediaResource.cpp",
|
||||
"Benchmark.cpp",
|
||||
"BitReader.cpp",
|
||||
"BitWriter.cpp",
|
||||
"CallbackThreadRegistry.cpp",
|
||||
|
||||
Reference in New Issue
Block a user