Android系统--Camera API 1

Camera1分析

1.相关概念介绍

camera 1相关内容 作用
camera.java 进行初始化设置以及调用jni实现功能
android_hardware_Camera.cpp 调用native层代码获得底层camera硬件的访问入口

camera.java

  1. 位置: frameworks/base/core/java/android/hardware/Camera.java
  2. 首先不会去调用缺省构造函数,获取Camera对象是在Camera.open()获取的,这个也是一个静态方法,在这个方法的基础上,会调用构造函数来进行初始化设置。
  3. 在这个类当中的主要方法有:
  • 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 处理获取聚焦的回调
  1. 关于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)是用于保存当前窗口的像素数据的。
    

android_hardware_Camera.cpp

  1. 位置:frameworks/base/core/jni/android_hardware_Camera.cpp
  2. 接下来分析JNI当中的几个函数:
  • 设置预览显示方法android_hardware_Camera_setPreviewDisplay()
static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
{
    LOGV("setPreviewDisplay");
    //强指针指向的Camera,利用native方法来获取
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    sp<Surface> surface = NULL;
    if (jSurface != NULL) {
        surface = reinterpret_cast<Surface*>(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)

通过分析可以看到,这个的Camera是一个Camera的类,在这里最终调用了camera的函数,进入下一步的分析。

Camera.cpp

  1. 位置:/frameworks/base/libs/ui/Camera.cpp
  2. 首先分析camera当中的设置方法:setPreviewDisplay(surface)
status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
{
    LOGV("setPreviewDisplay");
    sp <ICamera> 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<ISurface>& 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封装的返回值即可。</br>
在这里还想介绍的一点是,在实现命令时,client不需要与驱动直接进行通信,最终还是借助ProcessState以及IPCThreadState来与底层驱动进行通信。

  1. 针对remote进行分析:
  • 首先
BpCamera:public BpInterface<ICamera>
  • 其次
class BpInterface : public INTERFACE, public BpRefBase
{
public:
                                BpInterface(const sp<IBinder>& remote);

protected:
    virtual IBinder*            onAsBinder();
};

可以看到remote确实是一个IBinder类。

  1. 针对业务码进行分析:
    首先是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;

也是相对应的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351