介紹 Android 的 Camera 框架

jopen 12年前發布 | 102K 次閱讀 Android Android開發 移動開發

總體介紹
Android Camera 框架從整體上看是一個 client/service 的架構,有兩個進程:一個是 client 進
程,可以看成是 AP 端,主要包括 JAVA 代碼與一些 native c/c++代碼;另一個是 service 進
程,屬于服務端,是 native c/c++代碼,主要負責和 linux kernel 中的 camera driver 交互,搜
集 linux kernel 中 camera driver 傳上來的數據,并交給顯示系統(surface)顯示。client 進程與
service 進程通過 Binder 機制通信,       client 端通過調用 service 端的接口實現各個具體的功能。
需要注意的是真正的 preview 數據不會通過 Binder IPC 機制從 service 端復制到 client 端,   但
會通過回調函數與消息的機制將 preview 數據 buffer 的地址傳到 client 端, 最終可在 JAVA AP
中操作處理這個 preview 數據。
         client 端
從 JAVA AP 的角度看 camera ap 就是調用 FrameWork 層的 android.hardware.camera 類來實現
具體的功能。JAVA Ap 最終被打包成 APK。
FrameWork 層主要提供了 android.hardware.camera 類給應用層使用,這個類也是 JAVA 代碼
實 現 。 Android.hardware.camera 類 通 過 JNI 調 用 native 代 碼 實 現 具 體 的 功 能 。
Android.hardware.camera 類中提供了如下的一個參數類給應用層使用:
public class Parameters {
        // Parameter keys to communicate with the camera driver。
        private static final String KEY_PREVIEW_SIZE = "preview-size";
        private static final String KEY_PREVIEW_FORMAT = "preview-format";
        ......
}
參數會以字典(map)的方式組織存儲起來,關鍵字就是 Parameters 類中的這些靜態字符
串。這些參數最終會以形如“preview-size=640X480;preview-format=yuv422sp;....”格式的
字符串傳到 service 端。     源代碼位于:framework/base/core/java/android/hardware/camera.java

提供的接口示例:

獲得一個 android.hardware.camera 類的實例

public static Camera open() {
        return new Camera();
}
 接口直接調用 native 代碼(android_hardware_camera.cpp 中的代碼)
public native final void startPreview();
public native final void stopPreview();
android.hardware.camera 類的 JNI 調用實現在 android_hardware_camera.cpp 文件中,源代碼
位置:  framework/base/core/jni/android_hardware_camera.cpp
(framework/base/core/jni/文件夾下的文件都被編譯進 libandroid_runtime.so 公共庫中  )

android_hardware_camera.cpp 文件中的 JNI 調用實現函數都如下圖:

介紹 Android 的 Camera 框架

android_hardware_camera.cpp 文件中的 register_android_hardware_Camera(JNIEnv env)函數
會將上面的 native 函數注冊到虛擬機中,以供 FrameWork 層的 JAVA 代碼調用。這些 native
函數通過調用 libcamera_client.so 中的 Camera 類實現具體的功能。
核心的 libcamera_client.so 動態庫源代碼位于:   frameworks/base/libs/camera/,  實現了如下幾
個類:
 Camera---->Camera.cpp/Camera.h
 CameraParameters--->CameraParameters.cpp/CameraParameters.h
 Icamera--->ICamera.cpp/ICamera.h
 IcameraClient--->ICameraClient.cpp/ICameraClient.h
 IcameraService--->ICameraService.cpp/ICameraService.h
Icamera、IcameraClient、IcameraService 三個類是按照 Binder IPC 通信要求的框架實現的,用
來與 service 端通信。
類 CameraParameters 接收 FrameWork 層的 android.hardware.camera::Parameters 類為參數,
解析與格式化所有的參數設置。
Camera 是一個很重要的類,     它與 CameraService 端通過 Binder IPC 機制交互來實現具體功能。
Camera 繼承自 BnCameraClient,并最終繼承自 ICameraClient。
Camera 類通過:
sp sm = defaultServiceManager();
sp binder = sm->getService(String16("media.camera"));
sp mCameraService = interface_cast (binder);
得到名字為“media.camera”的 CameraService。通過調用 CameraService 的接口 connect()返
回得到 sp mCamera,并在 CameraService 端 new 一個 CameraService::Client 類
mClient。mClient 繼承自 BnCamera,并最終繼承自 ICamera。
之 后 Camera 類 通 過 這 個 sp mCamera 對 象 調 用 函 數 就 像 直 接 調 用
CameraService::Client 類 mClient 的函數。CameraService::Client 類實現具體的功能。
          service 端

