现在的位置: 首页 > 综合 > 正文

android 为摄像头增加闪光灯(s5pv210)

2013年09月17日 ⁄ 综合 ⁄ 共 5099字 ⁄ 字号 评论关闭

昨天刚好闪光灯弄过来,今天简单的做下总结。大概的说下,具体我也没有深入研究,不过效果确实是有了。

首先找到android拍照的时候所执行的函数代码在:

packages/apps/Camera/src/com/android/camera/Camera.java

找到这个地方:

            mCameraDevice.setParameters(mParameters);
            mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
                    mPostViewPictureCallback, new JpegPictureCallback(loc));
            mPreviewing = false;

据我理解,这里就是拍照的时候所执行的,而这里应该是调用的camera库里的takepicture下面我们找到库文件:

device/samsung/proprietary/libcamera

库文件就在这里,下面我们进入SeccameraHWInterface.cpp文件查找takepicture如下:

status_t CameraHardwareSec::takePicture()
{
    LOGV("%s :", __func__);

    stopPreview();

    Mutex::Autolock lock(mStateLock);
    if (mCaptureInProgress) {
        LOGE("%s : capture already in progress", __func__);
        return INVALID_OPERATION;
    }

    if (mPictureThread->run("CameraPictureThread", PRIORITY_DEFAULT) != NO_ERROR) {
        LOGE("%s : couldn't run picture thread", __func__);
        return INVALID_OPERATION;
    }
    mCaptureInProgress = true;

    return NO_ERROR;
}

里面的mPictureThread->run就是拍照的东西了,具体我就不分析了。接下来我们找下闪光灯的接口

在SecCamera.h里你会发现下面三个函数接口:

    bool            getFlashSupport(void);
    int             setFlashMode(int flash_mode);
    int             getFlashMode(void);

其中setFlashMode即为设置闪光灯的接口,找到这个函数

在SecCamera.cpp里如下:

int SecCamera::setFlashMode(int flash_mode)
{
    LOGV("%s(flash_mode(%d))", __func__, flash_mode);

    if (flash_mode <= FLASH_MODE_BASE || FLASH_MODE_MAX <= flash_mode) {
        LOGE("ERR(%s):Invalid flash_mode (%d)", __func__, flash_mode);
        return -1;
    }

    if (m_params->flash_mode != flash_mode) {
        m_params->flash_mode = flash_mode;
        if (m_flag_camera_start) {
            if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FLASH_MODE, flash_mode) < 0) {
                LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FLASH_MODE", __func__);
                return -1;
            }
        }
    }
    return 0;
}

这里又会调用fimc_v4l2_s_ctrl函数代码如下:

static int fimc_v4l2_s_ctrl(int fp, unsigned int id, unsigned int value)
{
    struct v4l2_control ctrl;
    int ret;

    ctrl.id = id;
    ctrl.value = value;
    //LOGD("%s :--------------------------value is %d",__func__,value);//add dao
    ret = ioctl(fp, VIDIOC_S_CTRL, &ctrl);
    if (ret < 0) {
        LOGE("ERR(%s):VIDIOC_S_CTRL(id = %#x (%d), value = %d) failed ret = %d\n",
             __func__, id, id-V4L2_CID_PRIVATE_BASE, value, ret);

        return ret;
    }

    return ctrl.value;
}

在这里进行了ioctl下面我们到内核里面去看看。
在内核下面的drivers/media/video/v4l2-ioctl.c有如下代码:

	case VIDIOC_S_CTRL:
	{
		struct v4l2_control *p = arg;
		struct v4l2_ext_controls ctrls;
		struct v4l2_ext_control ctrl;

		if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
			break;

		dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);

		if (ops->vidioc_s_ctrl) {
			ret = ops->vidioc_s_ctrl(file, fh, p);
			break;
		}
		if (!ops->vidioc_s_ext_ctrls)
			break;

		ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
		ctrls.count = 1;
		ctrls.controls = &ctrl;
		ctrl.id = p->id;
		ctrl.value = p->value;
		if (check_ext_ctrls(&ctrls, 1))
			ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls);
		break;
	}

很快我就想到了摄像头驱动里有这样的设置:

代码在drivers/media/video/samsung/ficm/ov2640.c

