四、Camera显示之Hal层的适配(二)

转载来自:http://blog.csdn.net/wsb1321/article/details/22080325

接着上一篇:

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又是如何管理的。 后续会接着分享。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
R58点亮ov2640.txt 开发板:全志公板,全志R58(CPU:Octa-Core Cortex-A7 CPU) http://www.allwinnertech.com/clq/r/R58.html 全志官网R58的简介 android4.4.4/linux3.4.39 2016/6/30 9:36 1、配置ov2640在android配置的分辨率为vga(预览/拍照/录像) 注意:系统自带的快拍APP就在这里查找分辨率参数发送到cameraHAL。 cubieboard2开发板使用的是全志A20的CPU,自带两路CSI的摄像头接口。 一般使用CSI1,所有生成的设备节点是/dev/video1。 一般情况下,MIPI为主摄像头(后置摄像头),那设备节点就是/dev/video0。 没有接MIPI摄像头,那就空出来,像全志A20那样配置成为了/dev/video1了。结果被坑了。 后来想起来: insmod /system/vendor/modules/ov2640.ko insmod /system/vendor/modules/vfe_v4l2.ko 手工加载vfe_v4l2.ko驱动模块之后,生成了设备节点/dev/video0。 赶紧修改为/dev/video0。然后使用adb push进去。 修改属性之后,摄像头还是不显示。重启之后正常了。这里折腾了好久!!!! R:\wyb\r58_bmi160_bma250_ov2640_dev\android\device\softwinner\octopus-f1\configs\camera.cfg ;------------------------------------------------------------------------------- ; 用于camera的配置 ; ; 采用格式: ; key = key_value ; 注意: 每个key需要顶格写; ; key_value紧跟着key后面的等号后面, 位于同一行中; ; key_value限制大小为256字节以内; ; ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- ; exif information of "make" and "model" ;------------------------------------------------------------------------------- key_camera_exif_make = MAKE_AllWinner key_camera_exif_model = MODEL_f1 ;------------------------------------------------------------------------------- ; 1 for single camera, 2 for double camera ;------------------------------------------------------------------------------- number_of_camera = 1 ;------------------------------------------------------------------------------- ; CAMERA_FACING_BACK ; ov8858 ov2640 ;------------------------------------------------------------------------------- camera_id = 0 ;------------------------------------------------------------------------------- ; 1 for CAMERA_FACING_FRONT ; 0 for CAMERA_FACING_BACK ;------------------------------------------------------------------------------- camera_facing = 0 ;------------------------------------------------------------------------------- ; 1 for camera without isp(using built-in isp of Axx) ; 0 for camera with isp ;------------------------------------------------------------------------------- use_builtin_isp = 0 ;------------------------------------------------------------------------------- ; camera orientation (0, 90, 180, 270) ;------------------------------------------------------------------------------- camera_orientation = 90 ;------------------------------------------------------------------------------- ; driver device name ;------------------------------------------------------------------------------- camera_device = /dev/video0 ;------------------------------------------------------------------------------- ; device id ; for two camera devices with one CSI ;------------------------------------------------------------------------------- device_id = 0 used_preview_size = 1 key_support_preview_size = 640x480 key_default_preview_size = 640x480 used_picture_size = 1 key_support_picture_size = 640x480 key_default_picture_size = 640x480 used_flash_mode = 0 key_support_flash_mode = on,off,auto,red-eye,torch key_default_flash_mode = off used_color_effect=0 key_support_color_effect = none,mono,negative,sepia,aqua key_default_color_effect = none used_frame_rate = 1 key_support_frame_rate = 25 key_default_frame_rate = 25 used_focus_mode = 1 key_support_focus_mode = auto,infinity,macro,fixed key_default_focus_mode = auto ;used_scene_mode = 0 ;key_support_scene_mode = auto,action,portrait,landscape,night,night-portrait,theatre,beach,snow,sunset,steadyphoto,fireworks,sports,party,candlelight,barcode,hdr ;key_default_scene_mode = auto used_scene_mode = 1 key_support_scene_mode = auto,hdr key_default_scene_mode = auto used_white_balance = 1 key_support_white_balance = auto,incandescent,fluorescent,warm-fluorescent,daylight,cloudy-daylight key_default_white_balance = auto used_exposure_compensation = 1 key_max_exposure_compensation = 3 key_min_exposure_compensation = -3 key_step_exposure_compensation = 1 key_default_exposure_compensation = 0 used_zoom = 1 key_zoom_supported = true key_smooth_zoom_supported = false key_zoom_ratios = 100,120,150,200,230,250,300 key_max_zoom = 30 key_default_zoom = 0 key_horizonal_view_angle = 64 key_vertical_view_angle = 39.4 2、R:\wyb\r58_bmi160_bma250_ov2640_dev\android\device\softwinner\octopus-f1\hawkview\sensor_list_cfg.ini #A80 sensor list configs # ##################bus config###################### # #used: 0: not used, 1: used; #csi_sel: 0: mipi, 1: parallel ; #device_sel: 0: dev0, 1: dev1; #sensor_twi_id: twi id, for example: sensor_twi_id = 0 # ##################power configs################### #power_settings_enable: 0: enable the power settings in sysconfig.fex; 1: enable the power settings in this file. # #iovdd The name of iovdd for this camera; #iovdd_vol The voltage value of iovdd in uV; # ###############detect sensor configs############## # #detect_sensor_num: The number of sensors need be detected in this bus. #sensor_name[x]: The sensor name in sensor driver. #sensor_twi_addr[x]: The i2c address of this sensor. #sensor_type[x]: The sensor type, 0: YUV, 1: RAW; #sensor_stby_mode[x]: Not used; #sensor_hflip[x] Horizontal flip; #sensor_vflip[x] Vertical flip; #act_name[x] The VCM name in vcm driver, only RAW sensor need be configured; #act_twi_addr[x] The i2c address of this VCM; # ################################################## [rear_camera_cfg] #bus configs used = 1 csi_sel = 1 device_sel = 1 sensor_twi_id = 2 #power configs power_settings_enable = 0 iovdd = "axp22_aldo2" iovdd_vol = 2800000 avdd = "axp15_aldo2" avdd_vol = 2800000 dvdd = "axp22_eldo1" dvdd_vol = 1500000 afvdd = "" afvdd_vol = 2800000 #detect sensor configs detect_sensor_num = 1 sensor_name0 = "ov2640" sensor_twi_addr0 = 0x60 sensor_type0 = 0 sensor_stby_mode0 = 0 sensor_hflip0 = 0 sensor_vflip0 = 0 act_name0 = act_twi_addr0 = 3、在init.rc(init.sun8i.rc)中加载ov2640.ko这个驱动模块。 R:\wyb\r58_bmi160_bma250_ov2640_dev\android\device\softwinner\octopus-f1\init.sun8i.rc #csi module insmod /system/vendor/modules/videobuf-core.ko insmod /system/vendor/modules/videobuf-dma-contig.ko insmod /system/vendor/modules/cam_detect.ko insmod /system/vendor/modules/cci.ko #insmod /system/vendor/modules/actuator.ko insmod /system/vendor/modules/vfe_os.ko insmod /system/vendor/modules/vfe_subdev.ko #insmod /system/vendor/modules/actuator.ko #insmod /system/vendor/modules/dw9714_act.ko #insmod /system/vendor/modules/hi253.ko #insmod /system/vendor/modules/ov8858_4lane.ko insmod /system/vendor/modules/ov2640.ko insmod /system/vendor/modules/vfe_v4l2.ko 启动之后实际加载的摄像头的驱动模块: shell@octopus-f1:/ $ shell@octopus-f1:/ $ lsmod cdc_ether 3163 0 - Live 0x00000000 rtl8150 9023 0 - Live 0x00000000 mcs7830 5644 0 - Live 0x00000000 qf9700 5904 0 - Live 0x00000000 asix 13590 0 - Live 0x00000000 usbnet 14128 4 cdc_ether,mcs7830,qf9700,asix, Live 0x00000000 bcm_btlpm 7658 0 - Live 0x00000000 ltr_501als 10649 0 - Live 0x00000000 bma250 7988 0 - Live 0x00000000 sw_device 14680 0 - Live 0x00000000 sunxi_schw 13015 0 - Live 0x00000000 (O) vfe_v4l2 786415 1 - Live 0x00000000 ov2640 14830 0 - Live 0x00000000 vfe_subdev 4695 2 vfe_v4l2,ov2640, Live 0x00000000 vfe_os 4113 2 vfe_v4l2,vfe_subdev, Live 0x00000000 cci 22800 2 vfe_v4l2,ov2640, Live 0x00000000 videobuf_dma_contig 4165 1 vfe_v4l2, Live 0x00000000 videobuf_core 16528 2 vfe_v4l2,videobuf_dma_contig, Live 0x00000000 pvrsrvkm 279691 38 - Live 0x00000000 (O) hdmi 38647 0 - Live 0x00000000 disp 1023342 6 hdmi, Live 0x00000000 sunxi_tr 9348 1 disp, Live 0x00000000 nand 299887 0 - Live 0x00000000 (O) shell@octopus-f1:/ $ 4、驱动程序:ov2640.c及其V4L2的适配。 配置ov5640.c的编译选项,默认已经配置好,不用修改: R:\wyb\r58_bmi160_bma250_ov2640_dev\lichee\linux-3.4\drivers\media\video\sunxi-vfe\device\ov2640.c R:\wyb\r58_bmi160_bma250_ov2640_dev\lichee\linux-3.4\drivers\media\video\sunxi-vfe\device\Makefile obj-m += ov5640.o R:\wyb\r58_bmi160_bma250_ov2640_dev\lichee\linux-3.4\drivers\media\video\sunxi-vfe\Kconfig 5、 R:\wyb\r58_bmi160_bma250_ov2640_dev\lichee\tools\pack\chips\sun8iw6p1\configs\f1\sys_config.fex ;-------------------------------------------------------------------------------- ;vip (video input port) configuration ;vip_used: 0:disable 1:enable ;vip_mode: 0:sample one interface to one buffer 1:sample two interface to one buffer ;vip_dev_qty: The quantity of devices linked to capture bus ; ;vip_define_sensor_list: If you want use sensor detect function, please set vip_define_sensor_list = 1, and ; verify that file /system/etc/hawkview/sensor_list_cfg.ini is properly configured! ; ;vip_dev(x)_pos: sensor position, "rear" or "front", if vip_define_sensor_list = 1, ;vip_dev(x)_pos must be configured! ; ;vip_dev(x)_isp_used 0:not use isp 1:use isp ;vip_dev(x)_fmt: 0:yuv 1:bayer raw rgb ;vip_dev(x)_stby_mode: 0:not shut down power at standby 1:shut down power at standby ;vip_dev(x)_vflip: flip in vertical direction 0:disable 1:enable ;vip_dev(x)_hflip: flip in horizontal direction 0:disable 1:enable ;vip_dev(x)_iovdd: camera module io power handle string, pmu power supply ;vip_dev(x)_iovdd_vol: camera module io power voltage, pmu power supply ;vip_dev(x)_avdd: camera module analog power handle string, pmu power supply ;vip_dev(x)_avdd_vol: camera module analog power voltage, pmu power supply ;vip_dev(x)_dvdd: camera module core power handle string, pmu power supply ;vip_dev(x)_dvdd_vol: camera module core power voltage, pmu power supply ;vip_dev(x)_afvdd: camera module vcm power handle string, pmu power supply ;vip_dev(x)_afvdd_vol: camera module vcm power voltage, pmu power supply ;x indicates the index of the devices which are linked to the same capture bus ;fill voltage in uV, e.g. iovdd = 2.8V, vip_devx_iovdd_vol = 2800000 ;fill handle string as below: ;axp22_eldo3 ;axp22_dldo4 ;axp22_eldo2 ;fill handle string "" when not using any pmu power supply ;-------------------------------------------------------------------------------- [csi0] vip_used = 1 vip_mode = 0 vip_dev_qty = 1 vip_define_sensor_list = 0 vip_csi_pck = port:PE00 vip_csi_mck = port:PE01 vip_csi_hsync = port:PE02 vip_csi_vsync = port:PE03 vip_csi_d0 = vip_csi_d1 = vip_csi_d2 = port:PE06 vip_csi_d3 = port:PE07 vip_csi_d4 = port:PE08 vip_csi_d5 = port:PE09 vip_csi_d6 = port:PE10 vip_csi_d7 = port:PE11 vip_csi_d8 = port:PE12 vip_csi_d9 = port:PE13 vip_csi_sck = port:PE14 vip_csi_sda = port:PE15 vip_dev0_mname = "ov2640" vip_dev0_pos = "rear" vip_dev0_lane = 1 vip_dev0_twi_id = 2 vip_dev0_twi_addr = 0x60 vip_dev0_isp_used = 0 vip_dev0_fmt = 0 vip_dev0_stby_mode = 0 vip_dev0_vflip = 0 vip_dev0_hflip = 0 vip_dev0_iovdd = "" vip_dev0_iovdd_vol = 2800000 vip_dev0_avdd = "" vip_dev0_avdd_vol = 2800000 vip_dev0_dvdd = "" vip_dev0_dvdd_vol = 1500000 vip_dev0_afvdd = "" vip_dev0_afvdd_vol = 2800000 vip_dev0_power_en = vip_dev0_reset = port:PE4 vip_dev0_pwdn = port:PE5 vip_dev0_flash_en = vip_dev0_flash_mode = vip_dev0_af_pwdn = 6、开发板上摄像头的I2C挂载在TWI2上面了,注意打开: ;---------------------------------------------------------------------------------- ;i2c configuration ;---------------------------------------------------------------------------------- [twi0] twi_used = 1 twi_scl = port:PH0 twi_sda = port:PH1 [twi1] twi_used = 1 twi_scl = port:PH2 twi_sda = port:PH3 [twi2] twi_used = 1 twi_scl = port:PH4 twi_sda = port:PH5 不过奇怪的是,摄像头并没有向其它平台那样生成这个设备节点: /sys/class/i2c-adapter/i2c-2/2-0030 shell@octopus-f1:/ $ shell@octopus-f1:/ $ cd /sys/class/i2c-adapter/i2c-2/ shell@octopus-f1:/sys/class/i2c-adapter/i2c-2 $ shell@octopus-f1:/sys/class/i2c-adapter/i2c-2 $ ll drwxr-xr-x root root 1970-01-02 08:06 2-003b --w------- root root 4096 1970-01-02 08:06 delete_device lrwxrwxrwx root root 1970-01-02 08:06 device -> ../../twi.2 -r--r--r-- root root 4096 1970-01-02 08:06 name --w------- root root 4096 1970-01-02 08:06 new_device drwxr-xr-x root root 1970-01-02 08:06 power lrwxrwxrwx root root 1970-01-02 08:06 subsystem -> ../../../../bus/i2c -rw-r--r-- root root 4096 1970-01-02 08:06 uevent shell@octopus-f1:/sys/class/i2c-adapter/i2c-2 $ 可能是ov2640的驱动程序不完整,没有通过i2c_detect来注册2-0030这个节点。 直接在驱动程序中读取I2C,还是对的。device ID = 0x2642。
书名:《Android开发技术实战详解——内核、移植和驱动》(电子工业出版社.王振丽)。本书从底原理开始讲起,结合真实的案例向读者详细介绍了android内核、移植和驱动开发的整个流程。全书分为19章,依次讲解驱动移植的必要性,何为hal深入分析,goldfish、msm、map内核和驱动解析,显示系统、输入系统、振动器系统、音频系统、视频输出系统的驱动,openmax多媒体、多媒体插件框架,传感器、照相机、wi-fi、蓝牙、gps和电话系统等。在每一章中,重点介绍了与Android驱动开发相关的底知识,并对Android源码进行了剖析。 本书适合Android研发人员及Android爱好者学习,也可以作为相关培训学校和大专院校相关专业的教学用书。 全书压缩打包成3部分,这是第2部分。 目录: 第1章 Android开发基础 1 1.1 什么是驱动 1 1.1.1 驱动程序的魅力 1 1.1.2 电脑中的驱动 2 1.1.3 手机中的驱动程序 2 1.2 开源还是不开源的问题 3 1.2.1 雾里看花的开源 3 1.2.2 从为什么选择java谈为什么不开源驱动程序 3 1.2.3 对驱动开发者来说是一把双刃剑 4 1.3 Android和Linux 4 1.3.1 Linux简介 5 1.3.2 Android和Linux的关系 5 1.4 简析Linux内核 8 1.4.1 内核的体系结构 8 1.4.2 和Android密切相关的Linux内核知识 10 1.5 分析Linux内核源代码很有必要 14 1.5.1 源代码目录结构 14 1.5.2 浏览源代码的工具 16 1.5.3 为什么用汇编语言编写内核代码 17 1.5.4 Linux内核的显著特性 18 1.5.5 学习Linux内核的方法 26 第2章 分析Android源代码 31 2.1 搭建Linux开发环境和工具 31 2.1.1 搭建Linux开发环境 31 2.1.2 设置环境变量 32 2.1.3 安装编译工具 32 2.2 获取Android源代码 33 2.3 分析并编译Android源代码 35 2.3.1 Android源代码的结构 35 2.3.2 编译Android源代码 40 2.3.3 运行Android源代码 42 2.3.4 实践演练——演示编译Android程序的两种方法 43 2.4 编译Android kernel 47 2.4.1 获取goldfish内核代码 47 2.4.2 获取msm内核代码 50 2.4.3 获取omap内核代码 50 2.4.4 编译Android的Linux内核 50 2.5 运行模拟器 52 2.5.1 Linux环境下运行模拟器的方法 53 2.5.2 模拟器辅助工具——adb 54 第3章 驱动需要移植 57 3.1 驱动开发需要做的工作 57 3.2 Android移植 59 3.2.1 移植的任务 60 3.2.2 移植的内容 60 3.2.3 驱动开发的任务 61 3.3 Android对Linux的改造 61 3.3.1 Android对Linux内核文件的改动 62 3.3.2 为Android构建 Linux的操作系统 63 3.4 内核空间和用户空间接口是一个媒介 64 3.4.1 内核空间和用户空间的相互作用 64 3.4.2 系统和硬件之间的交互 64 3.4.3 使用relay实现内核到用户空间的数据传输 66 3.5 三类驱动程序 70 3.5.1 字符设备驱动程序 70 3.5.2 块设备驱动程序 79 3.5.3 网络设备驱动程序 82 第4章 hal深入分析 84 4.1 认识hal 84 4.1.1 hal的发展 84 4.1.2 过去和现在的区别 86 4.2 分析hal源代码 86 4.2.1 分析hal moudle 86 4.2.2 分析mokoid工程 89 4.3 总结hal的使用方法 98 4.4 传感器在hal的表现 101 4.4.1 hal的sensor代码 102 4.4.2 总结sensor编程的流程 104 4.4.3 分析sensor源代码看Android api 与硬件平台的衔接 104 4.5 移植总结 116 4.5.1 移植各个Android部件的方式 116 4.5.2 移植技巧之一——不得不说的辅助工作 117 第5章 goldfish下的驱动解析 125 5.1 staging驱动 125 5.1.1 staging驱动概述 125 5.1.2 binder驱动程序 126 5.1.3 logger驱动程序 135 5.1.4 lowmemorykiller组件 136 5.1.5 timed output驱动程序 137 5.1.6 timed gpio驱动程序 139 5.1.7 ram console驱动程序 139 5.2 wakelock和early_suspend 140 5.2.1 wakelock和early_suspend的原理 140 5.2.2 Android休眠 141 5.2.3 Android唤醒 144 5.3 ashmem驱动程序 145 5.4 pmem驱动程序 148 5.5 alarm驱动程序 149 5.5.1 alarm简析 149 5.5.2 alarm驱动程序的实现 150 5.6 usb gadget驱动程序151 5.7 Android paranoid驱动程序153 5.8 goldfish设备驱动154 5.8.1 framebuffer驱动155 5.8.2 键盘驱动159 5.8.3 实时时钟驱动程序160 5.8.4 tty终端驱动程序161 5.8.5 nandflash驱动程序162 5.8.6 mmc驱动程序162 5.8.7 电池驱动程序162 第6章 msm内核和驱动解析164 6.1 msm基础164 6.1.1 常见msm处理器产品164 6.1.2 snapdragon内核介绍165 6.2 移植msm内核简介166 6.3 移植msm168 6.3.1 makefile文件168 6.3.2 驱动和组件170 6.3.3 设备驱动172 6.3.4 高通特有的组件174 第7章 omap内核和驱动解析177 7.1 omap基础177 7.1.1 omap简析177 7.1.2 常见omap处理器产品177 7.1.3 开发平台178 7.2 omap内核178 7.3 移植omap体系结构180 7.3.1 移植omap平台180 7.3.2 移植omap处理器183 7.4 移植Android专用驱动和组件188 7.5 omap的设备驱动190 第8章 显示系统驱动应用195 8.1 显示系统介绍195 8.1.1 Android的版本195 8.1.2 不同版本的显示系统195 8.2 移植和调试前的准备196 8.2.1 framebuffer驱动程序196 8.2.2 硬件抽象198 8.3 实现显示系统的驱动程序210 8.3.1 goldfish中的framebuffer驱动程序210 8.3.2 使用gralloc模块的驱动程序214 8.4 msm高通处理器中的显示驱动实现224 8.4.1 msm中的framebuffer驱动程序225 8.4.2 msm中的gralloc驱动程序227 8.5 omap处理器中的显示驱动实现235 第9章 输入系统驱动应用239 9.1 输入系统介绍239 9.1.1 Android输入系统结构元素介绍239 9.1.2 移植Android输入系统时的工作240 9.2 input(输入)驱动241 9.3 模拟器的输入驱动256 9.4 msm高通处理器中的输入驱动实现257 9.4.1 触摸屏驱动257 9.4.2 按键和轨迹球驱动264 9.5 omap处理器平台中的输入驱动实现266 9.5.1 触摸屏驱动267 9.5.2 键盘驱动267 第10章 振动器系统驱动269 10.1 振动器系统结构269 10.1.1 硬件抽象271 10.1.2 jni框架部分272 10.2 开始移植273 10.2.1 移植振动器驱动程序273 10.2.2 实现硬件抽象274 10.3 在msm平台实现振动器驱动275 第11章 音频系统驱动279 11.1 音频系统结构279 11.2 分析音频系统的次280 11.2.1 次说明280 11.2.2 media库中的audio框架281 11.2.3 本地代码284 11.2.4 jni代码288 11.2.5 java代码289 11.3 移植audio系统的必备技术289 11.3.1 移植audio系统所要做的工作289 11.3.2 分析硬件抽象290 11.3.3 分析audioflinger中的audio硬件抽象的实现291 11.4 真正实现audio硬件抽象298 11.5 msm平台实现audio驱动系统298 11.5.1 实现audio驱动程序298 11.5.2 实现硬件抽象299 11.6 oss平台实现audio驱动系统304 11.6.1 oss驱动程序介绍304 11.6.2 mixer305 11.7 alsa平台实现audio系统312 11.7.1 注册音频设备和音频驱动312 11.7.2 在Android中使用alsa声卡313 11.7.3 在omap平台移植Android的alsa声卡驱动322 第12章 视频输出系统驱动326 12.1 视频输出系统结构326 12.2 需要移植的部分328 12.3 分析硬件抽象328 12.3.1 overlay系统硬件抽象的接口328 12.3.2 实现overlay系统的硬件抽象331 12.3.3 实现接口332 12.4 实现overlay硬件抽象333 12.5 在omap平台实现overlay系统335 12.5.1 实现输出视频驱动程序335 12.5.2 实现overlay硬件抽象337 12.6 系统调用overlay hal的架构342 12.6.1 调用overlay hal的架构的流程342 12.6.2 s3c6410 Android overlay的测试代码346 第13章 openmax多媒体框架349 13.1 openmax基本次结构349 13.2 分析openmax框架构成350 13.2.1 openmax总体次结构350 13.2.2 openmax il的结构351 13.2.3 Android中的openmax354 13.3 实现openmax il接口354 13.3.1 openmax il的接口354 13.3.2 在openmax il中需要做什么361 13.3.3 研究Android中的openmax适配361 13.4 在omap平台实现openmax il363 13.4.1 实现文件364 13.4.2 分析ti openmax il的核心365 13.4.3 实现ti openmax il组件实例368 第14章 多媒体插件框架373 14.1 Android多媒体插件373 14.2 需要移植的内容374 14.3 opencore引擎375 14.3.1 opencore次结构375 14.3.2 opencore代码结构376 14.3.3 opencore编译结构377 14.3.4 opencore oscl381 14.3.5 实现opencore中的openmax部分383 14.3.6 opencore的扩展398 14.4 stagefright引擎404 14.4.1 stagefright代码结构404 14.4.2 stagefright实现openmax接口405 14.4.3 video buffer传输流程409 第15章 传感器系统415 15.1 传感器系统的结构415 15.2 需要移植的内容417 15.2.1 移植驱动程序417 15.2.2 移植硬件抽象418 15.2.3 实现上部分419 15.3 在模拟器中实现传感器424 第16章 照相机系统430 16.1 camera系统的结构430 16.2 需要移植的内容433 16.3 移植和调试433 16.3.1 v4l2驱动程序433 16.3.2 硬件抽象441 16.4 实现camera系统的硬件抽象446 16.4.1 java程序部分446 16.4.2 camera的java本地调用部分447 16.4.3 camera的本地库libui.so448 16.4.4 camera服务libcameraservice.so449 16.5 msm平台实现camera系统454 16.6 omap平台实现camera系统457 第17章 wi-fi系统、蓝牙系统和gps系统459 17.1 wi-fi系统459 17.1.1 wi-fi系统的结构459 17.1.2 需要移植的内容461 17.1.3 移植和调试461 17.1.4 omap平台实现wi-fi469 17.1.5 配置wi-fi的流程471 17.1.6 具体演练——在Android下实现ethernet473 17.2 蓝牙系统475 17.2.1 蓝牙系统的结构475 17.2.2 需要移植的内容477 17.2.3 具体移植478 17.2.4 msm平台的蓝牙驱动480 17.3 定位系统482 17.3.1 定位系统的结构483 17.3.2 需要移植的内容484 17.3.3 移植和调试484 第18章 电话系统498 18.1 电话系统基础498 18.1.1 电话系统简介498 18.1.2 电话系统结构500 18.2 需要移植的内容501 18.3 移植和调试502 18.3.1 驱动程序502 18.3.2 ril接口504 18.4 电话系统实现流程分析507 18.4.1 初始启动流程507 18.4.2 request流程509 18.4.3 response流程512 第19章 其他系统514 19.1 alarm警报器系统514 19.1.1 alarm系统的结构514 19.1.2 需要移植的内容515 19.1.3 移植和调试516 19.1.4 模拟器环境的具体实现518 19.1.5 msm平台实现alarm518 19.2 lights光系统519 19.2.1 lights光系统的结构520 19.2.2 需要移植的内容521 19.2.3 移植和调试521 19.2.4 msm平台实现光系统523 19.3 battery电池系统524 19.3.1 battery系统的结构524 19.3.2 需要移植的内容526 19.3.3 移植和调试526 19.3.4 在模拟器中实现电池系统529
书名:《Android开发技术实战详解——内核、移植和驱动》(电子工业出版社.王振丽)。本书从底原理开始讲起,结合真实的案例向读者详细介绍了android内核、移植和驱动开发的整个流程。全书分为19章,依次讲解驱动移植的必要性,何为hal深入分析,goldfish、msm、map内核和驱动解析,显示系统、输入系统、振动器系统、音频系统、视频输出系统的驱动,openmax多媒体、多媒体插件框架,传感器、照相机、wi-fi、蓝牙、gps和电话系统等。在每一章中,重点介绍了与Android驱动开发相关的底知识,并对Android源码进行了剖析。 本书适合Android研发人员及Android爱好者学习,也可以作为相关培训学校和大专院校相关专业的教学用书。 全书压缩打包成3部分,这是第3部分。 目录: 第1章 Android开发基础 1 1.1 什么是驱动 1 1.1.1 驱动程序的魅力 1 1.1.2 电脑中的驱动 2 1.1.3 手机中的驱动程序 2 1.2 开源还是不开源的问题 3 1.2.1 雾里看花的开源 3 1.2.2 从为什么选择java谈为什么不开源驱动程序 3 1.2.3 对驱动开发者来说是一把双刃剑 4 1.3 Android和Linux 4 1.3.1 Linux简介 5 1.3.2 Android和Linux的关系 5 1.4 简析Linux内核 8 1.4.1 内核的体系结构 8 1.4.2 和Android密切相关的Linux内核知识 10 1.5 分析Linux内核源代码很有必要 14 1.5.1 源代码目录结构 14 1.5.2 浏览源代码的工具 16 1.5.3 为什么用汇编语言编写内核代码 17 1.5.4 Linux内核的显著特性 18 1.5.5 学习Linux内核的方法 26 第2章 分析Android源代码 31 2.1 搭建Linux开发环境和工具 31 2.1.1 搭建Linux开发环境 31 2.1.2 设置环境变量 32 2.1.3 安装编译工具 32 2.2 获取Android源代码 33 2.3 分析并编译Android源代码 35 2.3.1 Android源代码的结构 35 2.3.2 编译Android源代码 40 2.3.3 运行Android源代码 42 2.3.4 实践演练——演示编译Android程序的两种方法 43 2.4 编译Android kernel 47 2.4.1 获取goldfish内核代码 47 2.4.2 获取msm内核代码 50 2.4.3 获取omap内核代码 50 2.4.4 编译Android的Linux内核 50 2.5 运行模拟器 52 2.5.1 Linux环境下运行模拟器的方法 53 2.5.2 模拟器辅助工具——adb 54 第3章 驱动需要移植 57 3.1 驱动开发需要做的工作 57 3.2 Android移植 59 3.2.1 移植的任务 60 3.2.2 移植的内容 60 3.2.3 驱动开发的任务 61 3.3 Android对Linux的改造 61 3.3.1 Android对Linux内核文件的改动 62 3.3.2 为Android构建 Linux的操作系统 63 3.4 内核空间和用户空间接口是一个媒介 64 3.4.1 内核空间和用户空间的相互作用 64 3.4.2 系统和硬件之间的交互 64 3.4.3 使用relay实现内核到用户空间的数据传输 66 3.5 三类驱动程序 70 3.5.1 字符设备驱动程序 70 3.5.2 块设备驱动程序 79 3.5.3 网络设备驱动程序 82 第4章 hal深入分析 84 4.1 认识hal 84 4.1.1 hal的发展 84 4.1.2 过去和现在的区别 86 4.2 分析hal源代码 86 4.2.1 分析hal moudle 86 4.2.2 分析mokoid工程 89 4.3 总结hal的使用方法 98 4.4 传感器在hal的表现 101 4.4.1 hal的sensor代码 102 4.4.2 总结sensor编程的流程 104 4.4.3 分析sensor源代码看Android api 与硬件平台的衔接 104 4.5 移植总结 116 4.5.1 移植各个Android部件的方式 116 4.5.2 移植技巧之一——不得不说的辅助工作 117 第5章 goldfish下的驱动解析 125 5.1 staging驱动 125 5.1.1 staging驱动概述 125 5.1.2 binder驱动程序 126 5.1.3 logger驱动程序 135 5.1.4 lowmemorykiller组件 136 5.1.5 timed output驱动程序 137 5.1.6 timed gpio驱动程序 139 5.1.7 ram console驱动程序 139 5.2 wakelock和early_suspend 140 5.2.1 wakelock和early_suspend的原理 140 5.2.2 Android休眠 141 5.2.3 Android唤醒 144 5.3 ashmem驱动程序 145 5.4 pmem驱动程序 148 5.5 alarm驱动程序 149 5.5.1 alarm简析 149 5.5.2 alarm驱动程序的实现 150 5.6 usb gadget驱动程序151 5.7 Android paranoid驱动程序153 5.8 goldfish设备驱动154 5.8.1 framebuffer驱动155 5.8.2 键盘驱动159 5.8.3 实时时钟驱动程序160 5.8.4 tty终端驱动程序161 5.8.5 nandflash驱动程序162 5.8.6 mmc驱动程序162 5.8.7 电池驱动程序162 第6章 msm内核和驱动解析164 6.1 msm基础164 6.1.1 常见msm处理器产品164 6.1.2 snapdragon内核介绍165 6.2 移植msm内核简介166 6.3 移植msm168 6.3.1 makefile文件168 6.3.2 驱动和组件170 6.3.3 设备驱动172 6.3.4 高通特有的组件174 第7章 omap内核和驱动解析177 7.1 omap基础177 7.1.1 omap简析177 7.1.2 常见omap处理器产品177 7.1.3 开发平台178 7.2 omap内核178 7.3 移植omap体系结构180 7.3.1 移植omap平台180 7.3.2 移植omap处理器183 7.4 移植Android专用驱动和组件188 7.5 omap的设备驱动190 第8章 显示系统驱动应用195 8.1 显示系统介绍195 8.1.1 Android的版本195 8.1.2 不同版本的显示系统195 8.2 移植和调试前的准备196 8.2.1 framebuffer驱动程序196 8.2.2 硬件抽象198 8.3 实现显示系统的驱动程序210 8.3.1 goldfish中的framebuffer驱动程序210 8.3.2 使用gralloc模块的驱动程序214 8.4 msm高通处理器中的显示驱动实现224 8.4.1 msm中的framebuffer驱动程序225 8.4.2 msm中的gralloc驱动程序227 8.5 omap处理器中的显示驱动实现235 第9章 输入系统驱动应用239 9.1 输入系统介绍239 9.1.1 Android输入系统结构元素介绍239 9.1.2 移植Android输入系统时的工作240 9.2 input(输入)驱动241 9.3 模拟器的输入驱动256 9.4 msm高通处理器中的输入驱动实现257 9.4.1 触摸屏驱动257 9.4.2 按键和轨迹球驱动264 9.5 omap处理器平台中的输入驱动实现266 9.5.1 触摸屏驱动267 9.5.2 键盘驱动267 第10章 振动器系统驱动269 10.1 振动器系统结构269 10.1.1 硬件抽象271 10.1.2 jni框架部分272 10.2 开始移植273 10.2.1 移植振动器驱动程序273 10.2.2 实现硬件抽象274 10.3 在msm平台实现振动器驱动275 第11章 音频系统驱动279 11.1 音频系统结构279 11.2 分析音频系统的次280 11.2.1 次说明280 11.2.2 media库中的audio框架281 11.2.3 本地代码284 11.2.4 jni代码288 11.2.5 java代码289 11.3 移植audio系统的必备技术289 11.3.1 移植audio系统所要做的工作289 11.3.2 分析硬件抽象290 11.3.3 分析audioflinger中的audio硬件抽象的实现291 11.4 真正实现audio硬件抽象298 11.5 msm平台实现audio驱动系统298 11.5.1 实现audio驱动程序298 11.5.2 实现硬件抽象299 11.6 oss平台实现audio驱动系统304 11.6.1 oss驱动程序介绍304 11.6.2 mixer305 11.7 alsa平台实现audio系统312 11.7.1 注册音频设备和音频驱动312 11.7.2 在Android中使用alsa声卡313 11.7.3 在omap平台移植Android的alsa声卡驱动322 第12章 视频输出系统驱动326 12.1 视频输出系统结构326 12.2 需要移植的部分328 12.3 分析硬件抽象328 12.3.1 overlay系统硬件抽象的接口328 12.3.2 实现overlay系统的硬件抽象331 12.3.3 实现接口332 12.4 实现overlay硬件抽象333 12.5 在omap平台实现overlay系统335 12.5.1 实现输出视频驱动程序335 12.5.2 实现overlay硬件抽象337 12.6 系统调用overlay hal的架构342 12.6.1 调用overlay hal的架构的流程342 12.6.2 s3c6410 Android overlay的测试代码346 第13章 openmax多媒体框架349 13.1 openmax基本次结构349 13.2 分析openmax框架构成350 13.2.1 openmax总体次结构350 13.2.2 openmax il的结构351 13.2.3 Android中的openmax354 13.3 实现openmax il接口354 13.3.1 openmax il的接口354 13.3.2 在openmax il中需要做什么361 13.3.3 研究Android中的openmax适配361 13.4 在omap平台实现openmax il363 13.4.1 实现文件364 13.4.2 分析ti openmax il的核心365 13.4.3 实现ti openmax il组件实例368 第14章 多媒体插件框架373 14.1 Android多媒体插件373 14.2 需要移植的内容374 14.3 opencore引擎375 14.3.1 opencore次结构375 14.3.2 opencore代码结构376 14.3.3 opencore编译结构377 14.3.4 opencore oscl381 14.3.5 实现opencore中的openmax部分383 14.3.6 opencore的扩展398 14.4 stagefright引擎404 14.4.1 stagefright代码结构404 14.4.2 stagefright实现openmax接口405 14.4.3 video buffer传输流程409 第15章 传感器系统415 15.1 传感器系统的结构415 15.2 需要移植的内容417 15.2.1 移植驱动程序417 15.2.2 移植硬件抽象418 15.2.3 实现上部分419 15.3 在模拟器中实现传感器424 第16章 照相机系统430 16.1 camera系统的结构430 16.2 需要移植的内容433 16.3 移植和调试433 16.3.1 v4l2驱动程序433 16.3.2 硬件抽象441 16.4 实现camera系统的硬件抽象446 16.4.1 java程序部分446 16.4.2 camera的java本地调用部分447 16.4.3 camera的本地库libui.so448 16.4.4 camera服务libcameraservice.so449 16.5 msm平台实现camera系统454 16.6 omap平台实现camera系统457 第17章 wi-fi系统、蓝牙系统和gps系统459 17.1 wi-fi系统459 17.1.1 wi-fi系统的结构459 17.1.2 需要移植的内容461 17.1.3 移植和调试461 17.1.4 omap平台实现wi-fi469 17.1.5 配置wi-fi的流程471 17.1.6 具体演练——在Android下实现ethernet473 17.2 蓝牙系统475 17.2.1 蓝牙系统的结构475 17.2.2 需要移植的内容477 17.2.3 具体移植478 17.2.4 msm平台的蓝牙驱动480 17.3 定位系统482 17.3.1 定位系统的结构483 17.3.2 需要移植的内容484 17.3.3 移植和调试484 第18章 电话系统498 18.1 电话系统基础498 18.1.1 电话系统简介498 18.1.2 电话系统结构500 18.2 需要移植的内容501 18.3 移植和调试502 18.3.1 驱动程序502 18.3.2 ril接口504 18.4 电话系统实现流程分析507 18.4.1 初始启动流程507 18.4.2 request流程509 18.4.3 response流程512 第19章 其他系统514 19.1 alarm警报器系统514 19.1.1 alarm系统的结构514 19.1.2 需要移植的内容515 19.1.3 移植和调试516 19.1.4 模拟器环境的具体实现518 19.1.5 msm平台实现alarm518 19.2 lights光系统519 19.2.1 lights光系统的结构520 19.2.2 需要移植的内容521 19.2.3 移植和调试521 19.2.4 msm平台实现光系统523 19.3 battery电池系统524 19.3.1 battery系统的结构524 19.3.2 需要移植的内容526 19.3.3 移植和调试526 19.3.4 在模拟器中实现电池系统529
书名:《Android开发技术实战详解——内核、移植和驱动》(电子工业出版社.王振丽)。本书从底原理开始讲起,结合真实的案例向读者详细介绍了android内核、移植和驱动开发的整个流程。全书分为19章,依次讲解驱动移植的必要性,何为hal深入分析,goldfish、msm、map内核和驱动解析,显示系统、输入系统、振动器系统、音频系统、视频输出系统的驱动,openmax多媒体、多媒体插件框架,传感器、照相机、wi-fi、蓝牙、gps和电话系统等。在每一章中,重点介绍了与Android驱动开发相关的底知识,并对Android源码进行了剖析。 本书适合Android研发人员及Android爱好者学习,也可以作为相关培训学校和大专院校相关专业的教学用书。 全书压缩打包成3部分,这是第1部分。 目录: 第1章 Android开发基础 1 1.1 什么是驱动 1 1.1.1 驱动程序的魅力 1 1.1.2 电脑中的驱动 2 1.1.3 手机中的驱动程序 2 1.2 开源还是不开源的问题 3 1.2.1 雾里看花的开源 3 1.2.2 从为什么选择java谈为什么不开源驱动程序 3 1.2.3 对驱动开发者来说是一把双刃剑 4 1.3 Android和Linux 4 1.3.1 Linux简介 5 1.3.2 Android和Linux的关系 5 1.4 简析Linux内核 8 1.4.1 内核的体系结构 8 1.4.2 和Android密切相关的Linux内核知识 10 1.5 分析Linux内核源代码很有必要 14 1.5.1 源代码目录结构 14 1.5.2 浏览源代码的工具 16 1.5.3 为什么用汇编语言编写内核代码 17 1.5.4 Linux内核的显著特性 18 1.5.5 学习Linux内核的方法 26 第2章 分析Android源代码 31 2.1 搭建Linux开发环境和工具 31 2.1.1 搭建Linux开发环境 31 2.1.2 设置环境变量 32 2.1.3 安装编译工具 32 2.2 获取Android源代码 33 2.3 分析并编译Android源代码 35 2.3.1 Android源代码的结构 35 2.3.2 编译Android源代码 40 2.3.3 运行Android源代码 42 2.3.4 实践演练——演示编译Android程序的两种方法 43 2.4 编译Android kernel 47 2.4.1 获取goldfish内核代码 47 2.4.2 获取msm内核代码 50 2.4.3 获取omap内核代码 50 2.4.4 编译Android的Linux内核 50 2.5 运行模拟器 52 2.5.1 Linux环境下运行模拟器的方法 53 2.5.2 模拟器辅助工具——adb 54 第3章 驱动需要移植 57 3.1 驱动开发需要做的工作 57 3.2 Android移植 59 3.2.1 移植的任务 60 3.2.2 移植的内容 60 3.2.3 驱动开发的任务 61 3.3 Android对Linux的改造 61 3.3.1 Android对Linux内核文件的改动 62 3.3.2 为Android构建 Linux的操作系统 63 3.4 内核空间和用户空间接口是一个媒介 64 3.4.1 内核空间和用户空间的相互作用 64 3.4.2 系统和硬件之间的交互 64 3.4.3 使用relay实现内核到用户空间的数据传输 66 3.5 三类驱动程序 70 3.5.1 字符设备驱动程序 70 3.5.2 块设备驱动程序 79 3.5.3 网络设备驱动程序 82 第4章 hal深入分析 84 4.1 认识hal 84 4.1.1 hal的发展 84 4.1.2 过去和现在的区别 86 4.2 分析hal源代码 86 4.2.1 分析hal moudle 86 4.2.2 分析mokoid工程 89 4.3 总结hal的使用方法 98 4.4 传感器在hal的表现 101 4.4.1 hal的sensor代码 102 4.4.2 总结sensor编程的流程 104 4.4.3 分析sensor源代码看Android api 与硬件平台的衔接 104 4.5 移植总结 116 4.5.1 移植各个Android部件的方式 116 4.5.2 移植技巧之一——不得不说的辅助工作 117 第5章 goldfish下的驱动解析 125 5.1 staging驱动 125 5.1.1 staging驱动概述 125 5.1.2 binder驱动程序 126 5.1.3 logger驱动程序 135 5.1.4 lowmemorykiller组件 136 5.1.5 timed output驱动程序 137 5.1.6 timed gpio驱动程序 139 5.1.7 ram console驱动程序 139 5.2 wakelock和early_suspend 140 5.2.1 wakelock和early_suspend的原理 140 5.2.2 Android休眠 141 5.2.3 Android唤醒 144 5.3 ashmem驱动程序 145 5.4 pmem驱动程序 148 5.5 alarm驱动程序 149 5.5.1 alarm简析 149 5.5.2 alarm驱动程序的实现 150 5.6 usb gadget驱动程序151 5.7 Android paranoid驱动程序153 5.8 goldfish设备驱动154 5.8.1 framebuffer驱动155 5.8.2 键盘驱动159 5.8.3 实时时钟驱动程序160 5.8.4 tty终端驱动程序161 5.8.5 nandflash驱动程序162 5.8.6 mmc驱动程序162 5.8.7 电池驱动程序162 第6章 msm内核和驱动解析164 6.1 msm基础164 6.1.1 常见msm处理器产品164 6.1.2 snapdragon内核介绍165 6.2 移植msm内核简介166 6.3 移植msm168 6.3.1 makefile文件168 6.3.2 驱动和组件170 6.3.3 设备驱动172 6.3.4 高通特有的组件174 第7章 omap内核和驱动解析177 7.1 omap基础177 7.1.1 omap简析177 7.1.2 常见omap处理器产品177 7.1.3 开发平台178 7.2 omap内核178 7.3 移植omap体系结构180 7.3.1 移植omap平台180 7.3.2 移植omap处理器183 7.4 移植Android专用驱动和组件188 7.5 omap的设备驱动190 第8章 显示系统驱动应用195 8.1 显示系统介绍195 8.1.1 Android的版本195 8.1.2 不同版本的显示系统195 8.2 移植和调试前的准备196 8.2.1 framebuffer驱动程序196 8.2.2 硬件抽象198 8.3 实现显示系统的驱动程序210 8.3.1 goldfish中的framebuffer驱动程序210 8.3.2 使用gralloc模块的驱动程序214 8.4 msm高通处理器中的显示驱动实现224 8.4.1 msm中的framebuffer驱动程序225 8.4.2 msm中的gralloc驱动程序227 8.5 omap处理器中的显示驱动实现235 第9章 输入系统驱动应用239 9.1 输入系统介绍239 9.1.1 Android输入系统结构元素介绍239 9.1.2 移植Android输入系统时的工作240 9.2 input(输入)驱动241 9.3 模拟器的输入驱动256 9.4 msm高通处理器中的输入驱动实现257 9.4.1 触摸屏驱动257 9.4.2 按键和轨迹球驱动264 9.5 omap处理器平台中的输入驱动实现266 9.5.1 触摸屏驱动267 9.5.2 键盘驱动267 第10章 振动器系统驱动269 10.1 振动器系统结构269 10.1.1 硬件抽象271 10.1.2 jni框架部分272 10.2 开始移植273 10.2.1 移植振动器驱动程序273 10.2.2 实现硬件抽象274 10.3 在msm平台实现振动器驱动275 第11章 音频系统驱动279 11.1 音频系统结构279 11.2 分析音频系统的次280 11.2.1 次说明280 11.2.2 media库中的audio框架281 11.2.3 本地代码284 11.2.4 jni代码288 11.2.5 java代码289 11.3 移植audio系统的必备技术289 11.3.1 移植audio系统所要做的工作289 11.3.2 分析硬件抽象290 11.3.3 分析audioflinger中的audio硬件抽象的实现291 11.4 真正实现audio硬件抽象298 11.5 msm平台实现audio驱动系统298 11.5.1 实现audio驱动程序298 11.5.2 实现硬件抽象299 11.6 oss平台实现audio驱动系统304 11.6.1 oss驱动程序介绍304 11.6.2 mixer305 11.7 alsa平台实现audio系统312 11.7.1 注册音频设备和音频驱动312 11.7.2 在Android中使用alsa声卡313 11.7.3 在omap平台移植Android的alsa声卡驱动322 第12章 视频输出系统驱动326 12.1 视频输出系统结构326 12.2 需要移植的部分328 12.3 分析硬件抽象328 12.3.1 overlay系统硬件抽象的接口328 12.3.2 实现overlay系统的硬件抽象331 12.3.3 实现接口332 12.4 实现overlay硬件抽象333 12.5 在omap平台实现overlay系统335 12.5.1 实现输出视频驱动程序335 12.5.2 实现overlay硬件抽象337 12.6 系统调用overlay hal的架构342 12.6.1 调用overlay hal的架构的流程342 12.6.2 s3c6410 Android overlay的测试代码346 第13章 openmax多媒体框架349 13.1 openmax基本次结构349 13.2 分析openmax框架构成350 13.2.1 openmax总体次结构350 13.2.2 openmax il的结构351 13.2.3 Android中的openmax354 13.3 实现openmax il接口354 13.3.1 openmax il的接口354 13.3.2 在openmax il中需要做什么361 13.3.3 研究Android中的openmax适配361 13.4 在omap平台实现openmax il363 13.4.1 实现文件364 13.4.2 分析ti openmax il的核心365 13.4.3 实现ti openmax il组件实例368 第14章 多媒体插件框架373 14.1 Android多媒体插件373 14.2 需要移植的内容374 14.3 opencore引擎375 14.3.1 opencore次结构375 14.3.2 opencore代码结构376 14.3.3 opencore编译结构377 14.3.4 opencore oscl381 14.3.5 实现opencore中的openmax部分383 14.3.6 opencore的扩展398 14.4 stagefright引擎404 14.4.1 stagefright代码结构404 14.4.2 stagefright实现openmax接口405 14.4.3 video buffer传输流程409 第15章 传感器系统415 15.1 传感器系统的结构415 15.2 需要移植的内容417 15.2.1 移植驱动程序417 15.2.2 移植硬件抽象418 15.2.3 实现上部分419 15.3 在模拟器中实现传感器424 第16章 照相机系统430 16.1 camera系统的结构430 16.2 需要移植的内容433 16.3 移植和调试433 16.3.1 v4l2驱动程序433 16.3.2 硬件抽象441 16.4 实现camera系统的硬件抽象446 16.4.1 java程序部分446 16.4.2 camera的java本地调用部分447 16.4.3 camera的本地库libui.so448 16.4.4 camera服务libcameraservice.so449 16.5 msm平台实现camera系统454 16.6 omap平台实现camera系统457 第17章 wi-fi系统、蓝牙系统和gps系统459 17.1 wi-fi系统459 17.1.1 wi-fi系统的结构459 17.1.2 需要移植的内容461 17.1.3 移植和调试461 17.1.4 omap平台实现wi-fi469 17.1.5 配置wi-fi的流程471 17.1.6 具体演练——在Android下实现ethernet473 17.2 蓝牙系统475 17.2.1 蓝牙系统的结构475 17.2.2 需要移植的内容477 17.2.3 具体移植478 17.2.4 msm平台的蓝牙驱动480 17.3 定位系统482 17.3.1 定位系统的结构483 17.3.2 需要移植的内容484 17.3.3 移植和调试484 第18章 电话系统498 18.1 电话系统基础498 18.1.1 电话系统简介498 18.1.2 电话系统结构500 18.2 需要移植的内容501 18.3 移植和调试502 18.3.1 驱动程序502 18.3.2 ril接口504 18.4 电话系统实现流程分析507 18.4.1 初始启动流程507 18.4.2 request流程509 18.4.3 response流程512 第19章 其他系统514 19.1 alarm警报器系统514 19.1.1 alarm系统的结构514 19.1.2 需要移植的内容515 19.1.3 移植和调试516 19.1.4 模拟器环境的具体实现518 19.1.5 msm平台实现alarm518 19.2 lights光系统519 19.2.1 lights光系统的结构520 19.2.2 需要移植的内容521 19.2.3 移植和调试521 19.2.4 msm平台实现光系统523 19.3 battery电池系统524 19.3.1 battery系统的结构524 19.3.2 需要移植的内容526 19.3.3 移植和调试526 19.3.4 在模拟器中实现电池系统529

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值