/*
* Copyright (C) 2008 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 exynos_rotator.c
* \brief source file for exynos_rotator HAL
* \author Sunmi Lee (carrotsm.lee@samsung.com)
* \date 2012/03/05
*
* <b>Revision History: </b>
* - 2012/03/05 : Sunmi Lee (carrotsm.lee@samsung.com) \n
* Create
*
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "libexynosrotator"
#include <cutils/log.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <videodev2.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "exynos_rotator.h"
#include "exynos_format.h"
#include "ExynosMutex.h"
#include "exynos_v4l2.h"
#define NUM_OF_ROTATOR_PLANES (3)
#define NODE_NUM_ROTATOR (21)
#define PFX_NODE_ROTATOR "/dev/video"
#define ROTATOR_MIN_W_SIZE (8)
#define ROTATOR_MIN_H_SIZE (8)
#define MAX_ROTATOR_WAITING_TIME_FOR_TRYLOCK (16000) // 16msec
#define ROTATOR_WAITING_TIME_FOR_TRYLOCK (8000) // 8msec
struct rotator_info {
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;
int rotation;
void *addr[NUM_OF_ROTATOR_PLANES];
bool stream_on;
enum v4l2_buf_type buf_type;
struct v4l2_format format;
struct v4l2_buffer buffer;
struct v4l2_plane planes[NUM_OF_ROTATOR_PLANES];
struct v4l2_crop crop;
};
struct ROTATOR_HANDLE {
int rotator_fd;
struct rotator_info src;
struct rotator_info dst;
void *op_mutex;
void *obj_mutex;
void *cur_obj_mutex;
};
static unsigned int m_rotator_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:
plane_count = 1;
break;
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV12MT_16X16:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
plane_count = 2;
break;
case V4L2_PIX_FMT_YVU420M:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
plane_count = 3;
break;
default:
ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)",
__func__, v4l_pixel_format);
plane_count = -1;
break;
}
return plane_count;
}
static unsigned int m_rotator_get_plane_size(
unsigned int *plane_size,
unsigned int width,
unsigned int height,
int v4l_pixel_format)
{
switch (v4l_pixel_format) {
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_BGR32:
plane_size[0] = width * height * 4;
break;
case V4L2_PIX_FMT_RGB24:
plane_size[0] = width * height * 3;
break;
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB444:
plane_size[0] = width * height * 2;
break;
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
plane_size[0] = width * height;
plane_size[1] = width * (height / 2);
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);
break;
case V4L2_PIX_FMT_YVU420M:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
plane_size[0] = width * height;
plane_size[1] = (width / 2) * (height / 2);
plane_size[2] = (width / 2) * (height / 2);
break;
default:
ALOGE("%s::unmatched v4l_pixel_format color_space(0x%x)",
__func__, v4l_pixel_format);
return -1;
break;
}
return 0;
}
static int m_exynos_rotator_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;
}
static bool m_exynos_rotator_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)
{
if (*w < ROTATOR_MIN_W_SIZE || *h < ROTATOR_MIN_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, ROTATOR_MIN_W_SIZE, *w, ROTATOR_MIN_H_SIZE, *h);
return false;
}
if (*crop_w < ROTATOR_MIN_W_SIZE || *crop_h < ROTATOR_MIN_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, ROTATOR_MIN_W_SIZE,* crop_w, ROTATOR_MIN_H_SIZE, *crop_h);
return false;
}
switch (v4l2_colorformat) {
// YUV420 3p
case V4L2_PIX_FMT_YUV420M:
case V4L2_PIX_FMT_YVU420M:
*w = ALIGN(*w, 16);
*h = ALIGN(*h, 16);
break;
// YUV420 2p
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV12MT:
case V4L2_PIX_FMT_NV21M:
*w = ALIGN(*w, 8);
*h = ALIGN(*h, 8);
break;
// YUV422
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
// RGB
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB444:
default:
*w = ALIGN(*w, 4);
*h = ALIGN(*h, 4);
break;
}
*crop_w = m_exynos_rotator_multiple_of_n(*crop_w, 4);
*crop_h = m_exynos_rotator_multiple_of_n(*crop_h, 4);
return true;
}
static bool m_exynos_rotator_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)
{
unsigned int *new_w;
unsigned int *new_h;
unsigned int *new_crop_w;
unsigned int *new_crop_h;
if (rotation == 90 || rotation == 270) {
new_w = h;
new_h = w;
new_crop_w = crop_h;
new_crop_h = crop_w;
} else {
new_w = w;
new_h = h;
new_crop_w = crop_w;
new_crop_h = crop_h;
}
if (*w < ROTATOR_MIN_W_SIZE || *h < ROTATOR_MIN_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, ROTATOR_MIN_W_SIZE, *w, ROTATOR_MIN_H_SIZE, *h);
return false;
}
if (*crop_w < ROTATOR_MIN_W_SIZE || *crop_h < ROTATOR_MIN_H_SIZE) {
ALOGE("%s::too small size (w : %d < %d) (h : %d < %d)",
__func__, ROTATOR_MIN_W_SIZE,* crop_w, ROTATOR_MIN_H_SIZE, *crop_h);
return false;
}
switch (v4l2_colorformat) {
// YUV420 3p
case V4L2_PIX_FMT_YUV420M:
case V4L2_PIX_FMT_YVU420M:
*new_w = ALIGN(*new_w, 16);
*new_h = ALIGN(*new_h, 16);
break;
// YUV420 2p
case V4L2_PIX_FMT_NV12M:
case V4L2_PIX_FMT_NV12MT:
case V4L2_PIX_FMT_NV21M:
*new_w = ALIGN(*new_w, 8);
*new_h = ALIGN(*new_h, 8);
break;
// YUV422
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YUV422P:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
// RGB
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_RGB555X:
case V4L2_PIX_FMT_RGB444:
default:
*new_w = ALIGN(*new_w, 4);
*new_h = ALIGN(*new_h, 4);
break;
}
*new_crop_w = m_exynos_rotator_multiple_of_n(*new_crop_w, 4);
*new_crop_h = m_exynos_rotator_multiple_of_n(*new_crop_h, 4);
return true;
}
static int m_exynos_rotator_create(void)
{
int fd = 0;
unsigned int cap;
char node[32];
sprintf(node, "%s%d", PFX_NODE_ROTATOR, NODE_NUM_ROTATOR);
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__);
if (0 < fd)
close(fd);
fd = 0;
return -1;
}
return fd;
}
static bool m_exynos_rotator_destroy(
struct ROTATOR_HANDLE *rotator_handle)
{
if (rotator_handle->src.stream_on == true) {
if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0)
ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
rotator_handle->src.stream_on = false;
}
if (rotator_handle->dst.stream_on == true) {
if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0)
ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
rotator_handle->dst.stream_on = false;
}
if (0 < rotator_handle->rotator_fd)
close(rotator_handle->rotator_fd);
rotator_handle->rotator_fd = 0;
return true;
}
bool m_exynos_rotator_find_and_trylock_and_create(
struct ROTATOR_HANDLE *rotator_handle)
{
int i = 0;
bool flag_find_new_rotator = false;
unsigned int total_sleep_time = 0;
do {
if (exynos_mutex_trylock(rotator_handle->obj_mutex) == true) {
// destroy old one.
m_exynos_rotator_destroy(rotator_handle);
// create new one.
rotator_handle->rotator_fd = m_exynos_rotator_create();
if (rotator_handle->rotator_fd < 0) {
rotator_handle->rotator_fd = 0;
exynos_mutex_unlock(rotator_handle->obj_mutex);
continue;
}
if (rotator_handle->cur_obj_mutex)
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
rotator_handle->cur_obj_mutex = rotator_handle->obj_mutex;
flag_find_new_rotator = true;
break;
}
// waiting for another process doesn't use rotator.
// we need to make decision how to do.
if (flag_find_new_rotator == false) {
usleep(ROTATOR_WAITING_TIME_FOR_TRYLOCK);
total_sleep_time += ROTATOR_WAITING_TIME_FOR_TRYLOCK;
ALOGV("%s::waiting for anthere process doens't use rotator", __func__);
}
} while( flag_find_new_rotator == false
&& total_sleep_time < MAX_ROTATOR_WAITING_TIME_FOR_TRYLOCK);
if (flag_find_new_rotator == false)
ALOGE("%s::we don't have no available rotator.. fail", __func__);
return flag_find_new_rotator;
}
static bool m_exynos_rotator_set_format(
int fd,
struct rotator_info *info,
bool force)
{
struct v4l2_requestbuffers req_buf;
int plane_count;
plane_count = m_rotator_get_plane_count(info->v4l2_colorformat);
if (plane_count < 0) {
ALOGE("%s::not supported v4l2_colorformat", __func__);
return false;
}
if (force == false) {
// format
info->format.type = info->buf_type;
if (exynos_v4l2_g_fmt(fd, &info->format) < 0) {
ALOGE("%s::exynos_v4l2_g_fmt() fail type=%d", __func__, info->buf_type);
return false;
}
if (info->width != info->format.fmt.pix_mp.width ||
info->height != info->format.fmt.pix_mp.height ||
info->v4l2_colorformat != info->format.fmt.pix_mp.pixelformat) {
ALOGV("%s::info is different..)", __func__);
goto set_hw;
}
// crop
if (info->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
info->crop.type = info->buf_type;
if (exynos_v4l2_g_crop(fd, &info->crop) < 0) {
ALOGE("%s::exynos_v4l2_g_crop() fail", __func__);
return false;
}
if (info->crop_left != info->crop.c.left ||
info->crop_top != info->crop.c.top ||
info->crop_width != info->crop.c.width ||
info->crop_height != info->crop.c.height) {
ALOGV("%s::crop is different..", __func__);
goto set_hw;
}
}
// rotation value;
int value = 0;
if (exynos_v4l2_g_ctrl(fd, V4L2_CID_ROTATE, &value) < 0) {
ALOGE("%s::exynos_v4l2_g_ctrl(V4L2_CID_ROTATE) fail");
return false;
}
if (info->rotation != value) {
ALOGV("%s::rotation is different..", __func__);
goto set_hw;
}
// skip s_fmt
ALOGV("%s::fmt, crop is same with old-one, so skip s_fmt crop..", __func__);
return true;
}
set_hw:
if (info->stream_on == true) {
if (exynos_v4l2_streamoff(fd, info->buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamoff() fail", __func__);
return false;
}
info->stream_on = 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;
}
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;
}
if (info->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
info->crop.type = info->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_type;
req_buf.memory = V4L2_MEMORY_USERPTR;
if (exynos_v4l2_reqbufs(fd, &req_buf) < 0) {
ALOGE("%s::exynos_v4l2_reqbufs() fail", __func__);
return false;
}
return true;
}
static bool m_exynos_rotator_set_addr(
int fd,
struct rotator_info *info)
{
unsigned int i;
unsigned int plane_size[NUM_OF_ROTATOR_PLANES];
m_rotator_get_plane_size(plane_size,
info->width,
info->height,
info->v4l2_colorformat);
info->buffer.index = 0;
info->buffer.type = info->buf_type;
info->buffer.memory = V4L2_MEMORY_USERPTR;
info->buffer.m.planes = info->planes;
info->buffer.length = info->format.fmt.pix_mp.num_planes;
for (i = 0; i < info->format.fmt.pix_mp.num_planes; i++) {
info->buffer.m.planes[i].m.userptr = (unsigned long)info->addr[i];
info->buffer.m.planes[i].length = plane_size[i];
info->buffer.m.planes[i].bytesused = 0;
}
if (exynos_v4l2_qbuf(fd, &info->buffer) < 0) {
ALOGE("%s::exynos_v4l2_qbuf() fail", __func__);
return false;
}
return true;
}
void *exynos_rotator_create(void)
{
int i = 0;
int op_id = 0;
char mutex_name[32];
struct ROTATOR_HANDLE *rotator_handle = (struct ROTATOR_HANDLE *)malloc(sizeof(struct ROTATOR_HANDLE));
if (rotator_handle == NULL) {
ALOGE("%s::malloc(struct ROTATOR_HANDLE) fail", __func__);
goto err;
}
rotator_handle->rotator_fd = 0;
memset(&rotator_handle->src, 0, sizeof(struct rotator_info));
memset(&rotator_handle->dst, 0, sizeof(struct rotator_info));
rotator_handle->src.buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
rotator_handle->dst.buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
rotator_handle->op_mutex = NULL;
rotator_handle->obj_mutex = NULL;
rotator_handle->cur_obj_mutex = NULL;
srand(time(NULL));
op_id = rand() % 1000000; // just make random id
sprintf(mutex_name, "%sOp%d", LOG_TAG, op_id);
rotator_handle->op_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_PRIVATE, mutex_name);
if (rotator_handle->op_mutex == NULL) {
ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name);
goto err;
}
exynos_mutex_lock(rotator_handle->op_mutex);
sprintf(mutex_name, "%sObject%d", LOG_TAG, i);
rotator_handle->obj_mutex = exynos_mutex_create(EXYNOS_MUTEX_TYPE_SHARED, mutex_name);
if (rotator_handle->obj_mutex == NULL) {
ALOGE("%s::exynos_mutex_create(%s) fail", __func__, mutex_name);
goto err;
}
if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
goto err;
}
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
exynos_mutex_unlock(rotator_handle->op_mutex);
return (void *)rotator_handle;
err:
if (rotator_handle) {
m_exynos_rotator_destroy(rotator_handle);
if (rotator_handle->cur_obj_mutex)
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
if ((rotator_handle->obj_mutex != NULL) &&
(exynos_mutex_get_created_status(rotator_handle->obj_mutex) == true)) {
if (exynos_mutex_destroy(rotator_handle->obj_mutex) == false)
ALOGE("%s::exynos_mutex_destroy() fail", __func__);
}
if (rotator_handle->op_mutex)
exynos_mutex_unlock(rotator_handle->op_mutex);
free(rotator_handle);
}
return NULL;
}
void exynos_rotator_destroy(
void *handle)
{
int i = 0;
struct ROTATOR_HANDLE *rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return;
}
exynos_mutex_lock(rotator_handle->op_mutex);
exynos_mutex_lock(rotator_handle->cur_obj_mutex);
m_exynos_rotator_destroy(rotator_handle);
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
if ((rotator_handle->obj_mutex != NULL) &&
(exynos_mutex_get_created_status(rotator_handle->obj_mutex) == true)) {
if (exynos_mutex_destroy(rotator_handle->obj_mutex) == false)
ALOGE("%s::exynos_mutex_destroy() fail", __func__);
}
exynos_mutex_unlock(rotator_handle->op_mutex);
if (rotator_handle)
free(rotator_handle);
}
int exynos_rotator_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)
{
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
rotator_handle->src.width = width;
rotator_handle->src.height = height;
rotator_handle->src.crop_left = crop_left;
rotator_handle->src.crop_top = crop_top;
rotator_handle->src.crop_width = crop_width;
rotator_handle->src.crop_height = crop_height;
rotator_handle->src.v4l2_colorformat = v4l2_colorformat;
rotator_handle->src.cacheable = cacheable;
exynos_mutex_unlock(rotator_handle->op_mutex);
return 0;
}
int exynos_rotator_set_dst_format(
void *handle,
unsigned int width,
unsigned int height,
unsigned int crop_left,
unsigned int crop_top,
unsigned int v4l2_colorformat,
unsigned int cacheable)
{
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
rotator_handle->dst.width = width;
rotator_handle->dst.height = height;
rotator_handle->dst.crop_left = crop_left;
rotator_handle->dst.crop_top = crop_top;
rotator_handle->dst.crop_width = rotator_handle->src.crop_width;
rotator_handle->dst.crop_height = rotator_handle->src.crop_height;
rotator_handle->dst.v4l2_colorformat = v4l2_colorformat;
rotator_handle->dst.cacheable = cacheable;
exynos_mutex_unlock(rotator_handle->op_mutex);
return 0;
}
int exynos_rotator_set_rotation(
void *handle,
int rotation)
{
int ret = -1;
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return ret;
}
exynos_mutex_lock(rotator_handle->op_mutex);
int new_rotation = rotation % 360;
if (new_rotation % 90 != 0) {
ALOGE("%s::rotation(%d) cannot be acceptable fail", __func__, rotation);
goto done;
}
if(new_rotation < 0)
new_rotation = -new_rotation;
rotator_handle->src.rotation = new_rotation;
rotator_handle->dst.rotation = new_rotation;
ret = 0;
done:
exynos_mutex_unlock(rotator_handle->op_mutex);
return ret;
}
int exynos_rotator_set_src_addr(
void *handle,
void *addr[3])
{
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
rotator_handle->src.addr[0] = addr[0];
rotator_handle->src.addr[1] = addr[1];
rotator_handle->src.addr[2] = addr[2];
exynos_mutex_unlock(rotator_handle->op_mutex);
return 0;
}
int exynos_rotator_set_dst_addr(
void *handle,
void *addr[3])
{
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
rotator_handle->dst.addr[0] = addr[0];
rotator_handle->dst.addr[1] = addr[1];
rotator_handle->dst.addr[2] = addr[2];
exynos_mutex_unlock(rotator_handle->op_mutex);
return 0;
}
int exynos_rotator_convert(
void *handle)
{
struct ROTATOR_HANDLE *rotator_handle;
int ret = -1;
int i = 0;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
char mutex_name[32];
bool flag_new_rotator = false;
exynos_mutex_lock(rotator_handle->op_mutex);
if (exynos_mutex_trylock(rotator_handle->cur_obj_mutex) == false) {
if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
goto done;
}
flag_new_rotator = true;
}
if (m_exynos_rotator_check_src_size(&rotator_handle->src.width, &rotator_handle->src.width,
&rotator_handle->src.crop_left, &rotator_handle->src.crop_top,
&rotator_handle->src.crop_width, &rotator_handle->src.crop_height,
rotator_handle->src.v4l2_colorformat) == false) {
ALOGE("%s::m_exynos_rotator_check_size(src) fail", __func__);
goto done;
}
if (m_exynos_rotator_check_dst_size(&rotator_handle->dst.width, &rotator_handle->dst.height,
&rotator_handle->dst.crop_left, &rotator_handle->dst.crop_top,
&rotator_handle->dst.crop_width, &rotator_handle->dst.crop_height,
rotator_handle->dst.v4l2_colorformat,
rotator_handle->dst.rotation) == false) {
ALOGE("%s::m_exynos_rotator_check_size(dst) fail", __func__);
goto done;
}
if (m_exynos_rotator_set_format(rotator_handle->rotator_fd, &rotator_handle->src, flag_new_rotator) == false) {
ALOGE("%s::m_exynos_rotator_set_format(src) fail", __func__);
goto done;
}
if (m_exynos_rotator_set_format(rotator_handle->rotator_fd, &rotator_handle->dst, flag_new_rotator) == false) {
ALOGE("%s::m_exynos_rotator_set_format(dst) fail", __func__);
goto done;
}
if (m_exynos_rotator_set_addr(rotator_handle->rotator_fd, &rotator_handle->src) == false) {
ALOGE("%s::m_exynos_rotator_set_addr(src) fail", __func__);
goto done;
}
if (m_exynos_rotator_set_addr(rotator_handle->rotator_fd, &rotator_handle->dst) == false) {
ALOGE("%s::m_exynos_rotator_set_addr(dst) fail", __func__);
goto done;
}
if (rotator_handle->src.stream_on == false) {
if (exynos_v4l2_streamon(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__);
goto done;
}
rotator_handle->src.stream_on = true;
}
if (rotator_handle->dst.stream_on == false) {
if (exynos_v4l2_streamon(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__);
goto done;
}
rotator_handle->dst.stream_on = true;
}
if (exynos_v4l2_dqbuf(rotator_handle->rotator_fd, &rotator_handle->src.buffer) < 0) {
ALOGE("%s::exynos_v4l2_dqbuf(src) fail", __func__);
goto done;
}
if (exynos_v4l2_dqbuf(rotator_handle->rotator_fd, &rotator_handle->dst.buffer) < 0) {
ALOGE("%s::exynos_v4l2_dqbuf(dst) fail", __func__);
goto done;
}
if (rotator_handle->src.stream_on == true) {
if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->src.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(src) fail", __func__);
goto done;
}
rotator_handle->src.stream_on = false;
}
if (rotator_handle->dst.stream_on == true) {
if (exynos_v4l2_streamoff(rotator_handle->rotator_fd, rotator_handle->dst.buf_type) < 0) {
ALOGE("%s::exynos_v4l2_streamon(dst) fail", __func__);
goto done;
}
rotator_handle->dst.stream_on = false;
}
ret = 0;
done:
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
exynos_mutex_unlock(rotator_handle->op_mutex);
return ret;
}
int exynos_rotator_connect(
void *handle,
void *hw)
{
struct ROTATOR_HANDLE *rotator_handle;
int ret = -1;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
if (exynos_mutex_trylock(rotator_handle->cur_obj_mutex) == false) {
if (m_exynos_rotator_find_and_trylock_and_create(rotator_handle) == false) {
ALOGE("%s::m_exynos_rotator_find_and_trylock_and_create() fail", __func__);
goto done;
}
}
ret = 0;
done:
exynos_mutex_unlock(rotator_handle->op_mutex);
return ret;
}
int exynos_rotator_disconnect(
void *handle,
void *hw)
{
struct ROTATOR_HANDLE *rotator_handle;
rotator_handle = (struct ROTATOR_HANDLE *)handle;
if (handle == NULL) {
ALOGE("%s::handle == NULL() fail", __func__);
return -1;
}
exynos_mutex_lock(rotator_handle->op_mutex);
exynos_mutex_unlock(rotator_handle->cur_obj_mutex);
exynos_mutex_unlock(rotator_handle->op_mutex);
return 0;
}