C++程序  |  859行  |  18.24 KB

/*
 * 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 <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_MINOR_MAX 63

//#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 minor, size, i = 0;

    Exynos_v4l2_In();

    do {
        if (i > VIDEODEV_MINOR_MAX)
            break;

        /* video device node */
        sprintf(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)) {
            minor = (int)((unsigned short)(s.st_rdev & 0x3f));
            ALOGD("try node: %s, minor: %d", filename, minor);
            /* open sysfs entry */
            sprintf(filename, "/sys/class/video4linux/video%d/name", minor);
            stream_fd = fopen(filename, "r");
            if (stream_fd == NULL) {
                ALOGE("failed to open sysfs entry for videodev");
                continue;   /* try next */
            }

            /* read sysfs entry for device name */
            size = (int)fgets(name, sizeof(name), stream_fd);
            fclose(stream_fd);

            /* check read size */
            if (size == 0) {
                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, minor);
                    found = true;
                }
            }
        }
    } while (found == false);

    if (found) {
        sprintf(filename, "/dev/video%d", minor);
        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);
    if (ret) {
        ALOGE("%s: no matching index founds", __func__);
        return false;
    }

    ALOGI("Name of input channel[%d] is %s", input.index, input.name);

    strcpy(input_name_buf, (const char *)input.name);

    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) {
        ALOGE("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_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;
}