blob: 32c160e460748a686f45bed0e930eeb9df0e02b4 [file] [log] [blame]
/*
* Copyright (C) 2015-2020 Intel Corporation.
*
* 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_TAG "BufferQueue"
#include "iutils/CameraLog.h"
#include "BufferQueue.h"
#include "PlatformData.h"
namespace icamera {
BufferProducer::BufferProducer(int memType) : mMemType(memType)
{
LOG1("@%s BufferProducer created mMemType: %d", __func__, mMemType);
}
BufferQueue::BufferQueue() : mBufferProducer(nullptr),
mProcessThread(nullptr),
mThreadRunning(false)
{
LOG1("@%s BufferQueue created", __func__);
}
BufferQueue::~BufferQueue()
{
LOG1("@%s BufferQueue destroyed", __func__);
}
int BufferQueue::queueInputBuffer(Port port, const std::shared_ptr<CameraBuffer> &camBuffer)
{
// If it's not in mInputQueue, then it's not for this processor.
if (mInputQueue.find(port) == mInputQueue.end()) {
return OK;
}
LOG2("%s CameraBuffer %p for port:%d", __func__, camBuffer.get(), port);
CameraBufQ &input = mInputQueue[port];
bool needSignal = input.empty();
input.push(camBuffer);
if (needSignal) {
mFrameAvailableSignal.signal();
}
LOG2("%s Exit", __func__);
return OK;
}
int BufferQueue::onFrameAvailable(Port port, const std::shared_ptr<CameraBuffer> &camBuffer)
{
AutoMutex l(mBufferQueueLock);
return queueInputBuffer(port, camBuffer);
}
void BufferQueue::setBufferProducer(BufferProducer *producer)
{
LOG1("%s producer %p", __func__, producer);
AutoMutex l(mBufferQueueLock);
mBufferProducer = producer;
if (producer == nullptr)
return;
mBufferProducer->addFrameAvailableListener(this);
}
void BufferQueue::addFrameAvailableListener(BufferConsumer *listener)
{
LOG1("%s listener %p", __func__, listener);
AutoMutex l(mBufferQueueLock);
bool isAlreadyAdded = false;
for (auto& consumer : mBufferConsumerList) {
if (consumer == listener) {
isAlreadyAdded = true;
break;
}
}
// If the listener has been already added, then we don't register it again.
if (isAlreadyAdded) {
return;
}
mBufferConsumerList.push_back(listener);
}
void BufferQueue::removeFrameAvailableListener(BufferConsumer *listener)
{
LOG1("%s listener %p", __func__, listener);
AutoMutex l(mBufferQueueLock);
for (auto it = mBufferConsumerList.begin(); it != mBufferConsumerList.end(); ++it) {
if ((*it) == listener) {
mBufferConsumerList.erase(it);
break;
}
}
}
int BufferQueue::qbuf(Port port, const std::shared_ptr<CameraBuffer> &camBuffer)
{
LOG2("%s CameraBuffer %p for port:%d", __func__, camBuffer.get(), port);
//Enqueue buffer to internal pool
AutoMutex l(mBufferQueueLock);
if (camBuffer != nullptr && camBuffer->getStreamType() == CAMERA_STREAM_INPUT) {
return queueInputBuffer(port, camBuffer);
}
if (mOutputQueue.find(port) == mOutputQueue.end()) {
LOGE("Not supported port:%d", port);
return BAD_VALUE;
}
CameraBufQ &output = mOutputQueue[port];
bool needSignal = output.empty();
output.push(camBuffer);
if (needSignal) {
mOutputAvailableSignal.signal();
}
return OK;
}
void BufferQueue::clearBufferQueues()
{
AutoMutex l(mBufferQueueLock);
mInputQueue.clear();
for (const auto& input : mInputFrameInfo) {
mInputQueue[input.first] = CameraBufQ();
}
mOutputQueue.clear();
for (const auto& output : mOutputFrameInfo) {
mOutputQueue[output.first] = CameraBufQ();
}
}
void BufferQueue::setFrameInfo(const std::map<Port, stream_t>& inputInfo,
const std::map<Port, stream_t>& outputInfo)
{
mInputFrameInfo = inputInfo;
mOutputFrameInfo = outputInfo;
clearBufferQueues();
}
void BufferQueue::getFrameInfo(std::map<Port, stream_t>& inputInfo,
std::map<Port, stream_t>& outputInfo) const
{
inputInfo = mInputFrameInfo;
outputInfo = mOutputFrameInfo;
}
int BufferQueue::waitFreeBuffersInQueue(ConditionLock& lock,
std::map<Port, std::shared_ptr<CameraBuffer> > &cInBuffer,
std::map<Port, std::shared_ptr<CameraBuffer> > &cOutBuffer,
int64_t timeout)
{
LOG2("@%s start waiting the input and output buffers", __func__);
if (!mThreadRunning) {
LOG1("@%s: Processor is not active.", __func__);
return OK;
}
int ret = OK;
timeout = (timeout ? timeout : kWaitDuration) * SLOWLY_MULTIPLIER;
for (auto& input: mInputQueue) {
Port port = input.first;
CameraBufQ &inputQueue = input.second;
while (inputQueue.empty()) {
LOG2("%s: wait input port %d", __func__, port);
ret = mFrameAvailableSignal.waitRelative(lock, timeout);
// Thread was stopped during wait
if (!mThreadRunning) {
LOG1("@%s: Processor is not active while waiting for input buffers", __func__);
return OK;
}
if (ret == TIMED_OUT) {
return ret;
}
}
// Wake up from the buffer available
cInBuffer[port] = inputQueue.front();
}
for (auto& output: mOutputQueue) {
Port port = output.first;
CameraBufQ &outputQueue = output.second;
while (outputQueue.empty()) {
LOG2("%s: wait output port %d", __func__, port);
ret = mOutputAvailableSignal.waitRelative(lock, timeout);
// Thread was stopped during wait
if (!mThreadRunning) {
LOG1("@%s: Processor is not active while waiting for output buffers.", __func__);
return OK;
}
if (ret == TIMED_OUT) {
return ret;
}
}
cOutBuffer[port] = outputQueue.front();
}
return ret;
}
int BufferQueue::allocProducerBuffers(int camId, int bufNum)
{
LOG1("%s: buffer queue size %d", __func__, bufNum);
mInternalBuffers.clear();
CheckError(!mBufferProducer, BAD_VALUE ,"@%s: Buffer Producer is nullptr", __func__);
for (const auto& item : mInputFrameInfo) {
Port port = item.first;
int srcFmt = item.second.format;
int srcWidth = item.second.width;
int srcHeight = item.second.height;
LOG1("%s fmt:%s (%dx%d)", __func__,
CameraUtils::format2string(srcFmt).c_str(), srcWidth, srcHeight);
int32_t size = 0;
bool isISYSCompression = PlatformData::getISYSCompression(camId);
if (isISYSCompression)
size = CameraUtils::getFrameSize(srcFmt, srcWidth, srcHeight, false, true, true);
else
size = CameraUtils::getFrameSize(srcFmt, srcWidth, srcHeight);
int memType = mBufferProducer->getMemoryType();
for (int i = 0; i < bufNum; i++) {
std::shared_ptr<CameraBuffer> camBuffer;
switch (memType) {
case V4L2_MEMORY_USERPTR:
camBuffer = CameraBuffer::create(camId, BUFFER_USAGE_PSYS_INPUT, V4L2_MEMORY_USERPTR,
size, i, srcFmt, srcWidth, srcHeight);
CheckError(!camBuffer, NO_MEMORY, "Allocate producer userptr buffer failed");
break;
case V4L2_MEMORY_MMAP:
camBuffer = std::make_shared<CameraBuffer>(camId, BUFFER_USAGE_PSYS_INPUT,
V4L2_MEMORY_MMAP, size, i, srcFmt);
CheckError(!camBuffer, NO_MEMORY, "Allocate producer mmap buffer failed");
camBuffer->setUserBufferInfo(srcFmt, srcWidth, srcHeight);
mBufferProducer->allocateMemory(port, camBuffer);
break;
default:
LOGE("Not supported v4l2 memory type:%d", memType);
return BAD_VALUE;
}
mInternalBuffers[port].push_back(camBuffer);
mBufferProducer->qbuf(port, camBuffer);
}
}
return OK;
}
} //namespace icamera