Android P之Camera HAL3流程分析(2)

我们使用TextureView显示相机预览数据,Camera2的预览和拍照数据都是使用CameraCaptureSession会话来请求的
    private void startPreview() {
        SurfaceTexture mSurfaceTexture = mTextureView.getSurfaceTexture();
        mSurfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        //通过view创建surface对象
        Surface previewSurface = new Surface(mSurfaceTexture);
        try {
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            //绑定请求和surface
            mCaptureRequestBuilder.addTarget(previewSurface);
            //预览数据会同时输出到previewSurface和mImageReader
            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()), new
                                                                            CameraCaptureSession.StateCallback()
{
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        //创建请求
                        mCaptureRequest = mCaptureRequestBuilder.build();
                        //保存相机会话对象
                        mCameraCaptureSession = session;
                        //开始预览
                        mCameraCaptureSession.setRepeatingRequest(mCaptureRequest, null, mCameraHandler);
                    }
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, mCameraHandler);
        }
    }

createCaptureSession阶段

当成功打开相机后,会通过CameraDevice.StateCallback回调接口的onOpened(@NonNull CameraDevice camera)方法返回一个CameraDevice对象给我们应用层,而这个CameraDevice对象真正是一个CameraDeviceImpl,那么接下来的createCaptureSession就是调用它来实现的。
frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
    public void createCaptureSession(List<Surface> outputs,
            CameraCaptureSession.StateCallback callback, Handler handler) {
        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
        for (Surface surface : outputs) {
            outConfigurations.add(new OutputConfiguration(surface));
        }
        createCaptureSessionInternal(null, outConfigurations, callback,
                checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
                /*sessionParams*/ null);
    }

这里我们来看一下该方法的几个参数:

第一个参数是一个范型为Surface的List,这里的Surface就是我们用来创建流的,一般如果没有特殊的要求,那我们只需要下两个Surface,一个提供预览,一个提供拍照。
预览的Surface就是相机预览区域,buffer轮转时,预览区的buffer就是要从这个预览Surface当中获取的,这个Surface一定要正确,否则就会导致session创建失败,预览区就会黑屏了,我们在平时的工作中经常碰到这样的情况;
而至于拍照Surface,我们一般使用ImageReader对象来获取,ImageReader是系统提供的一个类,它的创建过程已经为我们创建好了一个Surface,我们直接使用它来当作拍照Surface,当拍照成功后,我们就可以从ImageReader.OnImageAvailableListener内部类的onImageAvailable回调方法中获取到一个ImageReader对象,再调用getPlanes()获取到Plane数组,一般取第一个Plane,继续调用getBuffer()就可以获取到拍摄的照片的byte数组了。

第二个参数callback的类型为CameraCaptureSession.java类的内部类StateCallback,和openCamera一样,当session创建成功后,framework也会通过这个回调接口的onConfigured(@NonNull CameraCaptureSession session)方法返回一个CameraCaptureSession对象给我们,而真正的实现是一个CameraCaptureSessionImpl对象,我们可以使用它来作很多的工作,比如断开session连接调用abortCaptures();拍照调用capture()方法;下预览调用setRepeatingRequest;停预览调用stopRepeating(),这里的设计和openCamera是完全一样的。

第三个参数Handler的作用和openCamera也一样,还是为了保证线程不发生切换,我们在应用进程的哪个工作线程中执行createCaptureSession,那么framework回调我们时,也会通过这个handler把回调消息发送到当前handler线程的Looper循环上。

好了,参数分析完了,我们继续往下看代码,它实际就是调用createCaptureSessionInternal方法进一步处理的,这里的会把我们传入的surface列表进行一下转换,转换为OutputConfiguration对象,调用createCaptureSessionInternal方法时的第一个参数inputConfig一般为空,我们只关注outputConfig。

frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
    private void createCaptureSessionInternal(InputConfiguration inputConfig,
            List<OutputConfiguration> outputConfigurations,
            CameraCaptureSession.StateCallback callback, Executor executor,
            int operatingMode, CaptureRequest sessionParams) {
        synchronized(mInterfaceLock) {
            boolean isConstrainedHighSpeed =
                    (operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
            mCurrentSession.replaceSessionClose();
            boolean configureSuccess = true;
            Surface input = null;
            configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                    operatingMode, sessionParams);

            // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
            CameraCaptureSessionCore newSession = null;
            if (isConstrainedHighSpeed) {
                ArrayList<Surface> surfaces = new ArrayList<>(outputConfigurations.size());
                for (OutputConfiguration outConfig : outputConfigurations) {
                    surfaces.add(outConfig.getSurface());
                }
                StreamConfigurationMap config =
                    getCharacteristics().get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                SurfaceUtils.checkConstrainedHighSpeedSurfaces(surfaces, /*fpsRange*/null, config);

                newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
                        callback, executor, this, mDeviceExecutor, configureSuccess,
                        mCharacteristics);
            } else {
                newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
                        callback, executor, this, mDeviceExecutor, configureSuccess);
            }
            mCurrentSession = newSession;
            mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
        }
    }