實現在動態庫 libcameraservice.so 中,  源代碼位于:  frameworks/base/camera/libcameraservice

Libcameraservice.so 中主要有下面兩個類:
Libcameraservice.so::CameraService 類 , 繼 承 自 BnCameraService , 并 最 終 繼 承 自
     ICameraService
  Libcameraservice.so::CameraService::Client 類, 繼承自 BnCamera,    并最終繼承自 ICamera
CameraService::Client 類通過調用 Camera HAL 層來實現具體的功能。目前的 code 中只支持
一個 CameraService::Client 實例。
Camera Service 在 系 統 啟 動 時 new 了 一 個 實 例 , 以 “ media.camera ” 為 名 字 注 冊 到
ServiceManager 中。在 init.rc 中有如下代碼執行可執行文件/system/bin/mediaserver,啟動多
媒體服務進程。
service media /system/bin/mediaserver
Mediaserver 的 c 代碼如下:
int main(int argc,char** argv)
{
    sp proc(ProcessState::self());
    sp sm = defaultServiceManager();
    LOGI("ServiceManager: %p",sm。get());
    AudioFlinger::instantiate();
    MediaPlayerService::instantiate();
    CameraService::instantiate();
    AudioPolicyService::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}
                                          
 Camera HAL(硬件抽象層)
Libcameraservice.so::CameraService::Client 類調用 camera HAL 的代碼實現具體功能,camera
HAL 一般實現為一個動態庫 libcamera.so(動態庫名字可以改,只需要與 Android.mk 一致即
可)。Android 只給了一個定義文件:
/home/miracle/Work/android/android_src/froyo/frameworks/base/include/camera/CameraHard
wareInterface.h
class CameraHardwareInterface : public virtual RefBase {
public:
     virtual ~CameraHardwareInterface() { }
     virtual sp getPreviewHeap() const = 0;
     virtual sp getRawHeap() const = 0;
     virtual void setCallbacks(notify_callback notify_cb,data_callback data_cb,
                     data_callback_timestamp data_cb_timestamp,void
user) = 0;
     virtual void       enableMsgType(int32_t msgType) = 0;
     virtual void       disableMsgType(int32_t msgType) = 0;
     virtual bool       msgTypeEnabled(int32_t msgType) = 0;
     virtual status_t startPreview() = 0;
     virtual bool        useOverlay() {return false;}
     virtual status_t setOverlay(const sp &overlay) {return BAD_VALUE;}
     virtual void         stopPreview() = 0;
     virtual bool         previewEnabled() = 0;
     virtual status_t      startRecording() = 0;
     virtual bool         recordingEnabled() = 0;
     virtual status_t      autoFocus() = 0;
     virtual status_t      cancelAutoFocus() = 0;
     virtual status_t      takePicture() = 0;
     virtual status_t      cancelPicture() = 0;
     virtual status_t      setParameters(const CameraParameters& params) = 0;
     virtual CameraParameters getParameters() const = 0;
     virtual status_t sendCommand(int32_t cmd,int32_t arg1,int32_t arg2) = 0;
     virtual void release() = 0;
     virtual status_t dump(int fd,const Vector & args) const = 0;
};
extern "C" sp openCameraHardware();
}; // namespace android
可以看到在 JAVA Ap 中的功能調用最終會調用到 HAL 層這里,Camera HAL 層的實現是主要
的工作,      它一般通過 V4L2 command 從 linux kernel 中的 camera driver 得到 preview 數據。然
后交給 surface(overlay)顯示或者保存為文件。在 HAL 層需要打開對應的設備文件,并通過
ioctrl 訪問 camera driver。Android 通過這個 HAL 層來保證底層硬件(驅動)改變,只需修改
對應的 HAL 層代碼,FrameWork 層與 JAVA Ap 的都不用改變。
           Preview 數據流程
