Bug 1315850 - Implement CDM video decoder drain. r=jya
MozReview-Commit-ID: 5RbrWyLglRf
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -483,48 +483,69 @@ ChromiumCDMChild::RecvDecryptAndDecodeFr
WidevineVideoFrame frame;
cdm::Status rv = mCDM->DecryptAndDecodeFrame(input, &frame);
GMP_LOG("WidevineVideoDecoder::Decode(timestamp=%" PRId64 ") rv=%d",
input.timestamp,
rv);
if (rv == cdm::kSuccess) {
- // TODO: WidevineBuffers should hold a shmem instead of a array, and we can
- // send the handle instead of copying the array here.
-
- gmp::CDMVideoFrame output;
- output.mFormat() = static_cast<cdm::VideoFormat>(frame.Format());
- output.mImageWidth() = frame.Size().width;
- output.mImageHeight() = frame.Size().height;
- output.mData() = Move(
- reinterpret_cast<WidevineBuffer*>(frame.FrameBuffer())->ExtractBuffer());
- output.mYPlane() = { frame.PlaneOffset(cdm::VideoFrame::kYPlane),
- frame.Stride(cdm::VideoFrame::kYPlane) };
- output.mUPlane() = { frame.PlaneOffset(cdm::VideoFrame::kUPlane),
- frame.Stride(cdm::VideoFrame::kUPlane) };
- output.mVPlane() = { frame.PlaneOffset(cdm::VideoFrame::kVPlane),
- frame.Stride(cdm::VideoFrame::kVPlane) };
- output.mTimestamp() = frame.Timestamp();
-
- uint64_t duration = 0;
- if (mFrameDurations.Find(frame.Timestamp(), duration)) {
- output.mDuration() = duration;
- }
-
- Unused << SendDecoded(output);
+ ReturnOutput(frame);
} else if (rv == cdm::kNeedMoreData) {
Unused << SendDecoded(gmp::CDMVideoFrame());
} else {
Unused << SendDecodeFailed(rv);
}
return IPC_OK();
}
+void
+ChromiumCDMChild::ReturnOutput(WidevineVideoFrame& aFrame)
+{
+ // TODO: WidevineBuffers should hold a shmem instead of a array, and we can
+ // send the handle instead of copying the array here.
+ gmp::CDMVideoFrame output;
+ output.mFormat() = static_cast<cdm::VideoFormat>(aFrame.Format());
+ output.mImageWidth() = aFrame.Size().width;
+ output.mImageHeight() = aFrame.Size().height;
+ output.mData() = Move(
+ reinterpret_cast<WidevineBuffer*>(aFrame.FrameBuffer())->ExtractBuffer());
+ output.mYPlane() = { aFrame.PlaneOffset(cdm::VideoFrame::kYPlane),
+ aFrame.Stride(cdm::VideoFrame::kYPlane) };
+ output.mUPlane() = { aFrame.PlaneOffset(cdm::VideoFrame::kUPlane),
+ aFrame.Stride(cdm::VideoFrame::kUPlane) };
+ output.mVPlane() = { aFrame.PlaneOffset(cdm::VideoFrame::kVPlane),
+ aFrame.Stride(cdm::VideoFrame::kVPlane) };
+ output.mTimestamp() = aFrame.Timestamp();
+
+ uint64_t duration = 0;
+ if (mFrameDurations.Find(aFrame.Timestamp(), duration)) {
+ output.mDuration() = duration;
+ }
+
+ Unused << SendDecoded(output);
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvDrain()
+{
+ WidevineVideoFrame frame;
+ cdm::InputBuffer sample;
+ cdm::Status rv = mCDM->DecryptAndDecodeFrame(sample, &frame);
+ CDM_LOG("ChromiumCDMChild::RecvDrain(); DecryptAndDecodeFrame() rv=%d", rv);
+ if (rv == cdm::kSuccess) {
+ MOZ_ASSERT(frame.Format() != cdm::kUnknownVideoFormat);
+ ReturnOutput(frame);
+ } else {
+ Unused << SendDrainComplete();
+ }
+ return IPC_OK();
+}
+
mozilla::ipc::IPCResult
ChromiumCDMChild::RecvDestroy()
{
MOZ_ASSERT(IsOnMessageLoopThread());
GMP_LOG("ChromiumCDMChild::RecvDestroy()");
MOZ_ASSERT(!mDecoderInitialized);
--- a/dom/media/gmp/ChromiumCDMChild.h
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -1,19 +1,20 @@
/* -*- 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/. */
#ifndef ChromiumCDMChild_h_
#define ChromiumCDMChild_h_
+#include "content_decryption_module.h"
#include "mozilla/gmp/PChromiumCDMChild.h"
-#include "content_decryption_module.h"
#include "SimpleMap.h"
+#include "WidevineVideoFrame.h"
namespace mozilla {
namespace gmp {
class GMPContentChild;
class ChromiumCDMChild : public PChromiumCDMChild
, public cdm::Host_8
@@ -97,19 +98,21 @@ protected:
ipc::IPCResult RecvDecrypt(const uint32_t& aId,
const CDMInputBuffer& aBuffer) override;
ipc::IPCResult RecvInitializeVideoDecoder(
const CDMVideoDecoderConfig& aConfig) override;
ipc::IPCResult RecvDeinitializeVideoDecoder() override;
ipc::IPCResult RecvResetVideoDecoder() override;
ipc::IPCResult RecvDecryptAndDecodeFrame(
const CDMInputBuffer& aBuffer) override;
+ ipc::IPCResult RecvDrain() override;
ipc::IPCResult RecvDestroy() override;
void DecryptFailed(uint32_t aId, cdm::Status aStatus);
+ void ReturnOutput(WidevineVideoFrame& aFrame);
GMPContentChild* mPlugin = nullptr;
cdm::ContentDecryptionModule_8* mCDM = nullptr;
typedef SimpleMap<uint64_t> DurationMap;
DurationMap mFrameDurations;
bool mDecoderInitialized = false;
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -603,10 +603,28 @@ ChromiumCDMParent::FlushVideoDecoder()
ipc::IPCResult
ChromiumCDMParent::RecvResetVideoDecoderComplete()
{
mFlushDecoderPromise.Resolve(true, __func__);
return IPC_OK();
}
+RefPtr<MediaDataDecoder::DecodePromise>
+ChromiumCDMParent::Drain()
+{
+ MOZ_ASSERT(mDecodePromise.IsEmpty(), "Must wait for decoding to complete");
+
+ RefPtr<MediaDataDecoder::DecodePromise> p = mDecodePromise.Ensure(__func__);
+ if (!SendDrain()) {
+ mDecodePromise.Resolve(MediaDataDecoder::DecodedData(), __func__);
+ }
+ return p;
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvDrainComplete()
+{
+ mDecodePromise.ResolveIfExists(MediaDataDecoder::DecodedData(), __func__);
+ return IPC_OK();
+}
} // namespace gmp
} // namespace mozilla
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -66,16 +66,18 @@ public:
const VideoInfo& aInfo,
RefPtr<layers::ImageContainer> aImageContainer);
RefPtr<MediaDataDecoder::DecodePromise> DecryptAndDecodeFrame(
MediaRawData* aSample);
RefPtr<MediaDataDecoder::FlushPromise> FlushVideoDecoder();
+ RefPtr<MediaDataDecoder::DecodePromise> Drain();
+
protected:
~ChromiumCDMParent() {}
ipc::IPCResult Recv__delete__() override;
ipc::IPCResult RecvOnResolveNewSessionPromise(
const uint32_t& aPromiseId,
const nsCString& aSessionId) override;
ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId) override;
@@ -100,16 +102,17 @@ protected:
ipc::IPCResult RecvDecrypted(const uint32_t& aId,
const uint32_t& aStatus,
nsTArray<uint8_t>&& aData) override;
ipc::IPCResult RecvOnDecoderInitDone(const uint32_t& aStatus) override;
ipc::IPCResult RecvDecoded(const CDMVideoFrame& aFrame) override;
ipc::IPCResult RecvDecodeFailed(const uint32_t& aStatus) override;
ipc::IPCResult RecvShutdown() override;
ipc::IPCResult RecvResetVideoDecoderComplete() override;
+ ipc::IPCResult RecvDrainComplete() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
void RejectPromise(uint32_t aPromiseId,
nsresult aError,
const nsCString& aErrorMessage);
void ResolvePromise(uint32_t aPromiseId);
--- a/dom/media/gmp/PChromiumCDM.ipdl
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -41,16 +41,18 @@ child:
async InitializeVideoDecoder(CDMVideoDecoderConfig aConfig);
async DeinitializeVideoDecoder();
async ResetVideoDecoder();
async DecryptAndDecodeFrame(CDMInputBuffer aBuffer);
+ async Drain();
+
async Destroy();
parent:
async __delete__();
// cdm::Host8
async OnResolveNewSessionPromise(uint32_t aPromiseId, nsCString aSessionId);
@@ -84,13 +86,15 @@ parent:
async OnDecoderInitDone(uint32_t aStatus);
// Return values of cdm::ContentDecryptionModule8::DecryptAndDecodeFrame
async Decoded(CDMVideoFrame aFrame);
async DecodeFailed(uint32_t aStatus);
async ResetVideoDecoderComplete();
+ async DrainComplete();
+
async Shutdown();
};
} // namespace gmp
} // namespace mozilla
--- a/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp
+++ b/dom/media/platforms/agnostic/eme/ChromiumCDMVideoDecoder.cpp
@@ -121,19 +121,19 @@ ChromiumCDMVideoDecoder::Flush()
RefPtr<gmp::ChromiumCDMParent> cdm = mCDMParent;
return InvokeAsync(
mGMPThread, __func__, [cdm]() { return cdm->FlushVideoDecoder(); });
}
RefPtr<MediaDataDecoder::DecodePromise>
ChromiumCDMVideoDecoder::Drain()
{
- return DecodePromise::CreateAndReject(
- MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR, RESULT_DETAIL("Unimplemented")),
- __func__);
+ MOZ_ASSERT(mCDMParent);
+ RefPtr<gmp::ChromiumCDMParent> cdm = mCDMParent;
+ return InvokeAsync(mGMPThread, __func__, [cdm]() { return cdm->Drain(); });
}
RefPtr<ShutdownPromise>
ChromiumCDMVideoDecoder::Shutdown()
{
return ShutdownPromise::CreateAndResolve(true, __func__);
}