阅读48 返回首页    go 阿里云 go 技术社区[云栖]


Android Camera数据流分析全程记录(overlay方式)

https://blog.chinaunix.net/uid-26215986-id-3573400.html


这里为什么要研究overlay方式呢?android camera需要driver和app层需要有大量数据需要传输,如果使用非overlay方式进行数据从driver到app层的传输,使系统性能受到很到影响,使系统速度变慢,同时会影响功耗等,而在camera preview module时,通常我们是不必要将采集的数据保存下来的,而不像录像module下,需要将数据保存下来,所以overlay方式就是不经过数据回传,直接显示从driver的数据方式,采用这种方式app从无法获取到数据,所以这种方式应用在preview方式下

这里我是针对android4.0版本的,相对android2.x版本的overlay已经发生了很大的变化,想要研究这方面的可以自己去了解一下,这里不再多说了

开始部分我就直接在这里带过了,系统初始打开camera时,调用到app的onCreate方法,这里主要做了一下工作:
1.开始一个openCamera线程打开camera
2.实例化很多的对象,用于camera工作使用
3.实例化surfaceview和surfaceholder,并且填充了其中的surfacechanged,surfacedestoryed和surfacecreated这三个方式
4.开始一个preview线程用于preview过程
这其中3.4是我们这里要关注的重点,上面实例化了这个surfaceview将决定了我们到底是否使用overlay方式
在这里第三遍完成之后,系统会自动执行surfacechanged这个方式,每次显示区域发生改变都会自动调用这个方法,刚开始打开camera时,显示区域从无到有,因此必要这里会想调用到surfacechanged方法
我们就还是看看在这里都做了些什么事情

  1. public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
  2.         // Make sure we have a surface in the holder before proceeding.
  3.         if (holder.getSurface() == null) {
  4.             Log.d(TAG, "holder.getSurface() == null");
  5.             return;
  6.         }

  7.         Log.v(TAG, "surfaceChanged. w=" + w + ". h=" + h);

  8.         // We need to save the holder for later use, even when the mCameraDevice
  9.         // is null. This could happen if onResume() is invoked after this
  10.         // function.
  11.         mSurfaceHolder = holder;

  12.         // The mCameraDevice will be null if it fails to connect to the camera
  13.         // hardware. In this case we will show a dialog and then finish the
  14.         // activity, so it's OK to ignore it.
  15.         if (mCameraDevice == null) return;

  16.         // Sometimes surfaceChanged is called after onPause or before onResume.
  17.         // Ignore it.
  18.         if (mPausing || isFinishing()) return;

  19.         setSurfaceLayout();

  20.         // Set preview display if the surface is being created. Preview was
  21.         // already started. Also restart the preview if display rotation has
  22.         // changed. Sometimes this happens when the device is held in portrait
  23.         // and camera app is opened. Rotation animation takes some time and
  24.         // display rotation in onCreate may not be what we want.
  25.         if (mCameraState == PREVIEW_STOPPED) {//这里表示第一次打开camera时,那么调用startpreview
  26.             startPreview(true);
  27.             startFaceDetection();
  28.         } else {//这里则表示camera已经打开过程中发生的显示变化,比如横屏竖频转换,所以zheli只需要重新设置previewdisplay
  29.             if (Util.getDisplayRotation(this) != mDisplayRotation) {
  30.                 setDisplayOrientation();
  31.             }
  32.             if (holder.isCreating()) {
  33.                 // Set preview display if the surface is being created and preview
  34.                 // was already started. That means preview display was set to null
  35.                 // and we need to set it now.
  36.                 setPreviewDisplay(holder);
  37.             }
  38.         }

  39.         // If first time initialization is not finished, send a message to do
  40.         // it later. We want to finish surfaceChanged as soon as possible to let
  41.         // user see preview first.
  42.         if (!mFirstTimeInitialized) {
  43.             mHandler.sendEmptyMessage(FIRST_TIME_INIT);
  44.         } else {
  45.             initializeSecondTime();
  46.         }

  47.         SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
  48.         CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
  49.         boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
  50.         int displayRotation = Util.getDisplayRotation(this);
  51.         int displayOrientation = Util.getDisplayOrientation(displayRotation, mCameraId);

  52.         mTouchManager.initialize(preview.getHeight() / 3, preview.getHeight() / 3,
  53.                preview, this, mirror, displayOrientation);

  54.     }