Android 框架中 preview 數據的顯示過程如下:
1、 打開內核設備文件。CameraHardwareInterface.h 中定義的 openCameraHardware()打開
      linux kernel 中的 camera driver 的設備文件(如/dev/video0)      ,創建初始化一些相關的類
      的實例。
2、 設置攝像頭的工作參數。CameraHardwareInterface.h 中定義的 setParameters()函數,在
      這一步可以通過參數告訴 camera HAL 使用哪一個硬件攝像頭,  以及它工作的參數  (size,
    format 等) ,并在 HAL 層分配存儲 preview 數據的 buffers(如果 buffers 是在 linux kernel
    中的 camera driver 中分配的,在這一步也會拿到這些 buffers mmap 后的地址指針)                      。
3、 設置顯示目標。需在 JAVA APP 中創建一個 surface 然后傳遞到 CameraService 中。會調
    用到 libcameraservice.so 中的 setPreviewDisplay(const sp & surface)函數中。在
    這里分兩種情況考慮:一種是不使用 overlay;一種是使用 overlay 顯示。如果不使用
    overlay 那設置顯示目標最后就在 libcameraservice.so 中,不會進 Camera HAL 動態庫。
    并將上一步拿到的 preview 數據 buffers 地址注冊到 surface 中。 如果使用 overlay 那在
    libcameraservice.so 中會通過傳進來的 Isurface 創建 Overlay 類的實例,然后調用
    CameraHardwareInterface.h 中定義的 setOverlay()設置到 Camera HAL 動態庫中。
4、 開始 preview 工作。最終調用到 CameraHardwareInterface.h 中定義的 startPreview()函數。
    如果不使用 overlay,Camera HAL 得到 linux kernel 中的 preview 數據后回調通知到
    libcameraservice.so 中。在 libcameraservice.so 中會使用上一步的 surface 進行顯示。如
    果使用 overlay,    Camera HAL 得到 linux kernel 中的 preview 數據后直接交給 Overlay 對象,
    然后有 Overlay HAL 去顯示。
         模擬器中的虛擬 camera
如果沒有 camera 硬件,不實現真正的 Camera HAL 動態庫,可以使用虛擬 camera。源代碼
位于:
frameworks/base/camera/libcameraservice/FakeCamera.cpp
frameworks/base/camera/libcameraservice/CameraHardwareStub.cpp
FakeCamera.cpp 文件提供虛擬的 preview 數據。CameraHardwareStub.cpp 文件中實現了
camera HAL(硬件抽象層)的功能。當宏 USE_CAMERA_STUB 為 true 時可以使用這個虛擬的
camera。
ifeq ($(USE_CAMERA_STUB),true)
    LOCAL_STATIC_LIBRARIES += libcamerastub //虛擬的 camera
#if want show LOGV message,should use follow define。 add 0929
#LOCAL_CFLAGS += -DLOG_NDEBUG=0
    LOCAL_CFLAGS += -include CameraHardwareStub。h
else
    LOCAL_SHARED_LIBRARIES += libcamera //真正的 camera HAL 庫
endif

           框架圖

介紹 Android 的 Camera 框架

           Overlay 簡單介紹
overlay 一般用在 camera preview,視頻播放等需要高幀率的地方,還有可能 UI 界面設計
的需求, 如map 地圖查看軟件需兩層顯示信息。 overlay 需要硬件與驅動的支持。  Overlay 沒
有 java 層的 code,也就沒有 JNI 調用。一般都在 native 中使用。
Overlay 的使用方法
1. 頭文件
overlay object 對外的接口
#include
下面三個用于從 HAL 得到 overlay object
#include
#include
#include
   2.  相關動態庫文件
libui.so
libsurfaceflinger_client.so
    3.  調用步驟
  創建 surfaceflinger 的客戶端
sp client = new SurfaceComposerClient();
   創建推模式 surface
sp surface = client->createSurface(getpid(),0,320,240,
PIXEL_FORMAT_UNKNOWN,IsurfaceComposer::ePushBuffers);
  獲得 surface 接口
sp isurface = surface->getISurface();
   獲得 overlay 設備
sp ref = isurface->createOverlay(320,240,PIXEL_FORMAT_RGB_565);
這里會通過調用 overlay hal 層的 createoverlay()打開對應的設備文件。
  創建 overlay 對象
