| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * Copyright@ Samsung Electronics 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. |
| */ |
| |
| /*! |
| * \file libgscaler.cpp |
| * \brief source file for Gscaler HAL |
| * \author Sungchun Kang (sungchun.kang@samsung.com) |
| * \date 2013/06/01 |
| * |
| * <b>Revision History: </b> |
| * - 2013.06.01 : Sungchun Kang (sungchun.kang@samsung.com) \n |
| * Create |
| */ |
| |
| #include <linux/v4l2-subdev.h> |
| |
| #include "libgscaler_obj.h" |
| #include "libgscaler_media.h" |
| |
| void *exynos_gsc_create(void) |
| { |
| CGscaler *gsc = new CGscaler(GSC_M2M_MODE); |
| if (!gsc) { |
| ALOGE("%s:: failed to allocate Gscaler handle", __func__); |
| return NULL; |
| } |
| if (gsc->m_gsc_find_and_create(gsc) == false) { |
| ALOGE("%s::m_exynos_gsc_find_and_create() fail", __func__); |
| delete gsc; |
| return NULL; |
| } |
| |
| return reinterpret_cast<void *>(gsc); |
| } |
| |
| void *exynos_gsc_create_exclusive( |
| int dev_num, |
| int mode, |
| int out_mode, |
| int allow_drm) |
| { |
| Exynos_gsc_In(); |
| |
| if ((dev_num < 0) || (dev_num >= HW_SCAL_MAX)) { |
| ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); |
| return NULL; |
| } |
| |
| if ((dev_num >= NUM_OF_GSC_HW) && (dev_num < HW_SCAL_MAX)) { |
| CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); |
| if (!gsc) { |
| ALOGE("%s:: failed to allocate Gscaler handle", __func__); |
| return NULL; |
| } |
| |
| gsc->scaler = exynos_sc_create_exclusive(dev_num - HW_SCAL0, |
| allow_drm); |
| if (!gsc->scaler) { |
| delete(gsc); |
| ALOGE("%s::exynos_sc_create fail", __func__); |
| return NULL; |
| } |
| Exynos_gsc_Out(); |
| return reinterpret_cast<void *>(gsc); |
| } |
| |
| if ((mode < 0) || (mode >= NUM_OF_GSC_HW)) { |
| ALOGE("%s::fail:: mode is not valid(%d) ", __func__, mode); |
| return NULL; |
| } |
| |
| CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); |
| if (!gsc) { |
| ALOGE("%s:: failed to allocate Gscaler handle", __func__); |
| return NULL; |
| } |
| |
| if (mode == GSC_M2M_MODE) { |
| gsc->gsc_fd = gsc->m_gsc_m2m_create(dev_num); |
| if (gsc->gsc_fd < 0) { |
| ALOGE("%s::m_gsc_m2m_create(%i) fail", __func__, dev_num); |
| goto err; |
| } |
| } else { |
| ALOGE("%s::Unsupported Mode(%i) fail", __func__, dev_num); |
| goto err; |
| } |
| |
| Exynos_gsc_Out(); |
| |
| return reinterpret_cast<void *>(gsc); |
| err: |
| switch (mode) { |
| case GSC_M2M_MODE: |
| gsc->m_gsc_m2m_destroy(gsc); |
| break; |
| } |
| |
| delete(gsc); |
| |
| Exynos_gsc_Out(); |
| |
| return NULL; |
| } |
| |
| void exynos_gsc_destroy(void *handle) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return; |
| } |
| |
| if (gsc->mode == GSC_M2M_MODE) |
| gsc->m_gsc_m2m_destroy(gsc); |
| |
| delete(gsc); |
| |
| Exynos_gsc_Out(); |
| } |
| |
| int exynos_gsc_set_csc_property( |
| void *handle, |
| unsigned int eq_auto, |
| unsigned int range_full, |
| unsigned int v4l2_colorspace) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler *gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| if (gsc->gsc_id >= HW_SCAL0) { |
| int ret; |
| ret = exynos_sc_csc_exclusive(gsc->scaler, |
| range_full, v4l2_colorspace); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| gsc->eq_auto = eq_auto; |
| gsc->range_full = range_full; |
| gsc->v4l2_colorspace = v4l2_colorspace; |
| |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |
| |
| int exynos_gsc_set_src_format( |
| void *handle, |
| unsigned int width, |
| unsigned int height, |
| unsigned int crop_left, |
| unsigned int crop_top, |
| unsigned int crop_width, |
| unsigned int crop_height, |
| unsigned int v4l2_colorformat, |
| unsigned int cacheable, |
| unsigned int mode_drm) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler *gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| gsc->src_info.width = width; |
| gsc->src_info.height = height; |
| gsc->src_info.crop_left = crop_left; |
| gsc->src_info.crop_top = crop_top; |
| gsc->src_info.crop_width = crop_width; |
| gsc->src_info.crop_height = crop_height; |
| gsc->src_info.v4l2_colorformat = v4l2_colorformat; |
| gsc->src_info.cacheable = cacheable; |
| gsc->src_info.mode_drm = mode_drm; |
| gsc->src_info.dirty = true; |
| |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |
| |
| int exynos_gsc_set_dst_format( |
| void *handle, |
| unsigned int width, |
| unsigned int height, |
| unsigned int crop_left, |
| unsigned int crop_top, |
| unsigned int crop_width, |
| unsigned int crop_height, |
| unsigned int v4l2_colorformat, |
| unsigned int cacheable, |
| unsigned int mode_drm) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler *gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| gsc->dst_info.width = width; |
| gsc->dst_info.height = height; |
| gsc->dst_info.crop_left = crop_left; |
| gsc->dst_info.crop_top = crop_top; |
| gsc->dst_info.crop_width = crop_width; |
| gsc->dst_info.crop_height = crop_height; |
| gsc->dst_info.v4l2_colorformat = v4l2_colorformat; |
| gsc->dst_info.dirty = true; |
| gsc->dst_info.cacheable = cacheable; |
| gsc->dst_info.mode_drm = mode_drm; |
| |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |
| |
| int exynos_gsc_set_rotation( |
| void *handle, |
| int rotation, |
| int flip_horizontal, |
| int flip_vertical) |
| { |
| CGscaler *gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| int new_rotation = rotation % 360; |
| |
| if (new_rotation % 90 != 0) { |
| ALOGE("%s::rotation(%d) cannot be acceptable fail", __func__, |
| rotation); |
| return -1; |
| } |
| |
| if(new_rotation < 0) |
| new_rotation = -new_rotation; |
| |
| gsc->dst_info.rotation = new_rotation; |
| gsc->dst_info.flip_horizontal = flip_horizontal; |
| gsc->dst_info.flip_vertical = flip_vertical; |
| |
| return 0; |
| } |
| |
| int exynos_gsc_set_src_addr( |
| void *handle, |
| void *addr[3], |
| int mem_type, |
| int acquireFenceFd) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| gsc->src_info.buf.addr[0] = addr[0]; |
| gsc->src_info.buf.addr[1] = addr[1]; |
| gsc->src_info.buf.addr[2] = addr[2]; |
| gsc->src_info.acquireFenceFd = acquireFenceFd; |
| gsc->src_info.buf.mem_type = (enum v4l2_memory)mem_type; |
| |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |
| |
| int exynos_gsc_set_dst_addr( |
| void *handle, |
| void *addr[3], |
| int mem_type, |
| int acquireFenceFd) |
| { |
| Exynos_gsc_In(); |
| |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| gsc->dst_info.buf.addr[0] = addr[0]; |
| gsc->dst_info.buf.addr[1] = addr[1]; |
| gsc->dst_info.buf.addr[2] = addr[2]; |
| gsc->dst_info.acquireFenceFd = acquireFenceFd; |
| gsc->dst_info.buf.mem_type = (enum v4l2_memory)mem_type; |
| |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |
| |
| int exynos_gsc_convert(void *handle) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = -1; |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return ret; |
| } |
| |
| if (gsc->m_gsc_m2m_run_core(handle) < 0) { |
| ALOGE("%s::exynos_gsc_run_core fail", __func__); |
| goto done; |
| } |
| |
| if (gsc->m_gsc_m2m_wait_frame_done(handle) < 0) { |
| ALOGE("%s::exynos_gsc_m2m_wait_frame_done", __func__); |
| goto done; |
| } |
| |
| if (gsc->src_info.releaseFenceFd >= 0) { |
| close(gsc->src_info.releaseFenceFd); |
| gsc->src_info.releaseFenceFd = -1; |
| } |
| |
| if (gsc->dst_info.releaseFenceFd >= 0) { |
| close(gsc->dst_info.releaseFenceFd); |
| gsc->dst_info.releaseFenceFd = -1; |
| } |
| |
| if (gsc->m_gsc_m2m_stop(handle) < 0) { |
| ALOGE("%s::m_gsc_m2m_stop", __func__); |
| goto done; |
| } |
| |
| ret = 0; |
| |
| done: |
| Exynos_gsc_Out(); |
| |
| return ret; |
| } |
| |
| int exynos_gsc_subdev_s_crop(void *handle, |
| exynos_mpp_img __UNUSED__ *src_img, exynos_mpp_img *dst_img) |
| { |
| struct v4l2_subdev_crop sd_crop; |
| CGscaler *gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| sd_crop.pad = GSCALER_SUBDEV_PAD_SOURCE; |
| sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
| sd_crop.rect.left = dst_img->x; |
| sd_crop.rect.top = dst_img->y; |
| sd_crop.rect.width = dst_img->w; |
| sd_crop.rect.height = dst_img->h; |
| |
| return exynos_subdev_s_crop(gsc->mdev.gsc_sd_entity->fd, &sd_crop); |
| } |
| |
| int exynos_gsc_config_exclusive(void *handle, |
| exynos_mpp_img *src_img, exynos_mpp_img *dst_img) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_config_exclusive(gsc->scaler, |
| (exynos_sc_img *)src_img, (exynos_sc_img *)dst_img); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| switch (gsc->mode) { |
| case GSC_M2M_MODE: |
| ret = gsc->m_gsc_m2m_config(handle, src_img, dst_img); |
| break; |
| case GSC_OUTPUT_MODE: |
| ret = gsc->m_gsc_out_config(handle, src_img, dst_img); |
| break; |
| case GSC_CAPTURE_MODE: |
| ret = gsc->m_gsc_cap_config(handle, src_img, dst_img); |
| break; |
| default: |
| break; |
| } |
| |
| Exynos_gsc_Out(); |
| |
| return ret; |
| } |
| |
| int exynos_gsc_run_exclusive(void *handle, |
| exynos_mpp_img *src_img, exynos_mpp_img *dst_img) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (handle == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_run_exclusive(gsc->scaler, |
| (exynos_sc_img *)src_img, (exynos_sc_img *)dst_img); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| switch (gsc->mode) { |
| case GSC_M2M_MODE: |
| ret = gsc->m_gsc_m2m_run(handle, src_img, dst_img); |
| break; |
| case GSC_OUTPUT_MODE: |
| ret = gsc->m_gsc_out_run(handle, src_img); |
| break; |
| case GSC_CAPTURE_MODE: |
| ret = gsc->m_gsc_cap_run(handle, dst_img); |
| break; |
| default: |
| break; |
| } |
| |
| Exynos_gsc_Out(); |
| |
| return ret; |
| } |
| |
| void *exynos_gsc_create_blend_exclusive(int dev_num, int mode, int out_mode, |
| int allow_drm) |
| { |
| Exynos_gsc_In(); |
| |
| if ((dev_num < 0) || (dev_num >= HW_SCAL_MAX)) { |
| ALOGE("%s::fail:: dev_num is not valid(%d) ", __func__, dev_num); |
| return NULL; |
| } |
| |
| if ((dev_num >= NUM_OF_GSC_HW) && (dev_num < HW_SCAL_MAX)) { |
| CGscaler *gsc = new CGscaler(mode, out_mode, dev_num, allow_drm); |
| if (!gsc) { |
| ALOGE("%s:: failed to allocate Gscaler handle", __func__); |
| return NULL; |
| } |
| |
| gsc->scaler = exynos_sc_create_blend_exclusive(dev_num - HW_SCAL0, allow_drm); |
| if (!gsc->scaler) { |
| Exynos_gsc_Out(); |
| delete(gsc); |
| ALOGE("%s::exynos_sc_create_blend_exclusive failed", __func__); |
| return NULL; |
| } |
| Exynos_gsc_Out(); |
| |
| return reinterpret_cast<void *>(gsc); |
| } |
| |
| Exynos_gsc_Out(); |
| |
| return NULL; |
| } |
| |
| int exynos_gsc_config_blend_exclusive(void *handle, |
| exynos_mpp_img *src_img, exynos_mpp_img *dst_img, |
| struct SrcBlendInfo *srcblendinfo) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_config_blend_exclusive(gsc->scaler, |
| (exynos_sc_img *)src_img, |
| (exynos_sc_img *)dst_img, |
| srcblendinfo); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| int exynos_gsc_wait_frame_done_exclusive(void *handle) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (handle == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_wait_frame_done_exclusive(gsc->scaler); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| if (gsc->mode == GSC_M2M_MODE) |
| ret = gsc->m_gsc_m2m_wait_frame_done(handle); |
| |
| Exynos_gsc_Out(); |
| |
| return ret; |
| } |
| |
| int exynos_gsc_stop_exclusive(void *handle) |
| { |
| Exynos_gsc_In(); |
| |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (handle == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_stop_exclusive(gsc->scaler); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| switch (gsc->mode) { |
| case GSC_M2M_MODE: |
| ret = gsc->m_gsc_m2m_stop(handle); |
| break; |
| default: |
| break; |
| } |
| |
| Exynos_gsc_Out(); |
| |
| return ret; |
| } |
| |
| int exynos_gsc_free_and_close(void *handle) |
| { |
| Exynos_gsc_In(); |
| |
| struct v4l2_requestbuffers reqbuf; |
| int ret = 0; |
| CGscaler* gsc = GetGscaler(handle); |
| if (gsc == NULL) { |
| ALOGE("%s::handle == NULL() fail", __func__); |
| return -1; |
| } |
| |
| |
| if (gsc->gsc_id >= HW_SCAL0) { |
| ret = exynos_sc_free_and_close(gsc->scaler); |
| Exynos_gsc_Out(); |
| return ret; |
| } |
| |
| memset(&reqbuf, 0, sizeof(struct v4l2_requestbuffers)); |
| if (gsc->mode == GSC_OUTPUT_MODE) |
| reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| else |
| reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; |
| |
| reqbuf.memory = V4L2_MEMORY_DMABUF; |
| reqbuf.count = 0; |
| |
| if (ioctl(gsc->mdev.gsc_vd_entity->fd, VIDIOC_REQBUFS, &reqbuf) < 0) { |
| ALOGE("%s::request buffers failed", __func__); |
| return -1; |
| } |
| |
| exynos_gsc_destroy(gsc); |
| Exynos_gsc_Out(); |
| |
| return 0; |
| } |