Camera数据流分析全程记录(overlay方式)
这里为什么要研究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方法
我们就还是看看在这里都做了些什么事情
- public void surfaceChanged(SurfaceHolder
holder, int format, int w, int h) { - // Make sure we have a surface in the
holder before proceeding. - if (holder.getSurface() == null) {
- Log.d(TAG, "holder.getSurface()
== null"); - return;
- }
- Log.v(TAG, "surfaceChanged.
w=" + w + ". h=" + h); - // We need to save
the holder for later use, even when the mCameraDevice - // is null. This
could happen if onResume() is invoked
after this - // function.
- mSurfaceHolder = holder;
- // The mCameraDevice will be null if it
fails to connect to the camera - // hardware. In this case we
will show a dialog and then finish the - // activity, so
it's OK to ignore it. - if (mCameraDevice == null) return;
- // Sometimes surfaceChanged is called
after onPause or before onResume. - // Ignore it.
- if (mPausing || isFinishing()) return;
- setSurfaceLayout();
- // Set preview
display if the surface is being created. Preview was - // already started. Also
restart the preview if display rotation has - // changed. Sometimes
this happens when the device is held in portrait - // and camera
app is opened. Rotation animation takes some time and - // display rotation in onCreate
may not be what we want. - if (mCameraState == PREVIEW_STOPPED) {//这里表示第一次打开camera时,那么调用startpreview
- startPreview(true);
- startFaceDetection();
- } else {//这里则表示camera已经打开过程中发生的显示变化,比如横屏竖频转换,所以zheli只需要重新设置previewdisplay
- if (Util.getDisplayRotation(this) != mDisplayRotation) {
- setDisplayOrientation();
- }
- if (holder.isCreating()) {
- // Set preview
display if the surface is being created and preview - // was already started. That
means preview display was set to null - // and we
need to set it now. - setPreviewDisplay(holder);
- }
- }
- // If first time initialization is not finished, send
a message to do - // it later. We
want to finish surfaceChanged as soon as possible to let - // user see preview first.
- if (!mFirstTimeInitialized) {
- mHandler.sendEmptyMessage(FIRST_TIME_INIT);
- } else {
- initializeSecondTime();
- }
- SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
- CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
- boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
- int displayRotation = Util.getDisplayRotation(this);
- int displayOrientation = Util.getDisplayOrientation(displayRotation, mCameraId);
- mTouchManager.initialize(preview.getHeight() / 3, preview.getHeight() / 3,
- preview, this, mirror, displayOrientation);
- }
从上面代码我们必须知道,在surface发生变化时必须调用setPreviewDisplay,根据之后的学习,在startpreview方式中真正startpreview之前同样要调用setPreviewDisplay,在setPreviewDisplay的方法中完成了很多初始化,也是在这里决定是否使用overlay方式的,我们就先看看startpreview这个方法吧
- private void startPreview(boolean
updateAll) { - if (mPausing || isFinishing()) return;
- mFocusManager.resetTouchFocus();
- mCameraDevice.setErrorCallback(mErrorCallback);
- // If we're
previewing already, stop the preview first (this will blank - // the screen).
- if (mCameraState != PREVIEW_STOPPED) stopPreview();
- setPreviewDisplay(mSurfaceHolder);
- setDisplayOrientation();
- if (!mSnapshotOnIdle) {
- // If the
focus mode is continuous autofocus, call cancelAutoFocus to - // resume it
because it may have been paused by autoFocus call. - if (Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) {
- mCameraDevice.cancelAutoFocus();
- }
- mFocusManager.setAeAwbLock(false); // Unlock
AE and AWB. - }
- if ( updateAll ) {
- Log.v(TAG, "Updating
all parameters!"); - setCameraParameters(UPDATE_PARAM_INITIALIZE | UPDATE_PARAM_ZOOM | UPDATE_PARAM_PREFERENCE);
- } else {
- setCameraParameters(UPDATE_PARAM_MODE);
- }
- //setCameraParameters(UPDATE_PARAM_ALL);
- // Inform the mainthread to go on the
UI initialization. - if (mCameraPreviewThread != null) {
- synchronized (mCameraPreviewThread) {
- mCameraPreviewThread.notify();
- }
- }
- try {
- Log.v(TAG, "startPreview");
- mCameraDevice.startPreview();
- } catch (Throwable ex) {
- closeCamera();
- throw new RuntimeException("startPreview failed", ex);
- }
- mZoomState = ZOOM_STOPPED;
- setCameraState(IDLE);
- mFocusManager.onPreviewStarted();
- if ( mTempBracketingEnabled ) {
- mFocusManager.setTempBracketingState(FocusManager.TempBracketingStates.ACTIVE);
- }
- if (mSnapshotOnIdle) {
- mHandler.post(mDoSnapRunnable);
- }
- }
上面大家看到了,先调用了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层的实现
- /**
- @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)//这种情况下,window是null,表示不采用overlay方式,则不需要新建displayadapter
- {
- if(mDisplayAdapter.get() != NULL)
- {
- ///NULL window passed, destroy
the display adapter if present - CAMHAL_LOGD("NULL window passed, destroying display adapter");
- mDisplayAdapter.clear();
- ///@remarks If there
was a window previously existing, we usually expe