1. 程式人生 > >android之camera從上到下

android之camera從上到下

      如果你想了解一下android的camera的大致框架內容看看我附帶的圖片就可以達到要求。不過圖片畢竟比較抽象,還是然我們看下原始碼吧!
      原始碼從APP到硬體抽象層,以這中從上到下的呼叫流程非常清晰。大家可以很容易看懂。我想帶大家看的是camera從攝像頭捕獲一幀資料如何送到android的surface並且顯示出來的。在framework\base\libs\camera.cpp 中有setPreviewDisplay,當然這個Surface是從應用層的Surface.java一步一步傳進來的。Camera.java(activity)裡面的startPreview函式就是開始預覽的,這裡就呼叫了setPreviewDisplay(mSurfaceHolder);至於SurfaceHolder是什麼東西不用我多說了。再到Camera.java(hardware)這個實際就是與jni的介面了
這裡面就會通過Holder來獲取Surface,然後通過jni將Surface設定進來:
static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)
{
    LOGV("setPreviewDisplay");
    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));
    }
    if (camera->setPreviewDisplay(surface) != NO_ERROR) {
        jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");
    }
}
從程式碼可以看到surface是做了一些變化的,surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));具體你看下Surface.java就知道了,這個Surface實際是native層的surface(class Surface : public EGLNativeBase<ANativeWindow, Surface, RefBase>);回到jni來,緊接著就將這個Surface設到了camera的客戶端了(BnCameraClient)這個可以看圖。
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);
    }
}
這裡又對呼叫了getISurface來獲取另一個surface,此處的surface才是真做事的surface,管理它的正是surfaceFlinger,這個會在下一篇部落格中解釋。在這裡可以說這個Surface其實就是SurfaceLayer(繼承自LayerBaseClient::Surface),回到BnCameraClient,繼續呼叫BnCamera的setPreviewDisplay將surface進行了儲存mSurface = surface;
   來到startPreview可以看到會點呼叫mHardware->startPreview();然後registerPreviewBuffers;對於mHardware它是不同的廠家來實現的,就是開了一個執行緒不斷的從camera感測器獲取資料,至於registerPreviewBuffers是關鍵,它將CameraHardware裡面的記憶體(儲存幀資料的快取)註冊到了Surface。仔細看的話你會發現這寫記憶體可以儲存8幀(不同廠家不一樣)它是一塊類似環形的buffer。看過程式碼的人應該都知道,在預覽之前我們會先設定兩個回撥dataCallback和dataCallbackTimestamp,這兩個的區別在於前者用於預覽,而後者用於錄製。我們看dataCallback:
void CameraService::Client::dataCallback(int32_t msgType,
        const sp<IMemory>& dataPtr, void* user) {
    LOG2("dataCallback(%d)", msgType);

    sp<Client> client = getClientFromCookie(user);
    if (client == 0) return;
    if (!client->lockIfMessageWanted(msgType)) return;

    if (dataPtr == 0) {
        LOGE("Null data returned in data callback");
        client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
        return;
    }

    switch (msgType) {
        case CAMERA_MSG_PREVIEW_FRAME:
            client->handlePreviewData(dataPtr);
            break;
        case CAMERA_MSG_POSTVIEW_FRAME:
            client->handlePostview(dataPtr);
            break;
        case CAMERA_MSG_RAW_IMAGE:
            client->handleRawPicture(dataPtr);
            break;
        case CAMERA_MSG_COMPRESSED_IMAGE:
            client->handleCompressedPicture(dataPtr);
            break;
        default:
            client->handleGenericData(msgType, dataPtr);
            break;
    }
}
因為是Preview所以會到  client->handlePreviewData(dataPtr);而這個裡面會有這樣一句話mSurface->postBuffer(offset);看到了吧,就是說標號為offset的這塊記憶體有資料拉,通知surfaceFlinger重新整理這塊記憶體將畫面繪製到使用者可見的Surface上面去。

先就這樣吧,下回繼續。