static const struct v4l2_subdev_core_ops ov2640_core_ops = {
	.init = ov2640_init,	/* initializing API */
	.s_config = ov2640_s_config,	/* Fetch platform data */
	.queryctrl = ov2640_queryctrl,
	.querymenu = ov2640_querymenu,
	.g_ctrl = ov2640_g_ctrl,
	.s_ctrl = ov2640_s_ctrl,
};

这里有一个s_ctrl,事实证明确实是执行了ov2640_s_ctrl至于怎么调用过来的没有深入研究。

下面我们看到这个函数开始的部分

static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2640_state *state = to_state(sd);
	int err = 0;
	int value = ctrl->value;
	
	switch (ctrl->id) {

	case V4L2_CID_CAMERA_FLASH_MODE:
	case V4L2_CID_CAMERA_BRIGHTNESS:
		break;

第一个就是闪光灯的选项,文件系统里面设置闪光灯的就是传入的这个,可没作任何处理就直接跳出了。下面我在增加闪光灯驱动:

static int flash_ctrl(int mode)
{
	int err;

	err = gpio_request(S5PV210_GPD0(2), "GPD0"); //power
	if (err) {
		printk(KERN_ERR "failed to request GPD0 for "
				"flashlight power control\n");
		return err;
	}
	gpio_direction_output(S5PV210_GPD0(2), 1);

	err = gpio_request(S5PV210_GPD0(3), "GPD0"); //mode
	if (err) {
		printk(KERN_ERR "failed to request GPD0 for "
				"flashlight mode control\n");
		return err;
	}
	/*
		high is flash mode,low is torch mode
	*/
	switch(mode) {
		case FLASH_MODE_ON:
			gpio_direction_output(S5PV210_GPD0(3), 1);
			break;
		case FLASH_MODE_TORCH:
			gpio_direction_output(S5PV210_GPD0(3), 0);
			break;
		default:
			break;
	}
	mdelay(100);
	gpio_direction_output(S5PV210_GPD0(2), 0);

	gpio_free(S5PV210_GPD0(2));
	gpio_free(S5PV210_GPD0(3));
	return err;
}

电路我就不发出来了,流程搞清楚了,大家就好弄了。

修改ov2640_s_ctrl为:

	case V4L2_CID_CAMERA_FLASH_MODE:

		err = flash_ctrl(value);
		break;

只修改相关设置,其它的不变。现在接口已经全部写好,在看到文件系统里。
在拍照之前加上闪光灯设置,这个可以在库里设置也可以在app里设置,我直接在库里设置的,路径我就不在打了,前面的相关函数已经全部给出了,如下:

status_t CameraHardwareSec::takePicture()
{
    LOGV("%s :", __func__);

    stopPreview();

    Mutex::Autolock lock(mStateLock);
    if (mCaptureInProgress) {
        LOGE("%s : capture already in progress", __func__);
        return INVALID_OPERATION;
    }

    mSecCamera->setFlashMode(FLASH_MODE_ON);//add by dao

    if (mPictureThread->run("CameraPictureThread", PRIORITY_DEFAULT) != NO_ERROR) {
        LOGE("%s : couldn't run picture thread", __func__);
        return INVALID_OPERATION;
    }
    mCaptureInProgress = true;

    return NO_ERROR;
}

在拍照之前设置FlashMode为FLASH_MODE_ON模式,结果发现这样不行,搞了半天终于发现问题所在,直接把setFlashMode改为如下:

int SecCamera::setFlashMode(int flash_mode)
{
    LOGV("%s(flash_mode(%d))", __func__, flash_mode);

    fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FLASH_MODE, flash_mode);
/*
    if (flash_mode <= FLASH_MODE_BASE || FLASH_MODE_MAX <= flash_mode) {
        LOGE("ERR(%s):Invalid flash_mode (%d)", __func__, flash_mode);
        return -1;
    }

    if (m_params->flash_mode != flash_mode) {
        m_params->flash_mode = flash_mode;
        if (m_flag_camera_start) {
            if (fimc_v4l2_s_ctrl(m_cam_fd, V4L2_CID_CAMERA_FLASH_MODE, flash_mode) < 0) {
                LOGE("ERR(%s):Fail on V4L2_CID_CAMERA_FLASH_MODE", __func__);
                return -1;
            }
        }
    }
*/
    return 0;
}

重新编译库和内核,下载,结果测试成功。






抱歉!评论已关闭.