diff options
Diffstat (limited to 'dom/media/platforms/wmf/WMFMediaDataDecoder.cpp')
-rw-r--r-- | dom/media/platforms/wmf/WMFMediaDataDecoder.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp new file mode 100644 index 000000000..d2c13eac7 --- /dev/null +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp @@ -0,0 +1,227 @@ +/* -*- 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 "WMFMediaDataDecoder.h" +#include "VideoUtils.h" +#include "WMFUtils.h" +#include "nsTArray.h" +#include "mozilla/Telemetry.h" + +#include "mozilla/Logging.h" +#include "mozilla/SyncRunnable.h" + +#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) + +namespace mozilla { + +WMFMediaDataDecoder::WMFMediaDataDecoder(MFTManager* aMFTManager, + TaskQueue* aTaskQueue, + MediaDataDecoderCallback* aCallback) + : mTaskQueue(aTaskQueue) + , mCallback(aCallback) + , mMFTManager(aMFTManager) + , mIsFlushing(false) + , mIsShutDown(false) +{ +} + +WMFMediaDataDecoder::~WMFMediaDataDecoder() +{ +} + +RefPtr<MediaDataDecoder::InitPromise> +WMFMediaDataDecoder::Init() +{ + MOZ_ASSERT(!mIsShutDown); + return InitPromise::CreateAndResolve(mMFTManager->GetType(), __func__); +} + +// A single telemetry sample is reported for each MediaDataDecoder object +// that has detected error or produced output successfully. +static void +SendTelemetry(unsigned long hr) +{ + // Collapse the error codes into a range of 0-0xff that can be viewed in + // telemetry histograms. For most MF_E_* errors, unique samples are used, + // retaining the least significant 7 or 8 bits. Other error codes are + // bucketed. + uint32_t sample; + if (SUCCEEDED(hr)) { + sample = 0; + } else if (hr < 0xc00d36b0) { + sample = 1; // low bucket + } else if (hr < 0xc00d3700) { + sample = hr & 0xffU; // MF_E_* + } else if (hr <= 0xc00d3705) { + sample = 0x80 + (hr & 0xfU); // more MF_E_* + } else if (hr < 0xc00d6d60) { + sample = 2; // mid bucket + } else if (hr <= 0xc00d6d78) { + sample = hr & 0xffU; // MF_E_TRANSFORM_* + } else { + sample = 3; // high bucket + } + + nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction( + [sample] { + Telemetry::Accumulate(Telemetry::MEDIA_WMF_DECODE_ERROR, sample); + }); + NS_DispatchToMainThread(runnable); +} + +void +WMFMediaDataDecoder::Shutdown() +{ + MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); + + if (mTaskQueue) { + mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); + } else { + ProcessShutdown(); + } + mIsShutDown = true; +} + +void +WMFMediaDataDecoder::ProcessShutdown() +{ + if (mMFTManager) { + mMFTManager->Shutdown(); + mMFTManager = nullptr; + if (!mRecordedError && mHasSuccessfulOutput) { + SendTelemetry(S_OK); + } + } +} + +// Inserts data into the decoder's pipeline. +void +WMFMediaDataDecoder::Input(MediaRawData* aSample) +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); + + nsCOMPtr<nsIRunnable> runnable = + NewRunnableMethod<RefPtr<MediaRawData>>( + this, + &WMFMediaDataDecoder::ProcessDecode, + RefPtr<MediaRawData>(aSample)); + mTaskQueue->Dispatch(runnable.forget()); +} + +void +WMFMediaDataDecoder::ProcessDecode(MediaRawData* aSample) +{ + if (mIsFlushing) { + // Skip sample, to be released by runnable. + return; + } + + HRESULT hr = mMFTManager->Input(aSample); + if (FAILED(hr)) { + NS_WARNING("MFTManager rejected sample"); + mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("MFTManager::Input:%x", hr))); + if (!mRecordedError) { + SendTelemetry(hr); + mRecordedError = true; + } + return; + } + + mLastStreamOffset = aSample->mOffset; + + ProcessOutput(); +} + +void +WMFMediaDataDecoder::ProcessOutput() +{ + RefPtr<MediaData> output; + HRESULT hr = S_OK; + while (SUCCEEDED(hr = mMFTManager->Output(mLastStreamOffset, output)) && + output) { + mHasSuccessfulOutput = true; + mCallback->Output(output); + } + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { + mCallback->InputExhausted(); + } else if (FAILED(hr)) { + NS_WARNING("WMFMediaDataDecoder failed to output data"); + mCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, + RESULT_DETAIL("MFTManager::Output:%x", hr))); + if (!mRecordedError) { + SendTelemetry(hr); + mRecordedError = true; + } + } +} + +void +WMFMediaDataDecoder::ProcessFlush() +{ + if (mMFTManager) { + mMFTManager->Flush(); + } +} + +void +WMFMediaDataDecoder::Flush() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); + + mIsFlushing = true; + nsCOMPtr<nsIRunnable> runnable = + NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush); + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; +} + +void +WMFMediaDataDecoder::ProcessDrain() +{ + if (!mIsFlushing && mMFTManager) { + // Order the decoder to drain... + mMFTManager->Drain(); + // Then extract all available output. + ProcessOutput(); + } + mCallback->DrainComplete(); +} + +void +WMFMediaDataDecoder::Drain() +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); + + mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessDrain)); +} + +bool +WMFMediaDataDecoder::IsHardwareAccelerated(nsACString& aFailureReason) const { + MOZ_ASSERT(!mIsShutDown); + + return mMFTManager && mMFTManager->IsHardwareAccelerated(aFailureReason); +} + +void +WMFMediaDataDecoder::SetSeekThreshold(const media::TimeUnit& aTime) +{ + MOZ_ASSERT(mCallback->OnReaderTaskQueue()); + MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); + + RefPtr<WMFMediaDataDecoder> self = this; + nsCOMPtr<nsIRunnable> runnable = + NS_NewRunnableFunction([self, aTime]() { + media::TimeUnit threshold = aTime; + self->mMFTManager->SetSeekThreshold(threshold); + }); + mTaskQueue->Dispatch(runnable.forget()); +} + +} // namespace mozilla |