Camera显示之Hal层的适配

http://blog.csdn.net/wsb1321/article/details/21975951

Camera显示之Framework层设置显示窗口

接着上一篇:

Camera显示之app实现简单camera

mCamera.setPreviewDisplay(mSurfaceHolder);函数往下分析。 


一.调用关系图:



二.1.mCamera为:android.hardware.Camera。

最终:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {  
  2.        if (holder != null) {  
  3.            setPreviewDisplay(holder.getSurface());  
  4.        } else {  
  5.            setPreviewDisplay((Surface)null);  
  6.        }  
  7.    }  
  8.   
  9.   private native final void setPreviewDisplay(Surface surface) throws IOException;  


2.调用到jni层:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface)  
  2.   
  3.   
  4. {  
  5.     ALOGV("setPreviewDisplay");  
  6.     sp<Camera> camera = get_native_camera(env, thiz, NULL);//这里是拿到一个和CameraService通信的客户端。目的是和CameraService进行通信  
  7.     if (camera == 0) return;  
  8.   
  9.     sp<Surface> surface = NULL;  
  10.     if (jSurface != NULL) {  
  11.         surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));//将java层的Surface转化成native的Surface对象指针。  
  12.     }  
  13.        if (camera->setPreviewDisplay(surface) != NO_ERROR) {//通过CameraService的客户端最终和CameraService进行通信。  
  14.         jniThrowException(env, "java/io/IOException""setPreviewDisplay failed");  
  15.     }  
  16.     }  
  17. }  


我们来关注下:camera->setPreviewDisplay(surface)中的camera是如何获取的?

1).jni层

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // connect to camera service  
  2. static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,  
  3.     jobject weak_this, jint cameraId)//在Cameraopen的时候会调用  
  4. {  
  5.     sp<Camera> camera = Camera::connect(cameraId); //调用Camera的静态方法连接获取的。  
  6.   
  7.     if (camera == NULL) {  
  8.         jniThrowRuntimeException(env, "Fail to connect to camera service");  
  9.         return;  
  10.     }  
  11.   
  12.     // make sure camera hardware is alive  
  13.     if (camera->getStatus() != NO_ERROR) {  
  14.         jniThrowRuntimeException(env, "Camera initialization failed");  
  15.         return;  
  16.     }  
  17.   
  18.     jclass clazz = env->GetObjectClass(thiz);  
  19.     if (clazz == NULL) {  
  20.         jniThrowRuntimeException(env, "Can't find android/hardware/Camera");  
  21.         return;  
  22.     }  
  23.   
  24.     // We use a weak reference so the Camera object can be garbage collected.  
  25.     // The reference is only used as a proxy for callbacks.  
  26. //!++  
  27. #ifdef  MTK_CAMERA_BSP_SUPPORT  
  28.     sp<JNICameraContext> context = new MtkJNICameraContext(env, weak_this, clazz, camera);//将camera通过MtkJNICameraContext保存到这个实例, 要用的时候直接通过这个类实例获取。  
  29. #else  
  30.     sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);//Android原生的也是这个涉及思路。  



2).Camera.cpp

继续1)中:sp<Camera> camera = Camera::connect(cameraId);

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<Camera> Camera::connect(int cameraId)  
  2. {  
  3.     ALOGV("connect");  
  4.     sp<Camera> c = new Camera();  
  5.     const sp<ICameraService>& cs = getCameraService();//获取CameraService实例指针:  
  6.     if (cs != 0) {  
  7.         c->mCamera = cs->connect(c, cameraId);//调用CameraService的connect的方法。  
  8.     }  
  9.     if (c->mCamera != 0) {  
  10.         c->mCamera->asBinder()->linkToDeath(c);  
  11.         c->mStatus = NO_ERROR;  
  12.     } else {  
  13.         c.clear();  
  14.     }  
  15.     return c;  
  16. }  


3). CameraService.cpp


由于此方法代码较多, 我们只关注部分关键点:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<ICamera> CameraService::connect(  
  2.         const sp<ICameraClient>& cameraClient, int cameraId) {  
  3. #ifdef  MTK_CAMERAPROFILE_SUPPORT  
  4.     initCameraProfile();  
  5.     AutoCPTLog cptlog(Event_CS_connect);  
  6. #endif  
  7.     int callingPid = getCallingPid();  
  8.   
  9.     LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);  
  10. .............................  
  11.   
  12. ............................  
  13.   
  14.  int deviceVersion;  
  15.     if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {  
  16.         deviceVersion = info.device_version;  
  17.     } else {  
  18.         deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;  
  19.     }  
  20.   
  21.     switch(deviceVersion) {//从这个里面可以看到client是CameraClient  
  22.       case CAMERA_DEVICE_API_VERSION_1_0:  
  23.         client = new CameraClient(this, cameraClient, cameraId,  
  24.                 info.facing, callingPid, getpid());//Android原生设计。  
  25.         break;  
  26.       case CAMERA_DEVICE_API_VERSION_2_0://这里应该是MTK自己进行了扩展。  
  27.         client = new Camera2Client(this, cameraClient, cameraId,  
  28.                 info.facing, callingPid, getpid());  
  29.         break;  
  30.       default:  
  31.         ALOGE("Unknown camera device HAL version: %d", deviceVersion);  
  32.         return NULL;  
  33.     }  
  34.   
  35. .....................................................  
  36.   
  37. ....................................................  
  38.   
  39.   
  40.     mClient[cameraId] = client;  
  41.     LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());  
  42.     return client;//最终返回的是client, 也即是CameraClient。  
  43.   
  44. }  



通过以上的调用关系, 可以知道camera->setPreviewDisplay(surface)调用到了CameraClient中的对应的方法, 注意这里已经是两个不同的进程了(一个是app进程, 一个是CameraService所在的mediaserver进程), 在jni层通过Camera.cpp里面实现的客户端通过Binder机制连接到CameraService端, 后面的通信都是通过Binder来进行,而不是直接调用。


3.CameraService端:

继续2中的camera->setPreviewDisplay(surface):

可以知道最终会通过Binder调用到CameraClient端。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // set the Surface that the preview will use  
  2. status_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) {  
  3. #ifdef  MTK_CAMERAPROFILE_SUPPORT  
  4.     AutoCPTLog cptlog(Event_CS_setPreviewDisplay);  
  5. #endif  
  6.     LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());  
  7.   
  8.     sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);  
  9.     sp<ANativeWindow> window(surface);//将Surface么与ANativeWindow绑定。  
  10.     return setPreviewWindow(binder, window);  
  11. }  
  12.   
  13. status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,  
  14.         const sp<ANativeWindow>& window) {  
  15.     Mutex::Autolock lock(mLock);  
  16.     status_t result = checkPidAndHardware();  
  17.     if (result != NO_ERROR) return result;  
  18.   
  19.     // return if no change in surface.  
  20.     if (binder == mSurface) {  
  21.         return NO_ERROR;  
  22.     }  
  23.   
  24.     if (window != 0) {  
  25.         result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);  
  26.         if (result != NO_ERROR) {  
  27.             ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),  
  28.                     result);  
  29.             return result;  
  30.         }  
  31.     }  
  32.   
  33.     // If preview has been already started, register preview buffers now.  
  34.     if (mHardware->previewEnabled()) {  
  35.         if (window != 0) {  
  36.             native_window_set_scaling_mode(window.get(),  
  37.                     NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);  
  38.             native_window_set_buffers_transform(window.get(), mOrientation);  
  39.             result = mHardware->setPreviewWindow(window);  
  40.         }  
  41.     }  
  42.     //!++  
  43.     else if ( window == 0 ) {  
  44.         result = mHardware->setPreviewWindow(window);//将window设置到hal层, Android代码架构真正的实现就止于此,hal层的东西就看具体厂家根据自身情况进行实现了。  
  45.     }  
  46.     //!--  
  47.   
  48.     if (result == NO_ERROR) {  
  49.         // Everything has succeeded.  Disconnect the old window and remember the  
  50.         // new window.  
  51.         disconnectWindow(mPreviewWindow);  
  52.         mSurface = binder;  
  53.         mPreviewWindow = window;  
  54.     } else {  
  55.         // Something went wrong after we connected to the new window, so  
  56.         // disconnect here.  
  57.         disconnectWindow(window);  
  58.     }  
  59.   
  60.     return result;  
  61.   
  62. }  


三. 关键点, 这里jni层后涉及到camera所在的app进程和CameraService所在mediaserver两个不同的进程, 他们之间会通过Binder进行通信。 对于这部分, 后面会继续和大家分享。

