电竞比分网-中国电竞赛事及体育赛事平台

分享

android?camera框架分析與移植

 昵稱7324690 2012-08-25

android camera框架分析與移植

(2011-08-12 23:47:52)
標簽:

雜談

分類: Android

俗話說:知己知彼,百戰(zhàn)不殆,想要移植camera硬件,需要了解android中camera的框架思想和調用流程,才能事半功倍。

 

(1)       Android中camera編程思路:

     Camera類介紹:

常用接口,這些接口是camera編程時作為框架層回調時候使用:

 

android <wbr>camera框架分析與移植

常用方法,這些方法作為camera應用編程時使用的API

   android <wbr>camera框架分析與移植

 

在應用層的編程上常用流程為:

預覽: 

    mCamera = Camera.open();

Camera.Parameters p = mCamera.getParameters();

  p.setPreviewSize(w, h);

  mCamera.setParameters(p);
 

SurfaceView  mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);

  SurfaceHolder  holder = mSurfaceView.getHolder();

  holder.addCallback(this);

  mCamera.setPreviewDisplay(holder);

  mCamera.startPreview();

 

當我們打開攝像頭應用的時候首先是預覽的功能,預覽就是將攝像頭拍攝下的景物實時的呈現(xiàn)出來,在android應用中能夠顯示給用戶交互的類都是繼承自view類,我們需要給camera預覽顯示時提供一個畫布一樣的東西,這里我們使用surfaceview類,為什么不直接使用view類呢?關于view顯示的框架我將在以后的博文中給大家分析,這里使用surfaceview類作為camera的顯示,可以使camera框架層得到一個可以控制顯示框架的代理,使用這個代理可以將camera獲取的幀數(shù)據(jù)發(fā)送到顯示框架去合成顯示,如果我們設置了預覽回調:

android <wbr>camera框架分析與移植

也可以在回調中將每一幀的數(shù)據(jù)保存起來形成錄像的功能


拍照:
    mCamera.takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg)

拍照本身調用就需要設置回調函數(shù),回調函數(shù)中可以設置幾種回調方式,這幾種都是拍照時框架層提供給應用層數(shù)據(jù),有原始數(shù)據(jù),有jpeg數(shù)據(jù),這幾種都是拍攝下來的數(shù)據(jù)的不同儲存方式,供我們在應用層處理使用。

 

小結:在應用層上我們可以了解到什么?

預覽和拍照都可以通過回調的方式獲取框架層的數(shù)據(jù),當然預覽也可以不需要把框架層的數(shù)據(jù)獲取,直接發(fā)給顯示框架去顯示。

 

(2)       現(xiàn)在我們要開始分析camera類代碼了解調用細節(jié):

 

 

Camera.java (frameworks\base\core\java\android\hardware)     

public static Camera open() {

        return new Camera(); //構造camera

    }

 

    Camera() {

        mShutterCallback = null;

        mRawImageCallback = null;

        mJpegCallback = null;

        mPreviewCallback = null;

        mPostviewCallback = null;

        mZoomCallback = null;

 

        Looper looper;

        if ((looper = Looper.myLooper()) != null) { //創(chuàng)建Handler,處理本地的通知事件

            mEventHandler = new EventHandler(this, looper);

        } else if ((looper = Looper.getMainLooper()) != null) {

            mEventHandler = new EventHandler(this, looper);

        } else {

            mEventHandler = null;

        }

 

        native_setup(new WeakReference<Camera>(this)); //調用本地方法,完成初始化

    }

 

    private native final void native_setup(Object camera_this);

   

WeakReference 類的作用:如果想觀察一個類什么時候被垃圾回收清除,我們使用WeakReference類來定義,當Camera類的引用為null是,可以通過WeakReferenceget方法獲取此類的信息,了解此類是否被垃圾回收

 

EventHandler調用流程;

 

 

android <wbr>camera框架分析與移植

 

 

(1)        private native final void native_setup(Object camera_this);

(2)        private native final void native_setParameters(String params);

(3)        private native final String native_getParameters();

(4)        private native final void setPreviewDisplay(Surface surface);

(5)        public native final void startPreview();

 

camera中我們發(fā)現(xiàn)應用層代碼調用中都調用了本地(native)方法

 

 

 

android <wbr>camera框架分析與移植



 

 

 

Camera在應用層做了重要的兩件是,初始化一個EventHandler,等待本地消息通知,調用本地方法進入jni層代碼空間,在這里jni的調用方向有兩種:

