• Android CameraHal NativeWindow相关(一):从CameraHal::setPreviewWindow(struct preview_stream_ops *window)开始


    使用Android框架做Camera,NativeWindow是绕不过去的,但这块对于我来说是个空白。今天的内容是将此部分弄清楚。

    从CamerHal_Module开始,

    /*******************************************************************
     * implementation of camera_device_ops functions
     *******************************************************************/
    
    int camera_set_preview_window(struct camera_device * device,
            struct preview_stream_ops *window)
    {
        int rv = -EINVAL;
        aml_camera_device_t* aml_dev = NULL;
    
        LOGV("%s", __FUNCTION__);
    
        if(!device)
            return rv;
    
        aml_dev = (aml_camera_device_t*) device;
    
        rv = gCameraHals[aml_dev->cameraid]->setPreviewWindow(window);
    
        return rv;
    }

    从CameraService中会将从Surface获得的NativeWindow通过此函数传递下来。CameraHal所有的画图操作都是进行在此window上。

    上面的高亮代码会从之前初始化时得到Hal数组中得到当前Camera所对应的Hal,然后调用此Hal的setPreviewWindow()函数:

    /**
       @brief Sets ANativeWindow object.
    
       Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it
       to render buffers to display.
    
       @param[in] window The ANativeWindow object created by Surface flinger
       @return NO_ERROR If the ANativeWindow object passes validation criteria
       @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios
    
     */
    status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window)
    {
        status_t ret = NO_ERROR;
        CameraAdapter::BuffersDescriptor desc;
    
        LOG_FUNCTION_NAME;
        mSetPreviewWindowCalled = true;// 1-------设置标志,指示此函数已被调用过,在startPreview()函数中做会判断,若为false会调用mCameraAdapter->sendCommand(CameraAdapter::CAMERA_SWITCH_TO_EXECUTING)后返回。此sendcommand暂未被实现。
    
       ///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter
    // window 指针为NULL的话,将会清除掉Display Adapter,并返回。此分支在CameraServise中的disconnect中被调用,用于彻底清除Display Adapter

    //// Release the held ANativeWindow resources.
    //if (mPreviewWindow != 0) {
    //disconnectWindow(mPreviewWindow);
    //mPreviewWindow = 0;
    //mHardware->setPreviewWindow(mPreviewWindow);
    //}
    //mHardware.clear();

    if(!window)
        {
            if(mDisplayAdapter.get() != NULL)
            {
                ///NULL window passed, destroy the display adapter if present
                CAMHAL_LOGEA("NULL window passed, destroying display adapter");
                mDisplayAdapter.clear();
                ///@remarks If there was a window previously existing, we usually expect another valid window to be passed by the client
                ///@remarks so, we will wait until it passes a valid window to begin the preview again
                mSetPreviewWindowCalled = false;
            }
            CAMHAL_LOGEA("NULL ANativeWindow passed to setPreviewWindow");
            return NO_ERROR;
        }else
    //如果window存在,而Display Adapter不存在,需要做很多事情。
    if(mDisplayAdapter.get() == NULL) { // Need to create the display adapter since it has not been created // Create display adapter mDisplayAdapter = new ANativeWindowDisplayAdapter();// leon 2 ret = NO_ERROR; if(!mDisplayAdapter.get() || ((ret=mDisplayAdapter->initialize())!=NO_ERROR))// leon 3 display adapter 初始化 { if(ret!=NO_ERROR) { mDisplayAdapter.clear(); CAMHAL_LOGEA("DisplayAdapter initialize failed"); LOG_FUNCTION_NAME_EXIT; return ret; } else { CAMHAL_LOGEA("Couldn't create DisplayAdapter"); LOG_FUNCTION_NAME_EXIT; return NO_MEMORY; } } // DisplayAdapter needs to know where to get the CameraFrames from inorder to display // Since CameraAdapter is the one that provides the frames, set it as the frame provider for DisplayAdapter mDisplayAdapter->setFrameProvider(mCameraAdapter); // leon 4 设置视频数据的生产者 // Any dynamic errors that happen during the camera use case has to be propagated back to the application // via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application // Set it as the error handler for the DisplayAdapter mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get()); // leon 5 设置错误处理者,这里是使用AppCallbackNotifier // Update the display adapter with the new window that is passed from CameraService ret = mDisplayAdapter->setPreviewWindow(window);// leon 6 向display adpater设置显示窗口 if(ret!=NO_ERROR) { CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); }
    // mPreviewStartInProgress在startPreview()函数中,当window及display adapter为NULL时被设置为true.我的理解是,当startPreview在display adapter未被准备好时被调用,则设置此变量,等到准备好后可直接调用startPreview。
    if(mPreviewStartInProgress)// previewstart正在进行中 { CAMHAL_LOGDA("setPreviewWindow called when preview running"); // Start the preview since the window is now available ret = startPreview(); // leon 7 } }

    // 如果window及Display adapter都存在,则直接返回
    else { /* If mDisplayAdpater is already created. No need to do anything. * We get a surface handle directly now, so we can reconfigure surface * itself in DisplayAdapter if dimensions have changed */ } LOG_FUNCTION_NAME_EXIT; return ret; }

    上述代码段的注释说明:

    Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it to render buffers to display.
    通过此对象获得提供给CameraHal的Preview Buffers。DisplayAdapter将会与之交互,把这些Buffer渲染显示。

    leon 2

      mDisplayAdapter = new ANativeWindowDisplayAdapter();// leon 2

      我们此文的重点是ANativeWindowDisplayAdapter,先看一下类的定义

    /**
     * Display handler class - This class basically handles the buffer posting to display
    // 此类主要是用于处理用于显示的buffers。
    */ class ANativeWindowDisplayAdapter : public DisplayAdapter // leon2.1 继承DisplayAdapter,需要看看这是个什么东西 { public: typedef struct { void *mBuffer; void *mUser; int mOffset; int mWidth; int mHeight; int mWidthStride; int mHeightStride; int mLength; CameraFrame::FrameType mType; } DisplayFrame;
        typedef struct
            {
            void *mBuffer;
            void *mUser;
            int mOffset;
            int mWidth;
            int mHeight;
            int mWidthStride;
            int mHeightStride;
            int mLength;
            CameraFrame::FrameType mType;
            } DisplayFrame;
    CameraFrame::FrameType
    
    
    
    enum DisplayStates
            {
            DISPLAY_INIT = 0,
            DISPLAY_STARTED,
            DISPLAY_STOPPED,
            DISPLAY_EXITED
            };
    
    public:
    
        ANativeWindowDisplayAdapter();
        virtual ~ANativeWindowDisplayAdapter();
    
        ///Initializes the display adapter creates any resources required
        virtual status_t initialize();
    
        virtual int setPreviewWindow(struct preview_stream_ops *window);
        virtual int setFrameProvider(FrameNotifier *frameProvider);
        virtual int setErrorHandler(ErrorNotifier *errorNotifier);
        virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL, S3DParameters *s3dParams = NULL);
        virtual int disableDisplay(bool cancel_buffer = true);
        virtual status_t pauseDisplay(bool pause);
    
    #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
    
        //Used for shot to snapshot measurement
        virtual status_t setSnapshotTimeRef(struct timeval *refTime = NULL);
    
    #endif
    
        virtual int useBuffers(void* bufArr, int num);
        virtual bool supportsExternalBuffering();
    
        //Implementation of inherited interfaces
        virtual void* allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs);
        virtual uint32_t * getOffsets() ;
        virtual int getFd() ;
        virtual int freeBuffer(void* buf);
    
        virtual int maxQueueableBuffers(unsigned int& queueable);
    
        ///Class specific functions
        static void frameCallbackRelay(CameraFrame* caFrame);
        void frameCallback(CameraFrame* caFrame);
    
        void displayThread();
    
        private:
        void destroy();
        bool processHalMsg();
        status_t PostFrame(ANativeWindowDisplayAdapter::DisplayFrame &dispFrame);
        bool handleFrameReturn();
        status_t returnBuffersToWindow();
    
    public:
    
        static const int DISPLAY_TIMEOUT;
        static const int FAILED_DQS_TO_SUSPEND;
    
        class DisplayThread : public Thread
            {
            ANativeWindowDisplayAdapter* mDisplayAdapter;
            MSGUTILS::MessageQueue mDisplayThreadQ;
    
            public:
                DisplayThread(ANativeWindowDisplayAdapter* da)
                : Thread(false), mDisplayAdapter(da) { }
    
            ///Returns a reference to the display message Q for display adapter to post messages
                MSGUTILS::MessageQueue& msgQ()
                    {
                    return mDisplayThreadQ;
                    }
    
                virtual bool threadLoop()
                    {
                    mDisplayAdapter->displayThread();
                    return false;
                    }
    
                enum DisplayThreadCommands
                    {
                    DISPLAY_START,
                    DISPLAY_STOP,
                    DISPLAY_FRAME,
                    DISPLAY_EXIT
                    };
            };
    
        //friend declarations
    friend class DisplayThread;
    
    private:
        int postBuffer(void* displayBuf);
    
    private:
        bool mFirstInit;
        bool mSuspend;
        int mFailedDQs;
        bool mPaused; //Pause state
        preview_stream_ops_t*  mANativeWindow;
        sp<DisplayThread> mDisplayThread;
        FrameProvider *mFrameProvider; ///Pointer to the frame provider interface
        MSGUTILS::MessageQueue mDisplayQ;
        unsigned int mDisplayState;
        ///@todo Have a common class for these members
        mutable Mutex mLock;
        bool mDisplayEnabled;
        int mBufferCount;
        buffer_handle_t** mBufferHandleMap;
        native_handle_t** mGrallocHandleMap;//IMG_native_handle_t** mGrallocHandleMap;//TODO
        uint32_t* mOffsetsMap;
        int mFD;
        KeyedVector<int, int> mFramesWithCameraAdapterMap;
        sp<ErrorNotifier> mErrorNotifier;
    
        uint32_t mFrameWidth;
        uint32_t mFrameHeight;
        uint32_t mPreviewWidth;
        uint32_t mPreviewHeight;
    
        uint32_t mXOff;
        uint32_t mYOff;
    
        const char *mPixelFormat;
    
        uint32_t mNativeWindowPixelFormat;
    
    #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
        //Used for calculating standby to first shot
        struct timeval mStandbyToShot;
        bool mMeasureStandby;
        //Used for shot to snapshot/shot calculation
        struct timeval mStartCapture;
        bool mShotToShot;
    
    #endif
    
    };
    // leon 2.1
    class
    DisplayAdapter : public BufferProvider, public virtual RefBase// 接口类 { public: typedef struct S3DParameters_t { int mode; int framePacking; int order; int subSampling; } S3DParameters; ///Initializes the display adapter creates any resources required virtual int initialize() = 0; virtual int setPreviewWindow(struct preview_stream_ops *window) = 0; virtual int setFrameProvider(FrameNotifier *frameProvider) = 0; virtual int setErrorHandler(ErrorNotifier *errorNotifier) = 0; virtual int enableDisplay(int width, int height, struct timeval *refTime = NULL, S3DParameters *s3dParams = NULL) = 0; virtual int disableDisplay(bool cancel_buffer = true) = 0; //Used for Snapshot review temp. pause virtual int pauseDisplay(bool pause) = 0; #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS //Used for shot to snapshot measurement virtual int setSnapshotTimeRef(struct timeval *refTime = NULL) = 0; #endif virtual int useBuffers(void *bufArr, int num) = 0; virtual bool supportsExternalBuffering() = 0; // Get max queueable buffers display supports // This function should only be called after // allocateBuffer virtual int maxQueueableBuffers(unsigned int& queueable) = 0; };
    /*
      * Interface for providing buffers
      */
    class BufferProvider// 接口类
    {
    public:
        virtual void* allocateBuffer(int width, int height, const char* format, int &bytes, int numBufs) = 0;
    
        //additional methods used for memory mapping
        virtual uint32_t * getOffsets() = 0;
        virtual int getFd() = 0;
    
        virtual int freeBuffer(void* buf) = 0;
    
        virtual ~BufferProvider() {}
    };

    BufferProvider接口被另一个类MemoryManager集成并实现,用于提供不同于Display Adapter的实现方式,先不管,直接看display adapter的代码。
      mDisplayAdapter = new ANativeWindowDisplayAdapter();// leon 2
    new ANativeWindowDisplayAdapter

    构造函数虽长,但也只是进行一些成员变量的初始化

    Leon 3

    if(!mDisplayAdapter.get() || ((ret=mDisplayAdapter->initialize())!=NO_ERROR))// leon 3 display adapter 初始化
    status_t ANativeWindowDisplayAdapter::initialize()
    {
        LOG_FUNCTION_NAME;
    
        ///Create the display thread
        mDisplayThread = new DisplayThread(this); // leon 3.1 新建一个DisplayThread,用于处理需要Preview 数据。
        if ( !mDisplayThread.get() )
        {
            CAMHAL_LOGEA("Couldn't create display thread");
            LOG_FUNCTION_NAME_EXIT;
            return NO_MEMORY;
        }
    
        ///Start the display thread
        status_t ret = mDisplayThread->run("DisplayThread", PRIORITY_URGENT_DISPLAY); // leon 3.2 run
        if ( ret != NO_ERROR )
        {
            CAMHAL_LOGEA("Couldn't run display thread");
            LOG_FUNCTION_NAME_EXIT;
            return ret;
        }
    
        LOG_FUNCTION_NAME_EXIT;
    
        return ret;
    }
     Leon 3.1&3.2
    mDisplayThread = new DisplayThread(this); // leon 3.1 新建一个DisplayThread,用于处理需要Preview 数据。
    此线程类定义在NativewindowDisplayAdapter内部,另外类中有重要的MessageQueue类型成员变量,需要去看一下其实现
        class DisplayThread : public Thread
            {
            ANativeWindowDisplayAdapter* mDisplayAdapter;
            MSGUTILS::MessageQueue mDisplayThreadQ; // 3.2.2 消息队列
    
            public:
                DisplayThread(ANativeWindowDisplayAdapter* da)
                : Thread(false), mDisplayAdapter(da) { } // 3.1 将mDisplayAdapter赋值给类内部的成员变量mDisplayAdapter
    
            ///Returns a reference to the display message Q for display adapter to post messages
                MSGUTILS::MessageQueue& msgQ()
                    {
                    return mDisplayThreadQ;
                    }
    
                virtual bool threadLoop()  // 3.2 run 会运行ANativeWindowDisplayAdapter的displayThread()
                    {
                    mDisplayAdapter->displayThread();// Leon 3.2.1
                    return false;
                    }
    
                enum DisplayThreadCommands
                    {
                    DISPLAY_START,
                    DISPLAY_STOP,
                    DISPLAY_FRAME,
                    DISPLAY_EXIT
                    };
            };
    在run之前,先看一下消息队列MessageQueue的实现。
    Leon 3.2.2 MessageQueue mDisplayThreadQ,使用管道实现的一个消息队列。
    ///Message queue implementation
    class MessageQueue
    {
    public:
    
        MessageQueue();
        ~MessageQueue();
    
        ///Get a message from the queue
        android::status_t get(Message*);
    
        ///Get the input file descriptor of the message queue
        int getInFd();
    
        ///Set the input file descriptor for the message queue
        void setInFd(int fd);
    
        ///Queue a message
        android::status_t put(Message*);
    
        ///Returns if the message queue is empty or not
        bool isEmpty();
    
        void clear();
    
        ///Force whether the message queue has message or not
        void setMsg(bool hasMsg=false);
    
        ///Wait for message in maximum three different queues with a timeout
        static int waitForMsg(MessageQueue *queue1, MessageQueue *queue2=0, MessageQueue *queue3=0, int timeout = 0);
    
        bool hasMsg()
        {
          return mHasMsg;
        }
    
    private:
        int fd_read;
        int fd_write;
        bool mHasMsg;
    
    };
    MessageQueue
    Leon 3.2.1
    mDisplayAdapter->displayThread();// Leon 3.2.1

    void ANativeWindowDisplayAdapter::displayThread()
    {
        bool shouldLive = true;
        int timeout = 0;
        status_t ret;
    
        LOG_FUNCTION_NAME;
    
        while(shouldLive)
        {
        // 从两个消息队列中获取消息。下面会分析两个消息队列都负责什么消息。Leon3.2.1.2 mDisplayThread->msgQ() Leon3.2.1.3 mDisplayQ
    ret
    = MSGUTILS::MessageQueue::waitForMsg(&mDisplayThread->msgQ() // 在3.2.2中定义的线程内部的消息队列mDisplayThreadQ , &mDisplayQ // leon 3.2.1.1 定义在ANativeWindowDisplayAdapter的私有变量中。 , NULL , ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT); if ( !mDisplayThread->msgQ().isEmpty() ) { ///Received a message from CameraHal, process it shouldLive = processHalMsg();// leon 3.2.1.3 mDisplayThreadQ消息队列的处理函数 } else if( !mDisplayQ.isEmpty()) { if ( mDisplayState== ANativeWindowDisplayAdapter::DISPLAY_INIT ) { ///If display adapter is not started, continue continue; } else { MSGUTILS::Message msg; ///Get the dummy msg from the displayQ if(mDisplayQ.get(&msg)!=NO_ERROR) { CAMHAL_LOGEA("Error in getting message from display Q"); continue; } // There is a frame from ANativeWindow for us to dequeue // We dequeue and return the frame back to Camera adapter if(mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED) { handleFrameReturn(); } if (mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_EXITED) { ///we exit the thread even though there are frames still to dequeue. They will be dequeued ///in disableDisplay shouldLive = false; } } } } LOG_FUNCTION_NAME_EXIT; }
    Leon3.2.1.2  mDisplayThread->msgQ()

    mDisplayThread->msgQ().put(&msg)所有的引用都在ANativeWindowDisplayAdapter.cpp中,

    第一处:在析构函数中,用于销毁displayThread。传递的消息命令为DisplayThread::Display_EXIT;会创建一个信号量,并将信号量作为消息的参数传递给消息队列。之后等待应答,应答后,销毁DisplayThread。

    ANativeWindowDisplayAdapter::~ANativeWindowDisplayAdapter()
    {
        Semaphore sem;// 定义一信号量局部变量 。。。
    ///If Display thread exists if(mDisplayThread.get()) { ///Kill the display thread sem.Create(); // 创建信号量,count为0 msg.command = DisplayThread::DISPLAY_EXIT; // 设置传递的消息的命令 // Send the semaphore to signal once the command is completed msg.arg1 = &sem; // 将信号量作为参数传递给mDisplayThread消息队列中 ///Post the message to display thread mDisplayThread->msgQ().put(&msg); ///Wait for the ACK - implies that the thread is now started and waiting for frames sem.Wait();// 等待信号量的应答。 // Exit and cleanup the thread mDisplayThread->requestExitAndWait(); // Delete the display thread mDisplayThread.clear(); } }

    第二处:在enableDisplay,此函数在Hal中的startPreview()函数调用,消息命令是DisplayThread::DISPLAY_START,同样使用信号量,等待displayThread处理完后在执行。在此调用中会实现开启一个非常重要的回调函数,此回调函数会将Camera得到的frame数据post到nativewindow,使之显示出来。而回调函数是的源头在于CameraHal::setPreviewWindow(struct preview_stream_ops *window)----------------->mDisplayAdapter->setFrameProvider(mCameraAdapter);------------------------------>mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay), 而frameCallbackRelay就是被用到的回调函数。

    int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams)
    {
        //Send START_DISPLAY COMMAND to display thread. Display thread will start and then wait for a message
        sem.Create();
        msg.command = DisplayThread::DISPLAY_START;
    
        // Send the semaphore to signal once the command is completed
        msg.arg1 = &sem;
    
        ///Post the message to display thread
        mDisplayThread->msgQ().put(&msg);
    
        ///Wait for the ACK - implies that the thread is now started and waiting for frames
        sem.Wait();
    
        // Register with the frame provider for frames
        mFrameProvider->enableFrameNotification(CameraFrame::PREVIEW_FRAME_SYNC); 
    // 此处会用到mFrameProvider,此变量是CameraAdapter的实例,此语句会实现如下功能:开启CameraAdapter的关于PREVIEW_FRAME_SYNC的通知机制,并将callback函数设置进去,刚刚跟了一下,callback函数为ANativeWindowDisplayAdapter::frameCallbackRelay ,CameraAdapter将Camera获取的数据使用此回调函数传递给DisplayThread。通知来通知去的太复杂了。
    // mFrameProvider 是在Hal SetPreviewWindow()函数中通过mDisplayAdapter->setFrameProvider(mCameraAdapter)函数设置的,其中会通过
    mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay);语句构建FrameProvider,注意其参数frameCallbackRelay,frameCallbackRelay中调用ANativeWindowDisplayAdapter::frameCallback(CameraFrame*){


    void ANativeWindowDisplayAdapter::frameCallback(CameraFrame* caFrame)
    {
    ///Call queueBuffer of overlay in the context of the callback thread
    DisplayFrame df;
    df.mBuffer = caFrame->mBuffer;
    df.mType = (CameraFrame::FrameType) caFrame->mFrameType;
    df.mOffset = caFrame->mOffset;
    df.mWidthStride = caFrame->mAlignment;
    df.mLength = caFrame->mLength;
    df.mWidth = caFrame->mWidth;
    df.mHeight = caFrame->mHeight;
    PostFrame(df);

    } 最终回调函数会调用到PostFrame(df)这个非常重要的函数。将Camera数据Post到displayFrame中。

        mDisplayEnabled = true;
        mPreviewWidth = width;
        mPreviewHeight = height;
        CAMHAL_LOGVB("mPreviewWidth = %d mPreviewHeight = %d", mPreviewWidth, mPreviewHeight);
        LOG_FUNCTION_NAME_EXIT;
        return NO_ERROR;
    }

    第三处,是在disableDisplay中,跟第一处是一样的作用,不过传递的命令是DISPLAY_STOP。disableDisplay被destroy调用,destroy会在析构函数及setPreviewWindow中被调用,后者的作用是停掉现有的window,之后将新的window设置进去。

    回到ANativeWindowDisplayAdapter::displayThread()线程处理函数,看上面的三种类型的消息是如何处理的。

    Leon 3.2.1.3

    shouldLive = processHalMsg();// leon 3.2.1.3 mDisplayThreadQ消息队列的处理函数
    设置DisplayThread的状态mDisplayStat(started stoped exit),还有第四个状态INITED,是在ANATIVEWindowDisplayAdapter的构造函数中被初始化的。之后则会发送ACK给信号量创建者。那么,mDisplayStat会被谁,怎样使用的呢? 查找一下mDisplayStat,大部分是在第二个消息队列中被用到,例外的一个是在PostFrame中用于判断当前的状态(不重要)
    bool ANativeWindowDisplayAdapter::processHalMsg()
    {
        MSGUTILS::Message msg;
    
        LOG_FUNCTION_NAME;
    
    
        mDisplayThread->msgQ().get(&msg);
        bool ret = true, invalidCommand = false;
    
        switch ( msg.command )
        {
            case DisplayThread::DISPLAY_START:
                CAMHAL_LOGDA("Display thread received DISPLAY_START command from Camera HAL");
                mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STARTED;
                break;
            case DisplayThread::DISPLAY_STOP:
                ///@bug There is no API to disable SF without destroying it
                ///@bug Buffers might still be w/ display and will get displayed
                ///@remarks Ideal seqyence should be something like this
                ///mOverlay->setParameter("enabled", false);
                CAMHAL_LOGDA("Display thread received DISPLAY_STOP command from Camera HAL");
                mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_STOPPED;
                break;
            case DisplayThread::DISPLAY_EXIT:
                CAMHAL_LOGDA("Display thread received DISPLAY_EXIT command from Camera HAL.");
                CAMHAL_LOGDA("Stopping display thread...");
                mDisplayState = ANativeWindowDisplayAdapter::DISPLAY_EXITED;
                ///Note that the SF can have pending buffers when we disable the display
                ///This is normal and the expectation is that they may not be displayed.
                ///This is to ensure that the user experience is not impacted
                ret = false;
                break;
            default:
                CAMHAL_LOGEB("Invalid Display Thread Command 0x%x.", msg.command);
                invalidCommand = true;
                break;
        }
    
        ///Signal the semaphore if it is sent as part of the message
        if ( ( msg.arg1 ) && ( !invalidCommand ) )
        {
            CAMHAL_LOGDA("+Signalling display semaphore");
            Semaphore &sem = *((Semaphore*)msg.arg1);
            sem.Signal();
            CAMHAL_LOGDA("-Signalling display semaphore");
        }
    
        LOG_FUNCTION_NAME_EXIT;
        return ret;
    }

    Leon 3.2.1.1 displayThread线程中的第二个消息队列

    &mDisplayQ //  leon 3.2.1.1 定义在ANativeWindowDisplayAdapter的私有变量中。

      SGUTILS::MessageQueue mDisplayQ; //定义在ANativeWindowDisplayAdapter的私有变量中

    搜索一下mDisplayQ.put(&msg),看消息的入口在哪里?有两处,都在PostFrame函数中,上面讲到PostFrame存在于ANativeWindowDisplayAdapter::frameCallback,会被CameraAdapter回调执行,用于推送CameraFrame给Display。

    PostFrame系列函数非常重要,我们会在后面分析,此处先简单看看消息队列的处理。

    mDisplayQ.put(&msg)入口都是在向NativeWindow enqueue buffer后通知displayThread去dequeue buffer。

    再看displayThread得到消息后的处理:

    void ANativeWindowDisplayAdapter::displayThread()
    {
    
    
            ret = MSGUTILS::MessageQueue::waitForMsg(&mDisplayThread->msgQ()
                                                                    ,  &mDisplayQ
                                                                    , NULL
                                                                    , ANativeWindowDisplayAdapter::DISPLAY_TIMEOUT);
    
                if ( mDisplayState== ANativeWindowDisplayAdapter::DISPLAY_INIT )// 当当前状态还是INIT时,直接退出,我们在前面知道,在ANativeWindowDisplayAdapter构造时mDisplayState被赋值为INIT
                {
                    ///If display adapter is not started, continue
                    continue;
    
                }
                else
                {
                    MSGUTILS::Message msg;
                    ///Get the dummy msg from the displayQ
                    if(mDisplayQ.get(&msg)!=NO_ERROR)
                    {
                        CAMHAL_LOGEA("Error in getting message from display Q");
                        continue;
                    }
    
                    // There is a frame from ANativeWindow for us to dequeue
                    // We dequeue and return the frame back to Camera adapter
                    if(mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_STARTED)// 当当前状态为START时,会调用。而START是在ANativeWindowDisplayAdapter::enableDisplay中被调用,而ANativeWindowDisplayAdapter::enableDisplay又是被startPreview调用。
                    {
                        handleFrameReturn();  //  Leon AA 下面会看此函数的功能
                    }
    
                    if (mDisplayState == ANativeWindowDisplayAdapter::DISPLAY_EXITED)
                    {
                        ///we exit the thread even though there are frames still to dequeue. They will be dequeued
                        ///in disableDisplay
                        shouldLive = false;
                    }
        }// 看起来没有STOP的处理?
    }

    Leon AA  看一下handleFrameReturn();  跟上面的想法一样,但需要看一下其内部实现的细节。另开文章去分析此函数及PostFrame。

    bool ANativeWindowDisplayAdapter::handleFrameReturn()
    {
        status_t err;
        buffer_handle_t* buf;
        int i = 0;
        int stride;  // dummy variable to get stride
        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
        Rect bounds;
        void *y_uv[2];
    
        // TODO(XXX): Do we need to keep stride information in camera hal?
    
        LOG_FUNCTION_NAME;
        if ( NULL == mANativeWindow ) {
            return false;
        }
    
        err = mANativeWindow->dequeue_buffer(mANativeWindow, &buf, &stride);
        if (err != 0) {
            CAMHAL_LOGEB("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
    
            if ( ENODEV == err ) {
                CAMHAL_LOGEA("Preview surface abandoned!");
                mANativeWindow = NULL;
            }
    
            return false;
        }
    
        err = mANativeWindow->lock_buffer(mANativeWindow, buf);
        if (err != 0) {
            CAMHAL_LOGEB("lockbuffer failed: %s (%d)", strerror(-err), -err);
    
            if ( ENODEV == err ) {
                CAMHAL_LOGEA("Preview surface abandoned!");
                mANativeWindow = NULL;
            }
    
            return false;
        }
    
        for(i = 0; i < mBufferCount; i++)
        {
            if (mBufferHandleMap[i] == buf)
                break;
        }
    
        // lock buffer before sending to FrameProvider for filling
        bounds.left = 0;
        bounds.top = 0;
        bounds.right = mFrameWidth;
        bounds.bottom = mFrameHeight;
    
        int lock_try_count = 0;
        while (mapper.lock((buffer_handle_t) mGrallocHandleMap[i], CAMHAL_GRALLOC_USAGE, bounds, y_uv) < 0){
            if (++lock_try_count > LOCK_BUFFER_TRIES){
                if ( NULL != mErrorNotifier.get() ){
                    mErrorNotifier->errorNotify(CAMERA_ERROR_UNKNOWN);
                }
                return false;
            }
            CAMHAL_LOGEA("Gralloc Lock FrameReturn Error: Sleeping 15ms");
            usleep(15000);
        }
    
        mFramesWithCameraAdapterMap.add((int) mGrallocHandleMap[i], i);
    
        CAMHAL_LOGVB("handleFrameReturn: found graphic buffer %d of %d", i, mBufferCount-1);
        mFrameProvider->returnFrame( (void*)mGrallocHandleMap[i], CameraFrame::PREVIEW_FRAME_SYNC);
        LOG_FUNCTION_NAME_EXIT;
        return true;
    }

    小结displayThread:

      1、CameraHal::setPreviewWindow  调用ANativeWindowDisplayAdapter的initialize()

      2、status_t ANativeWindowDisplayAdapter::initialize()  的任务是New displayThread并使其运行起来,此时displayThread内部因无消息需要处理,并不会执行任何有用操作,

      3、displayThread中会监听两个消息队列,用于处理CameraHal不同状态下(INIT, START, STOP, EXIT)的不同消息。第一个队列用于改变当前状态,第二个队列根据当前状态对消息进行处理

        主要的处理方法只有一个,在STARTED状态下,在PostFrame函数中,当将Frame enqueue到NativeWindow之后,需要将NativeWindow中已处理完的Buffer dequeue出来。红色高亮的工作就由displayThread中的handleFrameReturn()负责。

     

     OK,  Leon 3:ret=mDisplayAdapter->initialize()部分分析完了,继续Leon 4.

    转到下一篇:     Android CameraHal NativeWindow相关(2)

  • 相关阅读:
    用户故事——老师
    用户故事——学生
    用户故事——管理员
    WebStorm 2018 最新激活码 license server
    vue cli 4.3.1版本脚手架 新人请看系列
    iviewtable表格数据 录音播放下载
    git修改远程仓库地址
    git上传提交个人心得
    layui 数据拆分 重组数据
    日志
  • 原文地址:https://www.cnblogs.com/leino11121/p/3327114.html
Copyright © 2020-2023  润新知