这个方法的作用就是配置surface了。该方法中最重要的就是configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations, operatingMode)这句了,它会执行surface配置,如果配置成功,则configureSuccess值为true,否则为false,接下来会创建session的实现类对象,一般是执行else分支,创建CameraCaptureSessionImpl对象
-----------------------------------------------------------------------------------------------------------------------------------

CameraCaptureSessionImpl的实现
frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
    CameraCaptureSessionImpl(int id, Surface input,
            CameraCaptureSession.StateCallback callback, Executor stateExecutor,
            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
            Executor deviceStateExecutor, boolean configureSuccess) {
        mInput = input;
        mStateExecutor = stateExecutor;
        mStateCallback = createUserStateCallbackProxy(mStateExecutor, callback);//创建回调函数的代理对象

        mDeviceExecutor = deviceStateExecutor;
        mDeviceImpl = deviceImpl;

        if (configureSuccess) {
            mStateCallback.onConfigured(this);//回调函数
            mConfigureSuccess = true;
        }
    }
    private StateCallback createUserStateCallbackProxy(Executor executor, StateCallback callback) {
        return new CallbackProxies.SessionStateCallbackProxy(executor, callback);
    }
frameworks/base/core/java/android/hardware/camera2/impl/CallbackProxies.java
public class CallbackProxies {
    public static class SessionStateCallbackProxy
            extends CameraCaptureSession.StateCallback {
        public SessionStateCallbackProxy(Executor executor,
                CameraCaptureSession.StateCallback callback) {
            mExecutor = executor;
            mCallback = callback;
        }
        public void onConfigured(CameraCaptureSession session) {
            final long ident = Binder.clearCallingIdentity();
            mExecutor.execute(() -> mCallback.onConfigured(session));//将session通过回调函数传递给应用
        }
    }
}
通过以上流程,上层应用可以成功获得CameraCaptureSession,后续就可以调用CameraCaptureSession进行拍照或者预览了。
-----------------------------------------------------------------------------------------------------------------------------------

configureStreamsChecked的实现
frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
    public boolean configureStreamsChecked(InputConfiguration inputConfig,
            List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams) {
        checkInputConfiguration(inputConfig);//当前inputConfig为null,所以这部分不执行
        synchronized(mInterfaceLock) {
            //检查当前缓存的输出流数据列表,如果当前的输出流信息已经在列表中,则不必要重新创建流,如果没有则需要创建流

            //要创建输出流的集合列表
            HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
            //要删除的streamId列表,保证当前mConfiguredOutputs列表中的输出流数据是最新可用的
            List<Integer> deleteList = new ArrayList<Integer>();
            //创建输出流,mConfiguredOutputs是内存中的输出流缓存列表,会保存输出流streamId和输出流
            for (int i = 0; i < mConfiguredOutputs.size(); ++i) {
                int streamId = mConfiguredOutputs.keyAt(i);
                OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
                if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
                    deleteList.add(streamId);
                } else {
                    addSet.remove(outConfig);
                }
            }

            mDeviceExecutor.execute(mCallOnBusy);//表示接下来要开始配置surface,处理繁忙状态了
            stopRepeating();//停预览

            try {
                mRemoteDevice.beginConfigure();//通知CameraServer进程中的binder服务端对象,开始配置
                InputConfiguration currentInputConfig = mConfiguredInput.getValue();
                if (inputConfig != currentInputConfig &&
                        (inputConfig == null || !inputConfig.equals(currentInputConfig))) {
                    if (currentInputConfig != null) {
                        mRemoteDevice.deleteStream(mConfiguredInput.getKey());
                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
                                REQUEST_ID_NONE, null);
                    }
                    if (inputConfig != null) {
                        int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
                                inputConfig.getHeight(), inputConfig.getFormat());
                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
                                streamId, inputConfig);
                    }
                }
                //删除过期输出流
                for (Integer streamId : deleteList) {
                    mRemoteDevice.deleteStream(streamId);
                    mConfiguredOutputs.delete(streamId);
                }

                for (OutputConfiguration outConfig : outputs) {//配置surface列表
                    if (addSet.contains(outConfig)) {
                        int streamId = mRemoteDevice.createStream(outConfig);
                        mConfiguredOutputs.put(streamId, outConfig);
                    }
                }

                if (sessionParams != null) {
                    mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
                } else {
                    mRemoteDevice.endConfigure(operatingMode, null);//通知CameraDeviceClient结束配置
                }
                success = true;
            } finally {
                if (success && outputs.size() > 0) {
                    mDeviceExecutor.execute(mCallOnIdle);
                } else {
                    mDeviceExecutor.execute(mCallOnUnconfigured);
                }
            }
        }
        return success;
    }
        下面这张图详细列出配置输入输出流函数中执行的主要步骤,由于当前的inputConfig为null,

  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值