1):java調用C/C++代碼,將用戶功能性的代碼放到jni層處理

2):C/C++代碼調用java層代碼,將框架層的消息傳遞給應用層處理

 

(2) Camera jni層代碼:

android_hardware_Camera.cpp (frameworks\base\core\jni)      

 

int register_android_hardware_Camera(JNIEnv *env)

{

    field fields_to_find[] = {

        { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },

        { "android/view/Surface",    "mSurface",         "I", &fields.surface }

    };

 

 

//初始化fields_t結構體contextsurface

    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)        return -1;

 

    jclass clazz = env->FindClass("android/hardware/Camera");

//初始化fields_t結構體post_event

    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",

                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");

    if (fields.post_event == NULL) {

        LOGE("Can't find android/hardware/Camera.postEventFromNative");

        return -1;

    }

 

 

    // Register native functions 注冊本地函數(shù)列表

    return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",

                                              camMethods, NELEM(camMethods));

}

 

int register_android_hardware_Camera方法是首先調用的方法,作用是將java層的變量域和方法域存在jni層,jni層調用java層的成員變量和成員方法都要依賴域:

struct fields_t {

    jfieldID    context;// mNativeContext

    jfieldID    surface;// mSurface

    jmethodID   post_event;// postEventFromNative

};

 

 

AndroidRuntime::registerNativeMethods 方法主要是將本地函數(shù)注冊給虛擬機,java層可以通過虛擬機調用這些方法

static JNINativeMethod camMethods[] = {

  { "native_setup",

    "(Ljava/lang/Object;)V",

    (void*)android_hardware_Camera_native_setup },

  { "native_release",

    "()V",

    (void*)android_hardware_Camera_release },

  { "setPreviewDisplay",

    "(Landroid/view/Surface;)V",

    (void *)android_hardware_Camera_setPreviewDisplay },

  { "startPreview",

    "()V",

    (void *)android_hardware_Camera_startPreview },

  { "stopPreview",

    "()V",

    (void *)android_hardware_Camera_stopPreview },

  { "previewEnabled",

    "()Z",

    (void *)android_hardware_Camera_previewEnabled },

  { "setHasPreviewCallback",

    "(ZZ)V",

    (void *)android_hardware_Camera_setHasPreviewCallback },

  { "addCallbackBuffer",

    "([B)V",

    (void *)android_hardware_Camera_addCallbackBuffer },

  { "native_autoFocus",

    "()V",

    (void *)android_hardware_Camera_autoFocus },

  { "native_cancelAutoFocus",

    "()V",

    (void *)android_hardware_Camera_cancelAutoFocus },

  { "native_takePicture",

    "()V",

    (void *)android_hardware_Camera_takePicture },

  { "native_setParameters",

    "(Ljava/lang/String;)V",

    (void *)android_hardware_Camera_setParameters },

  { "native_getParameters",

    "()Ljava/lang/String;",

    (void *)android_hardware_Camera_getParameters },

  { "reconnect",

    "()V",

    (void*)android_hardware_Camera_reconnect },

  { "lock",

    "()V",

    (void*)android_hardware_Camera_lock },

  { "unlock",

    "()V",

    (void*)android_hardware_Camera_unlock },

  { "startSmoothZoom",

    "(I)V",

    (void *)android_hardware_Camera_startSmoothZoom },

  { "stopSmoothZoom",

    "()V",

    (void *)android_hardware_Camera_stopSmoothZoom },

};

 

JNINativeMethod列出java層方法和c/c++層方法的映射表:

 

 

android <wbr>camera框架分析與移植

 

 

1android_hardware_Camera_native_setup方法

 

這個方法主要作用是建立如圖的聯(lián)系:

 

android <wbr>camera框架分析與移植

 sp<Camera> camera = Camera::connect();//初始化三組proxy/stub聯(lián)系

    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);

    context->incStrong(thiz);

    camera->setListener(context);//初始化mListener

    env->SetIntField(thiz, fields.context, (int)context.get());

 

  

隨后產(chǎn)生server和HAL之間的聯(lián)系:

 

android <wbr>camera框架分析與移植

void CameraService::Client::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr, void* user)