在CameraService的下一层就是hal层了, 这部分是各个厂家根据自己芯片的特色进行设计构建的。 所以这下面的实现肯定多种多样, 但是可以从去学习代码架构, 看看一帧数据是如何一步一步的进行显示的。


通过上面我们可以看到, 对于显示部分, 我们其实只是设置了一个surface, 在中间层, 又和 ANativeWindow的绑定, 最后完全交个hal层去实现。

后面的分析, 我会以ktm平台的实现去分析。


本篇接着上一篇:

Camera显示之Framework层设置显示窗口

话说上一篇说道

else if ( window == 0 ) {  

        result = mHardware->setPreviewWindow(window);//将window设置到hal层, Android代码架构真正的实现就止于此,hal层的东西就看具体厂家根据自身情况进行实现了。   } 


那究竟mHardware是如何和hal联系起来的的呢?


1.在CameraClient.cpp中:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t CameraClient::initialize(camera_module_t *module) {  
  2.     int callingPid = getCallingPid();  
  3.     LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);  
  4.   
  5.     char camera_device_name[10];  
  6.     status_t res;  
  7.     snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);  
  8.   
  9.     mHardware = new CameraHardwareInterface(camera_device_name);//<span style="color:#FF0000;">注意到此处。</span>  
  10.     res = mHardware->initialize(&module->common);//<span style="color:#FF0000;">注意此处</span>  
  11.     if (res != OK) {  
  12.         ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",  
  13.                 __FUNCTION__, mCameraId, strerror(-res), res);  
  14.         mHardware.clear();  
  15.         return NO_INIT;  
  16.     }  
  17.   
  18.     mHardware->setCallbacks(notifyCallback,  
  19.             dataCallback,  
  20.             dataCallbackTimestamp,  
  21.             (void *)mCameraId);  
  22.   
  23.     // Enable zoom, error, focus, and metadata messages by default  
  24.     enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |  
  25.                   CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);  
  26.   
  27. //!++  
  28. #ifdef  MTK_CAMERA_BSP_SUPPORT  
  29.     // Enable MTK-extended messages by default  
  30.     enableMsgType(MTK_CAMERA_MSG_EXT_NOTIFY | MTK_CAMERA_MSG_EXT_DATA);  
  31. #endif  
  32. //!--  
  33.   
  34.     LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);  
  35.     return OK;  
  36. }  

从代码片段:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. mHardware = new CameraHardwareInterface(camera_device_name);//注意到此处。  

mHardware 定义是 CameraHardwareInterface, 他也是Android的通用接口。 各个厂家提供的功能都要通过CameraHardwareInterface适配向CameraService提供硬件操作接口。

这篇的主题就是主要分享CameraHardwareInterface如何进行适配的。

2. 接着1中的代码片段:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. res = mHardware->initialize(&module->common);//涉及到module,module即为CameraClient::initialize(camera_module_t *module)传进来的参数, 为一个结构体变量的指针。  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CameraClient::initialize(camera_module_t *module)调用的地方为CameraService中connect camera的时候调用:  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. sp<ICamera> CameraService::connect(  
  2.         const sp<ICameraClient>& cameraClient, int cameraId) {  
  3. #ifdef  MTK_CAMERAPROFILE_SUPPORT  
  4.     initCameraProfile();   
  5.     AutoCPTLog cptlog(Event_CS_connect);  
  6. #endif  
  7.     int callingPid = getCallingPid();  
  8.   
  9.     LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);  
  10.   
  11.     if (!mModule) {  
  12.         ALOGE("Camera HAL module not loaded");  
  13. ...........................  
  14. ............................  
  15.   
  16. #endif  
  17.   
  18.     if (client->initialize(mModule) != OK) {//在这里调用CameraClient的initialize, 而传入的参数为mModule。  
  19. #ifdef  MTK_CAMERAPROFILE_SUPPORT  
  20.         CPTLogStr(Event_CS_newCamHwIF, CPTFlagEnd,  "new CameraHardwareInterface failed");  
  21. #endif    
  22. #ifdef  MTK_CAMERA_BSP_SUPPORT  

所以这里我们就关注下mModule这成员, mModule的定义:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Mutex               mSoundLock;  
  2. sp<MediaPlayer>     mSoundPlayer[NUM_SOUNDS];  
  3. int                 mSoundRef;  // reference count (release all MediaPlayer when 0)  
  4.   
  5. camera_module_t *mModule;//  

为一个camera_module_t结构体变量的指针。

Camera最先被使用到的地方是在onFirstRef()函数中, 在这里主要是初始化了mModule的一些变量。 至于onFirstRef何时调用, 后续进行相关的分享, 这里大家只要记住,这个是和sp相关的, 并且在构建sp的时候就会调用。 可以参考这位的博客:http://blog.csdn.net/gzzaigcnforever/article/details/20649781


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void CameraService::onFirstRef()  
  2. {  
  3.     BnCameraService::onFirstRef();  
  4.   
  5.     if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,//这个定义为"came"  
  6.                 (const hw_module_t **)&mModule) < 0) {//<span style="color:#FF0000;">注意这个函数调用</span>  
  7.         ALOGE("Could not load camera HAL module");  
  8.         mNumberOfCameras = 0;  
  9.     }  
  10.     else {  
  11.         mNumberOfCameras = mModule->get_number_of_cameras();  
  12.         if (mNumberOfCameras > MAX_CAMERAS) {  
  13.             ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",  
  14.                     mNumberOfCameras, MAX_CAMERAS);  
  15.             mNumberOfCameras = MAX_CAMERAS;  
  16.         }  
  17.         for (int i = 0; i < mNumberOfCameras; i++) {  
  18.             setCameraFree(i);  
  19.         }  
  20.     }  
  21. }  
  22.   
  23.   
  24.   
  25. /** Base path of the hal modules */  
  26. #define HAL_LIBRARY_PATH1 "/system/lib/hw"  
  27. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
  28. #define HAL_LIBRARY_PATH3 "/system/lib"  
  29.   
  30.   
  31. int hw_get_module(const char *id, const struct hw_module_t **module)  
  32. {  
  33.     return hw_get_module_by_class(id, NULL, module);  
  34. }  
  35.   
  36.   
  37. int hw_get_module_by_class(const char *class_id, const char *inst,  
  38.                            const struct hw_module_t **module)  
  39. {  
  40.     int status;  
  41.     int i;  
  42.     const struct hw_module_t *hmi = NULL;  
  43.     char prop[PATH_MAX];  
  44.     char path[PATH_MAX];  
  45.     char name[PATH_MAX];  
  46.   
  47.     if (inst)  
  48.         snprintf(name, PATH_MAX, "%s.%s", class_id, inst);//class_id为camera, inst为null, 所以现在name=“camera”  
  49.     else  
  50.         strlcpy(name, class_id, PATH_MAX);  
  51.   
  52.     /* 
  53.      * Here we rely on the fact that calling dlopen multiple times on 
  54.      * the same .so will simply increment a refcount (and not load 
  55.      * a new copy of the library). 
  56.      * We also assume that dlopen() is thread-safe. 
  57.      */  
  58.   
  59.     /* Loop through the configuration variants looking for a module */  
  60.     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {  
  61.         if (i < HAL_VARIANT_KEYS_COUNT) {  
  62.             if (property_get(variant_keys[i], prop, NULL) == 0) {  
  63.                 continue;  
  64.             }  
  65.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  66.                      HAL_LIBRARY_PATH2, name, prop);//path=/vendor/lib/hw/camera.**.so, 根据属性的配置值生成文件名。  
  67.   
  68.             if (access(path, R_OK) == 0) break;//判断是否有读文件权限。  
  69.   
  70.             snprintf(path, sizeof(path), "%s/%s.%s.so",//path=/system/lib/hw/camera.**.so  
  71.                      HAL_LIBRARY_PATH1, name, prop);  
  72.             if (access(path, R_OK) == 0) break;  
  73.   
  74.             snprintf(path, sizeof(path), "%s/%s.%s.so",  
  75.                      HAL_LIBRARY_PATH3, name, prop);//path=/system/lib/camera.**.so  
  76.             if (access(path, R_OK) == 0) break;  
  77.         } else {  
  78.             snprintf(path, sizeof(path), "%s/%s.default.so",  
  79.                      HAL_LIBRARY_PATH1, name);//path=/vendor/lib/hw/camera.default.so  
  80.             if (access(path, R_OK) == 0) break;  
  81.   
  82.             snprintf(path, sizeof(path), "%s/%s.default.so",//path=/system/lib/camera.default.so  
  83.                      HAL_LIBRARY_PATH3, name);  
  84.             if (access(path, R_OK) == 0) break;  
  85.         }  
  86.     }  
  87.   
  88.     status = -ENOENT;  
  89.     if (i < HAL_VARIANT_KEYS_COUNT+1) {  
  90.         /* load the module, if this fails, we're doomed, and we should not try 
  91.          * to load a different variant. */  
  92.         status = load(class_id, path, module);//动态加载动态库。  
  93.     }  
  94.   
  95.     return status;  
  96. }  


