mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 1288618 - Part 14: Add PVideoDecoder protocol for individual decoders. r=cpearce,dvander
This commit is contained in:
parent
7756c8a512
commit
a64365e7ad
75
dom/media/ipc/PVideoDecoder.ipdl
Normal file
75
dom/media/ipc/PVideoDecoder.ipdl
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; tab-width: 8; 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/dom/MediaIPCUtils.h";
|
||||
|
||||
include protocol PVideoDecoderManager;
|
||||
include LayersSurfaces;
|
||||
using VideoInfo from "MediaInfo.h";
|
||||
using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct MediaDataIPDL
|
||||
{
|
||||
int64_t offset;
|
||||
int64_t time;
|
||||
int64_t timecode;
|
||||
int64_t duration;
|
||||
uint32_t frames;
|
||||
bool keyframe;
|
||||
};
|
||||
|
||||
struct VideoDataIPDL
|
||||
{
|
||||
MediaDataIPDL base;
|
||||
IntSize display;
|
||||
SurfaceDescriptorGPUVideo sd;
|
||||
int32_t frameID;
|
||||
};
|
||||
|
||||
struct MediaRawDataIPDL
|
||||
{
|
||||
MediaDataIPDL base;
|
||||
Shmem buffer;
|
||||
};
|
||||
|
||||
// This protocol provides a way to use MediaDataDecoder/MediaDataDecoderCallback
|
||||
// across processes. The parent side currently is only implemented to work with
|
||||
// Window Media Foundation, but can be extended easily to support other backends.
|
||||
// The child side runs in the content process, and the parent side runs in the
|
||||
// GPU process. We run a separate IPDL thread for both sides.
|
||||
async protocol PVideoDecoder
|
||||
{
|
||||
manager PVideoDecoderManager;
|
||||
parent:
|
||||
async Init(VideoInfo info, LayersBackend backend);
|
||||
|
||||
async Input(MediaRawDataIPDL data);
|
||||
|
||||
async Flush();
|
||||
async Drain();
|
||||
async Shutdown();
|
||||
|
||||
async __delete__();
|
||||
|
||||
child:
|
||||
|
||||
async InitComplete();
|
||||
async InitFailed(nsresult reason);
|
||||
|
||||
// Each output includes a SurfaceDescriptorGPUVideo that represents the decoded
|
||||
// frame. This SurfaceDescriptor can be used on the Layers IPDL protocol, but
|
||||
// must be released explicitly using DeallocateSurfaceDescriptorGPUVideo
|
||||
// on the manager protocol.
|
||||
async Output(VideoDataIPDL data);
|
||||
async InputExhausted();
|
||||
async DrainComplete();
|
||||
async Error(nsresult error);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -3,6 +3,7 @@
|
||||
* 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 PVideoDecoder;
|
||||
include LayersSurfaces;
|
||||
include "mozilla/dom/MediaIPCUtils.h";
|
||||
|
||||
@ -11,7 +12,9 @@ namespace dom {
|
||||
|
||||
async protocol PVideoDecoderManager
|
||||
{
|
||||
manages PVideoDecoder;
|
||||
parent:
|
||||
async PVideoDecoder();
|
||||
|
||||
async DeallocateSurfaceDescriptorGPUVideo(SurfaceDescriptorGPUVideo sd);
|
||||
};
|
||||
|
208
dom/media/ipc/VideoDecoderChild.cpp
Normal file
208
dom/media/ipc/VideoDecoderChild.cpp
Normal file
@ -0,0 +1,208 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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 "VideoDecoderChild.h"
|
||||
#include "VideoDecoderManagerChild.h"
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "base/thread.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "GPUVideoImage.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using base::Thread;
|
||||
using namespace ipc;
|
||||
using namespace layers;
|
||||
using namespace gfx;
|
||||
|
||||
VideoDecoderChild::VideoDecoderChild()
|
||||
: mThread(VideoDecoderManagerChild::GetManagerThread())
|
||||
, mCanSend(true)
|
||||
{
|
||||
}
|
||||
|
||||
VideoDecoderChild::~VideoDecoderChild()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvOutput(const VideoDataIPDL& aData)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
VideoInfo info(aData.display().width, aData.display().height);
|
||||
|
||||
// The Image here creates a TextureData object that takes ownership
|
||||
// of the SurfaceDescriptor, and is responsible for making sure that
|
||||
// it gets deallocated.
|
||||
RefPtr<Image> image = new GPUVideoImage(aData.sd(), aData.display());
|
||||
|
||||
RefPtr<VideoData> video = VideoData::CreateFromImage(info,
|
||||
aData.base().offset(),
|
||||
aData.base().time(),
|
||||
aData.base().duration(),
|
||||
image,
|
||||
aData.base().keyframe(),
|
||||
aData.base().timecode(),
|
||||
IntRect());
|
||||
mCallback->Output(video);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvInputExhausted()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mCallback->InputExhausted();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvDrainComplete()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mCallback->DrainComplete();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvError(const nsresult& aError)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mCallback->Error(aError);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvInitComplete()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderChild::RecvInitFailed(const nsresult& aReason)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
mInitPromise.Reject(aReason, __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
mCanSend = false;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback,
|
||||
const VideoInfo& aVideoInfo,
|
||||
layers::LayersBackend aLayersBackend)
|
||||
{
|
||||
VideoDecoderManagerChild::GetSingleton()->SendPVideoDecoderConstructor(this);
|
||||
mIPDLSelfRef = this;
|
||||
mCallback = aCallback;
|
||||
mVideoInfo = aVideoInfo;
|
||||
mLayersBackend = aLayersBackend;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::DestroyIPDL()
|
||||
{
|
||||
if (mCanSend) {
|
||||
PVideoDecoderChild::Send__delete__(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::IPDLActorDestroyed()
|
||||
{
|
||||
mIPDLSelfRef = nullptr;
|
||||
}
|
||||
|
||||
// MediaDataDecoder methods
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise>
|
||||
VideoDecoderChild::Init()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
if (!mCanSend || !SendInit(mVideoInfo, mLayersBackend)) {
|
||||
return MediaDataDecoder::InitPromise::CreateAndReject(
|
||||
NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
|
||||
}
|
||||
return mInitPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::Input(MediaRawData* aSample)
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
if (!mCanSend) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: It would be nice to add an allocator method to
|
||||
// MediaDataDecoder so that the demuxer could write directly
|
||||
// into shmem rather than requiring a copy here.
|
||||
Shmem buffer;
|
||||
if (!AllocShmem(aSample->Size(), Shmem::SharedMemory::TYPE_BASIC, &buffer)) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(buffer.get<uint8_t>(), aSample->Data(), aSample->Size());
|
||||
|
||||
MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mTimecode,
|
||||
aSample->mDuration,
|
||||
aSample->mFrames,
|
||||
aSample->mKeyframe),
|
||||
buffer);
|
||||
if (!SendInput(sample)) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::Flush()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
if (!mCanSend || !SendFlush()) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::Drain()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
if (!mCanSend || !SendDrain()) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::Shutdown()
|
||||
{
|
||||
AssertOnManagerThread();
|
||||
if (!mCanSend || !SendShutdown()) {
|
||||
mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderChild::AssertOnManagerThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mThread);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
71
dom/media/ipc/VideoDecoderChild.h
Normal file
71
dom/media/ipc/VideoDecoderChild.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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_ipc_VideoDecoderChild_h
|
||||
#define include_dom_ipc_VideoDecoderChild_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PVideoDecoderChild.h"
|
||||
#include "MediaData.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class RemoteVideoDecoder;
|
||||
class RemoteDecoderModule;
|
||||
|
||||
class VideoDecoderChild final : public PVideoDecoderChild
|
||||
{
|
||||
public:
|
||||
explicit VideoDecoderChild();
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderChild)
|
||||
|
||||
// PVideoDecoderChild
|
||||
bool RecvOutput(const VideoDataIPDL& aData) override;
|
||||
bool RecvInputExhausted() override;
|
||||
bool RecvDrainComplete() override;
|
||||
bool RecvError(const nsresult& aError) override;
|
||||
bool RecvInitComplete() override;
|
||||
bool RecvInitFailed(const nsresult& aReason) override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
RefPtr<MediaDataDecoder::InitPromise> Init();
|
||||
void Input(MediaRawData* aSample);
|
||||
void Flush();
|
||||
void Drain();
|
||||
void Shutdown();
|
||||
|
||||
void InitIPDL(MediaDataDecoderCallback* aCallback,
|
||||
const VideoInfo& aVideoInfo,
|
||||
layers::LayersBackend aLayersBackend);
|
||||
void DestroyIPDL();
|
||||
|
||||
// Called from IPDL when our actor has been destroyed
|
||||
void IPDLActorDestroyed();
|
||||
|
||||
private:
|
||||
~VideoDecoderChild();
|
||||
|
||||
void AssertOnManagerThread();
|
||||
|
||||
RefPtr<VideoDecoderChild> mIPDLSelfRef;
|
||||
RefPtr<nsIThread> mThread;
|
||||
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
MozPromiseHolder<MediaDataDecoder::InitPromise> mInitPromise;
|
||||
|
||||
VideoInfo mVideoInfo;
|
||||
layers::LayersBackend mLayersBackend;
|
||||
bool mCanSend;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include_dom_ipc_VideoDecoderChild_h
|
@ -4,6 +4,7 @@
|
||||
* 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 "VideoDecoderManagerChild.h"
|
||||
#include "VideoDecoderChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -87,6 +88,26 @@ VideoDecoderManagerChild::GetSingleton()
|
||||
return sDecoderManager;
|
||||
}
|
||||
|
||||
/* static */ nsIThread*
|
||||
VideoDecoderManagerChild::GetManagerThread()
|
||||
{
|
||||
return sVideoDecoderChildThread;
|
||||
}
|
||||
|
||||
PVideoDecoderChild*
|
||||
VideoDecoderManagerChild::AllocPVideoDecoderChild()
|
||||
{
|
||||
return new VideoDecoderChild();
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderManagerChild::DeallocPVideoDecoderChild(PVideoDecoderChild* actor)
|
||||
{
|
||||
VideoDecoderChild* child = static_cast<VideoDecoderChild*>(actor);
|
||||
child->IPDLActorDestroyed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderManagerChild::Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderManagerChild)
|
||||
|
||||
static VideoDecoderManagerChild* GetSingleton();
|
||||
static nsIThread* GetManagerThread();
|
||||
|
||||
// Can be called from any thread, dispatches the request to the IPDL thread internally.
|
||||
void DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD);
|
||||
@ -28,6 +29,10 @@ public:
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
PVideoDecoderChild* AllocPVideoDecoderChild() override;
|
||||
bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override;
|
||||
|
||||
private:
|
||||
VideoDecoderManagerChild()
|
||||
{}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* 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 "VideoDecoderManagerParent.h"
|
||||
#include "VideoDecoderParent.h"
|
||||
#include "base/thread.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
@ -159,6 +160,12 @@ VideoDecoderManagerParent::ShutdownThreads()
|
||||
sVideoDecoderManagerThread = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderManagerParent::OnManagerThread()
|
||||
{
|
||||
return NS_GetCurrentThread() == sVideoDecoderManagerThread;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderManagerParent::CreateForContent(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
|
||||
{
|
||||
@ -190,6 +197,21 @@ VideoDecoderManagerParent::~VideoDecoderManagerParent()
|
||||
ClearAllOwnedImages();
|
||||
}
|
||||
|
||||
PVideoDecoderParent*
|
||||
VideoDecoderManagerParent::AllocPVideoDecoderParent()
|
||||
{
|
||||
RefPtr<nsIEventTarget> target = sVideoDecoderTaskThread;;
|
||||
return new VideoDecoderParent(this, sManagerTaskQueue, new TaskQueue(target.forget()));
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderManagerParent::DeallocPVideoDecoderParent(PVideoDecoderParent* actor)
|
||||
{
|
||||
VideoDecoderParent* parent = static_cast<VideoDecoderParent*>(actor);
|
||||
parent->Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderManagerParent::Open(Endpoint<PVideoDecoderManagerParent>&& aEndpoint)
|
||||
{
|
||||
|
@ -25,7 +25,12 @@ public:
|
||||
static void StartupThreads();
|
||||
static void ShutdownThreads();
|
||||
|
||||
bool OnManagerThread();
|
||||
|
||||
protected:
|
||||
PVideoDecoderParent* AllocPVideoDecoderParent() override;
|
||||
bool DeallocPVideoDecoderParent(PVideoDecoderParent* actor) override;
|
||||
|
||||
bool RecvDeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) override;
|
||||
|
||||
void ActorDestroy(mozilla::ipc::IProtocolManager<mozilla::ipc::IProtocol>::ActorDestroyReason) override {}
|
||||
|
227
dom/media/ipc/VideoDecoderParent.cpp
Normal file
227
dom/media/ipc/VideoDecoderParent.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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 "VideoDecoderParent.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "base/thread.h"
|
||||
#include "mozilla/layers/TextureHost.h"
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#include "MediaInfo.h"
|
||||
#include "VideoDecoderManagerParent.h"
|
||||
#ifdef XP_WIN
|
||||
#include "WMFDecoderModule.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using base::Thread;
|
||||
using namespace ipc;
|
||||
using namespace layers;
|
||||
using namespace gfx;
|
||||
|
||||
VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent,
|
||||
TaskQueue* aManagerTaskQueue,
|
||||
TaskQueue* aDecodeTaskQueue)
|
||||
: mParent(aParent)
|
||||
, mManagerTaskQueue(aManagerTaskQueue)
|
||||
, mDecodeTaskQueue(aDecodeTaskQueue)
|
||||
, mDestroyed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(VideoDecoderParent);
|
||||
// We hold a reference to ourselves to keep us alive until IPDL
|
||||
// explictly destroys us. There may still be refs held by
|
||||
// tasks, but no new ones should be added after we're
|
||||
// destroyed.
|
||||
mIPDLSelfRef = this;
|
||||
}
|
||||
|
||||
VideoDecoderParent::~VideoDecoderParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(VideoDecoderParent);
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::Destroy()
|
||||
{
|
||||
mDecodeTaskQueue->AwaitShutdownAndIdle();
|
||||
mDestroyed = true;
|
||||
mIPDLSelfRef = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::RecvInit(const VideoInfo& aInfo, const layers::LayersBackend& aBackend)
|
||||
{
|
||||
CreateDecoderParams params(aInfo);
|
||||
params.mTaskQueue = mDecodeTaskQueue;
|
||||
params.mCallback = this;
|
||||
params.mLayersBackend = aBackend;
|
||||
params.mImageContainer = new layers::ImageContainer();
|
||||
|
||||
#ifdef XP_WIN
|
||||
// TODO: Ideally we wouldn't hardcode the WMF PDM, and we'd use the normal PDM
|
||||
// factory logic for picking a decoder.
|
||||
WMFDecoderModule::Init();
|
||||
RefPtr<WMFDecoderModule> pdm(new WMFDecoderModule());
|
||||
pdm->Startup();
|
||||
|
||||
mDecoder = pdm->CreateVideoDecoder(params);
|
||||
if (!mDecoder) {
|
||||
Unused << SendInitFailed(NS_ERROR_DOM_MEDIA_FATAL_ERR);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
MOZ_ASSERT(false, "Can't use RemoteVideoDecoder on non-Windows platforms yet");
|
||||
#endif
|
||||
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
mDecoder->Init()->Then(mManagerTaskQueue, __func__,
|
||||
[self] (TrackInfo::TrackType aTrack) {
|
||||
if (!self->mDestroyed) {
|
||||
Unused << self->SendInitComplete();
|
||||
}
|
||||
},
|
||||
[self] (MediaResult aReason) {
|
||||
if (!self->mDestroyed) {
|
||||
Unused << self->SendInitFailed(aReason);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
|
||||
{
|
||||
// XXX: This copies the data into a buffer owned by the MediaRawData. Ideally we'd just take ownership
|
||||
// of the shmem.
|
||||
RefPtr<MediaRawData> data = new MediaRawData(aData.buffer().get<uint8_t>(), aData.buffer().Size<uint8_t>());
|
||||
data->mOffset = aData.base().offset();
|
||||
data->mTime = aData.base().time();
|
||||
data->mTimecode = aData.base().timecode();
|
||||
data->mDuration = aData.base().duration();
|
||||
data->mKeyframe = aData.base().keyframe();
|
||||
|
||||
DeallocShmem(aData.buffer());
|
||||
|
||||
mDecoder->Input(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::RecvFlush()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
mDecoder->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::RecvDrain()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
mDecoder->Drain();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::RecvShutdown()
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
if (mDecoder) {
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
if (mDecodeTaskQueue) {
|
||||
mDecodeTaskQueue->BeginShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::Output(MediaData* aData)
|
||||
{
|
||||
MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn());
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
RefPtr<MediaData> data = aData;
|
||||
mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self, data]() {
|
||||
if (self->mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(data->mType == MediaData::VIDEO_DATA, "Can only decode videos using VideoDecoderParent!");
|
||||
VideoData* video = static_cast<VideoData*>(data.get());
|
||||
|
||||
MOZ_ASSERT(video->mImage, "Decoded video must output a layer::Image to be used with VideoDecoderParent");
|
||||
|
||||
VideoDataIPDL output(MediaDataIPDL(data->mOffset,
|
||||
data->mTime,
|
||||
data->mTimecode,
|
||||
data->mDuration,
|
||||
data->mFrames,
|
||||
data->mKeyframe),
|
||||
video->mDisplay,
|
||||
self->GetManager()->StoreImage(video->mImage),
|
||||
video->mFrameID);
|
||||
Unused << self->SendOutput(output);
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::Error(const MediaResult& aError)
|
||||
{
|
||||
MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn());
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
MediaResult error = aError;
|
||||
mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self, error]() {
|
||||
if (!self->mDestroyed) {
|
||||
Unused << self->SendError(error);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::InputExhausted()
|
||||
{
|
||||
MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn());
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self]() {
|
||||
if (!self->mDestroyed) {
|
||||
Unused << self->SendInputExhausted();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
VideoDecoderParent::DrainComplete()
|
||||
{
|
||||
MOZ_ASSERT(mDecodeTaskQueue->IsCurrentThreadIn());
|
||||
RefPtr<VideoDecoderParent> self = this;
|
||||
mManagerTaskQueue->Dispatch(NS_NewRunnableFunction([self]() {
|
||||
if (!self->mDestroyed) {
|
||||
Unused << self->SendDrainComplete();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
bool
|
||||
VideoDecoderParent::OnReaderTaskQueue()
|
||||
{
|
||||
// Most of our calls into mDecoder come directly from IPDL so are on
|
||||
// the right thread, but not actually on the task queue. We only ever
|
||||
// run a single thread, not a pool, so this should work fine.
|
||||
return mParent->OnManagerThread();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
66
dom/media/ipc/VideoDecoderParent.h
Normal file
66
dom/media/ipc/VideoDecoderParent.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=99: */
|
||||
/* 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_ipc_VideoDecoderParent_h
|
||||
#define include_dom_ipc_VideoDecoderParent_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/PVideoDecoderParent.h"
|
||||
#include "VideoDecoderManagerParent.h"
|
||||
#include "MediaData.h"
|
||||
#include "ImageContainer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class VideoDecoderParent final : public PVideoDecoderParent,
|
||||
public MediaDataDecoderCallback
|
||||
{
|
||||
public:
|
||||
// We refcount this class since the task queue can have runnables
|
||||
// that reference us.
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VideoDecoderParent)
|
||||
|
||||
VideoDecoderParent(VideoDecoderManagerParent* aParent,
|
||||
TaskQueue* aManagerTaskQueue,
|
||||
TaskQueue* aDecodeTaskQueue);
|
||||
|
||||
void Destroy();
|
||||
|
||||
// PVideoDecoderParent
|
||||
bool RecvInit(const VideoInfo& aVideoInfo, const layers::LayersBackend& aBackend) override;
|
||||
bool RecvInput(const MediaRawDataIPDL& aData) override;
|
||||
bool RecvFlush() override;
|
||||
bool RecvDrain() override;
|
||||
bool RecvShutdown() override;
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
// MediaDataDecoderCallback
|
||||
void Output(MediaData* aData) override;
|
||||
void Error(const MediaResult& aError) override;
|
||||
void InputExhausted() override;
|
||||
void DrainComplete() override;
|
||||
bool OnReaderTaskQueue() override;
|
||||
|
||||
private:
|
||||
~VideoDecoderParent();
|
||||
|
||||
VideoDecoderManagerParent* GetManager() { return static_cast<VideoDecoderManagerParent*>(Manager()); }
|
||||
|
||||
RefPtr<VideoDecoderManagerParent> mParent;
|
||||
RefPtr<VideoDecoderParent> mIPDLSelfRef;
|
||||
RefPtr<TaskQueue> mManagerTaskQueue;
|
||||
RefPtr<TaskQueue> mDecodeTaskQueue;
|
||||
RefPtr<MediaDataDecoder> mDecoder;
|
||||
|
||||
// Can only be accessed from the manager thread
|
||||
bool mDestroyed;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include_dom_ipc_VideoDecoderParent_h
|
@ -6,6 +6,7 @@
|
||||
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'PVideoDecoder.ipdl',
|
||||
'PVideoDecoderManager.ipdl',
|
||||
]
|
||||
|
||||
@ -16,8 +17,10 @@ EXPORTS.mozilla.dom += [
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'VideoDecoderChild.cpp',
|
||||
'VideoDecoderManagerChild.cpp',
|
||||
'VideoDecoderManagerParent.cpp',
|
||||
'VideoDecoderParent.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
Loading…
Reference in New Issue
Block a user