Android8.0相机源码深入解析(二)

正文

上一篇介绍了framework到hal的调用过程,从framework到相机本地库到hal层.本篇介绍app和hal层数据传递.

app到相机本地库

app到hal层数据传递有Camera的方法setParameters传递参数,Parameters是Camera的内部类,主要包含一个LinkedHashMap对象.看Camera的方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Changes the settings for this Camera service.
*
* @param params the Parameters to use for this Camera service
* @throws RuntimeException if any parameter is invalid or not supported.
* @see #getParameters()
*/
public void setParameters(Parameters params) {
// If using preview allocations, don't allow preview size changes
if (mUsingPreviewAllocation) {
Size newPreviewSize = params.getPreviewSize();
Size currentPreviewSize = getParameters().getPreviewSize();
if (newPreviewSize.width != currentPreviewSize.width ||
newPreviewSize.height != currentPreviewSize.height) {
throw new IllegalStateException("Cannot change preview size" +
" while a preview allocation is configured.");
}
}

native_setParameters(params.flatten());
}

private native final void native_setParameters(String params);

预览时不能改变窗口大小,然后使用native方法.
找到native方法,根据前一篇的流程,同样可以在android_hardware_Camera.cpp找到jni方法的定义和native方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
{
ALOGV("setParameters");
sp<Camera> camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;

const jchar* str = env->GetStringCritical(params, 0);
String8 params8;
if (params) {
params8 = String8(reinterpret_cast<const char16_t*>(str),
env->GetStringLength(params));
env->ReleaseStringCritical(params, str);
}
if (camera->setParameters(params8) != NO_ERROR) {
jniThrowRuntimeException(env, "setParameters failed");
return;
}
}

然后到Camera.cpp

1
2
3
4
5
6
7
8
String8 Camera::getParameters() const
{
ALOGV("getParameters");
String8 params;
sp <::android::hardware::ICamera> c = mCamera;
if (c != 0) params = mCamera->getParameters();
return params;
}

再到ICamera:

1
2
3
4
5
6
7
8
9
// get preview/capture parameters - key/value pairs
String8 getParameters() const
{
ALOGV("getParameters");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
remote()->transact(GET_PARAMETERS, data, &reply);
return reply.readString8();
}

通过Binder机制到CameraClient:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
status_t CameraClient::setParameters(const String8& params) {
LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());

Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;

mLatestSetParameters = CameraParameters(params);
CameraParameters p(params);
// MIUI MOD:
const char* mute = p.get(CameraParameters::KEY_CAMERA_SERVICE_MUTE);

if (mute != NULL && strcmp(mute, CameraParameters::TRUE) == 0) {
sCameraService->setMuteState(true);
}
return mHardware->setParameters(p);
}

整个流程和前一篇的完全一致,熟悉整体过程中间步骤就不一一介绍了,看到这里之后我们就可以到hal层找对应的实现了.

hal层实现

找到QCamera2HardwareInterface的set_parameters方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/*===========================================================================
* FUNCTION : set_parameters
*
* DESCRIPTION: set camera parameters
*
* PARAMETERS :
* @device : ptr to camera device struct
* @parms : string of packed parameters
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int QCamera2HardwareInterface::set_parameters(struct camera_device *device,
const char *parms)
{
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL1_SET_PARAMETERS);
int ret = NO_ERROR;
QCamera2HardwareInterface *hw =
reinterpret_cast<QCamera2HardwareInterface *>(device->priv);
if (!hw) {
LOGE("NULL camera device");
return BAD_VALUE;
}
LOGI("E camera id %d", hw->getCameraId());
hw->lockAPI();
qcamera_api_result_t apiResult;
ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS, (void *)parms);
if (ret == NO_ERROR) {
hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS, &apiResult);
ret = apiResult.status;
}

// Give HWI control to restart (if necessary) after set params
// in single camera mode. In dual-cam mode, this control belongs to muxer.
if (hw->getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) {
if ((ret == NO_ERROR) && hw->getNeedRestart()) {
LOGD("stopping after param change");
ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_STOP, NULL);
if (ret == NO_ERROR) {
hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_STOP, &apiResult);
ret = apiResult.status;
}
}

if (ret == NO_ERROR) {
LOGD("committing param change");
ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, NULL);
if (ret == NO_ERROR) {
hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, &apiResult);
ret = apiResult.status;
}
}

if ((ret == NO_ERROR) && hw->getNeedRestart()) {
LOGD("restarting after param change");
ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_RESTART, NULL);
if (ret == NO_ERROR) {
hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_RESTART, &apiResult);
ret = apiResult.status;
}
}
}

hw->unlockAPI();
LOGI("X camera id %d ret %d", hw->getCameraId(), ret);

return ret;
}

然后到QCameraStateMachine状态机:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case QCAMERA_SM_EVT_SET_PARAMS:
{
bool needRestart = false;

rc = m_parent->waitDeferredWork(m_parent->mParamInitJob);
if (NO_ERROR != rc) {
LOGE("Param init deferred work failed");
} else {
rc = m_parent->updateParameters((char*)payload, needRestart);
}
result.status = rc;
result.request_api = evt;
result.result_type = QCAMERA_API_RESULT_TYPE_DEF;
m_parent->signalAPIResult(&result);
}
break;

根据状态又回到了QCamera2HardwareInterface的updateParameters方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*===========================================================================
* FUNCTION : updateParameters
*
* DESCRIPTION: update parameters
*
* PARAMETERS :
* @parms : input parameters string
* @needRestart : output, flag to indicate if preview restart is needed
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int QCamera2HardwareInterface::updateParameters(const char *parms, bool &needRestart)
{
int rc = NO_ERROR;
int retParallel = 0;

String8 str = String8(parms);
rc = mParameters.updateParameters(str, needRestart);
setNeedRestart(needRestart);

// update stream based parameter settings
for (int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) {
if (m_channels[i] != NULL) {
m_channels[i]->UpdateStreamBasedParameters(mParameters);
}
}
mHalInf->onSetParameters(mParameters.setting1(),mParameters.setting2()...);
...

return rc;
}

updateParameters会更新所有参数,首先更新基础参数,然后可以通过mHalInf更新一些自定义的参数,这部分代码省略了.
定制相机开发时可以增加Parameters中的key,做自定义开关配置参数传递等.

总结

参数传递和第一篇setPreview走的流程都差不多,熟悉后整体流程更清楚了,具体到代码阅读是只需要找Parameters对应的key,就可以找到关键方法了,系统代码的阅读也不复杂.
知道了app到hal的数据传递,那hal如何把数据传递给app层呢?我们下一篇分析hal到app的数据传递.