上面的思路就是:

遍历

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #define HAL_LIBRARY_PATH1 "/system/lib/hw"  
  2. #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"  
  3. #define HAL_LIBRARY_PATH3 "/system/lib"  
这几个目录下的so库,so库的名字为: a.camera.属性名.so和b.camera.default.so。 其中会优先找到a, 在没找到a后再去找到b。 在mtk平台上, 编译生成的so库就为 camera.default.so, 所以最终加载的会是camera.default.so这个库。


继续看看:load(class_id, path, module);:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int load(const char *id,  
  2.         const char *path,  
  3.         const struct hw_module_t **pHmi)  
  4. {  
  5.     int status;  
  6.     void *handle;  
  7.     struct hw_module_t *hmi;  
  8.   
  9.     /* 
  10.      * load the symbols resolving undefined symbols before 
  11.      * dlopen returns. Since RTLD_GLOBAL is not or'd in with 
  12.      * RTLD_NOW the external symbols will not be global 
  13.      */  
  14.     handle = dlopen(path, RTLD_NOW);  
  15.     if (handle == NULL) {  
  16.         char const *err_str = dlerror();  
  17.         ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");  
  18.         status = -EINVAL;  
  19.         goto done;  
  20.     }  
  21.   
  22.     /* Get the address of the struct hal_module_info. */  
  23.     const char *sym = HAL_MODULE_INFO_SYM_AS_STR;  
  24.     hmi = (struct hw_module_t *)dlsym(handle, sym);//关注这两句  
  25.     if (hmi == NULL) {  
  26.         ALOGE("load: couldn't find symbol %s", sym);  
  27.         status = -EINVAL;  
  28.         goto done;  
  29.     }  
  30.   
  31.     /* Check that the id matches */  
  32.     if (strcmp(id, hmi->id) != 0) {  
  33.         ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);  
  34.         status = -EINVAL;  
  35.         goto done;  
  36.     }  
  37.   
  38.     hmi->dso = handle;  
  39.   
  40.     /* success */  
  41.     status = 0;  
  42.   
  43.     done:  
  44.     if (status != 0) {  
  45.         hmi = NULL;  
  46.         if (handle != NULL) {  
  47.             dlclose(handle);  
  48.             handle = NULL;  
  49.         }  
  50.     } else {  
  51.         ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",  
  52.                 id, path, *pHmi, handle);  
  53.     }  
  54.   
  55.     *pHmi = hmi;  
  56.   
  57.     return status;  
  58. }  

关注这两句:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. const char *sym = HAL_MODULE_INFO_SYM_AS_STR;  
  2. hmi = (struct hw_module_t *)dlsym(handle, sym);//关注这两句  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. HAL_MODULE_INFO_SYM_AS_STR:  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Name of the hal_module_info 
  3.  */  
  4. #define HAL_MODULE_INFO_SYM         HMI  
  5.   
  6. /** 
  7.  * Name of the hal_module_info as a string 
  8.  */  
  9. #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"  
从上面可以看出就是要获取名为“HMI”函数的指针, 而HMI又是HAL_MODULE_INFO_SYM 的宏定义, 所以最终就是要找HAL_MODULE_INFO_SYM实现的地方:


[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static  
  2. camera_module  
  3. instantiate_camera_module()  
  4. {  
  5.     CAM_LOGD("[%s]", __FUNCTION__);  
  6.     //  
  7.     //  (1) Prepare One-shot init.  
  8.     MtkCamUtils::Property::clear();  
  9.   
  10.     //  (2)  
  11.     camera_module module = {  
  12.         common: {  
  13.              tag:                   HARDWARE_MODULE_TAG,  
  14.              module_api_version:    1,  
  15.              hal_api_version:       0,  
  16.              id:                    CAMERA_HARDWARE_MODULE_ID,  
  17.              name:                  "MTK Camera Module",  
  18.              author:                "MTK",  
  19.              methods:               CamDeviceManager::get_module_methods(),  
  20.              dso:                   NULL,   
  21.              reserved:              {0},   
  22.         },   
  23.         get_number_of_cameras:  CamDeviceManager::get_number_of_cameras,   
  24.         get_camera_info:        CamDeviceManager::get_camera_info,   
  25.     };  
  26.     return  module;  
  27. }  
  28.   
  29.   
  30. /******************************************************************************* 
  31. * Implementation of camera_module 
  32. *******************************************************************************/  
  33. camera_module HAL_MODULE_INFO_SYM = instantiate_camera_module();  

上面这个代码片段就是mtk实现的, 结合上边, 可以得到*pHmi指向了module这个结构体。 也即是说最后将*pHmi指向这里的module。 进一步回到上面, 就是CameraService中的mModule指向了这里的module。所以说后面的引用大概是CameraService中通过mModule->common->methods这种方式去或则mModule->get_number_of_cameras实现到MTK的hal层的调用。 这样就将Android原生CameraService通过CameraHardwareInterface连接到MTK实现的Hal层, 通过CamDeviceManager来承上启下的作用。

3.继续2关注到CamDeviceManager::get_module_methods()这个函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. hw_module_methods_t*  
  2. CamDeviceManager::  
  3. get_module_methods()  
  4. {  
  5.     static  
  6.     hw_module_methods_t  
  7.     _methods =  
  8.     {  
  9.         open:   CamDeviceManager::open_device  
  10.     };  
  11.   
  12.     return  &_methods;  
  13. }  

呵呵, 可以看到通过mModule->common->methods-->open可以引用到CamDeviceManager::open_device。

通过名字可以猜测到这个方法应该是在Camera启动的时候会去调用。

所以我们看看何时调用CamDeviceManager::open_device这个方法:


回到CameraService:CameraClient:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t CameraClient::initialize(camera_module_t *module) {  
  2.     int callingPid = getCallingPid();  
  3.     LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);  
  4.   
  5.     char camera_device_name[10];  
  6.     status_t res;  
  7.     snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);  
  8.   
  9.     mHardware = new CameraHardwareInterface(camera_device_name);  
  10.     res = mHardware->initialize(&module->common);//这里初始化了, 并且传入的module->common  


回到CameraHardwareInterface:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t initialize(hw_module_t *module)  
  2.     {  
  3.         ALOGI("Opening camera %s", mName.string());  
  4.         int rc = module->methods->open(module, mName.string(),  
  5.                                        (hw_device_t **)&mDevice);//这里进行了打开camera的操作, 这里调用到的已经是MTK hal层的方法了, 注意最后一个参数。  
  6.         if (rc != OK) {  
  7.             ALOGE("Could not open camera %s: %d", mName.string(), rc);  
  8.             return rc;  
  9.         }  
  10.         initHalPreviewWindow();  
  11.         return rc;  
  12.     }  

