diff options
Diffstat (limited to 'libgscaler/libgscaler.cpp')
-rw-r--r-- | libgscaler/libgscaler.cpp | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/libgscaler/libgscaler.cpp b/libgscaler/libgscaler.cpp new file mode 100644 index 0000000..fdf44cd --- /dev/null +++ b/libgscaler/libgscaler.cpp @@ -0,0 +1,608 @@ +/* + * 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; +} |