从上面代码我们必须知道,在surface发生变化时必须调用setPreviewDisplay,根据之后的学习,在startpreview方式中真正startpreview之前同样要调用setPreviewDisplay,在setPreviewDisplay的方法中完成了很多初始化,也是在这里决定是否使用overlay方式的,我们就先看看startpreview这个方法吧
  1. private void startPreview(boolean updateAll) {
  2.         if (mPausing || isFinishing()) return;

  3.         mFocusManager.resetTouchFocus();

  4.         mCameraDevice.setErrorCallback(mErrorCallback);

  5.         // If we're previewing already, stop the preview first (this will blank
  6.         // the screen).
  7.         if (mCameraState != PREVIEW_STOPPED) stopPreview();

  8.         setPreviewDisplay(mSurfaceHolder);
  9.         setDisplayOrientation();

  10.         if (!mSnapshotOnIdle) {
  11.             // If the focus mode is continuous autofocus, call cancelAutoFocus to
  12.             // resume it because it may have been paused by autoFocus call.
  13.             if (Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
  14.                 mCameraDevice.cancelAutoFocus();
  15.             }
  16.             mFocusManager.setAeAwbLock(false); // Unlock AE and AWB.
  17.         }

  18.         if ( updateAll ) {
  19.             Log.v(TAG, "Updating all parameters!");
  20.             setCameraParameters(UPDATE_PARAM_INITIALIZE | UPDATE_PARAM_ZOOM | UPDATE_PARAM_PREFERENCE);
  21.         } else {
  22.             setCameraParameters(UPDATE_PARAM_MODE);
  23.         }

  24.         //setCameraParameters(UPDATE_PARAM_ALL);

  25.         // Inform the mainthread to go on the UI initialization.
  26.         if (mCameraPreviewThread != null) {
  27.             synchronized (mCameraPreviewThread) {
  28.                 mCameraPreviewThread.notify();
  29.             }
  30.         }

  31.         try {
  32.             Log.v(TAG, "startPreview");
  33.             mCameraDevice.startPreview();
  34.         } catch (Throwable ex) {
  35.             closeCamera();
  36.             throw new RuntimeException("startPreview failed", ex);
  37.         }

  38.         mZoomState = ZOOM_STOPPED;
  39.         setCameraState(IDLE);
  40.         mFocusManager.onPreviewStarted();
  41.         if ( mTempBracketingEnabled ) {
  42.             mFocusManager.setTempBracketingState(FocusManager.TempBracketingStates.ACTIVE);
  43.         }

  44.         if (mSnapshotOnIdle) {
  45.             mHandler.post(mDoSnapRunnable);
  46.         }
  47.     }
上面大家看到了,先调用了setPreviewDisplay,最后调用mCameraDevice.startPreview()开始preview
这里过程如下:app-->frameworks-->JNI-->camera client-->camera service-->hardware interface-->HAL
1.setPreviewDisplay方法调用时在app层最初的传入的参数是surfaceholder结构
2.到了JNI层setPreviewDisplay方法传入的参数已经是surface结构了
3.到了camera service层
    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);
    sp<ANativeWindow> window(surface);
    return setPreviewWindow(binder, window);
    通过上面的转换调用同名不同参数的另外一个方法,到这里调用的参数已经转变为IBinder和ANativeWindow
4.调用hardware interface的setPreviewWindow(window),这里只有一个ANativeWindow类型的参数
5.到了camerahal_module中转站时又发生了变化
,看看下面的定义,参数变为preview_stream_ops 这个类型的结构
    int camera_set_preview_window(struct camera_device * device, struct preview_stream_ops *window)
