blob: 45842d2a3ad8ffc8652ad04dd1fd29246f8a7816 [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 "CameraBuffer"
#include <sys/mman.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <vector>
#include "iutils/CameraLog.h"
#include "iutils/Utils.h"
#include "PlatformData.h"
#include "CameraBuffer.h"
namespace icamera {
CameraBuffer::CameraBuffer(int cameraId, int usage, int memory, uint32_t size, int index, int format) :
mNumPlanes(1),
mAllocatedMemory(false),
mU(nullptr),
mBufferUsage(usage),
mSettingSequence(-1)
{
v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
int num_plane = 1;
LOG1("%s: construct CameraBuffer with cameraId:%d, usage:%d, memory:%d, size:%d, format:%d, index:%d",
__func__, cameraId, usage, memory, size, format, index);
mU = new camera_buffer_t;
CLEAR(*mU);
mU->flags = BUFFER_FLAG_INTERNAL;
mU->sequence = -1;
switch (usage) {
case BUFFER_USAGE_PSYS_INPUT:
//follow through
case BUFFER_USAGE_PSYS_INTERNAL:
case BUFFER_USAGE_GENERAL:
if (PlatformData::isIsysEnabled(cameraId)
&& PlatformData::isCSIFrontEndCapture(cameraId)) {
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
num_plane = CameraUtils::getNumOfPlanes(format);
} else {
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
}
break;
case BUFFER_USAGE_PSYS_STATS:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
break;
case BUFFER_USAGE_MIPI_CAPTURE:
case BUFFER_USAGE_METADATA:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
num_plane = CameraUtils::getNumOfPlanes(format);
break;
default:
LOGE("Not supported Usage");
}
CLEAR(mMmapAddrs);
CLEAR(mDmaFd);
initBuffer(memory, type, size, index, num_plane);
}
CameraBuffer::~CameraBuffer()
{
LOG1("Free CameraBuffer");
freeMemory();
if (mU->flags & BUFFER_FLAG_INTERNAL) {
delete mU;
}
}
void CameraBuffer::initBuffer(int memType, v4l2_buf_type bufType, uint32_t size, int idx, int num_plane)
{
mV.SetMemory(memType);
mV.SetIndex(idx);
mV.SetType(bufType);
if (!V4L2_TYPE_IS_MULTIPLANAR(bufType)) {
mV.SetOffset(0, 0);
mV.SetLength(size, 0);
LOGE("SINGLE PLANE!");
} else {
mV.SetLength(num_plane, 0);
mNumPlanes = num_plane;
for (int i = 0; i < mNumPlanes; ++i) {
mV.SetLength(size, i);
}
}
mV.SetFlags(mV.Flags() | V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | V4L2_BUF_FLAG_NO_CACHE_CLEAN);
}
//Helper function to construct a Internal CameraBuffer
std::shared_ptr<CameraBuffer> CameraBuffer::create(int cameraId, int usage, int memory, unsigned int size, int index,
int srcFmt, int srcWidth, int srcHeight)
{
std::shared_ptr<CameraBuffer> camBuffer = std::make_shared<CameraBuffer>(cameraId, usage, memory, size, index, srcFmt);
CheckError(!camBuffer, nullptr, "@%s: fail to alloc CameraBuffer", __func__);
camBuffer->setUserBufferInfo(srcFmt, srcWidth, srcHeight);
int ret = camBuffer->allocateMemory();
CheckError(ret != OK, nullptr, "Allocate memory failed ret %d", ret);
return camBuffer;
}
//Internal frame Buffer
void CameraBuffer::setUserBufferInfo(int format, int width, int height)
{
LOG1("%s: format:%d, width:%d, height:%d", __func__, format, width, height);
mU->s.width = width;
mU->s.height = height;
mU->s.format = format;
if (format != -1) {
mU->s.stride = CameraUtils::getStride(format, width);
}
}
void CameraBuffer::setUserBufferInfo(int format, int width, int height, void *usrPtr)
{
setUserBufferInfo(format, width, height);
setAddr(usrPtr, 0);
}
//Called when a buffer is from the application
void CameraBuffer::setUserBufferInfo(camera_buffer_t *ubuffer)
{
CheckError(ubuffer == nullptr, VOID_VALUE, "%s: ubuffer is nullptr", __func__);
if (mU->flags & BUFFER_FLAG_INTERNAL) delete mU;
mU = ubuffer;
LOG1("%s: ubuffer->s.MemType: %d, addr: %p, fd: %d", __func__, ubuffer->s.memType,
ubuffer->addr, ubuffer->dmafd);
//update the v4l2 buffer memory with user info
switch (ubuffer->s.memType) {
case V4L2_MEMORY_USERPTR:
setAddr(ubuffer->addr, 0);
break;
case V4L2_MEMORY_DMABUF:
setFd(ubuffer->dmafd, 0);
break;
case V4L2_MEMORY_MMAP:
/* do nothing */
break;
default:
LOGE("iomode %d is not supported yet.", mV.Memory());
break;
}
if (mU->s.streamType == CAMERA_STREAM_INPUT || ubuffer->sequence >= 0) {
// update timestamp if raw buffer is selected by user and timestamp is set
if (ubuffer->timestamp > 0) {
struct timeval timestamp = { 0 };
timestamp.tv_sec = ubuffer->timestamp / 1000000000LL;
timestamp.tv_usec = (ubuffer->timestamp - timestamp.tv_sec * 1000000000LL) / 1000LL;
mV.SetTimestamp(timestamp);
}
mV.SetSequence(ubuffer->sequence);
LOG2("%s, input buffer sequence %lld, timestamp %ld", __func__, ubuffer->sequence,
ubuffer->timestamp);
}
}
void CameraBuffer::updateV4l2Buffer(const v4l2_buffer_t& v4l2buf)
{
mV.SetField(v4l2buf.field);
mV.SetTimestamp(v4l2buf.timestamp);
mV.SetSequence(v4l2buf.sequence);
mV.SetRequestFd(v4l2buf.request_fd);
}
/*export mmap buffer as dma_buf fd stored in mV and mU*/
int CameraBuffer::exportMmapDmabuf(V4L2VideoNode *vDevice)
{
std::vector<int> fds;
int ret = vDevice->ExportFrame(mV.Index(), &fds);
CheckError(ret != OK, -1, "exportMmapDmabuf failed, ret %d", ret);
for (size_t i = 0; i < fds.size(); ++i) {
setFd(fds[i], i);
}
if (mU->flags & BUFFER_FLAG_DMA_EXPORT) {
mU->dmafd = getFd(0);
}
return OK;
}
int CameraBuffer::allocateMemory(V4L2VideoNode* vDevice)
{
int ret = BAD_VALUE;
LOG1("%s", __func__);
switch(mV.Memory()) {
case V4L2_MEMORY_USERPTR:
ret = allocateUserPtr();
mAllocatedMemory = true;
mU->addr = getAddr();
break;
case V4L2_MEMORY_MMAP:
exportMmapDmabuf(vDevice);
ret = allocateMmap(vDevice);
mU->addr = getAddr();
mAllocatedMemory = true;
break;
default:
LOGE("memory type %d is incorrect for allocateMemory.", mV.Memory());
return BAD_VALUE;
}
return ret;
}
int CameraBuffer::allocateUserPtr()
{
void* buffer = nullptr;
for (int i = 0; i < mNumPlanes; ++i) {
int ret = posix_memalign(&buffer, getpagesize(), mV.Length(i));
CheckError(ret != 0, -1, "%s, posix_memalign fails, ret:%d", __func__, ret);
mV.SetUserptr(reinterpret_cast<uintptr_t>(buffer), i);
mMmapAddrs[i] = buffer;
}
return OK;
}
void CameraBuffer::freeUserPtr()
{
for (int i = 0; i < mNumPlanes; ++i) {
void* ptr = reinterpret_cast<void*>(mV.Userptr(i));
mMmapAddrs[i] = nullptr;
::free(ptr);
mV.SetUserptr(reinterpret_cast<uintptr_t>(nullptr), i);
}
}
int CameraBuffer::allocateMmap(V4L2VideoNode* dev)
{
std::vector<void*> addrs;
int ret = dev->MapMemory(mV.Index(), PROT_READ | PROT_WRITE,
MAP_SHARED, &addrs);
CheckError(ret != OK, -1, "allocateMmap failed, ret %d", ret);
for (unsigned int i = 0; i < addrs.size(); ++i) {
if (addrs[i] == MAP_FAILED) {
mMmapAddrs[i] = nullptr;
continue ;
}
mMmapAddrs[i] = addrs[i];
}
return OK;
}
void* CameraBuffer::getAddr(int plane)
{
CheckError(plane < 0 || plane >= mNumPlanes, nullptr, "Wrong plane number %d", plane);
switch (mV.Memory()) {
case V4L2_MEMORY_MMAP:
return mMmapAddrs[plane];
case V4L2_MEMORY_USERPTR:
return reinterpret_cast<void*>(mV.Userptr(plane));
default:
LOGE("%s: Not supported memory type %u", __func__, mV.Memory());
}
return nullptr;
}
void CameraBuffer::setAddr(void *addr, int plane)
{
CheckError(plane < 0 || plane >= mNumPlanes, VOID_VALUE,
"Wrong plane number %d", plane);
switch (mV.Memory()) {
case V4L2_MEMORY_MMAP:
mMmapAddrs[plane] = addr;
return;
case V4L2_MEMORY_USERPTR:
mV.SetUserptr(reinterpret_cast<uintptr_t>(addr), plane);
mMmapAddrs[plane] = addr;
return;
default:
LOGE("%s: Not supported memory type %u", __func__, mV.Memory());
}
}
void CameraBuffer::freeMmap()
{
int ret = OK;
for (int i = 0; i < mNumPlanes; i++) {
if (getFd(i) != -1) {
::close(getFd(i));
setFd(-1, i);
}
if (mMmapAddrs[i]) {
ret = ::munmap(mMmapAddrs[i], mV.Length(i));
CheckError(ret != 0, VOID_VALUE, "failed to munmap buffer %d", i);
mMmapAddrs[i] = nullptr;
}
}
}
void* CameraBuffer::mapDmaBufferAddr(int fd, unsigned int bufferSize)
{
if(fd < 0 || !bufferSize) {
LOGE("%s, fd:0x%x, bufferSize:%u", __func__, fd, bufferSize);
return nullptr;
}
return ::mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
}
void CameraBuffer::unmapDmaBufferAddr(void* addr, unsigned int bufferSize)
{
if(addr == nullptr || !bufferSize) {
LOGE("%s, addr:%p, bufferSize:%u", __func__, addr, bufferSize);
return;
}
munmap(addr, bufferSize);
}
void CameraBuffer::freeMemory()
{
if (!mAllocatedMemory) {
LOG2("@%s Memory(in %p) is not allocated by CameraBuffer class. Don't free it.", __func__, this);
return ;
}
switch(mV.Memory()) {
case V4L2_MEMORY_USERPTR:
freeUserPtr();
break;
case V4L2_MEMORY_MMAP:
freeMmap();
break;
default:
LOGE("Free camera buffer failed, due to memory %d type is not implemented yet.", mV.Memory());
}
}
void CameraBuffer::updateUserBuffer(void)
{
mU->timestamp = TIMEVAL2NSECS(getTimestamp());
mU->s.field = getField();
// Use valid setting sequence to align shutter/parameter with buffer
mU->sequence = (mSettingSequence < 0) ? getSequence() : mSettingSequence;
}
void CameraBuffer::updateFlags(void)
{
int flag = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE | V4L2_BUF_FLAG_NO_CACHE_CLEAN;
bool set = true;
//clear the flags if the buffers is accessed by the SW
if ((mU->flags & BUFFER_FLAG_SW_READ) || (mU->flags & BUFFER_FLAG_SW_WRITE)) {
set = false;
}
mV.SetFlags(set ? (mV.Flags() | flag): (mV.Flags() & (~flag)));
}
bool CameraBuffer::isFlagsSet(int flag)
{
return ((mU->flags & flag) ? true : false);
}
void CameraBuffer::setFd(int val, int plane)
{
if (mV.Memory() == V4L2_MEMORY_MMAP) {
mDmaFd[plane] = val;
} else {
mV.SetFd(val, plane);
}
}
int CameraBuffer::getFd(int plane)
{
if (mV.Memory() == V4L2_MEMORY_MMAP) {
return mDmaFd[plane];
}
return mV.Fd(plane);
}
}//namespace icamera