/*
* 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_obj.cpp
* \brief source file for Gscaler HAL
* \author Sungchun Kang (sungchun.kang@samsung.com)
* \date 2013/06/01
*
* Revision History:
* - 2013.06.01 : Sungchun Kang (sungchun.kang@samsung.com) \n
* Create
*/
#include
#include "libgscaler_obj.h"
#include
#include
int CGscaler::m_gsc_output_create(void *handle, int dev_num, int out_mode)
{
Exynos_gsc_In();
struct media_device *media0;
struct media_entity *gsc_sd_entity;
struct media_entity *gsc_vd_entity;
struct media_entity *sink_sd_entity;
char node[32];
char devname[32];
unsigned int cap;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if ((out_mode != GSC_OUT_FIMD) &&
(out_mode != GSC_OUT_TV))
return -1;
gsc->out_mode = out_mode;
/* GSCX => FIMD_WINX : arbitrary linking is not allowed */
if ((out_mode == GSC_OUT_FIMD) &&
#ifndef USES_ONLY_GSC0_GSC1
(dev_num > 2))
#else
(dev_num > 1))
#endif
return -1;
/* media0 */
snprintf(node, sizeof(node), "%s%d", PFX_NODE_MEDIADEV, 0);
media0 = exynos_media_open(node);
if (media0 == NULL) {
ALOGE("%s::exynos_media_open failed (node=%s)", __func__, node);
return false;
}
gsc->mdev.media0 = media0;
/* Get the sink subdev entity by name and make the node of sink subdev*/
if (out_mode == GSC_OUT_FIMD)
snprintf(devname, sizeof(devname), PFX_FIMD_ENTITY, dev_num);
else
snprintf(devname, sizeof(devname), PFX_MXR_ENTITY, 0);
sink_sd_entity = exynos_media_get_entity_by_name(media0, devname,
strlen(devname));
if (!sink_sd_entity) {
ALOGE("%s:: failed to get the sink sd entity", __func__);
goto gsc_output_err;
}
gsc->mdev.sink_sd_entity = sink_sd_entity;
sink_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR);
if (sink_sd_entity->fd < 0) {
ALOGE("%s:: failed to open sink subdev node", __func__);
goto gsc_output_err;
}
/* get GSC video dev & sub dev entity by name*/
#if defined(USES_DT)
switch (dev_num) {
case 0:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY0);
break;
case 1:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY1);
break;
case 2:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY2);
break;
}
#else
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY, dev_num);
#endif
gsc_vd_entity = exynos_media_get_entity_by_name(media0, devname,
strlen(devname));
if (!gsc_vd_entity) {
ALOGE("%s:: failed to get the gsc vd entity", __func__);
goto gsc_output_err;
}
gsc->mdev.gsc_vd_entity = gsc_vd_entity;
snprintf(devname, sizeof(devname), PFX_GSC_SUBDEV_ENTITY, dev_num);
gsc_sd_entity = exynos_media_get_entity_by_name(media0, devname,
strlen(devname));
if (!gsc_sd_entity) {
ALOGE("%s:: failed to get the gsc sd entity", __func__);
goto gsc_output_err;
}
gsc->mdev.gsc_sd_entity = gsc_sd_entity;
/* gsc sub-dev open */
snprintf(devname, sizeof(devname), PFX_GSC_SUBDEV_ENTITY, dev_num);
gsc_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR);
if (gsc_sd_entity->fd < 0) {
ALOGE("%s: gsc sub-dev open fail", __func__);
goto gsc_output_err;
}
/* gsc video-dev open */
#if defined(USES_DT)
switch (dev_num) {
case 0:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY0);
break;
case 1:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY1);
break;
case 2:
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY2);
break;
}
#else
snprintf(devname, sizeof(devname), PFX_GSC_VIDEODEV_ENTITY, dev_num);
#endif
gsc_vd_entity->fd = exynos_v4l2_open_devname(devname, O_RDWR | O_NONBLOCK);
if (gsc_vd_entity->fd < 0) {
ALOGE("%s: gsc video-dev open fail", __func__);
goto gsc_output_err;
}
cap = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
if (exynos_v4l2_querycap(gsc_vd_entity->fd, cap) == false) {
ALOGE("%s::exynos_v4l2_querycap() fail", __func__);
goto gsc_output_err;
}
Exynos_gsc_Out();
return 0;
gsc_output_err:
gsc->m_gsc_out_destroy(handle);
return -1;
}
int CGscaler::m_gsc_capture_create(void *handle, int dev_num, int out_mode)
{
Exynos_gsc_In();
struct media_device *media1;
struct media_entity *gsc_sd_entity;
struct media_entity *gsc_vd_entity;
struct media_entity *sink_sd_entity;
char node[32];
char devname[32];
unsigned int cap;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
gsc->out_mode = out_mode;
if (dev_num != 2)
return -1;
/* media1 */
snprintf(node, sizeof(node), "%s%d", PFX_NODE_MEDIADEV, 1);
media1 = exynos_media_open(node);
if (media1 == NULL) {
ALOGE("%s::exynos_media_open failed (node=%s)", __func__, node);
return false;
}
gsc->mdev.media1 = media1;
/* DECON-TV sub-device Open */
snprintf(devname, sizeof(devname), DEX_WB_SD_NAME);
sink_sd_entity = exynos_media_get_entity_by_name(media1, devname,
strlen(devname));
if (!sink_sd_entity) {
ALOGE("%s:: failed to get the sink sd entity", __func__);
goto gsc_cap_err;
}
gsc->mdev.sink_sd_entity = sink_sd_entity;
sink_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR);
if (sink_sd_entity->fd < 0) {
ALOGE("%s:: failed to open sink subdev node", __func__);
goto gsc_cap_err;
}
/* Gscaler2 capture video-device Open */
snprintf(devname, sizeof(devname), PFX_GSC_CAPTURE_ENTITY);
gsc_vd_entity = exynos_media_get_entity_by_name(media1, devname,
strlen(devname));
if (!gsc_vd_entity) {
ALOGE("%s:: failed to get the gsc vd entity", __func__);
goto gsc_cap_err;
}
gsc->mdev.gsc_vd_entity = gsc_vd_entity;
gsc_vd_entity->fd = exynos_v4l2_open_devname(devname, O_RDWR);
if (gsc_vd_entity->fd < 0) {
ALOGE("%s: gsc video-dev open fail", __func__);
goto gsc_cap_err;
}
/* Gscaler2 capture sub-device Open */
snprintf(devname, sizeof(devname), GSC_WB_SD_NAME);
gsc_sd_entity = exynos_media_get_entity_by_name(media1, devname,
strlen(devname));
if (!gsc_sd_entity) {
ALOGE("%s:: failed to get the gsc sd entity", __func__);
goto gsc_cap_err;
}
gsc->mdev.gsc_sd_entity = gsc_sd_entity;
gsc_sd_entity->fd = exynos_subdev_open_devname(devname, O_RDWR);
if (gsc_sd_entity->fd < 0) {
ALOGE("%s: gsc sub-dev open fail", __func__);
goto gsc_cap_err;
}
if (exynos_media_setup_link(media1, sink_sd_entity->pads,
gsc_sd_entity->pads, MEDIA_LNK_FL_ENABLED) < 0) {
ALOGE("%s::exynos_media_setup_link failed", __func__);
goto gsc_cap_err;
}
cap = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE;
if (exynos_v4l2_querycap(gsc_vd_entity->fd, cap) == false) {
ALOGE("%s::exynos_v4l2_querycap() fail", __func__);
goto gsc_cap_err;
}
Exynos_gsc_Out();
return 0;
gsc_cap_err:
gsc->m_gsc_cap_destroy(handle);
return -1;
}
int CGscaler::m_gsc_out_stop(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if (gsc->src_info.stream_on == false) {
/* to handle special scenario.*/
gsc->src_info.qbuf_cnt = 0;
ALOGD("%s::GSC is already stopped", __func__);
goto SKIP_STREAMOFF;
}
gsc->src_info.qbuf_cnt = 0;
gsc->src_info.stream_on = false;
if (exynos_v4l2_streamoff(gsc->mdev.gsc_vd_entity->fd,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) < 0) {
ALOGE("%s::stream off failed", __func__);
return -1;
}
SKIP_STREAMOFF:
Exynos_gsc_Out();
return 0;
}
int CGscaler::m_gsc_cap_stop(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if (gsc->dst_info.stream_on == false) {
/* to handle special scenario.*/
gsc->dst_info.qbuf_cnt = 0;
ALOGD("%s::GSC is already stopped", __func__);
goto SKIP_STREAMOFF;
}
gsc->dst_info.qbuf_cnt = 0;
gsc->dst_info.stream_on = false;
if (exynos_v4l2_streamoff(gsc->mdev.gsc_vd_entity->fd,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) < 0) {
ALOGE("%s::stream off failed", __func__);
return -1;
}
SKIP_STREAMOFF:
Exynos_gsc_Out();
return 0;
}
bool CGscaler::m_gsc_out_destroy(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return false;
}
if (gsc->src_info.stream_on == true) {
if (gsc->m_gsc_out_stop(gsc) < 0)
ALOGE("%s::m_gsc_out_stop() fail", __func__);
gsc->src_info.stream_on = false;
}
if (gsc->mdev.gsc_vd_entity && gsc->mdev.gsc_vd_entity->fd > 0) {
close(gsc->mdev.gsc_vd_entity->fd);
gsc->mdev.gsc_vd_entity->fd = -1;
}
if (gsc->mdev.gsc_sd_entity && gsc->mdev.gsc_sd_entity->fd > 0) {
close(gsc->mdev.gsc_sd_entity->fd);
gsc->mdev.gsc_sd_entity->fd = -1;
}
if (gsc->mdev.sink_sd_entity && gsc->mdev.sink_sd_entity->fd > 0) {
close(gsc->mdev.sink_sd_entity->fd);
gsc->mdev.sink_sd_entity->fd = -1;
}
if (gsc->mdev.media0)
exynos_media_close(gsc->mdev.media0);
gsc->mdev.media0 = NULL;
gsc->mdev.gsc_sd_entity = NULL;
gsc->mdev.gsc_vd_entity = NULL;
gsc->mdev.sink_sd_entity = NULL;
Exynos_gsc_Out();
return true;
}
bool CGscaler::m_gsc_cap_destroy(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return false;
}
if (gsc->dst_info.stream_on == true) {
if (gsc->m_gsc_cap_stop(gsc) < 0)
ALOGE("%s::m_gsc_cap_stop() fail", __func__);
gsc->dst_info.stream_on = false;
}
if (!gsc->mdev.media1 || !gsc->mdev.gsc_sd_entity ||
!gsc->mdev.gsc_vd_entity || !gsc->mdev.sink_sd_entity) {
ALOGE("%s::gsc->mdev information is null", __func__);
return false;
}
if (exynos_media_setup_link(gsc->mdev.media1,
gsc->mdev.sink_sd_entity->pads,
gsc->mdev.gsc_sd_entity->pads, 0) < 0) {
ALOGE("%s::exynos_media_setup_unlin failed", __func__);
}
if (gsc->mdev.gsc_vd_entity && gsc->mdev.gsc_vd_entity->fd > 0) {
close(gsc->mdev.gsc_vd_entity->fd);
gsc->mdev.gsc_vd_entity->fd = -1;
}
if (gsc->mdev.gsc_sd_entity && gsc->mdev.gsc_sd_entity->fd > 0) {
close(gsc->mdev.gsc_sd_entity->fd);
gsc->mdev.gsc_sd_entity->fd = -1;
}
if (gsc->mdev.sink_sd_entity && gsc->mdev.sink_sd_entity->fd > 0) {
close(gsc->mdev.sink_sd_entity->fd);
gsc->mdev.sink_sd_entity->fd = -1;
}
if (gsc->mdev.media1)
exynos_media_close(gsc->mdev.media1);
gsc->mdev.media1 = NULL;
gsc->mdev.gsc_sd_entity = NULL;
gsc->mdev.gsc_vd_entity = NULL;
gsc->mdev.sink_sd_entity = NULL;
Exynos_gsc_Out();
return true;
}
int CGscaler::m_gsc_m2m_create(int dev)
{
Exynos_gsc_In();
int fd = 0;
int video_node_num;
unsigned int cap;
char node[32];
switch(dev) {
case 0:
video_node_num = NODE_NUM_GSC_0;
break;
case 1:
video_node_num = NODE_NUM_GSC_1;
break;
#ifndef USES_ONLY_GSC0_GSC1
case 2:
video_node_num = NODE_NUM_GSC_2;
break;
case 3:
video_node_num = NODE_NUM_GSC_3;
break;
#endif
default:
ALOGE("%s::unexpected dev(%d) fail", __func__, dev);
return -1;
break;
}
snprintf(node, sizeof(node), "%s%d", PFX_NODE_GSC, video_node_num);
fd = exynos_v4l2_open(node, O_RDWR);
if (fd < 0) {
ALOGE("%s::exynos_v4l2_open(%s) fail", __func__, node);
return -1;
}
cap = V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE;
if (exynos_v4l2_querycap(fd, cap) == false) {
ALOGE("%s::exynos_v4l2_querycap() fail", __func__);
close(fd);
fd = 0;
return -1;
}
Exynos_gsc_Out();
return fd;
}
bool CGscaler::m_gsc_find_and_create(void *handle)
{
Exynos_gsc_In();
int i = 0;
bool flag_find_new_gsc = false;
unsigned int total_sleep_time = 0;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return false;
}
do {
for (i = 0; i < NUM_OF_GSC_HW; i++) {
#ifndef USES_ONLY_GSC0_GSC1
if (i == 0 || i == 3)
#else
if (i == 0)
#endif
continue;
gsc->gsc_id = i;
gsc->gsc_fd = gsc->m_gsc_m2m_create(i);
if (gsc->gsc_fd < 0) {
gsc->gsc_fd = 0;
continue;
}
flag_find_new_gsc = true;
break;
}
if (flag_find_new_gsc == false) {
usleep(GSC_WAITING_TIME_FOR_TRYLOCK);
total_sleep_time += GSC_WAITING_TIME_FOR_TRYLOCK;
ALOGV("%s::waiting for the gscaler availability", __func__);
}
} while(flag_find_new_gsc == false
&& total_sleep_time < MAX_GSC_WAITING_TIME_FOR_TRYLOCK);
if (flag_find_new_gsc == false)
ALOGE("%s::we don't have any available gsc.. fail", __func__);
Exynos_gsc_Out();
return flag_find_new_gsc;
}
bool CGscaler::m_gsc_m2m_destroy(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return false;
}
/*
* just in case, we call stop here because we cannot afford to leave
* secure side protection on if things failed.
*/
gsc->m_gsc_m2m_stop(handle);
if (gsc->gsc_id >= HW_SCAL0) {
bool ret = exynos_sc_free_and_close(gsc->scaler);
Exynos_gsc_Out();
return ret;
}
if (0 < gsc->gsc_fd)
close(gsc->gsc_fd);
gsc->gsc_fd = 0;
Exynos_gsc_Out();
return true;
}
int CGscaler::m_gsc_m2m_stop(void *handle)
{
Exynos_gsc_In();
struct v4l2_requestbuffers req_buf;
int ret = 0;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if (!gsc->src_info.stream_on && !gsc->dst_info.stream_on) {
/* wasn't streaming, return success */
return 0;
} else if (gsc->src_info.stream_on != gsc->dst_info.stream_on) {
ALOGE("%s: invalid state, queue stream state doesn't match \
(%d != %d)", __func__, gsc->src_info.stream_on,
gsc->dst_info.stream_on);
ret = -1;
}
/*
* we need to plow forward on errors below to make sure that if we had
* turned on content protection on secure side, we turn it off.
*
* also, if we only failed to turn on one of the streams, we'll turn
* the other one off correctly.
*/
if (gsc->src_info.stream_on == true) {
if (exynos_v4l2_streamoff(gsc->gsc_fd,
gsc->src_info.buf.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamoff(src) fail", __func__);
ret = -1;
}
gsc->src_info.stream_on = false;
}
if (gsc->dst_info.stream_on == true) {
if (exynos_v4l2_streamoff(gsc->gsc_fd,
gsc->dst_info.buf.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamoff(dst) fail", __func__);
ret = -1;
}
gsc->dst_info.stream_on = false;
}
/* if drm is enabled */
if (gsc->allow_drm && gsc->protection_enabled) {
/*
if (gsc->gsc_id == 0)
protect_id = CP_PROTECT_GSC0;
else if (gsc->gsc_id == 1)
protect_id = CP_PROTECT_GSC1;
else if (gsc->gsc_id == 2)
protect_id = CP_PROTECT_GSC2;
else if (gsc->gsc_id == 3)
protect_id = CP_PROTECT_GSC3;
*/
/* CP_Disable_Path_Protection(protect_id); */
gsc->protection_enabled = false;
}
if (exynos_v4l2_s_ctrl(gsc->gsc_fd,
V4L2_CID_CONTENT_PROTECTION, 0) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail",
__func__);
ret = -1;
}
/* src: clear_buf */
req_buf.count = 0;
req_buf.type = gsc->src_info.buf.buf_type;
req_buf.memory = gsc->src_info.buf.mem_type;
if (exynos_v4l2_reqbufs(gsc->gsc_fd, &req_buf) < 0) {
ALOGE("%s::exynos_v4l2_reqbufs():src: fail", __func__);
ret = -1;
}
/* dst: clear_buf */
req_buf.count = 0;
req_buf.type = gsc->dst_info.buf.buf_type;
req_buf.memory = gsc->dst_info.buf.mem_type;;
if (exynos_v4l2_reqbufs(gsc->gsc_fd, &req_buf) < 0) {
ALOGE("%s::exynos_v4l2_reqbufs():dst: fail", __func__);
ret = -1;
}
Exynos_gsc_Out();
return ret;
}
int CGscaler::m_gsc_m2m_run_core(void *handle)
{
Exynos_gsc_In();
unsigned int rotate, hflip, vflip;
bool is_dirty;
bool is_drm;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
is_dirty = gsc->src_info.dirty || gsc->dst_info.dirty;
is_drm = gsc->src_info.mode_drm;
if (is_dirty && (gsc->src_info.mode_drm != gsc->dst_info.mode_drm)) {
ALOGE("%s: drm mode mismatch between src and dst, \
gsc%d (s=%d d=%d)", __func__, gsc->gsc_id,
gsc->src_info.mode_drm, gsc->dst_info.mode_drm);
return -1;
} else if (is_drm && !gsc->allow_drm) {
ALOGE("%s: drm mode is not supported on gsc%d", __func__,
gsc->gsc_id);
return -1;
}
CGscaler::rotateValueHAL2GSC(gsc->dst_img.rot, &rotate, &hflip, &vflip);
if (CGscaler::m_gsc_check_src_size(&gsc->src_info.width,
&gsc->src_info.height, &gsc->src_info.crop_left,
&gsc->src_info.crop_top, &gsc->src_info.crop_width,
&gsc->src_info.crop_height, gsc->src_info.v4l2_colorformat,
(rotate == 90 || rotate == 270)) == false) {
ALOGE("%s::m_gsc_check_src_size() fail", __func__);
return -1;
}
if (CGscaler::m_gsc_check_dst_size(&gsc->dst_info.width,
&gsc->dst_info.height, &gsc->dst_info.crop_left,
&gsc->dst_info.crop_top, &gsc->dst_info.crop_width,
&gsc->dst_info.crop_height, gsc->dst_info.v4l2_colorformat,
gsc->dst_info.rotation) == false) {
ALOGE("%s::m_gsc_check_dst_size() fail", __func__);
return -1;
}
/* dequeue buffers from previous work if necessary */
if (gsc->src_info.stream_on == true) {
if (gsc->m_gsc_m2m_wait_frame_done(handle) < 0) {
ALOGE("%s::exynos_gsc_m2m_wait_frame_done fail", __func__);
return -1;
}
}
/*
* need to set the content protection flag before doing reqbufs
* in set_format
*/
if (is_dirty && gsc->allow_drm && is_drm) {
if (exynos_v4l2_s_ctrl(gsc->gsc_fd,
V4L2_CID_CONTENT_PROTECTION, is_drm) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__);
return -1;
}
}
/*
* from this point on, we have to ensure to call stop to clean up
* whatever state we have set.
*/
if (gsc->src_info.dirty) {
if (CGscaler::m_gsc_set_format(gsc->gsc_fd, &gsc->src_info) == false) {
ALOGE("%s::m_gsc_set_format(src) fail", __func__);
goto done;
}
gsc->src_info.dirty = false;
}
if (gsc->dst_info.dirty) {
if (CGscaler::m_gsc_set_format(gsc->gsc_fd, &gsc->dst_info) == false) {
ALOGE("%s::m_gsc_set_format(dst) fail", __func__);
goto done;
}
gsc->dst_info.dirty = false;
}
/*
* set up csc equation property
*/
if (is_dirty) {
if (exynos_v4l2_s_ctrl(gsc->gsc_fd,
V4L2_CID_CSC_EQ_MODE, gsc->eq_auto) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ_MODE) fail", __func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->gsc_fd,
V4L2_CID_CSC_EQ, gsc->v4l2_colorspace) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ) fail", __func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->gsc_fd,
V4L2_CID_CSC_RANGE, gsc->range_full) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE) fail", __func__);
return -1;
}
}
/* if we are enabling drm, make sure to enable hw protection.
* Need to do this before queuing buffers so that the mmu is reserved
* and power domain is kept on.
*/
if (is_dirty && gsc->allow_drm && is_drm) {
/*
if (gsc->gsc_id == 0) {
protect_id = CP_PROTECT_GSC0;
} else if (gsc->gsc_id == 1) {
protect_id = CP_PROTECT_GSC1;
} else if (gsc->gsc_id == 2) {
protect_id = CP_PROTECT_GSC2;
} else if (gsc->gsc_id == 3) {
protect_id = CP_PROTECT_GSC3;
} else {
ALOGE("%s::invalid gscaler id %d for content protection",
__func__, gsc->gsc_id);
goto done;
}
*/
/* if (CP_Enable_Path_Protection(protect_id) != 0) {
ALOGE("%s::CP_Enable_Path_Protection failed", __func__);
goto done;
} */
gsc->protection_enabled = true;
}
if (gsc->m_gsc_set_addr(gsc->gsc_fd, &gsc->src_info) == false) {
ALOGE("%s::m_gsc_set_addr(src) fail", __func__);
goto done;
}
if (gsc->m_gsc_set_addr(gsc->gsc_fd, &gsc->dst_info) == false) {
ALOGE("%s::m_gsc_set_addr(dst) fail", __func__);
goto done;
}
if (gsc->src_info.stream_on == false) {
if (exynos_v4l2_streamon(gsc->gsc_fd, gsc->src_info.buf.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__);
goto done;
}
gsc->src_info.stream_on = true;
}
if (gsc->dst_info.stream_on == false) {
if (exynos_v4l2_streamon(gsc->gsc_fd, gsc->dst_info.buf.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__);
goto done;
}
gsc->dst_info.stream_on = true;
}
Exynos_gsc_Out();
return 0;
done:
gsc->m_gsc_m2m_stop(handle);
return -1;
}
bool CGscaler::m_gsc_check_src_size(
unsigned int *w, unsigned int *h,
unsigned int *crop_x, unsigned int *crop_y,
unsigned int *crop_w, unsigned int *crop_h,
int v4l2_colorformat, bool rotation)
{
unsigned int minWidth, minHeight, shift = 0;
if (v4l2_colorformat == V4L2_PIX_FMT_RGB32 || v4l2_colorformat == V4L2_PIX_FMT_RGB565)
shift = 1;
if (rotation) {
minWidth = GSC_MIN_SRC_H_SIZE >> shift;
minHeight = GSC_MIN_SRC_W_SIZE >> shift;
} else {
minWidth = GSC_MIN_SRC_W_SIZE >> shift;
minHeight = GSC_MIN_SRC_H_SIZE >> shift;
}
if (*w < minWidth || *h < minHeight) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, GSC_MIN_SRC_W_SIZE, *w, GSC_MIN_SRC_H_SIZE, *h);
return false;
}
if (*crop_w < minWidth || *crop_h < minHeight) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, GSC_MIN_SRC_W_SIZE,* crop_w, GSC_MIN_SRC_H_SIZE, *crop_h);
return false;
}
return true;
}
bool CGscaler::m_gsc_check_dst_size(
unsigned int *w, unsigned int *h,
unsigned int *crop_x, unsigned int *crop_y,
unsigned int *crop_w, unsigned int *crop_h,
int v4l2_colorformat,
int rotation)
{
if (*w < GSC_MIN_DST_W_SIZE || *h < GSC_MIN_DST_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, GSC_MIN_DST_W_SIZE, *w, GSC_MIN_DST_H_SIZE, *h);
return false;
}
if (*crop_w < GSC_MIN_DST_W_SIZE || *crop_h < GSC_MIN_DST_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, GSC_MIN_DST_W_SIZE,* crop_w, GSC_MIN_DST_H_SIZE, *crop_h);
return false;
}
return true;
}
int CGscaler::m_gsc_multiple_of_n(int number, int N)
{
int result = number;
switch (N) {
case 1:
case 2:
case 4:
case 8:
case 16:
case 32:
case 64:
case 128:
case 256:
result = (number - (number & (N-1)));
break;
default:
result = number - (number % N);
break;
}
return result;
}
int CGscaler::m_gsc_m2m_wait_frame_done(void *handle)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if ((gsc->src_info.stream_on == false) ||
(gsc->dst_info.stream_on == false)) {
ALOGE("%s:: src_strean_on or dst_stream_on are false", __func__);
return -1;
}
if (gsc->src_info.buf.buffer_queued) {
if (exynos_v4l2_dqbuf(gsc->gsc_fd, &gsc->src_info.buf.buffer) < 0) {
ALOGE("%s::exynos_v4l2_dqbuf(src) fail", __func__);
return -1;
}
gsc->src_info.buf.buffer_queued = false;
}
if (gsc->dst_info.buf.buffer_queued) {
if (exynos_v4l2_dqbuf(gsc->gsc_fd, &gsc->dst_info.buf.buffer) < 0) {
ALOGE("%s::exynos_v4l2_dqbuf(dst) fail", __func__);
return -1;
}
gsc->dst_info.buf.buffer_queued = false;
}
Exynos_gsc_Out();
return 0;
}
bool CGscaler::m_gsc_set_format(int fd, GscInfo *info)
{
Exynos_gsc_In();
struct v4l2_requestbuffers req_buf;
int plane_count;
plane_count = m_gsc_get_plane_count(info->v4l2_colorformat);
if (plane_count < 0) {
ALOGE("%s::not supported v4l2_colorformat", __func__);
return false;
}
if (exynos_v4l2_s_ctrl(fd, V4L2_CID_ROTATE, info->rotation) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_ROTATE) fail", __func__);
return false;
}
if (exynos_v4l2_s_ctrl(fd, V4L2_CID_VFLIP, info->flip_horizontal) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_VFLIP) fail", __func__);
return false;
}
if (exynos_v4l2_s_ctrl(fd, V4L2_CID_HFLIP, info->flip_vertical) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_HFLIP) fail", __func__);
return false;
}
info->format.type = info->buf.buf_type;
info->format.fmt.pix_mp.width = info->width;
info->format.fmt.pix_mp.height = info->height;
info->format.fmt.pix_mp.pixelformat = info->v4l2_colorformat;
info->format.fmt.pix_mp.field = V4L2_FIELD_ANY;
info->format.fmt.pix_mp.num_planes = plane_count;
if (exynos_v4l2_s_fmt(fd, &info->format) < 0) {
ALOGE("%s::exynos_v4l2_s_fmt() fail", __func__);
return false;
}
info->crop.type = info->buf.buf_type;
info->crop.c.left = info->crop_left;
info->crop.c.top = info->crop_top;
info->crop.c.width = info->crop_width;
info->crop.c.height = info->crop_height;
if (exynos_v4l2_s_crop(fd, &info->crop) < 0) {
ALOGE("%s::exynos_v4l2_s_crop() fail", __func__);
return false;
}
if (exynos_v4l2_s_ctrl(fd, V4L2_CID_CACHEABLE, info->cacheable) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl() fail", __func__);
return false;
}
req_buf.count = 1;
req_buf.type = info->buf.buf_type;
req_buf.memory = info->buf.mem_type;
if (exynos_v4l2_reqbufs(fd, &req_buf) < 0) {
ALOGE("%s::exynos_v4l2_reqbufs() fail", __func__);
return false;
}
Exynos_gsc_Out();
return true;
}
unsigned int CGscaler::m_gsc_get_plane_count(int v4l_pixel_format)
{
int plane_count = 0;
switch (v4l_pixel_format) {
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB444:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_YUV422P:
plane_count = 1;
break;
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV12MT_16X16:
case V4L2_PIX_FMT_NV21M:
plane_count = 2;
break;
case V4L2_PIX_FMT_YVU420M:
case V4L2_PIX_FMT_YUV420M:
plane_count = 3;
break;
default:
ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n",
__func__, v4l_pixel_format);
plane_count = -1;
break;
}
return plane_count;
}
bool CGscaler::m_gsc_set_addr(int fd, GscInfo *info)
{
unsigned int i;
unsigned int plane_size[NUM_OF_GSC_PLANES];
CGscaler::m_gsc_get_plane_size(plane_size, info->width,
info->height, info->v4l2_colorformat);
info->buf.buffer.index = 0;
info->buf.buffer.flags = V4L2_BUF_FLAG_USE_SYNC;
info->buf.buffer.type = info->buf.buf_type;
info->buf.buffer.memory = info->buf.mem_type;
info->buf.buffer.m.planes = info->buf.planes;
info->buf.buffer.length = info->format.fmt.pix_mp.num_planes;
info->buf.buffer.reserved = info->acquireFenceFd;
for (i = 0; i < info->format.fmt.pix_mp.num_planes; i++) {
if (info->buf.buffer.memory == V4L2_MEMORY_DMABUF)
info->buf.buffer.m.planes[i].m.fd = (long)info->buf.addr[i];
else
info->buf.buffer.m.planes[i].m.userptr =
(unsigned long)info->buf.addr[i];
info->buf.buffer.m.planes[i].length = plane_size[i];
info->buf.buffer.m.planes[i].bytesused = 0;
}
if (exynos_v4l2_qbuf(fd, &info->buf.buffer) < 0) {
ALOGE("%s::exynos_v4l2_qbuf() fail", __func__);
return false;
}
info->buf.buffer_queued = true;
info->releaseFenceFd = info->buf.buffer.reserved;
return true;
}
unsigned int CGscaler::m_gsc_get_plane_size(
unsigned int *plane_size,
unsigned int width,
unsigned int height,
int v4l_pixel_format)
{
switch (v4l_pixel_format) {
/* 1 plane */
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
plane_size[0] = width * height * 4;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_RGB24:
plane_size[0] = width * height * 3;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB444:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
plane_size[0] = width * height * 2;
plane_size[1] = 0;
plane_size[2] = 0;
break;
/* 2 planes */
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV21M:
plane_size[0] = width * height;
plane_size[1] = width * (height / 2);
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
plane_size[0] = width * height * 3 / 2;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_YUV422P:
plane_size[0] = width * height * 2;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_NV12MT_16X16:
plane_size[0] = ALIGN(width, 16) * ALIGN(height, 16);
plane_size[1] = ALIGN(width, 16) * ALIGN(height / 2, 8);
plane_size[2] = 0;
break;
/* 3 planes */
case V4L2_PIX_FMT_YUV420M:
plane_size[0] = width * height;
plane_size[1] = (width / 2) * (height / 2);
plane_size[2] = (width / 2) * (height / 2);
break;
case V4L2_PIX_FMT_YVU420:
plane_size[0] = ALIGN(width, 16) * height + ALIGN(width / 2, 16) * height;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_YUV420:
plane_size[0] = width * height * 3 / 2;
plane_size[1] = 0;
plane_size[2] = 0;
break;
case V4L2_PIX_FMT_YVU420M:
plane_size[0] = ALIGN(width, 16) * height;
plane_size[1] = ALIGN(width / 2, 16) * (height / 2);
plane_size[2] = plane_size[1];
break;
default:
ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)\n",
__func__, v4l_pixel_format);
return -1;
}
return 0;
}
int CGscaler::m_gsc_m2m_config(void *handle,
exynos_mpp_img *src_img, exynos_mpp_img *dst_img)
{
Exynos_gsc_In();
int32_t src_color_space;
int32_t dst_color_space;
int ret;
unsigned int rotate;
unsigned int hflip;
unsigned int vflip;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if ((src_img->drmMode && !gsc->allow_drm) ||
(src_img->drmMode != dst_img->drmMode)) {
ALOGE("%s::invalid drm state request for gsc%d (s=%d d=%d)",
__func__, gsc->gsc_id, src_img->drmMode, dst_img->drmMode);
return -1;
}
src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format);
dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format);
CGscaler::rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip);
exynos_gsc_set_rotation(gsc, rotate, hflip, vflip);
ret = exynos_gsc_set_src_format(gsc, src_img->fw, src_img->fh,
src_img->x, src_img->y, src_img->w, src_img->h,
src_color_space, src_img->cacheable, src_img->drmMode);
if (ret < 0) {
ALOGE("%s: fail: exynos_gsc_set_src_format \
[fw %d fh %d x %d y %d w %d h %d f %x rot %d]",
__func__, src_img->fw, src_img->fh, src_img->x, src_img->y,
src_img->w, src_img->h, src_color_space, src_img->rot);
return -1;
}
ret = exynos_gsc_set_dst_format(gsc, dst_img->fw, dst_img->fh,
dst_img->x, dst_img->y, dst_img->w, dst_img->h,
dst_color_space, dst_img->cacheable, dst_img->drmMode);
if (ret < 0) {
ALOGE("%s: fail: exynos_gsc_set_dst_format \
[fw %d fh %d x %d y %d w %d h %d f %x rot %d]",
__func__, dst_img->fw, dst_img->fh, dst_img->x, dst_img->y,
dst_img->w, dst_img->h, src_color_space, dst_img->rot);
return -1;
}
Exynos_gsc_Out();
return 0;
}
int CGscaler::m_gsc_out_config(void *handle,
exynos_mpp_img *src_img, exynos_mpp_img *dst_img)
{
Exynos_gsc_In();
struct v4l2_format fmt;
struct v4l2_crop crop;
struct v4l2_requestbuffers reqbuf;
struct v4l2_subdev_format sd_fmt;
struct v4l2_subdev_crop sd_crop;
unsigned int rotate;
unsigned int hflip;
unsigned int vflip;
bool rgb;
int32_t src_color_space;
int32_t dst_color_space;
int32_t src_planes;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
if (gsc->src_info.stream_on != false) {
ALOGE("Error: Src is already streamed on !!!!");
return -1;
}
memcpy(&gsc->src_img, src_img, sizeof(exynos_mpp_img));
memcpy(&gsc->dst_img, dst_img, sizeof(exynos_mpp_img));
src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format);
dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format);
src_planes = m_gsc_get_plane_count(src_color_space);
src_planes = (src_planes == -1) ? 1 : src_planes;
rgb = get_yuv_planes(dst_color_space) == -1;
CGscaler::rotateValueHAL2GSC(dst_img->rot, &rotate, &hflip, &vflip);
if (CGscaler::m_gsc_check_src_size(&gsc->src_img.fw,
&gsc->src_img.fh, &gsc->src_img.x, &gsc->src_img.y,
&gsc->src_img.w, &gsc->src_img.h, src_color_space,
(rotate == 90 || rotate == 270)) == false) {
ALOGE("%s::m_gsc_check_src_size() fail", __func__);
return -1;
}
/*set: src v4l2_buffer*/
gsc->src_info.buf.buf_idx = 0;
gsc->src_info.qbuf_cnt = 0;
/* set format: src pad of GSC sub-dev*/
sd_fmt.pad = GSCALER_SUBDEV_PAD_SOURCE;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
if (gsc->out_mode == GSC_OUT_FIMD) {
sd_fmt.format.width = gsc->dst_img.fw;
sd_fmt.format.height = gsc->dst_img.fh;
} else {
sd_fmt.format.width = gsc->dst_img.w;
sd_fmt.format.height = gsc->dst_img.h;
}
sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_RGB666_1X18 :
V4L2_MBUS_FMT_YDYUYDYV8_1X16;
if (exynos_subdev_s_fmt(gsc->mdev.gsc_sd_entity->fd, &sd_fmt) < 0) {
ALOGE("%s::GSC subdev set format failed", __func__);
return -1;
}
/* set crop: src crop of GSC sub-dev*/
sd_crop.pad = GSCALER_SUBDEV_PAD_SOURCE;
sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
if (gsc->out_mode == GSC_OUT_FIMD) {
sd_crop.rect.left = gsc->dst_img.x;
sd_crop.rect.top = gsc->dst_img.y;
sd_crop.rect.width = gsc->dst_img.w;
sd_crop.rect.height = gsc->dst_img.h;
} else {
sd_crop.rect.left = 0;
sd_crop.rect.top = 0;
sd_crop.rect.width = gsc->dst_img.w;
sd_crop.rect.height = gsc->dst_img.h;
}
/* sink pad is connected to GSC out */
/* set format: sink sub-dev */
if (gsc->out_mode == GSC_OUT_FIMD) {
sd_fmt.pad = FIMD_SUBDEV_PAD_SINK;
sd_fmt.format.width = gsc->dst_img.w;
sd_fmt.format.height = gsc->dst_img.h;
} else {
sd_fmt.pad = MIXER_V_SUBDEV_PAD_SINK;
sd_fmt.format.width = gsc->dst_img.w + gsc->dst_img.x*2;
sd_fmt.format.height = gsc->dst_img.h + gsc->dst_img.y*2;
}
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.format.code = rgb ? V4L2_MBUS_FMT_RGB666_1X18 :
V4L2_MBUS_FMT_YDYUYDYV8_1X16;
if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) {
ALOGE("%s::sink:set format failed (PAD=%d)", __func__,
sd_fmt.pad);
return -1;
}
/* set crop: sink sub-dev */
if (gsc->out_mode == GSC_OUT_FIMD)
sd_crop.pad = FIMD_SUBDEV_PAD_SINK;
else
sd_crop.pad = MIXER_V_SUBDEV_PAD_SINK;
sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
if (gsc->out_mode == GSC_OUT_FIMD) {
sd_crop.rect.left = gsc->dst_img.x;
sd_crop.rect.top = gsc->dst_img.y;
sd_crop.rect.width = gsc->dst_img.w;
sd_crop.rect.height = gsc->dst_img.h;
} else {
sd_crop.rect.left = 0;
sd_crop.rect.top = 0;
sd_crop.rect.width = gsc->dst_img.w;
sd_crop.rect.height = gsc->dst_img.h;
}
if (gsc->out_mode != GSC_OUT_FIMD) {
sd_fmt.pad = MIXER_V_SUBDEV_PAD_SOURCE;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.format.width = gsc->dst_img.w + gsc->dst_img.x*2;
sd_fmt.format.height = gsc->dst_img.h + gsc->dst_img.y*2;
sd_fmt.format.code = V4L2_MBUS_FMT_RGB666_1X18;
if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) {
ALOGE("%s::sink:set format failed (PAD=%d)", __func__,
sd_fmt.pad);
return -1;
}
sd_fmt.pad = MIXER_V_SUBDEV_PAD_SOURCE;
sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_crop.rect.left = gsc->dst_img.x;
sd_crop.rect.top = gsc->dst_img.y;
sd_crop.rect.width = gsc->dst_img.w;
sd_crop.rect.height = gsc->dst_img.h;
if (exynos_subdev_s_crop(gsc->mdev.sink_sd_entity->fd, &sd_crop) < 0) {
ALOGE("%s::sink: subdev set crop failed(PAD=%d)", __func__,
sd_crop.pad);
return -1;
}
}
/*set GSC ctrls */
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_ROTATE,
rotate) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_ROTATE: %d) failed",
__func__, rotate);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_HFLIP,
vflip) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_HFLIP: %d) failed",
__func__, vflip);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_VFLIP,
hflip) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_VFLIP: %d) failed",
__func__, hflip);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CACHEABLE, 1) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_CACHEABLE: 1) failed",
__func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CONTENT_PROTECTION, gsc->src_img.drmMode) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail",
__func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CSC_EQ_MODE, gsc->eq_auto) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ_MODE) fail", __func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CSC_EQ, gsc->v4l2_colorspace) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_EQ) fail", __func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CSC_RANGE, gsc->range_full) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE) fail", __func__);
return -1;
}
/* set src format :GSC video dev*/
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
fmt.fmt.pix_mp.width = gsc->src_img.fw;
fmt.fmt.pix_mp.height = gsc->src_img.fh;
fmt.fmt.pix_mp.pixelformat = src_color_space;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
fmt.fmt.pix_mp.num_planes = src_planes;
if (exynos_v4l2_s_fmt(gsc->mdev.gsc_vd_entity->fd, &fmt) < 0) {
ALOGE("%s::videodev set format failed", __func__);
return -1;
}
/* set src crop info :GSC video dev*/
crop.type = fmt.type;
crop.c.left = gsc->src_img.x;
crop.c.top = gsc->src_img.y;
crop.c.width = gsc->src_img.w;
crop.c.height = gsc->src_img.h;
if (exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop) < 0) {
ALOGE("%s::videodev set crop failed", __func__);
return -1;
}
reqbuf.type = fmt.type;
reqbuf.memory = V4L2_MEMORY_DMABUF;
reqbuf.count = MAX_BUFFERS_GSCALER_OUT;
if (exynos_v4l2_reqbufs(gsc->mdev.gsc_vd_entity->fd, &reqbuf) < 0) {
ALOGE("%s::request buffers failed", __func__);
return -1;
}
Exynos_gsc_Out();
return 0;
}
int CGscaler::m_gsc_cap_config(void *handle,
exynos_mpp_img *src_img, exynos_mpp_img *dst_img)
{
Exynos_gsc_In();
struct v4l2_format fmt;
struct v4l2_crop crop;
struct v4l2_requestbuffers reqbuf;
struct v4l2_subdev_format sd_fmt;
struct v4l2_subdev_crop sd_crop;
unsigned int rotate;
unsigned int hflip;
unsigned int vflip;
int32_t src_color_space;
int32_t dst_color_space;
int32_t dst_planes;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
memcpy(&gsc->src_img, src_img, sizeof(exynos_mpp_img));
memcpy(&gsc->dst_img, dst_img, sizeof(exynos_mpp_img));
src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(src_img->format);
dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(dst_img->format);
dst_planes = m_gsc_get_plane_count(dst_color_space);
dst_planes = (dst_planes == -1) ? 1 : dst_planes;
CGscaler::rotateValueHAL2GSC(src_img->rot, &rotate, &hflip, &vflip);
if (CGscaler::m_gsc_check_src_size(&gsc->src_img.fw,
&gsc->src_img.fh, &gsc->src_img.x, &gsc->src_img.y,
&gsc->src_img.w, &gsc->src_img.h, src_color_space,
(rotate == 90 || rotate == 270)) == false) {
ALOGE("%s::m_gsc_check_src_size() fail", __func__);
return -1;
}
/*set GSC ctrls */
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_ROTATE,
rotate) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_ROTATE: %d) failed",
__func__, rotate);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_HFLIP,
vflip) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_HFLIP: %d) failed",
__func__, vflip);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd, V4L2_CID_VFLIP,
hflip) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_VFLIP: %d) failed",
__func__, hflip);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CACHEABLE, 1) < 0) {
ALOGE("%s:: exynos_v4l2_s_ctrl (V4L2_CID_CACHEABLE: 1) failed",
__func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CONTENT_PROTECTION, gsc->src_img.drmMode) < 0) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CONTENT_PROTECTION) fail",
__func__);
return -1;
}
if (exynos_v4l2_s_ctrl(gsc->mdev.gsc_vd_entity->fd,
V4L2_CID_CSC_RANGE, gsc->range_full)) {
ALOGE("%s::exynos_v4l2_s_ctrl(V4L2_CID_CSC_RANGE: %d) fail",
__func__, gsc->range_full);
return -1;
}
/* set format: source pad of Decon-TV sub-dev*/
sd_fmt.pad = DECON_TV_WB_PAD;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.format.width = gsc->src_img.w;
sd_fmt.format.height = gsc->src_img.h;
sd_fmt.format.code = WB_PATH_FORMAT;
if (exynos_subdev_s_fmt(gsc->mdev.sink_sd_entity->fd, &sd_fmt) < 0) {
ALOGE("%s::Decon-TV subdev set format failed", __func__);
return -1;
}
if (!gsc->dst_info.stream_on) {
/* set src format: GSC video dev*/
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = gsc->dst_img.fw;
fmt.fmt.pix_mp.height = gsc->dst_img.fh;
fmt.fmt.pix_mp.pixelformat = dst_color_space;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
fmt.fmt.pix_mp.num_planes = dst_planes;
if (exynos_v4l2_s_fmt(gsc->mdev.gsc_vd_entity->fd, &fmt) < 0) {
ALOGE("%s::videodev set format failed", __func__);
return -1;
}
gsc->dst_info.buf.buf_idx = 0;
gsc->dst_info.qbuf_cnt = 0;
}
/* set format: sink pad of GSC sub-dev*/
sd_fmt.pad = GSCALER_SUBDEV_PAD_SINK;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.format.width = gsc->src_img.w;
sd_fmt.format.height = gsc->src_img.h;
sd_fmt.format.code = WB_PATH_FORMAT;
if (exynos_subdev_s_fmt(gsc->mdev.gsc_sd_entity->fd, &sd_fmt) < 0) {
ALOGE("%s::GSC subdev set format failed", __func__);
return -1;
}
/* set src crop info :GSC video dev*/
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
crop.c.left = gsc->dst_img.x;
crop.c.top = gsc->dst_img.y;
crop.c.width = gsc->dst_img.w;
crop.c.height = gsc->dst_img.h;
if (exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop) < 0) {
ALOGE("%s::videodev set crop failed", __func__);
return -1;
}
/* set crop: src crop of GSC sub-dev*/
sd_crop.pad = GSCALER_SUBDEV_PAD_SINK;
sd_crop.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_crop.rect.left = 0;
sd_crop.rect.top = 0;
sd_crop.rect.width = gsc->src_img.w;
sd_crop.rect.height = gsc->src_img.h;
if (exynos_subdev_s_crop(gsc->mdev.gsc_sd_entity->fd, &sd_crop) < 0) {
ALOGE("%s::GSC subdev set crop failed(PAD=%d)", __func__,
sd_crop.pad);
return -1;
}
reqbuf.type = fmt.type;
reqbuf.memory = V4L2_MEMORY_DMABUF;
reqbuf.count = MAX_BUFFERS_GSCALER_CAP;
if (!gsc->dst_info.stream_on) {
if (exynos_v4l2_reqbufs(gsc->mdev.gsc_vd_entity->fd, &reqbuf) < 0) {
ALOGE("%s::request buffers failed", __func__);
return -1;
}
}
Exynos_gsc_Out();
return 0;
}
void CGscaler::rotateValueHAL2GSC(unsigned int transform,
unsigned int *rotate, unsigned int *hflip, unsigned int *vflip)
{
int rotate_flag = transform & 0x7;
*rotate = 0;
*hflip = 0;
*vflip = 0;
switch (rotate_flag) {
case HAL_TRANSFORM_ROT_90:
*rotate = 90;
break;
case HAL_TRANSFORM_ROT_180:
*rotate = 180;
break;
case HAL_TRANSFORM_ROT_270:
*rotate = 270;
break;
case HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90:
*rotate = 90;
*vflip = 1; /* set vflip to compensate the rot & flip order. */
break;
case HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90:
*rotate = 90;
*hflip = 1; /* set hflip to compensate the rot & flip order. */
break;
case HAL_TRANSFORM_FLIP_H:
*hflip = 1;
break;
case HAL_TRANSFORM_FLIP_V:
*vflip = 1;
break;
default:
break;
}
}
int CGscaler::m_gsc_m2m_run(void *handle,
exynos_mpp_img *src_img, exynos_mpp_img *dst_img)
{
Exynos_gsc_In();
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
void *addr[3] = {NULL, NULL, NULL};
int ret = 0;
addr[0] = (void *)src_img->yaddr;
addr[1] = (void *)src_img->uaddr;
addr[2] = (void *)src_img->vaddr;
ret = exynos_gsc_set_src_addr(handle, addr, src_img->mem_type,
src_img->acquireFenceFd);
if (ret < 0) {
ALOGE("%s::fail: exynos_gsc_set_src_addr[%p %p %p]", __func__,
addr[0], addr[1], addr[2]);
return -1;
}
addr[0] = (void *)dst_img->yaddr;
addr[1] = (void *)dst_img->uaddr;
addr[2] = (void *)dst_img->vaddr;
ret = exynos_gsc_set_dst_addr(handle, addr, dst_img->mem_type,
dst_img->acquireFenceFd);
if (ret < 0) {
ALOGE("%s::fail: exynos_gsc_set_dst_addr[%p %p %p]", __func__,
addr[0], addr[1], addr[2]);
return -1;
}
ret = gsc->m_gsc_m2m_run_core(handle);
if (ret < 0) {
ALOGE("%s::fail: m_gsc_m2m_run_core", __func__);
return -1;
}
if (src_img->acquireFenceFd >= 0) {
close(src_img->acquireFenceFd);
src_img->acquireFenceFd = -1;
}
if (dst_img->acquireFenceFd >= 0) {
close(dst_img->acquireFenceFd);
dst_img->acquireFenceFd = -1;
}
src_img->releaseFenceFd = gsc->src_info.releaseFenceFd;
dst_img->releaseFenceFd = gsc->dst_info.releaseFenceFd;
Exynos_gsc_Out();
return 0;
}
int CGscaler::m_gsc_out_run(void *handle, exynos_mpp_img *src_img)
{
struct v4l2_plane planes[NUM_OF_GSC_PLANES];
struct v4l2_buffer buf;
int32_t src_color_space;
int32_t src_planes;
unsigned int i;
unsigned int plane_size[NUM_OF_GSC_PLANES];
int ret = 0;
unsigned int dq_retry_cnt = 0;
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
/* All buffers have been queued, dequeue one */
if (gsc->src_info.qbuf_cnt == MAX_BUFFERS_GSCALER_OUT) {
memset(&buf, 0, sizeof(struct v4l2_buffer));
for (i = 0; i < NUM_OF_GSC_PLANES; i++)
memset(&planes[i], 0, sizeof(struct v4l2_plane));
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.m.planes = planes;
src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->src_img.format);
src_planes = m_gsc_get_plane_count(src_color_space);
src_planes = (src_planes == -1) ? 1 : src_planes;
buf.length = src_planes;
do {
ret = exynos_v4l2_dqbuf(gsc->mdev.gsc_vd_entity->fd, &buf);
if (ret == -EAGAIN) {
ALOGE("%s::Retry DQbuf(index=%d)", __func__, buf.index);
usleep(10000);
dq_retry_cnt++;
continue;
}
break;
} while (dq_retry_cnt <= 10);
if (ret < 0) {
ALOGE("%s::dq buffer failed (index=%d)", __func__, buf.index);
return -1;
}
gsc->src_info.qbuf_cnt--;
}
memset(&buf, 0, sizeof(struct v4l2_buffer));
for (i = 0; i < NUM_OF_GSC_PLANES; i++)
memset(&planes[i], 0, sizeof(struct v4l2_plane));
src_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->src_img.format);
src_planes = m_gsc_get_plane_count(src_color_space);
src_planes = (src_planes == -1) ? 1 : src_planes;
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.flags = 0;
buf.length = src_planes;
buf.index = gsc->src_info.buf.buf_idx;
buf.m.planes = planes;
buf.reserved = -1;
gsc->src_info.buf.addr[0] = (void*)src_img->yaddr;
gsc->src_info.buf.addr[1] = (void*)src_img->uaddr;
gsc->src_info.buf.addr[2] = (void*)src_img->vaddr;
if (CGscaler::tmp_get_plane_size(src_color_space, plane_size,
gsc->src_img.fw, gsc->src_img.fh, src_planes) != true) {
ALOGE("%s:get_plane_size:fail", __func__);
return -1;
}
for (i = 0; i < buf.length; i++) {
buf.m.planes[i].m.fd = (long)gsc->src_info.buf.addr[i];
buf.m.planes[i].length = plane_size[i];
buf.m.planes[i].bytesused = plane_size[i];
}
/* Queue the buf */
if (exynos_v4l2_qbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) {
ALOGE("%s::queue buffer failed (index=%d)(mSrcBufNum=%d)",
__func__, gsc->src_info.buf.buf_idx,
MAX_BUFFERS_GSCALER_OUT);
return -1;
}
gsc->src_info.buf.buf_idx++;
gsc->src_info.buf.buf_idx =
gsc->src_info.buf.buf_idx % MAX_BUFFERS_GSCALER_OUT;
gsc->src_info.qbuf_cnt++;
if (gsc->src_info.stream_on == false) {
if (exynos_v4l2_streamon(gsc->mdev.gsc_vd_entity->fd,
(v4l2_buf_type)buf.type) < 0) {
ALOGE("%s::stream on failed", __func__);
return -1;
}
gsc->src_info.stream_on = true;
}
return 0;
}
int CGscaler::m_gsc_cap_run(void *handle, exynos_mpp_img *dst_img)
{
struct v4l2_plane planes[NUM_OF_GSC_PLANES];
struct v4l2_buffer buf;
int32_t dst_color_space;
int32_t dst_planes;
unsigned int i;
unsigned int plane_size[NUM_OF_GSC_PLANES];
CGscaler* gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
/* All buffers have been queued, dequeue one */
if (gsc->dst_info.qbuf_cnt == MAX_BUFFERS_GSCALER_CAP) {
memset(&buf, 0, sizeof(struct v4l2_buffer));
for (i = 0; i < NUM_OF_GSC_PLANES; i++)
memset(&planes[i], 0, sizeof(struct v4l2_plane));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.m.planes = planes;
dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->dst_img.format);
dst_planes = m_gsc_get_plane_count(dst_color_space);
dst_planes = (dst_planes == -1) ? 1 : dst_planes;
buf.length = dst_planes;
if (exynos_v4l2_dqbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) {
ALOGE("%s::dequeue buffer failed (index=%d)(mSrcBufNum=%d)",
__func__, gsc->src_info.buf.buf_idx,
MAX_BUFFERS_GSCALER_CAP);
return -1;
}
gsc->dst_info.qbuf_cnt--;
}
memset(&buf, 0, sizeof(struct v4l2_buffer));
for (i = 0; i < NUM_OF_GSC_PLANES; i++)
memset(&planes[i], 0, sizeof(struct v4l2_plane));
dst_color_space = HAL_PIXEL_FORMAT_2_V4L2_PIX(gsc->dst_img.format);
dst_planes = m_gsc_get_plane_count(dst_color_space);
dst_planes = (dst_planes == -1) ? 1 : dst_planes;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.flags = V4L2_BUF_FLAG_USE_SYNC;
buf.length = dst_planes;
buf.index = gsc->dst_info.buf.buf_idx;
buf.m.planes = planes;
buf.reserved = dst_img->acquireFenceFd;
gsc->dst_info.buf.addr[0] = (void*)dst_img->yaddr;
gsc->dst_info.buf.addr[1] = (void*)dst_img->uaddr;
gsc->dst_info.buf.addr[2] = (void*)dst_img->vaddr;
if (CGscaler::tmp_get_plane_size(dst_color_space, plane_size,
gsc->dst_img.fw, gsc->dst_img.fh, dst_planes) != true) {
ALOGE("%s:get_plane_size:fail", __func__);
return -1;
}
for (i = 0; i < buf.length; i++) {
buf.m.planes[i].m.fd = (int)(long)gsc->dst_info.buf.addr[i];
buf.m.planes[i].length = plane_size[i];
buf.m.planes[i].bytesused = plane_size[i];
}
/* Queue the buf */
if (exynos_v4l2_qbuf(gsc->mdev.gsc_vd_entity->fd, &buf) < 0) {
ALOGE("%s::queue buffer failed (index=%d)(mDstBufNum=%d)",
__func__, gsc->dst_info.buf.buf_idx,
MAX_BUFFERS_GSCALER_CAP);
return -1;
}
gsc->dst_info.buf.buf_idx++;
gsc->dst_info.buf.buf_idx =
gsc->dst_info.buf.buf_idx % MAX_BUFFERS_GSCALER_CAP;
gsc->dst_info.qbuf_cnt++;
if (gsc->dst_info.stream_on == false) {
if (exynos_v4l2_streamon(gsc->mdev.gsc_vd_entity->fd,
(v4l2_buf_type)buf.type) < 0) {
ALOGE("%s::stream on failed", __func__);
return -1;
}
gsc->dst_info.stream_on = true;
}
dst_img->releaseFenceFd = buf.reserved;
return 0;
}
bool CGscaler::tmp_get_plane_size(int V4L2_PIX,
unsigned int * size, unsigned int width, unsigned int height, int src_planes)
{
unsigned int frame_ratio = 1;
int src_bpp = get_yuv_bpp(V4L2_PIX);
unsigned int frame_size = width * height;
src_planes = (src_planes == -1) ? 1 : src_planes;
frame_ratio = 8 * (src_planes -1) / (src_bpp - 8);
switch (src_planes) {
case 1:
switch (V4L2_PIX) {
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB32:
size[0] = frame_size << 2;
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YVYU:
size[0] = frame_size << 1;
break;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV21M:
size[0] = (frame_size * 3) >> 1;
break;
case V4L2_PIX_FMT_YVU420:
size[0] = frame_size + (ALIGN((width >> 1), 16) * ((height >> 1) * 2));
break;
default:
ALOGE("%s::invalid color type (%x)", __func__, V4L2_PIX);
return false;
break;
}
size[1] = 0;
size[2] = 0;
break;
case 2:
size[0] = frame_size;
size[1] = frame_size / frame_ratio;
size[2] = 0;
break;
case 3:
size[0] = frame_size;
size[1] = frame_size / frame_ratio;
size[2] = frame_size / frame_ratio;
break;
default:
ALOGE("%s::invalid color foarmt", __func__);
return false;
break;
}
return true;
}
int CGscaler::ConfigMpp(void *handle, exynos_mpp_img *src,
exynos_mpp_img *dst)
{
return exynos_gsc_config_exclusive(handle, src, dst);
}
int CGscaler::ConfigBlendMpp(void *handle, exynos_mpp_img *src,
exynos_mpp_img *dst,
SrcBlendInfo *srcblendinfo)
{
return exynos_gsc_config_blend_exclusive(handle, src, dst, srcblendinfo);
}
int CGscaler::RunMpp(void *handle, exynos_mpp_img *src,
exynos_mpp_img *dst)
{
return exynos_gsc_run_exclusive(handle, src, dst);
}
int CGscaler::StopMpp(void *handle)
{
return exynos_gsc_stop_exclusive(handle);
}
void CGscaler::DestroyMpp(void *handle)
{
return exynos_gsc_destroy(handle);
}
int CGscaler::SetCSCProperty(void *handle, unsigned int eqAuto,
unsigned int fullRange, unsigned int colorspace)
{
return exynos_gsc_set_csc_property(handle, eqAuto, fullRange,
colorspace);
}
int CGscaler::FreeMpp(void *handle)
{
return exynos_gsc_free_and_close(handle);
}
int CGscaler::SetInputCrop(void *handle,
exynos_mpp_img *src_img, exynos_mpp_img *dst_img)
{
struct v4l2_crop crop;
CGscaler *gsc = GetGscaler(handle);
if (gsc == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
crop.c.left = src_img->x;
crop.c.top = src_img->y;
crop.c.width = src_img->w;
crop.c.height = src_img->h;
return exynos_v4l2_s_crop(gsc->mdev.gsc_vd_entity->fd, &crop);
}