上面过程参数类型一直在变化,不过从app层一直传到这里,其实是对同一个内存地址的传输,就像张三换了身衣服,但是他还是张三一样
现在我们就直接看看HAL层的实现
  1. /**
  2.    @brief Sets ANativeWindow object.

  3.    Preview buffers provided to CameraHal via this object. DisplayAdapter will be interfacing with it
  4.    to render buffers to display.

  5.    @param[in] window The ANativeWindow object created by Surface flinger
  6.    @return NO_ERROR If the ANativeWindow object passes validation criteria
  7.    @todo Define validation criteria for ANativeWindow object. Define error codes for scenarios

  8.  */
  9. status_t CameraHal::setPreviewWindow(struct preview_stream_ops *window)
  10. {
  11.     status_t ret = NO_ERROR;
  12.     CameraAdapter::BuffersDescriptor desc;

  13.     LOG_FUNCTION_NAME;
  14.     mSetPreviewWindowCalled = true;

  15.    ///If the Camera service passes a null window, we destroy existing window and free the DisplayAdapter
  16.     if(!window)//这种情况下,window是null,表示不采用overlay方式,则不需要新建displayadapter
  17.     {
  18.         if(mDisplayAdapter.get() != NULL)
  19.         {
  20.             ///NULL window passed, destroy the display adapter if present
  21.             CAMHAL_LOGD("NULL window passed, destroying display adapter");
  22.             mDisplayAdapter.clear();
  23.             ///@remarks If there was a window previously existing, we usually expect another valid window to be passed by the client
  24.             ///@remarks so, we will wait until it passes a valid window to begin the preview again
  25.             mSetPreviewWindowCalled = false;
  26.         }
  27.         CAMHAL_LOGD("NULL ANativeWindow passed to setPreviewWindow");
  28.         return NO_ERROR;
  29.     }else if(mDisplayAdapter.get() == NULL)//传入的window不是null,但是还没有未使用overlay方式创建displayadapter,创建displayadapter
  30.     {
  31.         // Need to create the display adapter since it has not been created
  32.         // Create display adapter
  33.         mDisplayAdapter = new ANativeWindowDisplayAdapter();
  34.         ret = NO_ERROR;
  35.         if(!mDisplayAdapter.get() || ((ret=mDisplayAdapter->initialize())!=NO_ERROR))
  36.         {
  37.             if(ret!=NO_ERROR)
  38.             {
  39.                 mDisplayAdapter.clear();
  40.                 CAMHAL_LOGEA("DisplayAdapter initialize failed");
  41.                 LOG_FUNCTION_NAME_EXIT;
  42.                 return ret;
  43.             }
  44.             else
  45.             {
  46.                 CAMHAL_LOGEA("Couldn't create DisplayAdapter");
  47.                 LOG_FUNCTION_NAME_EXIT;
  48.                 return NO_MEMORY;
  49.             }
  50.         }

  51.         // DisplayAdapter needs to know where to get the CameraFrames from inorder to display
  52.         // Since CameraAdapter is the one that provides the frames, set it as the frame provider for DisplayAdapter
  53.         mDisplayAdapter->setFrameProvider(mCameraAdapter);

  54.         // Any dynamic errors that happen during the camera use case has to be propagated back to the application
  55.         // via CAMERA_MSG_ERROR. AppCallbackNotifier is the class that notifies such errors to the application
  56.         // Set it as the error handler for the DisplayAdapter
  57.         mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get());

  58.         // Update the display adapter with the new window that is passed from CameraService
  59.         ret = mDisplayAdapter->setPreviewWindow(window);
  60.         if(ret!=NO_ERROR)
  61.             {
  62.             CAMHAL_LOGEB("DisplayAdapter setPreviewWindow returned error %d", ret);
  63.             }

  64.         if(mPreviewStartInProgress)
  65.         {
  66.             CAMHAL_LOGDA("setPreviewWindow called when preview running");
  67.             // Start the preview since the window is now available
  68.             ret = startPreview();
  69.         }
  70.     } else {//传入的window不是null,并且displaadaper已经创建好,那么这里只需要将新的window与已经创建好的displayadapter关联即可
  71.         // Update the display adapter with the new window that is passed from CameraService
  72.         ret = mDisplayAdapter->setPreviewWindow(window);
  73.         if ( (NO_ERROR == ret) && previewEnabled() ) {
  74.             restartPreview();
  75.         } else if (ret == ALREADY_EXISTS) {
  76.             // ALREADY_EXISTS should be treated as a noop in this case
  77.             ret = NO_ERROR;
  78.         }
  79.     }
  80.     LOG_FUNCTION_NAME_EXIT;

  81.     return ret;

  82. }
