/* * 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 #include #include #include #include #include #include #include #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(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(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(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(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 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(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(data); } device_buffer->m.planes[0].m.userptr = reinterpret_cast(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(&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