{"id":690,"date":"2013-08-25T17:47:59","date_gmt":"2013-08-25T09:47:59","guid":{"rendered":"http:\/\/guoh.ai\/lifelog\/?p=690"},"modified":"2013-09-02T13:42:57","modified_gmt":"2013-09-02T05:42:57","slug":"qcam-hal-2-0","status":"publish","type":"post","link":"https:\/\/guoh.ai\/lifelog\/2013\/08\/qcam-hal-2-0\/","title":{"rendered":"Qualcomm Camera HAL 2.0"},"content":{"rendered":"<p>\u6211\u4eec\u77e5\u9053\u5728HAL\u7684Vendor\u5b9e\u73b0\u5f53\u4e2d\u4f1a\u52a8\u6001\u53bbload\u4e00\u4e2a\u540d\u5b57\u4e3acamera.$platform$.so\u7684\u6863\u6848\uff0c\u7136\u540e\u53bb\u52a0\u8f7dAndroid HAL\u5f53\u4e2d\u5b9a\u4e49\u7684\u65b9\u6cd5\uff0c\u8fd9\u91cc\u4ee5Camera HAL 2.0\u5e76\u4e14Qualcomm msm8960\u4e3a\u4f8b\u5b50\u770b\u4e0b\uff0c\u7ed3\u5408\u4e4b\u524d\u7684<a href=\"http:\/\/guoh.ai\/lifelog\/2013\/07\/glance-at-camera-hal-2-0\/\" target=\"_blank\">\u4e00\u7bc7\u6587\u7ae0<\/a>(http:\/\/guoh.ai\/lifelog\/2013\/07\/glance-at-camera-hal-2-0\/)\u3002<\/p>\n<p>(\u6ce8\uff1a\u8fd9\u7bc7\u6587\u7ae0\u5df2\u7ecf\u8349\u7a3f\u6bd4\u8f83\u4e45\u4e86\uff0c\u4f46\u662f\u4e00\u76f4\u6ca1\u6709\u53d1\u51fa\u6765\uff0c\u56e0\u4e3a\u624b\u91cc\u7684\u8fd9\u7248\u4ee3\u7801\u6ca1\u6709\u8bbe\u5907\u53ef\u4ee5\u8dd1\uff0c\u53e6\u5916\u4e5f\u65e0\u6cd5\u786e\u5b9a\u4ee3\u7801\u662f\u5426\u5b8c\u5168\u6b63\u786e\uff0c\u81f3\u5c11\u53d1\u73b0\u4e86\u4e00\u4e9b\u5730\u65b9\u90fd\u662fstub\u5b9e\u73b0\uff0c\u6587\u4e2d\u53ef\u80fd\u5b58\u5728\u4e00\u4e9b\u9519\u8bef\uff0c\u5982\u53d1\u73b0\u4e0d\u6b63\u786e\u7684\u5730\u65b9\u6b22\u8fce\u6307\u51fa\uff0c\u6211\u4e5f\u4f1a\u5c3d\u91cf\u53d1\u73b0\u9519\u8bef\u5e76\u4fee\u6b63\uff01)<\/p>\n<p>\u6211\u4eec\u77e5\u9053\u5728camera2.h\u5f53\u4e2d\u5b9a\u4e49\u4e86\u5f88\u591a\u65b9\u6cd5\uff0c\u90a3\u4e48\u5728msm8960 HAL\u5c31\u662f\u5728\u5982\u4e0b\u5730\u65b9<br \/>\n\/path\/to\/qcam-hal\/QCamera\/HAL2<br \/>\n\u8fd9\u7f16\u8bd1\u51fa\u6765\u5c31\u662f\u4e00\u4e2acamera.$platform$.so\uff0c\u8bf7\u770b\u5b83\u7684\u5b9e\u73b0<br \/>\n\u9996\u5148\u662fHAL2\/wrapper\/QualcommCamera.h|cpp<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\/**\r\n * The functions need to be provided by the camera HAL.\r\n *\r\n * If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo()\r\n * and openCameraHardware() is 0 to N-1.\r\n *\/\r\n\r\nstatic hw_module_methods_t camera_module_methods = {\r\n    open: camera_device_open,\r\n};\r\n\r\nstatic hw_module_t camera_common  = {\r\n    tag: HARDWARE_MODULE_TAG,\r\n    module_api_version: CAMERA_MODULE_API_VERSION_2_0, \/\/ \u8fd9\u6837Camera Service\u624d\u4f1a\u53bb\u521d\u59cb\u5316Camera2Client\u4e00\u7cfb\u5217\r\n    hal_api_version: HARDWARE_HAL_API_VERSION,\r\n    id: CAMERA_HARDWARE_MODULE_ID,\r\n    name: &quot;Qcamera&quot;,\r\n    author:&quot;Qcom&quot;,\r\n    methods: &amp;camera_module_methods,\r\n    dso: NULL,\r\n    reserved:  {0},\r\n};\r\n\r\ncamera_module_t HAL_MODULE_INFO_SYM = { \/\/ \u8fd9\u4e2aHMI\uff0c\u6bcf\u4e2aHAL\u6a21\u5757\u90fd\u5fc5\u987b\u6709\u7684\r\n    common: camera_common,\r\n    get_number_of_cameras: get_number_of_cameras,\r\n    get_camera_info: get_camera_info,\r\n};\r\n\r\ncamera2_device_ops_t camera_ops = { \/\/ \u6ce8\u610f\u8fd9\u4e9b\u7ed1\u5b9a\u7684\u51fd\u6570\r\n    set_request_queue_src_ops:           android::set_request_queue_src_ops,\r\n    notify_request_queue_not_empty:      android::notify_request_queue_not_empty,\r\n    set_frame_queue_dst_ops:             android::set_frame_queue_dst_ops,\r\n    get_in_progress_count:               android::get_in_progress_count,\r\n    flush_captures_in_progress:          android::flush_captures_in_progress,\r\n    construct_default_request:           android::construct_default_request,\r\n\r\n    allocate_stream:                     android::allocate_stream,\r\n    register_stream_buffers:             android::register_stream_buffers,\r\n    release_stream:                      android::release_stream,\r\n\r\n    allocate_reprocess_stream:           android::allocate_reprocess_stream,\r\n    allocate_reprocess_stream_from_stream: android::allocate_reprocess_stream_from_stream,\r\n    release_reprocess_stream:            android::release_reprocess_stream,\r\n\r\n    trigger_action:                      android::trigger_action,\r\n    set_notify_callback:                 android::set_notify_callback,\r\n    get_metadata_vendor_tag_ops:         android::get_metadata_vendor_tag_ops,\r\n    dump:                                android::dump,\r\n};\r\n\r\ntypedef struct { \/\/ \u6ce8\u610f\u8fd9\u4e2a\u662fQualcomm\u81ea\u5df1\u5b9a\u4e49\u7684\u4e00\u4e2awrap\u7ed3\u6784\r\n  camera2_device_t hw_dev; \/\/ \u8fd9\u91cc\u662f\u6807\u51c6\u7684\r\n  QCameraHardwareInterface *hardware;\r\n  int camera_released;\r\n  int cameraId;\r\n} camera_hardware_t;\r\n\r\n\/* HAL should return NULL if it fails to open camera hardware. *\/\r\nextern &quot;C&quot; int  camera_device_open(\r\n  const struct hw_module_t* module, const char* id,\r\n          struct hw_device_t** hw_device)\r\n{\r\n    int rc = -1;\r\n    int mode = 0;\r\n    camera2_device_t *device = NULL;\r\n    if (module &amp;&amp; id &amp;&amp; hw_device) {\r\n        int cameraId = atoi(id);\r\n\r\n        if (!strcmp(module-&gt;name, camera_common.name)) {\r\n            camera_hardware_t *camHal =\r\n                (camera_hardware_t *) malloc(sizeof (camera_hardware_t));\r\n            if (!camHal) {\r\n                *hw_device = NULL;\r\n\t        \tALOGE(&quot;%s:  end in no mem&quot;, __func__);\r\n\t\t\t\treturn rc;\r\n\t    \t}\r\n\t\t    \/* we have the camera_hardware obj malloced *\/\r\n\t\t    memset(camHal, 0, sizeof (camera_hardware_t));\r\n\t\t    camHal-&gt;hardware = new QCameraHardwareInterface(cameraId, mode);\r\n\t\t    if (camHal-&gt;hardware &amp;&amp; camHal-&gt;hardware-&gt;isCameraReady()) {\r\n\t\t\t\tcamHal-&gt;cameraId = cameraId;\r\n\t\t    \tdevice = &amp;camHal-&gt;hw_dev; \/\/ \u8fd9\u91cccamera2_device_t\r\n\t\t        device-&gt;common.close = close_camera_device; \/\/ \u521d\u59cb\u5316camera2_device_t\r\n\t\t        device-&gt;common.version = CAMERA_DEVICE_API_VERSION_2_0;\r\n\t\t        device-&gt;ops = &amp;camera_ops;\r\n\t\t        device-&gt;priv = (void *)camHal;\r\n\t\t        rc =  0;\r\n\t\t    } else {\r\n\t\t        if (camHal-&gt;hardware) {\r\n\t\t            delete camHal-&gt;hardware;\r\n\t\t            camHal-&gt;hardware = NULL;\r\n\t\t        }\r\n\t\t        free(camHal);\r\n\t\t        device = NULL;\r\n\t\t    }\r\n        }\r\n    }\r\n    \/* pass actual hw_device ptr to framework. This amkes that we actally be use memberof() macro *\/\r\n    *hw_device = (hw_device_t*)&amp;device-&gt;common; \/\/ \u8fd9\u5c31\u662fkernel\u6216\u8005Android native framework\u5e38\u7528\u7684\u4e00\u62db\r\n    return rc;\r\n}<\/pre>\n<p>\u770b\u770ballocate stream<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int allocate_stream(const struct camera2_device *device,\r\n        uint32_t width,\r\n        uint32_t height,\r\n        int      format,\r\n        const camera2_stream_ops_t *stream_ops,\r\n        uint32_t *stream_id,\r\n        uint32_t *format_actual,\r\n        uint32_t *usage,\r\n        uint32_t *max_buffers)\r\n{\r\n    QCameraHardwareInterface *hardware = util_get_Hal_obj(device);\r\n\thardware-&gt;allocate_stream(width, height, format, stream_ops,\r\n            stream_id, format_actual, usage, max_buffers);\r\n    return rc;\r\n}<\/pre>\n<p>\u8fd9\u91cc\u6ce8\u610fQCameraHardwareInterface\u5728QCameraHWI.h|cpp\u5f53\u4e2d<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int QCameraHardwareInterface::allocate_stream(\r\n    uint32_t width,\r\n    uint32_t height, int format,\r\n    const camera2_stream_ops_t *stream_ops,\r\n    uint32_t *stream_id,\r\n    uint32_t *format_actual,\r\n    uint32_t *usage,\r\n    uint32_t *max_buffers)\r\n{\r\n    int ret = OK;\r\n    QCameraStream *stream = NULL;\r\n    camera_mode_t myMode = (camera_mode_t)(CAMERA_MODE_2D|CAMERA_NONZSL_MODE);\r\n\r\n    stream = QCameraStream_preview::createInstance(\r\n                        mCameraHandle-&gt;camera_handle,\r\n                        mChannelId,\r\n                        width,\r\n                        height,\r\n                        format,\r\n                        mCameraHandle,\r\n                        myMode);\r\n\r\n    stream-&gt;setPreviewWindow(stream_ops); \/\/ \u8fd9\u91cc\uff0c\u4e5f\u5c31\u662f\u53ea\u8981\u901a\u8fc7\u8be5\u65b9\u6cd5\u521b\u5efa\u7684stream\uff0c\u90fd\u4f1a\u6709\u5bf9\u5e94\u7684ANativeWindow\u8fdb\u6765\r\n    *stream_id = stream-&gt;getStreamId();\r\n    *max_buffers= stream-&gt;getMaxBuffers(); \/\/ \u4eceHAL\u5f97\u5230\u7684\r\n    *usage = GRALLOC_USAGE_HW_CAMERA_WRITE | CAMERA_GRALLOC_HEAP_ID\r\n        | CAMERA_GRALLOC_FALLBACK_HEAP_ID;\r\n    \/* Set to an arbitrary format SUPPORTED by gralloc *\/\r\n    *format_actual = HAL_PIXEL_FORMAT_YCrCb_420_SP;\r\n\r\n    return ret;\r\n}<\/pre>\n<p>QCameraStream_preview::createInstance\u76f4\u63a5\u8c03\u7528\u81ea\u5df1\u7684\u6784\u9020\u65b9\u6cd5\uff0c\u4e5f\u5c31\u662f\u4e0b\u9762<br \/>\n(\u76f8\u5173class\u5728QCameraStream.h|cpp\u548cQCameraStream_Preview.cpp)<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">QCameraStream_preview::QCameraStream_preview(uint32_t CameraHandle,\r\n                        uint32_t ChannelId,\r\n                        uint32_t Width,\r\n                        uint32_t Height,\r\n                        int requestedFormat,\r\n                        mm_camera_vtbl_t *mm_ops,\r\n                        camera_mode_t mode) :\r\n                 QCameraStream(CameraHandle,\r\n                        ChannelId,\r\n                        Width,\r\n                        Height,\r\n                        mm_ops,\r\n                        mode),\r\n                 mLastQueuedFrame(NULL),\r\n                 mDisplayBuf(NULL),\r\n                 mNumFDRcvd(0)\r\n{\r\n    mStreamId = allocateStreamId(); \/\/ \u5206\u914dstream id(\u6839\u636emStreamTable)\r\n\r\n    switch (requestedFormat) { \/\/ max buffer number\r\n    case CAMERA2_HAL_PIXEL_FORMAT_OPAQUE:\r\n        mMaxBuffers = 5;\r\n        break;\r\n    case HAL_PIXEL_FORMAT_BLOB:\r\n        mMaxBuffers = 1;\r\n        break;\r\n    default:\r\n        ALOGE(&quot;Unsupported requested format %d&quot;, requestedFormat);\r\n        mMaxBuffers = 1;\r\n        break;\r\n    }\r\n    \/*TODO: There has to be a better way to do this*\/\r\n}<\/pre>\n<p>\u518d\u770b\u770b<br \/>\n\/path\/to\/qcam-hal\/QCamera\/stack\/mm-camera-interface\/<br \/>\nmm_camera_interface.h<br \/>\n\u5f53\u4e2d<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">typedef struct {\r\n    uint32_t camera_handle;        \/* camera object handle *\/\r\n    mm_camera_info_t *camera_info; \/* reference pointer of camear info *\/\r\n    mm_camera_ops_t *ops;          \/* API call table *\/\r\n} mm_camera_vtbl_t;<\/pre>\n<p>mm_camera_interface.c<br \/>\n\u5f53\u4e2d<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\/* camera ops v-table *\/\r\nstatic mm_camera_ops_t mm_camera_ops = {\r\n    .sync = mm_camera_intf_sync,\r\n    .is_event_supported = mm_camera_intf_is_event_supported,\r\n    .register_event_notify = mm_camera_intf_register_event_notify,\r\n    .qbuf = mm_camera_intf_qbuf,\r\n    .camera_close = mm_camera_intf_close,\r\n    .query_2nd_sensor_info = mm_camera_intf_query_2nd_sensor_info,\r\n    .is_parm_supported = mm_camera_intf_is_parm_supported,\r\n    .set_parm = mm_camera_intf_set_parm,\r\n    .get_parm = mm_camera_intf_get_parm,\r\n    .ch_acquire = mm_camera_intf_add_channel,\r\n    .ch_release = mm_camera_intf_del_channel,\r\n    .add_stream = mm_camera_intf_add_stream,\r\n    .del_stream = mm_camera_intf_del_stream,\r\n    .config_stream = mm_camera_intf_config_stream,\r\n    .init_stream_bundle = mm_camera_intf_bundle_streams,\r\n    .destroy_stream_bundle = mm_camera_intf_destroy_bundle,\r\n    .start_streams = mm_camera_intf_start_streams,\r\n    .stop_streams = mm_camera_intf_stop_streams,\r\n    .async_teardown_streams = mm_camera_intf_async_teardown_streams,\r\n    .request_super_buf = mm_camera_intf_request_super_buf,\r\n    .cancel_super_buf_request = mm_camera_intf_cancel_super_buf_request,\r\n    .start_focus = mm_camera_intf_start_focus,\r\n    .abort_focus = mm_camera_intf_abort_focus,\r\n    .prepare_snapshot = mm_camera_intf_prepare_snapshot,\r\n    .set_stream_parm = mm_camera_intf_set_stream_parm,\r\n    .get_stream_parm = mm_camera_intf_get_stream_parm\r\n};<\/pre>\n<p>\u4ee5start stream\u4e3a\u4f8b\u5b50<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">mm_camera_intf_start_streams(mm_camera_interface\r\n    mm_camera_start_streams(mm_camera\r\n    \tmm_channel_fsm_fn(mm_camera_channel\r\n    \t\tmm_channel_fsm_fn_active(mm_camera_channel\r\n    \t\t\tmm_channel_start_streams(mm_camera_channel\r\n    \t\t\t\tmm_stream_fsm_fn(mm_camera_stream\r\n    \t\t\t\t\tmm_stream_fsm_reg(mm_camera_stream\r\n    \t\t\t\t\t\tmm_camera_cmd_thread_launch(mm_camera_data\r\n    \t\t\t\t\t\tmm_stream_streamon(mm_camera_stream<\/pre>\n<p><strong>\u6ce8\u610f\uff1a\u672c\u6587\u5f53\u4e2d\uff0c\u5982\u4e0a\u8fd9\u79cd\u68af\u5ea6\u6446\u653e\uff0c\u8868\u793a\u662f\u8c03\u7528\u5173\u7cfb\uff0c\u5982\u679c\u68af\u5ea6\u662f\u4e00\u6837\u7684\uff0c\u5c31\u8868\u793a\u8fd9\u4e9b\u65b9\u6cd5\u662f\u5728\u4e0a\u5c42\u540c\u4e00\u4e2a\u65b9\u6cd5\u91cc\u9762\u88ab\u8c03\u7528\u7684<\/strong><\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int32_t mm_stream_streamon(mm_stream_t *my_obj)\r\n{\r\n    int32_t rc;\r\n    enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;\r\n\r\n    \/* Add fd to data poll thread *\/\r\n    rc = mm_camera_poll_thread_add_poll_fd(&amp;my_obj-&gt;ch_obj-&gt;poll_thread&#x5B;0],\r\n                                           my_obj-&gt;my_hdl,\r\n                                           my_obj-&gt;fd,\r\n                                           mm_stream_data_notify,\r\n                                           (void*)my_obj);\r\n    if (rc &lt; 0) {\r\n        return rc;\r\n    }\r\n    rc = ioctl(my_obj-&gt;fd, VIDIOC_STREAMON, &amp;buf_type);\r\n    if (rc &lt; 0) {\r\n        CDBG_ERROR(&quot;%s: ioctl VIDIOC_STREAMON failed: rc=%d\\n&quot;,\r\n                   __func__, rc);\r\n        \/* remove fd from data poll thread in case of failure *\/\r\n        mm_camera_poll_thread_del_poll_fd(&amp;my_obj-&gt;ch_obj-&gt;poll_thread&#x5B;0], my_obj-&gt;my_hdl);\r\n    }\r\n    return rc;\r\n}<\/pre>\n<p>\u770b\u5230ioctl\uff0cVIDIOC_STREAMON\uff0c\u53ef\u4ee5\u9ad8\u5174\u4e00\u4e0b\u4e86\uff0c\u8fd9\u5c31\u662fV4L2\u89c4\u8303\u5f53\u4e2d\u7528\u6237\u7a7a\u95f4\u548c\u5185\u6838\u7a7a\u95f4\u901a\u4fe1\u7684\u65b9\u6cd5\uff0cV4L2(Video for Linux Two)\u662f\u4e00\u79cd\u7ecf\u5178\u800c\u4e14\u6210\u719f\u7684\u89c6\u9891\u901a\u4fe1\u534f\u8bae\uff0c\u4e4b\u524d\u662fV4L\uff0c\u4e0d\u6e05\u695a\u7684\u53ef\u4ee5\u53bb\u4e0b\u8f7d\u5b83\u7684\u89c4\u8303\uff0c\u53e6\u5916The Video4Linux2(http:\/\/lwn.net\/Articles\/203924\/)\u4e5f\u662f\u5f88\u597d\u7684\u8d44\u6599\u3002<br \/>\n\u8fd9\u91cc\u7b80\u5355\u4ecb\u7ecd\u4e0b\uff1a<\/p>\n<blockquote><p>\nopen(VIDEO_DEVICE_NAME, &#8230;) \/\/ \u5f00\u542f\u89c6\u9891\u8bbe\u5907\uff0c\u4e00\u822c\u5728\u7a0b\u5e8f\u521d\u59cb\u5316\u7684\u65f6\u5019\u8c03\u7528<\/p>\n<p>ioctl(&#8230;) \/\/ \u4e3b\u8981\u662f\u4e00\u4e9b\u9700\u8981\u4f20\u8f93\u6570\u636e\u91cf\u5f88\u5c0f\u7684\u63a7\u5236\u64cd\u4f5c<br \/>\n\u8fd9\u91cc\u53ef\u4ee5\u7528\u7684\u53c2\u6570\u5f88\u591a\uff0c\u5e76\u4e14\u901a\u5e38\u6765\u8bf4\u6211\u4eec\u4f1a\u6309\u7167\u4ee5\u4e0b\u65b9\u5f0f\u6765\u4f7f\u7528\uff0c\u6bd4\u5982<br \/>\nVIDIOC_QUERYCAP \/\/ \u67e5\u8be2\u8bbe\u5907\u80fd\u5e72\u4ec0\u4e48<br \/>\nVIDIOC_CROPCAP \/\/ \u67e5\u8be2\u8bbe\u5907crop\u80fd\u529b<br \/>\nVIDIOC_S_* \/\/ set\/get\u65b9\u6cd5\uff0c\u8bbe\u7f6e\/\u83b7\u53d6\u53c2\u6570<br \/>\nVIDIOC_G_*<br \/>\nVIDIOC_REQBUFS \/\/ \u5206\u914dbuffer\uff0c\u53ef\u4ee5\u6709\u591a\u79cd\u65b9\u5f0f<br \/>\nVIDIOC_QUERYBUF \/\/ \u67e5\u8be2\u5206\u914d\u7684buffer\u7684\u4fe1\u606f<br \/>\nVIDIOC_QBUF \/\/ QUEUE BUFFER \u628abuffer\u538b\u5165DRV\u7f13\u5b58\u961f\u5217(\u8fd9\u65f6\u5019buffer\u662f\u7a7a\u7684)<br \/>\nVIDIOC_STREAMON \/\/ \u5f00\u59cb\u89c6\u9891\u6570\u636e\u4f20\u8f93<br \/>\nVIDIOC_DQBUF \/\/ DEQUEUE BUFFER \u628abuffer\u4eceDRV\u7f13\u5b58\u961f\u5217\u4e2d\u53d6\u51fa(\u8fd9\u65f6\u5019buffer\u662f\u6709\u6570\u636e\u7684)<\/p>\n<p>[0&#8230;n]<br \/>\nQBUF -> DQBUF \/\/ \u53ef\u4ee5\u4e00\u76f4\u91cd\u590d\u8fd9\u4e2a\u52a8\u4f5c<\/p>\n<p>VIDIOC_STREAMOFF \/\/ \u505c\u6b62\u89c6\u9891\u6570\u636e\u4f20\u8f93<\/p>\n<p>close(VIDEO_DEVICE_FD) \/\/ \u5173\u95ed\u8bbe\u5907<br \/>\n\u4e0a\u9762\u5c31\u662f\u4e3b\u8981\u7684\u51fd\u6570\u548c\u7b80\u5355\u7684\u8c03\u7528\u987a\u5e8f\uff0c\u53e6\u5916\u8fd8\u6709\u51e0\u4e2a\u51fd\u6570<\/p>\n<p>select() \/\/ \u7b49\u5f85\u4e8b\u4ef6\u53d1\u751f\uff0c\u4e3b\u8981\u7528\u5728\u6211\u4eec\u628a\u5b58frame\u7684buffer\u63a8\u7ed9DRV\u4ee5\u540e\uff0c\u7b49\u5f85\u5b83\u7684\u53cd\u5e94<br \/>\nmmap\/munmap \/\/ \u4e3b\u8981\u5904\u7406\u6211\u4eecrequest\u7684buffer\u7684\uff0cbuffer\u5206\u914d\u5728\u8bbe\u5907\u7684\u5185\u5b58\u7a7a\u95f4\u7684\u65f6\u5019\u9700\u8981\n<\/p><\/blockquote>\n<p>\u5e76\u4e14\u770b\u770bmm_camera_stream\u8fd9\u4e2a\u6587\u4ef6\u91cc\u9762\u4e5f\u90fd\u662f\u8fd9\u4e48\u5b9e\u73b0\u7684\u3002<\/p>\n<p>\u770b\u5b8c\u8fd9\u91cc\uff0c\u6211\u4eec\u56de\u8fc7\u5934\u6765\u7ee7\u7eed\u770bQCam HAL\uff0c\u5f53\u7136\u5b83\u5b9e\u73b0\u7684\u7ec6\u8282\u4e5f\u4e0d\u662f\u6211\u4e0a\u9762start stream\u6240\u5217\u7684\u90a3\u4e48\u7b80\u5355\uff0c\u4f46\u662f\u5176\u5b9e\u4e5f\u4e0d\u7b97\u590d\u6742\uff0c\u89c9\u5f97\u91cd\u8981\u7684\u5c31\u662f\u72b6\u6001\u548c\u7528\u5230\u7684\u7ed3\u6784\u3002<\/p>\n<p>\u9996\u5148\u662fchannel\u72b6\u6001\uff0c\u76ee\u524d\u53ea\u652f\u63011\u4e2achannel\uff0c\u4f46\u662f\u53ef\u4ee5\u6709\u591a\u4e2astreams(\u540e\u9762\u4f1a\u4ecb\u7ecd\uff0c\u800c\u4e14\u76ee\u524d\u6700\u591a\u652f\u63018\u4e2astreams)<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\/* mm_channel *\/\r\ntypedef enum {\r\n    MM_CHANNEL_STATE_NOTUSED = 0,   \/* not used *\/\r\n    MM_CHANNEL_STATE_STOPPED,       \/* stopped *\/\r\n    MM_CHANNEL_STATE_ACTIVE,        \/* active, at least one stream active *\/\r\n    MM_CHANNEL_STATE_PAUSED,        \/* paused *\/\r\n    MM_CHANNEL_STATE_MAX\r\n} mm_channel_state_type_t;<\/pre>\n<p>\u5b83\u53ef\u4ee5\u6267\u884c\u7684\u4e8b\u4ef6<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">typedef enum {\r\n    MM_CHANNEL_EVT_ADD_STREAM,\r\n    MM_CHANNEL_EVT_DEL_STREAM,\r\n    MM_CHANNEL_EVT_START_STREAM,\r\n    MM_CHANNEL_EVT_STOP_STREAM,\r\n    MM_CHANNEL_EVT_TEARDOWN_STREAM,\r\n    MM_CHANNEL_EVT_CONFIG_STREAM,\r\n    MM_CHANNEL_EVT_PAUSE,\r\n    MM_CHANNEL_EVT_RESUME,\r\n    MM_CHANNEL_EVT_INIT_BUNDLE,\r\n    MM_CHANNEL_EVT_DESTROY_BUNDLE,\r\n    MM_CHANNEL_EVT_REQUEST_SUPER_BUF,\r\n    MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF,\r\n    MM_CHANNEL_EVT_START_FOCUS,\r\n    MM_CHANNEL_EVT_ABORT_FOCUS,\r\n    MM_CHANNEL_EVT_PREPARE_SNAPSHOT,\r\n    MM_CHANNEL_EVT_SET_STREAM_PARM,\r\n    MM_CHANNEL_EVT_GET_STREAM_PARM,\r\n    MM_CHANNEL_EVT_DELETE,\r\n    MM_CHANNEL_EVT_MAX\r\n} mm_channel_evt_type_t;<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\/* mm_stream *\/\r\ntypedef enum { \/\/ \u8fd9\u91cc\u7684\u72b6\u6001\u8981\u4ed4\u7ec6\uff0c\u6bcf\u6267\u884c\u4e00\u6b21\u65b9\u6cd5\uff0c\u72b6\u6001\u5c31\u9700\u8981\u53d8\u5316\r\n    MM_STREAM_STATE_NOTUSED = 0,      \/* not used *\/\r\n    MM_STREAM_STATE_INITED,           \/* inited  *\/\r\n    MM_STREAM_STATE_ACQUIRED,         \/* acquired, fd opened  *\/\r\n    MM_STREAM_STATE_CFG,              \/* fmt &amp; dim configured *\/\r\n    MM_STREAM_STATE_BUFFED,           \/* buf allocated *\/\r\n    MM_STREAM_STATE_REG,              \/* buf regged, stream off *\/\r\n    MM_STREAM_STATE_ACTIVE_STREAM_ON, \/* active with stream on *\/\r\n    MM_STREAM_STATE_ACTIVE_STREAM_OFF, \/* active with stream off *\/\r\n    MM_STREAM_STATE_MAX\r\n} mm_stream_state_type_t;<\/pre>\n<p>\u540c\u6837\uff0cstream\u53ef\u4ee5\u6267\u884c\u7684\u4e8b\u4ef6<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">typedef enum {\r\n    MM_STREAM_EVT_ACQUIRE,\r\n    MM_STREAM_EVT_RELEASE,\r\n    MM_STREAM_EVT_SET_FMT,\r\n    MM_STREAM_EVT_GET_BUF,\r\n    MM_STREAM_EVT_PUT_BUF,\r\n    MM_STREAM_EVT_REG_BUF,\r\n    MM_STREAM_EVT_UNREG_BUF,\r\n    MM_STREAM_EVT_START,\r\n    MM_STREAM_EVT_STOP,\r\n    MM_STREAM_EVT_QBUF,\r\n    MM_STREAM_EVT_SET_PARM,\r\n    MM_STREAM_EVT_GET_PARM,\r\n    MM_STREAM_EVT_MAX\r\n} mm_stream_evt_type_t;<\/pre>\n<p>\u8fd9\u91cc\u6bcf\u6b21\u6267\u884c\u51fd\u6570\u7684\u65f6\u5019\u90fd\u9700\u8981\u68c0\u67e5channel\/stream\u7684\u72b6\u6001\uff0c\u53ea\u6709\u72b6\u6001\u6b63\u786e\u7684\u65f6\u5019\u624d\u4f1a\u53bb\u6267\u884c<\/p>\n<p>\u6bd4\u5982\u4f60\u53ef\u4ee5\u89c2\u5bdf\u5230<br \/>\nmm_channel\u7684mm_channel_state_type_t state;<br \/>\nmm_stream\u7684mm_stream_state_type_t state;<br \/>\n\u5747\u8868\u793a\u8fd9\u4e2a\u7ed3\u6784\u5f53\u524d\u7684\u72b6\u6001<\/p>\n<p>\u53e6\u5916<br \/>\nstruct mm_camera_obj<br \/>\nstruct mm_channel<br \/>\nstruct mm_stream<br \/>\n\u8fd9\u4e09\u4e2a\u4e5f\u662f\u81ea\u4e0a\u800c\u4e0b\u5305\u542b\u7684\uff0c\u5e76\u4e14stream\u548cchannel\u8fd8\u4f1a\u6301\u6709\u7236\u7ed3\u6784(\u6682\u4e14\u8fd9\u4e48\u79f0\u547c\uff0c\u5b9e\u9645\u4e3acontainer\u5173\u7cfb)\u7684\u5f15\u7528\u3002<\/p>\n<p>\u5b9e\u9645\u4e0aVendor\u7684HAL\u6bcf\u4e2a\u90fd\u6709\u81ea\u5df1\u5b9e\u73b0\u7684\u65b9\u6cd5\uff0c\u4e5f\u53ef\u80fd\u5305\u542b\u5f88\u591a\u7279\u6709\u7684\u4e1c\u897f\uff0c\u6bd4\u5982\u8fd9\u91cc\u5b83\u4f1a\u5582\u7ed9ioctl\u4e00\u4e9b\u7279\u6709\u7684\u547d\u4ee4\u6216\u8005\u6570\u636e\u7ed3\u6784\uff0c\u8fd9\u4e9b\u6211\u4eec\u5c31\u53ea\u6709\u5728\u505a\u7279\u5b9a\u5e73\u53f0\u7684\u65f6\u5019\u53bb\u8003\u8651\u4e86\u3002\u8fd9\u4e9b\u90fd\u53ef\u80fd\u5343\u53d8\u4e07\u5316\uff0c\u6bd4\u5982OMAP4\u5b83\u540cDRV\u6c9f\u901a\u662f\u900f\u8fc7rpmsg\uff0c\u5e76\u7528OpenMAX\u7684\u4e00\u5957\u89c4\u8303\u6765\u5b9e\u73b0\u7684\u3002<\/p>\n<p>\u7406\u8bba\u5c31\u8fd9\u4e48\u591a\uff0c\u63a5\u7740\u770b\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u6bd4\u5982\u6211\u4eec\u5728Camera Service\u8981\u53bbstart preview\uff1a<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">Camera2Client::startPreviewL\r\n\tStreamingProcessor-&gt;updatePreviewStream\r\n\t\tCamera2Device-&gt;createStream\r\n\t\t\tStreamAdapter-&gt;connectToDevice\r\n\t\t\t\tcamera2_device_t-&gt;ops-&gt;allocate_stream \/\/ \u4e0a\u9762\u6709\u5206\u6790\r\n\t\t\t\tnative_window_api_*\u6216\u8005native_window_*\r\n\r\n\tStreamingProcessor-&gt;startStream\r\n\t\tCamera2Device-&gt;setStreamingRequest\r\n\t\t\tCamera2Device::RequestQueue-&gt;setStreamSlot \/\/ \u521b\u5efa\u4e00\u4e2astream slot\r\n\t\t\t\tCamera2Device::RequestQueue-&gt;signalConsumerLocked<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">status_t Camera2Device::MetadataQueue::signalConsumerLocked() {\r\n    status_t res = OK;\r\n    notEmpty.signal();\r\n    if (mSignalConsumer &amp;&amp; mDevice != NULL) {\r\n        mSignalConsumer = false;\r\n        mMutex.unlock();\r\n        res = mDevice-&gt;ops-&gt;notify_request_queue_not_empty(mDevice); \/\/ \u901a\u77e5Vendor HAL\u7684run command thread\u53bb\u8fd0\u884c\uff0c\r\n        \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ notify_request_queue_not_empty\u8fd9\u4e2a\u4e8b\u4ef6\u4e0d\u662f\u6bcf\u6b21\u90fd\u4f1a\u89e6\u53d1\u7684\uff0c\u53ea\u6709\u521d\u59cb\u5316\u65f6\u5019\r\n        \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u6216\u8005run command thread\u5728dequeue\u7684\u65f6\u5019\u53d1\u73b0\u6570\u636e\u4e3aNULL\uff0c\r\n        \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u800cCamera Service\u4e4b\u53d8\u53c8\u6709\u65b0\u7684request\u8fdb\u6765\u7684\u65f6\u5019\u624d\u4f1a\u53bb\u89e6\u53d1\r\n        \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u53ef\u4ee5\u8bf4\u662f\u51cf\u8f7b\u8d1f\u62c5\u5427\uff0c\u4e0d\u7528\u6ca1\u6709\u8bf7\u6c42\u7684\u65f6\u5019\uff0cthread\u4e5f\u4e00\u76f4\u5728\u90a3\u91cc\r\n        \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \/\/ \u4e0d\u8fc7\u901a\u5e38\u78b0\u5230\u8fd9\u6837\u7684\u60c5\u51b5\u90fd\u662f\u5229\u7528\u9501\u8ba9thread\u505c\u5728\u90a3\u91cc\r\n        mMutex.lock();\r\n    }\r\n    return res;\r\n}<\/pre>\n<p>\u7136\u800c\u5728Qualcomm HAL\u5f53\u4e2d<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int notify_request_queue_not_empty(const struct camera2_device *device) \/\/ \u8fd9\u4e2a\u65b9\u6cd5\u6ce8\u518c\u5230camera2_device_ops_t\u5f53\u4e2d\r\n\tQCameraHardwareInterface-&gt;notify_request_queue_not_empty()\r\n\t\tpthread_create(&amp;mCommandThread, &amp;attr, command_thread, (void *)this) != 0)<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void *command_thread(void *obj)\r\n{\r\n\t...\r\n\tpme-&gt;runCommandThread(obj);\r\n}<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void QCameraHardwareInterface::runCommandThread(void *data)\r\n{\r\n    \/**\r\n     * This function implements the main service routine for the incoming\r\n     * frame requests, this thread routine is started everytime we get a \r\n     * notify_request_queue_not_empty trigger, this thread makes the \r\n     * assumption that once it receives a NULL on a dequest_request call \r\n     * there will be a fresh notify_request_queue_not_empty call that is\r\n     * invoked thereby launching a new instance of this thread. Therefore,\r\n     * once we get a NULL on a dequeue request we simply let this thread die\r\n     *\/ \r\n    int res;\r\n    camera_metadata_t *request=NULL;\r\n    mPendingRequests=0;\r\n\r\n    while (mRequestQueueSrc) { \/\/ mRequestQueueSrc\u662f\u901a\u8fc7set_request_queue_src_ops\u8bbe\u7f6e\u8fdb\u6765\u7684\r\n    \t\t\t\t\t\t   \/\/ \u53c2\u89c1Camera2Device::MetadataQueue::setConsumerDevice\r\n    \t\t\t\t\t\t   \/\/ \u5728Camera2Device::initialize\u5f53\u4e2d\u88ab\u8c03\u7528\r\n        ALOGV(&quot;%s:Dequeue request using mRequestQueueSrc:%p&quot;,__func__,mRequestQueueSrc);\r\n        mRequestQueueSrc-&gt;dequeue_request(mRequestQueueSrc, &amp;request); \/\/ \u53d6framework request\r\n        if (request==NULL) {\r\n            ALOGE(&quot;%s:No more requests available from src command \\\r\n                    thread dying&quot;,__func__);\r\n            return;\r\n        }\r\n        mPendingRequests++;\r\n\r\n        \/* Set the metadata values *\/\r\n\r\n        \/* Wait for the SOF for the new metadata values to be applied *\/\r\n\r\n        \/* Check the streams that need to be active in the stream request *\/\r\n        sort_camera_metadata(request);\r\n\r\n        camera_metadata_entry_t streams;\r\n        res = find_camera_metadata_entry(request,\r\n                ANDROID_REQUEST_OUTPUT_STREAMS,\r\n                &amp;streams);\r\n        if (res != NO_ERROR) {\r\n            ALOGE(&quot;%s: error reading output stream tag&quot;, __FUNCTION__);\r\n            return;\r\n        }\r\n\r\n        res = tryRestartStreams(streams); \/\/ \u4f1a\u53bbprepareStream\u548cstreamOn\uff0c\u540e\u9762\u6709\u8be6\u7ec6\u4ee3\u7801\r\n        if (res != NO_ERROR) {\r\n            ALOGE(&quot;error tryRestartStreams %d&quot;, res);\r\n            return;\r\n        }\r\n\r\n        \/* 3rd pass: Turn on all streams requested *\/\r\n        for (uint32_t i = 0; i &lt; streams.count; i++) {\r\n            int streamId = streams.data.u8&amp;#91;i&amp;#93;;\r\n            QCameraStream *stream = QCameraStream::getStreamAtId(streamId);\r\n\r\n            \/* Increment the frame pending count in each stream class *\/\r\n\r\n            \/* Assuming we will have the stream obj in had at this point may be\r\n             * may be multiple objs in which case we loop through array of streams *\/\r\n            stream-&gt;onNewRequest();\r\n        }\r\n        ALOGV(&quot;%s:Freeing request using mRequestQueueSrc:%p&quot;,__func__,mRequestQueueSrc);\r\n        \/* Free the request buffer *\/\r\n        mRequestQueueSrc-&gt;free_request(mRequestQueueSrc,request);\r\n        mPendingRequests--;\r\n        ALOGV(&quot;%s:Completed request&quot;,__func__);\r\n    }\r\n \r\n    QCameraStream::streamOffAll();\r\n}<\/pre>\n<p>\u4e0b\u9762\u8fd9\u4e2a\u65b9\u6cd5\u89e3\u91camRequestQueueSrc\u6765\u81ea\u4f55\u5904<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\/\/ Connect to camera2 HAL as consumer (input requests\/reprocessing)\r\nstatus_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {\r\n    ATRACE_CALL();\r\n    status_t res;\r\n    res = d-&gt;ops-&gt;set_request_queue_src_ops(d,\r\n            this);\r\n    if (res != OK) return res;\r\n    mDevice = d;\r\n    return OK;\r\n}<\/pre>\n<p>\u56e0\u4e3a<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">QCameraStream_preview-&gt;prepareStream\r\n\tQCameraStream-&gt;initStream\r\n\t\tmm_camera_vtbl_t-&gt;ops-&gt;add_stream(... stream_cb_routine ...) \/\/ \u8fd9\u662f\u7528\u6765\u8fd4\u56de\u6570\u636e\u7684callback\uff0c\u5e26mm_camera_super_buf_t*\u548cvoid*\u4e24\u53c2\u6570\r\n\t\t\tmm_camera_add_stream\r\n\t\t\t\tmm_channel_fsm_fn(..., MM_CHANNEL_EVT_ADD_STREAM, ..., mm_evt_paylod_add_stream_t)\r\n\t\t\t\t\tmm_channel_fsm_fn_stopped\r\n\t\t\t\t\t\tmm_channel_add_stream(..., mm_camera_buf_notify_t, ...)\r\n\t\t\t\t\t\t\tmm_stream_fsm_inited<\/pre>\n<p>\u800c<br \/>\n\u5728mm_channel_add_stream\u5f53\u4e2d\u6709\u628amm_camera_buf_notify_t\u5305\u88c5\u5230mm_stream_t<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">mm_stream_t *stream_obj = NULL;\r\n\/* initialize stream object *\/\r\nmemset(stream_obj, 0, sizeof(mm_stream_t));\r\n\/* cd through intf always palced at idx 0 of buf_cb *\/\r\nstream_obj-&gt;buf_cb&#x5B;0].cb = buf_cb; \/\/ callback\r\nstream_obj-&gt;buf_cb&#x5B;0].user_data = user_data;\r\nstream_obj-&gt;buf_cb&#x5B;0].cb_count = -1; \/* infinite by default *\/ \/\/ \u9ed8\u8ba4\u65e0\u9650\u6b21\u6570<\/pre>\n<p>\u5e76\u4e14mm_stream_fsm_inited\uff0c\u4f20\u8fdb\u6765\u7684event\u53c2\u6570\u4e5f\u662fMM_STREAM_EVT_ACQUIRE<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int32_t mm_stream_fsm_inited(mm_stream_t *my_obj,\r\n                             mm_stream_evt_type_t evt,\r\n                             void * in_val,\r\n                             void * out_val)\r\n{\r\n    int32_t rc = 0;\r\n    char dev_name&#x5B;MM_CAMERA_DEV_NAME_LEN];\r\n\r\n    switch (evt) {\r\n    case MM_STREAM_EVT_ACQUIRE:\r\n        if ((NULL == my_obj-&gt;ch_obj) || (NULL == my_obj-&gt;ch_obj-&gt;cam_obj)) {\r\n            CDBG_ERROR(&quot;%s: NULL channel or camera obj\\n&quot;, __func__);\r\n            rc = -1;\r\n            break;\r\n        }\r\n\r\n        snprintf(dev_name, sizeof(dev_name), &quot;\/dev\/%s&quot;,\r\n                 mm_camera_util_get_dev_name(my_obj-&gt;ch_obj-&gt;cam_obj-&gt;my_hdl));\r\n\r\n        my_obj-&gt;fd = open(dev_name, O_RDWR | O_NONBLOCK); \/\/ \u6253\u5f00\u89c6\u9891\u8bbe\u5907\r\n        if (my_obj-&gt;fd &lt;= 0) {\r\n            CDBG_ERROR(&quot;%s: open dev returned %d\\n&quot;, __func__, my_obj-&gt;fd);\r\n            rc = -1;\r\n            break;\r\n        }\r\n        rc = mm_stream_set_ext_mode(my_obj);\r\n        if (0 == rc) {\r\n            my_obj-&gt;state = MM_STREAM_STATE_ACQUIRED; \/\/ mm_stream_state_type_t\r\n        } else {\r\n            \/* failed setting ext_mode\r\n             * close fd *\/\r\n            if(my_obj-&gt;fd &gt; 0) {\r\n                close(my_obj-&gt;fd);\r\n                my_obj-&gt;fd = -1;\r\n            }\r\n            break;\r\n        }\r\n        rc = get_stream_inst_handle(my_obj);\r\n        if(rc) {\r\n            if(my_obj-&gt;fd &gt; 0) {\r\n                close(my_obj-&gt;fd);\r\n                my_obj-&gt;fd = -1;\r\n            }\r\n        }\r\n        break;\r\n    default:\r\n        CDBG_ERROR(&quot;%s: Invalid evt=%d, stream_state=%d&quot;,\r\n                   __func__,evt,my_obj-&gt;state);\r\n        rc = -1;\r\n        break;\r\n    }\r\n    return rc;\r\n}<\/pre>\n<p>\u8fd8\u6709<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">QCameraStream-&gt;streamOn\r\n\tmm_camera_vtbl_t-&gt;ops-&gt;start_streams\r\n\t\tmm_camera_intf_start_streams\r\n\t\t\tmm_camera_start_streams\r\n\t\t\t\tmm_channel_fsm_fn(..., MM_CHANNEL_EVT_START_STREAM, ...)\r\n\t\t\t\t\tmm_stream_fsm_fn(..., MM_STREAM_EVT_START, ...)\r\n\t\t\t\t\t\tmm_camera_cmd_thread_launch \/\/ \u542f\u52a8CB\u7ebf\u7a0b\r\n\t\t\t\t\t\tmm_stream_streamon(mm_stream_t)\r\n\t\t\t\t\t\t\tmm_camera_poll_thread_add_poll_fd(..., mm_stream_data_notify , ...)<\/pre>\n<p>\u800c\t<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">static void mm_stream_data_notify(void* user_data)\r\n{\r\n    mm_stream_t *my_obj = (mm_stream_t*)user_data;\r\n    int32_t idx = -1, i, rc;\r\n    uint8_t has_cb = 0;\r\n    mm_camera_buf_info_t buf_info;\r\n\r\n    if (NULL == my_obj) {\r\n        return;\r\n    }\r\n\r\n    if (MM_STREAM_STATE_ACTIVE_STREAM_ON != my_obj-&gt;state) {\r\n        \/* this Cb will only received in active_stream_on state\r\n         * if not so, return here *\/\r\n        CDBG_ERROR(&quot;%s: ERROR!! Wrong state (%d) to receive data notify!&quot;,\r\n                   __func__, my_obj-&gt;state);\r\n        return;\r\n    }\r\n\r\n    memset(&amp;buf_info, 0, sizeof(mm_camera_buf_info_t));\r\n\r\n    pthread_mutex_lock(&amp;my_obj-&gt;buf_lock);\r\n    rc = mm_stream_read_msm_frame(my_obj, &amp;buf_info); \/\/ \u901a\u8fc7ioctl(..., VIDIOC_DQBUF, ...)\u8bfb\u53d6frame\u6570\u636e\r\n    if (rc != 0) {\r\n        pthread_mutex_unlock(&amp;my_obj-&gt;buf_lock);\r\n        return;\r\n    }\r\n    idx = buf_info.buf-&gt;buf_idx;\r\n\r\n    \/* update buffer location *\/\r\n    my_obj-&gt;buf_status&#x5B;idx].in_kernel = 0;\r\n\r\n    \/* update buf ref count *\/\r\n    if (my_obj-&gt;is_bundled) {\r\n        \/* need to add into super buf since bundled, add ref count *\/\r\n        my_obj-&gt;buf_status&#x5B;idx].buf_refcnt++;\r\n    }\r\n\r\n    for (i=0; i &lt; MM_CAMERA_STREAM_BUF_CB_MAX; i++) {\r\n        if(NULL != my_obj-&gt;buf_cb&#x5B;i].cb) {\r\n            \/* for every CB, add ref count *\/\r\n            my_obj-&gt;buf_status&#x5B;idx].buf_refcnt++;\r\n            has_cb = 1;\r\n        }\r\n    }\r\n    pthread_mutex_unlock(&amp;my_obj-&gt;buf_lock);\r\n\r\n    mm_stream_handle_rcvd_buf(my_obj, &amp;buf_info); \/\/ mm_camera_queue_enq\uff0c\u5f80queue\u91cc\u9762\u4e22frame\u6570\u636e(\r\n    \t\t\t\t\t\t\t\t\t\t\t  \/\/ \u524d\u63d0\u662f\u6709\u6ce8\u518ccallback)\uff0c\u5e76\u900f\u8fc7sem_post\u901a\u77e5queue\r\n    \t\t\t\t\t\t\t\t\t\t\t  \/\/ \u7136\u540emm_camera_cmd_thread_launch\u542f\u52a8\u7684\u7ebf\u7a0b\u4f1a\r\n    \t\t\t\t\t\t\t\t\t\t\t  \/\/ \u8f6e\u5faa\u8bfb\u53d6\u6570\u636e\uff0c\u7136\u540e\u6267\u884cCB\r\n}<\/pre>\n<p>\u8fd9\u6837\u5c31\u4f1a\u5bfc\u81f4\u5728stream on\u7684\u65f6\u5019stream_cb_routine(\u5b9e\u73b0\u5728QCameraStream\u5f53\u4e2d)\u5c31\u4f1a\u4e00\u76f4\u6267\u884c<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void stream_cb_routine(mm_camera_super_buf_t *bufs,\r\n                       void *userdata)\r\n{\r\n    QCameraStream *p_obj=(QCameraStream*) userdata;\r\n    switch (p_obj-&gt;mExtImgMode) { \/\/ \u8fd9\u4e2amode\u5728prepareStream\u7684\u65f6\u5019\u5c31\u4f1a\u786e\u5b9a\r\n    case MM_CAMERA_PREVIEW:\r\n        ALOGE(&quot;%s : callback for MM_CAMERA_PREVIEW&quot;, __func__);\r\n        ((QCameraStream_preview *)p_obj)-&gt;dataCallback(bufs); \/\/ CAMERA_PREVIEW\u548cCAMERA_VIDEO\u662f\u4e00\u6837\u7684\uff1f\r\n        break;\r\n    case MM_CAMERA_VIDEO:\r\n        ALOGE(&quot;%s : callback for MM_CAMERA_VIDEO&quot;, __func__);\r\n        ((QCameraStream_preview *)p_obj)-&gt;dataCallback(bufs);\r\n        break;\r\n    case MM_CAMERA_SNAPSHOT_MAIN:\r\n        ALOGE(&quot;%s : callback for MM_CAMERA_SNAPSHOT_MAIN&quot;, __func__);\r\n        p_obj-&gt;p_mm_ops-&gt;ops-&gt;qbuf(p_obj-&gt;mCameraHandle,\r\n                                   p_obj-&gt;mChannelId,\r\n                                   bufs-&gt;bufs&#x5B;0]);\r\n\t\tbreak;\r\n\tcase MM_CAMERA_SNAPSHOT_THUMBNAIL:\r\n\t\tbreak;\r\n\tdefault:\r\n\t\tbreak;\r\n    }\r\n}<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void QCameraStream::dataCallback(mm_camera_super_buf_t *bufs)\r\n{\r\n    if (mPendingCount != 0) { \/\/ \u8fd9\u4e2adataCallback\u662f\u4e00\u76f4\u5728\u90fd\u5728\u56de\u6765\u4e48\uff1f\r\n    \t\t\t\t\t\t   \/\/ \u800c\u4e14\u4ece\u4ee3\u7801\u6765\u770b\u8bbe\u7f6e\u4e0b\u53bb\u7684callback\u6b21\u6570\u9ed8\u8ba4\u662f-1\uff0c-1\u5c31\u8868\u793ainfinite\u3002\r\n    \t\t\t\t\t\t   \/\/ \u4f3c\u4e4e\u53ea\u80fd\u8fd9\u6837\u624d\u80fd\u89e3\u91ca\uff0c\u5426\u5219\u6ca1\u4eba\u89e6\u53d1\u7684\u8bdd\uff0c\u5373\u4f7fmPendingCount\u5728onNewRequest\u5f53\u4e2d\u52a01\u4e86\r\n    \t\t\t\t\t\t   \/\/ \u8fd9\u91cc\u4e5f\u611f\u77e5\u4e0d\u5230\r\n        ALOGD(&quot;Got frame request&quot;);\r\n        pthread_mutex_lock(&amp;mFrameDeliveredMutex);\r\n        mPendingCount--;\r\n        ALOGD(&quot;Completed frame request&quot;);\r\n        pthread_cond_signal(&amp;mFrameDeliveredCond);\r\n        pthread_mutex_unlock(&amp;mFrameDeliveredMutex);\r\n        processPreviewFrame(bufs);\r\n    } else {\r\n        p_mm_ops-&gt;ops-&gt;qbuf(mCameraHandle,\r\n                mChannelId, bufs-&gt;bufs&#x5B;0]); \/\/ \u5982\u679c\u6ca1\u6709\u9700\u8981\u6570\u636e\u7684\u60c5\u51b5\uff0c\u76f4\u63a5\u628abuffer\u538b\u5165DRV\u7684\u961f\u5217\u5f53\u4e2d\uff0c\u4f1acall\u5230V4L2\u7684QBUF\r\n    }\r\n}<\/pre>\n<p>\u6bd4\u8f83\u597d\u5947\u7684\u662f\u5728\u624b\u91cc\u8fd9\u7248QCam HAL\u7684code\u5f53\u4e2dcamera2_frame_queue_dst_ops_t\u6ca1\u6709\u88ab\u7528\u5230<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">int QCameraHardwareInterface::set_frame_queue_dst_ops(\r\n    const camera2_frame_queue_dst_ops_t *frame_dst_ops)\r\n{\r\n    mFrameQueueDst = frame_dst_ops; \/\/ \u8fd9\u4e2a\u73b0\u5728\u4f3c\u4e4e\u6ca1\u6709\u7528\u5230\u561b\r\n    return OK;\r\n}<\/pre>\n<p>\u8fd9\u6837Camera Service\u7684FrameProcessor\u7684Camera2Device->getNextFrame\u5c31\u6c38\u8fdc\u4e5f\u83b7\u53d6\u4e0d\u5230\u6570\u636e\uff0c\u4e0d\u77e5\u9053\u662f\u4e0d\u662f\u6211\u624b\u91cc\u7684\u8fd9\u7248\u4ee3\u7801\u7684\u95ee\u9898\uff0c\u800c\u4e14\u5728\u6700\u65b0\u7684Qualcomm Camera HAL\u4ee3\u7801\u4e5f\u4e0d\u5728AOSP\u6811\u5f53\u4e2d\u4e86\uff0c\u800c\u662f\u76f4\u63a5\u4ee5proprietary\u5f62\u5f0f\u7ed9\u7684so\u6863\uff0c\u8fd9\u53ea\u662f\u9898\u5916\u8bdd\u3002<\/p>\n<p>\u6240\u4ee5\u603b\u4f53\u6765\u770b\uff0c\u8fd9\u91cc\u53ef\u80fd\u6709\u51e0\u4e2aQCameraStream\uff0c\u6bcf\u4e2astream\u8d1f\u8d23\u81ea\u5df1\u7684\u4e8b\u60c5\u3002<br \/>\n\u4ed6\u4eec\u4e4b\u95f4\u4e5f\u6709\u76f8\u4e92\u5173\u7cfb\uff0c\u6bd4\u5982\u6709\u53ef\u80fd\u65b0\u7684stream\u8fdb\u6765\u4f1a\u5bfc\u81f4\u5176\u4ed6\u5df2\u7ecfstream-on\u7684stream\u91cd\u65b0\u542f\u52a8\u3002<\/p>\n<p>\u5728Camera HAL 2.0\u5f53\u4e2d\u6211\u4eec\u8fd8\u6709\u4e2a\u91cd\u70b9\u5c31\u662fre-process stream<br \/>\n\u7b80\u5355\u7684\u8bf4\u5c31\u662f\u628aoutput stream\u4f5c\u4e3ainput stream\u518d\u6b21\u6dfb\u52a0\u5230BufferQueue\u4e2d\uff0c\u8ba9\u5176\u4ed6\u7684consumer\u6765\u5904\u7406\uff0c\u5c31\u7c7b\u4f3c\u4e00\u4e2achain\u4e00\u6837\u3002<br \/>\n\u76ee\u524d\u5728ZslProcessor\u5f53\u4e2d\u6709\u7528\u5230\u3002<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">ZslProcessor-&gt;updateStream\r\n\tCamera2Device-&gt;createStream\r\n\tCamera2Device-&gt;createReprocessStreamFromStream \/\/ release\u7684\u65f6\u5019\u662f\u5148delete re-process\r\n\t\tnew ReprocessStreamAdapter\r\n\t\tReprocessStreamAdapter-&gt;connectToDevice\r\n\t\t\tcamera2_device_t-&gt;ops-&gt;allocate_reprocess_stream_from_stream<\/pre>\n<p>\u8fd9\u91ccReprocessStreamAdapter\u5b9e\u9645\u5c31\u662fcamera2_stream_in_ops_t\uff0c\u8d1f\u8d23\u7ba1\u7406re-process\u7684stream\u3002<\/p>\n<p>\u4f46\u662f\u8fd9\u7248\u7684\u4ee3\u7801Qualcomm\u4e5f\u4f3c\u4e4e\u6ca1\u6709\u53bb\u5b9e\u73b0\uff0c\u6240\u4ee5\u6682\u65f6\u5230\u6b64\u4e3a\u6b62\uff0c\u5982\u679c\u540e\u9762\u627e\u5230\u76f8\u5e94\u7684\u4ee3\u7801\uff0c\u518d\u6765\u770b\u3002<\/p>\n<p>\u6240\u4ee5\u770b\u5b8c\u8fd9\u4e48\u591a\u4e0d\u5fc5\u89c9\u5f97\u60ca\u8bb6\uff0c\u7ad9\u5728Camera Service\u7684\u7acb\u573a\uff0c\u5b83\u6301\u6709\u4e24\u4e2aMetadataQueue\uff0cmRequestQueue\u548cmFrameQueue\u3002<br \/>\napp\u8bf7\u6c42\u7684\u52a8\u4f5c\uff0c\u6bd4\u5982set parameter\/start preview\/start recording\u4f1a\u76f4\u63a5\u8f6c\u5316\u4e3arequest\uff0c\u653e\u5230mRequestQueue\uff0c\u7136\u540e\u53bb\u91cd\u542fpreview\/recording stream\u3002<br \/>\n\u6bd4\u5982capture\u4e5f\u4f1a\u8f6c\u6362\u4e3arequest\uff0c\u653e\u5230mRequestQueue\u3002<br \/>\n\u5982\u679c\u6709\u5fc5\u8981\uff0c\u4f1a\u901a\u8fc7notify_request_queue_not_empty\u53bb\u901a\u77e5QCam HAL\u6709\u8bf7\u6c42\u9700\u8981\u5904\u7406\uff0c\u7136\u540eQCam HAL\u4f1a\u542f\u52a8\u4e00\u4e2a\u7ebf\u7a0b(QCameraHardwareInterface::runCommandThread)\u53bb\u505a\u5904\u7406\u3002\u76f4\u5230\u6240\u6709request\u5904\u7406\u5b8c\u6bd5\u9000\u51fa\u7ebf\u7a0b\u3002<br \/>\n\u5728\u8fd9\u4e2a\u5904\u7406\u7684\u8fc7\u7a0b\u5f53\u4e2d\u4f1a\u5206\u522b\u8c03\u7528\u5230\u6bcf\u4e2astream\u7684processPreviewFrame\uff0c\u6709\u5fc5\u8981\u7684\u8bdd\u5b83\u6bcf\u4e2a\u90fd\u4f1a\u8c03\u7528\u81ea\u5df1\u540e\u7eed\u7684callback\u3002<br \/>\n\u8fd8\u6709\u4e00\u4e2a\u5b9e\u73b0\u7684\u7ec6\u8282\u5c31\u662f\uff0cstream_cb_routine\u662f\u4ecestart stream\u5c31\u6709\u5f00\u59cb\u6ce8\u518c\u5728\u540c\u4e00\u4e2achannel\u4e0a\u7684\uff0c\u800cstream_cb_routine\u95f4\u63a5\u8c03\u7528QCameraStream::dataCallback(\u5f53\u7136stream_cb_routine\u6709\u53bb\u6307\u5b9a\u8fd9\u4e2acallback\u56de\u6765\u7684\u539f\u56e0\u662f\u4ec0\u4e48\uff0c\u5c31\u597d\u8c03\u7528\u5bf9\u5e94\u7684dataCallback)\uff0c\u8fd9\u4e2acallback\u662f\u4e00\u76f4\u90fd\u5728\u56de\u6765\uff0c\u6240\u4ee5\u6bcf\u6b21new request\u8ba9mPendingCount\u52a01\u4e4b\u540e\uff0cdataCallback\u56de\u6765\u624d\u4f1a\u8c03\u7528processPreviewFrame\uff0c\u5426\u5219\u5c31\u76f4\u63a5\u628abuffer\u518d\u6b21\u538b\u56deDRV\u961f\u5217\u5f53\u4e2d\u3002<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void QCameraStream::dataCallback(mm_camera_super_buf_t *bufs)\r\n{\r\n    if (mPendingCount != 0) { \/\/ \u8fd9\u4e2adataCallback\u662f\u4e00\u76f4\u5728\u90fd\u5728\u56de\u6765\u4e48\uff1f\r\n    \t\t\t\t\t\t   \/\/ \u800c\u4e14\u4ece\u4ee3\u7801\u6765\u770b\u8bbe\u7f6e\u4e0b\u53bb\u7684callback\u6b21\u6570\u9ed8\u8ba4\u662f-1\uff0c-1\u5c31\u8868\u793ainfinite\u3002\r\n    \t\t\t\t\t\t   \/\/ \u4f3c\u4e4e\u53ea\u80fd\u8fd9\u6837\u624d\u80fd\u89e3\u91ca\uff0c\u5426\u5219\u6ca1\u4eba\u89e6\u53d1\u7684\u8bdd\uff0c\u5373\u4f7fmPendingCount\u5728onNewRequest\u5f53\u4e2d\u52a01\u4e86\r\n    \t\t\t\t\t\t   \/\/ \u8fd9\u91cc\u4e5f\u611f\u77e5\u4e0d\u5230\r\n        ALOGD(&quot;Got frame request&quot;);\r\n        pthread_mutex_lock(&amp;mFrameDeliveredMutex);\r\n        mPendingCount--;\r\n        ALOGD(&quot;Completed frame request&quot;);\r\n        pthread_cond_signal(&amp;mFrameDeliveredCond);\r\n        pthread_mutex_unlock(&amp;mFrameDeliveredMutex);\r\n        processPreviewFrame(bufs);\r\n    } else {\r\n        p_mm_ops-&gt;ops-&gt;qbuf(mCameraHandle,\r\n                mChannelId, bufs-&gt;bufs&#x5B;0]); \/\/ \u5982\u679c\u6ca1\u6709\u9700\u8981\u6570\u636e\u7684\u60c5\u51b5\uff0c\u76f4\u63a5\u628abuffer\u538b\u5165DRV\u7684\u961f\u5217\u5f53\u4e2d\uff0c\u4f1acall\u5230V4L2\u7684QBUF\r\n    }\r\n}<\/pre>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">void QCameraStream::onNewRequest()\r\n{\r\n    ALOGI(&quot;%s:E&quot;,__func__);\r\n    pthread_mutex_lock(&amp;mFrameDeliveredMutex);\r\n    ALOGI(&quot;Sending Frame request&quot;);\r\n    mPendingCount++;\r\n    pthread_cond_wait(&amp;mFrameDeliveredCond, &amp;mFrameDeliveredMutex); \/\/ \u7b49\u5e26\u4e00\u4e2a\u8bf7\u6c42\u5904\u7406\u5b8c\uff0c\u518d\u505a\u4e0b\u4e00\u4e2a\u8bf7\u6c42\r\n    ALOGV(&quot;Got frame&quot;);\r\n    pthread_mutex_unlock(&amp;mFrameDeliveredMutex);\r\n    ALOGV(&quot;%s:X&quot;,__func__);\r\n}<\/pre>\n<p>processPreviewFrame\u4f1a\u8c03\u7528\u5230\u521b\u5efa\u8fd9\u4e2astream\u7684\u65f6\u5019\u5173\u8054\u8fdb\u6765\u7684\u90a3\u4e2aBufferQueue\u7684enqueue_buffer\u65b9\u6cd5\uff0c\u628a\u6570\u636e\u585e\u5230BufferQueue\u4e2d\uff0c\u7136\u540e\u5bf9\u5e94\u7684consumer\u5c31\u4f1a\u6536\u5230\u4e86\u3002<br \/>\n\u6bd4\u5982\u5728Android Camera HAL 2.0\u5f53\u4e2d\u76ee\u524d\u6709<br \/>\ncamera2\/BurstCapture.h<br \/>\ncamera2\/CallbackProcessor.h<br \/>\ncamera2\/JpegProcessor.h<br \/>\ncamera2\/StreamingProcessor.h<br \/>\ncamera2\/ZslProcessor.h<br \/>\n\u5b9e\u73b0\u4e86\u5bf9\u5e94\u7684Consumer::FrameAvailableListener\uff0c\u4f46\u662fburst-capture\u73b0\u5728\u53ef\u4ee5\u4e0d\u8003\u8651\uff0c\u56e0\u4e3a\u90fd\u8fd8\u53ea\u662fstub\u5b9e\u73b0\u3002<\/p>\n<p>ZslProcessor.h\u548cCaptureSequencer.h\u90fd\u6709\u53bb\u5b9e\u73b0FrameProcessor::FilteredListener\u7684onFrameAvailable(&#8230;)<br \/>\n\u4f46\u662f\u6211\u4eec\u4e4b\u524d\u8bb2\u8fc7\u8fd9\u7248QCam HAL\u6ca1\u6709\u5b9e\u73b0\uff0c\u6240\u4ee5FrameProcessor\u662f\u65e0\u6cd5\u83b7\u53d6\u5230meta data\u7684\u3002<br \/>\n\u6240\u4ee5\u8fd9\u6837\u6765\u770bonFrameAbailable\u90fd\u4e0d\u4f1a\u5f97\u5230\u901a\u77e5\u3002(\u6211\u76f8\u4fe1\u662f\u6211\u624b\u91cc\u7684\u8fd9\u7248\u4ee3\u7801\u7684\u95ee\u9898\u5566)<\/p>\n<p>\u4e4b\u524d\u6211\u4eec\u8bf4\u8fc7QCam HAL\u6709\u90e8\u5206\u4e1c\u897f\u6ca1\u6709\u5b9e\u73b0\uff0c\u6240\u4ee5mFrameQueue\u5c31\u4e0d\u4f1a\u6709\u6570\u636e\uff0c\u4f46\u662f\u5b83\u672c\u6765\u5e94\u8be5\u662fDRV\u56de\u6765\u7684\u5143\u6570\u636e\u4f1aqueue\u5230\u8fd9\u91cc\u9762\u3002<\/p>\n<p>\u53e6\u5916<br \/>\nCaptureSequencer.h\u8fd8\u6709\u53bb\u5b9e\u73b0onCaptureAvailable\uff0c\u5f53JpegProcessor\u5904\u7406\u5b8c\u4e86\u4f1a\u901a\u77e5\u5b83\u3002<\/p>\n<p>\u597d\u5947\uff1f\u591a\u4e2astream(s)\u4e0d\u662f\u540c\u65f6\u8fd4\u56de\u7684\uff0c\u8fd9\u6837\u5982\u679cCPU\u5904\u7406\u5feb\u6162\u4e0d\u540c\u5c31\u4f1a\u6709\u65f6\u95f4\u5dee\uff1f\u8fd8\u6709\u5f88\u597d\u5947DRV\u662f\u5982\u4f55\u5904\u7406Video snapshot\u7684\uff0c\u5982\u679cbuffer\u662f\u987a\u5e8f\u7684\uff0c\u5c31\u4f1a\u5b58\u5728Video\u5c11\u4e00\u4e2aframe\uff0c\u5982\u679c\u4e0d\u662f\u987a\u5e8f\u7684\uff0c\u90a3\u5c31\u662fDRV\u4e00\u6b21\u8fd4\u56de\u591a\u4e2abuffer\uff1f\u4ee5\u524d\u771f\u6ca1\u6709\u60f3\u8fc7\u8fd9\u4e2a\u95ee\u9898@_@<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u6211\u4eec\u77e5\u9053\u5728HAL\u7684Vendor\u5b9e\u73b0\u5f53\u4e2d\u4f1a\u52a8\u6001\u53bbload\u4e00\u4e2a\u540d\u5b57\u4e3acamera.$platform$.so\u7684\u6863\u6848\uff0c\u7136\u540e\u53bb\u52a0\u8f7dAndroid HAL\u5f53\u4e2d\u5b9a\u4e49\u7684\u65b9\u6cd5\uff0c\u8fd9\u91cc\u4ee5Camera HAL 2.0\u5e76\u4e14Qualcomm msm8960\u4e3a\u4f8b\u5b50\u770b\u4e0b\uff0c\u7ed3\u5408\u4e4b\u524d\u7684\u4e00\u7bc7\u6587\u7ae0(http:\/\/guoh.ai\/lifelog\/2013\/07\/glance-at-camera-hal-2-0\/)\u3002 (\u6ce8\uff1a\u8fd9\u7bc7\u6587\u7ae0\u5df2\u7ecf\u8349\u7a3f\u6bd4\u8f83\u4e45\u4e86\uff0c\u4f46\u662f\u4e00\u76f4\u6ca1\u6709\u53d1\u51fa\u6765\uff0c\u56e0\u4e3a\u624b\u91cc\u7684\u8fd9\u7248\u4ee3\u7801\u6ca1\u6709\u8bbe\u5907\u53ef\u4ee5\u8dd1\uff0c\u53e6\u5916\u4e5f\u65e0\u6cd5\u786e\u5b9a\u4ee3\u7801\u662f\u5426\u5b8c\u5168\u6b63\u786e\uff0c\u81f3\u5c11\u53d1\u73b0\u4e86\u4e00\u4e9b\u5730\u65b9\u90fd\u662fstub\u5b9e\u73b0\uff0c\u6587\u4e2d\u53ef\u80fd\u5b58\u5728\u4e00\u4e9b\u9519\u8bef\uff0c\u5982\u53d1\u73b0\u4e0d\u6b63\u786e\u7684\u5730\u65b9\u6b22\u8fce\u6307\u51fa\uff0c\u6211\u4e5f\u4f1a\u5c3d\u91cf\u53d1\u73b0\u9519\u8bef\u5e76\u4fee\u6b63\uff01) \u6211\u4eec\u77e5\u9053\u5728camera2.h\u5f53\u4e2d\u5b9a\u4e49\u4e86\u5f88\u591a\u65b9\u6cd5\uff0c\u90a3\u4e48\u5728msm8960 HAL\u5c31\u662f\u5728\u5982\u4e0b\u5730\u65b9 \/path\/to\/qcam-hal\/QCamera\/HAL2 \u8fd9\u7f16\u8bd1\u51fa\u6765\u5c31\u662f\u4e00\u4e2acamera.$platform$.so\uff0c\u8bf7\u770b\u5b83\u7684\u5b9e\u73b0 \u9996\u5148\u662fHAL2\/wrapper\/QualcommCamera.h|cpp \/** * The functions need to be provided by the camera HAL. * * If getNumberOfCameras() returns N, the valid cameraId for getCameraInfo() * and openCameraHardware() is 0 to N-1. *\/ static hw_module_methods_t camera_module_methods = { open: camera_device_open, }; static hw_module_t camera_common = { &hellip; <a href=\"https:\/\/guoh.ai\/lifelog\/2013\/08\/qcam-hal-2-0\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Qualcomm Camera HAL 2.0<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_gfmr_meta_descriptions":[],"_gfmr_multilingual_taxonomy_terms":[],"footnotes":""},"categories":[7,28,34],"tags":[27],"class_list":["post-690","post","type-post","status-publish","format-standard","hentry","category-android","category-cpp","category-multimedia","tag-camera"],"_links":{"self":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/690","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/comments?post=690"}],"version-history":[{"count":5,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/690\/revisions"}],"predecessor-version":[{"id":706,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/posts\/690\/revisions\/706"}],"wp:attachment":[{"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/media?parent=690"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/categories?post=690"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guoh.ai\/lifelog\/wp-json\/wp\/v2\/tags?post=690"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}