这里我们重点看看新建displayadapter的过程:
1.实例化一个ANativeWindowDisplayAdapter对象
2.mDisplayAdapter->initialize()
3.mDisplayAdapter->setFrameProvider(mCameraAdapter)//这一步是关键,之后会遇到的
4.
mDisplayAdapter->setErrorHandler(mAppCallbackNotifier.get())
5.mDisplayAdapter->setPreviewWindow(window);
做完了上面这些步骤之后,就是startpreview了
  1. /**
  2.    @brief Start preview mode.

  3.    @param none
  4.    @return NO_ERROR Camera switched to VF mode
  5.    @todo Update function header with the different errors that are possible

  6.  */
  7. status_t CameraHal::startPreview() {
  8.     LOG_FUNCTION_NAME;

  9.     // When tunneling is enabled during VTC, startPreview happens in 2 steps:
  10.     // When the application sends the command CAMERA_CMD_PREVIEW_INITIALIZATION,
  11.     // cameraPreviewInitialization() is called, which in turn causes the CameraAdapter
  12.     // to move from loaded to idle state. And when the application calls startPreview,
  13.     // the CameraAdapter moves from idle to executing state.
  14.     //
  15.     // If the application calls startPreview() without sending the command
  16.     // CAMERA_CMD_PREVIEW_INITIALIZATION, then the function cameraPreviewInitialization()
  17.     // AND startPreview() are executed. In other words, if the application calls
  18.     // startPreview() without sending the command CAMERA_CMD_PREVIEW_INITIALIZATION,
  19.     // then the CameraAdapter moves from loaded to idle to executing state in one shot.
  20.     status_t ret = cameraPreviewInitialization();

  21.     // The flag mPreviewInitializationDone is set to true at the end of the function
  22.     // cameraPreviewInitialization(). Therefore, if everything goes alright, then the
  23.     // flag will be set. Sometimes, the function cameraPreviewInitialization() may
  24.     // return prematurely if all the resources are not available for starting preview.
  25.     // For example, if the preview window is not set, then it would return NO_ERROR.
  26.     // Under such circumstances, one should return from startPreview as well and should
  27.     // not continue execution. That is why, we check the flag and not the return value.
  28.     if (!mPreviewInitializationDone) return ret;

  29.     // Once startPreview is called, there is no need to continue to remember whether
  30.     // the function cameraPreviewInitialization() was called earlier or not. And so
  31.     // the flag mPreviewInitializationDone is reset here. Plus, this preserves the
  32.     // current behavior of startPreview under the circumstances where the application
  33.     // calls startPreview twice or more.
  34.     mPreviewInitializationDone = false;

  35.     ///Enable the display adapter if present, actual overlay enable happens when we post the buffer
  36.     if(mDisplayAdapter.get() != NULL) {
  37.         CAMHAL_LOGDA("Enabling display");
  38.         int width, height;
  39.         mParameters.getPreviewSize(&width, &height);

  40. #if PPM_INSTRUMENTATION || PPM_INSTRUMENTATION_ABS
  41.         ret = mDisplayAdapter->enableDisplay(width, height, &mStartPreview);
  42. #else
  43.         ret = mDisplayAdapter->enableDisplay(width, height, NULL);
  44. #endif

  45.         if ( ret != NO_ERROR ) {
  46.             CAMHAL_LOGEA("Couldn't enable display");

  47.             // FIXME: At this stage mStateSwitchLock is locked and unlock is supposed to be called
  48.             // only from mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW)
  49.             // below. But this will never happen because of goto error. Thus at next
  50.             // startPreview() call CameraHAL will be deadlocked.
  51.             // Need to revisit mStateSwitch lock, for now just abort the process.
  52.             CAMHAL_ASSERT_X(false,
  53.                 "At this stage mCameraAdapter->mStateSwitchLock is still locked, "
  54.                 "deadlock is guaranteed");

  55.             goto error;
  56.         }

  57.     }

  58.     ///Send START_PREVIEW command to adapter
  59.     CAMHAL_LOGDA("Starting CameraAdapter preview mode");

  60.     ret = mCameraAdapter->sendCommand(CameraAdapter::CAMERA_START_PREVIEW);

  61.     if(ret!=NO_ERROR) {
  62.         CAMHAL_LOGEA("Couldn't start preview w/ CameraAdapter");
  63.         goto error;
  64.     }
  65.     CAMHAL_LOGDA("Started preview");

  66.     mPreviewEnabled = true;
  67.     mPreviewStartInProgress = false;
  68.     return ret;

  69.     error:

  70.         CAMHAL_LOGEA("Performing cleanup after error");

  71.         //Do all the cleanup
  72.         freePreviewBufs();
  73.         mCameraAdapter->sendCommand(CameraAdapter::CAMERA_STOP_PREVIEW);
  74.         if(mDisplayAdapter.get() != NULL) {
  75.             mDisplayAdapter->disableDisplay(false);
  76.         }
  77.         mAppCallbackNotifier->stop();
  78.         mPreviewStartInProgress = false;
  79.         mPreviewEnabled = false;
  80.         LOG_FUNCTION_NAME_EXIT;

  81.         return ret;
  82. }
