blob: 0671f763db737003eea29e79d3fcd11f4d423854 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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_v4l2.c
* \brief source file for libv4l2
* \author Jinsung Yang (jsgood.yang@samsung.com)
* \author Sangwoo Park (sw5771.park@samsung.com)
* \date 2012/01/17
*
* <b>Revision History: </b>
* - 2012/01/17: Jinsung Yang (jsgood.yang@samsung.com) \n
* Initial version
*
*/
#include <stdio.h>
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include "exynos_v4l2.h"
//#define LOG_NDEBUG 0
#define LOG_TAG "libexynosv4l2"
#include <utils/Log.h>
#include "Exynos_log.h"
#define VIDEODEV_MAX 255
//#define EXYNOS_V4L2_TRACE 0
#ifdef EXYNOS_V4L2_TRACE
#define Exynos_v4l2_In() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s In , Line: %d", __FUNCTION__, __LINE__)
#define Exynos_v4l2_Out() Exynos_Log(EXYNOS_DEV_LOG_DEBUG, LOG_TAG, "%s Out , Line: %d", __FUNCTION__, __LINE__)
#else
#define Exynos_v4l2_In() ((void *)0)
#define Exynos_v4l2_Out() ((void *)0)
#endif
static bool __v4l2_check_buf_type(enum v4l2_buf_type type)
{
bool supported;
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
supported = true;
break;
default:
supported = (type >= V4L2_BUF_TYPE_PRIVATE) ? true : false;
break;
}
return supported;
}
static int __v4l2_open(const char *filename, int oflag, va_list ap)
{
mode_t mode = 0;
int fd;
if (oflag & O_CREAT)
mode = va_arg(ap, int);
fd = open(filename, oflag, mode);
return fd;
}
int exynos_v4l2_open(const char *filename, int oflag, ...)
{
va_list ap;
int fd;
Exynos_v4l2_In();
va_start(ap, oflag);
fd = __v4l2_open(filename, oflag, ap);
va_end(ap);
Exynos_v4l2_Out();
return fd;
}
int exynos_v4l2_open_devname(const char *devname, int oflag, ...)
{
bool found = false;
int fd = -1;
struct stat s;
va_list ap;
FILE *stream_fd;
char filename[64], name[64];
int i = 0;
Exynos_v4l2_In();
do {
if (i > VIDEODEV_MAX)
break;
/* video device node */
snprintf(filename, sizeof(filename), "/dev/video%d", i);
/* if the node is video device */
if ((lstat(filename, &s) == 0) && S_ISCHR(s.st_mode) &&
((int)((unsigned short)(s.st_rdev) >> 8) == 81)) {
ALOGD("try node: %s", filename);
/* open sysfs entry */
snprintf(filename, sizeof(filename), "/sys/class/video4linux/video%d/name", i);
if (S_ISLNK(s.st_mode)) {
ALOGE("symbolic link detected");
return -1;
}
stream_fd = fopen(filename, "r");
if (stream_fd == NULL) {
ALOGE("failed to open sysfs entry for videodev (%d - %s)", errno, strerror(errno));
i++;
continue; /* try next */
}
/* read sysfs entry for device name */
char *p = fgets(name, sizeof(name), stream_fd);
fclose(stream_fd);
/* check read size */
if (p == NULL) {
ALOGE("failed to read sysfs entry for videodev");
} else {
/* matched */
if (strncmp(name, devname, strlen(devname)) == 0) {
ALOGI("node found for device %s: /dev/video%d", devname, i);
found = true;
break;
}
}
}
i++;
} while (found == false);
if (found) {
snprintf(filename, sizeof(filename), "/dev/video%d", i);
va_start(ap, oflag);
fd = __v4l2_open(filename, oflag, ap);
va_end(ap);
if (fd > 0)
ALOGI("open video device %s", filename);
else
ALOGE("failed to open video device %s", filename);
} else {
ALOGE("no video device found");
}
Exynos_v4l2_Out();
return fd;
}
int exynos_v4l2_close(int fd)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0)
ALOGE("%s: invalid fd: %d", __func__, fd);
else
ret = close(fd);
Exynos_v4l2_Out();
return ret;
}
bool exynos_v4l2_enuminput(int fd, int index, char *input_name_buf)
{
int ret = -1;
struct v4l2_input input;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return NULL;
}
input.index = index;
ret = ioctl(fd, VIDIOC_ENUMINPUT, &input, 32);
if (ret) {
ALOGE("%s: no matching index founds", __func__);
return false;
}
ALOGI("Name of input channel[%d] is %s", input.index, input.name);
strncpy(input_name_buf, (const char *)input.name, 32);
Exynos_v4l2_Out();
return true;
}
int exynos_v4l2_s_input(int fd, int index)
{
int ret = -1;
struct v4l2_input input;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
input.index = index;
ret = ioctl(fd, VIDIOC_S_INPUT, &input);
if (ret){
ALOGE("failed to ioctl: VIDIOC_S_INPUT (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
bool exynos_v4l2_querycap(int fd, unsigned int need_caps)
{
struct v4l2_capability cap;
int ret;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return false;
}
if (!(need_caps & V4L2_CAP_VIDEO_CAPTURE) &&
!(need_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) &&
!(need_caps & V4L2_CAP_VIDEO_OUTPUT) &&
!(need_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) &&
!(need_caps & V4L2_CAP_VIDEO_OVERLAY)) {
ALOGE("%s: unsupported capabilities", __func__);
return false;
}
memset(&cap, 0, sizeof(cap));
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_QUERYCAP (%d - %s)", errno, strerror(errno));
return false;
}
if ((need_caps & cap.capabilities) != need_caps) {
ALOGE("%s: unsupported capabilities", __func__);
return false;
}
Exynos_v4l2_Out();
return true;
}
bool exynos_v4l2_enum_fmt(int fd, enum v4l2_buf_type type, unsigned int fmt)
{
struct v4l2_fmtdesc fmtdesc;
int found = 0;
Exynos_v4l2_In();
fmtdesc.type = type;
fmtdesc.index = 0;
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
if (fmtdesc.pixelformat == fmt) {
ALOGE("Passed fmt = %#x found pixel format[%d]: %s", fmt, fmtdesc.index, fmtdesc.description);
found = 1;
break;
}
fmtdesc.index++;
}
if (!found) {
ALOGE("%s: unsupported pixel format", __func__);
return false;
}
Exynos_v4l2_Out();
return true;
}
int exynos_v4l2_g_fmt(int fd, struct v4l2_format *fmt)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!fmt) {
ALOGE("%s: fmt is NULL", __func__);
return ret;
}
if (__v4l2_check_buf_type(fmt->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_G_FMT, fmt);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_G_FMT (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
static int __v4l2_s_fmt(int fd, unsigned int request, struct v4l2_format *fmt)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!fmt) {
ALOGE("%s: fmt is NULL", __func__);
return ret;
}
if (__v4l2_check_buf_type(fmt->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
} else {
ret = ioctl(fd, request, fmt);
if (ret) {
if (request == VIDIOC_TRY_FMT)
ALOGE("failed to ioctl: VIDIOC_TRY_FMT (%d - %s)", errno, strerror(errno));
else
ALOGE("failed to ioctl: VIDIOC_S_FMT (%d - %s)", errno, strerror(errno));
return ret;
}
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_try_fmt(int fd, struct v4l2_format *fmt)
{
return __v4l2_s_fmt(fd, VIDIOC_TRY_FMT, fmt);
}
int exynos_v4l2_s_fmt(int fd, struct v4l2_format *fmt)
{
return __v4l2_s_fmt(fd, VIDIOC_S_FMT, fmt);
}
int exynos_v4l2_reqbufs(int fd, struct v4l2_requestbuffers *req)
{
int ret = -1;
unsigned int count;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!req) {
ALOGE("%s: req is NULL", __func__);
return ret;
}
if ((req->memory != V4L2_MEMORY_MMAP) &&
(req->memory != V4L2_MEMORY_USERPTR) &&
(req->memory != V4L2_MEMORY_DMABUF)) {
ALOGE("%s: unsupported memory type", __func__);
return ret;
}
if (__v4l2_check_buf_type(req->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
count = req->count;
ret = ioctl(fd, VIDIOC_REQBUFS, req);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_REQBUFS (%d - %s)", ret, strerror(errno));
return ret;
}
if (count != req->count) {
ALOGW("number of buffers had been changed: %d => %d", count, req->count);
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_querybuf(int fd, struct v4l2_buffer *buf)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!buf) {
ALOGE("%s: buf is NULL", __func__);
return ret;
}
if ((buf->memory != V4L2_MEMORY_MMAP) &&
(buf->memory != V4L2_MEMORY_DMABUF)) {
ALOGE("%s: unsupported memory type", __func__);
return ret;
}
if (__v4l2_check_buf_type(buf->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_QUERYBUF, buf);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_QUERYBUF (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_qbuf(int fd, struct v4l2_buffer *buf)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!buf) {
ALOGE("%s: buf is NULL", __func__);
return ret;
}
if ((buf->memory != V4L2_MEMORY_MMAP) &&
(buf->memory != V4L2_MEMORY_USERPTR) &&
(buf->memory != V4L2_MEMORY_DMABUF)) {
ALOGE("%s: unsupported memory type", __func__);
return ret;
}
if (__v4l2_check_buf_type(buf->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_QBUF, buf);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_QBUF (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_dqbuf(int fd, struct v4l2_buffer *buf)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!buf) {
ALOGE("%s: buf is NULL", __func__);
return ret;
}
if ((buf->memory != V4L2_MEMORY_MMAP) &&
(buf->memory != V4L2_MEMORY_USERPTR) &&
(buf->memory != V4L2_MEMORY_DMABUF)) {
ALOGE("%s: unsupported memory type", __func__);
return ret;
}
if (__v4l2_check_buf_type(buf->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_DQBUF, buf);
if (ret) {
if (errno == EAGAIN)
return -errno;
ALOGW("failed to ioctl: VIDIOC_DQBUF (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_streamon(int fd, enum v4l2_buf_type type)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (__v4l2_check_buf_type(type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_STREAMON, &type);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_STREAMON (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_streamoff(int fd, enum v4l2_buf_type type)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (__v4l2_check_buf_type(type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_STREAMOFF (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_cropcap(int fd, struct v4l2_cropcap *crop)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!crop) {
ALOGE("%s: crop is NULL", __func__);
return ret;
}
if (__v4l2_check_buf_type(crop->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_CROPCAP, crop);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_CROPCAP (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_g_crop(int fd, struct v4l2_crop *crop)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!crop) {
ALOGE("%s: crop is NULL", __func__);
return ret;
}
if (__v4l2_check_buf_type(crop->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_G_CROP, crop);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_G_CROP (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_s_crop(int fd, struct v4l2_crop *crop)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (!crop) {
ALOGE("%s: crop is NULL", __func__);
return ret;
}
if (__v4l2_check_buf_type(crop->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_S_CROP, crop);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_S_CROP (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_g_ctrl(int fd, unsigned int id, int *value)
{
int ret = -1;
struct v4l2_control ctrl;
Exynos_v4l2_In();
ctrl.id = id;
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
ret = ioctl(fd, VIDIOC_G_CTRL, &ctrl);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_G_CTRL (%d - %s)", errno, strerror(errno));
return ret;
}
*value = ctrl.value;
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_s_ctrl(int fd, unsigned int id, int value)
{
int ret = -1;
struct v4l2_control ctrl;
Exynos_v4l2_In();
ctrl.id = id;
ctrl.value = value;
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
ret = ioctl(fd, VIDIOC_S_CTRL, &ctrl);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_S_CTRL (%d)", errno);
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_prepare(int fd, struct v4l2_buffer *arg)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
ret = ioctl(fd, VIDIOC_PREPARE_BUF, arg);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_PREPARE_BUF (%d)", errno);
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_g_parm(int fd, struct v4l2_streamparm *streamparm)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (__v4l2_check_buf_type(streamparm->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_G_PARM, streamparm);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_G_PARM (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_s_parm(int fd, struct v4l2_streamparm *streamparm)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (__v4l2_check_buf_type(streamparm->type) == false) {
ALOGE("%s: unsupported buffer type", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_S_PARM, streamparm);
if (ret) {
ALOGE("failed to ioctl: VIDIOC_S_PARM (%d - %s)", errno, strerror(errno));
return ret;
}
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_g_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (ctrl == NULL) {
ALOGE("%s: ctrl is NULL", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_G_EXT_CTRLS, ctrl);
if (ret)
ALOGE("failed to ioctl: VIDIOC_G_EXT_CTRLS (%d - %s)", errno, strerror(errno));
Exynos_v4l2_Out();
return ret;
}
int exynos_v4l2_s_ext_ctrl(int fd, struct v4l2_ext_controls *ctrl)
{
int ret = -1;
Exynos_v4l2_In();
if (fd < 0) {
ALOGE("%s: invalid fd: %d", __func__, fd);
return ret;
}
if (ctrl == NULL) {
ALOGE("%s: ctrl is NULL", __func__);
return ret;
}
ret = ioctl(fd, VIDIOC_S_EXT_CTRLS, ctrl);
if (ret)
ALOGE("failed to ioctl: VIDIOC_S_EXT_CTRLS (%d - %s)", errno, strerror(errno));
Exynos_v4l2_Out();
return ret;
}