{

    LOGV("dataCallback(%d)", msgType);

 

    sp<Client> client = getClientFromCookie(user);

    if (client == 0) {

        return;

    }

 

    sp<ICameraClient> c = client->mCameraClient;

    if (dataPtr == NULL) {

        LOGE("Null data returned in data callback");

        if (c != NULL) {

            c->notifyCallback(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);

            c->dataCallback(msgType, NULL);

        }

        return;

    }

       CAMERA_MSG_SHUTTER

 

    switch (msgType) {

        case CAMERA_MSG_PREVIEW_FRAME:

            client->handlePreviewData(dataPtr);//處理預覽數(shù)據(jù)函數(shù)

            break;

        case CAMERA_MSG_POSTVIEW_FRAME:

            client->handlePostview(dataPtr);

            break;

        case CAMERA_MSG_RAW_IMAGE: //處理未壓縮照片函數(shù)

            client->handleRawPicture(dataPtr);

            break;

        case CAMERA_MSG_COMPRESSED_IMAGE: //處理壓縮處理的照片函數(shù)

            client->handleCompressedPicture(dataPtr);

            break;

        default:

            if (c != NULL) {

                c->dataCallback(msgType, dataPtr);

            }

            break;

    }

 

#if DEBUG_CLIENT_REFERENCES

    if (client->getStrongCount() == 1) {

        LOGE("++++++++++++++++ (DATA CALLBACK) THIS WILL CAUSE A LOCKUP!");

        client->printRefs();

    }

#endif

}

 

Linux中使用V4L2最為攝像頭驅動,V4L2在用戶空間通過各種ioctl調用進行控制,并且可以使用mmap進行內(nèi)存映射

 android <wbr>camera框架分析與移植

 

ioctl函數(shù)命令參數(shù)如下:

 .vidioc_querycap  = vidioc_querycap,  //查詢驅動功能 
 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,  //獲取當前驅動支持的視頻格式 
 .vidioc_g_fmt_vid_cap  = vidioc_g_fmt_vid_cap,  //讀取當前驅動的頻捕獲格式 
 .vidioc_s_fmt_vid_cap  = vidioc_s_fmt_vid_cap,   //設置當前驅動的頻捕獲格式 
 .vidioc_try_fmt_vid_cap  = vidioc_try_fmt_vid_cap,  //驗證當前驅動的顯示格式 
 .vidioc_reqbufs   = vidioc_reqbufs,   //分配內(nèi)存 
 .vidioc_querybuf  = vidioc_querybuf,  //把VIDIOC_REQBUFS中分配的數(shù)據(jù)緩存轉換成物理地址 
 .vidioc_qbuf   = vidioc_qbuf,  //把數(shù)據(jù)從緩存中讀取出來 
 .vidioc_dqbuf   = vidioc_dqbuf,   //把數(shù)據(jù)放回緩存隊列 
 .vidioc_streamon  = vidioc_streamon,  //開始視頻顯示函數(shù) 
 .vidioc_streamoff  = vidioc_streamoff,   //結束視頻顯示函數(shù) 

 .vidioc_cropcap   = vidioc_cropcap,   //查詢驅動的修剪能力 
 .vidioc_g_crop   = vidioc_g_crop,     //讀取視頻信號的矩形邊框
 .vidioc_s_crop   = vidioc_s_crop,     //設置視頻信號的矩形邊框  .vidioc_querystd  = vidioc_querystd,   //檢查當前視頻設備支持的標準,例如PAL或NTSC。 
 .vidioc_default   = vidioc_default,

 

 android <wbr>camera框架分析與移植

 

HAL首先:初始化的時候進行camera基礎參數(shù)的設置,然后調用mmap系統(tǒng)調用將camera驅動層的數(shù)據(jù)隊列映射到用戶空間,

其次:當預覽方法被調用的時候啟動預覽線程,循環(huán)的檢測隊列中是否有幀數(shù)據(jù),如果幀數(shù)據(jù)存在,讀取幀數(shù)據(jù),由于讀取的數(shù)據(jù)為YUV格式的數(shù)據(jù),所有要將YUV數(shù)據(jù)轉換成RGB的送給顯示框架顯示,也可以將轉換過的數(shù)據(jù)送給視頻編碼模塊,編碼成功后儲存變成錄像的功能,

最后:當用戶使用拍照的功能的時候,拍照線程被調用(非循環(huán)),檢測隊列中的幀數(shù)據(jù),將幀數(shù)據(jù)從隊列中取出,拍照的數(shù)據(jù)一定需要傳到JAVA層,所有可以將數(shù)據(jù)轉換成JPEG格式再上傳,也可以轉換成RGB的數(shù)據(jù)上傳給java層

所有上傳的數(shù)據(jù)處理都要經(jīng)過dataCallback,除非實現(xiàn)了overlay

 

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多