上面标出的cameraPreviewInitialization()方法也十分关键,之前已经说过,之后如果需要会再做说明
Enable the display adapter if present, actual overlay enable happens when we post the buffer
说明如果display adapter不是null,这里会enable,overlay方式就启动了
我们接着往下看,看看driver获取的数据到底是怎样处理的,startpreview会通过camerahal-->cameraapapter-->V4Lcameradapter
调用到v4l2层的startpreview,下面看看他的具体是实现
  1. status_t V4LCameraAdapter::startPreview()
  2. {
  3.     status_t ret = NO_ERROR;

  4.     LOG_FUNCTION_NAME;
  5.     Mutex::Autolock lock(mPreviewBufsLock);

  6.     if(mPreviewing) {
  7.         ret = BAD_VALUE;
  8.         goto EXIT;
  9.     }

  10.     for (int i = 0; i < mPreviewBufferCountQueueable; i++) {

  11.         mVideoInfo->buf.index = i;
  12.         mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  13.         mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;

  14.         ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);//请求分配内存
  15.         if (ret < 0) {
  16.             CAMHAL_LOGEA("VIDIOC_QBUF Failed");
  17.             goto EXIT;
  18.         }
  19.         nQueued++;
  20.     }

  21.     ret = v4lStartStreaming();

  22.     // Create and start preview thread for receiving buffers from V4L Camera
  23.     if(!mCapturing) {
  24.         mPreviewThread = new PreviewThread(this);//开启PreviewThread
  25.         CAMHAL_LOGDA("Created preview thread");
  26.     }

  27.     //Update the flag to indicate we are previewing
  28.     mPreviewing = true;
  29.     mCapturing = false;

  30. EXIT:
  31.     LOG_FUNCTION_NAME_EXIT;
  32.     return ret;
  33. }
  1. int V4LCameraAdapter::previewThread()
  2. {
  3.     status_t ret = NO_ERROR;
  4.     int width, height;
  5.     CameraFrame frame;
  6.     void *y_uv[2];
  7.     int index = 0;
  8.     int stride = 4096;
  9.     char *fp = NULL;

  10.     mParams.getPreviewSize(&width, &height);

  11.     if (mPreviewing) {

  12.         fp = this->GetFrame(index);
  13.         if(!fp) {
  14.             ret = BAD_VALUE;
  15.             goto EXIT;
  16.         }
  17.         CameraBuffer *buffer = mPreviewBufs.keyAt(index);//获取camerabuffer
  18.         CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);//获取cameraframe
  19.         if (!lframe) {
  20.             ret = BAD_VALUE;
  21.             goto EXIT;
  22.         }

  23.         debugShowFPS();

  24.         if ( mFrameSubscribers.size() == 0 ) {
  25.             ret = BAD_VALUE;
  26.             goto EXIT;
  27.         }
  28.         y_uv[0] = (void*) lframe->mYuv[0];
  29.         //y_uv[1] = (void*) lframe->mYuv[1];
  30.         //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
  31.         convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);//convert the data
  32.         CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );

  33. #ifdef SAVE_RAW_FRAMES
  34.         unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
  35.         //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
  36.         convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
  37.         saveFile( nv12_buff, ((width*height)*3/2) );//if you want to save the data,save it
  38.         free (nv12_buff);
  39. #endif
  40.         //填充frame结构,用于数据处理
  41.         frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
  42.         frame.mBuffer = buffer;
  43.         frame.mLength = width*height*3/2;
  44.         frame.mAlignment = stride;
  45.         frame.mOffset = 0;
  46.         frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
  47.         frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;

  48.         if (mRecording)
  49.         {
  50.             frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
  51.             mFramesWithEncoder++;
  52.         }
  53.     
  54.         //这里是重点,数据回调,或者使用overlay方式显示这里是决定性调用
  55.         ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
  56.         if (ret != NO_ERROR) {
  57.             CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
  58.         } else {
  59.             ret = sendFrameToSubscribers(&frame);
  60.         }
  61.     }
  62. EXIT:

  63.     return ret;
  64. }
