mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- nsTArray*: fully sync with AF, and use ActualAlloc::Successful (adaf2f742) - Bug 1182808 - Part 2: Remove AlignedFallibleTArray. r=padenot (e0f112fb4) - Bug 1182808 - Part 3: Rename AlignedTArray_Impl to AlignedTArray and remove existing AlignedTArray. r=padenot (ff2beea1e) - Bug 1148582 - Include the rounded clip of the async scrolled scroll frame in its mAncestorClip. (1633f8cb2) - Bug 1148582 - Support multiple mask layers per layer in LayerManagerComposite. (d292070f8) - Bug 1143575. #include nsDebug.h in YCbCrImageDataSerializer.cpp for NS_WARN_IF. r=nical (c9a7fe42c) - Bug 1143575. Remove ImageClientBridge::Updated. r=nical (095f1f806) - Bug 1143575. Pass a picture rect with OpUseOverlaySource and OpUseTexture, and eliminate OpUpdatePictureRect. r=nical (c134913c2) - Bug 1143575. Extend IPDL OpUseTexture to support multiple timestamped images. r=nical (54d018cd1) - Bug 1143575. Replace ImageClientSingle::UpdateImage's use of Image serial numbers with ImageContainer state generation counters, and switch it to use ImageContainer::GetCurrentImages. r=nical (e2e096ad2) - Bug 1143575. ImageClient::UpdateImage should not return false when there's no image, because recreating the ImageClient won't help. r=nical (4be2ed5ed) - Bug 1143575. Make ImageClientSingle handle multiple textures. r=nical (8889f2639) - Bug 1143575. Store composition time in Compositor. r=nical (1501cc5d0) - Bug 1143575. Implement ImageHost support for multiple timed images. r=nical (99a440556) - Bug 1168456 - Remove NotifyWaitingForResourcesStatusChanged() call from MediaCodecReader r=bholley,bwu (efabdbeed) - Bug 1163871: Use DebugOnly to suppress opt build warning in gonk nsAppShell.cpp. r=mwu (fc77b0322) - Bug 1165161 - stop bootAnim with "browser-ui-startup-complete" event. r=mwu (a2a9bbfdd) - Bug 949036 - Make ID3v2 tag detection more careful - not every bit of data containing ID3 is a tag. r=eflores (ac590bbd1) - bug 1137076 handle null mDecoder during Reader shutdown r=edwin (1507b0627) - Bug 1150322 - Fix duration parsing in MediaOmxReader - r=sotaro (93577cfea) - Bug 1112219 - Implement platform independent MediaResourceManager r=cpearce,bwu,nical (cc722ccf3) - Bug 1091037 - Raise ImageBridge thread priority r=gsvelto,nical (d66ecdd06) - Bug 1143575. Route ImageCompositeNotifications to ImageContainers. r=nical (fe5d3da61) - bug 1184801 process AnalyserNode input only when required r=padenot (8079b66f5) - Bug 1157768 - FFTBlock Changes for using libav fft; r=padenot (3238d710c) - bug 914392 move mSharedBuffers ownership to engine r=padenot (4444d8352)
This commit is contained in:
@@ -47,6 +47,7 @@ class RenderFrameChild;
|
||||
|
||||
namespace layers {
|
||||
class APZEventState;
|
||||
class ImageCompositeNotification;
|
||||
struct SetTargetAPZCCallback;
|
||||
struct SetAllowedTouchBehaviorCallback;
|
||||
}
|
||||
|
||||
@@ -178,36 +178,67 @@ MP3Parser::GetSamplesPerFrame()
|
||||
|
||||
const char sID3Head[3] = { 'I', 'D', '3' };
|
||||
const uint32_t ID3_HEADER_LENGTH = 10;
|
||||
const uint32_t ID3_FOOTER_LENGTH = 10;
|
||||
const uint8_t ID3_FOOTER_PRESENT = 0x10;
|
||||
|
||||
ID3Parser::ID3Parser()
|
||||
: mCurrentChar(0)
|
||||
, mVersion(0)
|
||||
, mFlags(0)
|
||||
, mHeaderLength(0)
|
||||
{ }
|
||||
|
||||
void
|
||||
ID3Parser::Reset()
|
||||
{
|
||||
mCurrentChar = mHeaderLength = 0;
|
||||
mCurrentChar = mVersion = mFlags = mHeaderLength = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
ID3Parser::ParseChar(char ch)
|
||||
{
|
||||
// First three bytes of an ID3v2 header must match the string "ID3".
|
||||
if (mCurrentChar < sizeof(sID3Head) / sizeof(*sID3Head)
|
||||
&& ch != sID3Head[mCurrentChar]) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// The last four bytes of the header is a 28-bit unsigned integer with the
|
||||
// high bit of each byte unset.
|
||||
if (mCurrentChar >= 6 && mCurrentChar < ID3_HEADER_LENGTH) {
|
||||
if (ch & 0x80) {
|
||||
goto fail;
|
||||
} else {
|
||||
switch (mCurrentChar) {
|
||||
// The first three bytes of an ID3v2 header must match the string "ID3".
|
||||
case 0: case 1: case 2:
|
||||
if (ch != sID3Head[mCurrentChar]) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
// The fourth and fifth bytes give the version, between 2 and 4.
|
||||
case 3:
|
||||
if (ch < '\2' || ch > '\4') {
|
||||
goto fail;
|
||||
}
|
||||
mVersion = uint8_t(ch);
|
||||
break;
|
||||
case 4:
|
||||
if (ch != '\0') {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
// The sixth byte gives the flags; valid flags depend on the version.
|
||||
case 5:
|
||||
if ((ch & (0xff >> mVersion)) != '\0') {
|
||||
goto fail;
|
||||
}
|
||||
mFlags = uint8_t(ch);
|
||||
break;
|
||||
// Bytes seven through ten give the sum of the byte length of the extended
|
||||
// header, the padding and the frames after unsynchronisation.
|
||||
// These bytes form a 28-bit integer, with the high bit of each byte unset.
|
||||
case 6: case 7: case 8: case 9:
|
||||
if (ch & 0x80) {
|
||||
goto fail;
|
||||
}
|
||||
mHeaderLength <<= 7;
|
||||
mHeaderLength |= ch;
|
||||
}
|
||||
if (mCurrentChar == 9) {
|
||||
mHeaderLength += ID3_HEADER_LENGTH;
|
||||
mHeaderLength += (mFlags & ID3_FOOTER_PRESENT) ? ID3_FOOTER_LENGTH : 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Header already fully parsed!");
|
||||
}
|
||||
|
||||
mCurrentChar++;
|
||||
@@ -215,6 +246,10 @@ ID3Parser::ParseChar(char ch)
|
||||
return IsParsed();
|
||||
|
||||
fail:
|
||||
if (mCurrentChar) {
|
||||
Reset();
|
||||
return ParseChar(ch);
|
||||
}
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ public:
|
||||
|
||||
private:
|
||||
uint32_t mCurrentChar;
|
||||
uint8_t mVersion;
|
||||
uint8_t mFlags;
|
||||
uint32_t mHeaderLength;
|
||||
};
|
||||
|
||||
|
||||
@@ -182,9 +182,6 @@ MediaDecoderReader::AsyncReadMetadata()
|
||||
mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn();
|
||||
DECODER_LOG("MediaDecoderReader::AsyncReadMetadata");
|
||||
|
||||
// PreReadMetadata causes us to try to allocate various hardware and OS
|
||||
// resources, which may not be available at the moment.
|
||||
PreReadMetadata();
|
||||
if (IsWaitingMediaResources()) {
|
||||
return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__);
|
||||
}
|
||||
|
||||
@@ -165,19 +165,16 @@ public:
|
||||
virtual bool HasVideo() = 0;
|
||||
|
||||
// The default implementation of AsyncReadMetadata is implemented in terms of
|
||||
// synchronous PreReadMetadata() / ReadMetadata() calls. Implementations may also
|
||||
// synchronous ReadMetadata() calls. Implementations may also
|
||||
// override AsyncReadMetadata to create a more proper async implementation.
|
||||
virtual nsRefPtr<MetadataPromise> AsyncReadMetadata();
|
||||
|
||||
// A function that is called before ReadMetadata() call.
|
||||
virtual void PreReadMetadata() {};
|
||||
|
||||
// Read header data for all bitstreams in the file. Fills aInfo with
|
||||
// the data required to present the media, and optionally fills *aTags
|
||||
// with tag metadata from the file.
|
||||
// Returns NS_OK on success, or NS_ERROR_FAILURE on failure.
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) = 0;
|
||||
MetadataTags** aTags) { MOZ_CRASH(); }
|
||||
|
||||
// Fills aInfo with the latest cached data required to present the media,
|
||||
// ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
|
||||
|
||||
@@ -55,13 +55,6 @@ public:
|
||||
}
|
||||
|
||||
virtual nsRefPtr<MetadataPromise> AsyncReadMetadata() override;
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) override
|
||||
{
|
||||
// Unused as we provide AsyncReadMetadataAPI.
|
||||
// However we must implement it as it's pure virtual.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual void ReadUpdatedMetadata(MediaInfo* aInfo) override;
|
||||
|
||||
|
||||
@@ -534,12 +534,16 @@ AppleMP3Reader::NotifyDataArrived(const char* aBuffer,
|
||||
}
|
||||
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
LOGD("Updating media duration to %lluus\n", duration);
|
||||
mDuration = duration;
|
||||
MOZ_ASSERT(mDecoder);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDuration = duration;
|
||||
mDecoder->UpdateEstimatedMediaDuration(duration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,15 +404,20 @@ void
|
||||
DirectShowReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mMP3FrameParser.NeedsData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
if (duration != mDuration) {
|
||||
mDuration = duration;
|
||||
MOZ_ASSERT(mDecoder);
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDuration = duration;
|
||||
mDecoder->UpdateEstimatedMediaDuration(mDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ if CONFIG['MOZ_WEBRTC']:
|
||||
|
||||
if CONFIG['MOZ_OMX_DECODER']:
|
||||
DIRS += ['omx']
|
||||
DIRS += ['omx/mediaresourcemanager']
|
||||
|
||||
TEST_DIRS += [
|
||||
'compiledtest',
|
||||
|
||||
@@ -99,36 +99,40 @@ MediaCodecProxy::MediaCodecProxy(sp<ALooper> aLooper,
|
||||
, mPendingRequestMediaResource(false)
|
||||
{
|
||||
MOZ_ASSERT(mCodecLooper != nullptr, "ALooper should not be nullptr.");
|
||||
mResourceHandler = new MediaResourceHandler(this);
|
||||
}
|
||||
|
||||
MediaCodecProxy::~MediaCodecProxy()
|
||||
{
|
||||
releaseCodec();
|
||||
SetMediaCodecFree();
|
||||
ReleaseMediaCodec();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaCodecProxy::AskMediaCodecAndWait()
|
||||
{
|
||||
if (mResourceHandler == nullptr) {
|
||||
if (mResourceClient || mCodec.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncasecmp(mCodecMime.get(), "video/", 6) == 0) {
|
||||
mResourceHandler->requestResource(mCodecEncoder
|
||||
? IMediaResourceManagerService::HW_VIDEO_ENCODER
|
||||
: IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
mozilla::MediaSystemResourceType type =
|
||||
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
|
||||
mozilla::MediaSystemResourceType::VIDEO_DECODER;
|
||||
mResourceClient = new mozilla::MediaSystemResourceClient(type);
|
||||
mResourceClient->SetListener(this);
|
||||
} else if (strncasecmp(mCodecMime.get(), "audio/", 6) == 0) {
|
||||
if (allocateCodec()) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (!mResourceClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::MonitorAutoLock mon(mMediaCodecLock);
|
||||
mPendingRequestMediaResource = true;
|
||||
// request video codec
|
||||
mResourceClient->Acquire();
|
||||
|
||||
while (mPendingRequestMediaResource) {
|
||||
mMediaCodecLock.Wait();
|
||||
@@ -141,21 +145,30 @@ MediaCodecProxy::AskMediaCodecAndWait()
|
||||
bool
|
||||
MediaCodecProxy::AsyncAskMediaCodec()
|
||||
{
|
||||
if ((strncasecmp(mCodecMime.get(), "video/", 6) != 0) ||
|
||||
(mResourceHandler == nullptr)) {
|
||||
if (mResourceClient || mCodec.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strncasecmp(mCodecMime.get(), "video/", 6) != 0) {
|
||||
return false;
|
||||
}
|
||||
// request video codec
|
||||
mResourceHandler->requestResource(mCodecEncoder
|
||||
? IMediaResourceManagerService::HW_VIDEO_ENCODER
|
||||
: IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
mozilla::MediaSystemResourceType type =
|
||||
mCodecEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
|
||||
mozilla::MediaSystemResourceType::VIDEO_DECODER;
|
||||
mResourceClient = new mozilla::MediaSystemResourceClient(type);
|
||||
mResourceClient->SetListener(this);
|
||||
mResourceClient->Acquire();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecProxy::SetMediaCodecFree()
|
||||
MediaCodecProxy::ReleaseMediaCodec()
|
||||
{
|
||||
if (mResourceHandler == nullptr) {
|
||||
releaseCodec();
|
||||
|
||||
if (!mResourceClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,8 +178,10 @@ MediaCodecProxy::SetMediaCodecFree()
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
mResourceHandler->cancelResource();
|
||||
mResourceHandler = nullptr;
|
||||
if (mResourceClient) {
|
||||
mResourceClient->ReleaseResource();
|
||||
mResourceClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -477,15 +492,19 @@ MediaCodecProxy::getCapability(uint32_t *aCapability)
|
||||
return OK;
|
||||
}
|
||||
|
||||
// Called on a Binder thread
|
||||
// Called on ImageBridge thread
|
||||
void
|
||||
MediaCodecProxy::resourceReserved()
|
||||
MediaCodecProxy::ResourceReserved()
|
||||
{
|
||||
MCP_LOG("resourceReserved");
|
||||
// Create MediaCodec
|
||||
releaseCodec();
|
||||
if (!allocateCodec()) {
|
||||
SetMediaCodecFree();
|
||||
ReleaseMediaCodec();
|
||||
// Notification
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->codecCanceled();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -501,6 +520,18 @@ MediaCodecProxy::resourceReserved()
|
||||
}
|
||||
}
|
||||
|
||||
// Called on ImageBridge thread
|
||||
void
|
||||
MediaCodecProxy::ResourceReserveFailed()
|
||||
{
|
||||
ReleaseMediaCodec();
|
||||
// Notification
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->codecCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaCodecProxy::Prepare()
|
||||
{
|
||||
|
||||
@@ -624,8 +655,7 @@ status_t MediaCodecProxy::Output(MediaBuffer** aBuffer, int64_t aTimeoutUs)
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaResources()
|
||||
{
|
||||
releaseCodec();
|
||||
SetMediaCodecFree()
|
||||
ReleaseMediaCodec();
|
||||
}
|
||||
|
||||
void MediaCodecProxy::ReleaseMediaBuffer(MediaBuffer* aBuffer) {
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#include <stagefright/MediaCodec.h>
|
||||
#include <stagefright/MediaBuffer.h>
|
||||
#include <utils/threads.h>
|
||||
#include "MediaResourceHandler.h"
|
||||
|
||||
#include "mozilla/media/MediaSystemResourceClient.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsRefPtr.h"
|
||||
|
||||
namespace android {
|
||||
// This class is intended to be a proxy for MediaCodec with codec resource
|
||||
@@ -21,7 +23,8 @@ namespace android {
|
||||
// MediaCodecReader.cpp. Another useage is to use configure(), Prepare(),
|
||||
// Input(), and Output(). It is used in GonkVideoDecoderManager.cpp which
|
||||
// doesn't need to handle the buffers for codec.
|
||||
class MediaCodecProxy : public MediaResourceHandler::ResourceListener
|
||||
class MediaCodecProxy : public RefBase
|
||||
, public mozilla::MediaSystemResourceReservationListener
|
||||
{
|
||||
public:
|
||||
/* Codec resource notification listener.
|
||||
@@ -137,6 +140,7 @@ public:
|
||||
|
||||
// It asks for the OMX codec and blocked until the resource is grant to be
|
||||
// allocated.
|
||||
// Audio codec allocation should use this.
|
||||
bool AskMediaCodecAndWait();
|
||||
|
||||
// It asks for the OMX codec asynchronously.
|
||||
@@ -144,15 +148,14 @@ public:
|
||||
bool AsyncAskMediaCodec();
|
||||
|
||||
// Free the OMX codec so others can allocate it.
|
||||
void SetMediaCodecFree();
|
||||
void ReleaseMediaCodec();
|
||||
|
||||
protected:
|
||||
virtual ~MediaCodecProxy();
|
||||
|
||||
// MediaResourceHandler::EventListener::resourceReserved()
|
||||
virtual void resourceReserved();
|
||||
// MediaResourceHandler::EventListener::resourceCanceled()
|
||||
virtual void resourceCanceled() {}
|
||||
// MediaResourceReservationListener
|
||||
void ResourceReserved() override;
|
||||
void ResourceReserveFailed() override;
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
@@ -180,7 +183,7 @@ private:
|
||||
wp<CodecResourceListener> mListener;
|
||||
|
||||
// Media Resource Management
|
||||
sp<MediaResourceHandler> mResourceHandler;
|
||||
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
|
||||
|
||||
// MediaCodec instance
|
||||
mutable RWLock mCodecLock;
|
||||
|
||||
@@ -269,7 +269,6 @@ MediaCodecReader::ProcessCachedDataTask::Run()
|
||||
MediaCodecReader::MediaCodecReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaOmxCommonReader(aDecoder)
|
||||
, mExtractor(nullptr)
|
||||
, mIsWaitingResources(false)
|
||||
, mTextureClientIndexesLock("MediaCodecReader::mTextureClientIndexesLock")
|
||||
, mColorConverterBufferSize(0)
|
||||
, mParserMonitor("MediaCodecReader::mParserMonitor")
|
||||
@@ -290,19 +289,6 @@ MediaCodecReader::Init(MediaDecoderReader* aCloneDonor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaCodecReader::IsWaitingMediaResources()
|
||||
{
|
||||
return mIsWaitingResources;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::UpdateIsWaitingMediaResources()
|
||||
{
|
||||
mIsWaitingResources = (mVideoTrack.mCodec != nullptr) &&
|
||||
(!mVideoTrack.mCodec->allocated());
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::ReleaseMediaResources()
|
||||
{
|
||||
@@ -648,58 +634,66 @@ MediaCodecReader::ParseDataSegment(const char* aBuffer,
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::PreReadMetadata()
|
||||
{
|
||||
UpdateIsWaitingMediaResources();
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise>
|
||||
MediaCodecReader::AsyncReadMetadata()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
if (!ReallocateResources()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
if (!ReallocateExtractorResources()) {
|
||||
return MediaDecoderReader::MetadataPromise::CreateAndReject(
|
||||
ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
}
|
||||
|
||||
bool incrementalParserNeeded =
|
||||
mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
|
||||
if (incrementalParserNeeded && !TriggerIncrementalParser()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return MediaDecoderReader::MetadataPromise::CreateAndReject(
|
||||
ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
}
|
||||
|
||||
// Bug 1050667, both MediaDecoderStateMachine and MediaCodecReader
|
||||
// relies on IsWaitingMediaResources() function. And the waiting state will be
|
||||
// changed by binder thread, so we store the waiting state in a cache value to
|
||||
// make them in the same waiting state.
|
||||
UpdateIsWaitingMediaResources();
|
||||
if (IsWaitingMediaResources()) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
|
||||
|
||||
nsRefPtr<MediaCodecReader> self = this;
|
||||
mMediaResourceRequest.Begin(CreateMediaCodecs()
|
||||
->RefableThen(GetTaskQueue(), __func__,
|
||||
[self] (bool) -> void {
|
||||
self->mMediaResourceRequest.Complete();
|
||||
self->HandleResourceAllocated();
|
||||
}, [self] (bool) -> void {
|
||||
self->mMediaResourceRequest.Complete();
|
||||
self->mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
}));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
MediaCodecReader::HandleResourceAllocated()
|
||||
{
|
||||
// Configure video codec after the codecReserved.
|
||||
if (mVideoTrack.mSource != nullptr) {
|
||||
if (!ConfigureMediaCodec(mVideoTrack)) {
|
||||
DestroyMediaCodec(mVideoTrack);
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: start streaming
|
||||
|
||||
if (!UpdateDuration()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UpdateAudioInfo()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UpdateVideoInfo()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the total duration (the max of the audio and video track).
|
||||
@@ -727,14 +721,15 @@ MediaCodecReader::ReadMetadata(MediaInfo* aInfo,
|
||||
mozilla::TimeStamp::Now());
|
||||
}
|
||||
|
||||
*aInfo = mInfo;
|
||||
*aTags = nullptr;
|
||||
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
|
||||
metadata->mInfo = mInfo;
|
||||
metadata->mTags = nullptr;
|
||||
|
||||
#ifdef MOZ_AUDIO_OFFLOAD
|
||||
CheckAudioOffload();
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
mMetadataPromise.Resolve(metadata, __func__);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -1081,13 +1076,12 @@ MediaCodecReader::GetAudioOffloadTrack()
|
||||
}
|
||||
|
||||
bool
|
||||
MediaCodecReader::ReallocateResources()
|
||||
MediaCodecReader::ReallocateExtractorResources()
|
||||
{
|
||||
if (CreateLooper() &&
|
||||
CreateExtractor() &&
|
||||
CreateMediaSources() &&
|
||||
CreateTaskQueues() &&
|
||||
CreateMediaCodecs()) {
|
||||
CreateTaskQueues()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1098,6 +1092,10 @@ MediaCodecReader::ReallocateResources()
|
||||
void
|
||||
MediaCodecReader::ReleaseCriticalResources()
|
||||
{
|
||||
mMediaResourceRequest.DisconnectIfExists();
|
||||
mMediaResourcePromise.RejectIfExists(true, __func__);
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
|
||||
ResetDecode();
|
||||
// Before freeing a video codec, all video buffers needed to be released
|
||||
// even from graphics pipeline.
|
||||
@@ -1293,21 +1291,35 @@ MediaCodecReader::CreateTaskQueues()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsRefPtr<MediaOmxCommonReader::MediaResourcePromise>
|
||||
MediaCodecReader::CreateMediaCodecs()
|
||||
{
|
||||
if (CreateMediaCodec(mLooper, mAudioTrack, false, nullptr) &&
|
||||
CreateMediaCodec(mLooper, mVideoTrack, true, mVideoListener)) {
|
||||
return true;
|
||||
bool isWaiting = false;
|
||||
nsRefPtr<MediaResourcePromise> p = mMediaResourcePromise.Ensure(__func__);
|
||||
|
||||
if (!CreateMediaCodec(mLooper, mAudioTrack, false, isWaiting, nullptr)) {
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!CreateMediaCodec(mLooper, mVideoTrack, true, isWaiting, mVideoListener)) {
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
}
|
||||
|
||||
if (!isWaiting) {
|
||||
// No MediaCodec allocation wait.
|
||||
mMediaResourcePromise.Resolve(true, __func__);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
Track& aTrack,
|
||||
bool aAsync,
|
||||
bool& aIsWaiting,
|
||||
wp<MediaCodecProxy::CodecResourceListener> aListener)
|
||||
{
|
||||
if (aTrack.mSource != nullptr && aTrack.mCodec == nullptr) {
|
||||
@@ -1352,10 +1364,14 @@ MediaCodecReader::CreateMediaCodec(sp<ALooper>& aLooper,
|
||||
DestroyMediaCodec(aTrack);
|
||||
return false;
|
||||
}
|
||||
} else if (aAsync && !aTrack.mCodec->AsyncAskMediaCodec()) {
|
||||
NS_WARNING("Couldn't request MediaCodec asynchronously");
|
||||
DestroyMediaCodec(aTrack);
|
||||
return false;
|
||||
} else if (aAsync) {
|
||||
if (aTrack.mCodec->AsyncAskMediaCodec()) {
|
||||
aIsWaiting = true;
|
||||
} else {
|
||||
NS_WARNING("Couldn't request MediaCodec asynchronously");
|
||||
DestroyMediaCodec(aTrack);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1921,18 +1937,14 @@ MediaCodecReader::ClearColorConverterBuffer()
|
||||
void
|
||||
MediaCodecReader::VideoCodecReserved()
|
||||
{
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
mMediaResourcePromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
|
||||
// Called on Binder thread.
|
||||
void
|
||||
MediaCodecReader::VideoCodecCanceled()
|
||||
{
|
||||
if (mVideoTrack.mTaskQueue) {
|
||||
RefPtr<nsIRunnable> task =
|
||||
NS_NewRunnableMethod(this, &MediaCodecReader::ReleaseCriticalResources);
|
||||
mVideoTrack.mTaskQueue->Dispatch(task.forget());
|
||||
}
|
||||
mMediaResourcePromise.RejectIfExists(true, __func__);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -52,6 +52,7 @@ class MediaCodecReader : public MediaOmxCommonReader
|
||||
{
|
||||
typedef mozilla::layers::TextureClient TextureClient;
|
||||
typedef mozilla::layers::FenceHandle FenceHandle;
|
||||
typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
|
||||
|
||||
public:
|
||||
MediaCodecReader(AbstractMediaDecoder* aDecoder);
|
||||
@@ -61,9 +62,6 @@ public:
|
||||
// on failure.
|
||||
virtual nsresult Init(MediaDecoderReader* aCloneDonor);
|
||||
|
||||
// True if this reader is waiting media resource allocation
|
||||
virtual bool IsWaitingMediaResources();
|
||||
|
||||
// True when this reader need to become dormant state
|
||||
virtual bool IsDormantNeeded() { return true;}
|
||||
|
||||
@@ -94,13 +92,7 @@ public:
|
||||
virtual bool HasAudio();
|
||||
virtual bool HasVideo();
|
||||
|
||||
virtual void PreReadMetadata() override;
|
||||
// Read header data for all bitstreams in the file. Fills aInfo with
|
||||
// the data required to present the media, and optionally fills *aTags
|
||||
// with tag metadata from the file.
|
||||
// Returns NS_OK on success, or NS_ERROR_FAILURE on failure.
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
|
||||
|
||||
// Moves the decode head to aTime microseconds. aStartTime and aEndTime
|
||||
// denote the start and end times of the media in usecs, and aCurrentTime
|
||||
@@ -184,16 +176,17 @@ protected:
|
||||
|
||||
virtual bool CreateExtractor();
|
||||
|
||||
// Check the underlying HW resource is available and store the result in
|
||||
// mIsWaitingResources.
|
||||
void UpdateIsWaitingMediaResources();
|
||||
virtual void HandleResourceAllocated();
|
||||
|
||||
android::sp<android::MediaExtractor> mExtractor;
|
||||
// A cache value updated by UpdateIsWaitingMediaResources(), makes the
|
||||
// "waiting resources state" is synchronous to StateMachine.
|
||||
bool mIsWaitingResources;
|
||||
|
||||
MediaPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
|
||||
// XXX Remove after bug 1168008 land.
|
||||
MediaPromiseConsumerHolder<MediaResourcePromise> mMediaResourceRequest;
|
||||
MediaPromiseHolder<MediaResourcePromise> mMediaResourcePromise;
|
||||
|
||||
private:
|
||||
|
||||
// An intermediary class that can be managed by android::sp<T>.
|
||||
// Redirect codecReserved() and codecCanceled() to MediaCodecReader.
|
||||
class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
|
||||
@@ -336,7 +329,7 @@ private:
|
||||
MediaCodecReader() = delete;
|
||||
const MediaCodecReader& operator=(const MediaCodecReader& rhs) = delete;
|
||||
|
||||
bool ReallocateResources();
|
||||
bool ReallocateExtractorResources();
|
||||
void ReleaseCriticalResources();
|
||||
void ReleaseResources();
|
||||
|
||||
@@ -348,10 +341,11 @@ private:
|
||||
bool CreateMediaSources();
|
||||
void DestroyMediaSources();
|
||||
|
||||
bool CreateMediaCodecs();
|
||||
nsRefPtr<MediaResourcePromise> CreateMediaCodecs();
|
||||
static bool CreateMediaCodec(android::sp<android::ALooper>& aLooper,
|
||||
Track& aTrack,
|
||||
bool aAsync,
|
||||
bool& aIsWaiting,
|
||||
android::wp<android::MediaCodecProxy::CodecResourceListener> aListener);
|
||||
static bool ConfigureMediaCodec(Track& aTrack);
|
||||
void DestroyMediaCodecs();
|
||||
|
||||
@@ -24,6 +24,8 @@ class AbstractMediaDecoder;
|
||||
class MediaOmxCommonReader : public MediaDecoderReader
|
||||
{
|
||||
public:
|
||||
typedef MediaPromise<bool /* aIgnored */, bool /* aIgnored */, /* IsExclusive = */ true> MediaResourcePromise;
|
||||
|
||||
MediaOmxCommonReader(AbstractMediaDecoder* aDecoder);
|
||||
|
||||
void SetAudioChannel(dom::AudioChannel aAudioChannel) {
|
||||
|
||||
@@ -124,26 +124,17 @@ private:
|
||||
uint64_t mFullLength;
|
||||
};
|
||||
|
||||
void MediaOmxReader::CancelProcessCachedData()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MutexAutoLock lock(mMutex);
|
||||
mIsShutdown = true;
|
||||
}
|
||||
|
||||
MediaOmxReader::MediaOmxReader(AbstractMediaDecoder *aDecoder)
|
||||
: MediaOmxCommonReader(aDecoder)
|
||||
, mMutex("MediaOmxReader.Data")
|
||||
, mShutdownMutex("MediaOmxReader.Shutdown")
|
||||
, mHasVideo(false)
|
||||
, mHasAudio(false)
|
||||
, mVideoSeekTimeUs(-1)
|
||||
, mAudioSeekTimeUs(-1)
|
||||
, mLastParserDuration(-1)
|
||||
, mSkipCount(0)
|
||||
, mUseParserDuration(false)
|
||||
, mIsShutdown(false)
|
||||
, mMP3FrameParser(-1)
|
||||
, mIsWaitingResources(false)
|
||||
{
|
||||
if (!gMediaDecoderLog) {
|
||||
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
||||
@@ -161,6 +152,16 @@ nsresult MediaOmxReader::Init(MediaDecoderReader* aCloneDonor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<AbstractMediaDecoder>
|
||||
MediaOmxReader::SafeGetDecoder() {
|
||||
nsRefPtr<AbstractMediaDecoder> decoder;
|
||||
MutexAutoLock lock(mShutdownMutex);
|
||||
if (!mIsShutdown) {
|
||||
decoder = mDecoder;
|
||||
}
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
void MediaOmxReader::ReleaseDecoder()
|
||||
{
|
||||
if (mOmxDecoder.get()) {
|
||||
@@ -172,9 +173,10 @@ void MediaOmxReader::ReleaseDecoder()
|
||||
nsRefPtr<ShutdownPromise>
|
||||
MediaOmxReader::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> cancelEvent =
|
||||
NS_NewRunnableMethod(this, &MediaOmxReader::CancelProcessCachedData);
|
||||
NS_DispatchToMainThread(cancelEvent);
|
||||
{
|
||||
MutexAutoLock lock(mShutdownMutex);
|
||||
mIsShutdown = true;
|
||||
}
|
||||
|
||||
nsRefPtr<ShutdownPromise> p = MediaDecoderReader::Shutdown();
|
||||
|
||||
@@ -185,22 +187,11 @@ MediaOmxReader::Shutdown()
|
||||
return p;
|
||||
}
|
||||
|
||||
bool MediaOmxReader::IsWaitingMediaResources()
|
||||
{
|
||||
return mIsWaitingResources;
|
||||
}
|
||||
|
||||
void MediaOmxReader::UpdateIsWaitingMediaResources()
|
||||
{
|
||||
if (mOmxDecoder.get()) {
|
||||
mIsWaitingResources = mOmxDecoder->IsWaitingMediaResources();
|
||||
} else {
|
||||
mIsWaitingResources = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaOmxReader::ReleaseMediaResources()
|
||||
{
|
||||
mMediaResourceRequest.DisconnectIfExists();
|
||||
mMetadataPromise.RejectIfExists(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
|
||||
ResetDecode();
|
||||
// Before freeing a video codec, all video buffers needed to be released
|
||||
// even from graphics pipeline.
|
||||
@@ -235,23 +226,17 @@ nsresult MediaOmxReader::InitOmxDecoder()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaOmxReader::PreReadMetadata()
|
||||
{
|
||||
UpdateIsWaitingMediaResources();
|
||||
}
|
||||
|
||||
nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise>
|
||||
MediaOmxReader::AsyncReadMetadata()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
EnsureActive();
|
||||
|
||||
*aTags = nullptr;
|
||||
|
||||
// Initialize the internal OMX Decoder.
|
||||
nsresult rv = InitOmxDecoder();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
return MediaDecoderReader::MetadataPromise::CreateAndReject(
|
||||
ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
}
|
||||
|
||||
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
|
||||
@@ -263,32 +248,44 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
ProcessCachedData(0, true);
|
||||
}
|
||||
|
||||
if (!mOmxDecoder->AllocateMediaResources()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Bug 1050667, both MediaDecoderStateMachine and MediaOmxReader
|
||||
// relies on IsWaitingMediaResources() function. And the waiting state will be
|
||||
// changed by binder thread, so we store the waiting state in a cache value to
|
||||
// make them in consistent state.
|
||||
UpdateIsWaitingMediaResources();
|
||||
if (IsWaitingMediaResources()) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise> p = mMetadataPromise.Ensure(__func__);
|
||||
|
||||
nsRefPtr<MediaOmxReader> self = this;
|
||||
mMediaResourceRequest.Begin(mOmxDecoder->AllocateMediaResources()
|
||||
->RefableThen(GetTaskQueue(), __func__,
|
||||
[self] (bool) -> void {
|
||||
self->mMediaResourceRequest.Complete();
|
||||
self->HandleResourceAllocated();
|
||||
}, [self] (bool) -> void {
|
||||
self->mMediaResourceRequest.Complete();
|
||||
self->mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
}));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void MediaOmxReader::HandleResourceAllocated()
|
||||
{
|
||||
EnsureActive();
|
||||
|
||||
// After resources are available, set the metadata.
|
||||
if (!mOmxDecoder->EnsureMetadata()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3);
|
||||
if (isMP3 && mMP3FrameParser.IsMP3()) {
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
// The MP3FrameParser may reported a duration;
|
||||
// return -1 if no frame has been parsed.
|
||||
if (duration >= 0) {
|
||||
mUseParserDuration = true;
|
||||
mLastParserDuration = duration;
|
||||
mInfo.mMetadataDuration = Some(TimeUnit::FromMicroseconds(mLastParserDuration));
|
||||
}
|
||||
// Check if the MP3 frame parser found a duration.
|
||||
mLastParserDuration = mMP3FrameParser.GetDuration();
|
||||
}
|
||||
|
||||
if (mLastParserDuration >= 0) {
|
||||
// Prefer the parser duration if we have it.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
mDecoder->SetMediaDuration(mLastParserDuration);
|
||||
} else {
|
||||
// MP3 parser failed to find a duration.
|
||||
// Set the total duration (the max of the audio and video track).
|
||||
int64_t durationUs;
|
||||
mOmxDecoder->GetDuration(&durationUs);
|
||||
@@ -308,7 +305,8 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
nsIntSize displaySize(displayWidth, displayHeight);
|
||||
nsIntSize frameSize(width, height);
|
||||
if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Video track's frame sizes will not overflow. Activate the video track.
|
||||
@@ -332,13 +330,15 @@ nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo,
|
||||
mInfo.mAudio.mRate = sampleRate;
|
||||
}
|
||||
|
||||
*aInfo = mInfo;
|
||||
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
|
||||
metadata->mInfo = mInfo;
|
||||
metadata->mTags = nullptr;
|
||||
|
||||
#ifdef MOZ_AUDIO_OFFLOAD
|
||||
CheckAudioOffload();
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
mMetadataPromise.Resolve(metadata, __func__);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -472,23 +472,27 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
void MediaOmxReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (IsShutdown()) {
|
||||
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
|
||||
if (!decoder) { // reader has shut down
|
||||
return;
|
||||
}
|
||||
if (HasVideo()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mMP3FrameParser.NeedsData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
|
||||
if (!mMP3FrameParser.IsMP3()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t duration = mMP3FrameParser.GetDuration();
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (duration != mLastParserDuration && mUseParserDuration) {
|
||||
if (duration != mLastParserDuration) {
|
||||
ReentrantMonitorAutoEnter mon(decoder->GetReentrantMonitor());
|
||||
mLastParserDuration = duration;
|
||||
mDecoder->UpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
decoder->UpdateEstimatedMediaDuration(mLastParserDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,7 +578,8 @@ void MediaOmxReader::EnsureActive() {
|
||||
int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
|
||||
{
|
||||
// Could run on decoder thread or IO thread.
|
||||
if (IsShutdown()) {
|
||||
nsRefPtr<AbstractMediaDecoder> decoder = SafeGetDecoder();
|
||||
if (!decoder) { // reader has shut down
|
||||
return -1;
|
||||
}
|
||||
// We read data in chunks of 32 KiB. We can reduce this
|
||||
@@ -585,8 +590,8 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
|
||||
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
|
||||
|
||||
MOZ_ASSERT(mDecoder->GetResource());
|
||||
int64_t resourceLength = mDecoder->GetResource()->GetCachedDataEnd(0);
|
||||
MOZ_ASSERT(decoder->GetResource());
|
||||
int64_t resourceLength = decoder->GetResource()->GetCachedDataEnd(0);
|
||||
NS_ENSURE_TRUE(resourceLength >= 0, -1);
|
||||
|
||||
if (aOffset >= resourceLength) {
|
||||
@@ -597,7 +602,7 @@ int64_t MediaOmxReader::ProcessCachedData(int64_t aOffset, bool aWaitForCompleti
|
||||
|
||||
nsAutoArrayPtr<char> buffer(new char[bufferLength]);
|
||||
|
||||
nsresult rv = mDecoder->GetResource()->ReadFromCache(buffer.get(),
|
||||
nsresult rv = decoder->GetResource()->ReadFromCache(buffer.get(),
|
||||
aOffset, bufferLength);
|
||||
NS_ENSURE_SUCCESS(rv, -1);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "nsMimeTypes.h"
|
||||
#include "MP3FrameParser.h"
|
||||
#include "nsRect.h"
|
||||
|
||||
#include <ui/GraphicBuffer.h>
|
||||
#include <stagefright/MediaSource.h>
|
||||
|
||||
@@ -26,8 +27,11 @@ class AbstractMediaDecoder;
|
||||
|
||||
class MediaOmxReader : public MediaOmxCommonReader
|
||||
{
|
||||
// This flag protect the mIsShutdown variable, that may access by decoder / main / IO thread.
|
||||
Mutex mMutex;
|
||||
typedef MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
|
||||
|
||||
// This mutex is held when accessing the mIsShutdown variable, which is
|
||||
// modified on the decode task queue and read on main and IO threads.
|
||||
Mutex mShutdownMutex;
|
||||
nsCString mType;
|
||||
bool mHasVideo;
|
||||
bool mHasAudio;
|
||||
@@ -37,17 +41,16 @@ class MediaOmxReader : public MediaOmxCommonReader
|
||||
int64_t mAudioSeekTimeUs;
|
||||
int64_t mLastParserDuration;
|
||||
int32_t mSkipCount;
|
||||
bool mUseParserDuration;
|
||||
// If mIsShutdown is false, and mShutdownMutex is held, then
|
||||
// AbstractMediaDecoder::mDecoder will be non-null.
|
||||
bool mIsShutdown;
|
||||
MediaPromiseHolder<MediaDecoderReader::MetadataPromise> mMetadataPromise;
|
||||
MediaPromiseConsumerHolder<MediaResourcePromise> mMediaResourceRequest;
|
||||
protected:
|
||||
android::sp<android::OmxDecoder> mOmxDecoder;
|
||||
android::sp<android::MediaExtractor> mExtractor;
|
||||
MP3FrameParser mMP3FrameParser;
|
||||
|
||||
// A cache value updated by UpdateIsWaitingMediaResources(), makes the
|
||||
// "waiting resources state" is synchronous to StateMachine.
|
||||
bool mIsWaitingResources;
|
||||
|
||||
// Called by ReadMetadata() during MediaDecoderStateMachine::DecodeMetadata()
|
||||
// on decode thread. It create and initialize the OMX decoder including
|
||||
// setting up custom extractor. The extractor provide the essential
|
||||
@@ -58,10 +61,7 @@ protected:
|
||||
// to activate the decoder automatically.
|
||||
virtual void EnsureActive();
|
||||
|
||||
// Check the underlying HW resources are available and store the result in
|
||||
// mIsWaitingResources. The result might be changed by binder thread,
|
||||
// Can only called by ReadMetadata.
|
||||
void UpdateIsWaitingMediaResources();
|
||||
virtual void HandleResourceAllocated();
|
||||
|
||||
public:
|
||||
MediaOmxReader(AbstractMediaDecoder* aDecoder);
|
||||
@@ -85,15 +85,11 @@ public:
|
||||
return mHasVideo;
|
||||
}
|
||||
|
||||
// Return mIsWaitingResources.
|
||||
virtual bool IsWaitingMediaResources() override;
|
||||
|
||||
virtual bool IsDormantNeeded() { return true;}
|
||||
virtual void ReleaseMediaResources();
|
||||
|
||||
virtual void PreReadMetadata() override;
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags);
|
||||
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata() override;
|
||||
|
||||
virtual nsRefPtr<SeekPromise>
|
||||
Seek(int64_t aTime, int64_t aEndTime) override;
|
||||
|
||||
@@ -104,7 +100,7 @@ public:
|
||||
virtual nsRefPtr<ShutdownPromise> Shutdown() override;
|
||||
|
||||
bool IsShutdown() {
|
||||
MutexAutoLock lock(mMutex);
|
||||
MutexAutoLock lock(mShutdownMutex);
|
||||
return mIsShutdown;
|
||||
}
|
||||
|
||||
@@ -112,9 +108,10 @@ public:
|
||||
|
||||
int64_t ProcessCachedData(int64_t aOffset, bool aWaitForCompletion);
|
||||
|
||||
void CancelProcessCachedData();
|
||||
|
||||
android::sp<android::MediaSource> GetAudioOffloadTrack();
|
||||
|
||||
private:
|
||||
already_AddRefed<AbstractMediaDecoder> SafeGetDecoder();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
||||
#include "OMXCodecProxy.h"
|
||||
|
||||
namespace android {
|
||||
@@ -60,13 +58,13 @@ OMXCodecProxy::OMXCodecProxy(
|
||||
mFlags(flags),
|
||||
mNativeWindow(nativeWindow),
|
||||
mSource(source),
|
||||
mState(MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE)
|
||||
mState(ResourceState::START)
|
||||
{
|
||||
}
|
||||
|
||||
OMXCodecProxy::~OMXCodecProxy()
|
||||
{
|
||||
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
|
||||
mState = ResourceState::END;
|
||||
|
||||
if (mOMXCodec.get()) {
|
||||
wp<MediaSource> tmp = mOMXCodec;
|
||||
@@ -79,8 +77,9 @@ OMXCodecProxy::~OMXCodecProxy()
|
||||
// Complete all pending Binder ipc transactions
|
||||
IPCThreadState::self()->flushCommands();
|
||||
|
||||
if (mManagerService.get() && mClient.get()) {
|
||||
mManagerService->cancelClient(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER);
|
||||
if (mResourceClient) {
|
||||
mResourceClient->ReleaseResource();
|
||||
mResourceClient = nullptr;
|
||||
}
|
||||
|
||||
mSource.clear();
|
||||
@@ -88,25 +87,25 @@ OMXCodecProxy::~OMXCodecProxy()
|
||||
mComponentName = nullptr;
|
||||
}
|
||||
|
||||
MediaResourceManagerClient::State OMXCodecProxy::getState()
|
||||
void OMXCodecProxy::setListener(const wp<CodecResourceListener>& listener)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
return mState;
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
void OMXCodecProxy::setEventListener(const wp<OMXCodecProxy::EventListener>& listener)
|
||||
void OMXCodecProxy::notifyResourceReserved()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
mEventListener = listener;
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->codecReserved();
|
||||
}
|
||||
}
|
||||
|
||||
void OMXCodecProxy::notifyStatusChangedLocked()
|
||||
void OMXCodecProxy::notifyResourceCanceled()
|
||||
{
|
||||
if (mEventListener != nullptr) {
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->statusChanged();
|
||||
}
|
||||
sp<CodecResourceListener> listener = mListener.promote();
|
||||
if (listener != nullptr) {
|
||||
listener->codecCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,45 +113,32 @@ void OMXCodecProxy::requestResource()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mClient.get()) {
|
||||
if (mResourceClient) {
|
||||
return;
|
||||
}
|
||||
sp<MediaResourceManagerClient::EventListener> listener = this;
|
||||
mClient = new MediaResourceManagerClient(listener);
|
||||
mState = ResourceState::WAITING;
|
||||
|
||||
mManagerService = mClient->getMediaResourceManagerService();
|
||||
if (!mManagerService.get()) {
|
||||
mClient = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mManagerService->requestMediaResource(mClient, IMediaResourceManagerService::HW_VIDEO_DECODER, true /* will wait */);
|
||||
mozilla::MediaSystemResourceType type = mIsEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
|
||||
mozilla::MediaSystemResourceType::VIDEO_DECODER;
|
||||
mResourceClient = new mozilla::MediaSystemResourceClient(type);
|
||||
mResourceClient->SetListener(this);
|
||||
mResourceClient->Acquire();
|
||||
}
|
||||
|
||||
bool OMXCodecProxy::IsWaitingResources()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
return mState == MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE;
|
||||
}
|
||||
|
||||
// called on Binder ipc thread
|
||||
void OMXCodecProxy::statusChanged(int event)
|
||||
// Called on ImageBridge thread
|
||||
void
|
||||
OMXCodecProxy::ResourceReserved()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_WAIT_FOR_RESOURCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
mState = (MediaResourceManagerClient::State) event;
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::WAITING) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *mime;
|
||||
if (!mSrcMeta->findCString(kKeyMIMEType, &mime)) {
|
||||
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
|
||||
notifyStatusChangedLocked();
|
||||
mState = ResourceState::END;
|
||||
notifyResourceCanceled();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,8 +146,8 @@ void OMXCodecProxy::statusChanged(int event)
|
||||
sp<MediaSource> codec;
|
||||
mOMXCodec = OMXCodec::Create(mOMX, mSrcMeta, mIsEncoder, mSource, mComponentName, mFlags, mNativeWindow);
|
||||
if (mOMXCodec == nullptr) {
|
||||
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
|
||||
notifyStatusChangedLocked();
|
||||
mState = ResourceState::END;
|
||||
notifyResourceCanceled();
|
||||
return;
|
||||
}
|
||||
// Check if this video is sized such that we're comfortable
|
||||
@@ -181,27 +167,37 @@ void OMXCodecProxy::statusChanged(int event)
|
||||
printf_stderr("Failed to get video size, or it was too large for HW decoder (<w=%d, h=%d> but <maxW=%d, maxH=%d>)",
|
||||
width, height, maxWidth, maxHeight);
|
||||
mOMXCodec.clear();
|
||||
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
|
||||
notifyStatusChangedLocked();
|
||||
mState = ResourceState::END;
|
||||
notifyResourceCanceled();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOMXCodec->start() != OK) {
|
||||
NS_WARNING("Couldn't start OMX video source");
|
||||
mOMXCodec.clear();
|
||||
mState = MediaResourceManagerClient::CLIENT_STATE_SHUTDOWN;
|
||||
notifyStatusChangedLocked();
|
||||
mState = ResourceState::END;
|
||||
notifyResourceCanceled();
|
||||
return;
|
||||
}
|
||||
}
|
||||
notifyStatusChangedLocked();
|
||||
|
||||
mState = ResourceState::ACQUIRED;
|
||||
notifyResourceReserved();
|
||||
}
|
||||
|
||||
// Called on ImageBridge thread
|
||||
void
|
||||
OMXCodecProxy::ResourceReserveFailed()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
mState = ResourceState::NOT_ACQUIRED;
|
||||
}
|
||||
|
||||
status_t OMXCodecProxy::start(MetaData *params)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::ACQUIRED) {
|
||||
return NO_INIT;
|
||||
}
|
||||
CHECK(mOMXCodec.get() != nullptr);
|
||||
@@ -212,7 +208,7 @@ status_t OMXCodecProxy::stop()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::ACQUIRED) {
|
||||
return NO_INIT;
|
||||
}
|
||||
CHECK(mOMXCodec.get() != nullptr);
|
||||
@@ -223,7 +219,7 @@ sp<MetaData> OMXCodecProxy::getFormat()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::ACQUIRED) {
|
||||
sp<MetaData> meta = new MetaData;
|
||||
return meta;
|
||||
}
|
||||
@@ -235,7 +231,7 @@ status_t OMXCodecProxy::read(MediaBuffer **buffer, const ReadOptions *options)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::ACQUIRED) {
|
||||
return NO_INIT;
|
||||
}
|
||||
CHECK(mOMXCodec.get() != nullptr);
|
||||
@@ -246,7 +242,7 @@ status_t OMXCodecProxy::pause()
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
if (mState != MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
if (mState != ResourceState::ACQUIRED) {
|
||||
return NO_INIT;
|
||||
}
|
||||
CHECK(mOMXCodec.get() != nullptr);
|
||||
|
||||
@@ -13,18 +13,39 @@
|
||||
#include <stagefright/MediaSource.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
#include "mozilla/media/MediaSystemResourceClient.h"
|
||||
#include "nsRefPtr.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct MetaData;
|
||||
|
||||
class OMXCodecProxy : public MediaSource,
|
||||
public MediaResourceManagerClient::EventListener
|
||||
class OMXCodecProxy : public MediaSource
|
||||
, public mozilla::MediaSystemResourceReservationListener
|
||||
{
|
||||
public:
|
||||
struct EventListener : public virtual RefBase {
|
||||
virtual void statusChanged() = 0;
|
||||
/* Codec resource notification listener.
|
||||
* All functions are called on the Binder thread.
|
||||
*/
|
||||
struct CodecResourceListener : public virtual RefBase {
|
||||
/* The codec resource is reserved and can be granted.
|
||||
* The client can allocate the requested resource.
|
||||
*/
|
||||
virtual void codecReserved() = 0;
|
||||
/* The codec resource is not reserved any more.
|
||||
* The client should release the resource as soon as possible if the
|
||||
* resource is still being held.
|
||||
*/
|
||||
virtual void codecCanceled() = 0;
|
||||
};
|
||||
|
||||
// Enumeration for the valid resource allcoation states
|
||||
enum class ResourceState : int8_t {
|
||||
START,
|
||||
WAITING,
|
||||
ACQUIRED,
|
||||
NOT_ACQUIRED,
|
||||
END
|
||||
};
|
||||
|
||||
static sp<OMXCodecProxy> Create(
|
||||
@@ -35,15 +56,13 @@ public:
|
||||
uint32_t flags = 0,
|
||||
const sp<ANativeWindow> &nativeWindow = nullptr);
|
||||
|
||||
MediaResourceManagerClient::State getState();
|
||||
|
||||
void setEventListener(const wp<EventListener>& listener);
|
||||
void setListener(const wp<CodecResourceListener>& listener);
|
||||
|
||||
void requestResource();
|
||||
bool IsWaitingResources();
|
||||
|
||||
// MediaResourceManagerClient::EventListener
|
||||
virtual void statusChanged(int event);
|
||||
// MediaSystemResourceReservationListener
|
||||
void ResourceReserved() override;
|
||||
void ResourceReserveFailed() override;
|
||||
|
||||
// MediaSource
|
||||
virtual status_t start(MetaData *params = nullptr);
|
||||
@@ -68,6 +87,9 @@ protected:
|
||||
|
||||
virtual ~OMXCodecProxy();
|
||||
|
||||
void notifyResourceReserved();
|
||||
void notifyResourceCanceled();
|
||||
|
||||
void notifyStatusChangedLocked();
|
||||
|
||||
private:
|
||||
@@ -87,11 +109,12 @@ private:
|
||||
sp<MediaSource> mSource;
|
||||
|
||||
sp<MediaSource> mOMXCodec;
|
||||
sp<MediaResourceManagerClient> mClient;
|
||||
MediaResourceManagerClient::State mState;
|
||||
|
||||
sp<IMediaResourceManagerService> mManagerService;
|
||||
wp<OMXCodecProxy::EventListener> mEventListener;
|
||||
nsRefPtr<mozilla::MediaSystemResourceClient> mResourceClient;
|
||||
ResourceState mState;
|
||||
|
||||
// Codec Resource Notification Listener
|
||||
wp<CodecResourceListener> mListener;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "AudioChannelFormat.h"
|
||||
#include "GrallocImages.h"
|
||||
#include <mozilla/Monitor.h>
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@@ -45,27 +45,21 @@ enum BufferState
|
||||
bool
|
||||
OMXCodecReservation::ReserveOMXCodec()
|
||||
{
|
||||
if (!mManagerService.get()) {
|
||||
sp<MediaResourceManagerClient::EventListener> listener = this;
|
||||
mClient = new MediaResourceManagerClient(listener);
|
||||
|
||||
mManagerService = mClient->getMediaResourceManagerService();
|
||||
if (!mManagerService.get()) {
|
||||
mClient = nullptr;
|
||||
return true; // not really in use, but not usable
|
||||
}
|
||||
if (mClient) {
|
||||
// Already tried reservation.
|
||||
return false;
|
||||
}
|
||||
return (mManagerService->requestMediaResource(mClient, mType, false) == OK); // don't wait
|
||||
mClient = new mozilla::MediaSystemResourceClient(mType);
|
||||
return mClient->AcquireSyncNoWait(); // don't wait if resrouce is not available
|
||||
}
|
||||
|
||||
void
|
||||
OMXCodecReservation::ReleaseOMXCodec()
|
||||
{
|
||||
if (!mManagerService.get() || !mClient.get()) {
|
||||
if (!mClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
mManagerService->cancelClient(mClient, mType);
|
||||
mClient->ReleaseResource();
|
||||
}
|
||||
|
||||
OMXAudioEncoder*
|
||||
|
||||
@@ -15,22 +15,21 @@
|
||||
#include "AudioSegment.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
#include "MediaResourceManagerClient.h"
|
||||
#include "mozilla/media/MediaSystemResourceClient.h"
|
||||
#include "nsRefPtr.h"
|
||||
|
||||
#include <speex/speex_resampler.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// Wrapper class for managing HW codec reservations
|
||||
class OMXCodecReservation : public MediaResourceManagerClient::EventListener
|
||||
class OMXCodecReservation : public RefBase
|
||||
{
|
||||
public:
|
||||
OMXCodecReservation(bool aEncoder)
|
||||
{
|
||||
mType = aEncoder ? IMediaResourceManagerService::HW_VIDEO_ENCODER :
|
||||
IMediaResourceManagerService::HW_VIDEO_DECODER;
|
||||
mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
|
||||
mozilla::MediaSystemResourceType::VIDEO_DECODER;
|
||||
}
|
||||
|
||||
virtual ~OMXCodecReservation()
|
||||
@@ -44,14 +43,10 @@ public:
|
||||
/** Release the Encode or Decode resource for this instance */
|
||||
virtual void ReleaseOMXCodec();
|
||||
|
||||
// MediaResourceManagerClient::EventListener
|
||||
virtual void statusChanged(int event) {}
|
||||
|
||||
private:
|
||||
IMediaResourceManagerService::ResourceType mType;
|
||||
mozilla::MediaSystemResourceType mType;
|
||||
|
||||
sp<MediaResourceManagerClient> mClient;
|
||||
sp<IMediaResourceManagerService> mManagerService;
|
||||
nsRefPtr<mozilla::MediaSystemResourceClient> mClient;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -91,12 +91,13 @@ OmxDecoder::~OmxDecoder()
|
||||
mLooper->stop();
|
||||
}
|
||||
|
||||
void OmxDecoder::statusChanged()
|
||||
void OmxDecoder::codecReserved()
|
||||
{
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyStatusChanged, mReflector->id());
|
||||
// post AMessage to OmxDecoder via ALooper.
|
||||
notify->post();
|
||||
mMediaResourcePromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
void OmxDecoder::codecCanceled()
|
||||
{
|
||||
mMediaResourcePromise.RejectIfExists(true, __func__);
|
||||
}
|
||||
|
||||
static sp<IOMX> sOMX = nullptr;
|
||||
@@ -213,14 +214,6 @@ bool OmxDecoder::EnsureMetadata() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OmxDecoder::IsWaitingMediaResources()
|
||||
{
|
||||
if (mVideoSource.get()) {
|
||||
return mVideoSource->IsWaitingResources();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isInEmulator()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
@@ -228,8 +221,10 @@ static bool isInEmulator()
|
||||
return !strncmp(propQemu, "1", 1);
|
||||
}
|
||||
|
||||
bool OmxDecoder::AllocateMediaResources()
|
||||
nsRefPtr<mozilla::MediaOmxCommonReader::MediaResourcePromise> OmxDecoder::AllocateMediaResources()
|
||||
{
|
||||
nsRefPtr<MediaResourcePromise> p = mMediaResourcePromise.Ensure(__func__);
|
||||
|
||||
if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
|
||||
// OMXClient::connect() always returns OK and abort's fatally if
|
||||
// it can't connect.
|
||||
@@ -280,10 +275,11 @@ bool OmxDecoder::AllocateMediaResources()
|
||||
mNativeWindowClient);
|
||||
if (mVideoSource == nullptr) {
|
||||
NS_WARNING("Couldn't create OMX video source");
|
||||
return false;
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
} else {
|
||||
sp<OMXCodecProxy::EventListener> listener = this;
|
||||
mVideoSource->setEventListener(listener);
|
||||
sp<OMXCodecProxy::CodecResourceListener> listener = this;
|
||||
mVideoSource->setListener(listener);
|
||||
mVideoSource->requestResource();
|
||||
}
|
||||
}
|
||||
@@ -299,7 +295,8 @@ bool OmxDecoder::AllocateMediaResources()
|
||||
const char *audioMime = nullptr;
|
||||
sp<MetaData> meta = mAudioTrack->getFormat();
|
||||
if (!meta->findCString(kKeyMIMEType, &audioMime)) {
|
||||
return false;
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
}
|
||||
if (!strcasecmp(audioMime, "audio/raw")) {
|
||||
mAudioSource = mAudioTrack;
|
||||
@@ -325,20 +322,28 @@ bool OmxDecoder::AllocateMediaResources()
|
||||
flags);
|
||||
if (mAudioSource == nullptr) {
|
||||
NS_WARNING("Couldn't create OMX audio source");
|
||||
return false;
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
if (mAudioSource->start() != OK) {
|
||||
NS_WARNING("Couldn't start OMX audio source");
|
||||
mAudioSource.clear();
|
||||
return false;
|
||||
mMediaResourcePromise.Reject(true, __func__);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
if (!mVideoSource.get()) {
|
||||
// No resource allocation wait.
|
||||
mMediaResourcePromise.Resolve(true, __func__);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
void OmxDecoder::ReleaseMediaResources() {
|
||||
mMediaResourcePromise.RejectIfExists(true, __func__);
|
||||
|
||||
ReleaseVideoBuffer();
|
||||
ReleaseAudioBuffer();
|
||||
|
||||
@@ -821,15 +826,6 @@ void OmxDecoder::onMessageReceived(const sp<AMessage> &msg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kNotifyStatusChanged:
|
||||
{
|
||||
// Our decode may have acquired the hardware resource that it needs
|
||||
// to start. Notify the state machine to resume loading metadata.
|
||||
mDecoder->NotifyWaitingForResourcesStatusChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
TRESPASS();
|
||||
break;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/layers/FenceUtils.h"
|
||||
#include "MP3FrameParser.h"
|
||||
#include "MPAPI.h"
|
||||
#include "MediaOmxCommonReader.h"
|
||||
#include "MediaResource.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "OMXCodecProxy.h"
|
||||
@@ -20,7 +21,7 @@ class OmxDecoder;
|
||||
|
||||
namespace android {
|
||||
|
||||
class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||
class OmxDecoder : public OMXCodecProxy::CodecResourceListener {
|
||||
typedef MPAPI::AudioFrame AudioFrame;
|
||||
typedef MPAPI::VideoFrame VideoFrame;
|
||||
typedef mozilla::MP3FrameParser MP3FrameParser;
|
||||
@@ -28,6 +29,7 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||
typedef mozilla::AbstractMediaDecoder AbstractMediaDecoder;
|
||||
typedef mozilla::layers::FenceHandle FenceHandle;
|
||||
typedef mozilla::layers::TextureClient TextureClient;
|
||||
typedef mozilla::MediaOmxCommonReader::MediaResourcePromise MediaResourcePromise;
|
||||
|
||||
enum {
|
||||
kPreferSoftwareCodecs = 1,
|
||||
@@ -37,7 +39,6 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||
|
||||
enum {
|
||||
kNotifyPostReleaseVideoBuffer = 'noti',
|
||||
kNotifyStatusChanged = 'stat'
|
||||
};
|
||||
|
||||
AbstractMediaDecoder *mDecoder;
|
||||
@@ -120,6 +121,8 @@ class OmxDecoder : public OMXCodecProxy::EventListener {
|
||||
// 'true' if a read from the audio stream was done while reading the metadata
|
||||
bool mAudioMetadataRead;
|
||||
|
||||
mozilla::MediaPromiseHolder<MediaResourcePromise> mMediaResourcePromise;
|
||||
|
||||
void ReleaseVideoBuffer();
|
||||
void ReleaseAudioBuffer();
|
||||
// Call with mSeekLock held.
|
||||
@@ -141,8 +144,9 @@ public:
|
||||
OmxDecoder(MediaResource *aResource, AbstractMediaDecoder *aDecoder);
|
||||
~OmxDecoder();
|
||||
|
||||
// MediaResourceManagerClient::EventListener
|
||||
virtual void statusChanged();
|
||||
// OMXCodecProxy::CodecResourceListener
|
||||
virtual void codecReserved();
|
||||
virtual void codecCanceled();
|
||||
|
||||
// The MediaExtractor provides essential information for creating OMXCodec
|
||||
// instance. Such as video/audio codec, we can retrieve them through the
|
||||
@@ -158,11 +162,7 @@ public:
|
||||
// mDurationUs and video/audio metadata.
|
||||
bool EnsureMetadata();
|
||||
|
||||
// Only called by MediaOmxDecoder, do not call this function arbitrarily.
|
||||
// See bug 1050667.
|
||||
bool IsWaitingMediaResources();
|
||||
|
||||
bool AllocateMediaResources();
|
||||
nsRefPtr<MediaResourcePromise> AllocateMediaResources();
|
||||
void ReleaseMediaResources();
|
||||
bool SetVideoFormat();
|
||||
bool SetAudioFormat();
|
||||
|
||||
@@ -88,20 +88,28 @@ RtspMediaCodecReader::RequestVideoData(bool aSkipToNextKeyframe,
|
||||
return MediaCodecReader::RequestVideoData(aSkipToNextKeyframe, aTimeThreshold);
|
||||
}
|
||||
|
||||
nsresult
|
||||
RtspMediaCodecReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise>
|
||||
RtspMediaCodecReader::AsyncReadMetadata()
|
||||
{
|
||||
mRtspResource->DisablePlayoutDelay();
|
||||
EnsureActive();
|
||||
nsresult rv = MediaCodecReader::ReadMetadata(aInfo, aTags);
|
||||
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise> p =
|
||||
MediaCodecReader::AsyncReadMetadata();
|
||||
|
||||
// Send a PAUSE to the RTSP server because the underlying media resource is
|
||||
// not ready.
|
||||
SetIdle();
|
||||
|
||||
if (rv == NS_OK && !IsWaitingMediaResources()) {
|
||||
mRtspResource->EnablePlayoutDelay();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
return rv;
|
||||
void
|
||||
RtspMediaCodecReader::HandleResourceAllocated()
|
||||
{
|
||||
EnsureActive();
|
||||
MediaCodecReader::HandleResourceAllocated();
|
||||
mRtspResource->EnablePlayoutDelay();;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -58,8 +58,10 @@ public:
|
||||
// Disptach a DecodeAudioDataTask to decode audio data.
|
||||
virtual nsRefPtr<AudioDataPromise> RequestAudioData() override;
|
||||
|
||||
virtual nsresult ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags) override;
|
||||
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata()
|
||||
override;
|
||||
|
||||
virtual void HandleResourceAllocated() override;
|
||||
|
||||
private:
|
||||
// A pointer to RtspMediaResource for calling the Rtsp specific function.
|
||||
|
||||
@@ -81,22 +81,27 @@ void RtspOmxReader::EnsureActive() {
|
||||
MediaOmxReader::EnsureActive();
|
||||
}
|
||||
|
||||
nsresult RtspOmxReader::ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise>
|
||||
RtspOmxReader::AsyncReadMetadata()
|
||||
{
|
||||
// Send a PLAY command to the RTSP server before reading metadata.
|
||||
// Because we might need some decoded samples to ensure we have configuration.
|
||||
mRtspResource->DisablePlayoutDelay();
|
||||
EnsureActive();
|
||||
nsresult rv = MediaOmxReader::ReadMetadata(aInfo, aTags);
|
||||
|
||||
if (rv == NS_OK && !IsWaitingMediaResources()) {
|
||||
mRtspResource->EnablePlayoutDelay();
|
||||
} else if (IsWaitingMediaResources()) {
|
||||
// Send a PAUSE to the RTSP server because the underlying media resource is
|
||||
// not ready.
|
||||
SetIdle();
|
||||
}
|
||||
return rv;
|
||||
nsRefPtr<MediaDecoderReader::MetadataPromise> p =
|
||||
MediaOmxReader::AsyncReadMetadata();
|
||||
|
||||
// Send a PAUSE to the RTSP server because the underlying media resource is
|
||||
// not ready.
|
||||
SetIdle();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void RtspOmxReader::HandleResourceAllocated()
|
||||
{
|
||||
MediaOmxReader::HandleResourceAllocated();
|
||||
mRtspResource->EnablePlayoutDelay();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -64,8 +64,10 @@ public:
|
||||
|
||||
virtual void SetIdle() override;
|
||||
|
||||
virtual nsresult ReadMetadata(MediaInfo *aInfo, MetadataTags **aTags)
|
||||
final override;
|
||||
virtual nsRefPtr<MediaDecoderReader::MetadataPromise> AsyncReadMetadata()
|
||||
override;
|
||||
|
||||
virtual void HandleResourceAllocated() override;
|
||||
|
||||
private:
|
||||
// A pointer to RtspMediaResource for calling the Rtsp specific function.
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "IMediaResourceManagerClient"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <binder/Parcel.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
enum {
|
||||
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION
|
||||
};
|
||||
|
||||
class BpMediaResourceManagerClient : public BpInterface<IMediaResourceManagerClient>
|
||||
{
|
||||
public:
|
||||
BpMediaResourceManagerClient(const sp<IBinder>& impl)
|
||||
: BpInterface<IMediaResourceManagerClient>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
void statusChanged(int event)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerClient::getInterfaceDescriptor());
|
||||
data.writeInt32(event);
|
||||
remote()->transact(STATUS_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(MediaResourceManagerClient, "android.media.IMediaResourceManagerClient");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
status_t BnMediaResourceManagerClient::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
case STATUS_CHANGED: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerClient, data, reply);
|
||||
int event = data.readInt32();
|
||||
statusChanged(event);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,43 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
||||
#define ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IMediaResourceManagerClient : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(MediaResourceManagerClient);
|
||||
|
||||
// Notifies a change of media resource request status.
|
||||
virtual void statusChanged(int event) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnMediaResourceManagerClient : public BnInterface<IMediaResourceManagerClient>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
** Copyright 2010, The Android Open Source Project
|
||||
** Copyright 2013, Mozilla Foundation
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "IMediaResourceManagerDeathNotifier"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
|
||||
#include "IMediaResourceManagerDeathNotifier.h"
|
||||
|
||||
#define DN_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
|
||||
#define DN_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
|
||||
#define DN_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
|
||||
#define DN_LOGE_IF(cond, ...) \
|
||||
( (CONDITION(cond)) \
|
||||
? ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
|
||||
: (void)0 )
|
||||
|
||||
namespace android {
|
||||
|
||||
// client singleton for binder interface to services
|
||||
Mutex IMediaResourceManagerDeathNotifier::sServiceLock;
|
||||
sp<IMediaResourceManagerService> IMediaResourceManagerDeathNotifier::sMediaResourceManagerService;
|
||||
sp<IMediaResourceManagerDeathNotifier::DeathNotifier> IMediaResourceManagerDeathNotifier::sDeathNotifier;
|
||||
SortedVector< wp<IMediaResourceManagerDeathNotifier> > IMediaResourceManagerDeathNotifier::sObitRecipients;
|
||||
|
||||
// establish binder interface to MediaResourceManagerService
|
||||
/*static*/const sp<IMediaResourceManagerService>&
|
||||
IMediaResourceManagerDeathNotifier::getMediaResourceManagerService()
|
||||
{
|
||||
DN_LOGV("getMediaResourceManagerService");
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
if (sMediaResourceManagerService.get() == 0) {
|
||||
sp<IServiceManager> sm = defaultServiceManager();
|
||||
sp<IBinder> binder;
|
||||
do {
|
||||
binder = sm->getService(String16("media.resource_manager"));
|
||||
if (binder != 0) {
|
||||
break;
|
||||
}
|
||||
DN_LOGW("Media resource manager service not published, waiting...");
|
||||
usleep(500000); // 0.5 s
|
||||
} while(true);
|
||||
|
||||
if (sDeathNotifier == NULL) {
|
||||
sDeathNotifier = new DeathNotifier();
|
||||
}
|
||||
binder->linkToDeath(sDeathNotifier);
|
||||
sMediaResourceManagerService = interface_cast<IMediaResourceManagerService>(binder);
|
||||
}
|
||||
DN_LOGE_IF(sMediaResourceManagerService == 0, "no media player service!?");
|
||||
return sMediaResourceManagerService;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
IMediaResourceManagerDeathNotifier::addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
|
||||
{
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sObitRecipients.add(recipient);
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
IMediaResourceManagerDeathNotifier::removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient)
|
||||
{
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sObitRecipients.remove(recipient);
|
||||
}
|
||||
|
||||
void
|
||||
IMediaResourceManagerDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who)
|
||||
{
|
||||
DN_LOGW("media resource manager service died");
|
||||
// Need to do this with the lock held
|
||||
SortedVector< wp<IMediaResourceManagerDeathNotifier> > list;
|
||||
{
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sMediaResourceManagerService.clear();
|
||||
list = sObitRecipients;
|
||||
}
|
||||
|
||||
// Notify application when media server dies.
|
||||
// Don't hold the static lock during callback in case app
|
||||
// makes a call that needs the lock.
|
||||
size_t count = list.size();
|
||||
for (size_t iter = 0; iter < count; ++iter) {
|
||||
sp<IMediaResourceManagerDeathNotifier> notifier = list[iter].promote();
|
||||
if (notifier != 0) {
|
||||
notifier->died();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMediaResourceManagerDeathNotifier::DeathNotifier::~DeathNotifier()
|
||||
{
|
||||
Mutex::Autolock _l(sServiceLock);
|
||||
sObitRecipients.clear();
|
||||
if (sMediaResourceManagerService != 0) {
|
||||
sMediaResourceManagerService->asBinder()->unlinkToDeath(this);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
** Copyright 2010, The Android Open Source Project
|
||||
** Copyright 2013, Mozilla Foundation
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
|
||||
#define ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
|
||||
|
||||
#include <utils/threads.h>
|
||||
#include <utils/SortedVector.h>
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Handle MediaResourceManagerService's death notification.
|
||||
* Made from android's IMediaDeathNotifier class.
|
||||
*/
|
||||
class IMediaResourceManagerDeathNotifier: virtual public RefBase
|
||||
{
|
||||
public:
|
||||
IMediaResourceManagerDeathNotifier() { addObitRecipient(this); }
|
||||
virtual ~IMediaResourceManagerDeathNotifier() { removeObitRecipient(this); }
|
||||
|
||||
virtual void died() = 0;
|
||||
static const sp<IMediaResourceManagerService>& getMediaResourceManagerService();
|
||||
|
||||
private:
|
||||
IMediaResourceManagerDeathNotifier &operator=(const IMediaResourceManagerDeathNotifier &);
|
||||
IMediaResourceManagerDeathNotifier(const IMediaResourceManagerDeathNotifier &);
|
||||
|
||||
static void addObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
|
||||
static void removeObitRecipient(const wp<IMediaResourceManagerDeathNotifier>& recipient);
|
||||
|
||||
class DeathNotifier: public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
DeathNotifier() {}
|
||||
virtual ~DeathNotifier();
|
||||
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
};
|
||||
|
||||
friend class DeathNotifier;
|
||||
|
||||
static Mutex sServiceLock;
|
||||
static sp<IMediaResourceManagerService> sMediaResourceManagerService;
|
||||
static sp<DeathNotifier> sDeathNotifier;
|
||||
static SortedVector< wp<IMediaResourceManagerDeathNotifier> > sObitRecipients;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERDEATHNOTIFIER_H
|
||||
@@ -1,92 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "IMediaResourceManagerService"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <binder/Parcel.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Function ID used between BpMediaResourceManagerService and
|
||||
* BnMediaResourceManagerService by using Binder ipc.
|
||||
*/
|
||||
enum {
|
||||
REQUEST_MEDIA_RESOURCE = IBinder::FIRST_CALL_TRANSACTION,
|
||||
DEREGISTER_CLIENT
|
||||
};
|
||||
|
||||
class BpMediaResourceManagerService : public BpInterface<IMediaResourceManagerService>
|
||||
{
|
||||
public:
|
||||
BpMediaResourceManagerService(const sp<IBinder>& impl)
|
||||
: BpInterface<IMediaResourceManagerService>(impl)
|
||||
{
|
||||
}
|
||||
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
data.writeInt32(willWait ? 1 : 0);
|
||||
remote()->transact(REQUEST_MEDIA_RESOURCE, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IMediaResourceManagerService::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(client->asBinder());
|
||||
data.writeInt32(resourceType);
|
||||
remote()->transact(DEREGISTER_CLIENT, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
};
|
||||
|
||||
IMPLEMENT_META_INTERFACE(MediaResourceManagerService, "android.media.IMediaResourceManagerService");
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
status_t BnMediaResourceManagerService::onTransact(
|
||||
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
|
||||
{
|
||||
switch(code) {
|
||||
|
||||
case REQUEST_MEDIA_RESOURCE: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
int resourceType = data.readInt32();
|
||||
bool willWait = (data.readInt32() == 1);
|
||||
status_t result = requestMediaResource(client, resourceType, willWait);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
case DEREGISTER_CLIENT: {
|
||||
CHECK_INTERFACE(IMediaResourceManagerService, data, reply);
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(data.readStrongBinder());
|
||||
int resourceType = data.readInt32();
|
||||
status_t result = cancelClient(client, resourceType);
|
||||
reply->writeInt32(result);
|
||||
return NO_ERROR;
|
||||
} break;
|
||||
default:
|
||||
return BBinder::onTransact(code, data, reply, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,74 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
|
||||
#define ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
|
||||
|
||||
namespace android {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class IMediaResourceManagerService : public IInterface
|
||||
{
|
||||
public:
|
||||
DECLARE_META_INTERFACE(MediaResourceManagerService);
|
||||
|
||||
// Enumeration for the resource types
|
||||
enum ResourceType {
|
||||
HW_VIDEO_DECODER = 0,
|
||||
HW_AUDIO_DECODER, // Not supported currently.
|
||||
HW_VIDEO_ENCODER,
|
||||
HW_AUDIO_ENCODER, // Not supported currently.
|
||||
HW_CAMERA, // Not supported currently.
|
||||
NUM_OF_RESOURCE_TYPES,
|
||||
INVALID_RESOURCE_TYPE = -1
|
||||
};
|
||||
|
||||
enum ErrorCode {
|
||||
RESOURCE_NOT_AVAILABLE = -EAGAIN
|
||||
};
|
||||
|
||||
// Request a media resource for IMediaResourceManagerClient.
|
||||
// client is the binder that service will notify (through
|
||||
// IMediaResourceManagerClient::statusChanged()) when request status changed.
|
||||
// resourceType is type of resource that client would like to request.
|
||||
// willWait indicates that, when the resource is not currently available
|
||||
// (i.e., already in use by another client), if the client wants to wait. If
|
||||
// true, client will be put into a (FIFO) waiting list and be notified when
|
||||
// resource is available.
|
||||
// For unsupported types, this function returns BAD_TYPE. For supported
|
||||
// types, it always returns OK when willWait is true; otherwise it will
|
||||
// return true when resouce is available, or RESOURCE_NOT_AVAILABLE when
|
||||
// resouce is in use.
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client, int resourceType, bool willWait) = 0;
|
||||
// Cancel a media resource request and a resource allocated to IMediaResourceManagerClient.
|
||||
// Client must call this function after it's done with the media resource requested.
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client, int resourceType) = 0;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class BnMediaResourceManagerService : public BnInterface<IMediaResourceManagerService>
|
||||
{
|
||||
public:
|
||||
virtual status_t onTransact( uint32_t code,
|
||||
const Parcel& data,
|
||||
Parcel* reply,
|
||||
uint32_t flags = 0);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERSERVICE_H
|
||||
@@ -1,95 +0,0 @@
|
||||
/* -*- 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 "MediaResourceHandler.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
MediaResourceHandler::MediaResourceHandler(const wp<ResourceListener> &aListener)
|
||||
: mListener(aListener)
|
||||
, mType(IMediaResourceManagerService::INVALID_RESOURCE_TYPE)
|
||||
, mWaitingResource(false)
|
||||
{
|
||||
}
|
||||
|
||||
MediaResourceHandler::~MediaResourceHandler()
|
||||
{
|
||||
cancelResource();
|
||||
}
|
||||
|
||||
bool
|
||||
MediaResourceHandler::IsWaitingResource()
|
||||
{
|
||||
Mutex::Autolock al(mLock);
|
||||
return mWaitingResource;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaResourceHandler::requestResource(IMediaResourceManagerService::ResourceType aType)
|
||||
{
|
||||
Mutex::Autolock al(mLock);
|
||||
|
||||
if (mClient != nullptr && mService != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sp<MediaResourceManagerClient> client = new MediaResourceManagerClient(this);
|
||||
sp<IMediaResourceManagerService> service = client->getMediaResourceManagerService();
|
||||
|
||||
if (service == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (service->requestMediaResource(client, (int)aType, true) != OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mClient = client;
|
||||
mService = service;
|
||||
mType = aType;
|
||||
mWaitingResource = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaResourceHandler::cancelResource()
|
||||
{
|
||||
Mutex::Autolock al(mLock);
|
||||
|
||||
if (mClient != nullptr && mService != nullptr) {
|
||||
mService->cancelClient(mClient, (int)mType);
|
||||
}
|
||||
|
||||
mWaitingResource = false;
|
||||
mClient = nullptr;
|
||||
mService = nullptr;
|
||||
}
|
||||
|
||||
// Called on a Binder thread
|
||||
void
|
||||
MediaResourceHandler::statusChanged(int aEvent)
|
||||
{
|
||||
sp<ResourceListener> listener;
|
||||
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
listener = mListener.promote();
|
||||
if (listener == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWaitingResource = false;
|
||||
|
||||
MediaResourceManagerClient::State state = (MediaResourceManagerClient::State)aEvent;
|
||||
if (state == MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED) {
|
||||
listener->resourceReserved();
|
||||
} else {
|
||||
listener->resourceCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
@@ -1,71 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef MEDIA_RESOURCE_HANDLER_H
|
||||
#define MEDIA_RESOURCE_HANDLER_H
|
||||
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <mozilla/Attributes.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class MediaResourceHandler : public MediaResourceManagerClient::EventListener
|
||||
{
|
||||
public:
|
||||
/* Resource notification listener.
|
||||
* All functions are called on the Binder thread.
|
||||
*/
|
||||
struct ResourceListener : public virtual RefBase {
|
||||
/* The resource is reserved and can be granted.
|
||||
* The client can allocate the requested resource.
|
||||
*/
|
||||
virtual void resourceReserved() = 0;
|
||||
/* The resource is not reserved any more.
|
||||
* The client should release the resource as soon as possible if the
|
||||
* resource is still being held.
|
||||
*/
|
||||
virtual void resourceCanceled() = 0;
|
||||
};
|
||||
|
||||
MediaResourceHandler(const wp<ResourceListener> &aListener);
|
||||
|
||||
virtual ~MediaResourceHandler();
|
||||
|
||||
// Request Resource
|
||||
bool requestResource(IMediaResourceManagerService::ResourceType aType);
|
||||
// Cancel Resource
|
||||
void cancelResource();
|
||||
|
||||
bool IsWaitingResource();
|
||||
|
||||
protected:
|
||||
// MediaResourceManagerClient::EventListener::statusChanged()
|
||||
virtual void statusChanged(int event);
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
MediaResourceHandler() = delete;
|
||||
MediaResourceHandler(const MediaResourceHandler &) = delete;
|
||||
const MediaResourceHandler &operator=(const MediaResourceHandler &) = delete;
|
||||
|
||||
// Resource Notification Listener
|
||||
wp<ResourceListener> mListener;
|
||||
|
||||
// Resource Management
|
||||
Mutex mLock;
|
||||
sp<IMediaResourceManagerClient> mClient;
|
||||
sp<IMediaResourceManagerService> mService;
|
||||
IMediaResourceManagerService::ResourceType mType;
|
||||
|
||||
bool mWaitingResource;
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // MEDIA_RESOURCE_HANDLER_H
|
||||
@@ -1,40 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "MediaResourceManagerClient"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
MediaResourceManagerClient::MediaResourceManagerClient(const wp<EventListener>& listener)
|
||||
: mEventListener(listener)
|
||||
{
|
||||
}
|
||||
|
||||
void MediaResourceManagerClient::statusChanged(int event)
|
||||
{
|
||||
if (mEventListener != NULL) {
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != NULL) {
|
||||
listener->statusChanged(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaResourceManagerClient::died()
|
||||
{
|
||||
sp<EventListener> listener = mEventListener.promote();
|
||||
if (listener != NULL) {
|
||||
listener->statusChanged(CLIENT_STATE_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef ANDROID_MEDIARESOURCEMANAGERCLIENT_H
|
||||
#define ANDROID_MEDIARESOURCEMANAGERCLIENT_H
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
#include "IMediaResourceManagerDeathNotifier.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
class MediaResourceManagerClient: public BnMediaResourceManagerClient,
|
||||
public virtual IMediaResourceManagerDeathNotifier
|
||||
{
|
||||
public:
|
||||
// Enumeration for the valid decoding states
|
||||
enum State {
|
||||
CLIENT_STATE_WAIT_FOR_RESOURCE,
|
||||
CLIENT_STATE_RESOURCE_ASSIGNED,
|
||||
CLIENT_STATE_SHUTDOWN
|
||||
};
|
||||
|
||||
struct EventListener : public virtual RefBase {
|
||||
// Notifies a change of media resource request status.
|
||||
virtual void statusChanged(int event) = 0;
|
||||
};
|
||||
|
||||
MediaResourceManagerClient(const wp<EventListener>& listener);
|
||||
|
||||
// DeathRecipient
|
||||
void died();
|
||||
|
||||
// IMediaResourceManagerClient
|
||||
virtual void statusChanged(int event);
|
||||
|
||||
private:
|
||||
wp<EventListener> mEventListener;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIARESOURCEMANAGERCLIENT_H
|
||||
@@ -1,371 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "MediaResourceManagerService"
|
||||
|
||||
#include <mozilla/Assertions.h>
|
||||
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <media/stagefright/foundation/AMessage.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "MediaResourceManagerClient.h"
|
||||
#include "MediaResourceManagerService.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
const char* MediaResourceManagerService::kMsgKeyResourceType = "res-type";
|
||||
|
||||
/* static */
|
||||
void MediaResourceManagerService::instantiate() {
|
||||
defaultServiceManager()->addService(
|
||||
String16("media.resource_manager"),
|
||||
new MediaResourceManagerService());
|
||||
}
|
||||
|
||||
MediaResourceManagerService::MediaResourceManagerService()
|
||||
{
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("MediaResourceManagerService");
|
||||
|
||||
mReflector = new AHandlerReflector<MediaResourceManagerService>(this);
|
||||
// Register AMessage handler to ALooper.
|
||||
mLooper->registerHandler(mReflector);
|
||||
// Start ALooper thread.
|
||||
mLooper->start();
|
||||
}
|
||||
|
||||
MediaResourceManagerService::~MediaResourceManagerService()
|
||||
{
|
||||
// Unregister AMessage handler from ALooper.
|
||||
mLooper->unregisterHandler(mReflector->id());
|
||||
// Stop ALooper thread.
|
||||
mLooper->stop();
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::binderDied(const wp<IBinder>& who)
|
||||
{
|
||||
if (who != NULL) {
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
sp<IBinder> binder = who.promote();
|
||||
if (binder != NULL) {
|
||||
mResources.forgetClient(binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait)
|
||||
{
|
||||
ResourceType type = static_cast<ResourceType>(resourceType);
|
||||
// Support only HW_VIDEO_DECODER and HW_VIDEO_ENCODER.
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
case HW_VIDEO_ENCODER:
|
||||
break;
|
||||
default:
|
||||
// Type not supported.
|
||||
return BAD_TYPE;
|
||||
}
|
||||
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
// Must know if it will be granted or not - if there are enough unfufilled requests to
|
||||
// use up the resource, fail. Otherwise we know that enqueuing under lock will succeed.
|
||||
if (!willWait &&
|
||||
(mResources.findAvailableResource(type, mResources.countRequests(type) + 1) ==
|
||||
NAME_NOT_FOUND)) {
|
||||
return RESOURCE_NOT_AVAILABLE;
|
||||
}
|
||||
// We could early-return here without enqueuing IF we can do the rest of
|
||||
// the allocation safely here. However, enqueuing ensures there's only
|
||||
// one copy of that code, and that any callbacks are made from the same
|
||||
// context.
|
||||
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
mResources.enqueueRequest(binder, type);
|
||||
binder->linkToDeath(this);
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Post AMessage to MediaResourceManagerService via ALooper.
|
||||
notify->post();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
|
||||
sp<IBinder> binder = client->asBinder();
|
||||
cancelClientLocked(binder, static_cast<ResourceType>(resourceType));
|
||||
|
||||
sp<AMessage> notify = new AMessage(kNotifyRequest, mReflector->id());
|
||||
notify->setInt32(kMsgKeyResourceType, resourceType);
|
||||
// Next!
|
||||
// Note: since we held the lock while releasing and then posting, if there is
|
||||
// a queue, no willWait==false entries can jump into the queue thinking they'll
|
||||
// get the resource.
|
||||
notify->post();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Extract resource type from message.
|
||||
static int32_t getResourceType(const sp<AMessage>& message)
|
||||
{
|
||||
int32_t resourceType = MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
return message->findInt32(MediaResourceManagerService::kMsgKeyResourceType, &resourceType) ?
|
||||
resourceType : MediaResourceManagerService::INVALID_RESOURCE_TYPE;
|
||||
}
|
||||
|
||||
// Called on ALooper thread.
|
||||
void MediaResourceManagerService::onMessageReceived(const sp<AMessage> &msg)
|
||||
{
|
||||
Mutex::Autolock autoLock(mLock);
|
||||
ResourceType type = static_cast<ResourceType>(getResourceType(msg));
|
||||
|
||||
// Note: a message is sent both for "I added an entry to the queue"
|
||||
// (which may succeed, typically if the queue is empty), and for "I gave
|
||||
// up the resource", in which case it's "give to the next waiting client,
|
||||
// or no one".
|
||||
|
||||
// Exit if no resource is available, but leave the client in the waiting
|
||||
// list.
|
||||
int found = mResources.findAvailableResource(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit if no request.
|
||||
if (!mResources.hasRequest(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sp<IBinder> req = mResources.nextRequest(type);
|
||||
mResources.aquireResource(req, type, found);
|
||||
// Notify resource assignment to the client.
|
||||
sp<IMediaResourceManagerClient> client = interface_cast<IMediaResourceManagerClient>(req);
|
||||
client->statusChanged(MediaResourceManagerClient::CLIENT_STATE_RESOURCE_ASSIGNED);
|
||||
mResources.dequeueRequest(type);
|
||||
}
|
||||
|
||||
void MediaResourceManagerService::cancelClientLocked(const sp<IBinder>& binder,
|
||||
ResourceType resourceType)
|
||||
{
|
||||
mResources.forgetClient(binder, resourceType);
|
||||
binder->unlinkToDeath(this);
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::ResourceTable()
|
||||
{
|
||||
// Populate types of resources.
|
||||
for (int type = 0; type < NUM_OF_RESOURCE_TYPES; type++) {
|
||||
ssize_t index = mMap.add(static_cast<ResourceType>(type), Resources());
|
||||
Resources& resources = mMap.editValueAt(index);
|
||||
int available;
|
||||
switch (type) {
|
||||
case HW_VIDEO_DECODER:
|
||||
available = VIDEO_DECODER_COUNT;
|
||||
break;
|
||||
case HW_VIDEO_ENCODER:
|
||||
available = VIDEO_ENCODER_COUNT;
|
||||
break;
|
||||
default:
|
||||
available = 0;
|
||||
break;
|
||||
}
|
||||
resources.mSlots.insertAt(0, available);
|
||||
}
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceTable::~ResourceTable() {
|
||||
// Remove resouces.
|
||||
mMap.clear();
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::supportsType(ResourceType type)
|
||||
{
|
||||
return mMap.indexOfKey(type) != NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
ssize_t MediaResourceManagerService::ResourceTable::findAvailableResource(ResourceType type,
|
||||
size_t numberNeeded)
|
||||
{
|
||||
MOZ_ASSERT(numberNeeded > 0);
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
const Slots& slots = mMap.valueAt(found).mSlots;
|
||||
|
||||
found = NAME_NOT_FOUND;
|
||||
for (size_t i = 0; i < slots.size(); i++) {
|
||||
if (slots[i].mClient != nullptr) {
|
||||
// Already in use.
|
||||
continue;
|
||||
}
|
||||
if (--numberNeeded == 0) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::isOwnedByClient(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
return slot && slot->mClient == client;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::aquireResource(const sp<IBinder>& client,
|
||||
ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ResourceSlot* slot = resourceOfTypeAt(type, index);
|
||||
// Resouce should not be in use.
|
||||
MOZ_ASSERT(slot && slot->mClient == nullptr);
|
||||
if (!slot) {
|
||||
return NAME_NOT_FOUND;
|
||||
} else if (slot->mClient != nullptr) {
|
||||
// Resource already in use by other client.
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
slot->mClient = client;
|
||||
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
MediaResourceManagerService::ResourceSlot*
|
||||
MediaResourceManagerService::ResourceTable::resourceOfTypeAt(ResourceType type,
|
||||
size_t index)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Slots& slots = mMap.editValueAt(found).mSlots;
|
||||
MOZ_ASSERT(index < slots.size());
|
||||
if (index >= slots.size()) {
|
||||
// Index out of range.
|
||||
return nullptr;
|
||||
}
|
||||
return &(slots.editItemAt(index));
|
||||
}
|
||||
|
||||
bool MediaResourceManagerService::ResourceTable::hasRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return !queue.empty();
|
||||
}
|
||||
|
||||
uint32_t MediaResourceManagerService::ResourceTable::countRequests(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
sp<IBinder> MediaResourceManagerService::ResourceTable::nextRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Fifo& queue = mMap.valueAt(found).mRequestQueue;
|
||||
return *(queue.begin());
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::enqueueRequest(const sp<IBinder>& client,
|
||||
ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
mMap.editValueAt(found).mRequestQueue.push_back(client);
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::dequeueRequest(ResourceType type)
|
||||
{
|
||||
ssize_t found = mMap.indexOfKey(type);
|
||||
if (found == NAME_NOT_FOUND) {
|
||||
// Unsupported type.
|
||||
return found;
|
||||
}
|
||||
|
||||
Fifo& queue = mMap.editValueAt(found).mRequestQueue;
|
||||
queue.erase(queue.begin());
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client)
|
||||
{
|
||||
// Traverse all resources.
|
||||
for (size_t i = 0; i < mMap.size(); i++) {
|
||||
forgetClient(client, mMap.keyAt(i));
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t MediaResourceManagerService::ResourceTable::forgetClient(const sp<IBinder>& client, ResourceType type)
|
||||
{
|
||||
MOZ_ASSERT(supportsType(type));
|
||||
|
||||
Resources& resources = mMap.editValueFor(type);
|
||||
|
||||
// Remove pending requests for given client.
|
||||
Fifo& queue = resources.mRequestQueue;
|
||||
Fifo::iterator it(queue.begin());
|
||||
while (it != queue.end()) {
|
||||
if ((*it).get() == client.get()) {
|
||||
queue.erase(it);
|
||||
break;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
// Revoke ownership for given client.
|
||||
Slots& slots = resources.mSlots;
|
||||
for (size_t i = 0; i < slots.size(); i++) {
|
||||
ResourceSlot& slot = slots.editItemAt(i);
|
||||
if (client.get() == slot.mClient.get()) {
|
||||
slot.mClient = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
}; // namespace android
|
||||
@@ -1,135 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef ANDROID_MEDIARESOURCEMANAGERSERVICE_H
|
||||
#define ANDROID_MEDIARESOURCEMANAGERSERVICE_H
|
||||
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <media/stagefright/foundation/AHandlerReflector.h>
|
||||
#include <media/stagefright/foundation/ALooper.h>
|
||||
#include <utils/KeyedVector.h>
|
||||
#include <utils/List.h>
|
||||
#include <utils/RefBase.h>
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include "IMediaResourceManagerClient.h"
|
||||
#include "IMediaResourceManagerService.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
/**
|
||||
* Manage permissions of using media resources(hw decoder, hw encoder, camera)
|
||||
* XXX Current implementation supports only one hw video codec.
|
||||
* Need to extend to support multiple instance and other resources.
|
||||
*/
|
||||
class MediaResourceManagerService: public BnMediaResourceManagerService,
|
||||
public IBinder::DeathRecipient
|
||||
{
|
||||
public:
|
||||
// The maximum number of hardware resoureces available.
|
||||
enum
|
||||
{
|
||||
VIDEO_DECODER_COUNT = 1,
|
||||
VIDEO_ENCODER_COUNT = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kNotifyRequest = 'noti',
|
||||
};
|
||||
|
||||
static const char* kMsgKeyResourceType;
|
||||
|
||||
// Instantiate MediaResourceManagerService and register to service manager.
|
||||
// If service manager is not present, wait until service manager becomes present.
|
||||
static void instantiate();
|
||||
|
||||
// DeathRecipient
|
||||
virtual void binderDied(const wp<IBinder>& who);
|
||||
|
||||
// derived from IMediaResourceManagerService
|
||||
virtual status_t requestMediaResource(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType, bool willWait);
|
||||
virtual status_t cancelClient(const sp<IMediaResourceManagerClient>& client,
|
||||
int resourceType);
|
||||
|
||||
// Receive a message from AHandlerReflector.
|
||||
// Called on ALooper thread.
|
||||
void onMessageReceived(const sp<AMessage> &msg);
|
||||
|
||||
protected:
|
||||
MediaResourceManagerService();
|
||||
virtual ~MediaResourceManagerService();
|
||||
|
||||
private:
|
||||
// Represent a media resouce.
|
||||
// Hold a IMediaResourceManagerClient that got a media resource as IBinder.
|
||||
struct ResourceSlot
|
||||
{
|
||||
sp<IBinder> mClient;
|
||||
};
|
||||
typedef Vector<ResourceSlot> Slots;
|
||||
|
||||
typedef List<sp<IBinder> > Fifo;
|
||||
struct Resources
|
||||
{
|
||||
// Queue of media resource requests. Hold IMediaResourceManagerClient that
|
||||
// requesting a media resource as IBinder.
|
||||
Fifo mRequestQueue;
|
||||
// All resources that can be requested. Hold |ResourceSlot|s that track
|
||||
// their usage.
|
||||
Slots mSlots;
|
||||
};
|
||||
|
||||
typedef KeyedVector<ResourceType, Resources> ResourcesMap;
|
||||
// Manages requests from clients and availability of resources.
|
||||
class ResourceTable
|
||||
{
|
||||
ResourceTable();
|
||||
~ResourceTable();
|
||||
// Resource operations.
|
||||
bool supportsType(ResourceType type);
|
||||
ssize_t findAvailableResource(ResourceType type, size_t number_needed = 1);
|
||||
bool isOwnedByClient(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
status_t aquireResource(const sp<IBinder>& client, ResourceType type, size_t index);
|
||||
ResourceSlot* resourceOfTypeAt(ResourceType type, size_t index);
|
||||
// Request operations.
|
||||
bool hasRequest(ResourceType type);
|
||||
uint32_t countRequests(ResourceType type);
|
||||
sp<IBinder> nextRequest(ResourceType type);
|
||||
status_t enqueueRequest(const sp<IBinder>& client, ResourceType type);
|
||||
status_t dequeueRequest(ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client, ResourceType type);
|
||||
status_t forgetClient(const sp<IBinder>& client);
|
||||
|
||||
friend class MediaResourceManagerService;
|
||||
|
||||
// A map for all types of supported resources.
|
||||
ResourcesMap mMap;
|
||||
};
|
||||
|
||||
void cancelClientLocked(const sp<IBinder>& binder, ResourceType resourceType);
|
||||
|
||||
// ALooper is a message loop used in stagefright.
|
||||
// It creates a thread for messages and handles messages in the thread.
|
||||
// ALooper is a clone of Looper in android Java.
|
||||
// http://developer.android.com/reference/android/os/Looper.html
|
||||
sp<ALooper> mLooper;
|
||||
// deliver a message to a wrapped object(OmxDecoder).
|
||||
// AHandlerReflector is similar to Handler in android Java.
|
||||
// http://developer.android.com/reference/android/os/Handler.html
|
||||
sp<AHandlerReflector<MediaResourceManagerService> > mReflector;
|
||||
|
||||
// The lock protects manager operations called from multiple threads.
|
||||
Mutex mLock;
|
||||
|
||||
// Keeps all the records.
|
||||
ResourceTable mResources;
|
||||
};
|
||||
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEDIARESOURCEMANAGERSERVICE_H
|
||||
@@ -1,47 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS += [
|
||||
'IMediaResourceManagerClient.h',
|
||||
'IMediaResourceManagerDeathNotifier.h',
|
||||
'IMediaResourceManagerService.h',
|
||||
'MediaResourceHandler.h',
|
||||
'MediaResourceManagerClient.h',
|
||||
'MediaResourceManagerService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'IMediaResourceManagerClient.cpp',
|
||||
'IMediaResourceManagerDeathNotifier.cpp',
|
||||
'IMediaResourceManagerService.cpp',
|
||||
'MediaResourceHandler.cpp',
|
||||
'MediaResourceManagerClient.cpp',
|
||||
'MediaResourceManagerService.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Suppress some GCC/clang warnings being treated as errors:
|
||||
# - about multi-character constants which are used in codec-related code
|
||||
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
|
||||
CXXFLAGS += [
|
||||
'-Wno-error=multichar'
|
||||
]
|
||||
|
||||
CXXFLAGS += [
|
||||
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
|
||||
'frameworks/base/include',
|
||||
'frameworks/base/include/binder',
|
||||
'frameworks/base/include/utils',
|
||||
'frameworks/base/include/media/',
|
||||
'frameworks/base/include/media/stagefright/openmax',
|
||||
'frameworks/base/media/libstagefright/include',
|
||||
]
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
@@ -94,7 +94,6 @@ LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/dom/html',
|
||||
'/ipc/chromium/src',
|
||||
'mediaresourcemanager',
|
||||
]
|
||||
|
||||
CXXFLAGS += [
|
||||
|
||||
@@ -18,7 +18,6 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/media/omx/',
|
||||
'/dom/media/omx/mediaresourcemanager',
|
||||
]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/* -*- 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 "mozilla/Monitor.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
#include "MediaSystemResourceClient.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
Atomic<uint32_t> MediaSystemResourceClient::sSerialCounter(0);
|
||||
|
||||
MediaSystemResourceClient::MediaSystemResourceClient(MediaSystemResourceType aReourceType)
|
||||
: mResourceType(aReourceType)
|
||||
, mId(++sSerialCounter)
|
||||
, mListener(nullptr)
|
||||
, mResourceState(RESOURCE_STATE_START)
|
||||
, mIsSync(false)
|
||||
, mAcquireSyncWaitMonitor(nullptr)
|
||||
, mAcquireSyncWaitDone(nullptr)
|
||||
{
|
||||
mManager = MediaSystemResourceManager::Get();
|
||||
if (mManager) {
|
||||
mManager->Register(this);
|
||||
}
|
||||
}
|
||||
|
||||
MediaSystemResourceClient::~MediaSystemResourceClient()
|
||||
{
|
||||
ReleaseResource();
|
||||
if (mManager) {
|
||||
mManager->Unregister(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceClient::SetListener(MediaSystemResourceReservationListener* aListener)
|
||||
{
|
||||
if (!mManager) {
|
||||
return false;
|
||||
}
|
||||
return mManager->SetListener(this, aListener);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceClient::Acquire()
|
||||
{
|
||||
if (!mManager) {
|
||||
return;
|
||||
}
|
||||
mManager->Acquire(this);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceClient::AcquireSyncNoWait()
|
||||
{
|
||||
if (!mManager) {
|
||||
return false;
|
||||
}
|
||||
return mManager->AcquireSyncNoWait(this);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceClient::ReleaseResource()
|
||||
{
|
||||
if (!mManager) {
|
||||
return;
|
||||
}
|
||||
mManager->ReleaseResource(this);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,94 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceClient_h_)
|
||||
#define MediaSystemResourceClient_h_
|
||||
|
||||
#include "MediaSystemResourceManager.h"
|
||||
#include "MediaSystemResourceTypes.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/media/MediaSystemResourceTypes.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaSystemResourceManager;
|
||||
|
||||
|
||||
/**
|
||||
* This is a base class for listener callbacks.
|
||||
* This callback is invoked when the media system resource reservation state
|
||||
* is changed.
|
||||
*/
|
||||
class MediaSystemResourceReservationListener {
|
||||
public:
|
||||
virtual void ResourceReserved() = 0;
|
||||
virtual void ResourceReserveFailed() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* MediaSystemResourceClient is used to reserve a media system resource
|
||||
* like hw decoder. When system has a limitation of a media resource,
|
||||
* use this class to mediate use rights of the resource.
|
||||
*/
|
||||
class MediaSystemResourceClient
|
||||
{
|
||||
public:
|
||||
|
||||
// Enumeration for the valid decoding states
|
||||
enum ResourceState {
|
||||
RESOURCE_STATE_START,
|
||||
RESOURCE_STATE_WAITING,
|
||||
RESOURCE_STATE_ACQUIRED,
|
||||
RESOURCE_STATE_NOT_ACQUIRED,
|
||||
RESOURCE_STATE_END
|
||||
};
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceClient)
|
||||
|
||||
explicit MediaSystemResourceClient(MediaSystemResourceType aReourceType);
|
||||
|
||||
bool SetListener(MediaSystemResourceReservationListener* aListener);
|
||||
|
||||
// Try to acquire media resource asynchronously.
|
||||
// If the resource is used by others, wait until acquired.
|
||||
void Acquire();
|
||||
|
||||
// Try to acquire media resource synchronously. If the resource is not immediately
|
||||
// available, fail to acquire it.
|
||||
// return false if resource is not acquired.
|
||||
// return true if resource is acquired.
|
||||
//
|
||||
// This function should not be called on ImageBridge thread.
|
||||
// It should be used only for compatibility with legacy code.
|
||||
bool AcquireSyncNoWait();
|
||||
|
||||
void ReleaseResource();
|
||||
|
||||
private:
|
||||
~MediaSystemResourceClient();
|
||||
|
||||
nsRefPtr<MediaSystemResourceManager> mManager;
|
||||
const MediaSystemResourceType mResourceType;
|
||||
const uint32_t mId;
|
||||
|
||||
// Modified only by MediaSystemResourceManager.
|
||||
// Accessed and modified with MediaSystemResourceManager::mReentrantMonitor held.
|
||||
MediaSystemResourceReservationListener* mListener;
|
||||
ResourceState mResourceState;
|
||||
bool mIsSync;
|
||||
ReentrantMonitor* mAcquireSyncWaitMonitor;
|
||||
bool* mAcquireSyncWaitDone;
|
||||
|
||||
static mozilla::Atomic<uint32_t> sSerialCounter;
|
||||
|
||||
friend class MediaSystemResourceManager;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,425 @@
|
||||
/* -*- 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 "gfxPrefs.h"
|
||||
#include "MediaSystemResourceManagerChild.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
|
||||
#include "MediaSystemResourceManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
/* static */ StaticRefPtr<MediaSystemResourceManager> MediaSystemResourceManager::sSingleton;
|
||||
|
||||
/* static */ MediaSystemResourceManager*
|
||||
MediaSystemResourceManager::Get()
|
||||
{
|
||||
if (sSingleton) {
|
||||
return sSingleton;
|
||||
}
|
||||
MediaSystemResourceManager::Init();
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
MediaSystemResourceManager::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
if (sSingleton) {
|
||||
sSingleton->CloseIPC();
|
||||
sSingleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
MediaSystemResourceManager::IsMediaSystemResourceManagerEnabled()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
return true;
|
||||
#else
|
||||
// XXX MediaSystemResourceManager is enabled only when ImageBridge is enabled.
|
||||
// MediaSystemResourceManager uses ImageBridge's thread.
|
||||
if (gfxPrefs::AsyncVideoOOPEnabled() &&
|
||||
gfxPrefs::AsyncVideoEnabled()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class RunnableCallTask : public Task
|
||||
{
|
||||
public:
|
||||
explicit RunnableCallTask(nsIRunnable* aRunnable)
|
||||
: mRunnable(aRunnable) {}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
mRunnable->Run();
|
||||
}
|
||||
protected:
|
||||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
MediaSystemResourceManager::Init()
|
||||
{
|
||||
MOZ_ASSERT(IsMediaSystemResourceManagerEnabled());
|
||||
if (!ImageBridgeChild::IsCreated()) {
|
||||
NS_WARNING("ImageBridge does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
if (InImageBridgeChildThread()) {
|
||||
if (!sSingleton) {
|
||||
#ifdef DEBUG
|
||||
static int timesCreated = 0;
|
||||
timesCreated++;
|
||||
MOZ_ASSERT(timesCreated == 1);
|
||||
#endif
|
||||
sSingleton = new MediaSystemResourceManager();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantMonitor barrier("MediaSystemResourceManager::Init");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableFunction([&]() {
|
||||
if (!sSingleton) {
|
||||
sSingleton = new MediaSystemResourceManager();
|
||||
}
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
done = true;
|
||||
barrier.NotifyAll();
|
||||
});
|
||||
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
FROM_HERE, new RunnableCallTask(runnable));
|
||||
|
||||
// should stop the thread until done.
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MediaSystemResourceManager::MediaSystemResourceManager()
|
||||
: mReentrantMonitor("MediaSystemResourceManager.mReentrantMonitor")
|
||||
, mShutDown(false)
|
||||
, mChild(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
OpenIPC();
|
||||
}
|
||||
|
||||
MediaSystemResourceManager::~MediaSystemResourceManager()
|
||||
{
|
||||
MOZ_ASSERT(IsIpcClosed());
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::OpenIPC()
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
MOZ_ASSERT(!mChild);
|
||||
|
||||
media::PMediaSystemResourceManagerChild* child =
|
||||
ImageBridgeChild::GetSingleton()->SendPMediaSystemResourceManagerConstructor();
|
||||
mChild = static_cast<media::MediaSystemResourceManagerChild*>(child);
|
||||
mChild->SetManager(this);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::CloseIPC()
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
|
||||
if (!mChild) {
|
||||
return;
|
||||
}
|
||||
mChild->Destroy();
|
||||
mChild = nullptr;
|
||||
mShutDown = true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::OnIpcClosed()
|
||||
{
|
||||
mChild = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManager::IsIpcClosed()
|
||||
{
|
||||
return mChild ? true : false;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::Register(MediaSystemResourceClient* aClient)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MOZ_ASSERT(aClient);
|
||||
MOZ_ASSERT(!mResourceClients.Get(aClient->mId));
|
||||
|
||||
mResourceClients.Put(aClient->mId, aClient);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::Unregister(MediaSystemResourceClient* aClient)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MOZ_ASSERT(aClient);
|
||||
MOZ_ASSERT(mResourceClients.Get(aClient->mId));
|
||||
MOZ_ASSERT(mResourceClients.Get(aClient->mId) == aClient);
|
||||
|
||||
mResourceClients.Remove(aClient->mId);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManager::SetListener(MediaSystemResourceClient* aClient,
|
||||
MediaSystemResourceReservationListener* aListener)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MOZ_ASSERT(aClient);
|
||||
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
|
||||
MOZ_ASSERT(client);
|
||||
|
||||
if (!client) {
|
||||
return false;
|
||||
}
|
||||
// State Check
|
||||
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
|
||||
return false;
|
||||
}
|
||||
aClient->mListener = aListener;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(aClient);
|
||||
MOZ_ASSERT(!InImageBridgeChildThread());
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
|
||||
MOZ_ASSERT(client);
|
||||
MOZ_ASSERT(client == aClient);
|
||||
|
||||
aClient->mIsSync = false; // async request
|
||||
|
||||
if (!client) {
|
||||
HandleAcquireResult(aClient->mId, false);
|
||||
return;
|
||||
}
|
||||
// State Check
|
||||
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
|
||||
HandleAcquireResult(aClient->mId, false);
|
||||
return;
|
||||
}
|
||||
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&MediaSystemResourceManager::DoAcquire,
|
||||
aClient->mId));
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(aClient);
|
||||
MOZ_ASSERT(!InImageBridgeChildThread());
|
||||
|
||||
ReentrantMonitor barrier("MediaSystemResourceManager::AcquireSyncNoWait");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
bool done = false;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
|
||||
MOZ_ASSERT(client);
|
||||
MOZ_ASSERT(client == aClient);
|
||||
|
||||
aClient->mIsSync = true; // sync request
|
||||
|
||||
if (InImageBridgeChildThread()) {
|
||||
HandleAcquireResult(aClient->mId, false);
|
||||
return false;
|
||||
}
|
||||
if (!aClient ||
|
||||
!client ||
|
||||
client != aClient) {
|
||||
HandleAcquireResult(aClient->mId, false);
|
||||
return false;
|
||||
}
|
||||
// State Check
|
||||
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_START) {
|
||||
HandleAcquireResult(aClient->mId, false);
|
||||
return false;
|
||||
}
|
||||
// Hold barrier Monitor until acquire task end.
|
||||
aClient->mAcquireSyncWaitMonitor = &barrier;
|
||||
aClient->mAcquireSyncWaitDone = &done;
|
||||
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING;
|
||||
}
|
||||
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&MediaSystemResourceManager::DoAcquire,
|
||||
aClient->mId));
|
||||
|
||||
// should stop the thread until done.
|
||||
while (!done) {
|
||||
barrier.Wait();
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
if (aClient->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::DoAcquire(uint32_t aId)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
if (mShutDown || !mChild) {
|
||||
HandleAcquireResult(aId, false);
|
||||
return;
|
||||
}
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aId);
|
||||
MOZ_ASSERT(client);
|
||||
|
||||
if (!client ||
|
||||
client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
|
||||
HandleAcquireResult(aId, false);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aId == client->mId);
|
||||
bool willWait = !client->mAcquireSyncWaitMonitor ? true : false;
|
||||
mChild->SendAcquire(client->mId,
|
||||
client->mResourceType,
|
||||
willWait);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient)
|
||||
{
|
||||
MOZ_ASSERT(aClient);
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aClient->mId);
|
||||
MOZ_ASSERT(client);
|
||||
MOZ_ASSERT(client == aClient);
|
||||
|
||||
if (!client ||
|
||||
client != aClient ||
|
||||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_START ||
|
||||
aClient->mResourceState == MediaSystemResourceClient::RESOURCE_STATE_END) {
|
||||
|
||||
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
|
||||
return;
|
||||
}
|
||||
|
||||
aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END;
|
||||
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&MediaSystemResourceManager::DoRelease,
|
||||
aClient->mId));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::DoRelease(uint32_t aId)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
if (mShutDown || !mChild) {
|
||||
return;
|
||||
}
|
||||
mChild->SendRelease(aId);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::RecvResponse(uint32_t aId, bool aSuccess)
|
||||
{
|
||||
HandleAcquireResult(aId, aSuccess);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess)
|
||||
{
|
||||
if (!InImageBridgeChildThread()) {
|
||||
ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(
|
||||
this,
|
||||
&MediaSystemResourceManager::HandleAcquireResult,
|
||||
aId,
|
||||
aSuccess));
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
MediaSystemResourceClient* client = mResourceClients.Get(aId);
|
||||
if (!client) {
|
||||
// Client was already unregistered.
|
||||
return;
|
||||
}
|
||||
if (client->mResourceState != MediaSystemResourceClient::RESOURCE_STATE_WAITING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state
|
||||
if (aSuccess) {
|
||||
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_ACQUIRED;
|
||||
} else {
|
||||
client->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_NOT_ACQUIRED;
|
||||
}
|
||||
|
||||
if (client->mIsSync) {
|
||||
if (client->mAcquireSyncWaitMonitor) {
|
||||
// Notify AcquireSync() complete
|
||||
MOZ_ASSERT(client->mAcquireSyncWaitDone);
|
||||
ReentrantMonitorAutoEnter autoMon(*client->mAcquireSyncWaitMonitor);
|
||||
*client->mAcquireSyncWaitDone = true;
|
||||
client->mAcquireSyncWaitMonitor->NotifyAll();
|
||||
client->mAcquireSyncWaitMonitor = nullptr;
|
||||
client->mAcquireSyncWaitDone = nullptr;
|
||||
}
|
||||
} else {
|
||||
// Notify Acquire() result
|
||||
if (client->mListener) {
|
||||
if (aSuccess) {
|
||||
client->mListener->ResourceReserved();
|
||||
} else {
|
||||
client->mListener->ResourceReserveFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceManager_h_)
|
||||
#define MediaSystemResourceManager_h_
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "MediaSystemResourceTypes.h"
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace media {
|
||||
class MediaSystemResourceManagerChild;
|
||||
}
|
||||
|
||||
class MediaSystemResourceClient;
|
||||
class MediaSystemResourceReservationListener;
|
||||
class MediaTaskQueue;
|
||||
class ReentrantMonitor;
|
||||
|
||||
/**
|
||||
* Manage media system resource allocation requests within a process.
|
||||
*/
|
||||
class MediaSystemResourceManager
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceManager)
|
||||
|
||||
static MediaSystemResourceManager* Get();
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void OnIpcClosed();
|
||||
|
||||
void Register(MediaSystemResourceClient* aClient);
|
||||
void Unregister(MediaSystemResourceClient* aClient);
|
||||
|
||||
bool SetListener(MediaSystemResourceClient* aClient,
|
||||
MediaSystemResourceReservationListener* aListener);
|
||||
|
||||
void Acquire(MediaSystemResourceClient* aClient);
|
||||
bool AcquireSyncNoWait(MediaSystemResourceClient* aClient);
|
||||
void ReleaseResource(MediaSystemResourceClient* aClient);
|
||||
|
||||
void RecvResponse(uint32_t aId, bool aSuccess);
|
||||
|
||||
private:
|
||||
MediaSystemResourceManager();
|
||||
virtual ~MediaSystemResourceManager();
|
||||
|
||||
static bool IsMediaSystemResourceManagerEnabled();
|
||||
|
||||
void OpenIPC();
|
||||
void CloseIPC();
|
||||
bool IsIpcClosed();
|
||||
|
||||
void DoAcquire(uint32_t aId);
|
||||
|
||||
void DoRelease(uint32_t aId);
|
||||
|
||||
void HandleAcquireResult(uint32_t aId, bool aSuccess);
|
||||
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
bool mShutDown;
|
||||
|
||||
media::MediaSystemResourceManagerChild* mChild;
|
||||
|
||||
nsDataHashtable<nsUint32HashKey, MediaSystemResourceClient*> mResourceClients;
|
||||
|
||||
static StaticRefPtr<MediaSystemResourceManager> sSingleton;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "MediaSystemResourceManager.h"
|
||||
|
||||
#include "MediaSystemResourceManagerChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
MediaSystemResourceManagerChild::MediaSystemResourceManagerChild()
|
||||
: mDestroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
MediaSystemResourceManagerChild::~MediaSystemResourceManagerChild()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManagerChild::RecvResponse(const uint32_t& aId,
|
||||
const bool& aSuccess)
|
||||
{
|
||||
if (mManager) {
|
||||
mManager->RecvResponse(aId, aSuccess);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManagerChild::ActorDestroy(ActorDestroyReason aActorDestroyReason)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
if (mManager) {
|
||||
mManager->OnIpcClosed();
|
||||
}
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManagerChild::Destroy()
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
SendRemoveResourceManager();
|
||||
// WARNING: |this| is dead, hands off
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceManagerChild_h_)
|
||||
#define MediaSystemResourceManagerChild_h_
|
||||
|
||||
#include "mozilla/media/PMediaSystemResourceManagerChild.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class MediaSystemResourceManager;
|
||||
|
||||
namespace ipc {
|
||||
class BackgroundChildImpl;
|
||||
}
|
||||
|
||||
namespace media {
|
||||
|
||||
/**
|
||||
* Handle MediaSystemResourceManager's IPC
|
||||
*/
|
||||
class MediaSystemResourceManagerChild final : public PMediaSystemResourceManagerChild
|
||||
{
|
||||
public:
|
||||
struct ResourceListener {
|
||||
/* The resource is reserved and can be granted.
|
||||
* The client can allocate the requested resource.
|
||||
*/
|
||||
virtual void resourceReserved() = 0;
|
||||
/* The resource is not reserved any more.
|
||||
* The client should release the resource as soon as possible if the
|
||||
* resource is still being held.
|
||||
*/
|
||||
virtual void resourceCanceled() = 0;
|
||||
};
|
||||
|
||||
MediaSystemResourceManagerChild();
|
||||
virtual ~MediaSystemResourceManagerChild();
|
||||
|
||||
void Destroy();
|
||||
|
||||
void SetManager(MediaSystemResourceManager* aManager)
|
||||
{
|
||||
mManager = aManager;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool RecvResponse(const uint32_t& aId,
|
||||
const bool& aSuccess) override;
|
||||
|
||||
private:
|
||||
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
|
||||
|
||||
bool mDestroyed;
|
||||
MediaSystemResourceManager* mManager;
|
||||
|
||||
friend class mozilla::ipc::BackgroundChildImpl;
|
||||
};
|
||||
|
||||
} // namespatce media
|
||||
} // namespatce mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "MediaSystemResourceManagerParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
MediaSystemResourceManagerParent::MediaSystemResourceManagerParent()
|
||||
: mDestroyed(false)
|
||||
{
|
||||
mMediaSystemResourceService = MediaSystemResourceService::Get();
|
||||
}
|
||||
|
||||
MediaSystemResourceManagerParent::~MediaSystemResourceManagerParent()
|
||||
{
|
||||
MOZ_ASSERT(mDestroyed);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManagerParent::RecvAcquire(const uint32_t& aId,
|
||||
const MediaSystemResourceType& aResourceType,
|
||||
const bool& aWillWait)
|
||||
{
|
||||
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
|
||||
MOZ_ASSERT(!request);
|
||||
if (request) {
|
||||
// Send fail response
|
||||
mozilla::unused << SendResponse(aId, false /* fail */);
|
||||
return true;
|
||||
}
|
||||
|
||||
request = new MediaSystemResourceRequest(aId, aResourceType);
|
||||
mResourceRequests.Put(aId, request);
|
||||
mMediaSystemResourceService->Acquire(this, aId, aResourceType, aWillWait);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManagerParent::RecvRelease(const uint32_t& aId)
|
||||
{
|
||||
MediaSystemResourceRequest* request = mResourceRequests.Get(aId);
|
||||
if (!request) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mMediaSystemResourceService->ReleaseResource(this, aId, request->mResourceType);
|
||||
mResourceRequests.Remove(aId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSystemResourceManagerParent::RecvRemoveResourceManager()
|
||||
{
|
||||
return PMediaSystemResourceManagerParent::Send__delete__(this);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceManagerParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
|
||||
// Release all resource requests of the MediaSystemResourceManagerParent.
|
||||
// Clears all remaining pointers to this object.
|
||||
mMediaSystemResourceService->ReleaseResource(this);
|
||||
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,57 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceManagerParent_h_)
|
||||
#define MediaSystemResourceManagerParent_h_
|
||||
|
||||
#include "MediaSystemResourceManager.h"
|
||||
#include "MediaSystemResourceService.h"
|
||||
#include "MediaSystemResourceTypes.h"
|
||||
#include "mozilla/media/PMediaSystemResourceManagerParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
/**
|
||||
* Handle MediaSystemResourceManager's IPC
|
||||
*/
|
||||
class MediaSystemResourceManagerParent final : public PMediaSystemResourceManagerParent
|
||||
{
|
||||
public:
|
||||
MediaSystemResourceManagerParent();
|
||||
virtual ~MediaSystemResourceManagerParent();
|
||||
|
||||
protected:
|
||||
bool RecvAcquire(const uint32_t& aId,
|
||||
const MediaSystemResourceType& aResourceType,
|
||||
const bool& aWillWait) override;
|
||||
|
||||
bool RecvRelease(const uint32_t& aId) override;
|
||||
|
||||
bool RecvRemoveResourceManager() override;
|
||||
|
||||
private:
|
||||
void ActorDestroy(ActorDestroyReason aActorDestroyReason) override;
|
||||
|
||||
struct MediaSystemResourceRequest {
|
||||
MediaSystemResourceRequest()
|
||||
: mId(-1), mResourceType(MediaSystemResourceType::INVALID_RESOURCE) {}
|
||||
MediaSystemResourceRequest(uint32_t aId, MediaSystemResourceType aResourceType)
|
||||
: mId(aId), mResourceType(aResourceType) {}
|
||||
int32_t mId;
|
||||
MediaSystemResourceType mResourceType;
|
||||
};
|
||||
|
||||
bool mDestroyed;
|
||||
|
||||
nsRefPtr<MediaSystemResourceService> mMediaSystemResourceService;
|
||||
|
||||
nsClassHashtable<nsUint32HashKey, MediaSystemResourceRequest> mResourceRequests;
|
||||
};
|
||||
|
||||
} // namespatce media
|
||||
} // namespatce mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceMessageUtils_h_)
|
||||
#define MediaSystemResourceMessageUtils_h_
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "MediaSystemResourceTypes.h"
|
||||
|
||||
namespace IPC {
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::MediaSystemResourceType>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::MediaSystemResourceType,
|
||||
mozilla::MediaSystemResourceType::VIDEO_DECODER,
|
||||
mozilla::MediaSystemResourceType::INVALID_RESOURCE>
|
||||
{};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/* -*- 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 "MediaSystemResourceManagerParent.h"
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "MediaSystemResourceService.h"
|
||||
|
||||
using namespace mozilla::layers;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */ StaticRefPtr<MediaSystemResourceService> MediaSystemResourceService::sSingleton;
|
||||
|
||||
/* static */ MediaSystemResourceService*
|
||||
MediaSystemResourceService::Get()
|
||||
{
|
||||
if (sSingleton) {
|
||||
return sSingleton;
|
||||
}
|
||||
Init();
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
MediaSystemResourceService::Init()
|
||||
{
|
||||
if (!sSingleton) {
|
||||
sSingleton = new MediaSystemResourceService();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
MediaSystemResourceService::Shutdown()
|
||||
{
|
||||
if (sSingleton) {
|
||||
sSingleton->Destroy();
|
||||
sSingleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MediaSystemResourceService::MediaSystemResourceService()
|
||||
: mDestroyed(false)
|
||||
{
|
||||
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
// The maximum number of hardware resoureces available.
|
||||
// XXX need to hange to a dynamic way.
|
||||
enum
|
||||
{
|
||||
VIDEO_DECODER_COUNT = 1,
|
||||
VIDEO_ENCODER_COUNT = 1
|
||||
};
|
||||
|
||||
MediaSystemResource* resource;
|
||||
|
||||
resource = new MediaSystemResource(VIDEO_DECODER_COUNT);
|
||||
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_DECODER), resource);
|
||||
|
||||
resource = new MediaSystemResource(VIDEO_ENCODER_COUNT);
|
||||
mResources.Put(static_cast<uint32_t>(MediaSystemResourceType::VIDEO_ENCODER), resource);
|
||||
#endif
|
||||
}
|
||||
|
||||
MediaSystemResourceService::~MediaSystemResourceService()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::Destroy()
|
||||
{
|
||||
mDestroyed = true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::Acquire(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType,
|
||||
bool aWillWait)
|
||||
{
|
||||
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
|
||||
|
||||
if (!resource ||
|
||||
resource->mResourceCount == 0) {
|
||||
// Resource does not exit
|
||||
// Send fail response
|
||||
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to acquire a resource
|
||||
if (resource->mAcquiredRequests.size() < resource->mResourceCount) {
|
||||
// Resource is available
|
||||
resource->mAcquiredRequests.push_back(
|
||||
MediaSystemResourceRequest(aParent, aId));
|
||||
// Send success response
|
||||
mozilla::unused << aParent->SendResponse(aId, true /* success */);
|
||||
return;
|
||||
} else if (!aWillWait) {
|
||||
// Resource is not available and do not wait.
|
||||
// Send fail response
|
||||
mozilla::unused << aParent->SendResponse(aId, false /* fail */);
|
||||
return;
|
||||
}
|
||||
// Wait until acquire.
|
||||
resource->mWaitingRequests.push_back(
|
||||
MediaSystemResourceRequest(aParent, aId));
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType)
|
||||
{
|
||||
MOZ_ASSERT(CompositorParent::IsInCompositorThread());
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
|
||||
|
||||
if (!resource ||
|
||||
resource->mResourceCount == 0) {
|
||||
// Resource does not exit
|
||||
return;
|
||||
}
|
||||
RemoveRequest(aParent, aId, aResourceType);
|
||||
UpdateRequests(aResourceType);
|
||||
}
|
||||
|
||||
struct ReleaseResourceData
|
||||
{
|
||||
MediaSystemResourceService* mSelf;
|
||||
media::MediaSystemResourceManagerParent* mParent;
|
||||
};
|
||||
|
||||
/*static*/PLDHashOperator
|
||||
MediaSystemResourceService::ReleaseResourceForKey(const uint32_t& aKey,
|
||||
nsAutoPtr<MediaSystemResource>& aData,
|
||||
void* aClosure)
|
||||
{
|
||||
ReleaseResourceData* closure = static_cast<ReleaseResourceData*>(aClosure);
|
||||
|
||||
closure->mSelf->RemoveRequests(closure->mParent, static_cast<MediaSystemResourceType>(aKey));
|
||||
closure->mSelf->UpdateRequests(static_cast<MediaSystemResourceType>(aKey));
|
||||
|
||||
return PLDHashOperator::PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::ReleaseResource(media::MediaSystemResourceManagerParent* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReleaseResourceData data = { this, aParent };
|
||||
mResources.Enumerate(ReleaseResourceForKey, &data);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
|
||||
if (!resource) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::deque<MediaSystemResourceRequest>::iterator it;
|
||||
std::deque<MediaSystemResourceRequest>& acquiredRequests =
|
||||
resource->mAcquiredRequests;
|
||||
for (it = acquiredRequests.begin(); it != acquiredRequests.end(); it++) {
|
||||
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
|
||||
acquiredRequests.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<MediaSystemResourceRequest>& waitingRequests =
|
||||
resource->mWaitingRequests;
|
||||
for (it = waitingRequests.begin(); it != waitingRequests.end(); it++) {
|
||||
if (((*it).mParent == aParent) && ((*it).mId == aId)) {
|
||||
waitingRequests.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
|
||||
MediaSystemResourceType aResourceType)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
|
||||
|
||||
if (!resource ||
|
||||
resource->mResourceCount == 0) {
|
||||
// Resource does not exit
|
||||
return;
|
||||
}
|
||||
|
||||
std::deque<MediaSystemResourceRequest>::iterator it;
|
||||
std::deque<MediaSystemResourceRequest>& acquiredRequests =
|
||||
resource->mAcquiredRequests;
|
||||
for (it = acquiredRequests.begin(); it != acquiredRequests.end();) {
|
||||
if ((*it).mParent == aParent) {
|
||||
it = acquiredRequests.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<MediaSystemResourceRequest>& waitingRequests =
|
||||
resource->mWaitingRequests;
|
||||
for (it = waitingRequests.begin(); it != waitingRequests.end();) {
|
||||
if ((*it).mParent == aParent) {
|
||||
it = waitingRequests.erase(it);
|
||||
return;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSystemResourceService::UpdateRequests(MediaSystemResourceType aResourceType)
|
||||
{
|
||||
MediaSystemResource* resource = mResources.Get(static_cast<uint32_t>(aResourceType));
|
||||
|
||||
if (!resource ||
|
||||
resource->mResourceCount == 0) {
|
||||
// Resource does not exit
|
||||
return;
|
||||
}
|
||||
|
||||
std::deque<MediaSystemResourceRequest>& acquiredRequests =
|
||||
resource->mAcquiredRequests;
|
||||
std::deque<MediaSystemResourceRequest>& waitingRequests =
|
||||
resource->mWaitingRequests;
|
||||
|
||||
while ((acquiredRequests.size() < resource->mResourceCount) &&
|
||||
(waitingRequests.size() > 0)) {
|
||||
MediaSystemResourceRequest& request = waitingRequests.front();
|
||||
MOZ_ASSERT(request.mParent);
|
||||
// Send response
|
||||
mozilla::unused << request.mParent->SendResponse(request.mId, true /* success */);
|
||||
// Move request to mAcquiredRequests
|
||||
acquiredRequests.push_back(waitingRequests.front());
|
||||
waitingRequests.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,93 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceService_h_)
|
||||
#define MediaSystemResourceService_h_
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "MediaSystemResourceTypes.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace media {
|
||||
class MediaSystemResourceManagerParent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage media system resource allocation requests within system.
|
||||
*/
|
||||
class MediaSystemResourceService
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSystemResourceService)
|
||||
|
||||
static MediaSystemResourceService* Get();
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
void Acquire(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType,
|
||||
bool aWillWait);
|
||||
|
||||
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType);
|
||||
|
||||
void ReleaseResource(media::MediaSystemResourceManagerParent* aParent);
|
||||
|
||||
private:
|
||||
MediaSystemResourceService();
|
||||
~MediaSystemResourceService();
|
||||
|
||||
struct MediaSystemResourceRequest {
|
||||
MediaSystemResourceRequest()
|
||||
: mParent(nullptr), mId(-1) {}
|
||||
MediaSystemResourceRequest(media::MediaSystemResourceManagerParent* aParent, uint32_t aId)
|
||||
: mParent(aParent), mId(aId) {}
|
||||
media::MediaSystemResourceManagerParent* mParent;
|
||||
uint32_t mId;
|
||||
};
|
||||
|
||||
struct MediaSystemResource {
|
||||
MediaSystemResource()
|
||||
: mResourceCount(0) {}
|
||||
explicit MediaSystemResource(uint32_t aResourceCount)
|
||||
: mResourceCount(aResourceCount) {}
|
||||
|
||||
std::deque<MediaSystemResourceRequest> mWaitingRequests;
|
||||
std::deque<MediaSystemResourceRequest> mAcquiredRequests;
|
||||
uint32_t mResourceCount;
|
||||
};
|
||||
|
||||
void Destroy();
|
||||
|
||||
void RemoveRequest(media::MediaSystemResourceManagerParent* aParent,
|
||||
uint32_t aId,
|
||||
MediaSystemResourceType aResourceType);
|
||||
|
||||
void RemoveRequests(media::MediaSystemResourceManagerParent* aParent,
|
||||
MediaSystemResourceType aResourceType);
|
||||
|
||||
void UpdateRequests(MediaSystemResourceType aResourceType);
|
||||
|
||||
static PLDHashOperator ReleaseResourceForKey(const uint32_t& aKey,
|
||||
nsAutoPtr<MediaSystemResource>& aData,
|
||||
void* aClosure);
|
||||
|
||||
bool mDestroyed;
|
||||
|
||||
nsClassHashtable<nsUint32HashKey, MediaSystemResource> mResources;
|
||||
|
||||
static StaticRefPtr<MediaSystemResourceService> sSingleton;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#if !defined(MediaSystemResourceTypes_h_)
|
||||
#define MediaSystemResourceTypes_h_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum class MediaSystemResourceType : uint32_t {
|
||||
VIDEO_DECODER = 0,
|
||||
AUDIO_DECODER, // Not supported currently.
|
||||
VIDEO_ENCODER,
|
||||
AUDIO_ENCODER, // Not supported currently.
|
||||
CAMERA, // Not supported currently.
|
||||
INVALID_RESOURCE,
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
include protocol PImageBridge;
|
||||
include "mozilla/media/MediaSystemResourceMessageUtils.h";
|
||||
|
||||
using mozilla::MediaSystemResourceType from "mozilla/media/MediaSystemResourceTypes.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace media {
|
||||
|
||||
/*
|
||||
* The PMediaSystemResourceManager is a sub-protocol in PImageBridge
|
||||
*/
|
||||
sync protocol PMediaSystemResourceManager
|
||||
{
|
||||
manager PImageBridge;
|
||||
|
||||
child:
|
||||
async Response(uint32_t aId, bool aSuccess);
|
||||
async __delete__();
|
||||
|
||||
parent:
|
||||
async Acquire(uint32_t aId, MediaSystemResourceType aResourceType, bool aWillWait);
|
||||
async Release(uint32_t aId);
|
||||
|
||||
/**
|
||||
* Asynchronously tell the parent side to remove the PMediaSystemResourceManager.
|
||||
*/
|
||||
async RemoveResourceManager();
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -38,15 +38,28 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.media += ['MediaChild.h',
|
||||
'MediaParent.h',
|
||||
'MediaUtils.h'
|
||||
'MediaParent.h',
|
||||
'MediaSystemResourceClient.h',
|
||||
'MediaSystemResourceManager.h',
|
||||
'MediaSystemResourceManagerChild.h',
|
||||
'MediaSystemResourceManagerParent.h',
|
||||
'MediaSystemResourceMessageUtils.h',
|
||||
'MediaSystemResourceService.h',
|
||||
'MediaSystemResourceTypes.h',
|
||||
'MediaUtils.h'
|
||||
]
|
||||
UNIFIED_SOURCES += ['MediaChild.cpp',
|
||||
'MediaParent.cpp',
|
||||
'MediaUtils.cpp'
|
||||
'MediaSystemResourceClient.cpp',
|
||||
'MediaSystemResourceManager.cpp',
|
||||
'MediaSystemResourceManagerChild.cpp',
|
||||
'MediaSystemResourceManagerParent.cpp',
|
||||
'MediaSystemResourceService.cpp',
|
||||
'MediaUtils.cpp',
|
||||
]
|
||||
IPDL_SOURCES += [
|
||||
'PMedia.ipdl',
|
||||
'PMediaSystemResourceManager.ipdl',
|
||||
]
|
||||
# /dom/base needed for nsGlobalWindow.h in MediaChild.cpp
|
||||
LOCAL_INCLUDES += [
|
||||
|
||||
@@ -14,18 +14,18 @@
|
||||
* E: element type, must be a POD type.
|
||||
* N: N bytes alignment for the first element, defaults to 32
|
||||
*/
|
||||
template <typename E, int N, typename Alloc>
|
||||
class AlignedTArray_Impl : public nsTArray_Impl<E, Alloc>
|
||||
template <typename E, int N = 32>
|
||||
class AlignedTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
static_assert((N & (N-1)) == 0, "N must be power of 2");
|
||||
typedef nsTArray_Impl<E, Alloc> base_type;
|
||||
typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type;
|
||||
public:
|
||||
typedef E elem_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
typedef typename base_type::index_type index_type;
|
||||
|
||||
AlignedTArray_Impl() {}
|
||||
explicit AlignedTArray_Impl(size_type capacity) : base_type(capacity+sExtra) {}
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity + sExtra) {}
|
||||
elem_type* Elements() { return getAligned(base_type::Elements()); }
|
||||
const elem_type* Elements() const { return getAligned(base_type::Elements()); }
|
||||
elem_type& operator[](index_type i) { return Elements()[i];}
|
||||
@@ -47,8 +47,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
AlignedTArray_Impl(const AlignedTArray_Impl& other) = delete;
|
||||
void operator=(const AlignedTArray_Impl& other) = delete;
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
|
||||
static const size_type sPadding = N <= MOZ_ALIGNOF(E) ? 0 : N - MOZ_ALIGNOF(E);
|
||||
static const size_type sExtra = (sPadding + sizeof(E) - 1) / sizeof(E);
|
||||
@@ -60,34 +60,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedTArray : public AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayInfallibleAllocator> base_type;
|
||||
typedef AlignedTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedTArray() {}
|
||||
explicit AlignedTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedTArray(const AlignedTArray& other) = delete;
|
||||
void operator=(const AlignedTArray& other) = delete;
|
||||
};
|
||||
|
||||
template <typename E, int N=32>
|
||||
class AlignedFallibleTArray : public AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator>
|
||||
{
|
||||
public:
|
||||
typedef AlignedTArray_Impl<E, N, nsTArrayFallibleAllocator> base_type;
|
||||
typedef AlignedFallibleTArray<E, N> self_type;
|
||||
typedef typename base_type::size_type size_type;
|
||||
|
||||
AlignedFallibleTArray() {}
|
||||
explicit AlignedFallibleTArray(size_type capacity) : base_type(capacity) {}
|
||||
private:
|
||||
AlignedFallibleTArray(const AlignedFallibleTArray& other) = delete;
|
||||
void operator=(const AlignedFallibleTArray& other) = delete;
|
||||
};
|
||||
|
||||
#endif // AlignedTArray_h__
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static const uint32_t MAX_FFT_SIZE = 32768;
|
||||
static const size_t CHUNK_COUNT = MAX_FFT_SIZE >> WEBAUDIO_BLOCK_SIZE_BITS;
|
||||
static_assert(MAX_FFT_SIZE == CHUNK_COUNT * WEBAUDIO_BLOCK_SIZE,
|
||||
"MAX_FFT_SIZE must be a multiple of WEBAUDIO_BLOCK_SIZE");
|
||||
static_assert((CHUNK_COUNT & (CHUNK_COUNT - 1)) == 0,
|
||||
"CHUNK_COUNT must be power of 2 for remainder behavior");
|
||||
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(AnalyserNode, AudioNode)
|
||||
@@ -57,20 +65,7 @@ public:
|
||||
{
|
||||
*aOutput = aInput;
|
||||
|
||||
// If the input is silent, we sill need to send a silent buffer
|
||||
if (aOutput->IsNull()) {
|
||||
AllocateAudioBlock(1, aOutput);
|
||||
float* samples =
|
||||
static_cast<float*>(const_cast<void*>(aOutput->mChannelData[0]));
|
||||
PodZero(samples, WEBAUDIO_BLOCK_SIZE);
|
||||
}
|
||||
uint32_t channelCount = aOutput->mChannelData.Length();
|
||||
for (uint32_t channel = 0; channel < channelCount; ++channel) {
|
||||
float* samples =
|
||||
static_cast<float*>(const_cast<void*>(aOutput->mChannelData[channel]));
|
||||
AudioBlockInPlaceScale(samples, aOutput->mVolume);
|
||||
}
|
||||
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, *aOutput);
|
||||
nsRefPtr<TransferBuffer> transfer = new TransferBuffer(aStream, aInput);
|
||||
NS_DispatchToMainThread(transfer);
|
||||
}
|
||||
|
||||
@@ -89,10 +84,15 @@ AnalyserNode::AnalyserNode(AudioContext* aContext)
|
||||
, mMinDecibels(-100.)
|
||||
, mMaxDecibels(-30.)
|
||||
, mSmoothingTimeConstant(.8)
|
||||
, mWriteIndex(0)
|
||||
{
|
||||
mStream = aContext->Graph()->CreateAudioNodeStream(new AnalyserNodeEngine(this),
|
||||
MediaStreamGraph::INTERNAL_STREAM);
|
||||
|
||||
// Enough chunks must be recorded to handle the case of fftSize being
|
||||
// increased to maximum immediately before getFloatTimeDomainData() is
|
||||
// called, for example.
|
||||
(void)mChunks.SetLength(CHUNK_COUNT, fallible);
|
||||
|
||||
AllocateBuffer();
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ AnalyserNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mAnalysisBlock.SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mChunks.SizeOfExcludingThis(aMallocSizeOf);
|
||||
amount += mOutputBuffer.SizeOfExcludingThis(aMallocSizeOf);
|
||||
return amount;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ AnalyserNode::SetFftSize(uint32_t aValue, ErrorResult& aRv)
|
||||
{
|
||||
// Disallow values that are not a power of 2 and outside the [32,32768] range
|
||||
if (aValue < 32 ||
|
||||
aValue > 32768 ||
|
||||
aValue > MAX_FFT_SIZE ||
|
||||
(aValue & (aValue - 1)) != 0) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
@@ -212,11 +212,9 @@ AnalyserNode::GetFloatTimeDomainData(const Float32Array& aArray)
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
float* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
|
||||
size_t length = std::min(aArray.Length(), FftSize());
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
buffer[i] = mBuffer[(i + mWriteIndex) % mBuffer.Length()];;
|
||||
}
|
||||
GetTimeDomainData(buffer, length);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -224,11 +222,18 @@ AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray)
|
||||
{
|
||||
aArray.ComputeLengthAndData();
|
||||
|
||||
unsigned char* buffer = aArray.Data();
|
||||
size_t length = std::min(size_t(aArray.Length()), mBuffer.Length());
|
||||
size_t length = std::min(aArray.Length(), FftSize());
|
||||
|
||||
AlignedTArray<float> tmpBuffer;
|
||||
if (!tmpBuffer.SetLength(length, fallible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetTimeDomainData(tmpBuffer.Elements(), length);
|
||||
|
||||
unsigned char* buffer = aArray.Data();
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
const float value = mBuffer[(i + mWriteIndex) % mBuffer.Length()];
|
||||
const float value = tmpBuffer[i];
|
||||
// scale the value to the range of [0, UCHAR_MAX]
|
||||
const float scaled = std::max(0.0f, std::min(float(UCHAR_MAX),
|
||||
128.0f * (value + 1.0f)));
|
||||
@@ -239,25 +244,19 @@ AnalyserNode::GetByteTimeDomainData(const Uint8Array& aArray)
|
||||
bool
|
||||
AnalyserNode::FFTAnalysis()
|
||||
{
|
||||
float* inputBuffer;
|
||||
AlignedFallibleTArray<float> tmpBuffer;
|
||||
if (mWriteIndex == 0) {
|
||||
inputBuffer = mBuffer.Elements();
|
||||
} else {
|
||||
if (!tmpBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
inputBuffer = tmpBuffer.Elements();
|
||||
memcpy(inputBuffer, mBuffer.Elements() + mWriteIndex, sizeof(float) * (FftSize() - mWriteIndex));
|
||||
memcpy(inputBuffer + FftSize() - mWriteIndex, mBuffer.Elements(), sizeof(float) * mWriteIndex);
|
||||
AlignedTArray<float> tmpBuffer;
|
||||
size_t fftSize = FftSize();
|
||||
if (!tmpBuffer.SetLength(fftSize, fallible)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApplyBlackmanWindow(inputBuffer, FftSize());
|
||||
|
||||
float* inputBuffer = tmpBuffer.Elements();
|
||||
GetTimeDomainData(inputBuffer, fftSize);
|
||||
ApplyBlackmanWindow(inputBuffer, fftSize);
|
||||
mAnalysisBlock.PerformFFT(inputBuffer);
|
||||
|
||||
// Normalize so than an input sine wave at 0dBfs registers as 0dBfs (undo FFT scaling factor).
|
||||
const double magnitudeScale = 1.0 / FftSize();
|
||||
const double magnitudeScale = 1.0 / fftSize;
|
||||
|
||||
for (uint32_t i = 0; i < mOutputBuffer.Length(); ++i) {
|
||||
double scalarMagnitude = NS_hypot(mAnalysisBlock.RealData(i),
|
||||
@@ -289,13 +288,7 @@ bool
|
||||
AnalyserNode::AllocateBuffer()
|
||||
{
|
||||
bool result = true;
|
||||
if (mBuffer.Length() != FftSize()) {
|
||||
if (!mBuffer.SetLength(FftSize(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
memset(mBuffer.Elements(), 0, sizeof(float) * FftSize());
|
||||
mWriteIndex = 0;
|
||||
|
||||
if (mOutputBuffer.Length() != FrequencyBinCount()) {
|
||||
if (!mOutputBuffer.SetLength(FrequencyBinCount(), fallible)) {
|
||||
return false;
|
||||
}
|
||||
@@ -307,31 +300,57 @@ AnalyserNode::AllocateBuffer()
|
||||
void
|
||||
AnalyserNode::AppendChunk(const AudioChunk& aChunk)
|
||||
{
|
||||
const uint32_t bufferSize = mBuffer.Length();
|
||||
const uint32_t channelCount = aChunk.mChannelData.Length();
|
||||
uint32_t chunkDuration = aChunk.mDuration;
|
||||
MOZ_ASSERT((bufferSize & (bufferSize - 1)) == 0); // Must be a power of two!
|
||||
MOZ_ASSERT(channelCount > 0);
|
||||
MOZ_ASSERT(chunkDuration == WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
if (chunkDuration > bufferSize) {
|
||||
// Copy a maximum bufferSize samples.
|
||||
chunkDuration = bufferSize;
|
||||
if (mChunks.Length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
PodCopy(mBuffer.Elements() + mWriteIndex, static_cast<const float*>(aChunk.mChannelData[0]), chunkDuration);
|
||||
for (uint32_t i = 1; i < channelCount; ++i) {
|
||||
AudioBlockAddChannelWithScale(static_cast<const float*>(aChunk.mChannelData[i]), 1.0f,
|
||||
mBuffer.Elements() + mWriteIndex);
|
||||
++mCurrentChunk;
|
||||
mChunks[mCurrentChunk & (CHUNK_COUNT - 1)] = aChunk;
|
||||
}
|
||||
|
||||
// Reads into aData the oldest aLength samples of the fftSize most recent
|
||||
// samples.
|
||||
void
|
||||
AnalyserNode::GetTimeDomainData(float* aData, size_t aLength)
|
||||
{
|
||||
size_t fftSize = FftSize();
|
||||
MOZ_ASSERT(aLength <= fftSize);
|
||||
|
||||
if (mChunks.Length() == 0) {
|
||||
PodZero(aData, aLength);
|
||||
return;
|
||||
}
|
||||
if (channelCount > 1) {
|
||||
AudioBlockInPlaceScale(mBuffer.Elements() + mWriteIndex,
|
||||
1.0f / aChunk.mChannelData.Length());
|
||||
}
|
||||
mWriteIndex += chunkDuration;
|
||||
MOZ_ASSERT(mWriteIndex <= bufferSize);
|
||||
if (mWriteIndex >= bufferSize) {
|
||||
mWriteIndex = 0;
|
||||
|
||||
size_t readChunk =
|
||||
mCurrentChunk - ((fftSize - 1) >> WEBAUDIO_BLOCK_SIZE_BITS);
|
||||
size_t readIndex = (0 - fftSize) & (WEBAUDIO_BLOCK_SIZE - 1);
|
||||
MOZ_ASSERT(readIndex == 0 || readIndex + fftSize == WEBAUDIO_BLOCK_SIZE);
|
||||
|
||||
for (size_t writeIndex = 0; writeIndex < aLength; ) {
|
||||
const AudioChunk& chunk = mChunks[readChunk & (CHUNK_COUNT - 1)];
|
||||
const size_t channelCount = chunk.mChannelData.Length();
|
||||
size_t copyLength =
|
||||
std::min<size_t>(aLength - writeIndex, WEBAUDIO_BLOCK_SIZE);
|
||||
float* dataOut = &aData[writeIndex];
|
||||
|
||||
if (channelCount == 0) {
|
||||
PodZero(dataOut, copyLength);
|
||||
} else {
|
||||
float scale = chunk.mVolume / channelCount;
|
||||
{ // channel 0
|
||||
auto channelData =
|
||||
static_cast<const float*>(chunk.mChannelData[0]) + readIndex;
|
||||
AudioBufferCopyWithScale(channelData, scale, dataOut, copyLength);
|
||||
}
|
||||
for (uint32_t i = 1; i < channelCount; ++i) {
|
||||
auto channelData =
|
||||
static_cast<const float*>(chunk.mChannelData[i]) + readIndex;
|
||||
AudioBufferAddWithScale(channelData, scale, dataOut, copyLength);
|
||||
}
|
||||
}
|
||||
|
||||
readChunk++;
|
||||
writeIndex += copyLength;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,15 +71,16 @@ private:
|
||||
bool AllocateBuffer();
|
||||
bool FFTAnalysis();
|
||||
void ApplyBlackmanWindow(float* aBuffer, uint32_t aSize);
|
||||
void GetTimeDomainData(float* aData, size_t aLength);
|
||||
|
||||
private:
|
||||
FFTBlock mAnalysisBlock;
|
||||
nsTArray<AudioChunk> mChunks;
|
||||
double mMinDecibels;
|
||||
double mMaxDecibels;
|
||||
double mSmoothingTimeConstant;
|
||||
uint32_t mWriteIndex;
|
||||
AlignedFallibleTArray<float> mBuffer;
|
||||
AlignedFallibleTArray<float> mOutputBuffer;
|
||||
size_t mCurrentChunk = 0;
|
||||
AlignedTArray<float> mOutputBuffer;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
+12
-1
@@ -478,11 +478,17 @@ public:
|
||||
ScreenRotation GetScreenRotation() const {
|
||||
return mScreenRotation;
|
||||
}
|
||||
|
||||
void SetScreenRotation(ScreenRotation aRotation) {
|
||||
mScreenRotation = aRotation;
|
||||
}
|
||||
|
||||
TimeStamp GetCompositionTime() const {
|
||||
return mCompositionTime;
|
||||
}
|
||||
void SetCompositionTime(TimeStamp aTimeStamp) {
|
||||
mCompositionTime = aTimeStamp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
|
||||
const gfx::Rect& aVisibleRect,
|
||||
@@ -497,6 +503,11 @@ protected:
|
||||
*/
|
||||
static void SetBackend(LayersBackend backend);
|
||||
|
||||
/**
|
||||
* Render time for the current composition.
|
||||
*/
|
||||
TimeStamp mCompositionTime;
|
||||
|
||||
uint32_t mCompositorID;
|
||||
DiagnosticTypes mDiagnosticTypes;
|
||||
PCompositorParent* mParent;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "mozilla/ipc/CrossProcessMutex.h" // for CrossProcessMutex, etc
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h" // for ImageBridgeChild
|
||||
#include "mozilla/layers/PImageContainerChild.h"
|
||||
#include "mozilla/layers/ImageClient.h" // for ImageClient
|
||||
#include "nsISupportsUtils.h" // for NS_IF_ADDREF
|
||||
#include "YCbCrUtils.h" // for YCbCr conversions
|
||||
@@ -49,6 +50,8 @@ using namespace mozilla::gfx;
|
||||
|
||||
Atomic<int32_t> Image::sSerialCounter(0);
|
||||
|
||||
Atomic<uint32_t> ImageContainer::sGenerationCounter(0);
|
||||
|
||||
already_AddRefed<Image>
|
||||
ImageFactory::CreateImage(ImageFormat aFormat,
|
||||
const gfx::IntSize &,
|
||||
@@ -139,26 +142,55 @@ BufferRecycleBin::GetBuffer(uint32_t aSize)
|
||||
return result;
|
||||
}
|
||||
|
||||
ImageContainer::ImageContainer(ImageContainer::Mode flag)
|
||||
/**
|
||||
* The child side of PImageContainer. It's best to avoid ImageContainer filling
|
||||
* this role since IPDL objects should be associated with a single thread and
|
||||
* ImageContainer definitely isn't. This object belongs to (and is always
|
||||
* destroyed on) the ImageBridge thread, except when we need to destroy it
|
||||
* during shutdown.
|
||||
* An ImageContainer owns one of these; we have a weak reference to our
|
||||
* ImageContainer.
|
||||
*/
|
||||
class ImageContainerChild : public PImageContainerChild {
|
||||
public:
|
||||
explicit ImageContainerChild(ImageContainer* aImageContainer)
|
||||
: mLock("ImageContainerChild"), mImageContainer(aImageContainer) {}
|
||||
void ForgetImageContainer()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mImageContainer = nullptr;
|
||||
}
|
||||
|
||||
// This protects mImageContainer. This is always taken before the
|
||||
// mImageContainer's monitor (when both need to be held).
|
||||
Mutex mLock;
|
||||
ImageContainer* mImageContainer;
|
||||
};
|
||||
|
||||
ImageContainer::ImageContainer(Mode flag)
|
||||
: mReentrantMonitor("ImageContainer.mReentrantMonitor"),
|
||||
mGenerationCounter(++sGenerationCounter),
|
||||
mPaintCount(0),
|
||||
mPreviousImagePainted(false),
|
||||
mImageFactory(new ImageFactory()),
|
||||
mRecycleBin(new BufferRecycleBin()),
|
||||
mImageClient(nullptr)
|
||||
mImageClient(nullptr),
|
||||
mIPDLChild(nullptr)
|
||||
{
|
||||
if (ImageBridgeChild::IsCreated()) {
|
||||
// the refcount of this ImageClient is 1. we don't use a RefPtr here because the refcount
|
||||
// of this class must be done on the ImageBridge thread.
|
||||
switch(flag) {
|
||||
switch (flag) {
|
||||
case SYNCHRONOUS:
|
||||
break;
|
||||
case ASYNCHRONOUS:
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE).take();
|
||||
mIPDLChild = new ImageContainerChild(this);
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE, this).take();
|
||||
MOZ_ASSERT(mImageClient);
|
||||
break;
|
||||
case ASYNCHRONOUS_OVERLAY:
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY).take();
|
||||
mIPDLChild = new ImageContainerChild(this);
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY, this).take();
|
||||
MOZ_ASSERT(mImageClient);
|
||||
break;
|
||||
default:
|
||||
@@ -171,7 +203,8 @@ ImageContainer::ImageContainer(ImageContainer::Mode flag)
|
||||
ImageContainer::~ImageContainer()
|
||||
{
|
||||
if (IsAsync()) {
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
|
||||
mIPDLChild->ForgetImageContainer();
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mImageClient, mIPDLChild);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +219,8 @@ ImageContainer::CreateImage(ImageFormat aFormat)
|
||||
// If this ImageContainer is async but the image type mismatch, fix it here
|
||||
if (ImageBridgeChild::IsCreated()) {
|
||||
ImageBridgeChild::DispatchReleaseImageClient(mImageClient);
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(CompositableType::IMAGE_OVERLAY).take();
|
||||
mImageClient = ImageBridgeChild::GetSingleton()->CreateImageClient(
|
||||
CompositableType::IMAGE_OVERLAY, this).take();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -205,6 +239,9 @@ ImageContainer::SetCurrentImageInternal(Image *aImage)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mActiveImage != aImage) {
|
||||
mGenerationCounter = ++sGenerationCounter;
|
||||
}
|
||||
mActiveImage = aImage;
|
||||
CurrentImageChanged();
|
||||
}
|
||||
@@ -285,12 +322,19 @@ ImageContainer::HasCurrentImage()
|
||||
}
|
||||
|
||||
void
|
||||
ImageContainer::GetCurrentImages(nsTArray<OwningImage>* aImages)
|
||||
ImageContainer::GetCurrentImages(nsTArray<OwningImage>* aImages,
|
||||
uint32_t* aGenerationCounter)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
if (mActiveImage) {
|
||||
aImages->AppendElement()->mImage = mActiveImage;
|
||||
OwningImage* img = aImages->AppendElement();
|
||||
img->mImage = mActiveImage;
|
||||
img->mFrameID = mGenerationCounter;
|
||||
img->mProducerID = 0;
|
||||
}
|
||||
if (aGenerationCounter) {
|
||||
*aGenerationCounter = mGenerationCounter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,5 +598,24 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
|
||||
return textureClient;
|
||||
}
|
||||
|
||||
PImageContainerChild*
|
||||
ImageContainer::GetPImageContainerChild()
|
||||
{
|
||||
return mIPDLChild;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
ImageContainer::NotifyComposite(const ImageCompositeNotification& aNotification)
|
||||
{
|
||||
ImageContainerChild* child =
|
||||
static_cast<ImageContainerChild*>(aNotification.imageContainerChild());
|
||||
if (child) {
|
||||
MutexAutoLock lock(child->mLock);
|
||||
if (child->mImageContainer) {
|
||||
child->mImageContainer->NotifyCompositeInternal(aNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -98,6 +98,9 @@ namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ImageClient;
|
||||
class ImageCompositeNotification;
|
||||
class ImageContainerChild;
|
||||
class PImageContainerChild;
|
||||
class SharedPlanarYCbCrImage;
|
||||
class TextureClient;
|
||||
class CompositableClient;
|
||||
@@ -180,8 +183,9 @@ protected:
|
||||
void* mImplData;
|
||||
int32_t mSerial;
|
||||
ImageFormat mFormat;
|
||||
static mozilla::Atomic<int32_t> sSerialCounter;
|
||||
bool mSent;
|
||||
|
||||
static mozilla::Atomic<int32_t> sSerialCounter;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -284,6 +288,10 @@ public:
|
||||
|
||||
explicit ImageContainer(ImageContainer::Mode flag = SYNCHRONOUS);
|
||||
|
||||
typedef int32_t FrameID;
|
||||
typedef int32_t ProducerID;
|
||||
|
||||
|
||||
/**
|
||||
* Create an Image in one of the given formats.
|
||||
* Picks the "best" format from the list and creates an Image of that
|
||||
@@ -375,17 +383,22 @@ public:
|
||||
|
||||
struct OwningImage {
|
||||
nsRefPtr<Image> mImage;
|
||||
TimeStamp mTimeStamp;
|
||||
FrameID mFrameID;
|
||||
ProducerID mProducerID;
|
||||
};
|
||||
/**
|
||||
* Copy the current Image list to aImages.
|
||||
* This has to add references since otherwise there are race conditions
|
||||
* where the current image is destroyed before the caller can add
|
||||
* a reference. This lock strictly guarantees the underlying image remains
|
||||
* valid, it does not mean the current image cannot change.
|
||||
* a reference.
|
||||
* Can be called on any thread.
|
||||
* May return an empty list to indicate there is no current image.
|
||||
* If aGenerationCounter is non-null, sets *aGenerationCounter to a value
|
||||
* that's unique for this ImageContainer state.
|
||||
*/
|
||||
void GetCurrentImages(nsTArray<OwningImage>* aImages);
|
||||
void GetCurrentImages(nsTArray<OwningImage>* aImages,
|
||||
uint32_t* aGenerationCounter = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the size of the image in pixels.
|
||||
@@ -458,6 +471,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
PImageContainerChild* GetPImageContainerChild();
|
||||
|
||||
static void NotifyComposite(const ImageCompositeNotification& aNotification);
|
||||
|
||||
private:
|
||||
typedef mozilla::ReentrantMonitor ReentrantMonitor;
|
||||
|
||||
@@ -485,7 +502,11 @@ private:
|
||||
mPaintTime = TimeStamp();
|
||||
}
|
||||
|
||||
void NotifyCompositeInternal(const ImageCompositeNotification& aNotification) {}
|
||||
|
||||
nsRefPtr<Image> mActiveImage;
|
||||
// Updates every time mActiveImage changes
|
||||
uint32_t mGenerationCounter;
|
||||
|
||||
// Number of contained images that have been painted at least once. It's up
|
||||
// to the ImageContainer implementation to ensure accesses to this are
|
||||
@@ -516,6 +537,12 @@ private:
|
||||
// frames to the compositor through transactions in the main thread rather than
|
||||
// asynchronusly using the ImageBridge IPDL protocol.
|
||||
ImageClient* mImageClient;
|
||||
|
||||
// Object must be released on the ImageBridge thread. Field is immutable
|
||||
// after creation of the ImageContainer.
|
||||
ImageContainerChild* mIPDLChild;
|
||||
|
||||
static mozilla::Atomic<uint32_t> sGenerationCounter;
|
||||
};
|
||||
|
||||
class AutoLockImage
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsDebug.h" // for NS_WARN_IF
|
||||
#include "yuv_convert.h" // for ConvertYCbCrToRGB32, etc
|
||||
#include "nsDebug.h"
|
||||
|
||||
#define MOZ_ALIGN_WORD(x) (((x) + 3) & ~3)
|
||||
|
||||
|
||||
@@ -103,7 +103,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
GetForwarder()->UseTexture(this, mBuffer);
|
||||
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mBuffer;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize());
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
}
|
||||
@@ -380,7 +384,11 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
|
||||
// Add the new TexClient.
|
||||
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
|
||||
|
||||
forwarder->UseTexture(this, mFront);
|
||||
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mFront;
|
||||
t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
|
||||
forwarder->UseTextures(this, textures);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/ShadowLayerChild.h"
|
||||
#include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
|
||||
#include "mozilla/layers/PersistentBufferProvider.h"
|
||||
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
|
||||
@@ -610,7 +611,6 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ public:
|
||||
virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) override;
|
||||
virtual void RunOverfillCallback(const uint32_t aOverfill) override;
|
||||
|
||||
virtual void DidComposite(uint64_t aTransactionId);
|
||||
void DidComposite(uint64_t aTransactionId);
|
||||
|
||||
virtual bool SupportsMixBlendModes(EnumSet<gfx::CompositionOp>& aMixBlendModes) override
|
||||
{
|
||||
|
||||
@@ -157,12 +157,12 @@ CompositableClient::GetIPDLActor() const
|
||||
}
|
||||
|
||||
bool
|
||||
CompositableClient::Connect()
|
||||
CompositableClient::Connect(ImageContainer* aImageContainer)
|
||||
{
|
||||
if (!GetForwarder() || GetIPDLActor()) {
|
||||
return false;
|
||||
}
|
||||
GetForwarder()->Connect(this);
|
||||
GetForwarder()->Connect(this, aImageContainer);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace layers {
|
||||
class CompositableClient;
|
||||
class BufferTextureClient;
|
||||
class ImageBridgeChild;
|
||||
class ImageContainer;
|
||||
class CompositableForwarder;
|
||||
class CompositableChild;
|
||||
class PCompositableChild;
|
||||
@@ -146,7 +147,7 @@ public:
|
||||
/**
|
||||
* Establishes the connection with compositor side through IPDL
|
||||
*/
|
||||
virtual bool Connect();
|
||||
virtual bool Connect(ImageContainer* aImageContainer = nullptr);
|
||||
|
||||
void Destroy();
|
||||
|
||||
|
||||
@@ -396,7 +396,12 @@ ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
|
||||
mForwarder->UseComponentAlphaTextures(this, mTextureClient,
|
||||
mTextureClientOnWhite);
|
||||
} else {
|
||||
mForwarder->UseTexture(this, mTextureClient);
|
||||
nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = mTextureClient;
|
||||
IntSize size = mTextureClient->GetSize();
|
||||
t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
}
|
||||
mForwarder->UpdateTextureRegion(this,
|
||||
ThebesBufferData(BufferRect(),
|
||||
|
||||
+141
-123
@@ -113,129 +113,159 @@ void
|
||||
ImageClientSingle::FlushAllImages(bool aExceptFront,
|
||||
AsyncTransactionWaiter* aAsyncTransactionWaiter)
|
||||
{
|
||||
if (!aExceptFront && mFrontBuffer) {
|
||||
RemoveTextureWithWaiter(mFrontBuffer, aAsyncTransactionWaiter);
|
||||
mFrontBuffer = nullptr;
|
||||
if (!aExceptFront) {
|
||||
for (auto& b : mBuffers) {
|
||||
RemoveTextureWithWaiter(b.mTextureClient, aAsyncTransactionWaiter);
|
||||
}
|
||||
mBuffers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
|
||||
{
|
||||
AutoLockImage autoLock(aContainer);
|
||||
nsAutoTArray<ImageContainer::OwningImage,4> images;
|
||||
uint32_t generationCounter;
|
||||
aContainer->GetCurrentImages(&images, &generationCounter);
|
||||
|
||||
Image *image = autoLock.GetImage();
|
||||
if (!image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't try to update to an invalid image. We return true because the caller
|
||||
// would attempt to recreate the ImageClient otherwise, and that isn't going
|
||||
// to help.
|
||||
if (!image->IsValid()) {
|
||||
if (mLastUpdateGenerationCounter == generationCounter) {
|
||||
return true;
|
||||
}
|
||||
mLastUpdateGenerationCounter = generationCounter;
|
||||
|
||||
if (mLastPaintedImageSerial == image->GetSerial()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<TextureClient> texture = image->GetTextureClient(this);
|
||||
|
||||
AutoRemoveTexture autoRemoveTexture(this);
|
||||
if (texture != mFrontBuffer) {
|
||||
autoRemoveTexture.mTexture = mFrontBuffer;
|
||||
mFrontBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (!texture) {
|
||||
// Slow path, we should not be hitting it very often and if we do it means
|
||||
// we are using an Image class that is not backed by textureClient and we
|
||||
// should fix it.
|
||||
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
|
||||
const PlanarYCbCrData* data = ycbcr->GetData();
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
texture = TextureClient::CreateForYCbCr(GetForwarder(),
|
||||
data->mYSize, data->mCbCrSize, data->mStereoMode,
|
||||
TextureFlags::DEFAULT | mTextureFlags
|
||||
);
|
||||
if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return false;
|
||||
}
|
||||
bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
|
||||
MOZ_ASSERT(status);
|
||||
|
||||
texture->Unlock();
|
||||
if (!status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
|
||||
image->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
gfx::IntSize size = image->GetSize();
|
||||
|
||||
if (image->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
|
||||
texture = new EGLImageTextureClient(GetForwarder(),
|
||||
mTextureFlags,
|
||||
typedImage,
|
||||
size);
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
|
||||
SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
|
||||
const SurfaceTextureImage::Data* data = typedImage->GetData();
|
||||
texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
|
||||
data->mSurfTex, size,
|
||||
data->mOriginPos);
|
||||
#endif
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Bad ImageFormat.");
|
||||
}
|
||||
} else {
|
||||
RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
|
||||
MOZ_ASSERT(surface);
|
||||
texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
|
||||
gfx::BackendType::NONE, mTextureFlags);
|
||||
if (!texture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texture->CanExposeDrawTarget());
|
||||
|
||||
if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// We must not keep a reference to the DrawTarget after it has been unlocked.
|
||||
DrawTarget* dt = texture->BorrowDrawTarget();
|
||||
if (!dt) {
|
||||
gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(surface.get());
|
||||
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
|
||||
}
|
||||
|
||||
texture->Unlock();
|
||||
for (int32_t i = images.Length() - 1; i >= 0; --i) {
|
||||
if (!images[i].mImage->IsValid()) {
|
||||
// Don't try to update to an invalid image.
|
||||
images.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (!texture || !AddTextureClient(texture)) {
|
||||
return false;
|
||||
if (images.IsEmpty()) {
|
||||
// We return true because the caller would attempt to recreate the
|
||||
// ImageClient otherwise, and that isn't going to help.
|
||||
return true;
|
||||
}
|
||||
|
||||
mFrontBuffer = texture;
|
||||
GetForwarder()->UseTexture(this, texture);
|
||||
nsTArray<Buffer> newBuffers;
|
||||
nsAutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
|
||||
|
||||
UpdatePictureRect(image->GetPictureRect());
|
||||
for (auto& img : images) {
|
||||
Image* image = img.mImage;
|
||||
RefPtr<TextureClient> texture = image->GetTextureClient(this);
|
||||
|
||||
mLastPaintedImageSerial = image->GetSerial();
|
||||
aContainer->NotifyPaintedImage(image);
|
||||
for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
|
||||
if (mBuffers[i].mImageSerial == image->GetSerial()) {
|
||||
if (texture) {
|
||||
MOZ_ASSERT(texture == mBuffers[i].mTextureClient);
|
||||
} else {
|
||||
texture = mBuffers[i].mTextureClient;
|
||||
}
|
||||
// Remove this element from mBuffers so mBuffers only contains
|
||||
// images that aren't present in 'images'
|
||||
mBuffers.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
texture->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
if (!texture) {
|
||||
// Slow path, we should not be hitting it very often and if we do it means
|
||||
// we are using an Image class that is not backed by textureClient and we
|
||||
// should fix it.
|
||||
if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
|
||||
PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
|
||||
const PlanarYCbCrData* data = ycbcr->GetData();
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
texture = TextureClient::CreateForYCbCr(GetForwarder(),
|
||||
data->mYSize, data->mCbCrSize, data->mStereoMode,
|
||||
TextureFlags::DEFAULT | mTextureFlags
|
||||
);
|
||||
if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return false;
|
||||
}
|
||||
bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
|
||||
MOZ_ASSERT(status);
|
||||
|
||||
texture->Unlock();
|
||||
if (!status) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
|
||||
image->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
gfx::IntSize size = image->GetSize();
|
||||
|
||||
if (image->GetFormat() == ImageFormat::EGLIMAGE) {
|
||||
EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
|
||||
texture = new EGLImageTextureClient(GetForwarder(),
|
||||
mTextureFlags,
|
||||
typedImage,
|
||||
size);
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
} else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
|
||||
SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
|
||||
const SurfaceTextureImage::Data* data = typedImage->GetData();
|
||||
texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
|
||||
data->mSurfTex, size,
|
||||
data->mOriginPos);
|
||||
#endif
|
||||
} else {
|
||||
MOZ_ASSERT(false, "Bad ImageFormat.");
|
||||
}
|
||||
} else {
|
||||
RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
|
||||
MOZ_ASSERT(surface);
|
||||
texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
|
||||
gfx::BackendType::NONE, mTextureFlags);
|
||||
if (!texture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(texture->CanExposeDrawTarget());
|
||||
|
||||
if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// We must not keep a reference to the DrawTarget after it has been unlocked.
|
||||
DrawTarget* dt = texture->BorrowDrawTarget();
|
||||
if (!dt) {
|
||||
gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(surface.get());
|
||||
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
|
||||
}
|
||||
|
||||
texture->Unlock();
|
||||
}
|
||||
}
|
||||
if (!texture || !AddTextureClient(texture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
|
||||
t->mTextureClient = texture;
|
||||
t->mTimeStamp = img.mTimeStamp;
|
||||
t->mPictureRect = image->GetPictureRect();
|
||||
t->mFrameID = img.mFrameID;
|
||||
t->mProducerID = img.mProducerID;
|
||||
|
||||
Buffer* newBuf = newBuffers.AppendElement();
|
||||
newBuf->mImageSerial = image->GetSerial();
|
||||
newBuf->mTextureClient = texture;
|
||||
|
||||
aContainer->NotifyPaintedImage(image);
|
||||
texture->SyncWithObject(GetForwarder()->GetSyncObject());
|
||||
}
|
||||
|
||||
GetForwarder()->UseTextures(this, textures);
|
||||
|
||||
for (auto& b : mBuffers) {
|
||||
RemoveTexture(b.mTextureClient);
|
||||
}
|
||||
mBuffers.SwapElements(newBuffers);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -250,7 +280,7 @@ ImageClientSingle::AddTextureClient(TextureClient* aTexture)
|
||||
void
|
||||
ImageClientSingle::OnDetach()
|
||||
{
|
||||
mFrontBuffer = nullptr;
|
||||
mBuffers.Clear();
|
||||
}
|
||||
|
||||
ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
@@ -258,20 +288,9 @@ ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
|
||||
: CompositableClient(aFwd, aFlags)
|
||||
, mLayer(nullptr)
|
||||
, mType(aType)
|
||||
, mLastPaintedImageSerial(0)
|
||||
, mLastUpdateGenerationCounter(0)
|
||||
{}
|
||||
|
||||
void
|
||||
ImageClient::UpdatePictureRect(IntRect aRect)
|
||||
{
|
||||
if (mPictureRect == aRect) {
|
||||
return;
|
||||
}
|
||||
mPictureRect = aRect;
|
||||
MOZ_ASSERT(mForwarder);
|
||||
GetForwarder()->UpdatePictureRect(this, aRect);
|
||||
}
|
||||
|
||||
ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
|
||||
TextureFlags aFlags)
|
||||
: ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
|
||||
@@ -292,7 +311,6 @@ ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag
|
||||
static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
|
||||
AutoLockImage autoLock(aContainer);
|
||||
aContainer->NotifyPaintedImage(autoLock.GetImage());
|
||||
Updated();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -334,9 +352,10 @@ ImageClientOverlay::UpdateImage(ImageContainer* aContainer, uint32_t aContentFla
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mLastPaintedImageSerial == image->GetSerial()) {
|
||||
if (mLastUpdateGenerationCounter == (uint32_t)image->GetSerial()) {
|
||||
return true;
|
||||
}
|
||||
mLastUpdateGenerationCounter = (uint32_t)image->GetSerial();
|
||||
|
||||
AutoRemoveTexture autoRemoveTexture(this);
|
||||
if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) {
|
||||
@@ -347,9 +366,8 @@ ImageClientOverlay::UpdateImage(ImageContainer* aContainer, uint32_t aContentFla
|
||||
OverlaySource source;
|
||||
source.handle() = OverlayHandle(overlayId);
|
||||
source.size() = size;
|
||||
GetForwarder()->UseOverlaySource(this, source);
|
||||
GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect());
|
||||
}
|
||||
UpdatePictureRect(image->GetPictureRect());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -56,12 +56,6 @@ public:
|
||||
*/
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) = 0;
|
||||
|
||||
/**
|
||||
* The picture rect is the area of the texture which makes up the image. That
|
||||
* is, the area that should be composited. In texture space.
|
||||
*/
|
||||
virtual void UpdatePictureRect(gfx::IntRect aPictureRect);
|
||||
|
||||
virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) = 0;
|
||||
|
||||
void SetLayer(ClientLayer* aLayer) { mLayer = aLayer; }
|
||||
@@ -85,8 +79,7 @@ protected:
|
||||
|
||||
ClientLayer* mLayer;
|
||||
CompositableType mType;
|
||||
int32_t mLastPaintedImageSerial;
|
||||
gfx::IntRect mPictureRect;
|
||||
uint32_t mLastUpdateGenerationCounter;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -113,7 +106,11 @@ public:
|
||||
AsyncTransactionWaiter* aAsyncTransactionWaiter) override;
|
||||
|
||||
protected:
|
||||
RefPtr<TextureClient> mFrontBuffer;
|
||||
struct Buffer {
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
int32_t mImageSerial;
|
||||
};
|
||||
nsTArray<Buffer> mBuffers;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -128,8 +125,7 @@ public:
|
||||
TextureFlags aFlags);
|
||||
|
||||
virtual bool UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) override;
|
||||
virtual bool Connect() override { return false; }
|
||||
virtual void Updated() {}
|
||||
virtual bool Connect(ImageContainer* aImageContainer) override { return false; }
|
||||
|
||||
virtual TextureInfo GetTextureInfo() const override
|
||||
{
|
||||
|
||||
@@ -95,17 +95,15 @@ CanvasLayerComposite::RenderLayer(const IntRect& aClipRect)
|
||||
}
|
||||
#endif
|
||||
|
||||
EffectChain effectChain(this);
|
||||
AddBlendModeEffect(effectChain);
|
||||
RenderWithAllMasks(this, mCompositor, aClipRect,
|
||||
[&](EffectChain& effectChain, const Rect& clipRect) {
|
||||
mCompositableHost->Composite(this, effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
});
|
||||
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
|
||||
|
||||
mCompositableHost->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
mCompositableHost->BumpFlashCounter();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,28 +21,17 @@ namespace layers {
|
||||
void
|
||||
ColorLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
|
||||
{
|
||||
EffectChain effects(this);
|
||||
|
||||
GenEffectChain(effects);
|
||||
|
||||
gfx::IntRect boundRect = GetBounds();
|
||||
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(),
|
||||
effects);
|
||||
|
||||
gfx::Rect rect(boundRect.x, boundRect.y,
|
||||
boundRect.width, boundRect.height);
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y,
|
||||
aClipRect.width, aClipRect.height);
|
||||
|
||||
float opacity = GetEffectiveOpacity();
|
||||
|
||||
AddBlendModeEffect(effects);
|
||||
|
||||
gfx::Rect rect(GetBounds());
|
||||
const gfx::Matrix4x4& transform = GetEffectiveTransform();
|
||||
mCompositor->DrawQuad(rect, clipRect, effects, opacity, transform);
|
||||
|
||||
RenderWithAllMasks(this, mCompositor, aClipRect,
|
||||
[&](EffectChain& effectChain, const Rect& clipRect) {
|
||||
GenEffectChain(effectChain);
|
||||
mCompositor->DrawQuad(rect, clipRect, effectChain, GetEffectiveOpacity(), transform);
|
||||
});
|
||||
|
||||
mCompositor->DrawDiagnostics(DiagnosticFlags::COLOR,
|
||||
rect, clipRect,
|
||||
rect, Rect(aClipRect),
|
||||
transform);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "gfxUtils.h"
|
||||
#include "ImageHost.h" // for ImageHostBuffered, etc
|
||||
#include "TiledContentHost.h" // for TiledContentHost
|
||||
#include "mozilla/layers/ImageContainerParent.h"
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "mozilla/nsRefPtr.h" // for nsRefPtr
|
||||
@@ -20,6 +21,9 @@
|
||||
#include "mozilla/layers/PCompositableParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace gfx;
|
||||
|
||||
namespace layers {
|
||||
|
||||
class Compositor;
|
||||
@@ -30,14 +34,15 @@ class Compositor;
|
||||
*
|
||||
* CompositableParent is owned by the IPDL system. It's deletion is triggered
|
||||
* by either the CompositableChild's deletion, or by the IPDL communication
|
||||
* goind down.
|
||||
* going down.
|
||||
*/
|
||||
class CompositableParent : public PCompositableParent
|
||||
{
|
||||
public:
|
||||
CompositableParent(CompositableParentManager* aMgr,
|
||||
const TextureInfo& aTextureInfo,
|
||||
uint64_t aID = 0)
|
||||
uint64_t aID = 0,
|
||||
PImageContainerParent* aImageContainer = nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CompositableParent);
|
||||
mHost = CompositableHost::Create(aTextureInfo);
|
||||
@@ -45,6 +50,10 @@ public:
|
||||
if (aID) {
|
||||
CompositableMap::Set(aID, this);
|
||||
}
|
||||
if (aImageContainer) {
|
||||
mHost->SetImageContainer(
|
||||
static_cast<ImageContainerParent*>(aImageContainer));
|
||||
}
|
||||
}
|
||||
|
||||
~CompositableParent()
|
||||
@@ -84,9 +93,10 @@ CompositableHost::~CompositableHost()
|
||||
PCompositableParent*
|
||||
CompositableHost::CreateIPDLActor(CompositableParentManager* aMgr,
|
||||
const TextureInfo& aTextureInfo,
|
||||
uint64_t aID)
|
||||
uint64_t aID,
|
||||
PImageContainerParent* aImageContainer)
|
||||
{
|
||||
return new CompositableParent(aMgr, aTextureInfo, aID);
|
||||
return new CompositableParent(aMgr, aTextureInfo, aID, aImageContainer);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -104,13 +114,12 @@ CompositableHost::FromIPDLActor(PCompositableParent* aActor)
|
||||
}
|
||||
|
||||
void
|
||||
CompositableHost::UseTextureHost(TextureHost* aTexture)
|
||||
CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
||||
{
|
||||
if (!aTexture) {
|
||||
return;
|
||||
}
|
||||
if (GetCompositor()) {
|
||||
aTexture->SetCompositor(GetCompositor());
|
||||
for (auto& texture : aTextures) {
|
||||
texture.mTexture->SetCompositor(GetCompositor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,9 @@ class DataSourceSurface;
|
||||
namespace layers {
|
||||
|
||||
class Layer;
|
||||
class LayerComposite;
|
||||
class Compositor;
|
||||
class ImageContainerParent;
|
||||
class ThebesBufferData;
|
||||
class TiledContentHost;
|
||||
class CompositableParentManager;
|
||||
@@ -75,7 +77,8 @@ public:
|
||||
virtual void SetCompositor(Compositor* aCompositor);
|
||||
|
||||
// composite the contents of this buffer host to the compositor's surface
|
||||
virtual void Composite(EffectChain& aEffectChain,
|
||||
virtual void Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
@@ -98,16 +101,15 @@ public:
|
||||
|
||||
/**
|
||||
* Returns the front buffer.
|
||||
* *aPictureRect (if non-null, and the returned TextureHost is non-null)
|
||||
* is set to the picture rect.
|
||||
*/
|
||||
virtual TextureHost* GetAsTextureHost() { return nullptr; }
|
||||
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual LayerRenderState GetRenderState() = 0;
|
||||
|
||||
virtual void SetPictureRect(const gfx::IntRect& aPictureRect)
|
||||
{
|
||||
MOZ_ASSERT(false, "Should have been overridden");
|
||||
}
|
||||
|
||||
virtual gfx::IntSize GetImageSize() const
|
||||
{
|
||||
MOZ_ASSERT(false, "Should have been overridden");
|
||||
@@ -132,6 +134,8 @@ public:
|
||||
Layer* GetLayer() const { return mLayer; }
|
||||
void SetLayer(Layer* aLayer) { mLayer = aLayer; }
|
||||
|
||||
virtual void SetImageContainer(ImageContainerParent* aImageContainer) {}
|
||||
|
||||
virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
|
||||
|
||||
typedef uint32_t AttachFlags;
|
||||
@@ -151,12 +155,6 @@ public:
|
||||
SetLayer(aLayer);
|
||||
mAttached = true;
|
||||
mKeepAttached = aFlags & KEEP_ATTACHED;
|
||||
|
||||
// If we already have a textureHost before, use that in this moment.
|
||||
RefPtr<TextureHost> frontBuffer = GetAsTextureHost();
|
||||
if (frontBuffer) {
|
||||
UseTextureHost(frontBuffer);
|
||||
}
|
||||
}
|
||||
// Detach this compositable host from its layer.
|
||||
// If we are used for async video, then it is not safe to blindly detach since
|
||||
@@ -187,10 +185,18 @@ public:
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) = 0;
|
||||
|
||||
virtual void UseTextureHost(TextureHost* aTexture);
|
||||
struct TimedTexture {
|
||||
RefPtr<TextureHost> mTexture;
|
||||
TimeStamp mTimeStamp;
|
||||
gfx::IntRect mPictureRect;
|
||||
int32_t mFrameID;
|
||||
int32_t mProducerID;
|
||||
};
|
||||
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures);
|
||||
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
|
||||
TextureHost* aTextureOnWhite);
|
||||
virtual void UseOverlaySource(OverlaySource aOverlay) { }
|
||||
virtual void UseOverlaySource(OverlaySource aOverlay,
|
||||
const gfx::IntRect& aPictureRect) { }
|
||||
|
||||
virtual void RemoveTextureHost(TextureHost* aTexture);
|
||||
|
||||
@@ -203,7 +209,8 @@ public:
|
||||
static PCompositableParent*
|
||||
CreateIPDLActor(CompositableParentManager* mgr,
|
||||
const TextureInfo& textureInfo,
|
||||
uint64_t asyncID);
|
||||
uint64_t asyncID,
|
||||
PImageContainerParent* aImageContainer = nullptr);
|
||||
|
||||
static bool DestroyIPDLActor(PCompositableParent* actor);
|
||||
|
||||
@@ -271,7 +278,7 @@ private:
|
||||
* is async, we store references to the async compositables in a CompositableMap
|
||||
* that is accessed only on the compositor thread. During a layer transaction we
|
||||
* send the message OpAttachAsyncCompositable(ID, PLayer), and on the compositor
|
||||
* side we lookup the ID in the map and attach the correspondig compositable to
|
||||
* side we lookup the ID in the map and attach the corresponding compositable to
|
||||
* the layer.
|
||||
*
|
||||
* CompositableMap must be global because the image bridge doesn't have any
|
||||
|
||||
@@ -490,34 +490,25 @@ ContainerRender(ContainerT* aContainer,
|
||||
return;
|
||||
}
|
||||
|
||||
float opacity = aContainer->GetEffectiveOpacity();
|
||||
|
||||
gfx::IntRect visibleRect = aContainer->GetEffectiveVisibleRegion().GetBounds();
|
||||
gfx::Rect visibleRect(aContainer->GetEffectiveVisibleRegion().GetBounds());
|
||||
nsRefPtr<Compositor> compositor = aManager->GetCompositor();
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpPainting) {
|
||||
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
|
||||
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
|
||||
if (surf) {
|
||||
WriteSnapshotToDumpFile(aContainer, surf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
EffectChain effectChain(aContainer);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
|
||||
effectChain,
|
||||
!aContainer->GetTransform().CanDraw2D());
|
||||
if (autoMaskEffect.Failed()) {
|
||||
NS_WARNING("Failed to apply a mask effect.");
|
||||
return;
|
||||
}
|
||||
|
||||
aContainer->AddBlendModeEffect(effectChain);
|
||||
effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
|
||||
|
||||
gfx::Rect rect(visibleRect.x, visibleRect.y, visibleRect.width, visibleRect.height);
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
|
||||
aManager->GetCompositor()->DrawQuad(rect, clipRect, effectChain, opacity,
|
||||
aContainer->GetEffectiveTransform());
|
||||
nsRefPtr<ContainerT> container = aContainer;
|
||||
RenderWithAllMasks(aContainer, compositor, aClipRect,
|
||||
[&, surface, compositor, container](EffectChain& effectChain, const Rect& clipRect) {
|
||||
effectChain.mPrimaryEffect = new EffectRenderTarget(surface);
|
||||
compositor->DrawQuad(visibleRect, clipRect, effectChain,
|
||||
container->GetEffectiveOpacity(),
|
||||
container->GetEffectiveTransform());
|
||||
});
|
||||
} else {
|
||||
RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ ContentHostBase::~ContentHostBase()
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostTexture::Composite(EffectChain& aEffectChain,
|
||||
ContentHostTexture::Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const Filter& aFilter,
|
||||
@@ -218,10 +219,15 @@ ContentHostTexture::Composite(EffectChain& aEffectChain,
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostTexture::UseTextureHost(TextureHost* aTexture)
|
||||
ContentHostTexture::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
||||
{
|
||||
ContentHostBase::UseTextureHost(aTexture);
|
||||
mTextureHost = aTexture;
|
||||
ContentHostBase::UseTextureHost(aTextures);
|
||||
MOZ_ASSERT(aTextures.Length() == 1);
|
||||
const TimedTexture& t = aTextures[0];
|
||||
MOZ_ASSERT(t.mPictureRect.IsEqualInterior(
|
||||
nsIntRect(nsIntPoint(0, 0), nsIntSize(t.mTexture->GetSize()))),
|
||||
"Only default picture rect supported");
|
||||
mTextureHost = t.mTexture;
|
||||
mTextureHostOnWhite = nullptr;
|
||||
mTextureSourceOnWhite = nullptr;
|
||||
if (mTextureHost) {
|
||||
|
||||
@@ -114,7 +114,8 @@ public:
|
||||
, mLocked(false)
|
||||
{ }
|
||||
|
||||
virtual void Composite(EffectChain& aEffectChain,
|
||||
virtual void Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
@@ -131,7 +132,7 @@ public:
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;
|
||||
|
||||
virtual void UseTextureHost(TextureHost* aTexture) override;
|
||||
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
|
||||
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
|
||||
TextureHost* aTextureOnWhite) override;
|
||||
|
||||
|
||||
+229
-107
@@ -4,11 +4,14 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ImageHost.h"
|
||||
|
||||
#include "LayersLogging.h" // for AppendToString
|
||||
#include "composite/CompositableHost.h" // for CompositableHost, etc
|
||||
#include "ipc/IPCMessageUtils.h" // for null_t
|
||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||
#include "mozilla/layers/ImageContainerParent.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
|
||||
#include "nsAString.h"
|
||||
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
@@ -29,43 +32,155 @@ class ISurfaceAllocator;
|
||||
|
||||
ImageHost::ImageHost(const TextureInfo& aTextureInfo)
|
||||
: CompositableHost(aTextureInfo)
|
||||
, mHasPictureRect(false)
|
||||
, mImageContainer(nullptr)
|
||||
, mLastFrameID(-1)
|
||||
, mLastProducerID(-1)
|
||||
, mLocked(false)
|
||||
{}
|
||||
|
||||
ImageHost::~ImageHost()
|
||||
{}
|
||||
{
|
||||
SetImageContainer(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
ImageHost::UseTextureHost(TextureHost* aTexture)
|
||||
ImageHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures)
|
||||
{
|
||||
CompositableHost::UseTextureHost(aTexture);
|
||||
mFrontBuffer = aTexture;
|
||||
if (mFrontBuffer) {
|
||||
mFrontBuffer->Updated();
|
||||
mFrontBuffer->PrepareTextureSource(mTextureSource);
|
||||
MOZ_ASSERT(!mLocked);
|
||||
|
||||
CompositableHost::UseTextureHost(aTextures);
|
||||
MOZ_ASSERT(aTextures.Length() >= 1);
|
||||
|
||||
nsTArray<TimedImage> newImages;
|
||||
|
||||
// Remove all mImages without an mTextureSource to recycle.
|
||||
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
|
||||
if (!mImages[i].mTextureSource) {
|
||||
mImages.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new TimedImage entries and recycle any mTextureSources that match
|
||||
// our mFrontBuffers.
|
||||
for (uint32_t i = 0; i < aTextures.Length(); ++i) {
|
||||
const TimedTexture& t = aTextures[i];
|
||||
MOZ_ASSERT(t.mTexture);
|
||||
if (i + 1 < aTextures.Length() &&
|
||||
t.mProducerID == mLastProducerID && t.mFrameID < mLastFrameID) {
|
||||
// Ignore frames before a frame that we already composited. We don't
|
||||
// ever want to display these frames. This could be important if
|
||||
// the frame producer adjusts timestamps (e.g. to track the audio clock)
|
||||
// and the new frame times are earlier.
|
||||
continue;
|
||||
}
|
||||
TimedImage& img = *newImages.AppendElement();
|
||||
img.mFrontBuffer = t.mTexture;
|
||||
for (uint32_t i = 0; i < mImages.Length(); ++i) {
|
||||
if (mImages[i].mFrontBuffer == img.mFrontBuffer) {
|
||||
img.mTextureSource = mImages[i].mTextureSource;
|
||||
mImages.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
img.mTimeStamp = t.mTimeStamp;
|
||||
img.mPictureRect = t.mPictureRect;
|
||||
img.mFrameID = t.mFrameID;
|
||||
img.mProducerID = t.mProducerID;
|
||||
}
|
||||
// Recycle any leftover mTextureSources and call PrepareTextureSource on all
|
||||
// images.
|
||||
for (auto& img : newImages) {
|
||||
if (!img.mTextureSource && !mImages.IsEmpty()) {
|
||||
img.mTextureSource = mImages.LastElement().mTextureSource;
|
||||
mImages.RemoveElementAt(mImages.Length() - 1);
|
||||
}
|
||||
img.mFrontBuffer->Updated();
|
||||
img.mFrontBuffer->PrepareTextureSource(img.mTextureSource);
|
||||
}
|
||||
mImages.SwapElements(newImages);
|
||||
}
|
||||
|
||||
void
|
||||
ImageHost::RemoveTextureHost(TextureHost* aTexture)
|
||||
{
|
||||
MOZ_ASSERT(!mLocked);
|
||||
|
||||
CompositableHost::RemoveTextureHost(aTexture);
|
||||
if (aTexture && mFrontBuffer == aTexture) {
|
||||
mFrontBuffer->UnbindTextureSource();
|
||||
mTextureSource = nullptr;
|
||||
mFrontBuffer = nullptr;
|
||||
|
||||
for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
|
||||
if (mImages[i].mFrontBuffer == aTexture) {
|
||||
aTexture->UnbindTextureSource();
|
||||
mImages.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextureHost*
|
||||
ImageHost::GetAsTextureHost()
|
||||
int ImageHost::ChooseImageIndex() const
|
||||
{
|
||||
return mFrontBuffer;
|
||||
if (!mCompositor || mImages.IsEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
TimeStamp now = mCompositor->GetCompositionTime();
|
||||
|
||||
if (now.IsNull()) {
|
||||
// Not in a composition, so just return the last image we composited
|
||||
// (if it's one of the current images).
|
||||
for (uint32_t i = 0; i < mImages.Length(); ++i) {
|
||||
if (mImages[i].mFrameID == mLastFrameID &&
|
||||
mImages[i].mProducerID == mLastProducerID) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t result = 0;
|
||||
while (result + 1 < mImages.Length() &&
|
||||
mImages[result + 1].mTimeStamp <= now) {
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const ImageHost::TimedImage* ImageHost::ChooseImage() const
|
||||
{
|
||||
int index = ChooseImageIndex();
|
||||
return index >= 0 ? &mImages[index] : nullptr;
|
||||
}
|
||||
|
||||
ImageHost::TimedImage* ImageHost::ChooseImage()
|
||||
{
|
||||
int index = ChooseImageIndex();
|
||||
return index >= 0 ? &mImages[index] : nullptr;
|
||||
}
|
||||
|
||||
TextureHost*
|
||||
ImageHost::GetAsTextureHost(IntRect* aPictureRect)
|
||||
{
|
||||
TimedImage* img = ChooseImage();
|
||||
if (aPictureRect && img) {
|
||||
*aPictureRect = img->mPictureRect;
|
||||
}
|
||||
return img ? img->mFrontBuffer.get() : nullptr;
|
||||
}
|
||||
|
||||
void ImageHost::Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
AttachFlags aFlags)
|
||||
{
|
||||
CompositableHost::Attach(aLayer, aCompositor, aFlags);
|
||||
for (auto& img : mImages) {
|
||||
if (GetCompositor()) {
|
||||
img.mFrontBuffer->SetCompositor(GetCompositor());
|
||||
}
|
||||
img.mFrontBuffer->Updated();
|
||||
img.mFrontBuffer->PrepareTextureSource(img.mTextureSource);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageHost::Composite(EffectChain& aEffectChain,
|
||||
ImageHost::Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
@@ -78,12 +193,13 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
// set the new compositor yet.
|
||||
return;
|
||||
}
|
||||
if (!mFrontBuffer) {
|
||||
TimedImage* img = ChooseImage();
|
||||
if (!img) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the front buffer has a compositor
|
||||
mFrontBuffer->SetCompositor(GetCompositor());
|
||||
img->mFrontBuffer->SetCompositor(GetCompositor());
|
||||
|
||||
AutoLockCompositableHost autoLock(this);
|
||||
if (autoLock.Failed()) {
|
||||
@@ -91,36 +207,40 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mFrontBuffer->BindTextureSource(mTextureSource)) {
|
||||
if (!img->mFrontBuffer->BindTextureSource(img->mTextureSource)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mTextureSource) {
|
||||
if (!img->mTextureSource) {
|
||||
// BindTextureSource above should have returned false!
|
||||
MOZ_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isAlphaPremultiplied = !(mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
|
||||
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
|
||||
mTextureSource.get(),
|
||||
aFilter,
|
||||
isAlphaPremultiplied,
|
||||
GetRenderState());
|
||||
bool isAlphaPremultiplied =
|
||||
!(img->mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED);
|
||||
RefPtr<TexturedEffect> effect =
|
||||
CreateTexturedEffect(img->mFrontBuffer->GetFormat(),
|
||||
img->mTextureSource.get(), aFilter, isAlphaPremultiplied,
|
||||
GetRenderState());
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
|
||||
if (mImageContainer) {
|
||||
aLayer->GetLayerManager()->
|
||||
AppendImageCompositeNotification(ImageCompositeNotification(
|
||||
mImageContainer, nullptr,
|
||||
img->mTimeStamp, GetCompositor()->GetCompositionTime(),
|
||||
img->mFrameID, img->mProducerID));
|
||||
}
|
||||
mLastFrameID = img->mFrameID;
|
||||
mLastProducerID = img->mProducerID;
|
||||
}
|
||||
aEffectChain.mPrimaryEffect = effect;
|
||||
IntSize textureSize = mTextureSource->GetSize();
|
||||
gfx::Rect gfxPictureRect
|
||||
= mHasPictureRect ? gfx::Rect(0, 0, mPictureRect.width, mPictureRect.height)
|
||||
: gfx::Rect(0, 0, textureSize.width, textureSize.height);
|
||||
|
||||
gfx::Rect pictureRect(0, 0,
|
||||
mPictureRect.width,
|
||||
mPictureRect.height);
|
||||
BigImageIterator* it = mTextureSource->AsBigImageIterator();
|
||||
gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
|
||||
BigImageIterator* it = img->mTextureSource->AsBigImageIterator();
|
||||
if (it) {
|
||||
|
||||
// This iteration does not work if we have multiple texture sources here
|
||||
@@ -136,23 +256,19 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
// the corresponding source tiles from all planes, with appropriate
|
||||
// per-plane per-tile texture coords.
|
||||
// DrawQuad currently assumes that all planes use the same texture coords.
|
||||
MOZ_ASSERT(it->GetTileCount() == 1 || !mTextureSource->GetNextSibling(),
|
||||
MOZ_ASSERT(it->GetTileCount() == 1 || !img->mTextureSource->GetNextSibling(),
|
||||
"Can't handle multi-plane BigImages");
|
||||
|
||||
it->BeginBigImageIteration();
|
||||
do {
|
||||
IntRect tileRect = it->GetTileRect();
|
||||
gfx::Rect rect(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
|
||||
if (mHasPictureRect) {
|
||||
rect = rect.Intersect(pictureRect);
|
||||
effect->mTextureCoords = Rect(Float(rect.x - tileRect.x)/ tileRect.width,
|
||||
Float(rect.y - tileRect.y) / tileRect.height,
|
||||
Float(rect.width) / tileRect.width,
|
||||
Float(rect.height) / tileRect.height);
|
||||
} else {
|
||||
effect->mTextureCoords = Rect(0, 0, 1, 1);
|
||||
}
|
||||
if (mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
|
||||
rect = rect.Intersect(pictureRect);
|
||||
effect->mTextureCoords = Rect(Float(rect.x - tileRect.x) / tileRect.width,
|
||||
Float(rect.y - tileRect.y) / tileRect.height,
|
||||
Float(rect.width) / tileRect.width,
|
||||
Float(rect.height) / tileRect.height);
|
||||
if (img->mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
|
||||
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
|
||||
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
||||
}
|
||||
@@ -163,32 +279,24 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
} while (it->NextTile());
|
||||
it->EndBigImageIteration();
|
||||
// layer border
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE,
|
||||
gfxPictureRect, aClipRect,
|
||||
aTransform, mFlashCounter);
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE, pictureRect,
|
||||
aClipRect, aTransform, mFlashCounter);
|
||||
} else {
|
||||
IntSize textureSize = mTextureSource->GetSize();
|
||||
gfx::Rect rect;
|
||||
if (mHasPictureRect) {
|
||||
effect->mTextureCoords = Rect(Float(mPictureRect.x) / textureSize.width,
|
||||
Float(mPictureRect.y) / textureSize.height,
|
||||
Float(mPictureRect.width) / textureSize.width,
|
||||
Float(mPictureRect.height) / textureSize.height);
|
||||
rect = pictureRect;
|
||||
} else {
|
||||
effect->mTextureCoords = Rect(0, 0, 1, 1);
|
||||
rect = gfx::Rect(0, 0, textureSize.width, textureSize.height);
|
||||
}
|
||||
IntSize textureSize = img->mTextureSource->GetSize();
|
||||
effect->mTextureCoords = Rect(Float(img->mPictureRect.x) / textureSize.width,
|
||||
Float(img->mPictureRect.y) / textureSize.height,
|
||||
Float(img->mPictureRect.width) / textureSize.width,
|
||||
Float(img->mPictureRect.height) / textureSize.height);
|
||||
|
||||
if (mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
|
||||
if (img->mFrontBuffer->GetFlags() & TextureFlags::ORIGIN_BOTTOM_LEFT) {
|
||||
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
|
||||
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
||||
}
|
||||
|
||||
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
||||
GetCompositor()->DrawQuad(pictureRect, aClipRect, aEffectChain,
|
||||
aOpacity, aTransform);
|
||||
GetCompositor()->DrawDiagnostics(DiagnosticFlags::IMAGE,
|
||||
rect, aClipRect,
|
||||
pictureRect, aClipRect,
|
||||
aTransform, mFlashCounter);
|
||||
}
|
||||
}
|
||||
@@ -196,8 +304,10 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
void
|
||||
ImageHost::SetCompositor(Compositor* aCompositor)
|
||||
{
|
||||
if (mFrontBuffer && mCompositor != aCompositor) {
|
||||
mFrontBuffer->SetCompositor(aCompositor);
|
||||
if (mCompositor != aCompositor) {
|
||||
for (auto& img : mImages) {
|
||||
img.mFrontBuffer->SetCompositor(aCompositor);
|
||||
}
|
||||
}
|
||||
CompositableHost::SetCompositor(aCompositor);
|
||||
}
|
||||
@@ -208,13 +318,12 @@ ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
aStream << aPrefix;
|
||||
aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
|
||||
|
||||
AppendToString(aStream, mPictureRect, " [picture-rect=", "]");
|
||||
|
||||
if (mFrontBuffer) {
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
nsAutoCString pfx(aPrefix);
|
||||
pfx += " ";
|
||||
for (auto& img : mImages) {
|
||||
aStream << "\n";
|
||||
mFrontBuffer->PrintInfo(aStream, pfx.get());
|
||||
img.mFrontBuffer->PrintInfo(aStream, pfx.get());
|
||||
AppendToString(aStream, img.mPictureRect, " [picture-rect=", "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,11 +332,11 @@ ImageHost::Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml)
|
||||
{
|
||||
if (mFrontBuffer) {
|
||||
for (auto& img : mImages) {
|
||||
aStream << aPrefix;
|
||||
aStream << (aDumpHtml ? "<ul><li>TextureHost: "
|
||||
: "TextureHost: ");
|
||||
DumpTextureHost(aStream, mFrontBuffer);
|
||||
DumpTextureHost(aStream, img.mFrontBuffer);
|
||||
aStream << (aDumpHtml ? " </li></ul> " : " ");
|
||||
}
|
||||
}
|
||||
@@ -235,8 +344,9 @@ ImageHost::Dump(std::stringstream& aStream,
|
||||
LayerRenderState
|
||||
ImageHost::GetRenderState()
|
||||
{
|
||||
if (mFrontBuffer) {
|
||||
return mFrontBuffer->GetRenderState();
|
||||
TimedImage* img = ChooseImage();
|
||||
if (img) {
|
||||
return img->mFrontBuffer->GetRenderState();
|
||||
}
|
||||
return LayerRenderState();
|
||||
}
|
||||
@@ -244,17 +354,22 @@ ImageHost::GetRenderState()
|
||||
already_AddRefed<gfx::DataSourceSurface>
|
||||
ImageHost::GetAsSurface()
|
||||
{
|
||||
return mFrontBuffer->GetAsSurface();
|
||||
TimedImage* img = ChooseImage();
|
||||
if (img) {
|
||||
return img->mFrontBuffer->GetAsSurface();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageHost::Lock()
|
||||
{
|
||||
MOZ_ASSERT(!mLocked);
|
||||
if (!mFrontBuffer) {
|
||||
TimedImage* img = ChooseImage();
|
||||
if (!img) {
|
||||
return false;
|
||||
}
|
||||
if (!mFrontBuffer->Lock()) {
|
||||
if (!img->mFrontBuffer->Lock()) {
|
||||
return false;
|
||||
}
|
||||
mLocked = true;
|
||||
@@ -265,8 +380,9 @@ void
|
||||
ImageHost::Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mLocked);
|
||||
if (mFrontBuffer) {
|
||||
mFrontBuffer->Unlock();
|
||||
TimedImage* img = ChooseImage();
|
||||
if (img) {
|
||||
img->mFrontBuffer->Unlock();
|
||||
}
|
||||
mLocked = false;
|
||||
}
|
||||
@@ -274,38 +390,50 @@ ImageHost::Unlock()
|
||||
IntSize
|
||||
ImageHost::GetImageSize() const
|
||||
{
|
||||
if (mHasPictureRect) {
|
||||
return IntSize(mPictureRect.width, mPictureRect.height);
|
||||
const TimedImage* img = ChooseImage();
|
||||
if (img) {
|
||||
return IntSize(img->mPictureRect.width, img->mPictureRect.height);
|
||||
}
|
||||
|
||||
if (mFrontBuffer) {
|
||||
return mFrontBuffer->GetSize();
|
||||
}
|
||||
|
||||
return IntSize();
|
||||
}
|
||||
|
||||
already_AddRefed<TexturedEffect>
|
||||
ImageHost::GenEffect(const gfx::Filter& aFilter)
|
||||
{
|
||||
if (!mFrontBuffer->BindTextureSource(mTextureSource)) {
|
||||
TimedImage* img = ChooseImage();
|
||||
if (!img) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!img->mFrontBuffer->BindTextureSource(img->mTextureSource)) {
|
||||
return nullptr;
|
||||
}
|
||||
bool isAlphaPremultiplied = true;
|
||||
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
|
||||
if (img->mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED) {
|
||||
isAlphaPremultiplied = false;
|
||||
}
|
||||
|
||||
return CreateTexturedEffect(mFrontBuffer->GetFormat(),
|
||||
mTextureSource,
|
||||
return CreateTexturedEffect(img->mFrontBuffer->GetFormat(),
|
||||
img->mTextureSource,
|
||||
aFilter,
|
||||
isAlphaPremultiplied,
|
||||
GetRenderState());
|
||||
}
|
||||
|
||||
void
|
||||
ImageHost::SetImageContainer(ImageContainerParent* aImageContainer)
|
||||
{
|
||||
if (mImageContainer) {
|
||||
mImageContainer->mImageHosts.RemoveElement(this);
|
||||
}
|
||||
mImageContainer = aImageContainer;
|
||||
if (mImageContainer) {
|
||||
mImageContainer->mImageHosts.AppendElement(this);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
ImageHostOverlay::ImageHostOverlay(const TextureInfo& aTextureInfo)
|
||||
: CompositableHost(aTextureInfo)
|
||||
, mHasPictureRect(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -314,7 +442,8 @@ ImageHostOverlay::~ImageHostOverlay()
|
||||
}
|
||||
|
||||
void
|
||||
ImageHostOverlay::Composite(EffectChain& aEffectChain,
|
||||
ImageHostOverlay::Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
@@ -334,13 +463,8 @@ ImageHostOverlay::Composite(EffectChain& aEffectChain,
|
||||
gfx::Rect rect;
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y,
|
||||
aClipRect.width, aClipRect.height);
|
||||
if (mHasPictureRect) {
|
||||
rect.SetRect(mPictureRect.x, mPictureRect.y,
|
||||
mPictureRect.width, mPictureRect.height);
|
||||
} else {
|
||||
rect.SetRect(0, 0,
|
||||
mOverlay.size().width, mOverlay.size().height);
|
||||
}
|
||||
rect.SetRect(mPictureRect.x, mPictureRect.y,
|
||||
mPictureRect.width, mPictureRect.height);
|
||||
|
||||
mCompositor->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
|
||||
mCompositor->DrawDiagnostics(DiagnosticFlags::IMAGE | DiagnosticFlags::BIGIMAGE,
|
||||
@@ -358,19 +482,17 @@ ImageHostOverlay::GetRenderState()
|
||||
}
|
||||
|
||||
void
|
||||
ImageHostOverlay::UseOverlaySource(OverlaySource aOverlay)
|
||||
ImageHostOverlay::UseOverlaySource(OverlaySource aOverlay,
|
||||
const nsIntRect& aPictureRect)
|
||||
{
|
||||
mOverlay = aOverlay;
|
||||
mPictureRect = aPictureRect;
|
||||
}
|
||||
|
||||
IntSize
|
||||
ImageHostOverlay::GetImageSize() const
|
||||
{
|
||||
if (mHasPictureRect) {
|
||||
return IntSize(mPictureRect.width, mPictureRect.height);
|
||||
}
|
||||
|
||||
return IntSize();
|
||||
return IntSize(mPictureRect.width, mPictureRect.height);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace layers {
|
||||
|
||||
class Compositor;
|
||||
struct EffectChain;
|
||||
class ImageContainerParent;
|
||||
|
||||
/**
|
||||
* ImageHost. Works with ImageClientSingle and ImageClientBuffered
|
||||
@@ -44,26 +45,27 @@ public:
|
||||
|
||||
virtual CompositableType GetType() override { return mTextureInfo.mCompositableType; }
|
||||
|
||||
virtual void Composite(EffectChain& aEffectChain,
|
||||
virtual void Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion = nullptr) override;
|
||||
|
||||
virtual void UseTextureHost(TextureHost* aTexture) override;
|
||||
virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures) override;
|
||||
|
||||
virtual void RemoveTextureHost(TextureHost* aTexture) override;
|
||||
|
||||
virtual TextureHost* GetAsTextureHost() override;
|
||||
virtual TextureHost* GetAsTextureHost(gfx::IntRect* aPictureRect = nullptr) override;
|
||||
|
||||
virtual void Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
AttachFlags aFlags = NO_FLAGS) override;
|
||||
|
||||
virtual void SetCompositor(Compositor* aCompositor) override;
|
||||
|
||||
virtual void SetPictureRect(const gfx::IntRect& aPictureRect) override
|
||||
{
|
||||
mPictureRect = aPictureRect;
|
||||
mHasPictureRect = true;
|
||||
}
|
||||
virtual void SetImageContainer(ImageContainerParent* aImageContainer) override;
|
||||
|
||||
gfx::IntSize GetImageSize() const override;
|
||||
|
||||
@@ -84,11 +86,30 @@ public:
|
||||
virtual already_AddRefed<TexturedEffect> GenEffect(const gfx::Filter& aFilter) override;
|
||||
|
||||
protected:
|
||||
struct TimedImage {
|
||||
CompositableTextureHostRef mFrontBuffer;
|
||||
CompositableTextureSourceRef mTextureSource;
|
||||
TimeStamp mTimeStamp;
|
||||
gfx::IntRect mPictureRect;
|
||||
int32_t mFrameID;
|
||||
int32_t mProducerID;
|
||||
};
|
||||
|
||||
/**
|
||||
* ChooseImage is guaranteed to return the same TimedImage every time it's
|
||||
* called during the same composition --- it depends only on mImages and
|
||||
* mCompositor->GetCompositionTime().
|
||||
*/
|
||||
const TimedImage* ChooseImage() const;
|
||||
TimedImage* ChooseImage();
|
||||
int ChooseImageIndex() const;
|
||||
|
||||
nsTArray<TimedImage> mImages;
|
||||
// Weak reference, will be null if mImageContainer has been destroyed.
|
||||
ImageContainerParent* mImageContainer;
|
||||
int32_t mLastFrameID;
|
||||
int32_t mLastProducerID;
|
||||
|
||||
CompositableTextureHostRef mFrontBuffer;
|
||||
CompositableTextureSourceRef mTextureSource;
|
||||
gfx::IntRect mPictureRect;
|
||||
bool mHasPictureRect;
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
@@ -104,24 +125,20 @@ public:
|
||||
|
||||
virtual CompositableType GetType() { return mTextureInfo.mCompositableType; }
|
||||
|
||||
virtual void Composite(EffectChain& aEffectChain,
|
||||
virtual void Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion = nullptr) override;
|
||||
virtual LayerRenderState GetRenderState() override;
|
||||
virtual void UseOverlaySource(OverlaySource aOverlay) override;
|
||||
virtual void UseOverlaySource(OverlaySource aOverlay,
|
||||
const gfx::IntRect& aPictureRect) override;
|
||||
virtual gfx::IntSize GetImageSize() const override;
|
||||
virtual void SetPictureRect(const nsIntRect& aPictureRect) override
|
||||
{
|
||||
mPictureRect = aPictureRect;
|
||||
mHasPictureRect = true;
|
||||
}
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
|
||||
protected:
|
||||
gfx::IntRect mPictureRect;
|
||||
bool mHasPictureRect;
|
||||
OverlaySource mOverlay;
|
||||
};
|
||||
|
||||
|
||||
@@ -95,17 +95,15 @@ ImageLayerComposite::RenderLayer(const IntRect& aClipRect)
|
||||
|
||||
mCompositor->MakeCurrent();
|
||||
|
||||
EffectChain effectChain(this);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
AddBlendModeEffect(effectChain);
|
||||
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
|
||||
mImageHost->SetCompositor(mCompositor);
|
||||
mImageHost->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransformForBuffer(),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
RenderWithAllMasks(this, mCompositor, aClipRect,
|
||||
[&](EffectChain& effectChain, const Rect& clipRect) {
|
||||
mImageHost->SetCompositor(mCompositor);
|
||||
mImageHost->Composite(this, effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransformForBuffer(),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
});
|
||||
mImageHost->BumpFlashCounter();
|
||||
}
|
||||
|
||||
|
||||
@@ -247,27 +247,11 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags)
|
||||
{
|
||||
NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
|
||||
if (!mRoot) {
|
||||
mInTransaction = false;
|
||||
mIsCompositorReady = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
EndTransaction(nullptr, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
LayerManagerComposite::EndTransaction(const TimeStamp& aTimeStamp,
|
||||
EndTransactionFlags aFlags)
|
||||
{
|
||||
NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?");
|
||||
NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here");
|
||||
NS_ASSERTION(!(aFlags & END_NO_COMPOSITE),
|
||||
"Shouldn't get END_NO_COMPOSITE here");
|
||||
mInTransaction = false;
|
||||
@@ -299,6 +283,10 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
}
|
||||
|
||||
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
|
||||
MOZ_ASSERT(!aTimeStamp.IsNull());
|
||||
// Set composition timestamp here because we need it in
|
||||
// ComputeEffectiveTransforms (so the correct video frame size is picked)
|
||||
mCompositor->SetCompositionTime(aTimeStamp);
|
||||
// The results of our drawing always go directly into a pixel buffer,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "mozilla/gfx/Rect.h" // for Rect
|
||||
#include "mozilla/gfx/Types.h" // for SurfaceFormat
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/layers/LayersMessages.h"
|
||||
#include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc
|
||||
#include "mozilla/Maybe.h" // for Maybe
|
||||
#include "mozilla/RefPtr.h"
|
||||
@@ -109,12 +111,22 @@ public:
|
||||
{
|
||||
MOZ_CRASH("Use BeginTransactionWithDrawTarget");
|
||||
}
|
||||
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget, const gfx::IntRect& aRect);
|
||||
void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
|
||||
const gfx::IntRect& aRect);
|
||||
|
||||
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override;
|
||||
virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override
|
||||
{
|
||||
MOZ_CRASH("Use EndTransaction(aTimeStamp)");
|
||||
return false;
|
||||
}
|
||||
virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags aFlags = END_DEFAULT) override;
|
||||
EndTransactionFlags aFlags = END_DEFAULT) override
|
||||
{
|
||||
MOZ_CRASH("Use EndTransaction(aTimeStamp)");
|
||||
}
|
||||
void EndTransaction(const TimeStamp& aTimeStamp,
|
||||
EndTransactionFlags aFlags = END_DEFAULT);
|
||||
|
||||
virtual void SetRoot(Layer* aLayer) override { mRoot = aLayer; }
|
||||
|
||||
@@ -251,6 +263,15 @@ public:
|
||||
|
||||
bool AsyncPanZoomEnabled() const override;
|
||||
|
||||
void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification)
|
||||
{
|
||||
mImageCompositeNotifications.AppendElement(aNotification);
|
||||
}
|
||||
void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification>* aNotifications)
|
||||
{
|
||||
aNotifications->MoveElementsFrom(mImageCompositeNotifications);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Region we're clipping our current drawing to. */
|
||||
nsIntRegion mClippingRegion;
|
||||
@@ -297,6 +318,8 @@ private:
|
||||
RefPtr<Compositor> mCompositor;
|
||||
UniquePtr<LayerProperties> mClonedLayerTreeProperties;
|
||||
|
||||
nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
|
||||
|
||||
/**
|
||||
* Context target, nullptr when drawing directly to our swap chain.
|
||||
*/
|
||||
@@ -358,6 +381,8 @@ public:
|
||||
|
||||
virtual void SetLayerManager(LayerManagerComposite* aManager);
|
||||
|
||||
LayerManagerComposite* GetLayerManager() const { return mCompositeManager; }
|
||||
|
||||
/**
|
||||
* Perform a first pass over the layer tree to render all of the intermediate
|
||||
* surfaces that we can. This allows us to avoid framebuffer switches in the
|
||||
@@ -455,6 +480,138 @@ protected:
|
||||
gfx::IntRect mClearRect;
|
||||
};
|
||||
|
||||
// Render aLayer using aCompositor and apply all mask layers of aLayer: The
|
||||
// layer's own mask layer (aLayer->GetMaskLayer()), and any ancestor mask
|
||||
// layers.
|
||||
// If more than one mask layer needs to be applied, we use intermediate surfaces
|
||||
// (CompositingRenderTargets) for rendering, applying one mask layer at a time.
|
||||
// Callers need to provide a callback function aRenderCallback that does the
|
||||
// actual rendering of the source. It needs to have the following form:
|
||||
// void (EffectChain& effectChain, const Rect& clipRect)
|
||||
// aRenderCallback is called exactly once, inside this function, unless aLayer's
|
||||
// visible region is completely clipped out (in that case, aRenderCallback won't
|
||||
// be called at all).
|
||||
// This function calls aLayer->AsLayerComposite()->AddBlendModeEffect for the
|
||||
// final rendering pass.
|
||||
//
|
||||
// (This function should really live in LayerManagerComposite.cpp, but we
|
||||
// need to use templates for passing lambdas until bug 1164522 is resolved.)
|
||||
template<typename RenderCallbackType>
|
||||
void
|
||||
RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
|
||||
const gfx::IntRect& aClipRect,
|
||||
RenderCallbackType aRenderCallback)
|
||||
{
|
||||
Layer* firstMask = nullptr;
|
||||
size_t maskLayerCount = 0;
|
||||
size_t nextAncestorMaskLayer = 0;
|
||||
|
||||
size_t ancestorMaskLayerCount = aLayer->GetAncestorMaskLayerCount();
|
||||
if (Layer* ownMask = aLayer->GetMaskLayer()) {
|
||||
firstMask = ownMask;
|
||||
maskLayerCount = ancestorMaskLayerCount + 1;
|
||||
nextAncestorMaskLayer = 0;
|
||||
} else if (ancestorMaskLayerCount > 0) {
|
||||
firstMask = aLayer->GetAncestorMaskLayerAt(0);
|
||||
maskLayerCount = ancestorMaskLayerCount;
|
||||
nextAncestorMaskLayer = 1;
|
||||
} else {
|
||||
// no mask layers at all
|
||||
}
|
||||
|
||||
bool firstMaskIs3D = false;
|
||||
if (ContainerLayer* container = aLayer->AsContainerLayer()) {
|
||||
firstMaskIs3D = !container->GetTransform().CanDraw2D();
|
||||
}
|
||||
|
||||
if (maskLayerCount <= 1) {
|
||||
// This is the common case. Render in one pass and return.
|
||||
EffectChain effectChain(aLayer);
|
||||
LayerManagerComposite::AutoAddMaskEffect
|
||||
autoMaskEffect(firstMask, effectChain, firstMaskIs3D);
|
||||
aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain);
|
||||
aRenderCallback(effectChain, gfx::Rect(aClipRect));
|
||||
return;
|
||||
}
|
||||
|
||||
// We have multiple mask layers.
|
||||
// We split our list of mask layers into three parts:
|
||||
// (1) The first mask
|
||||
// (2) The list of intermediate masks (every mask except first and last)
|
||||
// (3) The final mask.
|
||||
// Part (2) can be empty.
|
||||
// For parts (1) and (2) we need to allocate intermediate surfaces to render
|
||||
// into. The final mask gets rendered into the original render target.
|
||||
|
||||
// Calculate the size of the intermediate surfaces.
|
||||
gfx::Rect visibleRect(aLayer->GetEffectiveVisibleRegion().GetBounds());
|
||||
gfx::Matrix4x4 transform = aLayer->GetEffectiveTransform();
|
||||
// TODO: Use RenderTargetIntRect and TransformTo<...> here
|
||||
gfx::IntRect surfaceRect =
|
||||
RoundedOut(transform.TransformBounds(visibleRect)).Intersect(aClipRect);
|
||||
if (surfaceRect.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CompositingRenderTarget> originalTarget =
|
||||
aCompositor->GetCurrentRenderTarget();
|
||||
|
||||
RefPtr<CompositingRenderTarget> firstTarget =
|
||||
aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
|
||||
if (!firstTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Render the source while applying the first mask.
|
||||
aCompositor->SetRenderTarget(firstTarget);
|
||||
{
|
||||
EffectChain firstEffectChain(aLayer);
|
||||
LayerManagerComposite::AutoAddMaskEffect
|
||||
firstMaskEffect(firstMask, firstEffectChain, firstMaskIs3D);
|
||||
aRenderCallback(firstEffectChain, gfx::Rect(aClipRect - surfaceRect.TopLeft()));
|
||||
// firstTarget now contains the transformed source with the first mask and
|
||||
// opacity already applied.
|
||||
}
|
||||
|
||||
// Apply the intermediate masks.
|
||||
gfx::Rect intermediateClip(surfaceRect - surfaceRect.TopLeft());
|
||||
RefPtr<CompositingRenderTarget> previousTarget = firstTarget;
|
||||
for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) {
|
||||
Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i);
|
||||
RefPtr<CompositingRenderTarget> intermediateTarget =
|
||||
aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
|
||||
if (!intermediateTarget) {
|
||||
break;
|
||||
}
|
||||
aCompositor->SetRenderTarget(intermediateTarget);
|
||||
EffectChain intermediateEffectChain(aLayer);
|
||||
LayerManagerComposite::AutoAddMaskEffect
|
||||
intermediateMaskEffect(intermediateMask, intermediateEffectChain);
|
||||
if (intermediateMaskEffect.Failed()) {
|
||||
continue;
|
||||
}
|
||||
intermediateEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
|
||||
aCompositor->DrawQuad(gfx::Rect(surfaceRect), intermediateClip,
|
||||
intermediateEffectChain, 1.0, gfx::Matrix4x4());
|
||||
previousTarget = intermediateTarget;
|
||||
}
|
||||
|
||||
aCompositor->SetRenderTarget(originalTarget);
|
||||
|
||||
// Apply the final mask, rendering into originalTarget.
|
||||
EffectChain finalEffectChain(aLayer);
|
||||
finalEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
|
||||
Layer* finalMask = aLayer->GetAncestorMaskLayerAt(ancestorMaskLayerCount - 1);
|
||||
|
||||
// The blend mode needs to be applied in this final step, because this is
|
||||
// where we're blending with the actual background (which is in originalTarget).
|
||||
aLayer->AsLayerComposite()->AddBlendModeEffect(finalEffectChain);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(finalMask, finalEffectChain);
|
||||
if (!autoMaskEffect.Failed()) {
|
||||
aCompositor->DrawQuad(gfx::Rect(surfaceRect), gfx::Rect(aClipRect),
|
||||
finalEffectChain, 1.0, gfx::Matrix4x4());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -106,12 +106,13 @@ PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
|
||||
PROFILER_LABEL("PaintedLayerComposite", "RenderLayer",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
MOZ_ASSERT(mBuffer->GetCompositor() == mCompositeManager->GetCompositor() &&
|
||||
Compositor* compositor = mCompositeManager->GetCompositor();
|
||||
|
||||
MOZ_ASSERT(mBuffer->GetCompositor() == compositor &&
|
||||
mBuffer->GetLayer() == this,
|
||||
"buffer is corrupted");
|
||||
|
||||
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
|
||||
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (gfxUtils::sDumpPainting) {
|
||||
@@ -122,21 +123,22 @@ PaintedLayerComposite::RenderLayer(const gfx::IntRect& aClipRect)
|
||||
}
|
||||
#endif
|
||||
|
||||
EffectChain effectChain(this);
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
|
||||
AddBlendModeEffect(effectChain);
|
||||
|
||||
mBuffer->SetPaintWillResample(MayResample());
|
||||
RenderWithAllMasks(this, compositor, aClipRect,
|
||||
[&](EffectChain& effectChain, const Rect& clipRect) {
|
||||
mBuffer->SetPaintWillResample(MayResample());
|
||||
|
||||
mBuffer->Composite(this, effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
GetEffectFilter(),
|
||||
clipRect,
|
||||
&visibleRegion);
|
||||
});
|
||||
|
||||
mBuffer->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
GetEffectFilter(),
|
||||
clipRect,
|
||||
&visibleRegion);
|
||||
mBuffer->BumpFlashCounter();
|
||||
|
||||
mCompositeManager->GetCompositor()->MakeCurrent();
|
||||
compositor->MakeCurrent();
|
||||
}
|
||||
|
||||
CompositableHost*
|
||||
|
||||
@@ -350,7 +350,8 @@ TiledLayerBufferComposite::Clear()
|
||||
}
|
||||
|
||||
void
|
||||
TiledContentHost::Composite(EffectChain& aEffectChain,
|
||||
TiledContentHost::Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
|
||||
@@ -235,12 +235,13 @@ public:
|
||||
bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor);
|
||||
|
||||
void Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion = nullptr) override;
|
||||
virtual void Composite(LayerComposite* aLayer,
|
||||
EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion = nullptr) override;
|
||||
|
||||
virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace layers {
|
||||
|
||||
class CompositableClient;
|
||||
class AsyncTransactionTracker;
|
||||
class ImageContainer;
|
||||
struct TextureFactoryIdentifier;
|
||||
class SurfaceDescriptor;
|
||||
class SurfaceDescriptorTiles;
|
||||
@@ -50,7 +51,8 @@ public:
|
||||
* Setup the IPDL actor for aCompositable to be part of layers
|
||||
* transactions.
|
||||
*/
|
||||
virtual void Connect(CompositableClient* aCompositable) = 0;
|
||||
virtual void Connect(CompositableClient* aCompositable,
|
||||
ImageContainer* aImageContainer = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
|
||||
@@ -72,15 +74,10 @@ public:
|
||||
const ThebesBufferData& aThebesBufferData,
|
||||
const nsIntRegion& aUpdatedRegion) = 0;
|
||||
|
||||
/**
|
||||
* Communicate the picture rect of a YUV image in aLayer to the compositor
|
||||
*/
|
||||
virtual void UpdatePictureRect(CompositableClient* aCompositable,
|
||||
const gfx::IntRect& aRect) = 0;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual void UseOverlaySource(CompositableClient* aCompositabl,
|
||||
const OverlaySource& aOverlay) = 0;
|
||||
const OverlaySource& aOverlay,
|
||||
const gfx::IntRect& aPictureRect) = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -133,12 +130,22 @@ public:
|
||||
mTexturesToRemove.Clear();
|
||||
}
|
||||
|
||||
struct TimedTextureClient {
|
||||
TimedTextureClient()
|
||||
: mTextureClient(nullptr), mFrameID(0), mProducerID(0) {}
|
||||
|
||||
TextureClient* mTextureClient;
|
||||
TimeStamp mTimeStamp;
|
||||
nsIntRect mPictureRect;
|
||||
int32_t mFrameID;
|
||||
int32_t mProducerID;
|
||||
};
|
||||
/**
|
||||
* Tell the CompositableHost on the compositor side what texture to use for
|
||||
* Tell the CompositableHost on the compositor side what textures to use for
|
||||
* the next composition.
|
||||
*/
|
||||
virtual void UseTexture(CompositableClient* aCompositable,
|
||||
TextureClient* aClient) = 0;
|
||||
virtual void UseTextures(CompositableClient* aCompositable,
|
||||
const nsTArray<TimedTextureClient>& aTextures) = 0;
|
||||
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
|
||||
TextureClient* aClientOnBlack,
|
||||
TextureClient* aClientOnWhite) = 0;
|
||||
|
||||
@@ -68,6 +68,15 @@ bool ScheduleComposition(const T& op)
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(MOZ_WIDGET_GONK)
|
||||
static bool ValidatePictureRect(const mozilla::gfx::IntSize& aSize,
|
||||
const nsIntRect& aPictureRect)
|
||||
{
|
||||
return nsIntRect(0, 0, aSize.width, aSize.height).Contains(aPictureRect) &&
|
||||
!aPictureRect.IsEmpty();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation& aEdit,
|
||||
EditReplyVector& replyv)
|
||||
@@ -102,13 +111,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
RenderTraceInvalidateEnd(thebes, "FF00FF");
|
||||
break;
|
||||
}
|
||||
case CompositableOperation::TOpUpdatePictureRect: {
|
||||
const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect();
|
||||
CompositableHost* compositable = AsCompositable(op);
|
||||
MOZ_ASSERT(compositable);
|
||||
compositable->SetPictureRect(op.picture());
|
||||
break;
|
||||
}
|
||||
case CompositableOperation::TOpUseTiledLayerBuffer: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
||||
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
|
||||
@@ -169,18 +171,28 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
case CompositableOperation::TOpUseTexture: {
|
||||
const OpUseTexture& op = aEdit.get_OpUseTexture();
|
||||
CompositableHost* compositable = AsCompositable(op);
|
||||
RefPtr<TextureHost> tex = TextureHost::AsTextureHost(op.textureParent());
|
||||
|
||||
MOZ_ASSERT(tex.get());
|
||||
compositable->UseTextureHost(tex);
|
||||
nsAutoTArray<CompositableHost::TimedTexture,4> textures;
|
||||
for (auto& timedTexture : op.textures()) {
|
||||
CompositableHost::TimedTexture* t = textures.AppendElement();
|
||||
t->mTexture =
|
||||
TextureHost::AsTextureHost(timedTexture.textureParent());
|
||||
MOZ_ASSERT(t->mTexture);
|
||||
t->mTimeStamp = timedTexture.timeStamp();
|
||||
t->mPictureRect = timedTexture.picture();
|
||||
t->mFrameID = timedTexture.frameID();
|
||||
t->mProducerID = timedTexture.producerID();
|
||||
MOZ_ASSERT(ValidatePictureRect(t->mTexture->GetSize(), t->mPictureRect));
|
||||
|
||||
MaybeFence maybeFence = op.fence();
|
||||
if (maybeFence.type() == MaybeFence::TFenceHandle) {
|
||||
FenceHandle fence = maybeFence.get_FenceHandle();
|
||||
if (fence.IsValid() && tex) {
|
||||
tex->SetAcquireFenceHandle(fence);
|
||||
MaybeFence maybeFence = timedTexture.fence();
|
||||
if (maybeFence.type() == MaybeFence::TFenceHandle) {
|
||||
FenceHandle fence = maybeFence.get_FenceHandle();
|
||||
if (fence.IsValid()) {
|
||||
t->mTexture->SetAcquireFenceHandle(fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
compositable->UseTextureHost(textures);
|
||||
|
||||
if (IsAsync() && compositable->GetLayer()) {
|
||||
ScheduleComposition(op);
|
||||
@@ -209,7 +221,10 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
const OpUseOverlaySource& op = aEdit.get_OpUseOverlaySource();
|
||||
CompositableHost* compositable = AsCompositable(op);
|
||||
MOZ_ASSERT(compositable->GetType() == CompositableType::IMAGE_OVERLAY, "Invalid operation!");
|
||||
compositable->UseOverlaySource(op.overlay());
|
||||
if (!ValidatePictureRect(op.overlay().size(), op.picture())) {
|
||||
return false;
|
||||
}
|
||||
compositable->UseOverlaySource(op.overlay(), op.picture());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -38,10 +38,12 @@
|
||||
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
#include "mozilla/layers/FrameUniformityData.h"
|
||||
#include "mozilla/layers/ImageBridgeParent.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/layers/PLayerTransactionParent.h"
|
||||
#include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager
|
||||
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "mozilla/Telemetry.h"
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
@@ -592,6 +594,7 @@ void CompositorParent::ShutDown()
|
||||
MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
|
||||
|
||||
ReleaseImageBridgeParentSingleton();
|
||||
MediaSystemResourceService::Shutdown();
|
||||
|
||||
sCompositorThreadHolder = nullptr;
|
||||
|
||||
@@ -1169,7 +1172,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
|
||||
}
|
||||
#endif
|
||||
mLayerManager->SetDebugOverlayWantsNextFrame(false);
|
||||
mLayerManager->EndEmptyTransaction();
|
||||
mLayerManager->EndTransaction(time);
|
||||
|
||||
if (!aTarget) {
|
||||
DidComposite();
|
||||
@@ -1198,6 +1201,7 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
|
||||
// Special full-tilt composite mode for performance testing
|
||||
ScheduleComposition();
|
||||
}
|
||||
mCompositor->SetCompositionTime(TimeStamp());
|
||||
|
||||
mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start);
|
||||
profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
|
||||
@@ -1824,6 +1828,13 @@ CompositorParent::DidComposite()
|
||||
unused << SendDidComposite(0, mPendingTransaction);
|
||||
mPendingTransaction = 0;
|
||||
}
|
||||
if (mLayerManager) {
|
||||
nsTArray<ImageCompositeNotification> notifications;
|
||||
mLayerManager->ExtractImageCompositeNotifications(¬ifications);
|
||||
if (!notifications.IsEmpty()) {
|
||||
unused << ImageBridgeParent::NotifyImageComposites(notifications);
|
||||
}
|
||||
}
|
||||
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
for (LayerTreeMap::iterator it = sIndirectLayerTrees.begin();
|
||||
|
||||
@@ -21,12 +21,15 @@
|
||||
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
||||
#include "mozilla/ipc/Transport.h" // for Transport
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
|
||||
#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
|
||||
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
|
||||
#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
|
||||
#include "mozilla/layers/ImageClient.h" // for ImageClient
|
||||
#include "mozilla/layers/LayersMessages.h" // for CompositableOperation
|
||||
#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
|
||||
#include "mozilla/layers/PImageContainerChild.h"
|
||||
#include "mozilla/layers/TextureClient.h" // for TextureClient
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
@@ -49,6 +52,7 @@ using base::Thread;
|
||||
using base::ProcessId;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::media;
|
||||
|
||||
typedef std::vector<CompositableOperation> OpVector;
|
||||
|
||||
@@ -104,18 +108,25 @@ struct AutoEndTransaction {
|
||||
};
|
||||
|
||||
void
|
||||
ImageBridgeChild::UseTexture(CompositableClient* aCompositable,
|
||||
TextureClient* aTexture)
|
||||
ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
|
||||
const nsTArray<TimedTextureClient>& aTextures)
|
||||
{
|
||||
MOZ_ASSERT(aCompositable);
|
||||
MOZ_ASSERT(aTexture);
|
||||
MOZ_ASSERT(aCompositable->GetIPDLActor());
|
||||
MOZ_ASSERT(aTexture->GetIPDLActor());
|
||||
|
||||
FenceHandle fence = aTexture->GetAcquireFenceHandle();
|
||||
nsAutoTArray<TimedTexture,4> textures;
|
||||
|
||||
for (auto& t : aTextures) {
|
||||
MOZ_ASSERT(t.mTextureClient);
|
||||
MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
|
||||
FenceHandle fence = t.mTextureClient->GetAcquireFenceHandle();
|
||||
textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
|
||||
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
|
||||
t.mTimeStamp, t.mPictureRect,
|
||||
t.mFrameID, t.mProducerID));
|
||||
}
|
||||
mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
|
||||
nullptr, aTexture->GetIPDLActor(),
|
||||
fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t())));
|
||||
textures));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -138,22 +149,15 @@ ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
void
|
||||
ImageBridgeChild::UseOverlaySource(CompositableClient* aCompositable,
|
||||
const OverlaySource& aOverlay)
|
||||
const OverlaySource& aOverlay,
|
||||
const nsIntRect& aPictureRect)
|
||||
{
|
||||
MOZ_ASSERT(aCompositable);
|
||||
mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(), aOverlay));
|
||||
mTxn->AddEdit(OpUseOverlaySource(nullptr, aCompositable->GetIPDLActor(),
|
||||
aOverlay, aPictureRect));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable,
|
||||
const gfx::IntRect& aRect)
|
||||
{
|
||||
MOZ_ASSERT(aCompositable);
|
||||
MOZ_ASSERT(aCompositable->GetIPDLActor());
|
||||
mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect));
|
||||
}
|
||||
|
||||
// Singleton
|
||||
static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
|
||||
static StaticRefPtr<ImageBridgeParent> sImageBridgeParentSingleton;
|
||||
@@ -171,6 +175,9 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
|
||||
|
||||
MOZ_ASSERT(InImageBridgeChildThread(),
|
||||
"Should be in ImageBridgeChild thread.");
|
||||
|
||||
MediaSystemResourceManager::Shutdown();
|
||||
|
||||
if (sImageBridgeChildSingleton) {
|
||||
// Force all managed protocols to shut themselves down cleanly
|
||||
InfallibleTArray<PCompositableChild*> compositables;
|
||||
@@ -181,13 +188,17 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
|
||||
InfallibleTArray<PTextureChild*> textures;
|
||||
sImageBridgeChildSingleton->ManagedPTextureChild(textures);
|
||||
for (int i = textures.Length() - 1; i >= 0; --i) {
|
||||
TextureClient::AsTextureClient(textures[i])->ForceRemove();
|
||||
TextureClient* client = TextureClient::AsTextureClient(textures[i]);
|
||||
if (client) {
|
||||
client->ForceRemove();
|
||||
}
|
||||
}
|
||||
sImageBridgeChildSingleton->SendWillStop();
|
||||
sImageBridgeChildSingleton->MarkShutDown();
|
||||
// From now on, no message can be sent through the image bridge from the
|
||||
// client side except the final Stop message.
|
||||
}
|
||||
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
@@ -210,10 +221,12 @@ static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone)
|
||||
static void CreateImageClientSync(RefPtr<ImageClient>* result,
|
||||
ReentrantMonitor* barrier,
|
||||
CompositableType aType,
|
||||
ImageContainer* aImageContainer,
|
||||
bool *aDone)
|
||||
{
|
||||
ReentrantMonitorAutoEnter autoMon(*barrier);
|
||||
*result = sImageBridgeChildSingleton->CreateImageClientNow(aType);
|
||||
*result = sImageBridgeChildSingleton->CreateImageClientNow(
|
||||
aType, aImageContainer);
|
||||
*aDone = true;
|
||||
barrier->NotifyAll();
|
||||
}
|
||||
@@ -250,19 +263,22 @@ ImageBridgeChild::MarkShutDown()
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeChild::Connect(CompositableClient* aCompositable)
|
||||
ImageBridgeChild::Connect(CompositableClient* aCompositable,
|
||||
ImageContainer* aImageContainer)
|
||||
{
|
||||
MOZ_ASSERT(aCompositable);
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
uint64_t id = 0;
|
||||
PCompositableChild* child =
|
||||
SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id);
|
||||
SendPCompositableConstructor(aCompositable->GetTextureInfo(),
|
||||
aImageContainer->GetPImageContainerChild(), &id);
|
||||
MOZ_ASSERT(child);
|
||||
aCompositable->InitIPDLActor(child, id);
|
||||
}
|
||||
|
||||
PCompositableChild*
|
||||
ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID)
|
||||
ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
|
||||
PImageContainerChild* aChild, uint64_t* aID)
|
||||
{
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
return CompositableClient::CreateIPDLActor();
|
||||
@@ -319,33 +335,43 @@ ConnectImageBridgeInChildProcess(Transport* aTransport,
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ReleaseImageClientNow(ImageClient* aClient)
|
||||
static void ReleaseImageClientNow(ImageClient* aClient,
|
||||
PImageContainerChild* aChild)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
aClient->Release();
|
||||
if (aClient) {
|
||||
aClient->Release();
|
||||
}
|
||||
if (aChild) {
|
||||
aChild->SendAsyncDelete();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
|
||||
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient,
|
||||
PImageContainerChild* aChild)
|
||||
{
|
||||
if (!aClient) {
|
||||
if (!aClient && !aChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCreated()) {
|
||||
// CompositableClient::Release should normally happen in the ImageBridgeChild
|
||||
// thread because it usually generate some IPDL messages.
|
||||
// However, if we take this branch it means that the ImageBridgeChild
|
||||
// has already shut down, along with the CompositableChild, which means no
|
||||
// message will be sent and it is safe to run this code from any thread.
|
||||
MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
|
||||
aClient->Release();
|
||||
if (aClient) {
|
||||
// CompositableClient::Release should normally happen in the ImageBridgeChild
|
||||
// thread because it usually generate some IPDL messages.
|
||||
// However, if we take this branch it means that the ImageBridgeChild
|
||||
// has already shut down, along with the CompositableChild, which means no
|
||||
// message will be sent and it is safe to run this code from any thread.
|
||||
MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
|
||||
aClient->Release();
|
||||
}
|
||||
delete aChild;
|
||||
return;
|
||||
}
|
||||
|
||||
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&ReleaseImageClientNow, aClient));
|
||||
NewRunnableFunction(&ReleaseImageClientNow, aClient, aChild));
|
||||
}
|
||||
|
||||
static void ReleaseTextureClientNow(TextureClient* aClient)
|
||||
@@ -383,7 +409,6 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
|
||||
MOZ_ASSERT(aContainer);
|
||||
sImageBridgeChildSingleton->BeginTransaction();
|
||||
aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
|
||||
aClient->OnTransaction();
|
||||
sImageBridgeChildSingleton->EndTransaction();
|
||||
}
|
||||
|
||||
@@ -416,7 +441,6 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
|
||||
aContainer->ClearCurrentImage();
|
||||
}
|
||||
aClient->FlushAllImages(aExceptFront, aWaiter);
|
||||
aClient->OnTransaction();
|
||||
sImageBridgeChildSingleton->EndTransaction();
|
||||
// This decrement is balanced by the increment in FlushAllImages.
|
||||
// If any AsyncTransactionTrackers were created by FlushAllImages and attached
|
||||
@@ -517,6 +541,19 @@ ImageBridgeChild::EndTransaction()
|
||||
SendPendingAsyncMessges();
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeChild::SendImageBridgeThreadId()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
SendImageBridgeThreadId(gettid());
|
||||
#endif
|
||||
}
|
||||
|
||||
static void CallSendImageBridgeThreadId(ImageBridgeChild* aImageBridgeChild)
|
||||
{
|
||||
MOZ_ASSERT(InImageBridgeChildThread());
|
||||
aImageBridgeChild->SendImageBridgeThreadId();
|
||||
}
|
||||
|
||||
PImageBridgeChild*
|
||||
ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
|
||||
@@ -536,6 +573,10 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(ConnectImageBridgeInChildProcess,
|
||||
aTransport, aOtherPid));
|
||||
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(CallSendImageBridgeThreadId,
|
||||
sImageBridgeChildSingleton.get()));
|
||||
|
||||
return sImageBridgeChildSingleton;
|
||||
}
|
||||
@@ -589,6 +630,10 @@ bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
|
||||
sImageBridgeParentSingleton = new ImageBridgeParent(
|
||||
CompositorParent::CompositorLoop(), nullptr, base::GetCurrentProcId());
|
||||
sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
|
||||
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(CallSendImageBridgeThreadId,
|
||||
sImageBridgeChildSingleton.get()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -621,18 +666,20 @@ ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier&
|
||||
}
|
||||
|
||||
already_AddRefed<ImageClient>
|
||||
ImageBridgeChild::CreateImageClient(CompositableType aType)
|
||||
ImageBridgeChild::CreateImageClient(CompositableType aType,
|
||||
ImageContainer* aImageContainer)
|
||||
{
|
||||
if (InImageBridgeChildThread()) {
|
||||
return CreateImageClientNow(aType);
|
||||
return CreateImageClientNow(aType, aImageContainer);
|
||||
}
|
||||
ReentrantMonitor barrier("CreateImageClient Lock");
|
||||
ReentrantMonitorAutoEnter autoMon(barrier);
|
||||
bool done = false;
|
||||
|
||||
RefPtr<ImageClient> result = nullptr;
|
||||
GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync,
|
||||
&result, &barrier, aType, &done));
|
||||
GetMessageLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&CreateImageClientSync, &result, &barrier, aType,
|
||||
aImageContainer, &done));
|
||||
// should stop the thread until the ImageClient has been created on
|
||||
// the other thread
|
||||
while (!done) {
|
||||
@@ -642,14 +689,18 @@ ImageBridgeChild::CreateImageClient(CompositableType aType)
|
||||
}
|
||||
|
||||
already_AddRefed<ImageClient>
|
||||
ImageBridgeChild::CreateImageClientNow(CompositableType aType)
|
||||
ImageBridgeChild::CreateImageClientNow(CompositableType aType,
|
||||
ImageContainer* aImageContainer)
|
||||
{
|
||||
MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
|
||||
if (aImageContainer) {
|
||||
SendPImageContainerConstructor(aImageContainer->GetPImageContainerChild());
|
||||
}
|
||||
RefPtr<ImageClient> client
|
||||
= ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
|
||||
MOZ_ASSERT(client, "failed to create ImageClient");
|
||||
if (client) {
|
||||
client->Connect();
|
||||
client->Connect(aImageContainer);
|
||||
}
|
||||
return client.forget();
|
||||
}
|
||||
@@ -791,6 +842,36 @@ ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
|
||||
return TextureClient::DestroyIPDLActor(actor);
|
||||
}
|
||||
|
||||
PMediaSystemResourceManagerChild*
|
||||
ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
|
||||
{
|
||||
MOZ_ASSERT(!mShuttingDown);
|
||||
return new mozilla::media::MediaSystemResourceManagerChild();
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
PImageContainerChild*
|
||||
ImageBridgeChild::AllocPImageContainerChild()
|
||||
{
|
||||
// we always use the "power-user" ctor
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::DeallocPImageContainerChild(PImageContainerChild* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
|
||||
{
|
||||
@@ -833,6 +914,15 @@ ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageDat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
|
||||
{
|
||||
for (auto& n : aNotifications) {
|
||||
ImageContainer::NotifyComposite(n);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PTextureChild*
|
||||
ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
|
||||
TextureFlags aFlags)
|
||||
|
||||
@@ -152,6 +152,9 @@ public:
|
||||
*/
|
||||
void ConnectAsync(ImageBridgeParent* aParent);
|
||||
|
||||
using PImageBridgeChild::SendImageBridgeThreadId;
|
||||
void SendImageBridgeThreadId();
|
||||
|
||||
static void IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier);
|
||||
|
||||
void BeginTransaction();
|
||||
@@ -171,7 +174,8 @@ public:
|
||||
*/
|
||||
virtual MessageLoop * GetMessageLoop() const override;
|
||||
|
||||
PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) override;
|
||||
PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo,
|
||||
PImageContainerChild* aChild, uint64_t* aID) override;
|
||||
bool DeallocPCompositableChild(PCompositableChild* aActor) override;
|
||||
|
||||
/**
|
||||
@@ -186,13 +190,29 @@ public:
|
||||
virtual bool
|
||||
DeallocPTextureChild(PTextureChild* actor) override;
|
||||
|
||||
PMediaSystemResourceManagerChild*
|
||||
AllocPMediaSystemResourceManagerChild() override;
|
||||
bool
|
||||
DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor) override;
|
||||
|
||||
virtual PImageContainerChild*
|
||||
AllocPImageContainerChild() override;
|
||||
virtual bool
|
||||
DeallocPImageContainerChild(PImageContainerChild* actor) override;
|
||||
|
||||
virtual bool
|
||||
RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
|
||||
|
||||
already_AddRefed<ImageClient> CreateImageClient(CompositableType aType);
|
||||
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType);
|
||||
virtual bool
|
||||
RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications) override;
|
||||
|
||||
static void DispatchReleaseImageClient(ImageClient* aClient);
|
||||
already_AddRefed<ImageClient> CreateImageClient(CompositableType aType,
|
||||
ImageContainer* aImageContainer);
|
||||
already_AddRefed<ImageClient> CreateImageClientNow(CompositableType aType,
|
||||
ImageContainer* aImageContainer);
|
||||
|
||||
static void DispatchReleaseImageClient(ImageClient* aClient,
|
||||
PImageContainerChild* aChild = nullptr);
|
||||
static void DispatchReleaseTextureClient(TextureClient* aClient);
|
||||
static void DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer);
|
||||
|
||||
@@ -203,21 +223,23 @@ public:
|
||||
|
||||
// CompositableForwarder
|
||||
|
||||
virtual void Connect(CompositableClient* aCompositable) override;
|
||||
virtual void Connect(CompositableClient* aCompositable,
|
||||
ImageContainer* aImageContainer) override;
|
||||
|
||||
virtual bool IsImageBridgeChild() const override { return true; }
|
||||
|
||||
/**
|
||||
* See CompositableForwarder::UseTexture
|
||||
* See CompositableForwarder::UseTextures
|
||||
*/
|
||||
virtual void UseTexture(CompositableClient* aCompositable,
|
||||
TextureClient* aClient) override;
|
||||
virtual void UseTextures(CompositableClient* aCompositable,
|
||||
const nsTArray<TimedTextureClient>& aTextures) override;
|
||||
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
|
||||
TextureClient* aClientOnBlack,
|
||||
TextureClient* aClientOnWhite) override;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
virtual void UseOverlaySource(CompositableClient* aCompositable,
|
||||
const OverlaySource& aOverlay) override;
|
||||
const OverlaySource& aOverlay,
|
||||
const nsIntRect& aPictureRect) override;
|
||||
#endif
|
||||
|
||||
virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
|
||||
@@ -235,13 +257,6 @@ public:
|
||||
NS_RUNTIMEABORT("should not be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicate the picture rect of a YUV image in aLayer to the compositor
|
||||
*/
|
||||
virtual void UpdatePictureRect(CompositableClient* aCompositable,
|
||||
const gfx::IntRect& aRect) override;
|
||||
|
||||
|
||||
virtual void UpdateTextureRegion(CompositableClient* aCompositable,
|
||||
const ThebesBufferData& aThebesBufferData,
|
||||
const nsIntRegion& aUpdatedRegion) override {
|
||||
|
||||
@@ -12,9 +12,12 @@
|
||||
#include "base/task.h" // for CancelableTask, DeleteTask, etc
|
||||
#include "base/tracked.h" // for FROM_HERE
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/Hal.h" // for hal::SetCurrentThreadPriority()
|
||||
#include "mozilla/HalTypes.h" // for hal::THREAD_PRIORITY_COMPOSITOR
|
||||
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/Transport.h" // for Transport
|
||||
#include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent
|
||||
#include "mozilla/layers/CompositableTransactionParent.h"
|
||||
#include "mozilla/layers/CompositorParent.h" // for CompositorParent
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
@@ -40,6 +43,7 @@ namespace layers {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::media;
|
||||
|
||||
std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
|
||||
|
||||
@@ -53,6 +57,7 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
|
||||
ProcessId aChildProcessId)
|
||||
: mMessageLoop(aLoop)
|
||||
, mTransport(aTransport)
|
||||
, mSetChildThreadPriority(false)
|
||||
, mCompositorThreadHolder(GetCompositorThreadHolder())
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
@@ -78,6 +83,12 @@ ImageBridgeParent::~ImageBridgeParent()
|
||||
new DeleteTask<Transport>(mTransport));
|
||||
}
|
||||
|
||||
nsTArray<PImageContainerParent*> parents;
|
||||
ManagedPImageContainerParent(parents);
|
||||
for (PImageContainerParent* p : parents) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
sImageBridges.erase(OtherPid());
|
||||
}
|
||||
|
||||
@@ -95,6 +106,20 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy));
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeParent::RecvImageBridgeThreadId(const PlatformThreadId& aThreadId)
|
||||
{
|
||||
MOZ_ASSERT(!mSetChildThreadPriority);
|
||||
if (mSetChildThreadPriority) {
|
||||
return false;
|
||||
}
|
||||
mSetChildThreadPriority = true;
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
hal::SetThreadPriority(aThreadId, hal::THREAD_PRIORITY_COMPOSITOR);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoImageBridgeParentAsyncMessageSender
|
||||
{
|
||||
public:
|
||||
@@ -217,11 +242,12 @@ static uint64_t GenImageContainerID() {
|
||||
|
||||
PCompositableParent*
|
||||
ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo,
|
||||
PImageContainerParent* aImageContainer,
|
||||
uint64_t* aID)
|
||||
{
|
||||
uint64_t id = GenImageContainerID();
|
||||
*aID = id;
|
||||
return CompositableHost::CreateIPDLActor(this, aInfo, id);
|
||||
return CompositableHost::CreateIPDLActor(this, aInfo, id, aImageContainer);
|
||||
}
|
||||
|
||||
bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor)
|
||||
@@ -242,6 +268,33 @@ ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
|
||||
return TextureHost::DestroyIPDLActor(actor);
|
||||
}
|
||||
|
||||
PMediaSystemResourceManagerParent*
|
||||
ImageBridgeParent::AllocPMediaSystemResourceManagerParent()
|
||||
{
|
||||
return new mozilla::media::MediaSystemResourceManagerParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeParent::DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor)
|
||||
{
|
||||
MOZ_ASSERT(aActor);
|
||||
delete static_cast<mozilla::media::MediaSystemResourceManagerParent*>(aActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
PImageContainerParent*
|
||||
ImageBridgeParent::AllocPImageContainerParent()
|
||||
{
|
||||
return new ImageContainerParent();
|
||||
}
|
||||
|
||||
bool
|
||||
ImageBridgeParent::DeallocPImageContainerParent(PImageContainerParent* actor)
|
||||
{
|
||||
delete actor;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ImageBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
|
||||
{
|
||||
@@ -254,6 +307,47 @@ ImageBridgeParent::RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData
|
||||
return true;
|
||||
}
|
||||
|
||||
class ProcessIdComparator
|
||||
{
|
||||
public:
|
||||
bool Equals(const ImageCompositeNotification& aA,
|
||||
const ImageCompositeNotification& aB) const
|
||||
{
|
||||
return aA.imageContainerParent()->OtherPid() == aB.imageContainerParent()->OtherPid();
|
||||
}
|
||||
bool LessThan(const ImageCompositeNotification& aA,
|
||||
const ImageCompositeNotification& aB) const
|
||||
{
|
||||
return aA.imageContainerParent()->OtherPid() < aB.imageContainerParent()->OtherPid();
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ bool
|
||||
ImageBridgeParent::NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications)
|
||||
{
|
||||
// Group the notifications by destination process ID and then send the
|
||||
// notifications in one message per group.
|
||||
aNotifications.Sort(ProcessIdComparator());
|
||||
uint32_t i = 0;
|
||||
bool ok = true;
|
||||
while (i < aNotifications.Length()) {
|
||||
nsAutoTArray<ImageCompositeNotification,1> notifications;
|
||||
notifications.AppendElement(aNotifications[i]);
|
||||
uint32_t end = i + 1;
|
||||
ProcessId pid = aNotifications[i].imageContainerParent()->OtherPid();
|
||||
while (end < aNotifications.Length() &&
|
||||
aNotifications[end].imageContainerParent()->OtherPid() == pid) {
|
||||
notifications.AppendElement(aNotifications[end]);
|
||||
++end;
|
||||
}
|
||||
if (!GetInstance(pid)->SendDidComposite(notifications)) {
|
||||
ok = false;
|
||||
}
|
||||
i = end;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
MessageLoop * ImageBridgeParent::GetMessageLoop() const {
|
||||
return mMessageLoop;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint64_t
|
||||
#include "CompositableTransactionParent.h"
|
||||
#include "ImageContainerParent.h"
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
@@ -67,12 +68,14 @@ public:
|
||||
}
|
||||
|
||||
// PImageBridge
|
||||
virtual bool RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
|
||||
virtual bool RecvUpdate(EditArray&& aEdits, EditReplyArray* aReply) override;
|
||||
virtual bool RecvUpdateNoSwap(EditArray&& aEdits) override;
|
||||
|
||||
virtual bool IsAsync() const override { return true; }
|
||||
|
||||
PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo,
|
||||
PImageContainerParent* aImageContainer,
|
||||
uint64_t*) override;
|
||||
bool DeallocPCompositableParent(PCompositableParent* aActor) override;
|
||||
|
||||
@@ -80,6 +83,11 @@ public:
|
||||
const TextureFlags& aFlags) override;
|
||||
virtual bool DeallocPTextureParent(PTextureParent* actor) override;
|
||||
|
||||
PMediaSystemResourceManagerParent* AllocPMediaSystemResourceManagerParent() override;
|
||||
bool DeallocPMediaSystemResourceManagerParent(PMediaSystemResourceManagerParent* aActor) override;
|
||||
virtual PImageContainerParent* AllocPImageContainerParent() override;
|
||||
virtual bool DeallocPImageContainerParent(PImageContainerParent* actor) override;
|
||||
|
||||
virtual bool
|
||||
RecvChildAsyncMessages(InfallibleTArray<AsyncChildMessageData>&& aMessages) override;
|
||||
|
||||
@@ -135,6 +143,8 @@ public:
|
||||
|
||||
static ImageBridgeParent* GetInstance(ProcessId aId);
|
||||
|
||||
static bool NotifyImageComposites(nsTArray<ImageCompositeNotification>& aNotifications);
|
||||
|
||||
// Overriden from IToplevelProtocol
|
||||
IToplevelProtocol*
|
||||
CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
|
||||
@@ -143,13 +153,14 @@ public:
|
||||
|
||||
private:
|
||||
void DeferredDestroy();
|
||||
|
||||
MessageLoop* mMessageLoop;
|
||||
Transport* mTransport;
|
||||
// This keeps us alive until ActorDestroy(), at which point we do a
|
||||
// deferred destruction of ourselves.
|
||||
nsRefPtr<ImageBridgeParent> mSelfRef;
|
||||
|
||||
bool mSetChildThreadPriority;
|
||||
|
||||
/**
|
||||
* Map of all living ImageBridgeParent instances
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 "ImageContainerParent.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/layers/ImageHost.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
ImageContainerParent::~ImageContainerParent()
|
||||
{
|
||||
while (!mImageHosts.IsEmpty()) {
|
||||
mImageHosts[mImageHosts.Length() - 1]->SetImageContainer(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void SendDeleteAndIgnoreResult(ImageContainerParent* self)
|
||||
{
|
||||
unused << PImageContainerParent::Send__delete__(self);
|
||||
}
|
||||
|
||||
bool ImageContainerParent::RecvAsyncDelete()
|
||||
{
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE, NewRunnableFunction(&SendDeleteAndIgnoreResult, this));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 mozilla_layers_ImageContainerParent_h
|
||||
#define mozilla_layers_ImageContainerParent_h
|
||||
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/layers/PImageContainerParent.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class ImageHost;
|
||||
|
||||
class ImageContainerParent : public PImageContainerParent
|
||||
{
|
||||
public:
|
||||
ImageContainerParent() {}
|
||||
~ImageContainerParent();
|
||||
|
||||
virtual bool RecvAsyncDelete() override;
|
||||
|
||||
nsAutoTArray<ImageHost*,1> mImageHosts;
|
||||
|
||||
private:
|
||||
virtual void ActorDestroy(ActorDestroyReason why) override {}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ifndef mozilla_layers_ImageContainerParent_h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "mozilla/layers/CompositableClient.h" // for CompositableChild
|
||||
#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
|
||||
#include "mozilla/layers/PLayerChild.h" // for PLayerChild
|
||||
#include "mozilla/layers/PImageContainerChild.h"
|
||||
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsDebug.h" // for NS_RUNTIMEABORT, etc
|
||||
|
||||
@@ -583,7 +583,6 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
||||
if (!Attach(cast(op.layerParent()), host, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
|
||||
break;
|
||||
}
|
||||
@@ -598,7 +597,7 @@ LayerTransactionParent::RecvUpdate(InfallibleTArray<Edit>&& cset,
|
||||
|
||||
{
|
||||
AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
|
||||
layer_manager()->EndTransaction(nullptr, nullptr, LayerManager::END_NO_IMMEDIATE_REDRAW);
|
||||
layer_manager()->EndTransaction(TimeStamp(), LayerManager::END_NO_IMMEDIATE_REDRAW);
|
||||
}
|
||||
|
||||
if (reply) {
|
||||
|
||||
@@ -9,6 +9,7 @@ include LayersSurfaces;
|
||||
include protocol PCompositable;
|
||||
include protocol PCompositor;
|
||||
include protocol PLayer;
|
||||
include protocol PImageContainer;
|
||||
include protocol PRenderFrame;
|
||||
include protocol PTexture;
|
||||
|
||||
@@ -53,7 +54,7 @@ struct TargetConfig {
|
||||
};
|
||||
|
||||
// Create a shadow layer for |layer|
|
||||
struct OpCreatePaintedLayer { PLayer layer; };
|
||||
struct OpCreatePaintedLayer { PLayer layer; };
|
||||
struct OpCreateContainerLayer { PLayer layer; };
|
||||
struct OpCreateImageLayer { PLayer layer; };
|
||||
struct OpCreateColorLayer { PLayer layer; };
|
||||
@@ -348,6 +349,7 @@ struct OpUseTiledLayerBuffer {
|
||||
struct OpUseOverlaySource {
|
||||
PCompositable compositable;
|
||||
OverlaySource overlay;
|
||||
IntRect picture;
|
||||
};
|
||||
|
||||
struct OpPaintTextureRegion {
|
||||
@@ -356,11 +358,6 @@ struct OpPaintTextureRegion {
|
||||
nsIntRegion updatedRegion;
|
||||
};
|
||||
|
||||
struct OpUpdatePictureRect {
|
||||
PCompositable compositable;
|
||||
IntRect picture;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells the CompositableHost to remove the corresponding TextureHost
|
||||
*/
|
||||
@@ -386,14 +383,28 @@ union MaybeFence {
|
||||
null_t;
|
||||
};
|
||||
|
||||
struct TimedTexture {
|
||||
PTexture texture;
|
||||
MaybeFence fence;
|
||||
TimeStamp timeStamp;
|
||||
IntRect picture;
|
||||
int32_t frameID;
|
||||
int32_t producerID;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tells the compositor-side which texture to use (for example, as front buffer
|
||||
* if there is several textures for double buffering)
|
||||
* Tells the compositor-side which textures to use (for example, as front buffer
|
||||
* if there are several textures for double buffering).
|
||||
* This provides a list of textures with timestamps, ordered by timestamp.
|
||||
* The newest texture whose timestamp is <= the current time is rendered
|
||||
* (where null is considered less than every other timestamp). If there is no
|
||||
* such texture, the first texture is rendered.
|
||||
* The first timestamp value can be null, but the others must not be.
|
||||
* The list must not be empty.
|
||||
*/
|
||||
struct OpUseTexture {
|
||||
PCompositable compositable;
|
||||
PTexture texture;
|
||||
MaybeFence fence;
|
||||
TimedTexture[] textures;
|
||||
};
|
||||
|
||||
struct OpUseComponentAlphaTextures {
|
||||
@@ -419,8 +430,6 @@ struct OpDeliverFenceToTracker {
|
||||
};
|
||||
|
||||
union CompositableOperation {
|
||||
OpUpdatePictureRect;
|
||||
|
||||
OpPaintTextureRegion;
|
||||
|
||||
OpUseTiledLayerBuffer;
|
||||
@@ -466,6 +475,18 @@ struct OpContentBufferSwap {
|
||||
nsIntRegion frontUpdatedRegion;
|
||||
};
|
||||
|
||||
/**
|
||||
* An ImageCompositeNotification is sent the first time a particular
|
||||
* image is composited by an ImageHost.
|
||||
*/
|
||||
struct ImageCompositeNotification {
|
||||
PImageContainer imageContainer;
|
||||
TimeStamp imageTimeStamp;
|
||||
TimeStamp firstCompositeTimeStamp;
|
||||
int32_t frameID;
|
||||
int32_t producerID;
|
||||
};
|
||||
|
||||
// Unit of a "changeset reply". This is a weird abstraction, probably
|
||||
// only to be used for buffer swapping.
|
||||
union EditReply {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
include LayersSurfaces;
|
||||
include LayersMessages;
|
||||
include protocol PLayer;
|
||||
include protocol PLayerTransaction;
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
include "nsRegion.h";
|
||||
@@ -42,6 +43,8 @@ child:
|
||||
// The compositor completed a layers transaction. id is the layers id
|
||||
// of the child layer tree that was composited (or 0 when notifying
|
||||
// the root layer tree).
|
||||
// transactionId is the id of the transaction before this composite, or 0
|
||||
// if there was no transaction since the last composite.
|
||||
async DidComposite(uint64_t id, uint64_t transactionId);
|
||||
|
||||
// The parent sends the child the requested fill ratio numbers.
|
||||
|
||||
@@ -6,15 +6,19 @@
|
||||
include LayersSurfaces;
|
||||
include LayersMessages;
|
||||
include protocol PCompositable;
|
||||
include protocol PImageContainer;
|
||||
include protocol PLayer;
|
||||
include protocol PTexture;
|
||||
include ProtocolTypes;
|
||||
include protocol PMediaSystemResourceManager;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h";
|
||||
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
|
||||
|
||||
using PlatformThreadId from "base/platform_thread.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
@@ -27,11 +31,16 @@ sync protocol PImageBridge
|
||||
{
|
||||
manages PCompositable;
|
||||
manages PTexture;
|
||||
manages PMediaSystemResourceManager;
|
||||
manages PImageContainer;
|
||||
|
||||
child:
|
||||
async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
|
||||
|
||||
async DidComposite(ImageCompositeNotification[] aNotifications);
|
||||
|
||||
parent:
|
||||
async ImageBridgeThreadId(PlatformThreadId aTreahdId);
|
||||
|
||||
sync Update(CompositableOperation[] ops) returns (EditReply[] reply);
|
||||
async UpdateNoSwap(CompositableOperation[] ops);
|
||||
@@ -48,8 +57,11 @@ parent:
|
||||
// Second step
|
||||
sync Stop();
|
||||
|
||||
sync PCompositable(TextureInfo aInfo) returns (uint64_t id);
|
||||
sync PCompositable(TextureInfo aInfo,
|
||||
PImageContainer aImageContainer) returns (uint64_t id);
|
||||
async PTexture(SurfaceDescriptor aSharedData, TextureFlags aTextureFlags);
|
||||
async PMediaSystemResourceManager();
|
||||
async PImageContainer();
|
||||
|
||||
async ChildAsyncMessages(AsyncChildMessageData[] aMessages);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 protocol PImageBridge;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
/**
|
||||
* PImageContainer represents an ImageContainer.
|
||||
*/
|
||||
|
||||
async protocol PImageContainer {
|
||||
manager PImageBridge;
|
||||
parent:
|
||||
/**
|
||||
* The child effectively owns the parent. When the child should be
|
||||
* destroyed, it sends an AsyncDelete to the parent but does not die
|
||||
* because we could still have messages in flight from the compositor
|
||||
* mentioning the child. The parent handles AsyncDelete by destroying
|
||||
* itself and sending __delete__ to the child to clean it up.
|
||||
*/
|
||||
async AsyncDelete();
|
||||
child:
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // layers
|
||||
} // mozilla
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user