关注到CamDeviceManager::open_device

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. int  
  2. CamDeviceManager::  
  3. open_device(const hw_module_t* module, const char* name, hw_device_t** device)  
  4. {  
  5.     return  CamDeviceManager::getInstance().openDevice(module, name, device);  
  6. }  
  7.   
  8.   
  9. int  
  10. CamDeviceManager::  
  11. openDevice(const hw_module_t* module, const char* name, hw_device_t** device)  
  12. {  
  13.     int err = OK;  
  14.     //  
  15.     ICamDevice* pdev = NULL;  
  16.     int32_t     i4OpenId = 0;  
  17.     //  
  18.     Mutex::Autolock lock(mMtxOpenLock);  
  19.     //  
  20.     MY_LOGI("+ mi4OpenNum(%d), mi4DeviceNum(%d)", mi4OpenNum, mi4DeviceNum);  
  21.   
  22.     if (name != NULL)  
  23.     {  
  24.         i4OpenId = ::atoi(name);  
  25.         //  
  26.         if  ( DevMetaInfo::queryNumberOfDevice() < i4OpenId )  
  27.         {  
  28.             err = -EINVAL;  
  29.             goto lbExit;  
  30.         }  
  31.         //  
  32.         if  ( MAX_SIMUL_CAMERAS_SUPPORTED <= mi4OpenNum )  
  33.         {  
  34.             MY_LOGW("open number(%d) >= maximum number(%d)", mi4OpenNum, MAX_SIMUL_CAMERAS_SUPPORTED);  
  35.             MY_LOGE("does not support multi-open");  
  36.             err = -ENOMEM;  
  37.             goto lbExit;  
  38.         }  
  39.         //  
  40.         pdev = createIDevice(  
  41.             i4OpenId,   
  42.             *get_hw_device(),   
  43.             module  
  44.         );//注意此处, 进行camDevice的创建  
  45.         //  
  46.         if  ( ! pdev )  
  47.         {  
  48.             MY_LOGE("camera device allocation fail: pdev(0)");  
  49.             err = -ENOMEM;  
  50.             goto lbExit;  
  51.         }  
  52.   
  53.         *device = pdev->get_hw_device();//此处将CamDevice的指针付给传进来形参, 最终是CameraHardwareInterface中的mDevice指向了CamDevice。  
  54.         //  
  55.         mi4OpenNum++;  
  56.     }  
  57.   
  58. lbExit:  
  59.     if  ( OK != err )  
  60.     {  
  61.         if  ( pdev )  
  62.         {  
  63.             destroyDevice(pdev);  
  64.             pdev = NULL;  
  65.         }  
  66.         //  
  67.         *device = NULL;  
  68.     }  
  69.     MY_LOGI("- mi4OpenNum(%d)", mi4OpenNum);  
  70.     return  err;  
  71. }  

4.继续往下关注到

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. pdev = createIDevice(  
  2.            i4OpenId,   
  3.            *get_hw_device(),   
  4.            module  
  5.        );  
的实现:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static  
  2. ICamDevice*  
  3. createIDevice(  
  4.     int32_t const           i4DevOpenId,   
  5.     hw_device_t const&      hwdevice,   
  6.     hw_module_t const*const hwmodule  
  7. )  
  8. {  
  9.     g_s8ClientAppMode = queryClientAppMode();  
  10.     //  
  11.     MY_LOGI("+ tid:%d OpenID:%d ClientAppMode:%s", ::gettid(), i4DevOpenId, g_s8ClientAppMode.string());  
  12.     //  
  13.     ICamDevice* pdev = NSCamDevice::createDevice(g_s8ClientAppMode, i4DevOpenId);//pDeve 指向的就是ICamDevice的一个对象  
  14.     //  
  15.     if  ( pdev != 0 )  
  16.     {  
  17.         pdev->incStrong(pdev);  
  18.         //  
  19.         hw_device_t* hwdev = pdev->get_hw_device();//  
  20.         *hwdev = hwdevice;  
  21.         hwdev->module = const_cast<hw_module_t*>(hwmodule);  
  22.         //  
  23.         if  ( ! pdev->init() )//在这里初始化了ICamDvice  
  24.         {  
  25.             MY_LOGE("fail to initialize a newly-created instance");  
  26.             pdev->uninit();  
  27.             pdev = NULL;  
  28.         }  
  29.     }  
  30.     //  
  31.     MY_LOGI("- created instance=%p", &(*pdev));  
  32.     return  pdev;//返回创建的ICamDevice。  
  33. }  

现在可以得出pdev即是指向ICamDevice对象


注意到ICamDevice对象的构造函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ICamDevice::  
  2. ICamDevice()  
  3.     : camera_device_t()  
  4.     , RefBase()  
  5.     , mDevOps()  
  6.     //  
  7.     , mMtxLock()  
  8.     //  
  9. {  
  10.     MY_LOGD("ctor");  
  11.     ::memset(static_cast<camera_device_t*>(this), 0, sizeof(camera_device_t));  
  12.     this->priv  = this;  
  13.     this->ops   = &mDevOps;//ops指向了mDevOps  
  14.     mDevOps     = gCameraDevOps;//mDevOps为gCameraDevOps指向的结构体  
  15. }  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. gCameraDevOps:  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static camera_device_ops_t const gCameraDevOps = {  
  2.     set_preview_window:         camera_set_preview_window,   
  3.     set_callbacks:              camera_set_callbacks,   
  4.     enable_msg_type:            camera_enable_msg_type,   
  5.     disable_msg_type:           camera_disable_msg_type,   
  6.     msg_type_enabled:           camera_msg_type_enabled,   
  7.     start_preview:              camera_start_preview,   
  8.     stop_preview:               camera_stop_preview,   
  9.     preview_enabled:            camera_preview_enabled,   
  10.     store_meta_data_in_buffers: camera_store_meta_data_in_buffers,   
  11.     start_recording:            camera_start_recording,   
  12.     stop_recording:             camera_stop_recording,   
  13.     recording_enabled:          camera_recording_enabled,   
  14.     release_recording_frame:    camera_release_recording_frame,   
  15.     auto_focus:                 camera_auto_focus,   
  16.     cancel_auto_focus:          camera_cancel_auto_focus,   
  17.     take_picture:               camera_take_picture,   
  18.     cancel_picture:             camera_cancel_picture,   
  19.     set_parameters:             camera_set_parameters,   
  20.     get_parameters:             camera_get_parameters,   
  21.     put_parameters:             camera_put_parameters,   
  22.     send_command:               camera_send_command,   
  23.     release:                    camera_release,   
  24.     dump:                       camera_dump,   
  25.   
  26. };  

所以在CameraHardwareInterface中通过:

mDevice->ops->set_preview_window(mDevice, 0)类似的方法就可以调用到ICamDevice中对应的方法了。


5. 我们回到Camera显示相关的东西,

在CameraClient中//!++
    else if ( window == 0 ) {
        result = mHardware->setPreviewWindow(window);
    }

进而在CameraHardwareInterface中:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** Set the ANativeWindow to which preview frames are sent */  
  2.    status_t setPreviewWindow(const sp<ANativeWindow>& buf)  
  3.    {  
  4.        ALOGV("%s(%s) buf %p", __FUNCTION__, mName.string(), buf.get());  
  5.   
  6.        if (mDevice->ops->set_preview_window) {  
  7.            //!++  
  8.            if  ( buf == 0 ) {  
  9.                ALOGD("set_preview_window(0) before mPreviewWindow = 0");  
  10.                mDevice->ops->set_preview_window(mDevice, 0);//直接调用了ICamDevice的相关的方法。  
  11.                mPreviewWindow = 0;  
  12.                return  OK;  
  13.            }  
  14.            //!--  
  15.            mPreviewWindow = buf;  
  16.            mHalPreviewWindow.user = this;  
  17.            ALOGV("%s &mHalPreviewWindow %p mHalPreviewWindow.user %p", __FUNCTION__,  
  18.                    &mHalPreviewWindow, mHalPreviewWindow.user);  
  19.            return mDevice->ops->set_preview_window(mDevice,  
  20.                    buf.get() ? &mHalPreviewWindow.nw : 0);  
  21.        }  
  22.        return INVALID_OPERATION;  
  23.    }  

5.说到这里, CameraService::CameraClient--->CameraHardwareInterface-->CamDeviceManager-->ICamDevice这一条完整的路线非常清楚。


具体思路就是:

a.CameraHardwareInterface是Android原生定义的和硬件hal层连接的适配接口。各个厂家根据需要去具体实现这些接口,并具体实现底层的相关功能。

b.为了代码通用性和模块的分离性, 对hal层模块的实现封装成动态库(so), CameraService根据需要动态加载hal层的库。

c.CamDeviceManager是Hal层的一个入口类, 从CameraService打开关闭camera的时候都是通过它进行总的安排。

d.hal层下具体的实现都是不断的适配CameraHardwareInterface向上提供的接口的一个过程。


附上以一个打开Camera的流程图供参考:


接着上一篇:

Camera显示之Hal层的适配(一)


一.基本关系

1.先来看看KTM hal层大概类图关系:

大概类图关系就是这样, 其中和显示相关的类图关系如红线所圈区域。

可以猜测到 与显示相关的逻辑处理应该都会在DisplayClient这个类去实现。


2.CamDeviceManager和DisplayClient关系的建立:

以后app下达有关预览显示相关的东西啊在hal层基本上都是这一条先进行传递命令, 不过总1中我们可以看到CamDevice还有一些衍生类, 这些都是mtk为不同设备做的一些定制, 主要的路径还是如上图所示。


