使用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;
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
构造函数虽长,但也只是进行一些成员变量的初始化
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; };
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.