Android系统--Camera|Android系统--Camera API 1
Camera1分析
1.相关概念介绍
camera 1相关内容 | 作用 |
---|---|
camera.java | 进行初始化设置以及调用jni实现功能 |
android_hardware_Camera.cpp | 调用native层代码获得底层camera硬件的访问入口 |
- 位置: frameworks/base/core/java/android/hardware/Camera.java
- 首先不会去调用缺省构造函数,获取Camera对象是在Camera.open()获取的,这个也是一个静态方法,在这个方法的基础上,会调用构造函数来进行初始化设置。
- 在这个类当中的主要方法有:
- public final void setPreviewDisplay(SurfaceHolder holder)
- public final void takePicture(ShutterCallback shutter, PictureCallback raw,PictureCallback jpeg)
- public void handleMessage(Message msg)
- 相机初始化
- 相机参数设定
- 相机处理回调
- 相机调用JNI(主要目的)
- 相机消息处理
Message | 解释 |
---|---|
CAMERA_MSG_SHUTTER | 处理相机回调 |
CAMERA_MSG_RAW_IMAGE | 处理当拍照完成且图片为raw的回调 |
CAMERA_MSG_COMPRESSED_IMAGE | 处理当拍照完成且图片为JPEG的回调 |
CAMERA_MSG_PREVIEW_FRAME | 处理获取预览的回调 |
CAMERA_MSG_FOCUS | 处理获取聚焦的回调 |
- 关于surface:简单的说Surface对应了一块屏幕缓冲区,每个window对应一个Surface,任何View都要画在Surface的Canvas上(后面有原因解释)。传统的view共享一块屏幕缓冲区,所有的绘制必须在UI线程中进行。在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原始缓冲区的句柄”,这句话包括下面两个意思:
1、通过Surface(因为Surface是句柄)就可以获得原生缓冲器以及其中的内容。就像在C++语言中,可以通过一个文件的句柄,就可以获得文件的内容一样。 2、原始缓冲区(a raw buffer)是用于保存当前窗口的像素数据的。
- 位置:frameworks/base/core/jni/android_hardware_Camera.cpp
- 接下来分析JNI当中的几个函数:
- 设置预览显示方法android_hardware_Camera_setPreviewDisplay()
static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
{
LOGV("setPreviewDisplay");
//强指针指向的Camera,利用native方法来获取
sp camera = get_native_camera(env, thiz, NULL);
if (camera == 0) return;
sp surface = NULL;
if (jSurface != NULL) {
surface = reinterpret_cast(env->GetIntField(jSurface, fields.surface));
}
//直接调用底层的方法来对Camera设置预览显示
if (camera->setPreviewDisplay(surface) != NO_ERROR) {
jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
}
}
这个方法,主要是设置对Surface的设置,作为一个Native层的函数,其对应的camera.java当中的方法为:
public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
if (holder != null) {
setPreviewDisplay(holder.getSurface());
} else {
setPreviewDisplay((Surface)null);
}
}private native final void setPreviewDisplay(Surface surface);
接下来继续追踪设置surface的过程,可以看到在Native层调用的一个方法为:
camera->setPreviewDisplay(surface)
【Android系统--Camera|Android系统--Camera API 1】通过分析可以看到,这个的Camera是一个Camera的类,在这里最终调用了camera的函数,进入下一步的分析。
Camera.cpp
- 位置:/frameworks/base/libs/ui/Camera.cpp
- 首先分析camera当中的设置方法:setPreviewDisplay(surface)
status_t Camera::setPreviewDisplay(const sp& surface)
{
LOGV("setPreviewDisplay");
sp c = mCamera;
if (c == 0) return NO_INIT;
if (surface != 0) {
return c->setPreviewDisplay(surface->getISurface());
} else {
LOGD("app passed NULL surface");
return c->setPreviewDisplay(0);
}
}
可以看到,在这里首先引用一个ICamera的强指针,并且进一步调用了以ISurface为参数的方法,其中的ICamera为一个接口类,是进一步与底层进行通信的,当进入Native层之后,需要借助BpCamera进行转换:
查看进一步的BpCamera类,BpInterface接口类:
status_t setPreviewDisplay(const sp& surface)
{
LOGV("setPreviewDisplay");
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
data.writeStrongBinder(surface->asBinder());
remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
return reply.readInt32();
}
可以看到,这里便是与camera service进行通信的代码,而这里则是通过Parcel进行传入参数的封装以及返回的接收,最终可以看到,利用remote进行的命令传输,可以预想这个remote是一个IBinder对象,这个命令的传输是对Binder驱动的封装,下面的Binder驱动当中的open,mmap,ioctl已经被封装了,只需要最后接收相应的以Parcel封装的返回值即可。
在这里还想介绍的一点是,在实现命令时,client不需要与驱动直接进行通信,最终还是借助ProcessState以及IPCThreadState来与底层驱动进行通信。
- 针对remote进行分析:
- 首先
BpCamera:public BpInterface
- 其次
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp& remote);
protected:
virtual IBinder*onAsBinder();
};
可以看到remote确实是一个IBinder类。
- 针对业务码进行分析:
首先是ICamera当中的类型:
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_PREVIEW_DISPLAY,
SET_PREVIEW_CALLBACK_FLAG,
START_PREVIEW,
STOP_PREVIEW,
AUTO_FOCUS,
TAKE_PICTURE,
SET_PARAMETERS,
GET_PARAMETERS,
CONNECT,
LOCK,
UNLOCK,
PREVIEW_ENABLED,
START_RECORDING,
STOP_RECORDING,
RECORDING_ENABLED,
RELEASE_RECORDING_FRAME,
};
进一步看IBinder当中的业务码对应的是:
/**
* The first transaction code available for user commands.
*/
int FIRST_CALL_TRANSACTION= 0x00000001;
/**
* The last transaction code available for user commands.
*/
int LAST_CALL_TRANSACTION= 0x00ffffff;
也是相对应的。
推荐阅读
- android第三方框架(五)ButterKnife
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 单点登陆
- android|android studio中ndk的使用
- 操作系统|[译]从内部了解现代浏览器(1)
- 游乐园系统,助力游乐园管理
- 中国MES系统软件随工业化成长
- Android事件传递源码分析