想要知道Driver回来的数据是如何显示出来的吗?
这个工作是在哪一层做的?
跟踪代码就可以理清楚这一过程,这里代码版本是Jelly Bean。
CameraHardwareInterface初始化的时候会初始化好window有关的数据
struct camera_preview_window { struct preview_stream_ops nw; void *user; }; struct camera_preview_window mHalPreviewWindow; status_t initialize(hw_module_t *module) { ALOGI("Opening camera %s", mName.string()); int rc = module->methods->open(module, mName.string(), (hw_device_t **)&mDevice); if (rc != OK) { ALOGE("Could not open camera %s: %d", mName.string(), rc); return rc; } initHalPreviewWindow(); return rc; } void initHalPreviewWindow() { mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer; mHalPreviewWindow.nw.lock_buffer = __lock_buffer; mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer; mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer; mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count; mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry; mHalPreviewWindow.nw.set_crop = __set_crop; mHalPreviewWindow.nw.set_timestamp = __set_timestamp; mHalPreviewWindow.nw.set_usage = __set_usage; mHalPreviewWindow.nw.set_swap_interval = __set_swap_interval; mHalPreviewWindow.nw.get_min_undequeued_buffer_count = __get_min_undequeued_buffer_count; } static int __dequeue_buffer(struct preview_stream_ops* w, buffer_handle_t** buffer, int *stride) { int rc; ANativeWindow *a = anw(w); ANativeWindowBuffer* anb; rc = native_window_dequeue_buffer_and_wait(a, &anb); if (!rc) { *buffer = &anb->handle; *stride = anb->stride; } return rc; } static int __enqueue_buffer(struct preview_stream_ops* w, buffer_handle_t* buffer) { ANativeWindow *a = anw(w); return a->queueBuffer(a, container_of(buffer, ANativeWindowBuffer, handle), -1); }
继而在Vendor的HAL当中,这里以TI为例子
/** @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; ///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter if(!window) { if(mDisplayAdapter.get() != NULL) { ///NULL window passed, destroy the display adapter if present CAMHAL_LOGDA("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_LOGDA("NULL ANativeWindow passed to setPreviewWindow"); return NO_ERROR; }else if(mDisplayAdapter.get() == NULL) { // Need to create the display adapter since it has not been created // Create display adapter mDisplayAdapter = new ANativeWindowDisplayAdapter(); ... // 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); ... // Update the display adapter with the new window that is passed from CameraService // 这里的window(ANativeWindowDisplayAdapter::mANativeWindow)就是CameraHardwareInterface::mHalPreviewWindow::nw ret = mDisplayAdapter->setPreviewWindow(window); if(ret!=NO_ERROR) { CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret); } if(mPreviewStartInProgress) { CAMHAL_LOGDA("setPreviewWindow called when preview running"); // Start the preview since the window is now available ret = startPreview(); } } else { // Update the display adapter with the new window that is passed from CameraService ret = mDisplayAdapter->setPreviewWindow(window); if ( (NO_ERROR == ret) && previewEnabled() ) { restartPreview(); } else if (ret == ALREADY_EXISTS) { // ALREADY_EXISTS should be treated as a noop in this case ret = NO_ERROR; } } LOG_FUNCTION_NAME_EXIT; return ret; }
注意看setPreviewWindow之前我加的一行中文注释
在TI的HAL当中有去做包一些adaper出来,实际就是取数据的(比如V4L2CameraAdapter,也就是CameraAdapter),和数据发其他地方(比如ANativeWindowDisplayAdapter,也就是DisplayAdapter)去用的。
在TI的HW当中,有previewThread(位于V4LCameraAdapter当中),previewThread会不断的通过IOCTL从V4L2获取frame
int V4LCameraAdapter::previewThread() { status_t ret = NO_ERROR; int width, height; CameraFrame frame; if (mPreviewing) { int index = 0; char *fp = this->GetFrame(index); uint8_t* ptr = (uint8_t*) mPreviewBufs.keyAt(index); int width, height; uint16_t* dest = (uint16_t*)ptr; uint16_t* src = (uint16_t*) fp; mParams.getPreviewSize(&width, &height); ... mParams.getPreviewSize(&width, &height); frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; frame.mBuffer = ptr; ... ret = sendFrameToSubscribers(&frame); } return ret; } char * V4LCameraAdapter::GetFrame(int &index) { int ret; mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; /* DQ */ ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); if (ret < 0) { CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed"); return NULL; } nDequeued++; index = mVideoInfo->buf.index; return (char *)mVideoInfo->mem[mVideoInfo->buf.index]; } class CameraFrame { public: enum FrameType { PREVIEW_FRAME_SYNC = 0x1, ///SYNC implies that the frame needs to be explicitly returned after consuming in order to be filled by camera again PREVIEW_FRAME = 0x2 , ///Preview frame includes viewfinder and snapshot frames IMAGE_FRAME_SYNC = 0x4, ///Image Frame is the image capture output frame IMAGE_FRAME = 0x8, VIDEO_FRAME_SYNC = 0x10, ///Timestamp will be updated for these frames VIDEO_FRAME = 0x20, FRAME_DATA_SYNC = 0x40, ///Any extra data assosicated with the frame. Always synced with the frame FRAME_DATA= 0x80, RAW_FRAME = 0x100, SNAPSHOT_FRAME = 0x200, ALL_FRAMES = 0xFFFF ///Maximum of 16 frame types supported }; enum FrameQuirks { ENCODE_RAW_YUV422I_TO_JPEG = 0x1 << 0, HAS_EXIF_DATA = 0x1 << 1, }; //default contrustor CameraFrame(): ... { ... } //copy constructor CameraFrame(const CameraFrame &frame) : ... { ... } void *mCookie; void *mCookie2; void *mBuffer; int mFrameType; nsecs_t mTimestamp; unsigned int mWidth, mHeight; uint32_t mOffset; unsigned int mAlignment; int mFd; size_t mLength; unsigned mFrameMask; unsigned int mQuirks; unsigned int mYuv[2]; ///@todo add other member vars like stride etc };
对于ANativeWindowDisplayAdapter,它有给自己配置一个FrameProvider,实际就是会去注册一种callback,当从driver回来数据的时候会去通知对应的callback,当然这个时候还没有真正的去注册
int ANativeWindowDisplayAdapter::setFrameProvider(FrameNotifier *frameProvider) { LOG_FUNCTION_NAME; // Check for NULL pointer if ( !frameProvider ) { CAMHAL_LOGEA("NULL passed for frame provider"); LOG_FUNCTION_NAME_EXIT; return BAD_VALUE; } //Release any previous frame providers if ( NULL != mFrameProvider ) { delete mFrameProvider; } /** Dont do anything here, Just save the pointer for use when display is actually enabled or disabled */ mFrameProvider = new FrameProvider(frameProvider, this, frameCallbackRelay); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; }
并且我们在开始start preview的时候会去注册这个callback,当然同时在start preview的时候我们也会去分配一块buffer,这样driver回来的数据才有地方放,申请buffer如下
CameraHal::allocateBuffer(…) __dequeue_buffer
下面是启动living preview,注册callback
int ANativeWindowDisplayAdapter::enableDisplay(int width, int height, struct timeval *refTime, S3DParameters *s3dParams) { Semaphore sem; TIUTILS::Message msg; LOG_FUNCTION_NAME; if ( mDisplayEnabled ) { CAMHAL_LOGDA("Display is already enabled"); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } #if 0 //TODO: s3d is not part of bringup...will reenable if (s3dParams) mOverlay->set_s3d_params(s3dParams->mode, s3dParams->framePacking, s3dParams->order, s3dParams->subSampling); #endif #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS if ( NULL != refTime ) { Mutex::Autolock lock(mLock); memcpy(&mStandbyToShot, refTime, sizeof(struct timeval)); mMeasureStandby = true; } #endif //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); mDisplayEnabled = true; mPreviewWidth = width; mPreviewHeight = height; CAMHAL_LOGVB("mPreviewWidth = %d mPreviewHeight = %d", mPreviewWidth, mPreviewHeight); LOG_FUNCTION_NAME_EXIT; return NO_ERROR; } int FrameProvider::enableFrameNotification(int32_t frameTypes) { LOG_FUNCTION_NAME; status_t ret = NO_ERROR; ///Enable the frame notification to CameraAdapter (which implements FrameNotifier interface) mFrameNotifier->enableMsgType(frameTypes<<MessageNotifier::FRAME_BIT_FIELD_POSITION , mFrameCallback , NULL , mCookie ); // 把frameCallbackRelay这个callback添加到BaseCameraAdapter::mFrameSubscribers当中 // 详见 preview_stream_ops_t* mANativeWindow; 以及 ANativeWindowDisplayAdapter::PostFrame(...) // __enqueue_buffer // 最终会把数据更新到CameraHardwareInterface的sp<ANativeWindow> mPreviewWindow; // 这样每过来一个frame,也就是去更新我们看到的preview数据 LOG_FUNCTION_NAME_EXIT; return ret; }
见上面代码中嵌的中文注释,这是我加的。
另外displayThread(位于ANativeWindowDisplayAdapter当中),displayThread会听一些从Camera HAL来的消息,然后执行,这个不是很复杂。
也就是说数据是怎么贴到view上去,这是HAL这层做掉的,虽然只是一个调用ANativeWindow的过程!
这只是一个粗糙的过程,再深层细节的我们暂时不研究。