首先找到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; }
重新编译库和内核,下载,结果测试成功。
转载自:http://blog.csdn.net/hclydao/article/details/7735133