【Camera专题】Camera驱动源码全解析_下
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了【Camera专题】Camera驱动源码全解析_下相关的知识,希望对你有一定的参考价值。
参考技术A 1、手把手撸一份驱动 到 点亮 Camera
2、Camera dtsi 完全解析
3、Camera驱动源码全解析上
4、Camera驱动源码全解析下
上篇文章分析了C文件函数的实现,本文继续分析h文件的配置信息。
推荐文章:
MIPI CSI2学习(一):说一说MIPI CSI2
高通camera驱动分析
参照sensor规格书或者咨询fae,配置:
2.1 sensor帧的输出和关闭
sensor以流的方式 输出帧.
2.2 开启sensor 端的group 功能
开启sensor 端的group 功能,将曝光(line),gain等打包,保证在同一帧进去生效
2.3 sensor嵌入式数据
2.4 sensor初始化相关寄存器
2.5 sensor分辨率相关寄存器
以上的sensor寄存器配置一般有fae厂商提供,驱动工程师尽可能的掌握相关寄存器代表的含义。
如控制宽高、帧率、曝光等等寄存器
我们只用到16位,因此
sensor_id_reg_addr = 0x300b,
sensor_id = 0x0D42,
曝光时间以行长为单位; PCLK以Hz为单位;
行长以周期数为单位,帧长以行长数为单位;其中周期数就是频率
T 周期以ms为单位;
f 频率以Hz为单位;
f = 1 / T;
可以参考这篇文章:
camera曝光和帧率_songqiangzmt的博客
比如这里又3个寄存器,每个寄存器是8bit:
max_linecount = 0x ff ff -8
暂时没弄清楚
这里指的是暗电流值,
一般来说 raw8 都是 16, raw10为 16x4=64, raw12 =16x4x4
传感器可以流式传输许多不同的 数据类型(DT) 。
该数据被包装在不同的流中。 在一个流中,可以有一个或多个不同的DT。 一种 虚拟通道(VC) 分配给每个流。 DT和VC的组合应为唯一,并分配了一个通道ID(CID)。
有关如何指定CID的要求/限制。 当前的MIPI CSI_Rx支持四个VC,每个VC最多可以有四个CID,如下表所示。
传感器可能具有内置的pattern generator。 通过设置专用寄存器,传感器可以将生成的图案输出。
当出现图像异常时,可以使用此功能看看sensor本身输出是否有问题。
binning_factor主要是用来控制拍照亮度跟预览亮度一致的,当然也可以解决预览噪点过大的问题!
3A算法里,曝光时间 snap_exp_time *= (float)(binning_multiplier);
3A源码
赋值源码
关键日志:
CSI :Camera Serial Interface 定义了一个位于处理器和摄像模组之间的高速串行接口
为使CSI_Tx(传感器)和CRI_Rx(设备)正常工作,需要一段时间它们之间需要同步。
此时间在此处设置为计时器时钟滴答数。 它必须介于公式计算的MIN和MAX值之间
MIN [Settle count * T(Timer clock)] > T(HS_SETTLE)_MIN
MAX [Settle count * T(Timer clock)] < T(HS-PREPARE)+T(HS_ZERO) - 4*T(Timer clock)
settle_cnt(即稳定计数)– 必须根据传感器输出特性配置该值,以确保传感器的 PHY
发送器与 MSM 的 PHY 接收器无障碍同步。
对于 28 nm 以及更小的 MSM 芯片,使用以下公式计算稳定计数:
settle_cnt = T(HS_SETTLE)_avg /T(TIMER_CLK),
其中 T(HS_SETTLE)_avg = (T(HS_SETTLE)_min + T(HS_SETTLE)_max) / 2,如传
感器数据表所指示
如果sensor可以直接流式传输HDR帧,该函数才有用。
这里的 rolloff compensations = Lens Shading Correction (LSC)
有些sensor可以自己内部做lsc补偿。rolloff_config就是用了配置sensor的这些信息。
注意:如果你使用了sensor LSC补偿,平台端 lsc补偿就要关闭,否则双倍补偿,可能会造成图片失真。
typedef enum
SENSOR_DELAY_EXPOSURE, /* delay for exposure /
SENSOR_DELAY_ANALOG_SENSOR_GAIN, / delay for sensor analog gain /
SENSOR_DELAY_DIGITAL_SENSOR_GAIN, / delay for sensor digital gain /
SENSOR_DELAY_ISP_GAIN, / delay for sensor ISP (error) gain*/
SENSOR_DELAY_MAX,
sensor_delay_type_t;
SENSOR_DELAY_EXPOSURE – Sets the exposure of frame N at frame N + delay
SENSOR_DELAY_ANALOG_SENSOR_GAIN – Sets the analog gain register at frame N + delay
SENSOR_DELAY_DIGITAL_SENSOR_GAIN – Sets the digital gain register at frame N + delay
SENSOR_DELAY_ISP_GAIN – Passes the isp digital gain to the isp module at frame N + delay
如果出现ae闪烁问题,可以尝试修改延迟,让gain和expose同步。
This is the readout time (in nanoseconds) of the sensor’s analog-to-digital converter. Usually it is
the minimum line time when the sensor is running at the maximum pixel clock.
NOTE: This is the sensor module’s own information. Refer to the sensor vendor for more information
noise_coeff 小波里用来定义噪声的模板
噪声系数模型: N(x) = sqrt(Sx + O)
这些参数一般由tunning团队修改。
关于角度
注意:
如果 <MountAngle>360</MountAngle>; 这个值配置成360度,那么以dtsi配置的角度为准。
源码:
关于帧率
https://www.cnblogs.com/ZHJEE/p/10351155.html
继续当一名咸鱼( ̄︶ ̄)!
Camera1 源码解析系列—— Camera1 Open() 流程解析
前言
这一章里,我们将 Camera.java
中的 open()
方法作为切入点,按照 Framework -> Android Runtime -> C/C++ Libraries -> HAL
的顺序去分析整个调用流程。
1 Framework层
1.1 Camera.java
- 路径:
frameworks/base/core/java/android/hardware/Camera.java
- 首先从
Open()
方法开始:- 获取
Camera
设备的个数。 - 依次获取设备信息,如果是获取到后置摄像头(默认),则调用
new Camera(int)
构造对应的摄像头实例。
- 获取
- 注释翻译:
- 构造一个新的摄像头对象,以获取第一个后置摄像头。
- 若设备中没有后置摄像头,则返回
null
。
- NOTE:还有一个方法
open(int)
,它可以直接指定打开的摄像头。
/***
* Creates a new Camera object to access
* the first back-facing camera on the
* device. If the device does not have a back-facing camera,
* this returns null.
* @see #open(int)
*/
public static Camera open()
int numberOfCameras = getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < numberOfCameras; i++)
getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK)
return new Camera(i);
return null;
Camera(int cameraId)
:- 通过调用
cameraInitNormal(Id)
方法对指定摄像头进行初始化。
- 通过调用
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId)
int err = cameraInitNormal(cameraId);
if (checkInitErrors(err))
if (err == -EACCES)
throw new RuntimeException("Fail to connect to camera service");
else if (err == -ENODEV)
throw new RuntimeException("Camera initialization failed");
// Should never hit this.
throw new RuntimeException("Unknown camera error");
cameraInitNormal(int cameraId)
:- 指定
halVersion
参数。 - 调用
cameraInitVersion(int cameraId, int halVersion)
。
- 指定
private int cameraInitNormal(int cameraId)
return cameraInitVersion(cameraId,
CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
cameraInitVersion(int cameraId, int halVersion)
:- 将各个回调函数置空。
- 通过
Looper
对事件处理对象进行实例化后,就调用native_setup
方法进入JNI(Java Native Interface)
库中调用对应的函数。 - 至此,
open()
方法开始进入Android Runtime
层。
private int cameraInitVersion(int cameraId,
int halVersion)
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
Looper looper;
if ((looper = Looper.myLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else if ((looper = Looper.getMainLooper()) != null)
mEventHandler = new EventHandler(this, looper);
else
mEventHandler = null;
return native_setup(new WeakReference<Camera>(this),
cameraId, halVersion,
ActivityThread.currentOpPackageName());
1.2 Framework 中流程简图
2 Android Runtime
2.1 android_hardware_Camera.cpp
- 路径:
frameworks/base/core/jni/android_hardware_Camera.cpp
native_setup()
:- 刚开始要先把
clientPackageName
做一个类型转换,变成clientName
。 - 建立一个
Camera
类型的StrongPointer(sp)
。
- 刚开始要先把
- 通过函数
Camera::connect()
或Camera::connectLegacy()
,让客户端与服务端进行连接,并返回相应的Camera
实例。 - 最后对返回的实例进行一些基本的检查,并保存上下文。
- 在
connect()
的时候,就进入了C/C++ Libraries
的 C/S 结构中,而Camera
则属于Client
。
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env,
jobject thiz, jobject weak_this,
jint cameraId, jint halVersion,
jstring clientPackageName)
// convert jstring to String16(clientPackageName -> clientName)
......
......
sp<Camera> camera;
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT)
/***** NOTE THIS *****/
// Default path: hal version is don't care, do normal camera connect.
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID,
Camera::USE_CALLING_PID);
else
jint status = Camera::connectLegacy(cameraId,
halVersion, clientName,
Camera::USE_CALLING_UID, camera);
if (status != NO_ERROR)
return status;
if (camera == NULL)
return -EACCES;
// make sure camera hardware is alive
if (camera->getStatus() != NO_ERROR)
return NO_INIT;
// save context in opaque field
......
......
2.2 Runtime 中流程简图
3 C/C++ Libraries
3.1 Camera
3.1.1 Camera.h
- 路径:
frameworks/av/include/camera/Camera.h
- 注意
CameraTraits<Camera>
的结构体:
template <>
struct CameraTraits<Camera>
typedef CameraListener TCamListener;
typedef ::android::hardware::ICamera TCamUser;
typedef ::android::hardware::ICameraClient TCamCallbacks;
typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
(const sp<::android::hardware::ICameraClient>&,
int, const String16&, int, int,
/*out*/
sp<::android::hardware::ICamera>*);
static TCamConnectService fnConnectService;
;
3.1.2 Camera.cpp
- 路径:
framework/av/camera/Camera.cpp
- 注意
fnConnectService
是对应到ICameraService::connect
函数的。
CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
&::android::hardware::ICameraService::connect;
Camera::connect()
:- 这里直接调用了
CameraBaseT::connect()
,这是定义在CameraBase.cpp
中的函数。
- 这里直接调用了
sp<Camera> Camera::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid)
return CameraBaseT::connect(cameraId,
clientPackageName, clientUid, clientPid);
3.2 CameraBase
3.2.1 CameraBase.h
- 路径:
frameworks/av/include/camera/CameraBase.h
- 注意模板信息:
TCam
对应Camera
。TCamTraits
对应CameraTraits<Camera>
。
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
- 注意类成员变量声明部分:
- 即可知道
CameraBaseT
对应CameraBase<Camera>
。
- 即可知道
sp<TCamUser> mCamera;
status_t mStatus;
sp<TCamListener> mListener;
const int mCameraId;
/***** NOTE THIS *****/
typedef CameraBase<TCam> CameraBaseT;
3.2.2 CameraBase.cpp
- 路径:framework/av/camera/CameraBase.cpp
- connect():
- 实例化一个 Camera
- 通过 Camera 获取 ICameraClient 指针。
- 通过 getCameraService() 函数获取 ICameraService。
- 通过 ICameraService::connect() 函数获得一个 mCamera, 即 ICamera 实例。
- 将 ICamera 实例与 Binder 建立联系。
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid)
ALOGV("%s: connect", __FUNCTION__);
/***** NOTE THIS *****/
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
const sp<::android::hardware::ICameraService> cs = getCameraService();
binder::Status ret;
if (cs != nullptr)
/***** NOTE THIS *****/
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
ret = (cs.get()->*fnConnectService)(cl, cameraId,
clientPackageName, clientUid,
clientPid, /*out*/ &c->mCamera);
if (ret.isOk() && c->mCamera != nullptr)
/***** NOTE THIS *****/
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
else
ALOGW("An error occurred while connecting to camera %d: %s", cameraId,
(cs != nullptr) ? "Service not available" : ret.toString8().string());
c.clear();
return c;
getCameraService()
:- 注意,
gCameraService
是一个ICameraService
。 - 首先调用
ICameraService
的get
函数,如果能获取到ICameraService
则返回。 - 若没有返回,则通过
IServiceManager
来获取一个ICameraService
,这个过程中主要是通过IBinder
来进行数据获取的。
- 注意,
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService()
Mutex::Autolock _l(gLock);
/***** NOTE THIS *****/
if (gCameraService.get() == 0)
char value[PROPERTY_VALUE_MAX];
property_get("config.disable_cameraservice", value, "0");
if (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0)
return gCameraService;
/***** NOTE THIS *****/
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do
binder = sm->getService(String16(kCameraServiceName));
if (binder != 0)
break;
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
while(true);
if (gDeathNotifier == NULL)
gDeathNotifier = new DeathNotifier();
binder->linkToDeath(gDeathNotifier);
/***** NOTE THIS *****/
gCameraService = interface_cast<::android::hardware::ICameraService>(binder);
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
3.3 ICameraService
这一节主要是了解一下关于 Binder
通讯中的一些内部逻辑。实际上在 CameraBase
中,所调用的 connect
对应的是 CameraService::connect()
。
3.3.1 ICameraService.aidl
● 路径:frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
● aidl
是一种内部进程通讯的描述语言,通过它我们可以定义通讯的接口。
● 注释:
○ 这里定义了运行在媒体服务端的,本地摄像头服务的 Binder
接口。
/**
* Binder interface for the native camera service running in mediaserver.
*
* @hide
*/
connect
接口:- 这里的注释说明了,这个方法调用的是旧的
Camera API
,即API 1
。
- 这里的注释说明了,这个方法调用的是旧的
/**
* Open a camera device through the old camera API
*/
ICamera connect(ICameraClient client,
int cameraId,
String opPackageName,
int clientUid, int clientPid);
3.3.2 ICameraService.cpp
- 路径:
out/target/product/generic/obj/SHARED_LIBRARIES/libcamera_client_intermediates/aidl-generated/src/aidl/android/hardware/ICameraService.cpp
out
文件夹是源码编译后才生成的。- 这个
ICameraService.cpp
以及其头文件ICameraService.
h 都是根据其对应的aidl
文件自动生成的。 BpCameraService::connect()
:- 注意,这里是
BpCameraservice
,它继承了ICameraService
,同时也继承了BpInterface
。 Parcel
可以看成是Binder
通讯中的信息传递中介。- 首先把相应的数据写入
Parcel
。 - 然后调用远程接口
remote()
中的处理函数transact()
。 - 最后通过返回的
reply
数据判断是否有error
。
- 注意,这里是
::android::binder::Status BpCameraService::connect(const ::android::sp<::android::hardware::ICameraClient>& client,
int32_t cameraId, const ::android::String16& opPackageName,
int32_t clientUid, int32_t clientPid,
::android::sp<::android::hardware::ICamera>* _aidl_return)
::android::Parcel _aidl_data;
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
/***** NOTE THIS *****/
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_data.writeStrongBinder(::android::hardware::ICameraClient::asBinder(client));
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_data.writeInt32(cameraId);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_data.writeString16(opPackageName);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_data.writeInt32(clientUid);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_data.writeInt32(clientPid);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
/***** NOTE THIS *****/
_aidl_ret_status = remote()->transact(ICameraService::CONNECT, _aidl_data, &_aidl_reply);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
if (!_aidl_status.isOk())
return _aidl_status;
_aidl_ret_status = _aidl_reply.readStrongBinder(_aidl_return);
if (((_aidl_ret_status) != (::android::OK)))
goto _aidl_error;
_aidl_error:
_aidl_status.setFromStatusT(_aidl_ret_status);
return _aidl_status;
BnCameraService::onTransact()
:- 消息处理函数。
- 这个函数太长,只截取
CONNECT
相关的一段。 BpCameraService
通过Binder
封装了接口,而BnCameraService
则具体实现接口。- 注意到这里一一接收了
Bp
传来的数据,然后调用了具体的connect
函数获取ICamera
并且返回。
case Call::CONNECT:
::android::sp<::android::hardware::ICameraClient> in_client;
int32_t in_cameraId;
::android::String16 in_opPackageName;
int32_t in_clientUid;
int32_t in_clientPid;
/***** NOTE THIS *****/
::android::sp<::android::hardware::ICamera> _aidl_return;
if (!(_aidl_data.checkInterface(this)))
_aidl_ret_status = ::android::BAD_TYPE;
break;
_aidl_ret_status = _aidl_data.readStrongBinder(&in_client);
if (((_aidl_ret_status) != Camera1 源码解析系列—— Camera1 startPreview() 流程解析
Camera1 源码解析系列—— Camera1 startPreview() 流程解析
Camera1 源码解析系列—— Camera1 Open() 流程解析