blob: 8cd7f82c9bbeb7d537fc2b0a933988067e547621 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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 "FrameCaptureProcessor"
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/FrameCaptureProcessor.h>
#include <media/stagefright/MediaErrors.h>
#include <renderengine/RenderEngine.h>
#include <ui/Fence.h>
#include <ui/PixelFormat.h>
#include <utils/Log.h>
namespace android {
//static
Mutex FrameCaptureProcessor::sLock;
//static
sp<FrameCaptureProcessor> FrameCaptureProcessor::sInstance;
//static
sp<FrameCaptureProcessor> FrameCaptureProcessor::getInstance() {
Mutex::Autolock _l(sLock);
if (sInstance == nullptr) {
sInstance = new FrameCaptureProcessor();
sInstance->createRenderEngine();
}
// init only once, if failed nullptr will be returned afterwards.
return (sInstance->initCheck() == OK) ? sInstance : nullptr;
}
//static
status_t FrameCaptureProcessor::PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response) {
status_t err = msg->postAndAwaitResponse(response);
if (err != OK) {
return err;
}
if (!(*response)->findInt32("err", &err)) {
err = OK;
}
return err;
}
//static
void FrameCaptureProcessor::PostReplyWithError(
const sp<AReplyToken> &replyID, status_t err) {
sp<AMessage> response = new AMessage;
if (err != OK) {
response->setInt32("err", err);
}
response->postReply(replyID);
}
FrameCaptureProcessor::FrameCaptureProcessor()
: mInitStatus(NO_INIT), mTextureName(0) {}
FrameCaptureProcessor::~FrameCaptureProcessor() {
if (mLooper != nullptr) {
mLooper->unregisterHandler(id());
mLooper->stop();
}
}
void FrameCaptureProcessor::createRenderEngine() {
// this method should only be called once, immediately after ctor
CHECK(mInitStatus == NO_INIT);
mLooper = new ALooper();
mLooper->setName("capture_looper");
mLooper->start(); // default priority
mLooper->registerHandler(this);
sp<AMessage> response;
status_t err = PostAndAwaitResponse(new AMessage(kWhatCreate, this), &response);
if (err != OK) {
mInitStatus = ERROR_UNSUPPORTED;
mLooper->unregisterHandler(id());
mLooper->stop();
mLooper.clear();
return;
}
// only need one texture name
mRE->genTextures(1, &mTextureName);
mInitStatus = OK;
}
status_t FrameCaptureProcessor::capture(
const sp<Layer> &layer, const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
sp<AMessage> msg = new AMessage(kWhatCapture, this);
msg->setObject("layer", layer);
msg->setRect("crop", sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom);
msg->setObject("buffer", buffer);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
status_t FrameCaptureProcessor::onCreate() {
mRE = renderengine::RenderEngine::create(
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
.setImageCacheSize(2 /*maxFrameBufferAcquiredBuffers*/)
.setUseColorManagerment(true)
.setEnableProtectedContext(false)
.setPrecacheToneMapperShaderOnly(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::LOW)
.build());
if (mRE == nullptr) {
return ERROR_UNSUPPORTED;
}
return OK;
}
status_t FrameCaptureProcessor::onCapture(const sp<Layer> &layer,
const Rect &sourceCrop, const sp<GraphicBuffer> &buffer) {
renderengine::DisplaySettings clientCompositionDisplay;
std::vector<const renderengine::LayerSettings*> clientCompositionLayers;
clientCompositionDisplay.physicalDisplay = sourceCrop;
clientCompositionDisplay.clip = sourceCrop;
clientCompositionDisplay.outputDataspace = ui::Dataspace::V0_SRGB;
clientCompositionDisplay.maxLuminance = sDefaultMaxLumiance;
clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
// from Layer && BufferLayer
renderengine::LayerSettings layerSettings;
layer->getLayerSettings(sourceCrop, mTextureName, &layerSettings);
clientCompositionLayers.push_back(&layerSettings);
// Use an empty fence for the buffer fence, since we just created the buffer so
// there is no need for synchronization with the GPU.
base::unique_fd bufferFence;
base::unique_fd drawFence;
mRE->useProtectedContext(false);
status_t err = mRE->drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer.get(),
/*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
sp<Fence> fence = new Fence(std::move(drawFence));
if (err != OK) {
ALOGE("drawLayers returned err %d", err);
} else {
err = fence->wait(500);
if (err != OK) {
ALOGW("wait for fence returned err %d", err);
err = OK;
}
}
mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL);
return err;
}
void FrameCaptureProcessor::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCreate:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
status_t err = onCreate();
PostReplyWithError(replyID, err);
break;
}
case kWhatCapture:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<RefBase> layerObj, bufferObj;
int32_t left, top, right, bottom;
CHECK(msg->findObject("layer", &layerObj));
CHECK(msg->findRect("crop", &left, &top, &right, &bottom));
CHECK(msg->findObject("buffer", &bufferObj));
sp<GraphicBuffer> buffer = static_cast<GraphicBuffer*>(bufferObj.get());
sp<Layer> layer = static_cast<Layer*>(layerObj.get());
PostReplyWithError(replyID,
onCapture(layer, Rect(left, top, right, bottom), buffer));
break;
}
default:
TRESPASS();
}
}
} // namespace android