Camera1 源码解析系列—— Camera1 startPreview() 流程解析
Posted ByteSaid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Camera1 源码解析系列—— Camera1 startPreview() 流程解析相关的知识,希望对你有一定的参考价值。
前言
上一篇关于分析了 hw_get_module()
的调用逻辑,本篇通过追踪 Camera.startPreview()
方法,以加深对控制流的理解。
1 Frameworks
1.1 Camera.java
- 路径:
frameworks/base/core/java/android/hardware/Camera.java
startPreview()
:- 给上层
application
提供一个接口。 - 进入
Runtime
层。
- 给上层
/**
* Starts capturing and drawing preview frames to the screen.
* Preview will not actually start until a surface is supplied
* with @link #setPreviewDisplay(SurfaceHolder) or
* @link #setPreviewTexture(SurfaceTexture).
*
* <p>If @link #setPreviewCallback(Camera.PreviewCallback),
* @link #setOneShotPreviewCallback(Camera.PreviewCallback), or
* @link #setPreviewCallbackWithBuffer(Camera.PreviewCallback) were
* called, @link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)
* will be called when preview data becomes available.
*/
public native final void startPreview();
2 Android Runtime
2.1 android_hardware_Camera.cpp
- 路径:
frameworks/base/core/jni/android_hardware_Camera.cpp
android_hardware_Camera_startPreview()
:- 调用
get_native_camera()
函数获取一个Camera
实例。 - 调用
Camera::startPreview()
。
- 调用
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
ALOGV("startPreview");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;
if (camera->startPreview() != NO_ERROR)
jniThrowRuntimeException(env, "startPreview failed");
return;
get_native_camera()
:- 从
DVM
中获取关于Camera
的上下文。 - 从上下文信息中获取
Camera
实例。
- 从
sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
sp<Camera> camera;
Mutex::Autolock _l(sLock);
JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));
if (context != NULL)
camera = context->getCamera();
ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
if (camera == 0)
jniThrowRuntimeException(env,
"Camera is being used after Camera.release() was called");
if (pContext != NULL) *pContext = context;
return camera;
3 Libraries
3.1 Camera.cpp
- 路径:
frameworks/av/camera/Camera.cpp
startPreview()
:mCamera
即是在connect
过程中返回的CameraClient
,它具体实现了startPreview()
接口。- 调用
CameraClient::startPreview()
。
// start preview mode
status_t Camera::startPreview()
ALOGV("startPreview");
sp <::android::hardware::ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->startPreview();
3.2 CameraClient.cpp
- 路径:
frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp
startPreview()
:- 通过
startCameraMode
函数进入具体的实现逻辑。
- 通过
// start preview mode
status_t CameraClient::startPreview()
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
startCameraMode()
:- 根据传入的参数
CAMERA_PREVIEW_MODE
确定进入的分支。 - 调用
startPreviewMode()
。
- 根据传入的参数
// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode)
LOG1("startCameraMode(%d)", mode);
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
switch(mode)
case CAMERA_PREVIEW_MODE:
if (mSurface == 0 && mPreviewWindow == 0)
LOG1("mSurface is not set yet.");
// still able to start preview in this case.
return startPreviewMode();
case CAMERA_RECORDING_MODE:
if (mSurface == 0 && mPreviewWindow == 0)
ALOGE("mSurface or mPreviewWindow must be set before startRecordingMode.");
return INVALID_OPERATION;
return startRecordingMode();
default:
return UNKNOWN_ERROR;
startPreviewMode()
:- 如果预览已经存在,则直接返回成功信息。
- 如果未存在,则继续往下走。
mHardware
是CameraHardwareInterface
的实例,在connect
过程的最后被初始化。- 通过
mHardware
调用setPreviewWindow()
和startPreview()
接口。 - 进入
HAL
层。
status_t CameraClient::startPreviewMode()
LOG1("startPreviewMode");
status_t result = NO_ERROR;
// if preview has been enabled, nothing needs to be done
if (mHardware->previewEnabled())
return NO_ERROR;
if (mPreviewWindow != 0)
mHardware->setPreviewScalingMode(
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
mHardware->setPreviewTransform(mOrientation);
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
if (result == NO_ERROR)
mCameraService->updateProxyDeviceState(
ICameraServiceProxy::CAMERA_STATE_ACTIVE,
String8::format("%d", mCameraId));
return result;
4 HAL
4.1 CameraHardwareInterface.h
- 路径:
frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h
previewEnable()
:- 通过
mDevice->ops
继续向下调用(不是我们主要追踪的)。 mDevice
即是通过hw_get_module()
相关流程进行初始化的设备实例,它的类型是camera_device_t
。- 如果
preview
存在,则返回true
。
- 通过
/**
* Returns true if preview is enabled.
*/
int previewEnabled()
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->preview_enabled)
return mDevice->ops->preview_enabled(mDevice);
return false;
setPreviewWindow()
:- 如果
set_preview_window
函数指针为空,则返回失败信息。 - 若否,通过
mDevice->ops
继续向下调用(不是我们主要追踪的)。
- 如果
/** Set the ANativeWindow to which preview frames are sent */
status_t setPreviewWindow(const sp<ANativeWindow>& buf)
ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());
if (mDevice->ops->set_preview_window)
mPreviewWindow = buf;
if (buf != nullptr)
if (mPreviewScalingMode != NOT_SET)
setPreviewScalingMode(mPreviewScalingMode);
if (mPreviewTransform != NOT_SET)
setPreviewTransform(mPreviewTransform);
mHalPreviewWindow.user = this;
ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,
&mHalPreviewWindow, mHalPreviewWindow.user);
return mDevice->ops->set_preview_window(mDevice,
buf.get() ? &mHalPreviewWindow.nw : 0);
return INVALID_OPERATION;
startPreview()
:- 若
start_preview()
函数指针为空,则返回失败信息。 - 若否,则通过
mDevice
进行下一步操作。 - 关于
mDevice
,我们结合Camera.open()
流程与hw_get_module()
相关逻辑,可以知道它的逻辑是这样的:- 在
CameraService
启动时,会调用onFirstRef()
对module
进行初始化,获取module
实例。 - 在
open
过程中,CameraClient
连接CameraServer
成功时,会实例化CameraHardwareInterface
,并传入module
实例对其初始化。 - 在初始化过程中,通过
module
实例对应的open
方法,我们获得一个device
实例,即mDevice
,这对应了具体的摄像头设备。 - 通过
mDevice
,我们就可以将对应的指令传达到硬件设备。
- 在
- 通过对
camera_device_t
类型进行追踪,可以找到函数指针的一个具体指向。
- 若
/**
* Start preview mode.
*/
status_t startPreview()
ALOGV("%s(%s)", __FUNCTION__, mName.string());
if (mDevice->ops->start_preview)
return mDevice->ops->start_preview(mDevice);
return INVALID_OPERATION;
4.2 camera.h
- 路径:
hardware/libhardware/include/hardware/camera.h
struct camera_device
:- 这里就声明了我们想要追踪的
camera_device_t
。 ops
对应的类型是camera_device_ops_t
,这个结构中声明了函数指针。
- 这里就声明了我们想要追踪的
typedef struct camera_device
/**
* camera_device.common.version must be in the range
* HARDWARE_DEVICE_API_VERSION(0,0)-(1,FF). CAMERA_DEVICE_API_VERSION_1_0 is
* recommended.
*/
hw_device_t common;
camera_device_ops_t *ops;
void *priv;
camera_device_t;
struct camera_device_ops
:- 可以看到,所有关于
Camera
设备的操作,对应的函数指针都在这里声明了。但是看不出函数指针具体指向哪里。 - 在
Linux
下用find . -name "*.cpp" | xargs grep "start_preview ="
可以找到一些对应的文件,这些文件所处的路径与具体的设备商有关。 - 在这些文件中,就确定了函数指针的指向。
- 可以看到,所有关于
typedef struct camera_device_ops
int (*set_preview_window)(struct camera_device *,
struct preview_stream_ops *window);
void (*set_callbacks)(struct camera_device *,
camera_notify_callback notify_cb,
camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory,
void *user);
void (*enable_msg_type)(struct camera_device *, int32_t msg_type);
void (*disable_msg_type)(struct camera_device *, int32_t msg_type);
int (*msg_type_enabled)(struct camera_device *, int32_t msg_type);
/**
* Start preview mode.
*/
int (*start_preview)(struct camera_device *);
void (*stop_preview)(struct camera_device *);
int (*preview_enabled)(struct camera_device *);
int (*store_meta_data_in_buffers)(struct camera_device *, int enable);
int (*start_recording)(struct camera_device *);
void (*stop_recording)(struct camera_device *);
int (*recording_enabled)(struct camera_device *);
void (*release_recording_frame)(struct camera_device *,
const void *opaque);
int (*auto_focus)(struct camera_device *);
int (*cancel_auto_focus)(struct camera_device *);
int (*take_picture)(struct camera_device *);
int (*cancel_picture)(struct camera_device *);
int (*set_parameters)(struct camera_device *, const char *parms);
char *(*get_parameters)(struct camera_device *);
void (*put_parameters)(struct camera_device *, char *);
int (*send_command)(struct camera_device *,
int32_t cmd, int32_t arg1, int32_t arg2);
void (*release)(struct camera_device *);
int (*dump)(struct camera_device *, int fd);
camera_device_ops_t;
4.3 hardware/ti/omap4-aah/camera
通过 find
指令,找到了一些与函数指针指向有关的文件。从这些文件的路径上看,它们与不同的设备供应商有关。下面去 ti/omap4-aah
子文件夹去一探究竟。
4.3.1 CameraHal_Module.cpp
- 路径:
hardware/ti/omap4-aah/camera/CameraHal_Module.cpp
camera_device_open()
:- 在
open
流程中,就指定了ops
中指针的对应关系。
- 在
memset(camera_device, 0, sizeof(*camera_device));
memset(camera_ops, 0, sizeof(*camera_ops));
camera_device->base.common.tag = HARDWARE_DEVICE_TAG;
camera_device->base.common.version = 0;
camera_device->base.common.module = (hw_module_t *)(module);
camera_device->base.common.close = camera_device_close;
camera_device->base.ops = camera_ops;
camera_ops->set_preview_window = camera_set_preview_window;
camera_ops->set_callbacks = camera_set_callbacks;
camera_ops->enable_msg_type = camera_enable_msg_type;
camera_ops->disable_msg_type = camera_disable_msg_type;
camera_ops->msg_type_enabled = camera_msg_type_enabled;
camera_ops->start_preview = camera_start_preview;
camera_ops->stop_preview = camera_stop_preview;
camera_ops->preview_enabled = camera_preview_enabled;
camera_ops->store_meta_data_in_buffers = camera_store_meta_data_in_buffers;
camera_ops->start_recording = camera_start_recording;
camera_ops->stop_recording = camera_stop_recording;
camera_ops->recording_enabled = camera_recording_enabled;
camera_ops->release_recording_frame = camera_release_recording_frame;
camera_ops->auto_focus = camera_auto_focus;
camera_ops->cancel_auto_focus = camera_cancel_auto_focus;
camera_ops->take_picture = camera_take_picture;
camera_ops->cancel_picture = camera_cancel_picture;
camera_ops->set_parameters = camera_set_parameters;
camera_ops->get_parameters = camera_get_parameters;
camera_ops->put_parameters = camera_put_parameters;
camera_ops->send_command = camera_send_command;
camera_ops->release = camera_release;
camera_ops->dump = camera_dump;
*device = &camera_device->base.common;
// -------- TI specific stuff --------
camera_device->cameraid = cameraid;
camera_start_preview()
:- 注意
gCameraHals
是CameraHal *
。 - 通过调用
CameraHal::startPreview()
完成业务逻辑。
- 注意
int camera_start_preview(struct camera_device * device)
CAMHAL_LOG_MODULE_FUNCTION_NAME;
int rv = -EINVAL;
ti_camera_device_t* ti_dev = NULL;
if(!device)
return rv;
ti_dev = (ti_camera_device_t*) device;
rv = gCameraHals[ti_dev->cameraid]->startPreview();
return rv;
4.3.2 CameraHal.cpp
- 路径:
hardware/ti/omap4-aah/camera/CameraHal.cpp
- 这个文件对应的功能是,将
Camera Hardware Interface
映射到V4L2
。 - 注意两个声明:
extern "C" CameraAdapter* OMXCameraAdapter_Factory(size_t);
extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t);
- 分别对应
OMX
与V4L
的适配器工厂,这里可能是将Adapter
模式与Factory
模式结合使用。
startPreview()
:- 源代码中带有大量注释,在这里我将其去掉,只关注调用逻辑。
- 首先调用了
cameraPreviewInitialization()
函数进行初始化。 - 通过
CameraAdapter
发送CAMERA_START_PREVIEW
指令,若成功执行,则完成流程。
status_t CameraHal::startPreview()
LOG_FUNCTION_NAME;
status_t ret = cameraPreviewInitialization();
if (!mPreviewInitializationDone) return ret;
mPreviewInitializationDone = false;
if(mDisplayAdapter.get() != NULL)
CAMHAL_LOGDA("Enabling display");
int width, height;
mParameters.getPreviewSize(&width, &height);
#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview);
#else
ret = mDisplayAdapter->enableDisplay(width, height, NULL);
#endif
if ( ret != NO_ERROR )
CAMHAL_LOGEA("Couldn't enable display");
CAMHAL_ASSERT_X(false,
"At this stage mCameraAdapter->mStateSwitchLock is still locked, "
"deadlock is guaranteed");
goto error;
CAMHAL_LOGDA("Starting CameraAdapter preview mode");
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW);
if(ret!=NO_ERROR)
CAMHAL_LOGEA("Couldn't start preview w/ CameraAdapter");
goto error;
CAMHAL_LOGDA("Started preview");
mPreviewEnabled = true;
mPreviewStartInProgress = false;
return ret;
error:
CAMHAL_LOGEA("Performing cleanup after error");
//Do all the cleanup
freePreviewBufs();
mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW);
if(mDisplayAdapter.get() != NULL)
mDisplayAdapter->disableDisplay(false);
mAppCallbackNotifier->stop();
mPreviewStartInProgress = false;
mPreviewEnabled = false;
LOG_FUNCTION_NAME_EXIT;
return ret;
cameraPreviewInitialization()
:- 这段代码比较长,但从注释看,它主要做三件事:
- 通过
Adapter
设置相关参数; - 申请
Buffers
空间; - 对
Buffers
进行相应设置以进行预览。
- 通过
- 了解了大体思路,再看看具体代码:
mCameraAdapter->setParameters()
:设置参数。allocPreviewBufs()
:申请Buffers
。desc
:注意到这个变量对应着CameraAdapter::BuffersDescriptor
,在申请Buffers
空间成功后,便对其进行相应的成员设以上是关于Camera1 源码解析系列—— Camera1 startPreview() 流程解析的主要内容,如果未能解决你的问题,请参考以下文章
Camera1 源码解析系列—— Camera1 startPreview() 流程解析
Camera1 源码解析系列—— Camera1 Open() 流程解析
Camera1 源码解析系列—— Camera1 takePicture() 流程解析
- 这段代码比较长,但从注释看,它主要做三件事: