/*
|
* Copyright (c) 2021 by Allwinnertech Co., Ltd.
|
*
|
* 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 "CameraHALv3_V4L2Gralloc"
|
|
#include "v4l2_gralloc.h"
|
|
#include <hardware/camera3.h>
|
#include <hardware/gralloc.h>
|
#include <linux/videodev2.h>
|
#include <system/graphics.h>
|
#include <ui/GraphicBufferMapper.h>
|
#include <ui/Rect.h>
|
|
#include <cstdlib>
|
#include <memory>
|
|
#include "stream_format.h"
|
#include GPU_PUBLIC_INCLUDE
|
|
namespace v4l2_camera_hal {
|
|
// Copy |height| lines from |src| to |dest|,
|
// where |src| and |dest| may have different line lengths.
|
void copyWithPadding(uint8_t* dest,
|
const uint8_t* src,
|
size_t dest_stride,
|
size_t src_stride,
|
size_t height) {
|
size_t copy_stride = dest_stride;
|
if (copy_stride > src_stride) {
|
// Adding padding, not reducing. 0 out the extra memory.
|
memset(dest, 0, src_stride * height);
|
copy_stride = src_stride;
|
}
|
uint8_t* dest_line_start = dest;
|
const uint8_t* src_line_start = src;
|
for (size_t row = 0; row < height;
|
++row, dest_line_start += dest_stride, src_line_start += src_stride) {
|
memcpy(dest_line_start, src_line_start, copy_stride);
|
}
|
}
|
|
V4L2Gralloc* V4L2Gralloc::NewV4L2Gralloc() {
|
// Initialize and check the gralloc module.
|
const hw_module_t* module = nullptr;
|
int res = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
|
if (res || !module) {
|
HAL_LOGE("Couldn't get gralloc module.");
|
return nullptr;
|
}
|
const gralloc_module_t* gralloc =
|
reinterpret_cast<const gralloc_module_t*>(module);
|
|
return new V4L2Gralloc(gralloc);
|
}
|
|
// Private. As checked by above factory, module will be non-null
|
// and a supported version.
|
V4L2Gralloc::V4L2Gralloc(const gralloc_module_t* module) : mModule(module) {
|
for (int i = 0; i< MAX_BUFFER_NUM; i++) {
|
aBufferData[i] = (BufferData *)malloc(sizeof(BufferData));
|
memset(aBufferData[i] , 0, sizeof(BufferData));
|
}
|
}
|
|
V4L2Gralloc::~V4L2Gralloc() {
|
// Unlock buffers that are still locked.
|
unlockAllBuffers();
|
for (int i = 0; i< MAX_BUFFER_NUM; i++) {
|
free(aBufferData[i]);
|
}
|
}
|
|
int V4L2Gralloc::get_share_fd(const buffer_handle_t* buffer,
|
int* sharefd,
|
unsigned long * mJpegBufferSizes) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
private_handle_t* hnd = (private_handle_t *)(*buffer);
|
HAL_LOGD("buffer_handle_t buffer : %p, hnd->height:%d, hnd->width:%d, "
|
"hnd->usage:0x%x, hnd->share_fd:%d.",
|
*buffer, hnd->height, hnd->width,
|
hnd->usage, hnd->share_fd);
|
*mJpegBufferSizes = hnd->width*hnd->height;
|
*sharefd = hnd->share_fd;
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_handle(const buffer_handle_t* buffer,
|
void ** dst_addr) {
|
int ret = -1;
|
void* virFromGralloc;
|
private_handle_t* hnd = (private_handle_t *)(*buffer);
|
HAL_LOGD("buffer_handle_t buffer : %p, hnd->height:%d, "
|
"hnd->width:%d, hnd->usage:0x%x.",
|
*buffer, hnd->height, hnd->width, hnd->usage);
|
|
/* let the graphics framework to lock the buffer,
|
* and get the virtual address. */
|
const android::Rect rect(hnd->width, hnd->height);
|
android::GraphicBufferMapper& grbuffer_mapper(
|
android::GraphicBufferMapper::get());
|
ret = grbuffer_mapper.lock(*buffer, hnd->usage, rect, &virFromGralloc);
|
HAL_LOGV("virFromGralloc = %p ", virFromGralloc);
|
if (ret != 1) {
|
HAL_LOGD("grbuffer_mapper.lock : %d -> %s",
|
ret, strerror(ret));
|
}
|
*dst_addr = virFromGralloc;
|
HAL_LOGD("lock get buffer vaddr is %p", *dst_addr);
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_handle_ycbcr(const buffer_handle_t* buffer,
|
android_ycbcr* ycbcr_dst_addr) {
|
int ret = -1;
|
private_handle_t* hnd = (private_handle_t *)(*buffer);
|
HAL_LOGV("buffer_handle_t buffer : %p, hnd->height:%d,"
|
" hnd->width:%d, hnd->usage:0x%x.",
|
*buffer, hnd->height, hnd->width, hnd->usage);
|
// let the graphics framework to lock the buffer, and get the virtual address.
|
const android::Rect rect(hnd->width, hnd->height);
|
android::GraphicBufferMapper& grbuffer_mapper(
|
android::GraphicBufferMapper::get());
|
ret = grbuffer_mapper.lockYCbCr(*buffer, hnd->usage, rect, ycbcr_dst_addr);
|
if (ret != 1) {
|
HAL_LOGV("grbuffer_mapper.lock : %d -> %s",
|
ret, strerror(ret));
|
}
|
HAL_LOGV("lock get buffer vaddr is %p", (void*)ycbcr_dst_addr);
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_handle(const buffer_handle_t* buffer,
|
void** dst_addr,
|
unsigned long * mJpegBufferSizes) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
private_handle_t *hnd = (private_handle_t *)(*buffer);
|
HAL_LOGD("buffer_handle_t buffer : %p, hnd->height:%d, "
|
"hnd->width:%d, hnd->usage:0x%x, hnd->share_fd:%d.",
|
*buffer,
|
hnd->height,
|
hnd->width,
|
hnd->usage,
|
hnd->share_fd);
|
*mJpegBufferSizes = hnd->width * hnd->height;
|
int ret = -1;
|
void * virFromGralloc;
|
|
// let the graphics framework to lock the buffer,
|
// and get the virtual address.
|
const android::Rect rect(hnd->width, hnd->height);
|
android::GraphicBufferMapper& grbuffer_mapper(
|
android::GraphicBufferMapper::get());
|
ret = grbuffer_mapper.lock(*buffer, hnd->usage, rect, &virFromGralloc);
|
HAL_LOGV("virFromGralloc = %p ", virFromGralloc);
|
if (ret != 1) {
|
HAL_LOGD("%s: grbuffer_mapper.lock: %d -> %s",
|
__FUNCTION__, ret, strerror(ret));
|
}
|
*dst_addr = virFromGralloc;
|
HAL_LOGD("lock get buffer vaddr is %p", *dst_addr);
|
|
return 0;
|
}
|
|
int V4L2Gralloc::unlock_handle(const buffer_handle_t* buffer) {
|
int ret = -1;
|
private_handle_t* hnd = (private_handle_t *)(*buffer);
|
HAL_LOGV("buffer : %p,The id is %lld.", *buffer, hnd->aw_buf_id);
|
// let the graphics framework to lock the buffer,
|
// and get the virtual address.
|
const android::Rect rect(hnd->width, hnd->height);
|
android::GraphicBufferMapper& grbuffer_mapper(
|
android::GraphicBufferMapper::get());
|
ret = grbuffer_mapper.unlock(*buffer);
|
if (ret != 1) {
|
HAL_LOGV("grbuffer_mapper.unlock: %d -> %s", ret, strerror(ret));
|
}
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_buffer(const camera3_stream_buffer_t* camera_buffer,
|
unsigned long* device_buffer) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
buffer_handle_t buffer = *camera_buffer->buffer;
|
camera3_stream_t* stream = camera_buffer->stream;
|
int ret = 0;
|
private_handle_t *hnd = (private_handle_t *)buffer;
|
|
HAL_LOGV("buffer_handle_t buffer : %p, hnd->height:%d, hnd->width:%d.",
|
buffer, hnd->height, hnd->width);
|
|
void* data;
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&data);
|
|
if (ret) {
|
HAL_LOGE("Failed to lock buffer: %d", ret);
|
return ret;
|
}
|
HAL_LOGV("*camera_buffer->buffer:0x%p, stream->width:%d,"
|
" stream->height:%d, lock buffer:%p.",
|
(*camera_buffer->buffer),
|
stream->width,
|
stream->height, data);
|
// If so, great, point to the beginning.
|
if (!data) {
|
ALOGE("Gralloc lock returned null ptr");
|
return -ENODEV;
|
}
|
*device_buffer = reinterpret_cast<unsigned long>(data);
|
HAL_LOGD("lock get buffer vaddr is %p", (void*)device_buffer);
|
return 0;
|
}
|
|
int V4L2Gralloc::unlock_buffer(const camera3_stream_buffer_t* camera_buffer) {
|
buffer_handle_t buffer = *camera_buffer->buffer;
|
private_handle_t *hnd = (private_handle_t *)buffer;
|
HAL_LOGV("buffer : %p,The id is %lld.", buffer, hnd->aw_buf_id);
|
// Unlock.
|
int res = mModule->unlock(mModule, buffer);
|
if (res) {
|
HAL_LOGE("Failed to unlock buffer at %p", buffer);
|
return -ENODEV;
|
}
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_pic(const camera3_stream_buffer_t* camera_buffer,
|
unsigned long* device_buffer) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
buffer_handle_t buffer = *camera_buffer->buffer;
|
void* data;
|
camera3_stream_t* stream = camera_buffer->stream;
|
int ret = 0;
|
HAL_LOGV("buffer_handle_t buffer : %p", buffer);
|
|
void* nv21_data;
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&nv21_data);
|
if (ret) {
|
HAL_LOGE("Failed to lock buffer: %d", ret);
|
return ret;
|
}
|
HAL_LOGV("*camera_buffer->buffer:0x%p, stream->width:%d, stream->height:%d.",
|
(*camera_buffer->buffer), stream->width, stream->height);
|
// If so, great, point to the beginning.
|
data = nv21_data;
|
HAL_LOGD("yuv_data:0x%p.", nv21_data);
|
if (!data) {
|
ALOGE("Gralloc lock returned null ptr");
|
return -ENODEV;
|
}
|
|
// Set up the device buffer.
|
static_assert(sizeof(unsigned long) >= sizeof(void*),
|
"void* must be able to fit in the v4l2_buffer m.userptr "
|
"field (unsigned long) for this code to work");
|
|
*device_buffer = reinterpret_cast<unsigned long>(data);
|
HAL_LOGD("lock get buffer vaddr is %p", (void*)device_buffer);
|
return 0;
|
}
|
|
int V4L2Gralloc::lock_index(const camera3_stream_buffer_t* camera_buffer,
|
unsigned long* device_buffer,
|
uint32_t result_index) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
buffer_handle_t buffer = *camera_buffer->buffer;
|
void* data;
|
camera3_stream_t* stream = camera_buffer->stream;
|
int ret = 0;
|
HAL_LOGV("buffer_handle_t buffer : %p", buffer);
|
aBufferDataVideo[result_index] = buffer;
|
|
void* nv21_data;
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&nv21_data);
|
if (ret) {
|
HAL_LOGE("Failed to lock buffer: %d", ret);
|
return ret;
|
}
|
HAL_LOGV("*camera_buffer->buffer:0x%p, stream->width:%d, stream->height:%d.",
|
(*camera_buffer->buffer), stream->width, stream->height);
|
// If so, great, point to the beginning.
|
data = nv21_data;
|
|
if (!data) {
|
ALOGE("Gralloc lock returned null ptr");
|
return -ENODEV;
|
}
|
|
*device_buffer = reinterpret_cast<unsigned long>(data);
|
HAL_LOGD("lock get buffer vaddr is %p",(void*)device_buffer);
|
return 0;
|
}
|
|
int V4L2Gralloc::unlock_index(uint32_t result_index) {
|
const buffer_handle_t buffer = aBufferDataVideo[result_index];
|
private_handle_t *hnd = (private_handle_t *)buffer;
|
HAL_LOGV("buffer_handle_t[%d] buffer : %p,The id is %lld.",
|
result_index, buffer, hnd->aw_buf_id);
|
// Unlock.
|
int res = mModule->unlock(mModule, buffer);
|
if (res) {
|
HAL_LOGE("Failed to unlock buffer at %p", buffer);
|
return -ENODEV;
|
}
|
|
return 0;
|
}
|
|
int V4L2Gralloc::lock(const camera3_stream_buffer_t* camera_buffer,
|
uint32_t bytes_per_line,
|
v4l2_buffer* device_buffer) {
|
// Lock the camera buffer (varies depending on if the buffer is YUV or not).
|
std::shared_ptr<BufferData> buffer_data(
|
new BufferData{camera_buffer, bytes_per_line});
|
memcpy(aBufferData[device_buffer->index],
|
buffer_data.get(),
|
sizeof(BufferData));
|
|
HAL_LOGD("aBufferData[%d]:%p, camera_buffer:%p.",
|
device_buffer->index,
|
aBufferData[device_buffer->index],
|
aBufferData[device_buffer->index]->camera_buffer);
|
|
buffer_handle_t buffer = *camera_buffer->buffer;
|
void* data;
|
camera3_stream_t* stream = camera_buffer->stream;
|
private_handle_t *hnd = (private_handle_t *)buffer;
|
int ret = 0;
|
HAL_LOGV("buffer_handle_t[%d] buffer : %p,"
|
" The camera_buffer is %p,id is %lld.",
|
device_buffer->index, buffer, camera_buffer, hnd->aw_buf_id);
|
|
switch (StreamFormat::HalToV4L2PixelFormat(stream->format)) {
|
case V4L2_PIX_FMT_NV21:
|
case V4L2_PIX_FMT_NV12:
|
case V4L2_PIX_FMT_YUV420:
|
void* nv21_data;
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&nv21_data);
|
if (ret) {
|
HAL_LOGE("Failed to lock buffer: %d", ret);
|
return ret;
|
}
|
HAL_LOGV("*camera_buffer->buffer:0x%p, stream->width:%d,"
|
" stream->height:%d, bytes_per_line:%d.",
|
(*camera_buffer->buffer),
|
stream->width,
|
stream->height, bytes_per_line);
|
// If so, great, point to the beginning.
|
data = nv21_data;
|
HAL_LOGD("yuv_data:0x%p, bytes_per_line:%d.",
|
nv21_data, bytes_per_line);
|
break;
|
// TODO(b/30119452): support more YCbCr formats.
|
case V4L2_PIX_FMT_YVU420:
|
android_ycbcr yuv_data;
|
ret = mModule->lock_ycbcr(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&yuv_data);
|
if (ret) {
|
HAL_LOGE("Failed to lock ycbcr buffer: %d", ret);
|
return ret;
|
}
|
HAL_LOGV("*camera_buffer->buffer:0x%p, stream->width:%d,"
|
" stream->height:%d, bytes_per_line:%d.",
|
(*camera_buffer->buffer),
|
stream->width,
|
stream->height,
|
bytes_per_line);
|
HAL_LOGV("yuv_data.ystride:%zu, yuv_data.cstride:%zu,"
|
" yuv_data.chroma_step:%zu, yuv_data.y:0x%p, yuv_data.cb:0x%p, "
|
"yuv_data.cr:0x%p.",
|
yuv_data.ystride,
|
yuv_data.cstride,
|
yuv_data.chroma_step,
|
yuv_data.y,
|
yuv_data.cb,
|
yuv_data.cr);
|
|
// Check if gralloc format matches v4l2 format
|
// (same padding, not interleaved, contiguous).
|
// In there yuv_data.chroma_step is difference.
|
// So what the yuv_data.chroma_step meant for buffer?
|
if (1) {
|
// If so, great, point to the beginning.
|
data = yuv_data.y;
|
HAL_LOGD("yuv_data.y:0x%p, bytes_per_line:%d.",
|
yuv_data.y, bytes_per_line);
|
} else {
|
// If not, allocate a contiguous buffer of appropriate size
|
// (to be transformed back upon unlock).
|
data = new uint8_t[device_buffer->length];
|
// Make a dynamically-allocated copy of yuv_data,
|
// since it will be needed at transform time.
|
// buffer_data->transform_dest.reset(new android_ycbcr(yuv_data));
|
}
|
break;
|
case V4L2_PIX_FMT_JPEG:
|
// Jpeg buffers are just contiguous blobs; lock length * 1.
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
device_buffer->length,
|
1,
|
&data);
|
if (ret) {
|
HAL_LOGE("Failed to lock jpeg buffer: %d", ret);
|
return ret;
|
}
|
break;
|
case V4L2_PIX_FMT_BGR32: // Fall-through.
|
case V4L2_PIX_FMT_RGB32:
|
// RGB formats have nice agreed upon representation. Unless using android
|
// flex formats.
|
ret = mModule->lock(mModule,
|
buffer,
|
stream->usage,
|
0,
|
0,
|
stream->width,
|
stream->height,
|
&data);
|
if (ret) {
|
HAL_LOGE("Failed to lock RGB buffer: %d", ret);
|
return ret;
|
}
|
break;
|
default:
|
return -EINVAL;
|
}
|
|
if (!data) {
|
ALOGE("Gralloc lock returned null ptr");
|
return -ENODEV;
|
}
|
|
// Set up the device buffer.
|
static_assert(sizeof(unsigned long) >= sizeof(void*),
|
"void* must be able to fit in the v4l2_buffer m.userptr "
|
"field (unsigned long) for this code to work");
|
|
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == device_buffer->type) {
|
// Note the mapping of index:buffer info for when unlock is called.
|
device_buffer->m.planes[0].m.userptr =
|
reinterpret_cast<unsigned long>(data);
|
|
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == device_buffer->type) {
|
// Note the mapping of index:buffer info for when unlock is called.
|
device_buffer->m.userptr = reinterpret_cast<unsigned long>(data);
|
}
|
device_buffer->m.planes[0].m.userptr = reinterpret_cast<unsigned long>(data);
|
HAL_LOGD("lock get index:%d buffer vaddr is %p", device_buffer->index, data);
|
|
return 0;
|
}
|
|
int V4L2Gralloc::unlock(const v4l2_buffer* device_buffer) {
|
// TODO(b/30000211): support multi-planar data (video_capture_mplane).
|
if (device_buffer->type != V4L2_CAPTURE_TYPE) {
|
return -EINVAL;
|
}
|
HAL_LOGV("unlock get index:%d buffer ", device_buffer->index);
|
// Find and pop the matching entry in the map.
|
HAL_LOGD("aBufferData[%d]:%p, camera_buffer:%p.",
|
device_buffer->index,
|
aBufferData[device_buffer->index],
|
aBufferData[device_buffer->index]->camera_buffer);
|
|
const camera3_stream_buffer_t* camera_buffer =
|
aBufferData[device_buffer->index]->camera_buffer;
|
const buffer_handle_t buffer = *camera_buffer->buffer;
|
|
private_handle_t *hnd = (private_handle_t *)buffer;
|
HAL_LOGV("buffer_handle_t[%d] buffer : %p,The camera_buffer is %p,"
|
" id is %lld, vaddr is 0x%p.",
|
device_buffer->index,
|
buffer, camera_buffer,
|
hnd->aw_buf_id,
|
static_cast<void*>(&hnd->base));
|
|
// Unlock.
|
int res = mModule->unlock(mModule, buffer);
|
if (res) {
|
HAL_LOGE("Failed to unlock buffer at %p", buffer);
|
return -ENODEV;
|
}
|
HAL_LOGD("The camera_buffer is %p,camera_buffer->buffer is %p",
|
camera_buffer, camera_buffer->buffer);
|
|
return 0;
|
}
|
|
int V4L2Gralloc::unlockAllBuffers() {
|
HAL_LOG_ENTER();
|
bool failed = false;
|
// If any unlock failed, return error.
|
if (failed) {
|
return -ENODEV;
|
}
|
return 0;
|
}
|
|
} // namespace default_camera_hal
|