2016-03-03 05:57:11 +03:00
|
|
|
/* -*- 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"
|
2016-03-09 07:34:50 +03:00
|
|
|
#include "BufferMediaResource.h"
|
|
|
|
#include "MediaData.h"
|
2016-05-12 11:54:35 +03:00
|
|
|
#include "MediaPrefs.h"
|
2016-03-03 05:57:11 +03:00
|
|
|
#include "PDMFactory.h"
|
|
|
|
#include "WebMDemuxer.h"
|
2017-01-31 22:43:07 +03:00
|
|
|
#include "gfxPrefs.h"
|
2016-11-29 08:03:36 +03:00
|
|
|
#include "mozilla/AbstractThread.h"
|
2016-03-03 05:57:11 +03:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-03-03 06:23:19 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2016-03-17 09:20:21 +03:00
|
|
|
#include "mozilla/dom/ContentChild.h"
|
2017-01-31 22:43:07 +03:00
|
|
|
#include "mozilla/gfx/gfxVars.h"
|
2016-03-03 05:57:11 +03:00
|
|
|
|
2017-01-26 03:59:20 +03:00
|
|
|
#ifndef MOZ_WIDGET_ANDROID
|
|
|
|
#include "WebMSample.h"
|
|
|
|
#endif
|
|
|
|
|
2016-03-03 05:57:11 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
2016-04-13 05:44:29 +03:00
|
|
|
// Update this version number to force re-running the benchmark. Such as when
|
|
|
|
// an improvement to FFVP9 or LIBVPX is deemed worthwhile.
|
2016-11-22 09:26:57 +03:00
|
|
|
const uint32_t VP9Benchmark::sBenchmarkVersionID = 2;
|
2016-04-13 05:44:29 +03:00
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
const char* VP9Benchmark::sBenchmarkFpsPref = "media.benchmark.vp9.fps";
|
2016-04-13 05:44:29 +03:00
|
|
|
const char* VP9Benchmark::sBenchmarkFpsVersionCheck = "media.benchmark.vp9.versioncheck";
|
2016-03-09 07:34:50 +03:00
|
|
|
bool VP9Benchmark::sHasRunTest = false;
|
2016-03-03 05:57:11 +03:00
|
|
|
|
2016-04-19 10:36:19 +03:00
|
|
|
// static
|
2016-03-03 05:57:11 +03:00
|
|
|
bool
|
2016-03-09 07:34:50 +03:00
|
|
|
VP9Benchmark::IsVP9DecodeFast()
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
|
2016-04-20 18:09:49 +03:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
2016-10-26 12:08:21 +03:00
|
|
|
return false;
|
2016-04-20 18:09:49 +03:00
|
|
|
#else
|
2016-03-09 07:34:50 +03:00
|
|
|
bool hasPref = Preferences::HasUserValue(sBenchmarkFpsPref);
|
2016-04-13 05:44:29 +03:00
|
|
|
uint32_t hadRecentUpdate = Preferences::GetUint(sBenchmarkFpsVersionCheck, 0U);
|
2016-03-09 07:34:50 +03:00
|
|
|
|
2016-04-13 05:44:29 +03:00
|
|
|
if (!sHasRunTest && (!hasPref || hadRecentUpdate != sBenchmarkVersionID)) {
|
2016-03-03 05:57:11 +03:00
|
|
|
sHasRunTest = true;
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<WebMDemuxer> demuxer =
|
Bug 1331289 - Use MediaContainerType in MediaResource, SourceBuffer, TrackBuffersManager, and dependencies - r=jya
Continuing the work of replacing MIME strings with MediaContainerType, starting
from MediaResource and following the dependencies.
Most changes are mechanical: Just change ns*String into MediaContainerType, and
MIME string literals into MEDIAMIMETYPE("a/b").
Some checks for empty/invalid strings and lowercase comparisons can go, thanks
to the always-valid always-lowercase-MIME invariants of MediaContainerType.
One special case in is MediaSourceResource, which used to have an empty string
as its type (because its own type is not relevant, but its SourceBuffers carry
types). Because the inherited GetContentType *must* be overridden, and must
return a MediaContainerType, we needed a valid type even though it should not
be seen in the real world. I've chosen "application/x.mediasource" for that.
MozReview-Commit-ID: 1aCH75Kh2e6
--HG--
extra : rebase_source : 0d9cd9b69c264e5dcfc3845f80ee107f4bcbcd9a
2016-12-28 10:59:02 +03:00
|
|
|
new WebMDemuxer(
|
2017-01-26 03:59:20 +03:00
|
|
|
new BufferMediaResource(sWebMSample, sizeof(sWebMSample), nullptr,
|
Bug 1331289 - Use MediaContainerType in MediaResource, SourceBuffer, TrackBuffersManager, and dependencies - r=jya
Continuing the work of replacing MIME strings with MediaContainerType, starting
from MediaResource and following the dependencies.
Most changes are mechanical: Just change ns*String into MediaContainerType, and
MIME string literals into MEDIAMIMETYPE("a/b").
Some checks for empty/invalid strings and lowercase comparisons can go, thanks
to the always-valid always-lowercase-MIME invariants of MediaContainerType.
One special case in is MediaSourceResource, which used to have an empty string
as its type (because its own type is not relevant, but its SourceBuffers carry
types). Because the inherited GetContentType *must* be overridden, and must
return a MediaContainerType, we needed a valid type even though it should not
be seen in the real world. I've chosen "application/x.mediasource" for that.
MozReview-Commit-ID: 1aCH75Kh2e6
--HG--
extra : rebase_source : 0d9cd9b69c264e5dcfc3845f80ee107f4bcbcd9a
2016-12-28 10:59:02 +03:00
|
|
|
MediaContainerType(MEDIAMIMETYPE("video/webm"))));
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<Benchmark> estimiser =
|
|
|
|
new Benchmark(demuxer,
|
|
|
|
{
|
|
|
|
Preferences::GetInt("media.benchmark.frames", 300), // frames to measure
|
|
|
|
1, // start benchmarking after decoding this frame.
|
|
|
|
8, // loop after decoding that many frames.
|
|
|
|
TimeDuration::FromMilliseconds(
|
|
|
|
Preferences::GetUint("media.benchmark.timeout", 1000))
|
|
|
|
});
|
|
|
|
estimiser->Run()->Then(
|
2017-03-28 13:12:49 +03:00
|
|
|
SystemGroup::AbstractMainThreadFor(TaskCategory::Other), __func__,
|
2016-03-09 07:34:50 +03:00
|
|
|
[](uint32_t aDecodeFps) {
|
2016-03-17 09:20:21 +03:00
|
|
|
if (XRE_IsContentProcess()) {
|
|
|
|
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
|
|
|
|
if (contentChild) {
|
|
|
|
contentChild->SendNotifyBenchmarkResult(NS_LITERAL_STRING("VP9"),
|
|
|
|
aDecodeFps);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps);
|
2016-04-13 05:44:29 +03:00
|
|
|
Preferences::SetUint(sBenchmarkFpsVersionCheck, sBenchmarkVersionID);
|
2016-03-17 09:20:21 +03:00
|
|
|
}
|
2017-02-15 22:15:15 +03:00
|
|
|
Telemetry::Accumulate(Telemetry::HistogramID::VIDEO_VP9_BENCHMARK_FPS, aDecodeFps);
|
2016-03-09 07:34:50 +03:00
|
|
|
},
|
|
|
|
[]() { });
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
if (!hasPref) {
|
2016-03-03 05:57:11 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t decodeFps = Preferences::GetUint(sBenchmarkFpsPref);
|
|
|
|
uint32_t threshold =
|
|
|
|
Preferences::GetUint("media.benchmark.vp9.threshold", 150);
|
|
|
|
|
|
|
|
return decodeFps >= threshold;
|
2016-04-20 18:09:49 +03:00
|
|
|
#endif
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
Benchmark::Benchmark(MediaDataDemuxer* aDemuxer, const Parameters& aParameters)
|
2016-03-09 13:38:49 +03:00
|
|
|
: QueueObject(AbstractThread::GetCurrent())
|
2016-03-09 07:34:50 +03:00
|
|
|
, mParameters(aParameters)
|
2016-03-03 05:57:11 +03:00
|
|
|
, mKeepAliveUntilComplete(this)
|
2016-03-09 07:34:50 +03:00
|
|
|
, mPlaybackState(this, aDemuxer)
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
2016-03-09 07:34:50 +03:00
|
|
|
MOZ_COUNT_CTOR(Benchmark);
|
2016-03-09 13:38:49 +03:00
|
|
|
MOZ_ASSERT(Thread(), "Must be run in task queue");
|
2016-03-09 07:34:50 +03:00
|
|
|
}
|
2016-03-03 05:57:11 +03:00
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
Benchmark::~Benchmark()
|
|
|
|
{
|
|
|
|
MOZ_COUNT_DTOR(Benchmark);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<Benchmark::BenchmarkPromise>
|
|
|
|
Benchmark::Run()
|
|
|
|
{
|
2016-03-09 13:38:49 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<BenchmarkPromise> p = mPromise.Ensure(__func__);
|
2016-03-03 05:57:11 +03:00
|
|
|
RefPtr<Benchmark> self = this;
|
|
|
|
mPlaybackState.Dispatch(
|
|
|
|
NS_NewRunnableFunction([self]() { self->mPlaybackState.DemuxSamples(); }));
|
2016-03-09 07:34:50 +03:00
|
|
|
return p;
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-03-09 07:34:50 +03:00
|
|
|
Benchmark::ReturnResult(uint32_t aDecodeFps)
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
2016-03-09 13:38:49 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
2016-03-03 05:57:11 +03:00
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
mPromise.ResolveIfExists(aDecodeFps, __func__);
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Benchmark::Dispose()
|
|
|
|
{
|
2016-03-09 13:38:49 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
2016-03-03 05:57:11 +03:00
|
|
|
|
|
|
|
mKeepAliveUntilComplete = nullptr;
|
2016-03-09 07:34:50 +03:00
|
|
|
mPromise.RejectIfExists(false, __func__);
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
2016-03-09 13:38:49 +03:00
|
|
|
void
|
|
|
|
Benchmark::Init()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2017-01-31 22:43:07 +03:00
|
|
|
gfxVars::Initialize();
|
|
|
|
gfxPrefs::GetSingleton();
|
2016-05-12 11:54:35 +03:00
|
|
|
MediaPrefs::GetSingleton();
|
2016-03-09 13:38:49 +03:00
|
|
|
}
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
BenchmarkPlayback::BenchmarkPlayback(Benchmark* aMainThreadState,
|
|
|
|
MediaDataDemuxer* aDemuxer)
|
2016-03-03 05:57:11 +03:00
|
|
|
: QueueObject(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK)))
|
|
|
|
, mMainThreadState(aMainThreadState)
|
2016-05-24 11:48:26 +03:00
|
|
|
, mDecoderTaskQueue(new TaskQueue(GetMediaThreadPool(
|
2016-03-09 07:34:50 +03:00
|
|
|
MediaThreadType::PLATFORM_DECODER)))
|
|
|
|
, mDemuxer(aDemuxer)
|
|
|
|
, mSampleIndex(0)
|
|
|
|
, mFrameCount(0)
|
|
|
|
, mFinished(false)
|
2017-01-26 15:56:46 +03:00
|
|
|
, mDrained(false)
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
2016-03-09 13:38:49 +03:00
|
|
|
MOZ_ASSERT(static_cast<Benchmark*>(mMainThreadState)->OnThread());
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BenchmarkPlayback::DemuxSamples()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(OnThread());
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
|
|
|
mDemuxer->Init()->Then(
|
2016-03-03 05:57:11 +03:00
|
|
|
Thread(), __func__,
|
2016-03-09 07:34:50 +03:00
|
|
|
[this, ref](nsresult aResult) {
|
2016-03-03 05:57:11 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
2016-03-09 07:34:50 +03:00
|
|
|
mTrackDemuxer =
|
|
|
|
mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
|
|
|
if (!mTrackDemuxer) {
|
|
|
|
MainThreadShutdown();
|
2016-03-11 00:37:09 +03:00
|
|
|
return;
|
2016-03-09 07:34:50 +03:00
|
|
|
}
|
|
|
|
DemuxNextSample();
|
2016-03-03 05:57:11 +03:00
|
|
|
},
|
2016-09-12 05:22:20 +03:00
|
|
|
[this, ref](const MediaResult& aError) { MainThreadShutdown(); });
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-03-09 07:34:50 +03:00
|
|
|
BenchmarkPlayback::DemuxNextSample()
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(OnThread());
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
|
|
|
RefPtr<MediaTrackDemuxer::SamplesPromise> promise = mTrackDemuxer->GetSamples();
|
|
|
|
promise->Then(
|
|
|
|
Thread(), __func__,
|
|
|
|
[this, ref](RefPtr<MediaTrackDemuxer::SamplesHolder> aHolder) {
|
|
|
|
mSamples.AppendElements(Move(aHolder->mSamples));
|
2017-01-26 15:56:46 +03:00
|
|
|
if (ref->mParameters.mStopAtFrame
|
|
|
|
&& mSamples.Length() == (size_t)ref->mParameters.mStopAtFrame.ref()) {
|
2016-03-09 07:34:50 +03:00
|
|
|
InitDecoder(Move(*mTrackDemuxer->GetInfo()));
|
|
|
|
} else {
|
|
|
|
Dispatch(NS_NewRunnableFunction([this, ref]() { DemuxNextSample(); }));
|
|
|
|
}
|
|
|
|
},
|
2016-09-12 05:22:20 +03:00
|
|
|
[this, ref](const MediaResult& aError) {
|
|
|
|
switch (aError.Code()) {
|
|
|
|
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
|
2016-03-09 07:34:50 +03:00
|
|
|
InitDecoder(Move(*mTrackDemuxer->GetInfo()));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MainThreadShutdown();
|
|
|
|
}
|
|
|
|
});
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-03-09 07:34:50 +03:00
|
|
|
BenchmarkPlayback::InitDecoder(TrackInfo&& aInfo)
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
2016-03-09 07:34:50 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
2016-03-03 05:57:11 +03:00
|
|
|
|
|
|
|
RefPtr<PDMFactory> platform = new PDMFactory();
|
2017-01-26 15:56:46 +03:00
|
|
|
mDecoder = platform->CreateDecoder({ aInfo, mDecoderTaskQueue });
|
2016-03-09 07:34:50 +03:00
|
|
|
if (!mDecoder) {
|
|
|
|
MainThreadShutdown();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
2016-03-03 05:57:11 +03:00
|
|
|
mDecoder->Init()->Then(
|
2016-03-09 13:14:01 +03:00
|
|
|
Thread(), __func__,
|
2016-03-09 07:34:50 +03:00
|
|
|
[this, ref](TrackInfo::TrackType aTrackType) {
|
2016-03-09 13:14:01 +03:00
|
|
|
InputExhausted();
|
2016-03-03 05:57:11 +03:00
|
|
|
},
|
2017-01-26 15:56:46 +03:00
|
|
|
[this, ref](const MediaResult& aError) {
|
2016-03-09 07:34:50 +03:00
|
|
|
MainThreadShutdown();
|
2016-03-03 05:57:11 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-03-09 07:34:50 +03:00
|
|
|
BenchmarkPlayback::MainThreadShutdown()
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
|
|
|
MOZ_ASSERT(OnThread());
|
|
|
|
|
2016-03-17 04:58:21 +03:00
|
|
|
if (mFinished) {
|
|
|
|
// Nothing more to do.
|
|
|
|
return;
|
|
|
|
}
|
2016-03-11 00:37:09 +03:00
|
|
|
mFinished = true;
|
|
|
|
|
2016-03-09 07:34:50 +03:00
|
|
|
if (mDecoder) {
|
2017-01-26 15:56:46 +03:00
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
|
|
|
mDecoder->Flush()->Then(
|
|
|
|
Thread(), __func__,
|
|
|
|
[ref, this]() {
|
|
|
|
mDecoder->Shutdown()->Then(
|
|
|
|
Thread(), __func__,
|
|
|
|
[ref, this]() {
|
|
|
|
mDecoderTaskQueue->BeginShutdown();
|
|
|
|
mDecoderTaskQueue->AwaitShutdownAndIdle();
|
|
|
|
mDecoderTaskQueue = nullptr;
|
|
|
|
|
|
|
|
if (mTrackDemuxer) {
|
|
|
|
mTrackDemuxer->Reset();
|
|
|
|
mTrackDemuxer->BreakCycles();
|
|
|
|
mTrackDemuxer = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread()->AsTaskQueue()->BeginShutdown()->Then(
|
|
|
|
ref->Thread(), __func__,
|
|
|
|
[ref]() { ref->Dispose(); },
|
|
|
|
[]() { MOZ_CRASH("not reached"); });
|
|
|
|
},
|
|
|
|
[]() { MOZ_CRASH("not reached"); });
|
|
|
|
mDecoder = nullptr;
|
|
|
|
},
|
|
|
|
[]() { MOZ_CRASH("not reached"); });
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-01-26 15:56:46 +03:00
|
|
|
BenchmarkPlayback::Output(const MediaDataDecoder::DecodedData& aResults)
|
2016-03-09 07:34:50 +03:00
|
|
|
{
|
2017-01-26 15:56:46 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
2016-03-09 07:34:50 +03:00
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
2017-01-26 15:56:46 +03:00
|
|
|
mFrameCount += aResults.Length();
|
|
|
|
if (!mDecodeStartTime && mFrameCount >= ref->mParameters.mStartupFrame) {
|
|
|
|
mDecodeStartTime = Some(TimeStamp::Now());
|
|
|
|
}
|
|
|
|
TimeStamp now = TimeStamp::Now();
|
|
|
|
int32_t frames = mFrameCount - ref->mParameters.mStartupFrame;
|
|
|
|
TimeDuration elapsedTime = now - mDecodeStartTime.refOr(now);
|
|
|
|
if (!mFinished
|
|
|
|
&& (((frames == ref->mParameters.mFramesToMeasure) && frames > 0)
|
|
|
|
|| elapsedTime >= ref->mParameters.mTimeout
|
|
|
|
|| mDrained)) {
|
2016-03-09 07:34:50 +03:00
|
|
|
uint32_t decodeFps = frames / elapsedTime.ToSeconds();
|
|
|
|
MainThreadShutdown();
|
|
|
|
ref->Dispatch(NS_NewRunnableFunction([ref, decodeFps]() {
|
|
|
|
ref->ReturnResult(decodeFps);
|
|
|
|
}));
|
2017-01-26 15:56:46 +03:00
|
|
|
}
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
|
|
|
|
2017-01-26 15:56:46 +03:00
|
|
|
void
|
|
|
|
BenchmarkPlayback::InputExhausted()
|
2016-03-03 05:57:11 +03:00
|
|
|
{
|
2017-01-26 15:56:46 +03:00
|
|
|
MOZ_ASSERT(OnThread());
|
|
|
|
if (mFinished || mSampleIndex >= mSamples.Length()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
RefPtr<Benchmark> ref(mMainThreadState);
|
|
|
|
mDecoder->Decode(mSamples[mSampleIndex])
|
|
|
|
->Then(Thread(), __func__,
|
|
|
|
[ref, this](const MediaDataDecoder::DecodedData& aResults) {
|
|
|
|
Output(aResults);
|
|
|
|
InputExhausted();
|
|
|
|
},
|
|
|
|
[ref, this](const MediaResult& aError) { MainThreadShutdown(); });
|
|
|
|
mSampleIndex++;
|
|
|
|
if (mSampleIndex == mSamples.Length()) {
|
|
|
|
if (ref->mParameters.mStopAtFrame) {
|
|
|
|
mSampleIndex = 0;
|
|
|
|
} else {
|
|
|
|
mDecoder->Drain()->Then(
|
|
|
|
Thread(), __func__,
|
|
|
|
[ref, this](const MediaDataDecoder::DecodedData& aResults) {
|
|
|
|
mDrained = true;
|
|
|
|
Output(aResults);
|
|
|
|
},
|
|
|
|
[ref, this](const MediaResult& aError) { MainThreadShutdown(); });
|
|
|
|
}
|
|
|
|
}
|
2016-03-03 05:57:11 +03:00
|
|
|
}
|
2016-03-09 07:34:50 +03:00
|
|
|
|
2017-01-26 15:56:46 +03:00
|
|
|
} // namespace mozilla
|