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)

原文地址:https://www.cnblogs.com/leino11121/p/3327114.html