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/AppShutdown.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/BackgroundHangMonitor.h"
|
#include "mozilla/BackgroundHangMonitor.h"
|
||||||
#include "mozilla/BenchmarkStorageChild.h"
|
|
||||||
#include "mozilla/FOGIPC.h"
|
#include "mozilla/FOGIPC.h"
|
||||||
#include "GMPServiceChild.h"
|
#include "GMPServiceChild.h"
|
||||||
#include "Geolocation.h"
|
#include "Geolocation.h"
|
||||||
@@ -2008,16 +2007,6 @@ bool ContentChild::DeallocPMediaChild(media::PMediaChild* aActor) {
|
|||||||
return media::DeallocPMediaChild(aActor);
|
return media::DeallocPMediaChild(aActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
PBenchmarkStorageChild* ContentChild::AllocPBenchmarkStorageChild() {
|
|
||||||
return BenchmarkStorageChild::Instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContentChild::DeallocPBenchmarkStorageChild(
|
|
||||||
PBenchmarkStorageChild* aActor) {
|
|
||||||
delete aActor;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_WEBRTC
|
#ifdef MOZ_WEBRTC
|
||||||
PWebrtcGlobalChild* ContentChild::AllocPWebrtcGlobalChild() {
|
PWebrtcGlobalChild* ContentChild::AllocPWebrtcGlobalChild() {
|
||||||
auto* child = new WebrtcGlobalChild();
|
auto* child = new WebrtcGlobalChild();
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ class nsIOpenWindowInfo;
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
class RemoteSpellcheckEngineChild;
|
class RemoteSpellcheckEngineChild;
|
||||||
class ChildProfilerController;
|
class ChildProfilerController;
|
||||||
class BenchmarkStorageChild;
|
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
class UntypedEndpoint;
|
class UntypedEndpoint;
|
||||||
@@ -232,10 +231,6 @@ class ContentChild final : public PContentChild,
|
|||||||
|
|
||||||
bool DeallocPMediaChild(PMediaChild* aActor);
|
bool DeallocPMediaChild(PMediaChild* aActor);
|
||||||
|
|
||||||
PBenchmarkStorageChild* AllocPBenchmarkStorageChild();
|
|
||||||
|
|
||||||
bool DeallocPBenchmarkStorageChild(PBenchmarkStorageChild* aActor);
|
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvNotifyEmptyHTTPCache();
|
mozilla::ipc::IPCResult RecvNotifyEmptyHTTPCache();
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvRegisterChrome(
|
mozilla::ipc::IPCResult RecvRegisterChrome(
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
#include "mozilla/AutoRestore.h"
|
#include "mozilla/AutoRestore.h"
|
||||||
#include "mozilla/ClipboardContentAnalysisParent.h"
|
#include "mozilla/ClipboardContentAnalysisParent.h"
|
||||||
#include "mozilla/BasePrincipal.h"
|
#include "mozilla/BasePrincipal.h"
|
||||||
#include "mozilla/BenchmarkStorageParent.h"
|
|
||||||
#include "mozilla/Casting.h"
|
#include "mozilla/Casting.h"
|
||||||
#include "mozilla/ClearOnShutdown.h"
|
#include "mozilla/ClearOnShutdown.h"
|
||||||
#include "mozilla/ClipboardReadRequestParent.h"
|
#include "mozilla/ClipboardReadRequestParent.h"
|
||||||
@@ -328,9 +327,6 @@
|
|||||||
# include "nsIRemoteAgent.h"
|
# include "nsIRemoteAgent.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For VP9Benchmark::sBenchmarkFpsPref
|
|
||||||
#include "Benchmark.h"
|
|
||||||
|
|
||||||
#include "mozilla/RemoteDecodeUtils.h"
|
#include "mozilla/RemoteDecodeUtils.h"
|
||||||
#include "nsIToolkitProfileService.h"
|
#include "nsIToolkitProfileService.h"
|
||||||
#include "nsIToolkitProfile.h"
|
#include "nsIToolkitProfile.h"
|
||||||
@@ -4445,16 +4441,6 @@ bool ContentParent::DeallocPMediaParent(media::PMediaParent* aActor) {
|
|||||||
return media::DeallocPMediaParent(aActor);
|
return media::DeallocPMediaParent(aActor);
|
||||||
}
|
}
|
||||||
|
|
||||||
PBenchmarkStorageParent* ContentParent::AllocPBenchmarkStorageParent() {
|
|
||||||
return new BenchmarkStorageParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ContentParent::DeallocPBenchmarkStorageParent(
|
|
||||||
PBenchmarkStorageParent* aActor) {
|
|
||||||
delete aActor;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MOZ_WEBSPEECH
|
#ifdef MOZ_WEBSPEECH
|
||||||
already_AddRefed<PSpeechSynthesisParent>
|
already_AddRefed<PSpeechSynthesisParent>
|
||||||
ContentParent::AllocPSpeechSynthesisParent() {
|
ContentParent::AllocPSpeechSynthesisParent() {
|
||||||
@@ -5621,18 +5607,6 @@ mozilla::ipc::IPCResult ContentParent::RecvEndDriverCrashGuard(
|
|||||||
return IPC_OK();
|
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(
|
mozilla::ipc::IPCResult ContentParent::RecvNotifyPushObservers(
|
||||||
const nsACString& aScope, nsIPrincipal* aPrincipal,
|
const nsACString& aScope, nsIPrincipal* aPrincipal,
|
||||||
const nsAString& aMessageId) {
|
const nsAString& aMessageId) {
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ class SandboxBrokerPolicyFactory;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
class PreallocatedProcessManagerImpl;
|
class PreallocatedProcessManagerImpl;
|
||||||
class BenchmarkStorageParent;
|
|
||||||
|
|
||||||
using mozilla::loader::PScriptCacheParent;
|
using mozilla::loader::PScriptCacheParent;
|
||||||
|
|
||||||
@@ -951,10 +950,6 @@ class ContentParent final : public PContentParent,
|
|||||||
|
|
||||||
bool DeallocPMediaParent(PMediaParent* aActor);
|
bool DeallocPMediaParent(PMediaParent* aActor);
|
||||||
|
|
||||||
PBenchmarkStorageParent* AllocPBenchmarkStorageParent();
|
|
||||||
|
|
||||||
bool DeallocPBenchmarkStorageParent(PBenchmarkStorageParent* aActor);
|
|
||||||
|
|
||||||
#ifdef MOZ_WEBSPEECH
|
#ifdef MOZ_WEBSPEECH
|
||||||
already_AddRefed<PSpeechSynthesisParent> AllocPSpeechSynthesisParent();
|
already_AddRefed<PSpeechSynthesisParent> AllocPSpeechSynthesisParent();
|
||||||
|
|
||||||
@@ -1152,9 +1147,6 @@ class ContentParent final : public PContentParent,
|
|||||||
mozilla::ipc::IPCResult RecvGetHyphDict(
|
mozilla::ipc::IPCResult RecvGetHyphDict(
|
||||||
nsIURI* aURIParams, mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle);
|
nsIURI* aURIParams, mozilla::ipc::ReadOnlySharedMemoryHandle* aOutHandle);
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvNotifyBenchmarkResult(const nsAString& aCodecName,
|
|
||||||
const uint32_t& aDecodeFPS);
|
|
||||||
|
|
||||||
mozilla::ipc::IPCResult RecvNotifyPushObservers(const nsACString& aScope,
|
mozilla::ipc::IPCResult RecvNotifyPushObservers(const nsACString& aScope,
|
||||||
nsIPrincipal* aPrincipal,
|
nsIPrincipal* aPrincipal,
|
||||||
const nsAString& aMessageId);
|
const nsAString& aMessageId);
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ include protocol PRemoteWorkerService;
|
|||||||
include protocol PProfiler;
|
include protocol PProfiler;
|
||||||
include protocol PScriptCache;
|
include protocol PScriptCache;
|
||||||
include protocol PSessionStorageObserver;
|
include protocol PSessionStorageObserver;
|
||||||
include protocol PBenchmarkStorage;
|
|
||||||
include CrashReporterInitArgs;
|
include CrashReporterInitArgs;
|
||||||
include DOMTypes;
|
include DOMTypes;
|
||||||
include WindowGlobalTypes;
|
include WindowGlobalTypes;
|
||||||
@@ -508,7 +507,6 @@ sync protocol PContent
|
|||||||
manages PURLClassifierLocalByName;
|
manages PURLClassifierLocalByName;
|
||||||
manages PScriptCache;
|
manages PScriptCache;
|
||||||
manages PSessionStorageObserver;
|
manages PSessionStorageObserver;
|
||||||
manages PBenchmarkStorage;
|
|
||||||
|
|
||||||
// Depending on exactly how the new browser is being created, it might be
|
// Depending on exactly how the new browser is being created, it might be
|
||||||
// created from either the child or parent process!
|
// created from either the child or parent process!
|
||||||
@@ -1135,8 +1133,6 @@ parent:
|
|||||||
|
|
||||||
async PSessionStorageObserver();
|
async PSessionStorageObserver();
|
||||||
|
|
||||||
async PBenchmarkStorage();
|
|
||||||
|
|
||||||
// Services remoting
|
// Services remoting
|
||||||
|
|
||||||
async StartVisitedQueries(nullable nsIURI[] uri);
|
async StartVisitedQueries(nullable nsIURI[] uri);
|
||||||
@@ -1550,12 +1546,6 @@ parent:
|
|||||||
bool aUserActivation,
|
bool aUserActivation,
|
||||||
bool aTextDirectiveUserActivation);
|
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.
|
* 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 "AudioDeviceInfo.h"
|
||||||
#include "DOMMediaStream.h"
|
#include "DOMMediaStream.h"
|
||||||
#include "DecoderBenchmark.h"
|
|
||||||
#include "ImageContainer.h"
|
#include "ImageContainer.h"
|
||||||
#include "MediaDecoderStateMachineBase.h"
|
#include "MediaDecoderStateMachineBase.h"
|
||||||
#include "MediaFormatReader.h"
|
#include "MediaFormatReader.h"
|
||||||
@@ -239,7 +238,6 @@ MediaDecoder::MediaDecoder(MediaDecoderInit& aInit)
|
|||||||
mOwner(aInit.mOwner),
|
mOwner(aInit.mOwner),
|
||||||
mAbstractMainThread(aInit.mOwner->AbstractMainThread()),
|
mAbstractMainThread(aInit.mOwner->AbstractMainThread()),
|
||||||
mFrameStats(new FrameStatistics()),
|
mFrameStats(new FrameStatistics()),
|
||||||
mDecoderBenchmark(new DecoderBenchmark()),
|
|
||||||
mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer()),
|
mVideoFrameContainer(aInit.mOwner->GetVideoFrameContainer()),
|
||||||
mMinimizePreroll(aInit.mMinimizePreroll),
|
mMinimizePreroll(aInit.mMinimizePreroll),
|
||||||
mFiredMetadataLoaded(false),
|
mFiredMetadataLoaded(false),
|
||||||
@@ -546,29 +544,6 @@ void MediaDecoder::OnSecondaryVideoContainerInstalled(
|
|||||||
GetOwner()->OnSecondaryVideoContainerInstalled(aSecondaryVideoContainer);
|
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() {
|
void MediaDecoder::ShutdownInternal() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
mVideoFrameContainer = nullptr;
|
mVideoFrameContainer = nullptr;
|
||||||
@@ -630,9 +605,6 @@ void MediaDecoder::SetStateMachineParameters() {
|
|||||||
mDecoderStateMachine->OnSecondaryVideoContainerInstalled().Connect(
|
mDecoderStateMachine->OnSecondaryVideoContainerInstalled().Connect(
|
||||||
mAbstractMainThread, this,
|
mAbstractMainThread, this,
|
||||||
&MediaDecoder::OnSecondaryVideoContainerInstalled);
|
&MediaDecoder::OnSecondaryVideoContainerInstalled);
|
||||||
mOnStoreDecoderBenchmark = mReader->OnStoreDecoderBenchmark().Connect(
|
|
||||||
mAbstractMainThread, this, &MediaDecoder::OnStoreDecoderBenchmark);
|
|
||||||
|
|
||||||
mOnEncrypted = mReader->OnEncrypted().Connect(
|
mOnEncrypted = mReader->OnEncrypted().Connect(
|
||||||
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::DispatchEncrypted);
|
mAbstractMainThread, GetOwner(), &MediaDecoderOwner::DispatchEncrypted);
|
||||||
mOnWaitingForKey = mReader->OnWaitingForKey().Connect(
|
mOnWaitingForKey = mReader->OnWaitingForKey().Connect(
|
||||||
@@ -656,7 +628,6 @@ void MediaDecoder::DisconnectEvents() {
|
|||||||
mOnNextFrameStatus.Disconnect();
|
mOnNextFrameStatus.Disconnect();
|
||||||
mOnTrackInfoUpdated.Disconnect();
|
mOnTrackInfoUpdated.Disconnect();
|
||||||
mOnSecondaryVideoContainerInstalled.Disconnect();
|
mOnSecondaryVideoContainerInstalled.Disconnect();
|
||||||
mOnStoreDecoderBenchmark.Disconnect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ShutdownPromise> MediaDecoder::ShutdownStateMachine() {
|
RefPtr<ShutdownPromise> MediaDecoder::ShutdownStateMachine() {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ namespace mozilla {
|
|||||||
|
|
||||||
class AbstractThread;
|
class AbstractThread;
|
||||||
class DOMMediaStream;
|
class DOMMediaStream;
|
||||||
class DecoderBenchmark;
|
|
||||||
class ProcessedMediaTrack;
|
class ProcessedMediaTrack;
|
||||||
class FrameStatistics;
|
class FrameStatistics;
|
||||||
class VideoFrameContainer;
|
class VideoFrameContainer;
|
||||||
@@ -562,8 +561,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
|||||||
void OnSecondaryVideoContainerInstalled(
|
void OnSecondaryVideoContainerInstalled(
|
||||||
const RefPtr<VideoFrameContainer>& aSecondaryVideoContainer);
|
const RefPtr<VideoFrameContainer>& aSecondaryVideoContainer);
|
||||||
|
|
||||||
void OnStoreDecoderBenchmark(const VideoInfo& aInfo);
|
|
||||||
|
|
||||||
void FinishShutdown();
|
void FinishShutdown();
|
||||||
|
|
||||||
void ConnectMirrors(MediaDecoderStateMachineBase* aObject);
|
void ConnectMirrors(MediaDecoderStateMachineBase* aObject);
|
||||||
@@ -607,9 +604,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
|||||||
// Counters related to decode and presentation of frames.
|
// Counters related to decode and presentation of frames.
|
||||||
const RefPtr<FrameStatistics> mFrameStats;
|
const RefPtr<FrameStatistics> mFrameStats;
|
||||||
|
|
||||||
// Store a benchmark of the decoder based on FrameStatistics.
|
|
||||||
RefPtr<DecoderBenchmark> mDecoderBenchmark;
|
|
||||||
|
|
||||||
RefPtr<VideoFrameContainer> mVideoFrameContainer;
|
RefPtr<VideoFrameContainer> mVideoFrameContainer;
|
||||||
|
|
||||||
// True if the decoder has been directed to minimize its preroll before
|
// True if the decoder has been directed to minimize its preroll before
|
||||||
@@ -674,7 +668,6 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
|||||||
MediaEventListener mOnNextFrameStatus;
|
MediaEventListener mOnNextFrameStatus;
|
||||||
MediaEventListener mOnTrackInfoUpdated;
|
MediaEventListener mOnTrackInfoUpdated;
|
||||||
MediaEventListener mOnSecondaryVideoContainerInstalled;
|
MediaEventListener mOnSecondaryVideoContainerInstalled;
|
||||||
MediaEventListener mOnStoreDecoderBenchmark;
|
|
||||||
|
|
||||||
// True if we have suspended video decoding.
|
// True if we have suspended video decoding.
|
||||||
bool mIsVideoDecodingSuspended = false;
|
bool mIsVideoDecodingSuspended = false;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#ifdef MOZ_AV1
|
#ifdef MOZ_AV1
|
||||||
# include "AOMDecoder.h"
|
# include "AOMDecoder.h"
|
||||||
#endif
|
#endif
|
||||||
#include "DecoderBenchmark.h"
|
|
||||||
#include "MediaData.h"
|
#include "MediaData.h"
|
||||||
#include "MediaDataDecoderProxy.h"
|
#include "MediaDataDecoderProxy.h"
|
||||||
#include "MediaInfo.h"
|
#include "MediaInfo.h"
|
||||||
@@ -483,10 +482,6 @@ void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {
|
|||||||
ownerData.mDecoder.get());
|
ownerData.mDecoder.get());
|
||||||
mOwner->SetVideoDecodeThreshold();
|
mOwner->SetVideoDecodeThreshold();
|
||||||
mOwner->ScheduleUpdate(aTrack);
|
mOwner->ScheduleUpdate(aTrack);
|
||||||
if (aTrack == TrackInfo::kVideoTrack) {
|
|
||||||
DecoderBenchmark::CheckVersion(
|
|
||||||
ownerData.GetCurrentInfo()->mMimeType);
|
|
||||||
}
|
|
||||||
if (aTrack == TrackInfo::kAudioTrack) {
|
if (aTrack == TrackInfo::kAudioTrack) {
|
||||||
ownerData.mProcessName = ownerData.mDecoder->GetProcessName();
|
ownerData.mProcessName = ownerData.mDecoder->GetProcessName();
|
||||||
ownerData.mCodecName = ownerData.mDecoder->GetCodecName();
|
ownerData.mCodecName = ownerData.mDecoder->GetCodecName();
|
||||||
@@ -1021,19 +1016,6 @@ void MediaFormatReader::ShutdownDecoder(TrackType aTrack) {
|
|||||||
decoder.ShutdownDecoder();
|
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() {
|
void MediaFormatReader::NotifyTrackInfoUpdated() {
|
||||||
MOZ_ASSERT(OnTaskQueue());
|
MOZ_ASSERT(OnTaskQueue());
|
||||||
if (mWorkingInfoChanged) {
|
if (mWorkingInfoChanged) {
|
||||||
@@ -2200,11 +2182,6 @@ void MediaFormatReader::HandleDemuxedSamples(
|
|||||||
PROFILER_MARKER_TEXT("StreamID Change", MEDIA_PLAYBACK, {}, markerString);
|
PROFILER_MARKER_TEXT("StreamID Change", MEDIA_PLAYBACK, {}, markerString);
|
||||||
LOG("%s", markerString.get());
|
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.mNextStreamSourceID.reset();
|
||||||
decoder.mLastStreamSourceID = info->GetID();
|
decoder.mLastStreamSourceID = info->GetID();
|
||||||
decoder.mInfo = info;
|
decoder.mInfo = info;
|
||||||
@@ -2500,10 +2477,6 @@ void MediaFormatReader::Update(TrackType aTrack) {
|
|||||||
} else if (decoder.HasCompletedDrain()) {
|
} else if (decoder.HasCompletedDrain()) {
|
||||||
if (decoder.mDemuxEOS) {
|
if (decoder.mDemuxEOS) {
|
||||||
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
|
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__);
|
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
|
||||||
} else if (decoder.mWaitingForDataStartTime) {
|
} else if (decoder.mWaitingForDataStartTime) {
|
||||||
if (decoder.mDrainState == DrainState::DrainCompleted &&
|
if (decoder.mDrainState == DrainState::DrainCompleted &&
|
||||||
|
|||||||
@@ -250,10 +250,6 @@ class MediaFormatReader final
|
|||||||
|
|
||||||
MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
|
MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
|
||||||
|
|
||||||
MediaEventSource<VideoInfo>& OnStoreDecoderBenchmark() {
|
|
||||||
return mOnStoreDecoderBenchmark;
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() {
|
MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() {
|
||||||
return mTrackInfoUpdatedEvent;
|
return mTrackInfoUpdatedEvent;
|
||||||
}
|
}
|
||||||
@@ -346,11 +342,6 @@ class MediaFormatReader final
|
|||||||
|
|
||||||
size_t SizeOfQueue(TrackType aTrack);
|
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();
|
void NotifyTrackInfoUpdated();
|
||||||
|
|
||||||
enum class DrainState {
|
enum class DrainState {
|
||||||
@@ -879,8 +870,6 @@ class MediaFormatReader final
|
|||||||
|
|
||||||
MediaEventProducer<MediaResult> mOnDecodeWarning;
|
MediaEventProducer<MediaResult> mOnDecodeWarning;
|
||||||
|
|
||||||
MediaEventProducer<VideoInfo> mOnStoreDecoderBenchmark;
|
|
||||||
|
|
||||||
MediaEventProducer<VideoInfo, AudioInfo> mTrackInfoUpdatedEvent;
|
MediaEventProducer<VideoInfo, AudioInfo> mTrackInfoUpdatedEvent;
|
||||||
|
|
||||||
RefPtr<FrameStatistics> mFrameStats;
|
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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "ADTSDemuxer.h"
|
#include "ADTSDemuxer.h"
|
||||||
#include "Benchmark.h"
|
|
||||||
#include "BufferMediaResource.h"
|
#include "BufferMediaResource.h"
|
||||||
#include "FlacDemuxer.h"
|
#include "FlacDemuxer.h"
|
||||||
#include "FuzzingInterface.h"
|
#include "FuzzingInterface.h"
|
||||||
@@ -16,9 +15,96 @@
|
|||||||
#include "systemservices/MediaUtils.h"
|
#include "systemservices/MediaUtils.h"
|
||||||
#include "WaveDemuxer.h"
|
#include "WaveDemuxer.h"
|
||||||
#include "WebMDemuxer.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;
|
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 {
|
class FuzzRunner {
|
||||||
public:
|
public:
|
||||||
explicit FuzzRunner(Benchmark* aBenchmark) : mBenchmark(aBenchmark) {}
|
explicit FuzzRunner(Benchmark* aBenchmark) : mBenchmark(aBenchmark) {}
|
||||||
@@ -28,7 +114,7 @@ class FuzzRunner {
|
|||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
mBenchmark->Init();
|
Benchmark::Init();
|
||||||
mBenchmark->Run()->Then(
|
mBenchmark->Run()->Then(
|
||||||
// Non DocGroup-version of AbstractThread::MainThread() is fine for
|
// Non DocGroup-version of AbstractThread::MainThread() is fine for
|
||||||
// testing.
|
// testing.
|
||||||
@@ -37,13 +123,279 @@ class FuzzRunner {
|
|||||||
|
|
||||||
// Wait until benchmark completes.
|
// Wait until benchmark completes.
|
||||||
SpinEventLoopUntil("FuzzRunner::Run"_ns, [&]() { return done; });
|
SpinEventLoopUntil("FuzzRunner::Run"_ns, [&]() { return done; });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RefPtr<Benchmark> mBenchmark;
|
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) \
|
#define MOZ_MEDIA_FUZZER(_name) \
|
||||||
static int FuzzingRunMedia##_name(const uint8_t* data, size_t size) { \
|
static int FuzzingRunMedia##_name(const uint8_t* data, size_t size) { \
|
||||||
if (!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",
|
"TestAudioSinkWrapper.cpp",
|
||||||
"TestAudioTrackEncoder.cpp",
|
"TestAudioTrackEncoder.cpp",
|
||||||
"TestAudioTrackGraph.cpp",
|
"TestAudioTrackGraph.cpp",
|
||||||
"TestBenchmarkStorage.cpp",
|
|
||||||
"TestBitWriter.cpp",
|
"TestBitWriter.cpp",
|
||||||
"TestBlankVideoDataCreator.cpp",
|
"TestBlankVideoDataCreator.cpp",
|
||||||
"TestBufferReader.cpp",
|
"TestBufferReader.cpp",
|
||||||
"TestCubebInputStream.cpp",
|
"TestCubebInputStream.cpp",
|
||||||
"TestDataMutex.cpp",
|
"TestDataMutex.cpp",
|
||||||
"TestDecoderBenchmark.cpp",
|
|
||||||
"TestDeviceInputTrack.cpp",
|
"TestDeviceInputTrack.cpp",
|
||||||
"TestDriftCompensation.cpp",
|
"TestDriftCompensation.cpp",
|
||||||
"TestGMPUtils.cpp",
|
"TestGMPUtils.cpp",
|
||||||
"TestGroupId.cpp",
|
"TestGroupId.cpp",
|
||||||
"TestImageConversion.cpp",
|
"TestImageConversion.cpp",
|
||||||
"TestIntervalSet.cpp",
|
"TestIntervalSet.cpp",
|
||||||
"TestKeyValueStorage.cpp",
|
|
||||||
"TestMediaCodecsSupport.cpp",
|
"TestMediaCodecsSupport.cpp",
|
||||||
"TestMediaDataDecoder.cpp",
|
|
||||||
"TestMediaDataEncoder.cpp",
|
"TestMediaDataEncoder.cpp",
|
||||||
"TestMediaEventSource.cpp",
|
"TestMediaEventSource.cpp",
|
||||||
"TestMediaInfo.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 <utility>
|
||||||
|
|
||||||
#include "AllocationPolicy.h"
|
#include "AllocationPolicy.h"
|
||||||
#include "Benchmark.h"
|
|
||||||
#include "DecoderBenchmark.h"
|
|
||||||
#include "DecoderTraits.h"
|
#include "DecoderTraits.h"
|
||||||
#include "MediaInfo.h"
|
#include "MediaInfo.h"
|
||||||
#include "MediaRecorder.h"
|
#include "MediaRecorder.h"
|
||||||
@@ -463,7 +461,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
|||||||
return AllocationWrapper::CreateDecoder(params, sVideoAllocPolicy)
|
return AllocationWrapper::CreateDecoder(params, sVideoAllocPolicy)
|
||||||
->Then(
|
->Then(
|
||||||
taskQueue, __func__,
|
taskQueue, __func__,
|
||||||
[taskQueue, frameRate, shouldResistFingerprinting,
|
[taskQueue, shouldResistFingerprinting,
|
||||||
config = std::move(config)](
|
config = std::move(config)](
|
||||||
AllocationWrapper::AllocateDecoderPromise::
|
AllocationWrapper::AllocateDecoderPromise::
|
||||||
ResolveOrRejectValue&& aValue) mutable {
|
ResolveOrRejectValue&& aValue) mutable {
|
||||||
@@ -477,7 +475,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
|||||||
// efficient.
|
// efficient.
|
||||||
RefPtr<CapabilitiesPromise> p = decoder->Init()->Then(
|
RefPtr<CapabilitiesPromise> p = decoder->Init()->Then(
|
||||||
taskQueue, __func__,
|
taskQueue, __func__,
|
||||||
[taskQueue, decoder, frameRate,
|
[taskQueue, decoder,
|
||||||
shouldResistFingerprinting,
|
shouldResistFingerprinting,
|
||||||
config = std::move(config)](
|
config = std::move(config)](
|
||||||
MediaDataDecoder::InitPromise::
|
MediaDataDecoder::InitPromise::
|
||||||
@@ -494,39 +492,7 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
|||||||
p = CapabilitiesPromise::CreateAndResolve(std::move(info), __func__);
|
p = CapabilitiesPromise::CreateAndResolve(std::move(info), __func__);
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(config->IsVideo());
|
MOZ_ASSERT(config->IsVideo());
|
||||||
if (StaticPrefs::media_mediacapabilities_from_database()) {
|
if (config->GetAsVideoInfo()->mImage.height < 480) {
|
||||||
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) {
|
|
||||||
// Assume that we can do stuff at 480p or less in
|
// Assume that we can do stuff at 480p or less in
|
||||||
// a power efficient manner and smoothly. If
|
// a power efficient manner and smoothly. If
|
||||||
// greater than 480p we assume that if the video
|
// greater than 480p we assume that if the video
|
||||||
@@ -543,28 +509,6 @@ void MediaCapabilities::CreateMediaCapabilitiesDecodingInfo(
|
|||||||
bool smooth = true;
|
bool smooth = true;
|
||||||
bool powerEfficient =
|
bool powerEfficient =
|
||||||
decoder->IsHardwareAccelerated(reason);
|
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;
|
MediaCapabilitiesDecodingInfo info;
|
||||||
info.mSupported = true;
|
info.mSupported = true;
|
||||||
info.mSmooth = smooth;
|
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",
|
"MediaCapabilities.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
EXPORTS.mozilla += [
|
|
||||||
"BenchmarkStorageChild.h",
|
|
||||||
"BenchmarkStorageParent.h",
|
|
||||||
"KeyValueStorage.h",
|
|
||||||
]
|
|
||||||
|
|
||||||
EXPORTS += [
|
|
||||||
"DecoderBenchmark.h",
|
|
||||||
]
|
|
||||||
|
|
||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
"BenchmarkStorageChild.cpp",
|
|
||||||
"BenchmarkStorageParent.cpp",
|
|
||||||
"DecoderBenchmark.cpp",
|
|
||||||
"KeyValueStorage.cpp",
|
|
||||||
"MediaCapabilities.cpp",
|
"MediaCapabilities.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
IPDL_SOURCES += ["PBenchmarkStorage.ipdl"]
|
|
||||||
|
|
||||||
include("/ipc/chromium/chromium-config.mozbuild")
|
include("/ipc/chromium/chromium-config.mozbuild")
|
||||||
|
|
||||||
FINAL_LIBRARY = "xul"
|
FINAL_LIBRARY = "xul"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "MediaSource.h"
|
#include "MediaSource.h"
|
||||||
|
|
||||||
#include "AsyncEventRunner.h"
|
#include "AsyncEventRunner.h"
|
||||||
#include "Benchmark.h"
|
|
||||||
#include "DecoderDoctorDiagnostics.h"
|
#include "DecoderDoctorDiagnostics.h"
|
||||||
#include "DecoderTraits.h"
|
#include "DecoderTraits.h"
|
||||||
#include "MP4Decoder.h"
|
#include "MP4Decoder.h"
|
||||||
@@ -80,10 +79,10 @@ static bool IsVP9Forced(DecoderDoctorDiagnostics* aDiagnostics) {
|
|||||||
MediaContainerType(MEDIAMIMETYPE(VIDEO_MP4)), aDiagnostics);
|
MediaContainerType(MEDIAMIMETYPE(VIDEO_MP4)), aDiagnostics);
|
||||||
bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
|
bool hwsupported = gfx::gfxVars::CanUseHardwareVideoDecoding();
|
||||||
#ifdef MOZ_WIDGET_ANDROID
|
#ifdef MOZ_WIDGET_ANDROID
|
||||||
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast() ||
|
return !mp4supported || !hwsupported ||
|
||||||
java::HardwareCodecCapabilityUtils::HasHWVP9(false /* aIsEncoder */);
|
java::HardwareCodecCapabilityUtils::HasHWVP9(false /* aIsEncoder */);
|
||||||
#else
|
#else
|
||||||
return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast();
|
return !mp4supported || !hwsupported;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ EXPORTS += [
|
|||||||
"AudioSegment.h",
|
"AudioSegment.h",
|
||||||
"AudioStream.h",
|
"AudioStream.h",
|
||||||
"BackgroundVideoDecodingPermissionObserver.h",
|
"BackgroundVideoDecodingPermissionObserver.h",
|
||||||
"Benchmark.h",
|
|
||||||
"BitReader.h",
|
"BitReader.h",
|
||||||
"BitWriter.h",
|
"BitWriter.h",
|
||||||
"BufferMediaResource.h",
|
"BufferMediaResource.h",
|
||||||
@@ -263,7 +262,6 @@ UNIFIED_SOURCES += [
|
|||||||
"AudioTrackList.cpp",
|
"AudioTrackList.cpp",
|
||||||
"BackgroundVideoDecodingPermissionObserver.cpp",
|
"BackgroundVideoDecodingPermissionObserver.cpp",
|
||||||
"BaseMediaResource.cpp",
|
"BaseMediaResource.cpp",
|
||||||
"Benchmark.cpp",
|
|
||||||
"BitReader.cpp",
|
"BitReader.cpp",
|
||||||
"BitWriter.cpp",
|
"BitWriter.cpp",
|
||||||
"CallbackThreadRegistry.cpp",
|
"CallbackThreadRegistry.cpp",
|
||||||
|
|||||||
Reference in New Issue
Block a user