{"id":4335,"date":"2023-02-16T22:59:03","date_gmt":"2023-02-16T14:59:03","guid":{"rendered":"https:\/\/blog.coderfan.org\/?p=4335"},"modified":"2023-05-10T16:28:39","modified_gmt":"2023-05-10T08:28:39","slug":"android12-evs-architecture-analysis-of-evs-app","status":"publish","type":"post","link":"https:\/\/blog.coderfan.org\/en\/android12-evs-architecture-analysis-of-evs-app.html","title":{"rendered":"Android12 EVS\u67b6\u6784\u5168\u89e3\u4e4b\u5e94\u7528\u89e3\u6790"},"content":{"rendered":"<div class='booster-block booster-read-block'>\n                <div class=\"twp-read-time\">\n                \t<i class=\"booster-icon twp-clock\"><\/i> <span>Read Time:<\/span>7 Minute, 30 Second                <\/div>\n\n            <\/div>\n<p class=\"has-text-align-justify\">\u4e4b\u524d\u5df2\u7ecf\u9488\u5bf9EVS\u7684\u6574\u4f53\u67b6\u6784\u8fdb\u884c\u4e86\u89e3\u6790\uff0c\u5e76\u5bf9\u5404\u4e2a\u6a21\u5757\u7684\u529f\u80fd\u8fdb\u884c\u4e86\u521d\u6b65\u7684\u4ecb\u7ecd\u548c\u8bb2\u89e3\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u5c06\u6df1\u5165\u5230\u6bcf\u4e2a\u6a21\u5757\u7684\u5185\u90e8\uff0c\u770b\u770b\u6a21\u5757\u5185\u7684\u5177\u4f53\u903b\u8f91\uff0c\u90a3\u4e48\u4eca\u5929\u6211\u4eec\u89e3\u6790EVS\u67b6\u6784\u4e2d\u7684\u5e94\u7528\u2014\u2014EVS APP\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify has-mobile-text-align-justify\">\u9996\u5148\u8fd8\u662f\u9700\u8981\u8bf4\u660e\uff0c\u5728Android\u7cfb\u7edf\u4e2d\u8c08\u5230App\u5f88\u591a\u4eba\u90fd\u9ed8\u8ba4\u5176\u662f\u8fd0\u884c\u5728JVM\u4e4b\u4e0a\u7684Application\uff0c\u4f46\u662f\u6b64\u5904\u7684EVS APP\u5219\u662f\u8fd0\u884c\u5728Native Framework\u8fd9\u4e00\u5c42\u7684\uff0c\u975e\u4f20\u7edfAndroid\u57fa\u4e8eapk\u5f62\u5f0f\u7684\u5e94\u7528\u3002\u4e4b\u6240\u4ee5\u79f0\u4e4b\u4e3aEVS APP\uff0c\u662f\u56e0\u4e3a\u5176\u5177\u4f53\u7684\u529f\u80fd\u903b\u8f91\uff0c\u4e0e\u8fd0\u884c\u5728JVM\u4e0a\u7684APP\u4fdd\u6301\u4e00\u81f4\uff0c\u5373<strong>\u57fa\u4e8e\u7528\u6237\u9700\u6c42\uff0c\u54cd\u5e94\u7528\u6237\u8f93\u5165\uff0c\u5b9e\u73b0\u7528\u6237\u4ea4\u4e92<\/strong>\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u7a0b\u5e8f\u5165\u53e3<\/h3>\n\n\n\n<p class=\"has-text-align-justify\">EVS APP\u7684\u5165\u53e3\u6211\u4eec\u53ef\u4ee5\u5728evs_app.cpp\u6587\u4ef6\u5185\u627e\u5230\uff0c\u6211\u4eec\u627e\u5230main\u7a0b\u5e8f\u5165\u53e3\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code has-tablet-text-align-justify has-mobile-text-align-justify\"><code>\/\/ Main entry point\nint main(int argc, char** argv)\n{\n    LOG(INFO) &lt;&lt; \"EVS app starting\";\n\n    \/\/ Register a signal handler\n    registerSigHandler();\n\n    \/\/ Set up default behavior, then check for command line options\n    bool useVehicleHal = true;\n    bool printHelp = false;\n    const char* evsServiceName = \"default\";\n    int displayId = -1;\n    bool useExternalMemory = false;\n    android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;\n    int32_t mockGearSignal = static_cast&lt;int32_t&gt;(VehicleGear::GEAR_REVERSE);\n    for (int i = 1; i &lt; argc; i++)\n    {\n    ...\n\t}\n\n    \/\/ Load our configuration information\n    ConfigManager config;\n    if (!config.initialize(CONFIG_OVERRIDE_PATH))\n    {\n        if (!config.initialize(CONFIG_DEFAULT_PATH))\n        {\n            return EXIT_FAILURE;\n        }\n    }\n\n    configureRpcThreadpool(1, false \/* callerWillJoin *\/);\n\n    \/\/ Construct our async helper object\n    sp&lt;EvsVehicleListener&gt; pEvsListener = new EvsVehicleListener();\n\n    \/\/ Get the EVS manager service\n    LOG(INFO) &lt;&lt; \"Acquiring EVS Enumerator\";\n    pEvs = IEvsEnumerator::getService(evsServiceName);\n    if (pEvs.get() == nullptr)\n    {\n        LOG(ERROR) &lt;&lt; \"getService(\" &lt;&lt; evsServiceName\n                   &lt;&lt; \") returned NULL.  Exiting.\";\n        return EXIT_FAILURE;\n    }\n\n    \/\/ Request exclusive access to the EVS display\n    LOG(INFO) &lt;&lt; \"Acquiring EVS Display\";\n\n    \/\/ We'll use an available display device.\n    displayId = config.setActiveDisplayId(displayId);\n    if (displayId &lt; 0)\n    {\n        PLOG(ERROR) &lt;&lt; \"EVS Display is unknown.  Exiting.\";\n        return EXIT_FAILURE;\n    }\n\n    pDisplay = pEvs-&gt;openDisplay_1_1(displayId);\n    if (pDisplay.get() == nullptr)\n    {\n        LOG(ERROR) &lt;&lt; \"EVS Display unavailable.  Exiting.\";\n        return EXIT_FAILURE;\n    }\n\n    config.useExternalMemory(useExternalMemory);\n    config.setExternalMemoryFormat(extMemoryFormat);\n\n    \/\/ Set a mock gear signal for the test mode\n    config.setMockGearSignal(mockGearSignal);\n\n    \/\/ Connect to the Vehicle HAL so we can monitor state\n    sp&lt;IVehicle&gt; pVnet;\n    if (useVehicleHal)\n    {\n        LOG(INFO) &lt;&lt; \"Connecting to Vehicle HAL\";\n        pVnet = IVehicle::getService();\n        if (pVnet.get() == nullptr)\n        {\n            LOG(ERROR) &lt;&lt; \"Vehicle HAL getService returned NULL.  Exiting.\";\n            return EXIT_FAILURE;\n        }\n        else\n        {\n            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::GEAR_SELECTION))\n            {\n                LOG(ERROR) &lt;&lt; \"Without gear notification, we can't support EVS.  Exiting.\";\n                return EXIT_FAILURE;\n            }\n            if (!subscribeToVHal(pVnet, pEvsListener, VehicleProperty::TURN_SIGNAL_STATE))\n            {\n                LOG(WARNING) &lt;&lt; \"Didn't get turn signal notifications, so we'll ignore those.\";\n            }\n        }\n    }\n    else\n    {\n        LOG(WARNING) &lt;&lt; \"Test mode selected, so not talking to Vehicle HAL\";\n    }\n\n    \/\/ Configure ourselves for the current vehicle state at startup\n    LOG(INFO) &lt;&lt; \"Constructing state controller\";\n    pStateController = new EvsStateControl(pVnet, pEvs, pDisplay, config);\n    if (!pStateController-&gt;startUpdateLoop())\n    {\n        LOG(ERROR) &lt;&lt; \"Initial configuration failed.  Exiting.\";\n        return EXIT_FAILURE;\n    }\n\n    \/\/ Run forever, reacting to events as necessary\n    LOG(INFO) &lt;&lt; \"Entering running state\";\n    pEvsListener-&gt;run(pStateController);\n\n    \/\/ In normal operation, we expect to run forever, but in some error conditions we'll quit.\n    \/\/ One known example is if another process preempts our registration for our service name.\n    LOG(ERROR) &lt;&lt; \"EVS Listener stopped.  Exiting.\";\n    return EXIT_SUCCESS;\n}<\/code><\/pre>\n\n\n\n<p>\u5728main\u51fd\u6570\u5185\uff0c\u4e3b\u8981\u505a\u4e86\u4ee5\u4e0b\u51e0\u4ef6\u4e8b\uff1a<\/p>\n\n\n\n<p class=\"has-text-align-justify\">1.\u6ce8\u518c\u4fe1\u53f7\u5904\u7406\u51fd\u6570\uff0c\u5982\u8fdb\u7a0b\u6536\u5230SIGABRT\u3001SIGTERM\u4e0eSIGINT\u7b49\u4fe1\u53f7\u540e\u4f1a\u5411EvsStateControl\u6a21\u5757\u53d1\u9001\u547d\u4ee4\u7ed3\u675f\u5185\u90e8\u7ebf\u7a0b\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">2.\u89e3\u6790\u7a0b\u5e8f\u542f\u52a8\u53c2\u6570\uff0c\u5982display\u8bbe\u5b9a\u3001\u8f66\u8f86\u6321\u4f4d\u8bbe\u5b9a\u7b49\u4fe1\u53f7\uff1b\u5982\u679c\u672a\u5339\u914d\u5230\u5bf9\u5e94\u7684\u542f\u52a8\u53c2\u6570\u5219\u6253\u5370\u5e2e\u52a9\u4fe1\u606f\uff0c\u8fd9\u90e8\u5206\u4e00\u822c\u7528\u4e8e\u8c03\u8bd5\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">3.\u89e3\u6790\u914d\u7f6e\u6587\u4ef6\uff0c\u914d\u7f6e\u6587\u4ef6\u7528\u4e8e\u914d\u7f6e\u5e94\u7528\u6240\u9700\u8981\u7684\u4e00\u4e9b\u4fe1\u606f<\/p>\n\n\n\n<p class=\"has-text-align-justify\">4.\u83b7\u53d6\u5e95\u5c42Hal\u679a\u4e3e\u5bf9\u8c61\uff0c\u6253\u5f00Display\u8bbe\u5907<\/p>\n\n\n\n<p class=\"has-text-align-justify\">5.\u5411Vehicle\u6ce8\u518c\u8ba2\u9605\u4fe1\u53f7\uff0c\u5e76\u521b\u5efaEvsVehicleListener\u6765\u5bf9\u56de\u8c03\u505a\u5904\u7406\uff1b\u8fd9\u91cc\u53ea\u8ba2\u9605\u4e86\u6321\u4f4d\u548c\u8f6c\u5411\u706f\u4fe1\u606f<\/p>\n\n\n\n<p>6.\u542f\u52a8StateControl\u6a21\u5757\u5185\u7684loop\u7ebf\u7a0b<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5f00\u542f\u7ed8\u5236<\/h3>\n\n\n\n<p class=\"has-text-align-justify\">\u5728EVS\u67b6\u6784\u4e2d\uff0c\u9700\u8981\u4e00\u76f4\u4fdd\u6301\u5bf9\u8f66\u8eab\u4fe1\u606f\u7684\u76d1\u542c\uff0c\u4ece\u800c\u6765\u51b3\u5b9a\u662f\u5426\u9700\u8981\u8fdb\u884c\u753b\u9762\u7684\u7ed8\u5236\uff0c\u4ee5\u53ca\u5207\u6362\u753b\u9762\u7684\u72b6\u6001\u3002\u800c\u8fd9\u4e00\u5207\u63a7\u5236\u7684\u6e90\u5934\uff0c\u6765\u6e90\u4e8eEvsStateControl\u6a21\u5757\uff1a<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void EvsStateControl::updateLoop()\n{\n    ALOGD(\"Starting EvsStateControl update loop\");\n    bool run = true;\n    while (run)\n    {\n        \/\/ Process incoming commands\n        {\n            std::lock_guard&lt;std::mutex&gt; lock(mLock);\n            while (!mCommandQueue.empty())\n            {\n                const Command&amp; cmd = mCommandQueue.front();\n                switch (cmd.operation)\n                {\n                case Op::EXIT:\n                    run = false;\n                    break;\n                case Op::CHECK_VEHICLE_STATE:\n                    break;\n                case Op::TOUCH_EVENT:\n                    break;\n                }\n                mCommandQueue.pop();\n            }\n        }\n      }\n...\n     if (!selectStateForCurrentConditions())\n     {\n            ALOGE(\"selectStateForCurrentConditions failed,loop again\");\n            continue;\n      }\n...\n     if (!mCurrentRenderer-&gt;drawFrame(convertBufferDesc(tgtBuffer)))\n     {\n        run = false;\n      }\n       \/\/ Send the finished image back for display\n      displayHandle-&gt;returnTargetBufferForDisplay(tgtBuffer);\n      if (!mFirstFrameIsDisplayed)\n      {\n         mFirstFrameIsDisplayed = true;\n         mEvsStats.finishComputingFirstFrameLatency(android::uptimeMillis());\n       }\n ...\n}<\/code><\/pre>\n\n\n\n<p>\u5728\u8be5loop\u5faa\u73af\u4e2d\uff0c\u4e3b\u8981\u5305\u542b\u4e09\u4e2a\u884c\u4e3a\uff1a<\/p>\n\n\n\n<p class=\"has-text-align-justify\">1.\u63a5\u6536\u5904\u7406\u4e09\u7c7bcommand:\u9000\u51fa\uff0c\u8f66\u8eab\u72b6\u6001\u53d8\u5316\u4e0eTouch\u4e8b\u4ef6\u3002\u5f53\u524d\u5b9e\u73b0\u4e2d\u9000\u51fa\u7684command\u53ea\u5728\u7a0b\u5e8f\u6355\u83b7\u5230\u8bf8\u5982SIGTERM\u7b49\u4fe1\u53f7\u65f6\u53d1\u9001\uff0c\u8f66\u8eab\u72b6\u6001\u53d8\u5316\u5219\u5728EvsVehicleListener\u63a5\u6536\u5230Vehicle HAL\u56de\u8c03\u65f6\u8fdb\u884c\u53d1\u9001\uff0c\u800cTouch\u4e8b\u4ef6\u5f53\u524d\u6ca1\u6709\u5b9e\u73b0\uff0c\u662f\u9700\u8981\u5f00\u53d1\u8005\u81ea\u884c\u5b9e\u73b0\u7684\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">2.<strong>\u6839\u636e\u8f66\u8eab\u72b6\u6001\u9009\u62e9\u4e0d\u540c\u7684\u7ed8\u5236\u7c7b\u578b\u4e0e\u65b9\u5f0f<\/strong>\u3002\u8fd9\u91cc\u7684\u7c7b\u578b\u5206\u4e3a\u4e24\u7c7b\uff1aRenderDirectView\u4e0eRenderTopView,\u8fd9\u4e24\u7c7b\u7ed8\u5236\u7c7b\u578b\u90fd\u6709\u5355\u72ec\u7684\u7c7b\u5b9e\u73b0\u3002\u7b80\u5355\u6765\u8bb2\uff0cRenderDirectView\u662f\u9488\u5bf9\u4e8e\u53ea\u6709\u5355\u4e2a\u6444\u50cf\u5934\u56fe\u50cf\u8f93\u5165\u7684\u60c5\u51b5\uff0c\u800cRenderTopView\u5219\u662f\u5b58\u5728\u591a\u4e2a\u6444\u50cf\u5934\u56fe\u50cf\u8f93\u5165\u65f6\u7684\u7ed8\u5236\u3002\u800c\u7ed8\u5236\u65b9\u5f0f\u5219\u662f\u5206\u4e3aGPU\u52a0\u901f\u4e0e\u7eafCPU\u5904\u7406\u4e24\u7c7b\u3002\u524d\u8005\u9700\u8981\u501f\u52a9\u4e8eOpenGL ES\u5b9e\u73b0\u56fe\u50cf\u7ed8\u5236\uff0c\u800c\u540e\u8005\u5219\u662f\u901a\u8fc7CPU\u76f4\u63a5\u64cd\u4f5c\u5185\u5b58\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">\u5728EVS\u67b6\u6784\u4e2d\uff0c\u51b3\u5b9a\u7ed8\u5236\u7684\u7c7b\u578b\u7531\u5f53\u524d\u7684\u8f66\u8eab\u72b6\u6001\u4e0e\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u914d\u7f6e\u53c2\u6570\u5171\u540c\u51b3\u5b9a\u3002\u8f66\u8eab\u72b6\u6001\u5206\u4e3a\uff1aOFF\u3001REVERSE\u3001RIGHT\u3001LEFT\u3001PARKING\u8fd9\u4e94\u7c7b\uff0cREVERSE\u4e0ePARKING\u7531\u6321\u4f4d\u51b3\u5b9a\uff0c\u800cRIGHT\u4e0eLEFT\u7531\u8f6c\u5411\u706f\u51b3\u5b9a\uff0c\u6321\u4f4d\u7684\u4f18\u5148\u7ea7\u662f\u9ad8\u4e8e\u8f6c\u5411\u706f\u7684\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">\u5728\u5f97\u5230\u4e0a\u8ff0\u72b6\u6001\u540e\uff0cEVS\u5185\u4f1a\u5224\u65ad\u914d\u7f6e\u4e86\u4e0a\u8ff0\u72b6\u6001\u7684\u6444\u50cf\u5934\u4e2a\u6570\uff0c\u5f53\u53ea\u6709\u4e00\u4e2a\u6444\u50cf\u5934\u65f6\u5219\u4f1a\u4ee5RenderDirectView\u7c7b\u578b\u8fdb\u884c\u56fe\u50cf\u7ed8\u5236\uff0c\u800c\u5b58\u5728\u591a\u4e2a\u6444\u50cf\u5934\u65f6\u5219\u4f1a\u8baeRenderTopView\u7c7b\u578b\u8fdb\u884c\u56fe\u50cf\u7ed8\u5236\uff0c\u5982\u4e0b\u6240\u793a\u3002<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"cpp\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">      if (mCameraList[desiredState].size() == 1)\n        {\n            mDesiredRenderer =std::make_unique&lt;RenderDirectView>(mEvs, \n            mCameraDescList[desiredState][0],mConfig);\n            if (!mDesiredRenderer)\n            {\n                LOGE(\"Failed to construct direct renderer.  Skipping state change.\");\n                return false;\n            }\n        }\n        else if (mCameraList[desiredState].size() > 1 || desiredState == PARKING)\n        {\n             ConfigManager.mDesiredRenderer =\n            std::make_unique&lt;RenderTopView>(mEvs, mCameraList[desiredState], mConfig);\n            if (!mDesiredRenderer)\n            {\n                LOGE(\"Failed to construct top view renderer.  Skipping state change.\");\n                return false;\n            }\n        }<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u83b7\u53d6Display Buffer<\/h3>\n\n\n\n<p class=\"has-text-align-justify\">\u5728\u6211\u4eec\u5f00\u59cb\u6b63\u5f0f\u7684\u7ed8\u5236\u65f6\uff0c\u6211\u4eec\u9700\u8981\u4e00\u5757\u513fdisplay buffer\u7528\u4e8e\u627f\u8f7d\u6211\u4eec\u7ed8\u5236\u597d\u7684\u5185\u5bb9\u7528\u4e8e\u663e\u793a\uff0c\u8fd9\u4e9bbuffer\u7edf\u4e00\u90fd\u6765\u6e90\u4e8eGraphicBuffer\u3002\u5728Android12.1\u539f\u751fEVS\u5b9e\u73b0\u4e2d\uff0cEVS APP\u901a\u8fc7HIDL\u63a5\u53e3\u5411EVS HAL\u7533\u8bf7\u8fd9\u7c7bBuffer\uff0c\u5b9a\u4e49\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">    \/**\n     * This call returns a handle to a frame buffer associated with the display.\n     *\n     * @return buffer A handle to a frame buffer.  The returned buffer may be\n     *                locked and written to by software and\/or GL.  This buffer\n     *                must be returned via a call to\n     *                returnTargetBufferForDisplay() even if the display is no\n     *                longer visible.\n     *\/\n     getTargetBuffer() generates (BufferDesc buffer);<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-justify\">\u5f53EVS APP\u9996\u6b21\u901a\u8fc7\u8be5\u63a5\u53e3\u5411EVS HAL\u7533\u8bf7\u7528\u4e8e\u663e\u793a\u7684frame buffer\u65f6,EVS HAL\u5373\u4f1a\u901a\u8fc7GraphicBufferAllocator\u7684\u670d\u52a1\u5206\u914d\u8fd9\u6837\u4e00\u5757\u513f\u5185\u5b58\uff0c\u4ee3\u7801\u5982\u4e0b\uff1a<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">\/**\n * This call returns a handle to a frame buffer associated with the display.\n * This buffer may be locked and written to by software and\/or GL.  This buffer\n * must be returned via a call to returnTargetBufferForDisplay() even if the\n * display is no longer visible.\n *\/\nReturn&lt;void> EvsGlDisplay::getTargetBuffer(getTargetBuffer_cb _hidl_cb)\n{\n    \/\/ ALOGD(\"%s Entered\", __FUNCTION__);\n    std::lock_guard&lt;std::mutex> lock(mAccessLock);\n\n    if (mRequestedState == EvsDisplayState::DEAD)\n    {\n        ALOGE(\"Rejecting buffer request from object that lost ownership of the display.\");\n        _hidl_cb({});\n        return Void();\n    }\n\n    \/\/ If we don't already have a buffer, allocate one now\n    if (!mBuffer.memHandle)\n    {\n        \/\/ Initialize our display window\n        \/\/ NOTE:  This will cause the display to become \"VISIBLE\" before a frame is actually\n        \/\/ returned, which is contrary to the spec and will likely result in a black frame being\n        \/\/ (briefly) shown.\n        if (!mGlWrapper.initialize(mDisplayProxy, mDisplayId))\n        {\n            \/\/ Report the failure\n            ALOGE(\"Failed to initialize GL display\");\n            _hidl_cb({});\n            return Void();\n        }\n\n        \/\/ Assemble the buffer description we'll use for our render target\n        mBuffer.width = mGlWrapper.getWidth();\n        mBuffer.height = mGlWrapper.getHeight();\n        mBuffer.format = HAL_PIXEL_FORMAT_RGBA_8888;\n        mBuffer.usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;\n        mBuffer.bufferId = 0x3870; \/\/ Arbitrary magic number for self recognition\n        mBuffer.pixelSize = 4;\n\n        \/\/ Allocate the buffer that will hold our displayable image\n        buffer_handle_t handle = nullptr;\n        GraphicBufferAllocator&amp; alloc(GraphicBufferAllocator::get());\n        status_t result = alloc.allocate(mBuffer.width, mBuffer.height,\n                                         mBuffer.format, 1,\n                                         mBuffer.usage, &amp;handle,\n                                         &amp;mBuffer.stride,\n                                         0, \"EvsGlDisplay\");\n        if (result != NO_ERROR)\n        {\n            \/\/           ALOGE &lt;&lt; \"Error \" &lt;&lt; result\n            \/\/                 &lt;&lt; \" allocating \" &lt;&lt; mBuffer.width &lt;&lt; \" x \" &lt;&lt; mBuffer.height\n            \/\/                 &lt;&lt; \" graphics buffer.\";\n            ALOGE(\"allocating width:%d,height:%d graphics buffer error\", mBuffer.width, mBuffer.height);\n            _hidl_cb({});\n            mGlWrapper.shutdown();\n            return Void();\n        }\n        if (!handle)\n        {\n            ALOGE(\"We didn't get a buffer handle back from the allocator\");\n            _hidl_cb({});\n            mGlWrapper.shutdown();\n            return Void();\n        }\n\n        mBuffer.memHandle = handle;\n        ALOGD(\"Allocated new buffer %p with stride:%d \", mBuffer.memHandle.getNativeHandle(), mBuffer.stride);\n        mFrameBusy = false;\n    }\n\n    \/\/ Do we have a frame available?\n    if (mFrameBusy)\n    {\n        \/\/ This means either we have a 2nd client trying to compete for buffers\n        \/\/ (an unsupported mode of operation) or else the client hasn't returned\n        \/\/ a previously issued buffer yet (they're behaving badly).\n        \/\/ NOTE:  We have to make the callback even if we have nothing to provide\n        ALOGE(\"getTargetBuffer called while no buffers available.\");\n        _hidl_cb({});\n        return Void();\n    }\n    else\n    {\n        \/\/ Mark our buffer as busy\n        mFrameBusy = true;\n\n        \/\/ Send the buffer to the client\n        ALOGV(\"Providing display buffer handle:%p  as id %d \", mBuffer.memHandle.getNativeHandle(), mBuffer.bufferId);\n        _hidl_cb(mBuffer);\n        return Void();\n    }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">\u83b7\u53d6Camera Buffer<\/h3>\n\n\n\n<p class=\"has-text-align-justify\">\u9664\u4e86Display Buffer\uff0c\u6211\u4eec\u8fd8\u9700\u8981\u83b7\u53d6Camera\u6570\u636e\uff0c\u6d89\u53ca\u5230\u7684\u63a5\u53e3\u5305\u62ec\uff1adeliverFrame\uff0cnewFrameAvailable,getNewFrame\u4e0edoneWithFrame.\u5176\u4e2ddeliverFrame\u4e0edoneWithFrame\u90fd\u5c5e\u4e8eHIDL\u63a5\u53e3\uff0c\u5176\u5b9a\u4e49\u4e0b\uff1a<\/p>\n\n\n\n<p>I<em>EvsCamera.hal<\/em>\uff1a<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">    \/**\n     * Return a frame that was delivered by to the IEvsCameraStream.\n     *\n     * When done consuming a frame delivered to the IEvsCameraStream\n     * interface, it must be returned to the IEvsCamera for reuse.\n     * A small, finite number of buffers are available (possibly as small\n     * as one), and if the supply is exhausted, no further frames may be\n     * delivered until a buffer is returned.\n     *\n     * @param  buffer A buffer to be returned.\n     *\/\n    oneway doneWithFrame(BufferDesc buffer);<\/code><\/pre>\n\n\n\n<p>I<em>EvsCameraStream.hal<\/em>\uff1a<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">    \/**\n     * Receives calls from the HAL each time a video frame is ready for inspection.\n     * Buffer handles received by this method must be returned via calls to\n     * IEvsCamera::doneWithFrame(). When the video stream is stopped via a call\n     * to IEvsCamera::stopVideoStream(), this callback may continue to happen for\n     * some time as the pipeline drains. Each frame must still be returned.\n     * When the last frame in the stream has been delivered, a NULL bufferHandle\n     * must be delivered, signifying the end of the stream. No further frame\n     * deliveries may happen thereafter.\n     *\n     * @param buffer a buffer descriptor of a delivered image frame.\n     *\/\n    oneway deliverFrame(BufferDesc buffer);<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-justify\">\u63a5\u53e3\u6267\u884c\u6d41\u7a0b\u4e0a\uff0c\u5f53EVS HAL\u83b7\u53d6\u5230\u65b0\u7684\u5e27\u65f6\uff0c\u4f1a\u901a\u8fc7deliverFrame\u63a5\u53e3\u5c06\u6570\u636e\u4e0a\u62a5\u7ed9EVS APP\uff0cEVS APP\u4f1a\u5c06\u5176\u5b58\u50a8\u81f3\u4e00\u4e2a\u53ccBuffer\u4e2d\uff08\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u65b0\u7684camera\u6570\u636e\uff0c\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u4e2d\u7684camera\u6570\u636e\uff0c\u4e24\u8005\u5faa\u73af\uff09\uff0c\u5728EVS APP\u7ed8\u5236\u65f6\uff0c\u5148\u901a\u8fc7newFrameAvailable\u63a5\u53e3\u5224\u65ad\u5f53\u524d\u662f\u5426\u6709\u65b0\u7684\u6570\u636e\u5230\u6765\uff0c\u5982\u5b58\u5728\u65b0\u7684\u6570\u636e\uff0c\u5219\u901a\u8fc7getNewFrame\u6765\u83b7\u53d6\u65b0\u7684camera\u6570\u636e\uff0c\u5728\u4f7f\u7528OpenGL ES\u63a5\u53e3\u8fdb\u884c\u7ed8\u5236\u6e32\u67d3\u540e\uff0c\u518d\u901a\u8fc7  doneWithFrame \u5c06buffer\u5f52\u8fd8\u7ed9\u5e95\u5c42\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u7ed8\u5236\u6d41\u7a0b<\/h3>\n\n\n\n<p class=\"has-text-align-justify\">\u65e0\u8bba\u662fRenderDirectView\u8fd8\u662fRenderTopView\uff0c\u5176\u7ed8\u5236\u6d41\u7a0b\u5927\u4f53\u90fd\u662f\u7c7b\u4f3c\u7684\u3002\u7ed8\u5236\u7684\u63a7\u5236\u5728EvsStateControl\u6a21\u5757\u5185\uff0c\u5982\u4e0b\u6240\u793a\uff1a<\/p>\n\n\n\n<pre class=\"io-enlighter-pre\"><code class=\"gl\" data-enlighter-language=\"cpp\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-highlight=\"\">        mCurrentRenderer = std::move(mDesiredRenderer);\n\n        \/\/ Start the camera stream render\n        LOGD(\"EvsStartCameraStreamTiming start time:%lld ms.\", android::elapsedRealtime());\n        if (!mCurrentRenderer->activate())\n        {\n            LOGE(\"New renderer failed to activate\");\n            return false;\n        }\n\n        \/\/ Activate the display\n        LOGD(\"EvsStartCameraStreamTiming start time:%lld ms.\", android::elapsedRealtime());\n        Return&lt;EvsResult> result =\n                     displayHandle->setDisplayState(EvsDisplayState::VISIBLE_ON_NEXT_FRAME);\n        if (result != EvsResult::OK)\n        {\n            LOGE(\"setDisplayState returned an error:%s \", result.description().c_str());\n            return false;\n        }<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-justify\">\u6211\u4eec\u901a\u8fc7\u8c03\u7528activate\u51fd\u6570\u6765\u542f\u52a8Render\u7684\u8fc7\u7a0b\uff0c\u8fd9\u90e8\u5206\u6d89\u53ca\u5230OpenGL ES\u7684\u4e00\u4e9b\u77e5\u8bc6\u3002\u7b80\u5355\u63cf\u8ff0\u4e00\u4e0b\u6d41\u7a0b\uff1a<\/p>\n\n\n\n<p class=\"has-text-align-justify\">1\uff09\u521d\u59cb\u5316EGL\u73af\u5883\uff0c\u5305\u62ec\u8bbe\u5b9aeglDisplay\u3001eglSurface\u3001eglContext\u7b49\uff0c\u8c03\u7528makeCurrent\u5173\u8054\u6211\u4eec\u540e\u7eed\u7684\u7ed8\u5236\u884c\u4e3a\u3002<\/p>\n\n\n\n<p>2\uff09\u6839\u636e\u8bbe\u5b9a\u7684\u9876\u70b9\u7740\u8272\u5668\u4e0e\u7247\u6bb5\u7740\u8272\u5668\u52a0\u8f7dshader\uff0c\u83b7\u5f97shaderProgram<\/p>\n\n\n\n<p class=\"has-text-align-justify\">3\uff09\u83b7\u53d6Camera\u6570\u636e\uff0c\u751f\u62102D\u7eb9\u7406\u3002\u5982\u679c\u6709\u591a\u4e2a\u6444\u50cf\u5934\uff0c\u9700\u8981\u751f\u6210\u591a\u4e2a\u5bf9\u5e94\u7684\u7eb9\u7406\u3002<\/p>\n\n\n\n<p>4\uff09\u6839\u636ePNG\u5207\u56fe\uff0c\u751f\u6210\u5bf9\u5e94\u76842D\u7eb9\u7406\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">\u4ee5\u4e0a\u5b8c\u6210Render\u524d\u7684\u57fa\u7840\u8bbe\u5b9a\uff0c\u7136\u540e\u6211\u4eec\u8c03\u7528drawFrame\u63a5\u53e3\u6765\u5b9e\u73b0\u5177\u4f53\u7684\u7ed8\u5236\u3002\u8fd9\u91cc\u9762\u4e5f\u53ef\u4ee5\u8fdb\u884c\u7ec6\u5206\uff1a<\/p>\n\n\n\n<p>1\uff09\u901a\u8fc7attachRenderTarget\u63a5\u53e3\u5c06Camera\u6570\u636e\u7ed1\u5b9a\u5230Graphicbuffer\u4e2d\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">2\uff09\u8ba1\u7b97\u9876\u70b9\u5750\u6807\uff0c\u8bbe\u5b9a\u7eb9\u7406\u5750\u6807\uff0c\u8fd9\u91cc\u9762\u53ef\u80fd\u4f1a\u5305\u542b\u4e00\u4e9b\u56fe\u50cf\u65cb\u8f6c\u3001\u7ffb\u8f6c\u3001\u955c\u50cf\u7b49\u64cd\u4f5c\u3002<\/p>\n\n\n\n<p>3\uff09\u66f4\u65b02D\u7eb9\u7406<\/p>\n\n\n\n<p class=\"has-text-align-justify\">4\uff09\u8c03\u7528glFinish\u5c06\u6240\u6709\u7684OpenGL\u6307\u4ee4\u8fdb\u884c\u6267\u884c<\/p>\n\n\n\n<p class=\"has-text-align-justify\">5\uff09\u6700\u540e\u8c03\u7528detachRenderTarget\uff0c\u7ed3\u675f\u6b64\u5e27\u753b\u9762\u7684\u7ed8\u5236<\/p>\n\n\n\n<p>\u4ee5\u4e0a\u5c31\u662fEVS\u5e94\u7528\u4e2d\u6838\u5fc3\u90e8\u5206\u7684\u89e3\u6790\u4e86\uff0c\u5173\u4e8e\u56fe\u50cf\u7ed8\u5236\u8fd9\u5757\u5176\u5b9e\u8fd8\u6709\u5f88\u591a\u77e5\u8bc6\u53ef\u4ee5\u8fdb\u4e00\u6b65\u6316\u6398\uff0c\u4f1a\u6d89\u53ca\u5230\u5927\u91cf\u7684OpenGL ES\u77e5\u8bc6\uff0c\u672c\u7bc7\u535a\u6587\u4e0d\u505a\u8fc7\u591a\u6df1\u5165\uff0c\u611f\u5174\u8da3\u7684\u670b\u53cb\u53ef\u4ee5\u81ea\u884c\u4e86\u89e3\u3002<\/p>\n\n\n\n<p class=\"has-text-align-justify\">\u6700\u540e\u653e\u4e0a\u4e00\u4e2a\u6d41\u7a0b\u56fe\uff0c\u5e2e\u52a9\u5927\u5bb6\u66f4\u597d\u7684\u7406\u89e3\uff1a<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/02\/EvsDrawWorkFlow.svg\" alt=\"\" class=\"wp-image-4368\"\/><\/figure>\n\n\n\n<p><\/p>\n        <div class=\"booster-block booster-reactions-block\">\n            <div class=\"twp-reactions-icons\">\n                \n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-1\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/happy.svg\" alt=\"Happy\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">\n                        Happy                    <\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">4<\/span>\n                        \n                                                <span class=\"twp-react-percent\"><span>100<\/span> %<\/span>\n                                            <\/div>\n                <\/div>\n\n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-2\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/sad.svg\" alt=\"Sad\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">\n                        Sad                    <\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">0<\/span>\n                                                                        <span class=\"twp-react-percent\"><span>0<\/span> %<\/span>\n                                            <\/div>\n                <\/div>\n\n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-3\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/excited.svg\" alt=\"Excited\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">\n                        Excited                    <\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">0<\/span>\n                                                                        <span class=\"twp-react-percent\"><span>0<\/span> %<\/span>\n                                            <\/div>\n                <\/div>\n\n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-6\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/sleepy.svg\" alt=\"Sleepy\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">\n                        Sleepy                    <\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">0<\/span>\n                        \n                                                <span class=\"twp-react-percent\"><span>0<\/span> %<\/span>\n                                            <\/div>\n                <\/div>\n\n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-4\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/angry.svg\" alt=\"Angry\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">Angry<\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">0<\/span>\n                                                                        <span class=\"twp-react-percent\"><span>0<\/span> %<\/span>\n                        \n                    <\/div>\n                <\/div>\n\n                <div class=\"twp-reacts-wrap\">\n                    <a react-data=\"be-react-5\" post-id=\"4335\" class=\"be-face-icons un-reacted\" href=\"javascript:void(0)\">\n                        <img decoding=\"async\" src=\"https:\/\/blog.coderfan.org\/wp-content\/plugins\/booster-extension\/\/assets\/icon\/surprise.svg\" alt=\"Surprise\">\n                    <\/a>\n                    <div class=\"twp-reaction-title\">Surprise<\/div>\n                    <div class=\"twp-count-percent\">\n                                                    <span style=\"display: none;\" class=\"twp-react-count\">0<\/span>\n                                                                        <span class=\"twp-react-percent\"><span>0<\/span> %<\/span>\n                                            <\/div>\n                <\/div>\n\n            <\/div>\n        <\/div>","protected":false},"excerpt":{"rendered":"<p>\u5173\u4e8eEVS APP\u7684\u77e5\u8bc6\u70b9\u8bb2\u89e3\u3002<\/p>","protected":false},"author":1,"featured_media":4483,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_editorskit_title_hidden":false,"_editorskit_reading_time":4,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[18],"tags":[],"class_list":["post-4335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-operating-system"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[]}},"aioseo_notices":[],"featured_image_urls":{"full":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"thumbnail":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-150x150.jpg",150,150,true],"medium":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-300x158.jpg",300,158,true],"medium_large":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"large":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"1536x1536":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"2048x2048":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"trp-custom-language-flag":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-18x9.jpg",18,9,true]},"post_excerpt_stackable":"<p>\u5173\u4e8eEVS APP\u7684\u77e5\u8bc6\u70b9\u8bb2\u89e3\u3002<\/p>\n","category_list":"<a href=\"https:\/\/blog.coderfan.org\/en\/category\/operating-system\" rel=\"category tag\">\u64cd\u4f5c\u7cfb\u7edf<\/a>","author_info":{"name":"FranzKafka95","url":"https:\/\/blog.coderfan.org\/en\/author\/yushenglonely95"},"comments_num":"0 comments","featured_image_urls_v2":{"full":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"thumbnail":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-150x150.jpg",150,150,true],"medium":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-300x158.jpg",300,158,true],"medium_large":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"large":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"1536x1536":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"2048x2048":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android.jpg",512,269,false],"trp-custom-language-flag":["https:\/\/blog.coderfan.org\/wp-content\/uploads\/2023\/04\/android-18x9.jpg",18,9,true]},"post_excerpt_stackable_v2":"<p>\u5173\u4e8eEVS APP\u7684\u77e5\u8bc6\u70b9\u8bb2\u89e3\u3002<\/p>\n","category_list_v2":"<a href=\"https:\/\/blog.coderfan.org\/en\/category\/operating-system\" rel=\"category tag\">\u64cd\u4f5c\u7cfb\u7edf<\/a>","author_info_v2":{"name":"FranzKafka95","url":"https:\/\/blog.coderfan.org\/en\/author\/yushenglonely95"},"comments_num_v2":"0 comments","_links":{"self":[{"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/posts\/4335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/comments?post=4335"}],"version-history":[{"count":26,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/posts\/4335\/revisions"}],"predecessor-version":[{"id":4600,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/posts\/4335\/revisions\/4600"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/media\/4483"}],"wp:attachment":[{"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/media?parent=4335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/categories?post=4335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.coderfan.org\/en\/wp-json\/wp\/v2\/tags?post=4335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}