mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-06-09 09:58:57 +00:00
4b50ae13c8
The DrainComplete() caught with mWaitForInternalDrain still won't necessarily be from the internal Drain(), but all we need is that one DrainComplete() is caught for the internal Drain() because one more will be generated if there is a Drain() in progress. What protecting mWaitForInternalDrain access with the monitor provides here is that the compiler won't use its address for storage of other data meaningless in the context of mWaitForInternalDrain and so, for example, two DrainComplete() calls won't unintentionally think that they are both for one internal drain.
267 lines
5.9 KiB
C++
267 lines
5.9 KiB
C++
/* -*- 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 "SharedDecoderManager.h"
|
|
|
|
namespace mozilla {
|
|
|
|
class SharedDecoderCallback : public MediaDataDecoderCallback
|
|
{
|
|
public:
|
|
explicit SharedDecoderCallback(SharedDecoderManager* aManager)
|
|
: mManager(aManager)
|
|
{
|
|
}
|
|
|
|
virtual void Output(MediaData* aData) override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->mActiveCallback->Output(aData);
|
|
}
|
|
}
|
|
virtual void Error() override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->mActiveCallback->Error();
|
|
}
|
|
}
|
|
virtual void InputExhausted() override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->mActiveCallback->InputExhausted();
|
|
}
|
|
}
|
|
virtual void DrainComplete() override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->DrainComplete();
|
|
}
|
|
}
|
|
virtual void NotifyResourcesStatusChanged() override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->mActiveCallback->NotifyResourcesStatusChanged();
|
|
}
|
|
}
|
|
virtual void ReleaseMediaResources() override
|
|
{
|
|
if (mManager->mActiveCallback) {
|
|
mManager->mActiveCallback->ReleaseMediaResources();
|
|
}
|
|
}
|
|
|
|
SharedDecoderManager* mManager;
|
|
};
|
|
|
|
SharedDecoderManager::SharedDecoderManager()
|
|
: mTaskQueue(new FlushableMediaTaskQueue(GetMediaThreadPool()))
|
|
, mActiveProxy(nullptr)
|
|
, mActiveCallback(nullptr)
|
|
, mWaitForInternalDrain(false)
|
|
, mMonitor("SharedDecoderProxy")
|
|
, mDecoderReleasedResources(false)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread()); // taskqueue must be created on main thread.
|
|
mCallback = new SharedDecoderCallback(this);
|
|
}
|
|
|
|
SharedDecoderManager::~SharedDecoderManager()
|
|
{
|
|
}
|
|
|
|
already_AddRefed<MediaDataDecoder>
|
|
SharedDecoderManager::CreateVideoDecoder(
|
|
PlatformDecoderModule* aPDM,
|
|
const VideoInfo& aConfig,
|
|
layers::LayersBackend aLayersBackend,
|
|
layers::ImageContainer* aImageContainer,
|
|
FlushableMediaTaskQueue* aVideoTaskQueue,
|
|
MediaDataDecoderCallback* aCallback)
|
|
{
|
|
if (!mDecoder) {
|
|
mLayersBackend = aLayersBackend;
|
|
mImageContainer = aImageContainer;
|
|
// We use the manager's task queue for the decoder, rather than the one
|
|
// passed in, so that none of the objects sharing the decoder can shutdown
|
|
// the task queue while we're potentially still using it for a *different*
|
|
// object also sharing the decoder.
|
|
mDecoder =
|
|
aPDM->CreateDecoder(aConfig,
|
|
mTaskQueue,
|
|
mCallback,
|
|
mLayersBackend,
|
|
mImageContainer);
|
|
if (!mDecoder) {
|
|
mPDM = nullptr;
|
|
return nullptr;
|
|
}
|
|
nsresult rv = mDecoder->Init();
|
|
if (NS_FAILED(rv)) {
|
|
mDecoder = nullptr;
|
|
return nullptr;
|
|
}
|
|
mPDM = aPDM;
|
|
}
|
|
|
|
nsRefPtr<SharedDecoderProxy> proxy(new SharedDecoderProxy(this, aCallback));
|
|
return proxy.forget();
|
|
}
|
|
|
|
void
|
|
SharedDecoderManager::DisableHardwareAcceleration()
|
|
{
|
|
MOZ_ASSERT(mPDM);
|
|
mPDM->DisableHardwareAcceleration();
|
|
}
|
|
|
|
bool
|
|
SharedDecoderManager::Recreate(const VideoInfo& aConfig)
|
|
{
|
|
mDecoder->Flush();
|
|
mDecoder->Shutdown();
|
|
mDecoder = mPDM->CreateDecoder(aConfig,
|
|
mTaskQueue,
|
|
mCallback,
|
|
mLayersBackend,
|
|
mImageContainer);
|
|
if (!mDecoder) {
|
|
return false;
|
|
}
|
|
nsresult rv = mDecoder->Init();
|
|
return rv == NS_OK;
|
|
}
|
|
|
|
void
|
|
SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
|
|
{
|
|
if (mActiveProxy == aProxy) {
|
|
return;
|
|
}
|
|
SetIdle(mActiveProxy);
|
|
|
|
mActiveProxy = aProxy;
|
|
mActiveCallback = aProxy->mCallback;
|
|
}
|
|
|
|
void
|
|
SharedDecoderManager::SetIdle(MediaDataDecoder* aProxy)
|
|
{
|
|
if (aProxy && mActiveProxy == aProxy) {
|
|
{
|
|
MonitorAutoLock mon(mMonitor);
|
|
mWaitForInternalDrain = true;
|
|
// We don't want to hold the lock while calling Drain() as some
|
|
// platform implementations call DrainComplete() immediately.
|
|
}
|
|
nsresult rv = mActiveProxy->Drain();
|
|
if (NS_SUCCEEDED(rv)) {
|
|
MonitorAutoLock mon(mMonitor);
|
|
while (mWaitForInternalDrain) {
|
|
mon.Wait();
|
|
}
|
|
}
|
|
mActiveProxy->Flush();
|
|
mActiveProxy = nullptr;
|
|
}
|
|
}
|
|
|
|
void
|
|
SharedDecoderManager::DrainComplete()
|
|
{
|
|
{
|
|
MonitorAutoLock mon(mMonitor);
|
|
if (mWaitForInternalDrain) {
|
|
mWaitForInternalDrain = false;
|
|
mon.NotifyAll();
|
|
return;
|
|
}
|
|
}
|
|
mActiveCallback->DrainComplete();
|
|
}
|
|
|
|
void
|
|
SharedDecoderManager::Shutdown()
|
|
{
|
|
if (mDecoder) {
|
|
mDecoder->Shutdown();
|
|
mDecoder = nullptr;
|
|
}
|
|
mPDM = nullptr;
|
|
if (mTaskQueue) {
|
|
mTaskQueue->BeginShutdown();
|
|
mTaskQueue->AwaitShutdownAndIdle();
|
|
mTaskQueue = nullptr;
|
|
}
|
|
}
|
|
|
|
SharedDecoderProxy::SharedDecoderProxy(SharedDecoderManager* aManager,
|
|
MediaDataDecoderCallback* aCallback)
|
|
: mManager(aManager)
|
|
, mCallback(aCallback)
|
|
{
|
|
}
|
|
|
|
SharedDecoderProxy::~SharedDecoderProxy()
|
|
{
|
|
Shutdown();
|
|
}
|
|
|
|
nsresult
|
|
SharedDecoderProxy::Init()
|
|
{
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
SharedDecoderProxy::Input(MediaRawData* aSample)
|
|
{
|
|
if (mManager->mActiveProxy != this) {
|
|
mManager->Select(this);
|
|
}
|
|
return mManager->mDecoder->Input(aSample);
|
|
}
|
|
|
|
nsresult
|
|
SharedDecoderProxy::Flush()
|
|
{
|
|
if (mManager->mActiveProxy == this) {
|
|
return mManager->mDecoder->Flush();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
SharedDecoderProxy::Drain()
|
|
{
|
|
if (mManager->mActiveProxy == this) {
|
|
return mManager->mDecoder->Drain();
|
|
} else {
|
|
mCallback->DrainComplete();
|
|
return NS_OK;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
SharedDecoderProxy::Shutdown()
|
|
{
|
|
mManager->SetIdle(this);
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
SharedDecoderProxy::IsWaitingMediaResources()
|
|
{
|
|
return mManager->mDecoder->IsWaitingMediaResources();
|
|
}
|
|
|
|
bool
|
|
SharedDecoderProxy::IsHardwareAccelerated() const
|
|
{
|
|
return mManager->mDecoder->IsHardwareAccelerated();
|
|
}
|
|
|
|
}
|