sp overlay = new Overlay(ref);
   使用 overlay API
overlay_buffer_t buffer; //typedef void* overlay_buffer_t;
void* address = overlay->getBufferAddress(buffer);
address 指針就是 mmap 后的 overlay buffer 指針,   只需將數據填充到這個 address 指針就可
以看到畫面了。
Android overlay 框架
介紹 Android 的 Camera 框架
overlay 本地框架代碼
源代碼位于:frameworks/base/libs/ui/ ,編譯到 libui.so 中。
  Overlay.cpp : 提 供 給 外 部 程 序 調 用 的 Overlay object 接 口 與 API 。 定 義 在
      frameworks/base/include/ui/Overlay.h 中。實現了兩個類:OverlayRef 與 Overlay。外部
      程序通過這個 Overlay 對象來使用 overlay 的功能。Overlay.cpp 內部通過 binder 與
      surfaceFlinger service 通信,最終調用到 Overlay HAL。
 IOVerlay.cpp:  定義提供 binder 所需的類,        其中 LayerBuffer::OverlaySource::OverlayChannel
  繼承自 BnOverlay。
overlay 的服務部分代碼
源代碼位于:frameworks/base/libs/surfaceflinger/
overlay 系統被包在 Surface 系統中, 通過 surface 來控制 overlay 或者在不使用 overlay 的情
況下統一的來管理。所以 overlay 的 service 部分也包含在 SurfaceFlinger service 中,主要的
類 LayerBuffer。
android 啟動的時候會啟動 SurfaceFlinger service,SurfaceFlinger 啟動時會實例化一個
DisplayHardware:
DisplayHardware* const hw = new DisplayHardware(this,dpy);
DisplayHardware 構造函數調用函數 init:
DisplayHardware::DisplayHardware(const sp & flinger,
                                         uint32_t dpy)
: DisplayHardwareBase(flinger,dpy)
{
  init(dpy);
}
Init 函數中:
if(hw_get_module(OVERLAY_HARDWARE_MODULE_ID,&module) == 0) {
     overlay_control_open(module,&mOverlayEngine);
}
獲得 overlay 的 module 參數,       調用 overlay_control_open 獲取控制設備結構 mOverlayEngine。
擁有了控制設備結構體就可以創建數據設備結構體 ,并具體控制使用 overlay 了。
overlay HAL 層
源代碼位于:hardware/libhardware/include/hardware/overlay.h
android 只給出了接口的定義,需要我們自己實現具體的功能。 overlay hal 層生成的動態庫
在 SurfaceFlinger 中顯式的加載。Overlay HAL 層具體功能如何實現取決于硬件與驅動程序。
Android 提供了一個 Overlay Hal 層實現的框架代碼,                hardware/libhardware/modules/overlay/。
因為 overlay hal 層生成的動態庫是顯式的動態打開(hw_get_module -> dlopen),所以這個庫
文件必須放在文件系統的 system/lib/hw/下。
多層 overlay
例如需要同時支持 overlay1 與 overlay2。
 1. overlay hal 的 overlay_control_device_t 中要添加 overlay1 與 overlay2 的結構:
struct overlay_control_context_t {
   struct overlay_control_device_t device;
   /* our private state goes below here */
   struct overlay_t* overlay_video1;//overlay1
   struct overlay_t* overlay_video2;//overlay2
};
每個 overlay_t 代表一層 overlay,每層 ovelay 有自己的 handle。
在構造 OverlayRef 之前需指明使用哪一層 overlay:
sp ref = isurface->createOverlay(320,240,PIXEL_FORMAT_RGB_565);
可以使用自定義參數調用 overlay_control_device_t::setParameter()來指定 Hal 層具體實現。
2,通過 Overlay object 來拿到 overlay1 與 overlay2 的 buffer 指針。
</overlayref> </isurface> </surface> </surfacecomposerclient> </surfaceflinger> </surfaceflinger> </surfaceflinger> </ui> </isurface> </camerahardwareinterface> </string16> </overlay> </imemoryheap> </imemoryheap> </iservicemanager> </processstate> </icamera> </icamera> </icameraservice> </icameraservice> </ibinder> </iservicemanager>

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!