1. 程式人生 > >Android攝像頭相關原始碼分析: 裝置驅動, HAL, Framework

Android攝像頭相關原始碼分析: 裝置驅動, HAL, Framework

Hardware的分析可以自底向上, 首先看V4L2Camera, 再看CameraHardware, 再到CameraFactory. Framework的程式碼自底向上看東西就太多了, 因此先從SDK中的攝像頭部分看起. HAL和Framework說的都是C++的東西, 實現了安卓的底層. 但是實際上在開發app的時候用是SDK是JAVA語言編寫的. 我們知道JAVA可以通過JNI來呼叫C++程式碼, 接下來就來看看ADK中是如何使用的.

首先考慮一段呼叫攝像頭預覽的程式碼:

Camera cam = Camera.open();           // 獲取一個攝像頭例項
cam.setPreviewDisplay(
surfaceHolder); // 設定預覽視窗 cam.startPreview(); // 開始預覽

第一行開啟的是預設攝像頭, 也可以換成 Camera.open(1) 開啟其他攝像頭, 這幾個函式的定義在ADK中位於Camera.java中, open函式為:

frameworks/base/core/java/android/hardware/Camera.java

public static Camera open(int cameraId) {
    return new Camera(cameraId);
}

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; }

可以看到, 直接open不加任何引數開啟的其實是第一個後置攝像頭. 總之最後open返回了一個Camera物件. 這裡看到了一個熟悉的函式getNumberOfCameras, 在HAL中的camera_module_t中, 除了必須的hw_module_t, 還有兩個函式指標 get_number_of_cameras 和get_camera_info, 估計這個 getNumberOfCameras 最終就是呼叫了get_number_of_cameras. 於是來看這個函式:

/**
 * Returns the number of physical cameras available on this device.
 */
public native static int getNumberOfCameras();

這個函式在Camera.java中只有一個宣告, 表明這是一個native函式, 於是就要找其對應的JNI的定義.

frameworks/base/core/jni/android_hardware_Camera.cpp

static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz)
{
    return Camera::getNumberOfCameras();
}

再來找這個C++中的Camera類, 這個類已經位於android framework中了, 但是getNumberOfCameras的定義其實是在它的父類CameraBase中:

frameworks/av/camera/CameraBase.cpp

template <typename TCam, typename TCamTraits>
int CameraBase<TCam, TCamTraits>::getNumberOfCameras() {
    const sp<ICameraService> cs = getCameraService();

    if (!cs.get()) {
        // as required by the public Java APIs
        return 0;
    }
    return cs->getNumberOfCameras();
}

可以看到這裡只是簡單的獲取CameraService, 然後呼叫其getNumberOfCameras 函式, 再來看這個函式:

frameworks/av/camera/CameraBase.cpp

template <typename TCam, typename TCamTraits>
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
    Mutex::Autolock _l(gLock);
    if (gCameraService.get() == 0) {
        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);
        gCameraService = interface_cast<ICameraService>(binder);
    }
    ALOGE_IF(gCameraService == 0, "no CameraService!?");
    return gCameraService;
}

可以看到gCameraService是一個sp<ICameraService>型別的單例, 第一次呼叫這個函式的時候對gCameraService初始化, 以後每次只是簡單地返回這個變數. 在初始化的過程中, 用到了defaultServiceManager獲取了一個sm, 並通過sm->getService獲取到CameraService. defaultServiceManager這個函式位於frameworks/native/lib/binder/IServiceManager.cpp, 屬於binder通訊的一部分, 超出了本文的範圍, 以後有空再寫一篇部落格說明.

open函式呼叫完之後, 就是setPreviewDisplay和startPreiview, 這兩個函式同樣是native的, 其實現類似, 下面就只看看startPreview:

frameworks/base/core/jni/android_hardware_Camera.cpp

static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
    ALOGV("startPreview");
    sp<Camera> camera = get_native_camera(env, thiz, NULL);
    if (camera == 0) return;

    if (camera->startPreview() != NO_ERROR) {
        jniThrowRuntimeException(env, "startPreview failed");
        return;
    }
}

這段程式碼首先獲取了一個Camera物件, 然後對其呼叫startPreview, get_native_camera的實習如下:

sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{
    sp<Camera> camera;
    Mutex::Autolock _l(sLock);
    JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetLongField(thiz, fields.context));
    if (context != NULL) {
        camera = context->getCamera();
    }
    ALOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
    if (camera == 0) {
        jniThrowRuntimeException(env,
                "Camera is being used after Camera.release() was called");
    }

    if (pContext != NULL) *pContext = context;
    return camera;
}

該函式通過env->GetLongField獲取了一個JNICameraContext的物件的指標, 然後就能通過getCamera得到Camera物件了, 而這個JNICameraContext的物件的指標是在native_setup中設定的:

 1: static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
 2:     jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
 3: {
 4:     // Convert jstring to String16
 5:     const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
 6:     jsize rawClientNameLen = env->GetStringLength(clientPackageName);
 7:     String16 clientName(rawClientName, rawClientNameLen);
 8:     env->ReleaseStringChars(clientPackageName, rawClientName);
 9: 
10:     sp<Camera> camera;
11:     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
12:         // Default path: hal version is don't care, do normal camera connect.
13:         camera = Camera::connect(cameraId, clientName,
14:                 Camera::USE_CALLING_UID);
15:     } else {
16:         jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
17:                 Camera::USE_CALLING_UID, camera);
18:         if (status != NO_ERROR) {
19:             return status;
20:         }
21:     }
22: 
23:     if (camera == NULL) {
24:         return -EACCES;
25:     }
26: 
27:     // make sure camera hardware is alive
28:     if (camera->getStatus() != NO_ERROR) {
29:         return NO_INIT;
30:     }
31: 
32:     jclass clazz = env->GetObjectClass(thiz);
33:     if (clazz == NULL) {
34:         // This should never happen
35:         jniThrowRuntimeException(env, "Can't find android/hardware/Camera");
36:         return INVALID_OPERATION;
37:     }
38: 
39:     // We use a weak reference so the Camera object can be garbage collected.
40:     // The reference is only used as a proxy for callbacks.
41:     sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
42:     context->incStrong((void*)android_hardware_Camera_native_setup);
43:     camera->setListener(context);
44: 
45:     // save context in opaque field
46:     env->SetLongField(thiz, fields.context, (jlong)context.get());
47:     return NO_ERROR;
48: }

注意第13行, 通過Camera::connect獲取到了一個Camera物件, 這裡終於又從ADK 層進入到了Framework層.