Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析
Posted Give.Me.Five
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析相关的知识,希望对你有一定的参考价值。
上篇已经分析了CameraService 的初始化过程,之前分析到ICameraService.connectDevice(…), 通过CameraService建立起cameraID 与CameraDevice的联系,那我们继续往下分析, CameraPreview创建的过程:
private void createCameraPreviewSession()
try
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
// This is the output Surface we need to start preview.
//初始化一个surface,当成一个preview的一个buffer数据
Surface surface = new Surface(texture);
// We set up a CaptureRequest.Builder with the output Surface.
mPreviewRequestBuilder
= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
// Here, we create a CameraCaptureSession for camera preview.
//把surface 和 mImageReader的buffer 当成preview的一个surface 的集合
mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
new CameraCaptureSession.StateCallback()
...
public void createCaptureSession(List<Surface> outputs,
CameraCaptureSession.StateCallback callback, Handler handler)
throws CameraAccessException
List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
//将之前的surface集合 转化成OutputConfiguration的集合
for (Surface surface : outputs)
outConfigurations.add(new OutputConfiguration(surface));
//根据OutputConfiguration集合, 再来创建captureSession
createCaptureSessionInternal(null, outConfigurations, callback,
checkAndWrapHandler(handler), /*operatingMode*/ICameraDeviceUser.NORMAL_MODE,
/*sessionParams*/ null);
private void createCaptureSessionInternal(InputConfiguration inputConfig,
List<OutputConfiguration> outputConfigurations,
CameraCaptureSession.StateCallback callback, Executor executor,
int operatingMode, CaptureRequest sessionParams) throws CameraAccessException
synchronized(mInterfaceLock)
checkIfCameraClosedOrInError();
//检查是否是高速模式
boolean isConstrainedHighSpeed =
(operatingMode == ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE);
// TODO: dont block for this
boolean configureSuccess = true;
CameraAccessException pendingException = null;
Surface input = null;
try
//在空闲时,配置stream流
configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
operatingMode, sessionParams);
if (configureSuccess == true && inputConfig != null)
input = mRemoteDevice.getInputSurface();
catch (CameraAccessException e)
configureSuccess = false;
pendingException = e;
input = null;
if (DEBUG)
Log.v(TAG, "createCaptureSession - failed with exception ", e);
// Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
//遍历outputConfigurations中的surface, 然后再添加到surfaces中
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);
// TODO: wait until current session closes, then create the new session
mCurrentSession = newSession;
if (pendingException != null)
throw pendingException;
mSessionStateCallback = mCurrentSession.getDeviceStateCallback();
在createCaptureSessionInternal函数中,在空闲中会创建和配置数据流,同时放入到配置中去,最后再来创建session会话,关键是在configureStreamsChecked时,如何创建和配置流的,我们继续去分析这个函数
public boolean configureStreamsChecked(InputConfiguration inputConfig,
List<OutputConfiguration> outputs, int operatingMode, CaptureRequest sessionParams)
throws CameraAccessException
// Treat a null input the same an empty list
if (outputs == null)
outputs = new ArrayList<OutputConfiguration>();
if (outputs.size() == 0 && inputConfig != null)
throw new IllegalArgumentException("cannot configure an input stream without " +
"any output streams");
checkInputConfiguration(inputConfig);
boolean success = false;
synchronized(mInterfaceLock)
checkIfCameraClosedOrInError();
// Streams to create
HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
// Streams to delete
List<Integer> deleteList = new ArrayList<Integer>();
// Determine which streams need to be created, which to be deleted
for (int i = 0; i < mConfiguredOutputs.size(); ++i)
int streamId = mConfiguredOutputs.keyAt(i);
OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration())
// Always delete the deferred output configuration when the session
// is created, as the deferred output configuration doesn't have unique surface
// related identifies.
deleteList.add(streamId);
else
addSet.remove(outConfig); // Don't create a stream previously created
mDeviceExecutor.execute(mCallOnBusy);
stopRepeating();
try
//当空闲的时候,配置outputconfig
waitUntilIdle();
mRemoteDevice.beginConfigure();
// reconfigure the input stream if the input configuration is different.
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);
// Delete all streams first (to free up HW resources)
for (Integer streamId : deleteList)
mRemoteDevice.deleteStream(streamId);
mConfiguredOutputs.delete(streamId);
//基于新的config创建stream流,然后将stream流放入到ConfigureOutput中
for (OutputConfiguration outConfig : outputs)
if (addSet.contains(outConfig))
int streamId = mRemoteDevice.createStream(outConfig);
mConfiguredOutputs.put(streamId, outConfig);
operatingMode = (operatingMode | (customOpMode << 16));
if (sessionParams != null)
mRemoteDevice.endConfigure(operatingMode, sessionParams.getNativeCopy());
else
mRemoteDevice.endConfigure(operatingMode, null);
success = true;
catch (IllegalArgumentException e)
// OK. camera service can reject stream config if it's not supported by HAL
// This is only the result of a programmer misusing the camera2 api.
Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
return false;
catch (CameraAccessException e)
if (e.getReason() == CameraAccessException.CAMERA_IN_USE)
throw new IllegalStateException("The camera is currently busy." +
" You must wait until the previous operation completes.", e);
throw e;
finally
if (success && outputs.size() > 0)
mDeviceExecutor.execute(mCallOnIdle);
else
// Always return to the 'unconfigured' state if we didn't hit a fatal error
mDeviceExecutor.execute(mCallOnUnconfigured);
return success;
这个函数中会将所有的configs 创建addset 集合,然后将已经包含了重复的config 删掉,最后在空闲时,创建stream流,然后将streamID 和config配置到mConfiguredOutputs中。
分析到这里,CameraDevice 创建createCameraPreviewSession会话就分析完了,也看到创建的surface 绑定到cameraDevice上了。到这里Camera2的接口分析就暂时告一个段落了。
以上是关于Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析的主要内容,如果未能解决你的问题,请参考以下文章
Android Camera 打开预览流程分析--CameraService中的打开流程
Android Camera 打开预览流程分析--打开camera的SDK流程
Android Camera 打开预览流程分析--打开camera的SDK流程
Android Camera 打开预览流程分析--打开camera的SDK流程