Bug 1934014 - Remove decoder benchmark machinery. r=media-playback-reviewers,aosmond

Differential Revision: https://phabricator.services.mozilla.com/D230546
This commit is contained in:
Paul Adenot
2025-04-23 11:15:34 +00:00
parent f850fbdb19
commit 162c218f45
30 changed files with 360 additions and 24472 deletions

View File

@@ -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();

View File

@@ -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(

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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 &&

View File

@@ -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;

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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) { \

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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",