blob: 70da89fdd0dd1d236a19e3dbb1b58e30ac54ead7 [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 "CameraStream"
#include "iutils/CameraLog.h"
#include "iutils/Errors.h"
#include "iutils/Utils.h"
#include "CameraStream.h"
#include "PlatformData.h"
using std::shared_ptr;
namespace icamera {
CameraStream::CameraStream(int cameraId, int streamId, const stream_t& stream)
: mCameraId(cameraId),
mStreamId(streamId),
mPort(MAIN_PORT),
mBufferProducer(nullptr),
mNumHoldingUserBuffers(0),
mIsWaitingBufferReturn(false)
{
LOG1("@%s: mCameraId:%d, width:%d, height:%d, format:%s", __func__,
mCameraId, stream.width, CameraUtils::getInterlaceHeight(stream.field, stream.height),
CameraUtils::pixelCode2String(stream.format));
LOG2("@%s: automation checkpoint: WHF: %d,%d,%s", __func__,
stream.width, CameraUtils::getInterlaceHeight(stream.field, stream.height),
CameraUtils::pixelCode2String(stream.format));
}
CameraStream::~CameraStream()
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
}
int CameraStream::start()
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
return OK;
}
int CameraStream::stop()
{
LOG1("@%s, mCameraId:%d", __func__, mCameraId);
mIsWaitingBufferReturn = false;
mNumHoldingUserBuffers = 0;
if (mBufferProducer != nullptr)
mBufferProducer->removeFrameAvailableListener(this);
AutoMutex poolLock(mBufferPoolLock);
mUserBuffersPool.clear();
return OK;
}
/*
* Allocate memory to the stream processor which should be
* set by the CameraDevice
*/
int CameraStream::allocateMemory(camera_buffer_t *ubuffer)
{
LOG1("@%s, mCameraId:%d, ubuffer %p", __func__, mCameraId, ubuffer);
int ret = BAD_VALUE;
shared_ptr<CameraBuffer> camBuffer = userBufferToCameraBuffer(ubuffer);
CheckError(!camBuffer, ret, "@%s: fail to alloc CameraBuffer", __func__);
// mBufferProducer will not change after start
if (mBufferProducer)
ret = mBufferProducer->allocateMemory(mPort, camBuffer);
return ret;
}
shared_ptr<CameraBuffer> CameraStream::userBufferToCameraBuffer(camera_buffer_t *ubuffer)
{
if (ubuffer == nullptr) return nullptr;
shared_ptr<CameraBuffer> camBuffer = nullptr;
AutoMutex l(mBufferPoolLock);
for (auto buffer = mUserBuffersPool.begin(); buffer != mUserBuffersPool.end(); buffer++) {
/* check if the buffer is already in the pool, when the userBuffer is same as ubuffer
* will continue to check the buffer, because the data addr in ubuffer may change */
if ((*buffer)->getUserBuffer() == ubuffer) {
/* when memType matches, the dmafd or the addr should match */
if (((*buffer)->getMemory() == static_cast<uint32_t>(ubuffer->s.memType)) &&
((ubuffer->addr != nullptr && (*buffer)->getUserBuffer()->addr == ubuffer->addr) ||
(ubuffer->dmafd >= 0 && (*buffer)->getUserBuffer()->dmafd == ubuffer->dmafd))) {
camBuffer = *buffer;
} else {
mUserBuffersPool.erase(buffer);
}
break;
}
}
if (!camBuffer) { // Not found in the pool, so create a new CameraBuffer for it.
ubuffer->index = mUserBuffersPool.size();
camBuffer = std::make_shared<CameraBuffer>(mCameraId, BUFFER_USAGE_GENERAL,
ubuffer->s.memType, ubuffer->s.size, ubuffer->index, ubuffer->s.format);
CheckError(!camBuffer, nullptr, "@%s: fail to alloc CameraBuffer", __func__);
mUserBuffersPool.push_back(camBuffer);
}
camBuffer->setUserBufferInfo(ubuffer);
// Update the v4l2 flags
camBuffer->updateFlags();
return camBuffer;
}
void CameraStream::waitToReturnAllUserBufffers()
{
LOG1("%s: wait for all user buffers to be returned to user", __func__);
ConditionLock lock(mBufferPoolLock);
if (mNumHoldingUserBuffers > 0){
// mIsWaitingBufferReturn flag is used to prevent situation that signal goes before wait
mIsWaitingBufferReturn = true;
int ret = mAllBuffersReturnedSignal.waitRelative(lock,
kWaitDuration * SLOWLY_MULTIPLIER);
if (ret == TIMED_OUT) {
LOGW("@%s, mCameraId:%d, time out happens when waiting return user buffers",
__func__, mCameraId);
return;
}
mIsWaitingBufferReturn = false;
}
LOG1("%s: all buffers have been returned to user", __func__);
return;
}
// Q buffers to the stream processor which should be set by the CameraDevice
int CameraStream::qbuf(camera_buffer_t *ubuffer, long sequence)
{
shared_ptr<CameraBuffer> camBuffer = userBufferToCameraBuffer(ubuffer);
if (camBuffer) {
camBuffer->setSettingSequence(sequence);
LOG2("@%s, mCameraId:%d, mStreamId:%d, CameraBuffer:%p for port:%d, ubuffer:%p, addr:%p",
__func__, mCameraId, mStreamId, camBuffer.get(), mPort, ubuffer, ubuffer->addr);
}
int ret = BAD_VALUE;
// mBufferProducer will not change after start, no lock
if (mBufferProducer != nullptr) {
ret = mBufferProducer->qbuf(mPort, camBuffer);
if (ret == OK) {
mNumHoldingUserBuffers++;
}
}
return ret;
}
//This function is called in stop status, no lock
void CameraStream::setBufferProducer(BufferProducer *producer)
{
LOG1("@%s, mCameraId:%d, producer %p", __func__, mCameraId, producer);
mBufferProducer = producer;
if (producer != nullptr)
producer->addFrameAvailableListener(this);
}
int CameraStream::onFrameAvailable(Port port, const shared_ptr<CameraBuffer> &camBuffer)
{
// Ignore if the buffer is not for this stream.
if (mPort != port) return OK;
if (camBuffer->getStreamId() != mStreamId) return OK;
LOG2("@%s: mCameraId:%d, mStreamId:%d, CameraBuffer:%p for port:%d",
__func__, mCameraId, mStreamId, camBuffer.get(), port);
// Update the user buffer info before return back
camBuffer->updateUserBuffer();
EventFrameAvailable frameData;
frameData.streamId = mStreamId;
EventData eventData;
eventData.type = EVENT_FRAME_AVAILABLE;
eventData.buffer = camBuffer;
eventData.data.frameDone = frameData;
notifyListeners(eventData);
camera_buffer_t* ubuffer = camBuffer->getUserBuffer();
LOG2("ubuffer:%p, addr:%p, timestamp:%lu, sequence:%ld",
ubuffer, ubuffer->addr, ubuffer->timestamp, ubuffer->sequence);
LOGVCSYNC("[onFrameDone], CPU-timestamp:%lu, sequence:%ld, vc:%d, kernel-timestamp:%luus, endl",
CameraUtils::systemTime(),
ubuffer->sequence,
camBuffer->getVirtualChannel(),
ubuffer->timestamp);
PERF_CAMERA_ATRACE_PARAM3("sequence", camBuffer->getSequence(),
"csi2_port", camBuffer->getCsi2Port(),
"virtual_channel", camBuffer->getVirtualChannel());
AutoMutex l(mBufferPoolLock);
if (mNumHoldingUserBuffers > 0) {
mNumHoldingUserBuffers--;
}
LOG2("mNumHoldingUserBuffers has already been counted down to %d", mNumHoldingUserBuffers);
// mIsWaitingBufferReturn is used to prevent signal before wait
if (mIsWaitingBufferReturn && mNumHoldingUserBuffers == 0) {
LOG2("%s: all user buffer returned, trigger signal", __func__);
mAllBuffersReturnedSignal.signal();
}
return OK;
}
} //namespace icamera