简介
- 通过整理前几篇笔记,我已经对整个
Camera
的框架有比较清晰的认识,并且也已经渐渐摸清楚了整个控制流的逻辑。
- 这次,我打算通过追踪
Camera.startPreview()
方法,以加深对控制流的理解。同时尝试结合上一篇关于 module
的认识,将这个流程走到尽可能底部的位置。
Camera.startPreview() flow
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()
。
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
函数进入具体的实现逻辑。
status_t CameraClient::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}
startCameraMode()
:
- 根据传入的参数
CAMERA_PREVIEW_MODE
确定进入的分支。
- 调用
startPreviewMode()
。
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.");
}
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 (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
。
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
继续向下调用(不是我们主要追踪的)。
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
类型进行追踪,可以找到函数指针的一个具体指向。
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 {
hw_device_t common;
camera_device_ops_t *ops;
void *priv;
} camera_device_t;
struct camera_device_ops
:
- 由于注释过长,我把除了
start_preview
以外的注释都去掉了。
- 可以看到,所有关于
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);
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;
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");
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
空间成功后,便对其进行相应的成员设置。
mAppCallbackNotifier->start()
:开启回调通知。
mAppCallbackNotifier->startPreviewCallbacks()
:将 Buffers
对应到相应的回调函数中,以供上层 APP
获取预览所需的数据。
- NOTE:
- 代码中不断使用
mCameraAdapter->sendCommand()
来发送指令,并获取一些数据。
- 指令发送到对应的
Adapter
(如 V4L Adapter
),就会调用相应的函数进行处理。
status_t CameraHal::cameraPreviewInitialization()
{
status_t ret = NO_ERROR;
CameraAdapter::BuffersDescriptor desc;
CameraFrame frame;
unsigned int required_buffer_count;
unsigned int max_queueble_buffers;
#if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
gettimeofday(&mStartPreview, NULL);
#endif
LOG_FUNCTION_NAME;
if (mPreviewInitializationDone) {
return NO_ERROR;
}
if ( mPreviewEnabled ){
CAMHAL_LOGDA("Preview already running");
LOG_FUNCTION_NAME_EXIT;
return ALREADY_EXISTS;
}
if ( NULL != mCameraAdapter ) {
ret = mCameraAdapter->setParameters(mParameters);
}
if ((mPreviewStartInProgress == false) && (mDisplayPaused == false)){
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW,( int ) &frame);
if ( NO_ERROR != ret ){
CAMHAL_LOGEB("Error: CAMERA_QUERY_RESOLUTION_PREVIEW %d", ret);
return ret;
}
mPreviewWidth = frame.mWidth;
mPreviewHeight = frame.mHeight;
}
if(!mSetPreviewWindowCalled || (mDisplayAdapter.get() == NULL)){
CAMHAL_LOGD("Preview not started. Preview in progress flag set");
mPreviewStartInProgress = true;
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_SWITCH_TO_EXECUTING);
if ( NO_ERROR != ret ){
CAMHAL_LOGEB("Error: CAMERA_SWITCH_TO_EXECUTING %d", ret);
return ret;
}
return NO_ERROR;
}
if( (mDisplayAdapter.get() != NULL) && ( !mPreviewEnabled ) && ( mDisplayPaused ) )
{
CAMHAL_LOGDA("Preview is in paused state");
mDisplayPaused = false;
mPreviewEnabled = true;
if ( NO_ERROR == ret )
{
ret = mDisplayAdapter->pauseDisplay(mDisplayPaused);
if ( NO_ERROR != ret )
{
CAMHAL_LOGEB("Display adapter resume failed %x", ret);
}
}
if(mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
{
mAppCallbackNotifier->enableMsgType (CAMERA_MSG_PREVIEW_FRAME);
}
signalEndImageCapture();
return ret;
}
required_buffer_count = atoi(mCameraProperties->get(CameraProperties::REQUIRED_PREVIEW_BUFS));
ret = allocPreviewBufs(mPreviewWidth, mPreviewHeight, mParameters.getPreviewFormat(), required_buffer_count, max_queueble_buffers);
if ( NO_ERROR != ret )
{
CAMHAL_LOGEA("Couldn't allocate buffers for Preview");
goto error;
}
if ( mMeasurementEnabled )
{
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA,
( int ) &frame,
required_buffer_count);
if ( NO_ERROR != ret )
{
return ret;
}
ret = allocPreviewDataBufs(frame.mLength, required_buffer_count);
if ( NO_ERROR != ret ) {
CAMHAL_LOGEA("Couldn't allocate preview data buffers");
goto error;
}
if ( NO_ERROR == ret )
{
desc.mBuffers = mPreviewDataBuffers;
desc.mOffsets = mPreviewDataOffsets;
desc.mFd = mPreviewDataFd;
desc.mLength = mPreviewDataLength;
desc.mCount = ( size_t ) required_buffer_count;
desc.mMaxQueueable = (size_t) required_buffer_count;
mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA,
( int ) &desc);
}
}
desc.mBuffers = mPreviewBuffers;
desc.mOffsets = mPreviewOffsets;
desc.mFd = mPreviewFd;
desc.mLength = mPreviewLength;
desc.mCount = ( size_t ) required_buffer_count;
desc.mMaxQueueable = (size_t) max_queueble_buffers;
ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW,
( int ) &desc);
if ( NO_ERROR != ret )
{
CAMHAL_LOGEB("Failed to register preview buffers: 0x%x", ret);
freePreviewBufs();
return ret;
}
ret = mAppCallbackNotifier->start();
if( ALREADY_EXISTS == ret )
{
CAMHAL_LOGDA("AppCallbackNotifier already running");
ret = NO_ERROR;
}
else if ( NO_ERROR == ret ) {
CAMHAL_LOGDA("Started AppCallbackNotifier..");
mAppCallbackNotifier->setMeasurements(mMeasurementEnabled);
}
else
{
CAMHAL_LOGDA("Couldn't start AppCallbackNotifier");
goto error;
}
if (ret == NO_ERROR) mPreviewInitializationDone = true;
mAppCallbackNotifier->startPreviewCallbacks(mParameters, mPreviewBuffers, mPreviewOffsets, mPreviewFd, mPreviewLength, required_buffer_count);
return ret;
error:
CAMHAL_LOGEA("Performing cleanup after error");
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;
}
4.3.3 BaseCameraAdapter.cpp
- 位置:
hardware/ti/omap4-aah/camera/BaseCameraAdapter.cpp
- 注意到文件中定义的常量:
const LUT cameraCommandsUserToHAL[] = {
{ "CAMERA_START_PREVIEW", CameraAdapter::CAMERA_START_PREVIEW },
{ "CAMERA_STOP_PREVIEW", CameraAdapter::CAMERA_STOP_PREVIEW },
{ "CAMERA_START_VIDEO", CameraAdapter::CAMERA_START_VIDEO },
{ "CAMERA_STOP_VIDEO", CameraAdapter::CAMERA_STOP_VIDEO },
{ "CAMERA_START_IMAGE_CAPTURE", CameraAdapter::CAMERA_START_IMAGE_CAPTURE },
{ "CAMERA_STOP_IMAGE_CAPTURE", CameraAdapter::CAMERA_STOP_IMAGE_CAPTURE },
{ "CAMERA_PERFORM_AUTOFOCUS", CameraAdapter::CAMERA_PERFORM_AUTOFOCUS },
{ "CAMERA_CANCEL_AUTOFOCUS", CameraAdapter::CAMERA_CANCEL_AUTOFOCUS },
{ "CAMERA_PREVIEW_FLUSH_BUFFERS", CameraAdapter::CAMERA_PREVIEW_FLUSH_BUFFERS },
{ "CAMERA_START_SMOOTH_ZOOM", CameraAdapter::CAMERA_START_SMOOTH_ZOOM },
{ "CAMERA_STOP_SMOOTH_ZOOM", CameraAdapter::CAMERA_STOP_SMOOTH_ZOOM },
{ "CAMERA_USE_BUFFERS_PREVIEW", CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW },
{ "CAMERA_SET_TIMEOUT", CameraAdapter::CAMERA_SET_TIMEOUT },
{ "CAMERA_CANCEL_TIMEOUT", CameraAdapter::CAMERA_CANCEL_TIMEOUT },
{ "CAMERA_START_BRACKET_CAPTURE", CameraAdapter::CAMERA_START_BRACKET_CAPTURE },
{ "CAMERA_STOP_BRACKET_CAPTURE", CameraAdapter::CAMERA_STOP_BRACKET_CAPTURE },
{ "CAMERA_QUERY_RESOLUTION_PREVIEW", CameraAdapter::CAMERA_QUERY_RESOLUTION_PREVIEW },
{ "CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE", CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_IMAGE_CAPTURE },
{ "CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA", CameraAdapter::CAMERA_QUERY_BUFFER_SIZE_PREVIEW_DATA },
{ "CAMERA_USE_BUFFERS_IMAGE_CAPTURE", CameraAdapter::CAMERA_USE_BUFFERS_IMAGE_CAPTURE },
{ "CAMERA_USE_BUFFERS_PREVIEW_DATA", CameraAdapter::CAMERA_USE_BUFFERS_PREVIEW_DATA },
{ "CAMERA_TIMEOUT_EXPIRED", CameraAdapter::CAMERA_TIMEOUT_EXPIRED },
{ "CAMERA_START_FD", CameraAdapter::CAMERA_START_FD },
{ "CAMERA_STOP_FD", CameraAdapter::CAMERA_STOP_FD },
{ "CAMERA_SWITCH_TO_EXECUTING", CameraAdapter::CAMERA_SWITCH_TO_EXECUTING },
{ "CAMERA_USE_BUFFERS_VIDEO_CAPTURE", CameraAdapter::CAMERA_USE_BUFFERS_VIDEO_CAPTURE },
#ifdef OMAP_ENHANCEMENT_CPCAM
{ "CAMERA_USE_BUFFERS_REPROCESS", CameraAdapter::CAMERA_USE_BUFFERS_REPROCESS },
{ "CAMERA_START_REPROCESS", CameraAdapter::CAMERA_START_REPROCESS },
#endif
};
BaseCameraAdapter::sendCommand()
:
- 利用
switch
将不同的命令对应到各自的逻辑中。
- 此处的
BaseCameraAdapter::startPreview()
实际上做什么操作,具体的实现是在其子类中,接下来选取一个子类 V4LCameraAdapter
继续深入。
case CameraAdapter::CAMERA_START_PREVIEW:
{
CAMHAL_LOGDA("Start Preview");
if ( ret == NO_ERROR )
{
ret = setState(operation);
}
if ( ret == NO_ERROR )
{
ret = startPreview();
}
if ( ret == NO_ERROR )
{
ret = commitState();
}
else
{
ret |= rollbackState();
}
break;
}
4.3.4 V4LCameraAdapter.h
- 位置:
hardware/ti/omap4-aah/camera/inc/V4LCameraAdapter/V4LCameraAdapter.h
- 类
V4LCameraAdapter
继承了 BaseCameraAdapter
。
- 注意它有一个内部私有类:
threadLoop()
应该是与线程的循环执行有关。
- 这个线程不断执行
Adapter
中的 previewThread()
函数。
private:
class PreviewThread : public android::Thread {
V4LCameraAdapter* mAdapter;
public:
PreviewThread(V4LCameraAdapter* hw) :
Thread(false), mAdapter(hw) { }
virtual void onFirstRef() {
run("CameraPreviewThread", android::PRIORITY_URGENT_DISPLAY);
}
virtual bool threadLoop() {
mAdapter->previewThread();
return true;
}
};
status_t recalculateFPS();
char * GetFrame(int &index);
int previewThread();
4.3.5 V4LCameraAdapter.cpp
- 位置:
hardware/ti/omap4-aah/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
startPreview()
:
- 通过
v4lIoctl()
函数从硬件获取需要的数据,并存入 Buffers
。
- 启动一个
PreviewThread
,用于接收从 V4L
摄像头设备传回的数据。
- 最后设置一些
flag
表明预览功能已开启,startPreview
的控制流程就结束了。
status_t V4LCameraAdapter::startPreview()
{
status_t ret = NO_ERROR;
LOG_FUNCTION_NAME;
android::AutoMutex lock(mPreviewBufsLock);
if(mPreviewing) {
ret = BAD_VALUE;
goto EXIT;
}
for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
mVideoInfo->buf.index = i;
mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
if (ret < 0) {
CAMHAL_LOGEA("VIDIOC_QBUF Failed");
goto EXIT;
}
nQueued++;
}
ret = v4lStartStreaming();
if(!mCapturing) {
mPreviewThread = new PreviewThread(this);
CAMHAL_LOGDA("Created preview thread");
}
mPreviewing = true;
mCapturing = false;
EXIT:
LOG_FUNCTION_NAME_EXIT;
return ret;
}
previewThread()
:
- 在
PreviewThread
线程中不断被调用。
- 获取设备传回的数据,并进行一些格式转换操作:
convertYUV422ToNV12Tiler()
- 给帧数据进行一些必要的参数设置,如帧大小、时间戳等。
- 将帧数据发送给用户:
sendFrameToSubscribers(&frame)
int V4LCameraAdapter::previewThread()
{
status_t ret = NO_ERROR;
int width, height;
CameraFrame frame;
void *y_uv[2];
int index = 0;
int stride = 4096;
char *fp = NULL;
mParams.getPreviewSize(&width, &height);
if (mPreviewing) {
fp = this->GetFrame(index);
if(!fp) {
ret = BAD_VALUE;
goto EXIT;
}
CameraBuffer *buffer = mPreviewBufs.keyAt(index);
CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);
if (!lframe) {
ret = BAD_VALUE;
goto EXIT;
}
debugShowFPS();
if ( mFrameSubscribers.size() == 0 ) {
ret = BAD_VALUE;
goto EXIT;
}
y_uv[0] = (void*) lframe->mYuv[0];
convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );
#ifdef SAVE_RAW_FRAMES
unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
saveFile( nv12_buff, ((width*height)*3/2) );
free (nv12_buff);
#endif
frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
frame.mBuffer = buffer;
frame.mLength = width*height*3/2;
frame.mAlignment = stride;
frame.mOffset = 0;
frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;
if (mRecording)
{
frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
mFramesWithEncoder++;
}
ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
if (ret != NO_ERROR) {
CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
} else {
ret = sendFrameToSubscribers(&frame);
}
}
EXIT:
return ret;
}
4.3.6 * AppCallbackNotifier.cpp
- 位置:
hardware/ti/omap4-aah/camera/AppCallbackNotifier.cpp
- 在
CameraHal.cpp
中,预览功能初始化的部分,调用到了 AppCallbackNotifier
类的函数。这个类应该是与各个回调函数有关,即与数据流有着密切的联系。
- 在这里,我打算简单地了解一些对应的逻辑。
startPreviewCallbacks()
:
- 对
previewBuffers
进行一些必要的设置。
- 同步预览帧:
mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC)
- 到这里以后,就不知道该往哪去深入了,但是回调函数在哪调用了?
status_t AppCallbackNotifier::startPreviewCallbacks(android::CameraParameters ¶ms, CameraBuffer *buffers, uint32_t *offsets, int fd, size_t length, size_t count)
{
unsigned int *bufArr;
int size = 0;
LOG_FUNCTION_NAME;
android::AutoMutex lock(mLock);
if ( NULL == mFrameProvider )
{
CAMHAL_LOGEA("Trying to start video recording without FrameProvider");
return -EINVAL;
}
if ( mPreviewing )
{
CAMHAL_LOGDA("+Already previewing");
return NO_INIT;
}
int w,h;
params.getPreviewSize(&w, &h);
mPreviewWidth = w;
mPreviewHeight = h;
mPreviewStride = 4096;
mPreviewPixelFormat = CameraHal::getPixelFormatConstant(params.getPreviewFormat());
size = CameraHal::calculateBufferSize(mPreviewPixelFormat, w, h);
mPreviewMemory = mRequestMemory(-1, size, AppCallbackNotifier::MAX_BUFFERS, NULL);
if (!mPreviewMemory) {
return NO_MEMORY;
}
for (int i=0; i < AppCallbackNotifier::MAX_BUFFERS; i++) {
mPreviewBuffers[i].type = CAMERA_BUFFER_MEMORY;
mPreviewBuffers[i].opaque = (unsigned char*) mPreviewMemory->data + (i*size);
mPreviewBuffers[i].mapped = mPreviewBuffers[i].opaque;
}
if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME ) ) {
mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC);
}
if ( mCameraHal->msgTypeEnabled(CAMERA_MSG_POSTVIEW_FRAME) ) {
mFrameProvider->enableFrameNotification(CameraFrame::SNAPSHOT_FRAME);
}
mPreviewBufCount = 0;
mPreviewing = true;
LOG_FUNCTION_NAME_EXIT;
return NO_ERROR;
}
setCallbacks()
:
- 我想知道回调函数在哪调用,于是找到了这个设置回调的函数。
- 数据回调名为
mDataCb
,于是搜索 mDataCb
。
void AppCallbackNotifier::setCallbacks(CameraHal* cameraHal,
camera_notify_callback notify_cb,
camera_data_callback data_cb,
camera_data_timestamp_callback data_cb_timestamp,
camera_request_memory get_memory,
void *user)
{
android::AutoMutex lock(mLock);
LOG_FUNCTION_NAME;
mCameraHal = cameraHal;
mNotifyCb = notify_cb;
mDataCb = data_cb;
mDataCbTimestamp = data_cb_timestamp;
mRequestMemory = get_memory;
mCallbackCookie = user;
LOG_FUNCTION_NAME_EXIT;
}
notifyEvent()
:
- 在这个函数中发现了对回调函数
mDataCb
的调用。
- 下面选出的这个分支是与
PREVIEW_METADATA
有关,即预览元数据。
- 元数据在
evt->mEventData
中,看命名应该是与 Event 有关。
Event
相关的机制目前我还不太清楚,也还不会去深究,只需要知道它拿到了数据就行。
- 申请一个
camera_memory_t
对应的 Buffers
空间后,就调用回调函数将元数据往上层进行传输了。
case CameraHalEvent::EVENT_METADATA:
metaEvtData = evt->mEventData->metadataEvent;
if ( ( NULL != mCameraHal ) &&
( NULL != mNotifyCb) &&
( mCameraHal->msgTypeEnabled(CAMERA_MSG_PREVIEW_METADATA) ) )
{
camera_memory_t *tmpBuffer = mRequestMemory(-1, 1, 1, NULL);
mDataCb(CAMERA_MSG_PREVIEW_METADATA,
tmpBuffer,
0,
metaEvtData->getMetadataResult(),
mCallbackCookie);
metaEvtData.clear();
if ( NULL != tmpBuffer ) {
tmpBuffer->release(tmpBuffer);
}
}
break;
流程简图
- 图中标明了控制流程的主要调用顺序,对于数据流暂不考究。
- 实际上,在
HAL
层与 Device
之间应该还有一层 Linux Kernel(drivers)
,但这目前已经超出我所需要了解的范围,所以就先忽略掉了。
- 注意
HAL
层中,CameraHardwareInterface
是通用的入口,而真正实现与驱动层的对接是与平台相关的,不同平台有不同的实现方案。
小结
- 本篇笔记中,我们选定
Camera.startPreview()
方法作为切入点,结合 hw_get_module()
相关内容,对其整个流程进行追踪分析,从而对之前已有初步了解的 Camera
控制流逻辑有一个更全面的理解。
- 在
HAL
层中,涉及到了不同平台的实现,而且这些具体实现还是有比较大的区别的。
- 目前还不够清楚的地方,就是
Event
、Binder
等 Android
内部机制的实现。
- 在下一篇,我开始整理
Camera
数据流的逻辑。由于目前所探究的数据流相对来说比较简单,主要就是几个 callback
函数的调用逻辑,所以我打算结合初始化与控制流的部分,将整个 Camera
流程整理、结合起来,作为这系列学习笔记的终结。