现在就开始看看setInitFrameCount方法都做了些什么
  1. int BaseCameraAdapter::setInitFrameRefCount(CameraBuffer * buf, unsigned int mask)
  2. {
  3.   int ret = NO_ERROR;
  4.   unsigned int lmask;

  5.   LOG_FUNCTION_NAME;

  6.   if (buf == NULL)
  7.     {
  8.       return -EINVAL;
  9.     }

  10.   for( lmask = 1; lmask < CameraFrame::ALL_FRAMES; lmask <<= 1){
  11.     if( lmask & mask ){
  12.       switch( lmask ){

  13.       case CameraFrame::IMAGE_FRAME:
  14.         {
  15.           setFrameRefCount(buf, CameraFrame::IMAGE_FRAME, (int) mImageSubscribers.size());
  16.         }
  17.         break;
  18.       case CameraFrame::RAW_FRAME:
  19.         {
  20.           setFrameRefCount(buf, CameraFrame::RAW_FRAME, mRawSubscribers.size());
  21.         }
  22.         break;
  23.       case CameraFrame::PREVIEW_FRAME_SYNC:
  24.         {
  25.           setFrameRefCount(buf, CameraFrame::PREVIEW_FRAME_SYNC, mFrameSubscribers.size());//这里这个mFrameSubscribers对应的key上保存着响应的callback方法
  26.         }
  27.         break;
  28.       case CameraFrame::SNAPSHOT_FRAME:
  29.         {
  30.           setFrameRefCount(buf, CameraFrame::SNAPSHOT_FRAME, mSnapshotSubscribers.size());
  31.         }
  32.         break;
  33.       case CameraFrame::VIDEO_FRAME_SYNC:
  34.         {
  35.           setFrameRefCount(buf,CameraFrame::VIDEO_FRAME_SYNC, mVideoSubscribers.size());
  36.         }
  37.         break;
  38.       case CameraFrame::FRAME_DATA_SYNC:
  39.         {
  40.           setFrameRefCount(buf, CameraFrame::FRAME_DATA_SYNC, mFrameDataSubscribers.size());
  41.         }
  42.         break;
  43.       case CameraFrame::REPROCESS_INPUT_FRAME:
  44.         {
  45.           setFrameRefCount(buf,CameraFrame::REPROCESS_INPUT_FRAME, mVideoInSubscribers.size());
  46.         }
  47.         break;
  48.       default:
  49.         CAMHAL_LOGEB("FRAMETYPE NOT SUPPORTED 0x%x", lmask);
  50.         break;
  51.       }//SWITCH
  52.       mask &= ~lmask;
  53.     }//IF
  54.   }//FOR
  55.   LOG_FUNCTION_NAME_EXIT;
  56.   return ret;
  57. }
上面我标注的部分通过enableMsgType方法实现mFrameSubscribers.add的,经callback添加到对应的key处,算是实现关联,
同样的通过disableMsgType方法实现mFrameSubscribers.removeItem的,具体在哪里调用enableMsgType和disableMsgType之后再给予说明
  1. void BaseCameraAdapter::setFrameRefCount(CameraBuffer * frameBuf, CameraFrame::FrameType frameType, int refCount)
  2. {

  3.     LOG_FUNCTION_NAME;

  4.     switch ( frameType )
  5.         {
  6.         case CameraFrame::IMAGE_FRAME:
  7.         case CameraFrame::RAW_FRAME:
  8.                 {
  9.                 Mutex::Autolock lock(mCaptureBufferLock);
  10.                 mCaptureBuffersAvailable.replaceValueFor(frameBuf, refCount);
  11.                 }
  12.             break;
  13.         case CameraFrame::SNAPSHOT_FRAME:
  14.                 {
  15.                 Mutex::Autolock lock(mSnapshotBufferLock);
  16.                 mSnapshotBuffersAvailable.replaceValueFor( ( unsigned int ) frameBuf, refCount);
  17.                 }
  18.             break;
  19.         case CameraFrame::PREVIEW_FRAME_SYNC:
  20.                 {
  21.                 Mutex::Autolock lock(mPreviewBufferLock)
  22.                 mPreviewBuffersAvailable.replaceValueFor(frameBuf, refCount);//这里我的理解是refCount和frameBuf实现了绑定,即camerabuf保存在mPreviewBuffersAvailable对应的key处
  23.                 }
  24.             break;
  25.         case CameraFrame::FRAME_DATA_SYNC:
  26.                 {
  27.          

    最后更新:2017-04-03 18:52:05

      上一篇:go Android 动态添加控件
      下一篇:go Java中的HashMap和ConcurrentHashMap的并发性能测试