二.接着之前的在CameraClient中的代码:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. //!++  
  2. else if ( window == 0 ) {  
  3.     result = mHardware->setPreviewWindow(window);  
  4. }  

1.setPreviewWindow(window)通过CameraHardwareInterface适配:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. mDevice->ops->set_preview_window(mDevice,  
  2.                     buf.get() ? &mHalPreviewWindow.nw : 0);  

来实现向hal层下达命令和设置参数。

在这里我们发现传入的是mHalPreviewWindow.nw, 而不是我们之前所讲述的ANativeWindow 这是因为mHalPreviewWindow.nw将ANativeWindow的一些流的操作进行封装, 使之操作更加简便。

mHalPreviewWindow.nw的定义:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. struct camera_preview_window {  
  2.        struct preview_stream_ops nw;  
  3.        void *user;  
  4.    };  

就是结构体:struct :

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. typedef struct preview_stream_ops {  
  2.     int (*dequeue_buffer)(struct preview_stream_ops* w,  
  3.                           buffer_handle_t** buffer, int *stride);  
  4.     int (*enqueue_buffer)(struct preview_stream_ops* w,  
  5.                 buffer_handle_t* buffer);  
  6.     int (*cancel_buffer)(struct preview_stream_ops* w,  
  7.                 buffer_handle_t* buffer);  
  8.     int (*set_buffer_count)(struct preview_stream_ops* w, int count);  
  9.     int (*set_buffers_geometry)(struct preview_stream_ops* pw,  
  10.                 int w, int h, int format);  
  11.     int (*set_crop)(struct preview_stream_ops *w,  
  12.                 int left, int top, int right, int bottom);  
  13.     int (*set_usage)(struct preview_stream_ops* w, int usage);  
  14.     int (*set_swap_interval)(struct preview_stream_ops *w, int interval);  
  15.     int (*get_min_undequeued_buffer_count)(const struct preview_stream_ops *w,  
  16.                 int *count);  
  17.     int (*lock_buffer)(struct preview_stream_ops* w,  
  18.                 buffer_handle_t* buffer);  
  19.     // Timestamps are measured in nanoseconds, and must be comparable  
  20.     // and monotonically increasing between two frames in the same  
  21.     // preview stream. They do not need to be comparable between  
  22.     // consecutive or parallel preview streams, cameras, or app runs.  
  23.     int (*set_timestamp)(struct preview_stream_ops *w, int64_t timestamp);  

对显示流的操作都是通过这些函数实现的,而mHalPreviewWindow中实现了具体操的方法, 在这些方法的实现中实现对作ANativeWindow的操作。 而在hal端就是通过mHalPreviewWindow.nw 进行对ANativeWindow的具体操作。


基本类图关系:


2.继续1中的:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. mDevice->ops->set_preview_window(mDevice,  
  2.                     buf.get() ? &mHalPreviewWindow.nw : 0);  

我已经知道了mHalPreviewWindow.nw为传入的一个重要参数mHalPreviewWindow.nw 为preview_stream_ops。

继续看看set_preview_window这个方法。 我们有上篇文章知道ops是ICamDevice的一个成员gCameraDevOps,类型为camera_device_ops_t:

可以看到:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static camera_device_ops_t const gCameraDevOps = {  
  2.     set_preview_window:         camera_set_preview_window,   
  3.     set_callbacks:              camera_set_callbacks,   
  4.     enable_msg_type:            camera_enable_msg_type,   
  5.     disable_msg_type:           camera_disable_msg_type,   
  6.     msg_type_enabled:           camera_msg_type_enabled,   
  7.     start_preview:              camera_start_preview,   
  8.     stop_preview:               camera_stop_preview,   
  9.     preview_enabled:            camera_preview_enabled,   
  10.     store_meta_data_in_buffers: camera_store_meta_data_in_buffers,   
  11.     start_recording:            camera_start_recording,   
  12.     stop_recording:             camera_stop_recording,   
  13.     recording_enabled:          camera_recording_enabled,   
  14.     release_recording_frame:    camera_release_recording_frame,   
  15.     auto_focus:                 camera_auto_focus,   
  16.     cancel_auto_focus:          camera_cancel_auto_focus,   
  17.     take_picture:               camera_take_picture,   
  18.     cancel_picture:             camera_cancel_picture,   
  19.     set_parameters:             camera_set_parameters,   
  20.     get_parameters:             camera_get_parameters,   
  21.     put_parameters:             camera_put_parameters,   
  22.     send_command:               camera_send_command,   
  23.     release:                    camera_release,   
  24.     dump:                       camera_dump,   
  25.   
  26. };  


gCameraDevOps 中的函数地址映射到ICamDevice中的函数实现。

所以 :ops->set_preview_window(mDevice, buf.get() ? &mHalPreviewWindow.nw : 0) 就对应到ICamDevice::camera_set_preview_window的发发调用。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static int camera_set_preview_window(  
  2.     struct camera_device * device,  
  3.     struct preview_stream_ops *window  
  4. )  
  5. {  
  6.     int err = -EINVAL;  
  7.     //  
  8.     ICamDevice*const pDev = ICamDevice::getIDev(device);  
  9.     if  ( pDev )  
  10.     {  
  11.         err = pDev->setPreviewWindow(window);  
  12.     }  
  13.     //  
  14.     return  err;  
  15. }  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. static inline ICamDevice*   getIDev(camera_device*const device)  
  2.                                 {  
  3.                                     return (NULL == device)  
  4.                                                 ? NULL  
  5.                                                 : reinterpret_cast<ICamDevice*>(device->priv);//得到device->priv  


由上篇文章:

知道device->pri实际上是在创建实例的时候指向的自己:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ICamDevice::    
  2. ICamDevice()    
  3.     : camera_device_t()    
  4.     , RefBase()    
  5.     , mDevOps()    
  6.     //    
  7.     , mMtxLock()    
  8.     //    
  9. {    
  10.     MY_LOGD("ctor");    
  11.     ::memset(static_cast<camera_device_t*>(this), 0, sizeof(camera_device_t));    
  12.     this->priv  = this//用priv指针保存自己。  
  13.     this->ops   = &mDevOps;//ops指向了mDevOps    
  14.     mDevOps     = gCameraDevOps;//mDevOps为gCameraDevOps指向的结构体    
  15. }    


继续回到pDev->setPreviewWindow(window);

在ICamDevice中没有对setPreviewWindow具体的实现,而是在其子类CamDevice对ICamDevice进行了具体的实现;

随意代码定位到CamDevice:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t  
  2. CamDevice::  
  3. setPreviewWindow(preview_stream_ops* window)  
  4. {  
  5.     MY_LOGI("+ window(%p)", window);  
  6.     //  
  7.     status_t status = initDisplayClient(window);//开始初始化DisplayClient  
  8.     if  ( OK == status && previewEnabled() && mpDisplayClient != 0 )  
  9.     {  
  10.         status = enableDisplayClient();//时能DisplayClient端  
  11.     }  
  12.     //  
  13.     return  status;  
  14. }  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t  
  2. CamDevice::  
  3. initDisplayClient(preview_stream_ops* window)  
  4. {  
  5. #if '1'!=MTKCAM_HAVE_DISPLAY_CLIENT  
  6.     #warning "Not Build Display Client"  
  7.     MY_LOGD("Not Build Display Client");  
  8. ..............  
  9. .............  
  10. /  [3.1] create a Display Client.  
  11.     mpDisplayClient = IDisplayClient::createInstance();  
  12.     if  ( mpDisplayClient == 0 )  
  13.     {  
  14.         MY_LOGE("Cannot create mpDisplayClient");  
  15.         status = NO_MEMORY;  
  16.         goto lbExit;  
  17.     }  
  18.     //  [3.2] initialize the newly-created Display Client.  
  19.     if  ( ! mpDisplayClient->init() )  
  20.     {  
  21.         MY_LOGE("mpDisplayClient init() failed");  
  22.         mpDisplayClient->uninit();  
  23.         mpDisplayClient.clear();  
  24.         status = NO_MEMORY;  
  25.         goto lbExit;  
  26.     }  
  27.     //  [3.3] set preview_stream_ops & related window info.  
  28.     if  ( ! mpDisplayClient->setWindow(window, previewSize.width, previewSize.height, queryDisplayBufCount()) )//绑定window  
  29.     {  
  30.         status = INVALID_OPERATION;  
  31.         goto lbExit;  
  32.     }  
  33.     //  [3.4] set Image Buffer Provider Client if it exist.  
  34.     if  ( mpCamAdapter != 0 && ! mpDisplayClient->setImgBufProviderClient(mpCamAdapter) )//重要! 设置流数据的Buffer提供者。  
  35.     {  
  36.         status = INVALID_OPERATION;  
  37.         goto lbExit;  
  38.     }  
  39. ..................  
  40. ..................  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. status_t  
  2. CamDevice::  
  3. enableDisplayClient()  
  4. {  
  5.     status_t status = OK;  
  6.     Size previewSize;  
  7.     //  
  8.     //  [1] Get preview size.  
  9.     if  ( ! queryPreviewSize(previewSize.width, previewSize.height) )  
  10.     {  
  11.         MY_LOGE("queryPreviewSize");  
  12.         status = DEAD_OBJECT;  
  13.         goto lbExit;  
  14.     }  
  15.     //  
  16.     //  [2] Enable  
  17.     if  ( ! mpDisplayClient->enableDisplay(previewSize.width, previewSize.height, queryDisplayBufCount(), mpCamAdapter) )//设置了预览数据的尺寸和Buffer提供者相关的数据  
  18.     {  
  19.         MY_LOGE("mpDisplayClient(%p)->enableDisplay()", mpDisplayClient.get());  
  20.         status = INVALID_OPERATION;  
  21.         goto lbExit;  
  22.     }  
  23.     //  
  24.     status = OK;  
  25. lbExit:  
  26.     return  status;  
  27. }  


3.定位到DisplayClient中:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. enableDisplay(  
  2.     int32_t const   i4Width,   
  3.     int32_t const   i4Height,   
  4.     int32_t const   i4BufCount,   
  5.     sp<IImgBufProviderClient>const& rpClient  
  6. )  
  7. {  
  8.     bool ret = false;  
  9.     preview_stream_ops* pStreamOps = mpStreamOps;  
  10.     //  
  11.     //  [1] Re-configurate this instance if any setting changes.  
  12.     if  ( ! checkConfig(i4Width, i4Height, i4BufCount, rpClient) )  
  13.     {  
  14.         MY_LOGW("<Config Change> Uninit the current DisplayClient(%p) and re-config..."this);  
  15.         //  
  16.         //  [.1] uninitialize  
  17.         uninit();  
  18.         //  
  19.         //  [.2] initialize  
  20.         if  ( ! init() )  
  21.         {  
  22.             MY_LOGE("re-init() failed");  
  23.             goto lbExit;  
  24.         }  
  25.         //  
  26.         //  [.3] set related window info.  
  27.         if  ( ! setWindow(pStreamOps, i4Width, i4Height, i4BufCount) )//window的尺寸和预览数据的大小一致  
  28.         {  
  29.             goto lbExit;  
  30.         }  
  31.         //  
  32.         //  [.4] set Image Buffer Provider Client.  
  33.         if  ( ! setImgBufProviderClient(rpClient) )//Buffer的数据提供者为mpCamAdapter, 就是CamAdapter, 后面的预览数据元都是通过它来提供。  
  34.         {  
  35.             goto lbExit;  
  36.         }  
  37.     }  
  38.     //  
  39.     //  [2] Enable.  
  40.     if  ( ! enableDisplay() )//开始进行数据的获取和显示  
  41.     {  
  42.         goto lbExit;  
  43.     }  
  44.     //  
  45.     ret = true;  
  46. lbExit:  
  47.     return  ret;  
  48. }  

先来看看第一个关键函数:setWindow(pStreamOps, i4Width, i4Height, i4BufCount)

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. setWindow(  
  4.     preview_stream_ops*const window,   
  5.     int32_t const   wndWidth,   
  6.     int32_t const   wndHeight,   
  7.     int32_t const   i4MaxImgBufCount  
  8. )  
  9. {  
  10.     MY_LOGI("+ window(%p), WxH=%dx%d, count(%d)", window, wndWidth, wndHeight, i4MaxImgBufCount);  
  11.     //  
  12.     if  ( ! window )  
  13.     {  
  14.         MY_LOGE("NULL window passed into");  
  15.         return  false;  
  16.     }  
  17.     //  
  18.     if  ( 0 >= wndWidth || 0 >= wndHeight || 0 >= i4MaxImgBufCount )  
  19.     {  
  20.         MY_LOGE("bad arguments - WxH=%dx%d, count(%d)", wndWidth, wndHeight, i4MaxImgBufCount);  
  21.         return  false;  
  22.     }  
  23.     //  
  24.     //  
  25.     Mutex::Autolock _l(mModuleMtx);  
  26.     return  set_preview_stream_ops(window, wndWidth, wndHeight, i4MaxImgBufCount);//  
  27. }  

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ool  
  2. DisplayClient::  
  3. set_preview_stream_ops(  
  4.     preview_stream_ops*const window,   
  5.     int32_t const   wndWidth,   
  6.     int32_t const   wndHeight,   
  7.     int32_t const   i4MaxImgBufCount  
  8. )  
  9. {  
  10.     CamProfile profile(__FUNCTION__, "DisplayClient");  
  11.     //  
  12.     bool        ret = false;  
  13.     status_t    err = 0;  
  14.     int32_t     min_undequeued_buf_count = 0;  
  15.     //  
  16.     //  (2) Check  
  17.     if  ( ! mStreamBufList.empty() )  
  18.     {  
  19.         MY_LOGE(  
  20.             "locked buffer count(%d)!=0, "  
  21.             "callers must return all dequeued buffers, "  
  22. //            "and then call cleanupQueue()"  
  23.             , mStreamBufList.size()  
  24.         );  
  25.         dumpDebug(mStreamBufList, __FUNCTION__);  
  26.         goto lbExit;  
  27.     }  
  28.     //  
  29.     //  (3) Sava info.  
  30.     mpStreamImgInfo.clear();//mpStreamImgInfo封装的视屏数据流的基本信息。  
  31.     mpStreamImgInfo     = new ImgInfo(wndWidth, wndHeight, CAMERA_DISPLAY_FORMAT, CAMERA_DISPLAY_FORMAT_HAL, "Camera@Display");//设置了Stream的宽高和显示类型。  
  32.     mpStreamOps         = window;//mpStreamOps保存了上层传进来的对象指针。后面就通过它和显示方进行交互。  
  33.     mi4MaxImgBufCount   = i4MaxImgBufCount;  
  34.   
  35. ........................  
  36. ........................  
  37.   
  38.  err = mpStreamOps->set_buffer_count(mpStreamOps, mi4MaxImgBufCount+min_undequeued_buf_count);  
  39.     if  ( err )  
  40.     {  
  41.         MY_LOGE("set_buffer_count failed: status[%s(%d)]", ::strerror(-err), -err);  
  42.         if ( ENODEV == err )  
  43.         {  
  44.             MY_LOGD("Preview surface abandoned!");  
  45.             mpStreamOps = NULL;  
  46.         }  
  47.         goto lbExit;  
  48.     }  
  49.     //  
  50.     //  (4.4) Set window geometry  
  51.     err = mpStreamOps->set_buffers_geometry(//设置基本的流信息  
  52.             mpStreamOps,   
  53.             mpStreamImgInfo->mu4ImgWidth,   
  54.             mpStreamImgInfo->mu4ImgHeight,   
  55.             mpStreamImgInfo->mi4ImgFormat  
  56.         );  

通过 上面的代码片段和分析, 确定了上层传递下来的对象指针保存在mpStreamOps, 与显示相关的交互都将通过mpStreamOps来进行操作。 而mpStreamImgInfo封装了流数据的大小和格式等。


再来看看第二个关键函数:setImgBufProviderClient(rpClient):

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. setImgBufProviderClient(sp<IImgBufProviderClient>const& rpClient)  
  4. {  
  5.     bool ret = false;  
  6.     //  
  7.     MY_LOGD("+ ImgBufProviderClient(%p), mpImgBufQueue.get(%p)", rpClient.get(), mpImgBufQueue.get());  
  8.     //  
  9.     if  ( rpClient == 0 )  
  10.     {  
  11.         MY_LOGE("NULL ImgBufProviderClient");  
  12.         mpImgBufPvdrClient = NULL;  
  13.         goto lbExit;  
  14.     }  
  15.     //  
  16.     if  ( mpImgBufQueue != 0 )  
  17.     {  
  18.         if  ( ! rpClient->onImgBufProviderCreated(mpImgBufQueue) )//通知Provider端(Buffer数据提供者端),我这边已经建好Buffer队列, 后面你就填充数据到对应的Buffer供我使用。  
  19.         {  
  20.             goto lbExit;  
  21.         }  
  22.         mpImgBufPvdrClient = rpClient;//用mpImgBufPvdrClient保存provider的对象指针, 方便使用。  
  23.     }  
  24.     //  
  25.     ret = true;  
  26. lbExit:  
  27.     MY_LOGD("-");  
  28.     return  ret;  
  29. };  

再来看看第三个关键函数 enableDisplay() :

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. enableDisplay()  
  4. {  
  5.     bool ret = false;  
  6.     //  
  7.     //  (1) Lock  
  8.     Mutex::Autolock _l(mModuleMtx);  
  9.     //  
  10.     MY_LOGD("+ isDisplayEnabled(%d), mpDisplayThread.get(%p)", isDisplayEnabled(), mpDisplayThread.get());  
  11.     //  
  12.     //  (2) Check to see if it has been enabled.  
  13.     if  ( isDisplayEnabled() )  
  14.     {  
  15.         MY_LOGD("Display is already enabled");  
  16.         ret = true;  
  17.         goto lbExit;  
  18.     }  
  19.     //  
  20.     //  (3) Check to see if thread is alive.  
  21.     if  ( mpDisplayThread == 0 )  
  22.     {  
  23.         MY_LOGE("NULL mpDisplayThread");  
  24.         goto lbExit;  
  25.     }  
  26.     //  
  27.     //  (4) Enable the flag.  
  28.     ::android_atomic_write(1, &mIsDisplayEnabled);  
  29.     //  
  30.     //  (5) Post a command to wake up the thread.  
  31.     mpDisplayThread->postCommand(Command(Command::eID_WAKEUP));//通知获取数据的线程开始运行  
  32.     //  
  33.     //  
  34.     ret = true;  
  35. lbExit:  
  36.     MY_LOGD("- ret(%d)", ret);  
  37.     return ret;  
  38. }  


 
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayThread::  
  3. threadLoop()  
  4. {  
  5.     Command cmd;  
  6.     if  ( getCommand(cmd) )  
  7.     {  
  8.         switch  (cmd.eId)  
  9.         {  
  10.         case Command::eID_EXIT:  
  11.             MY_LOGD("Command::%s", cmd.name());  
  12.             break;  
  13.         //  
  14.         case Command::eID_WAKEUP://对应上面发送的命令  
  15.         default:  
  16.             if  ( mpThreadHandler != 0 )  
  17.             {  
  18.                 mpThreadHandler->onThreadLoop(cmd);//注意此处, mpThreadHandler就是DisplayClient(它继承了IDisplayThreadHandler),  
  19.             }  
  20.             else  
  21.             {  
  22.                 MY_LOGE("cannot handle cmd(%s) due to mpThreadHandler==NULL", cmd.name());  
  23.             }  
  24.             break;  
  25.         }  
  26.     }  
  27.     //  
  28.     MY_LOGD("- mpThreadHandler.get(%p)", mpThreadHandler.get());  
  29.     return  true;  
  30. }  
 
 
 
回到DisplayClient的onThreadLoop函数: 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. onThreadLoop(Command const& rCmd)  
  4. {  
  5.     //  (0) lock Processor.  
  6.     sp<IImgBufQueue> pImgBufQueue;  
  7.     {  
  8.         Mutex::Autolock _l(mModuleMtx);  
  9.         pImgBufQueue = mpImgBufQueue;  
  10.         if  ( pImgBufQueue == 0 || ! isDisplayEnabled() )//判断显示相关的初始化是否完成和启动  
  11.         {  
  12.             MY_LOGW("pImgBufQueue.get(%p), isDisplayEnabled(%d)", pImgBufQueue.get(), isDisplayEnabled());  
  13.             return  true;  
  14.         }  
  15.     }  
  16.   
  17.     //  (1) Prepare all TODO buffers.  
  18.     if  ( ! prepareAllTodoBuffers(pImgBufQueue) )//为pImgBufQueue添加空Buffer。  
  19.     {  
  20.         return  true;  
  21.     }  
  22.   
  23.     //  (2) Start  
  24.     if  ( ! pImgBufQueue->startProcessor() )//开始获取数据  
  25.     {  
  26.         return  true;  
  27.     }  
  28.     //  
  29.     {  
  30.         Mutex::Autolock _l(mStateMutex);  
  31.         mState = eState_Loop;  
  32.         mStateCond.broadcast();  
  33.     }  
  34.     //  
  35.     //  (3) Do until disabled.  
  36.     while   ( 1 )//进入无限循环  
  37.     {  
  38.         //  (.1)  
  39.         waitAndHandleReturnBuffers(pImgBufQueue);//等待pImgBufQueue中的数据,并送到显示端显示  
  40.   
  41.         //  (.2) break if disabled.  
  42.         if  ( ! isDisplayEnabled() )  
  43.         {  
  44.             MY_LOGI("Display disabled");  
  45.             break;  
  46.         }  
  47.   
  48.         //  (.3) re-prepare all TODO buffers, if possible,   
  49.         //  since some DONE/CANCEL buffers return.  
  50.         prepareAllTodoBuffers(pImgBufQueue);//又重新准备Buffer。  
  51.     }  
  52.     //  
  53.     //  (4) Stop  
  54.     pImgBufQueue->pauseProcessor();  
  55.     pImgBufQueue->flushProcessor();  
  56.     pImgBufQueue->stopProcessor();//停止数据获取  
  57.     //  
  58.     //  (5) Cancel all un-returned buffers.  
  59.     cancelAllUnreturnBuffers();//没有来得及显示额数据, 也取消掉。  
  60.     //  
  61.     {  
  62.         Mutex::Autolock _l(mStateMutex);  
  63.         mState = eState_Suspend;  
  64.         mStateCond.broadcast();  
  65.     }  
  66.     //  
  67.     return  true;  
  68. }  

上边这个代码片段对预览数据的处理就在waitAndHandleReturnBuffers(pImgBufQueue);中。


4.对waitAndHandleReturnBuffers(pImgBufQueue);进行分析:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)  
  4. {  
  5.     bool ret = false;  
  6.     Vector<ImgBufQueNode> vQueNode;  
  7.     //  
  8.     MY_LOGD_IF((1<=miLogLevel), "+");  
  9.     //  
  10.     //  (1) deque buffers from processor.  
  11.     rpBufQueue->dequeProcessor(vQueNode);//从provider端(数据提供端)获取一个填充数据了的Buffer。  
  12.     if  ( vQueNode.empty() ) {  
  13.         MY_LOGW("vQueNode.empty()");  
  14.         goto lbExit;  
  15.     }  
  16.   
  17.     //  (2) handle buffers dequed from processor.  
  18.     ret = handleReturnBuffers(vQueNode);//处理填充了数据的这个Buffer中的数据。  
  19.   
  20. lbExit:  
  21.     //  
  22.     MY_LOGD_IF((2<=miLogLevel), "- ret(%d)", ret);  
  23.     return ret;  
  24. }  

看看handleReturnBuffers函数:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool  
  2. DisplayClient::  
  3. handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode)  
  4. {  
  5.     /* 
  6.      * Notes: 
  7.      *  For 30 fps, we just enque (display) the latest frame,  
  8.      *  and cancel the others. 
  9.      *  For frame rate > 30 fps, we should judge the timestamp here or source. 
  10.      */  
  11.     //  (1) determine the latest DONE buffer index to display; otherwise CANCEL.  
  12.     int32_t idxToDisp = 0;  
  13.     for ( idxToDisp = rvQueNode.size()-1; idxToDisp >= 0; idxToDisp--)  
  14.     {  
  15.         if  ( rvQueNode[idxToDisp].isDONE() )  
  16.             break;  
  17.     }  
  18.     if  ( rvQueNode.size() > 1 )  
  19.     {  
  20.         MY_LOGW("(%d) display frame count > 1 --> select %d to display", rvQueNode.size(), idxToDisp);  
  21.     }  
  22.     //  
  23.     //  Show Time duration.  
  24.     if  ( 0 <= idxToDisp )  
  25.     {  
  26.         nsecs_t const _timestamp1 = rvQueNode[idxToDisp].getImgBuf()->getTimestamp();  
  27.         mProfile_buffer_timestamp.pulse(_timestamp1);  
  28.         nsecs_t const _msDuration_buffer_timestamp = ::ns2ms(mProfile_buffer_timestamp.getDuration());  
  29.         mProfile_buffer_timestamp.reset(_timestamp1);  
  30.         //  
  31.         mProfile_dequeProcessor.pulse();  
  32.         nsecs_t const _msDuration_dequeProcessor = ::ns2ms(mProfile_dequeProcessor.getDuration());  
  33.         mProfile_dequeProcessor.reset();  
  34.         //  
  35.         MY_LOGD_IF(  
  36.             (1<=miLogLevel), "+ %s(%lld) %s(%lld)",   
  37.             (_msDuration_buffer_timestamp < 0 ) ? "time inversion!" : "", _msDuration_buffer_timestamp,   
  38.             (_msDuration_dequeProcessor > 34) ? "34ms < Duration" : "", _msDuration_dequeProcessor  
  39.         );  
  40.     }  
  41.     //  
  42.     //  (2) Lock  
  43.     Mutex::Autolock _l(mModuleMtx);  
  44.     //  
  45.     //  (3) Remove from List and enquePrvOps/cancelPrvOps, one by one.  
  46.     int32_t const queSize = rvQueNode.size();  
  47.     for (int32_t i = 0; i < queSize; i++)  
  48.     {  
  49.         sp<IImgBuf>const&       rpQueImgBuf = rvQueNode[i].getImgBuf(); //  ImgBuf in Queue.  
  50.         sp<StreamImgBuf>const pStreamImgBuf = *mStreamBufList.begin();  //  ImgBuf in List.  
  51.         //  (.1)  Check valid pointers to image buffers in Queue & List  
  52.         if  ( rpQueImgBuf == 0 || pStreamImgBuf == 0 )  
  53.         {  
  54.             MY_LOGW("Bad ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf.get(), pStreamImgBuf.get());  
  55.             continue;  
  56.         }  
  57.         //  (.2)  Check the equality of image buffers between Queue & List.  
  58.         if  ( rpQueImgBuf->getVirAddr() != pStreamImgBuf->getVirAddr() )  
  59.         {  
  60.             MY_LOGW("Bad address in ImgBuf:(Que[%d], List.begin)=(%p, %p)", i, rpQueImgBuf->getVirAddr(), pStreamImgBuf->getVirAddr());  
  61.             continue;  
  62.         }  
  63.         //  (.3)  Every check is ok. Now remove the node from the list.  
  64.         mStreamBufList.erase(mStreamBufList.begin());//经过检查返回的这一帧数据的Buffer是DisplayClient端分配和提供的。  
  65.         //  
  66.         //  (.4)  enquePrvOps/cancelPrvOps  
  67.         if  ( i == idxToDisp ) {  
  68.             MY_LOGD_IF(  
  69.                 (1<=miLogLevel),   
  70.                 "Show frame:%d %d [ion:%d %p/%d %lld]",   
  71.                 i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(),   
  72.                 pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()  
  73.             );  
  74.             //  
  75.             if(mpExtImgProc != NULL)  
  76.             {  
  77.                 if(mpExtImgProc->getImgMask() & ExtImgProc::BufType_Display)  
  78.                 {  
  79.                     IExtImgProc::ImgInfo img;  
  80.                     //  
  81.                     img.bufType     = ExtImgProc::BufType_Display;  
  82.                     img.format      = pStreamImgBuf->getImgFormat();  
  83.                     img.width       = pStreamImgBuf->getImgWidth();  
  84.                     img.height      = pStreamImgBuf->getImgHeight();  
  85.                     img.stride[0]   = pStreamImgBuf->getImgWidthStride(0);  
  86.                     img.stride[1]   = pStreamImgBuf->getImgWidthStride(1);  
  87.                     img.stride[2]   = pStreamImgBuf->getImgWidthStride(2);  
  88.                     img.virtAddr    = (MUINT32)(pStreamImgBuf->getVirAddr());  
  89.                     img.bufSize     = pStreamImgBuf->getBufSize();  
  90.                     //  
  91.                     mpExtImgProc->doImgProc(img);  
  92.                 }  
  93.             }  
  94.             //  
  95.             enquePrvOps(pStreamImgBuf);//送入显示端显示  
  96.         }  
  97.         else {  
  98.             MY_LOGW(  
  99.                 "Drop frame:%d %d [ion:%d %p/%d %lld]",   
  100.                 i, rvQueNode[i].getStatus(), pStreamImgBuf->getIonFd(),   
  101.                 pStreamImgBuf->getVirAddr(), pStreamImgBuf->getBufSize(), pStreamImgBuf->getTimestamp()  
  102.             );  
  103.             cancelPrvOps(pStreamImgBuf);  
  104.         }  
  105.     }  
  106.     //  
  107.     MY_LOGD_IF((1<=miLogLevel), "-");  
  108.     return  true;  
  109. }  
  110.   
  111.   
  112.   
  113. void  
  114. DisplayClient::  
  115. enquePrvOps(sp<StreamImgBuf>const& rpImgBuf)  
  116. {  
  117.     mProfile_enquePrvOps.pulse();  
  118.     if  ( mProfile_enquePrvOps.getDuration() >= ::s2ns(2) ) {  
  119.         mProfile_enquePrvOps.updateFps();  
  120.         mProfile_enquePrvOps.showFps();  
  121.         mProfile_enquePrvOps.reset();  
  122.     }  
  123.     //  
  124.     status_t    err = 0;  
  125.     //  
  126.     CamProfile profile(__FUNCTION__, "DisplayClient");  
  127.     profile.print_overtime(  
  128.         ((1<=miLogLevel) ? 0 : 1000),   
  129.         "+ locked buffer count(%d), rpImgBuf(%p,%p), Timestamp(%lld)",   
  130.         mStreamBufList.size(), rpImgBuf.get(), rpImgBuf->getVirAddr(), rpImgBuf->getTimestamp()  
  131.     );  
  132.     //  
  133.     //  [1] unlock buffer before sending to display  
  134.     GraphicBufferMapper::get().unlock(rpImgBuf->getBufHndl());  
  135.     profile.print_overtime(1, "GraphicBufferMapper::unlock");  
  136.     //  
  137.     //  [2] Dump image if wanted.  
  138.     dumpImgBuf_If(rpImgBuf);  
  139.     //  
  140.     //  [3] set timestamp.  
  141.     err = mpStreamOps->set_timestamp(mpStreamOps, rpImgBuf->getTimestamp());  
  142.     profile.print_overtime(2, "mpStreamOps->set_timestamp, Timestamp(%lld)", rpImgBuf->getTimestamp());  
  143.     if  ( err )  
  144.     {  
  145.         MY_LOGE(  
  146.             "mpStreamOps->set_timestamp failed: status[%s(%d)], rpImgBuf(%p), Timestamp(%lld)",   
  147.             ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getTimestamp()  
  148.         );  
  149.     }  
  150.     //  
  151.     //  [4] set gralloc buffer type & dirty  
  152.     ::gralloc_extra_setBufParameter(  
  153.         rpImgBuf->getBufHndl(),   
  154.         GRALLOC_EXTRA_MASK_TYPE | GRALLOC_EXTRA_MASK_DIRTY,   
  155.         GRALLOC_EXTRA_BIT_TYPE_CAMERA | GRALLOC_EXTRA_BIT_DIRTY  
  156.     );  
  157.     //  
  158.     //  [5] unlocks and post the buffer to display.  
  159.     err = mpStreamOps->enqueue_buffer(mpStreamOps, rpImgBuf->getBufHndlPtr());//注意这里可以看到最终是通过mpStreamOps送入送给显示端显示的。  
  160.     profile.print_overtime(10, "mpStreamOps->enqueue_buffer, Timestamp(%lld)", rpImgBuf->getTimestamp());  
  161.     if  ( err )  
  162.     {  
  163.         MY_LOGE(  
  164.             "mpStreamOps->enqueue_buffer failed: status[%s(%d)], rpImgBuf(%p,%p)",   
  165.             ::strerror(-err), -err, rpImgBuf.get(), rpImgBuf->getVirAddr()  
  166.         );  
  167.     }  
  168. }  



从上面的代码片段, 可以看到从显示数据最终是通过mpStreamOps(CameraHardwareInterface中传下来的的mHalPreviewWindow.nw)来进行处理的。

至此预览数据就算完全交给了ANativeWindow进行显示。

但是预览数据究竟是怎样从Provider端来的, 我们也提到在DisplayClient也会去分配一些buffer, 这些Buffer又是如何管理的。 后续会接着分享。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值