CameraX源码分析

参考链接:Android Camera-CameraX源码分析
如果官网的源码不好下载,推荐一个开源的库:https://github.com/xiandanin/CameraX

一、源码结构

1.文件结构

  • camera-core:Camera核心库,设计架构的实现
  • camera-camera2:Camera2的配置和操作封装
  • camera-view:自定义的 CameraView 组件
  • camera-extensions:Camera的扩展,用于访问设备专属供应商效果(例如散景、HDR 及其他功能)的 API

其中camera-corecamera-camera2是必须使用的库,使用该库,可以轻松地使用Camera2 API的功能

2.camerax结构

主要看其中几个重要属性:
camera-core\src\main\java\androidx\camera\core

private static final CameraX INSTANCE = new CameraX();
final CameraRepository mCameraRepository = new CameraRepository();
private final AtomicBoolean mInitialized = new AtomicBoolean(false);
private final UseCaseGroupRepository mUseCaseGroupRepository = new UseCaseGroupRepository();
private final ErrorHandler mErrorHandler = new ErrorHandler();
private CameraFactory mCameraFactory;
private CameraDeviceSurfaceManager mSurfaceManager;
private UseCaseConfigFactory mDefaultConfigFactory;
private Context mContext;

主要看其中几个主要的属性:

  • CameraRepository:Camera仓库,保存可用 Camera 的列表
  • UseCaseGroupRepository:UseCaseGroupLifecycleController实例仓库,每个UseCaseGroupLifecycleController都与一个LifecycleOwner相关联,该LifecycleOwner调节组中所有用例共享的通用生命周期
    CameraFactory:Camera抽象工厂,Camera2CameraFactory是具体的实现类
    CameraDeviceSurfaceManager:Camera设备与对应数据流管理,具体实现是Camera2DeviceSurfaceManager
    UseCaseConfigFactory:UseCase配置工厂

3.CameraX主要使用UseCase的概念与相机设备进行交互,目前提供的UseCase

  • 预览(Preview)
  • 图片拍摄(ImageCapture)
  • 图片分析(ImageAnalysis)

二、CameraX初始化

1.Camera2Initializer

CameraX初始化方法:init

public static void init(Context context, @NonNull AppConfig appConfig) {
   INSTANCE.initInternal(context, appConfig);
}

init 是通过ContentProvier配置初始化,具体实现类Camera2Initializer

public final class Camera2Initializer extends ContentProvider {
    private static final String TAG = "Camera2Initializer";
 
    @Override
    public boolean onCreate() {
        Log.d(TAG, "CameraX initializing with Camera2 ...");
 
        CameraX.init(getContext(), Camera2AppConfig.create(getContext()));
        return false;
    }
    ...
}

在AndroidMainifest.xml会自动生成provider配置,ContentProvider的OnCreate调用比Applicantion的 onCreate调用更早。

<provider
   android:name="androidx.camera.camera2.impl.Camera2Initializer"
   android:exported="false"
   android:multiprocess="true"
   android:authorities="${applicationId}.camerax-init"
   android:initOrder="100" />

2.Camera2AppConfig

init 方法传入的 AppConfig 的 create:

public static AppConfig create(Context context) {
   // Create the camera factory for creating Camera2 camera objects
   CameraFactory cameraFactory = new Camera2CameraFactory(context);
 
   // Create the DeviceSurfaceManager for Camera2
   CameraDeviceSurfaceManager surfaceManager = new Camera2DeviceSurfaceManager(context);
 
   // Create default configuration factory
   ExtendableUseCaseConfigFactory configFactory = new ExtendableUseCaseConfigFactory();
   configFactory.installDefaultProvider(
            ImageAnalysisConfig.class, new ImageAnalysisConfigProvider(cameraFactory, context));
   configFactory.installDefaultProvider(
            ImageCaptureConfig.class, new ImageCaptureConfigProvider(cameraFactory, context));
   configFactory.installDefaultProvider(
            VideoCaptureConfig.class, new VideoCaptureConfigProvider(cameraFactory, context));
   configFactory.installDefaultProvider(
            PreviewConfig.class, new PreviewConfigProvider(cameraFactory, context));
 
   AppConfig.Builder appConfigBuilder =
            new AppConfig.Builder()
                  .setCameraFactory(cameraFactory)
                  .setDeviceSurfaceManager(surfaceManager)
                  .setUseCaseConfigFactory(configFactory);
 
   return appConfigBuilder.build();
}

通过 AppConfig.Builder 进行构建,CameraX中的默认属性都在这里初始化。后面具体讲到某个 UseCase 的时候,详细分析下具体的ConfigProvider

3.CameraX.initInternal

CameraX真正初始化方法:initInternal

private void initInternal(Context context, AppConfig appConfig) {
   if (mInitialized.getAndSet(true)) {
      return;
   }
 
   mContext = context.getApplicationContext();
   mCameraFactory = appConfig.getCameraFactory(null);
   if (mCameraFactory == null) {
      throw new IllegalStateException(
               "Invalid app configuration provided. Missing CameraFactory.");
   }
 
   mSurfaceManager = appConfig.getDeviceSurfaceManager(null);
   if (mSurfaceManager == null) {
      throw new IllegalStateException(
               "Invalid app configuration provided. Missing CameraDeviceSurfaceManager.");
   }
 
   mDefaultConfigFactory = appConfig.getUseCaseConfigRepository(null);
   if (mDefaultConfigFactory == null) {
      throw new IllegalStateException(
               "Invalid app configuration provided. Missing UseCaseConfigFactory.");
   }
 
   mCameraRepository.init(mCameraFactory);
}

直接从 AppConfig 中获取到具体实例,mCameraFactory对应的实例是Camera2CameraFactory,mCameraRepository.init(mCameraFactory)进行 Camera 相关的初始化

4.CameraRepository.init

public void init(CameraFactory cameraFactory) {
   synchronized (mCamerasLock) {
      try {
            Set<String> camerasList = cameraFactory.getAvailableCameraIds();
            for (String id : camerasList) {
               Log.d(TAG, "Added camera: " + id);
               mCameras.put(id, cameraFactory.getCamera(id));
            }
      ...
   }
}

getAvailableCameraIds获取可用 Camera Id列表,Camera2CameraFactory的getCamera真正初始化Camera

public BaseCamera getCamera(@NonNull String cameraId) {
   Camera camera = new Camera(mCameraManager, cameraId,
            mAvailabilityRegistry.getAvailableCameraCount(), sHandler);
   mAvailabilityRegistry.registerCamera(camera);
   return camera;
}

通过CameraAvailabilityRegistry的registerCamera方法进行Camera注册
到此为止,CameraX 相关属性就初始化完成了

三、bindToLifecycle

从第一个UseCase预览(preview)来讲解CameraX 生命周期过程,以及数据传输流程。
前面一篇文章已经讲解过 CameraX 的使用,其中预览(preivew),会先声明PreviewConfig,通过 config 生成Preivew,preview.setOnPreviewOutputUpdateListener设置监听Camera数据流。这一系列流程能够实现,主要通过CameraX.bindToLifecycle实现
具体流程:

在这里插入图片描述

public static void bindToLifecycle(LifecycleOwner lifecycleOwner, UseCase... useCases) {
   Threads.checkMainThread();
   UseCaseGroupLifecycleController useCaseGroupLifecycleController =
            INSTANCE.getOrCreateUseCaseGroup(lifecycleOwner);
   UseCaseGroup useCaseGroupToBind = useCaseGroupLifecycleController.getUseCaseGroup();
 
   Collection<UseCaseGroupLifecycleController> controllers =
            INSTANCE.mUseCaseGroupRepository.getUseCaseGroups();
   //检查UseCase 只能在一个lifecycle上
   for (UseCase useCase : useCases) {
      for (UseCaseGroupLifecycleController controller : controllers) {
            UseCaseGroup useCaseGroup = controller.getUseCaseGroup();
            if (useCaseGroup.contains(useCase) && useCaseGroup != useCaseGroupToBind) {
               throw new IllegalStateException(
                        String.format(
                              "Use case %s already bound to a different lifecycle.",
                              useCase));
            }
      }
   }
 
   //onBind监听回调
   for (UseCase useCase : useCases) {
      useCase.onBind();
   }
 
   calculateSuggestedResolutions(lifecycleOwner, useCases);
 
   for (UseCase useCase : useCases) {
      useCaseGroupToBind.addUseCase(useCase);
      for (String cameraId : useCase.getAttachedCameraIds()) {
            attach(cameraId, useCase);
      }
   }
 
   useCaseGroupLifecycleController.notifyState();
}

2.UseCaseGroupLifecycleController

创建 UseCaseGroupLifecycleController,UseCaseGroup控制器,通过Lifecycle组件进行 start 和 stop 操作

UseCaseGroupLifecycleController useCaseGroupLifecycleController =
            INSTANCE.getOrCreateUseCaseGroup(lifecycleOwner);
...
private UseCaseGroupLifecycleController getOrCreateUseCaseGroup(LifecycleOwner lifecycleOwner) {
   return mUseCaseGroupRepository.getOrCreateUseCaseGroup(
            lifecycleOwner, new UseCaseGroupRepository.UseCaseGroupSetup() {
               @Override
               public void setup(UseCaseGroup useCaseGroup) {
                  useCaseGroup.setListener(mCameraRepository);
               }
            });
}

通过UseCaseGroupRepository创建UseCaseGroupLifecycleController

UseCaseGroupLifecycleController getOrCreateUseCaseGroup(
            LifecycleOwner lifecycleOwner, UseCaseGroupSetup groupSetup) {
   UseCaseGroupLifecycleController useCaseGroupLifecycleController;
   synchronized (mUseCasesLock) {
      //如果有缓存,则直接返回,否则进行创建
      useCaseGroupLifecycleController = mLifecycleToUseCaseGroupControllerMap.get(
               lifecycleOwner);
      if (useCaseGroupLifecycleController == null) {
            useCaseGroupLifecycleController = createUseCaseGroup(lifecycleOwner);
            groupSetup.setup(useCaseGroupLifecycleController.getUseCaseGroup());
      }
   }
   return useCaseGroupLifecycleController;
}
...
 private UseCaseGroupLifecycleController createUseCaseGroup(LifecycleOwner lifecycleOwner) {
   ...
   // Need to add observer before creating UseCaseGroupLifecycleController to make sure
   // UseCaseGroups can be stopped before the latest active one is started.
   lifecycleOwner.getLifecycle().addObserver(createLifecycleObserver());
   UseCaseGroupLifecycleController useCaseGroupLifecycleController =
            new UseCaseGroupLifecycleController(lifecycleOwner.getLifecycle());
   //创建后,放入 map 缓存
   synchronized (mUseCasesLock) {
      mLifecycleToUseCaseGroupControllerMap.put(lifecycleOwner,
               useCaseGroupLifecycleController);
   }
   return useCaseGroupLifecycleController;
}

创建UseCaseGroupLifecycleController,并增加Lifecycle生命周期控制:

UseCaseGroupLifecycleController(Lifecycle lifecycle) {
   this(lifecycle, new UseCaseGroup());
}
 
/** Wraps an existing {@link UseCaseGroup} so it is controlled by lifecycle transitions. */
UseCaseGroupLifecycleController(Lifecycle lifecycle, UseCaseGroup useCaseGroup) {
   this.mUseCaseGroup = useCaseGroup;
   this.mLifecycle = lifecycle;
   //绑定Lifecycle
   lifecycle.addObserver(this);
}
 
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart(LifecycleOwner lifecycleOwner) {
   synchronized (mUseCaseGroupLock) {
      mUseCaseGroup.start();
   }
}
 
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop(LifecycleOwner lifecycleOwner) {
   synchronized (mUseCaseGroupLock) {
      mUseCaseGroup.stop();
   }
}
 
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy(LifecycleOwner lifecycleOwner) {
   synchronized (mUseCaseGroupLock) {
      mUseCaseGroup.clear();
   }
}

上面的代码,增加了ON_START,ON_STOP,ON_DESTROY的生命周期监听

2.calculateSuggestedResolutions

根据传入的配置,生成各个UseCase的最佳解决方案。后面的代码会以Preview这个 UseCase 展开,其他 UseCase 代码逻辑类似。

private static void calculateSuggestedResolutions(LifecycleOwner lifecycleOwner,
            UseCase... useCases) {
   // There will only one lifecycleOwner active. Therefore, only collect use cases belong to
   // same lifecycleOwner and calculate the suggested resolutions.
   ...
   // Collect new use cases for different camera devices
   for (UseCase useCase : useCases) {
      String cameraId = null;
      try {
            cameraId = getCameraWithCameraDeviceConfig(
                  (CameraDeviceConfig) useCase.getUseCaseConfig());
      } catch (CameraInfoUnavailableException e) {
            throw new IllegalArgumentException(
                  "Unable to get camera id for the camera device config.", e);
      }
   }
   ...
   // Get suggested resolutions and update the use case session configuration
   for (String cameraId : newCameraIdUseCaseMap.keySet()) {
      Map<UseCase, Size> suggestResolutionsMap =
               getSurfaceManager()
                        .getSuggestedResolutions(
                              cameraId,
                              originalCameraIdUseCaseMap.get(cameraId),
                              newCameraIdUseCaseMap.get(cameraId));

      for (UseCase useCase : newCameraIdUseCaseMap.get(cameraId)) {
            Size resolution = suggestResolutionsMap.get(useCase);
            Map<String, Size> suggestedCameraSurfaceResolutionMap = new HashMap<>();
            suggestedCameraSurfaceResolutionMap.put(cameraId, resolution);
            //更新配置
            useCase.updateSuggestedResolution(suggestedCameraSurfaceResolutionMap);
      }
   }
}

每个 UseCase 会去更新对应配置 updateSuggestedResolution->onSuggestedResolutionUpdated

public void updateSuggestedResolution(Map<String, Size> suggestedResolutionMap) {
   Map<String, Size> resolutionMap = onSuggestedResolutionUpdated(suggestedResolutionMap);
   ...
}

onSuggestedResolutionUpdated针对不同的 UseCase 有不同的实现,这里以Preview为例

protected Map<String, Size> onSuggestedResolutionUpdated(
            Map<String, Size> suggestedResolutionMap) {
   //获取前面配置的 config
   PreviewConfig config = (PreviewConfig) getUseCaseConfig();
   String cameraId = getCameraIdUnchecked(config);
   Size resolution = suggestedResolutionMap.get(cameraId);
   ...
   //设置 config
   updateConfigAndOutput(config, resolution);
   return suggestedResolutionMap;
}
...
private void updateConfigAndOutput(PreviewConfig config, Size resolution) {
   String cameraId = getCameraIdUnchecked(config);
   //初始化pipeline
   mSessionConfigBuilder = createPipeline(config, resolution);
   attachToCamera(cameraId, mSessionConfigBuilder.build());
   updateOutput(mSurfaceTextureHolder.getSurfaceTexture(), resolution);
}

3.Preview.createPipeline

创建Preview管道,通过 PreviewConfig 的配置,创建对应的显示Surface和SessionConfig

SessionConfig.Builder createPipeline(PreviewConfig config, Size resolution) {
   Threads.checkMainThread();
   SessionConfig.Builder sessionConfigBuilder = SessionConfig.Builder.createFrom(config);

   final CaptureProcessor captureProcessor = config.getCaptureProcessor(null);
   //扩展的 extensions实现
   if (captureProcessor != null) {
      CaptureStage captureStage = new CaptureStage.DefaultCaptureStage();
      // TODO: To allow user to use an Executor for the processing.
      ...
   } else {
      final ImageInfoProcessor processor = config.getImageInfoProcessor(null);
      if (processor != null) {
            sessionConfigBuilder.addCameraCaptureCallback(new CameraCaptureCallback() {
               @Override
               public void onCaptureCompleted(
                        @NonNull CameraCaptureResult cameraCaptureResult) {
                  super.onCaptureCompleted(cameraCaptureResult);
                  if (processor.process(
                           new CameraCaptureResultImageInfo(cameraCaptureResult))) {
                        notifyUpdated();
                  }
               }
            });
      }
      //默认的 Surface
      CheckedSurfaceTexture checkedSurfaceTexture = new CheckedSurfaceTexture(resolution);

      mSurfaceTextureHolder = checkedSurfaceTexture;
      sessionConfigBuilder.addSurface(checkedSurfaceTexture);
   }
   ...
}


这里就可以看到我们熟悉的味道,在Camera2中 用到的Surface,Session相关配置,后面会用到相关配置。
在CheckedSurfaceTexture中会创建FixedSizeSurfaceTexture用来显示图像。

4.Preview.updateOutput

增加数据的监听

void updateOutput(SurfaceTexture surfaceTexture, Size resolution) {
   PreviewConfig useCaseConfig = (PreviewConfig) getUseCaseConfig();
   ...
   PreviewOutput newOutput =
            PreviewOutput.create(surfaceTexture, resolution, relativeRotation);

   // Only update the output if something has changed
   if (!Objects.equals(mLatestPreviewOutput, newOutput)) {
      SurfaceTexture oldTexture =
               (mLatestPreviewOutput == null)
                        ? null
                        : mLatestPreviewOutput.getSurfaceTexture();
      OnPreviewOutputUpdateListener outputListener = getOnPreviewOutputUpdateListener();
      ...

      if (outputListener != null) {
            mSurfaceDispatched = true;
            updateListener(outputListener, newOutput);
      }
   }
}

根据Preview设置的setOnPreviewOutputUpdateListener,获取到对应的Listener,通过updateListener方法回调数据。

private void updateListener(OnPreviewOutputUpdateListener listener, PreviewOutput output) {
   ...
   mOutputUpdateExecutor.execute(() -> listener.onUpdated(output));
   ...
}

notifyState

调用UseCaseGroupLifecycleController的notifyState,激活 UseCase 状态,在UseCaseGroupLifecycleController中有增加生命周期的监听,在ON_START状态会调用mUseCaseGroup.start方法。

void notifyState() {
   synchronized (mUseCaseGroupLock) {
      if (mLifecycle.getCurrentState().isAtLeast(State.STARTED)) {
            mUseCaseGroup.start();
      }
      for (UseCase useCase : mUseCaseGroup.getUseCases()) {
            useCase.notifyState();
      }
   }
}


UseCaseGroup.start

void start() {
   synchronized (mListenerLock) {
      if (mListener != null) {
            mListener.onGroupActive(this);
      }
      mIsActive = true;
   }
}

启动 start 状态,调用CameraRepository的onGroupActive方法:

Camera2的预览流程

拍照的流程ImageCapture.takePicture

在这里插入图片描述

sendImageCaptureRequest

创建 ImageCaptureRequest,设置cameraId、targetRatio、回调等

private void sendImageCaptureRequest(
      @Nullable Executor listenerExecutor, OnImageCapturedListener listener) {

   String cameraId = getCameraIdUnchecked(mConfig);

   // Get the relative rotation or default to 0 if the camera info is unavailable
   int relativeRotation = 0;
   try {
      CameraInfoInternal cameraInfoInternal = CameraX.getCameraInfo(cameraId);
      relativeRotation =
               cameraInfoInternal.getSensorRotationDegrees(
                        mConfig.getTargetRotation(Surface.ROTATION_0));
   } catch (CameraInfoUnavailableException e) {
      Log.e(TAG, "Unable to retrieve camera sensor orientation.", e);
   }

   Rational targetRatio = mConfig.getTargetAspectRatioCustom(null);
   targetRatio = ImageUtil.rotate(targetRatio, relativeRotation);

   mImageCaptureRequests.offer(
            new ImageCaptureRequest(relativeRotation, targetRatio, listenerExecutor, listener));
   if (mImageCaptureRequests.size() == 1) {
      issueImageCaptureRequests();
   }
}

takePictureInternal

void issueImageCaptureRequests() {
   if (mImageCaptureRequests.isEmpty()) {
      return;
   }
   takePictureInternal();
}
...
//拍照流程
private void takePictureInternal() {
   //自定义 Future 调用链
   FutureChain.from(preTakePicture(state))
      .transformAsync{
         ...
         return ImageCapture.this.issueTakePicture(state);
      })
      .transformAsync{
         ...
         return ImageCapture.this.postTakePicture(state);
      })
      .addCallback(
         ...
         onTakePictureFinish(null);
      )
}

自定义了整个拍照工作流,通过issueTakePicture进行拍照,postTakePicture是拍照成功,释放资源,取消3A。下面重点看下issueTakePicture流程

issueTakePicture

ListenableFuture<Void> issueTakePicture(TakePictureState state) {
   ...
   getCurrentCameraControl().submitCaptureRequests(captureConfigs);
   ...
}

通过CameraControl提交Capture 请求,CameraControl具体实现是Camera2CameraControl。

submitCaptureRequests

public void submitCaptureRequests(@NonNull final List<CaptureConfig> captureConfigs) {
   mExecutor.execute(new Runnable() {
      @Override
      public void run() {
            submitCaptureRequestsInternal(captureConfigs);
      }
   });
}
...
void submitCaptureRequestsInternal(final List<CaptureConfig> captureConfigs) {
   mControlUpdateListener.onCameraControlCaptureRequests(captureConfigs);
   //mControlUpdateListener是Camera 的回调,onCameraControlCaptureRequests 真正实现在 Camera 中
}
//Camera.java
public void onCameraControlUpdateSessionConfig(@NonNull SessionConfig sessionConfig) {
   mCameraControlSessionConfig = sessionConfig;
   updateCaptureSessionConfig();
}
...
private void updateCaptureSessionConfig() {
      ...
         SessionConfig sessionConfig = validatingBuilder.build();
         mCaptureSession.setSessionConfig(sessionConfig);
      ...
   }
}
Camera 获取 Capture的SessionConfig,通过`CaptureSession`进行状态控制

CaptureSession.setSessionConfig

void setSessionConfig(SessionConfig sessionConfig) {
   synchronized (mStateLock) {
      switch (mState) {
            case UNINITIALIZED:
               throw new IllegalStateException(
                        "setSessionConfig() should not be possible in state: " + mState);
            case INITIALIZED:
            case OPENING:
               mSessionConfig = sessionConfig;
               break;
            case OPENED:
               mSessionConfig = sessionConfig;

               if (!mConfiguredSurfaceMap.keySet().containsAll(sessionConfig.getSurfaces())) {
                  Log.e(TAG, "Does not have the proper configured lists");
                  return;
               }

               Log.d(TAG, "Attempting to submit CaptureRequest after setting");
               issueRepeatingCaptureRequests();
               break;
            case CLOSED:
            case RELEASING:
            case RELEASED:
               throw new IllegalStateException(
                        "Session configuration cannot be set on a closed/released session.");
      }
   }
}

在Camera的OPENED状态,则进行拍照流程

拍照流程 issueRepeatingCaptureRequests

void issueRepeatingCaptureRequests() {
   ...
   CameraCaptureSession.CaptureCallback comboCaptureCallback =
                    createCamera2CaptureCallback(
                            captureConfig.getCameraCaptureCallbacks(),
                            mCaptureCallback);

   CameraCaptureSessionCompat.setSingleRepeatingRequest(mCameraCaptureSession,
                    captureRequest, mExecutor, comboCaptureCallback);
   ...
}

CameraCaptureSessionCompat根据 Android 版本有CameraCaptureSessionCompatBaseImpl和CameraCaptureSessionCompatApi28Impl两种实现,最终通过CameraCaptureSession实现真正的拍照。
拍照完成后,通过最开始设置的 Listener 进行回调

ImageCapture.createPipeline

在 Preview 那小节,讲解过 bindToLifecycle 流程,这里的ImageCapture也是一个UseCase。在CameraX中的calculateSuggestedResolutions方法,最终会调用到各个UseCase的onSuggestedResolutionUpdated方法。在ImageCapture的onSuggestedResolutionUpdated方法,通过createPipeline创建了拍照数据的回调


SessionConfig.Builder createPipeline(ImageCaptureConfig config,  Size resolution) {
   ...
   //和 Camera2的流程一致
   mProcessingImageResultThread = new HandlerThread("OnImageAvailableHandlerThread");
   mProcessingImageResultThread.start();
   mProcessingImageResultHandler = new Handler(mProcessingImageResultThread.getLooper());
   ...
   mImageReader.setOnImageAvailableListener(
      new ImageReaderProxy.OnImageAvailableListener() {
         @Override
         public void onImageAvailable(ImageReaderProxy imageReader) {
            ImageProxy image = null;
            try {
                  image = imageReader.acquireLatestImage();
            } catch (IllegalStateException e) {
                  Log.e(TAG, "Failed to acquire latest image.", e);
            } finally {
                  if (image != null) {
                     // Call the head request listener to process the captured image.
                     ImageCaptureRequest imageCaptureRequest;
                     if ((imageCaptureRequest = mImageCaptureRequests.peek()) != null) {
                        SingleCloseImageProxy wrappedImage = new SingleCloseImageProxy(
                                 image);
                        wrappedImage.addOnImageCloseListener(mOnImageCloseListener);
                        //ImageCaptureRequest设置 Listener
                        imageCaptureRequest.dispatchImage(wrappedImage);
                     } else {
                        // Discard the image if we have no requests.
                        image.close();
                     }
                  }
            }
         }
      },
      mProcessingImageResultHandler);
   ...
}

ImageReader设置了 Camera 数据会调用,并通过ImageCaptureRequest的dispatchImage方法进行分发

ImageCaptureRequest.dispatchImage

void dispatchImage(final ImageProxy image) {
   try {
         mListenerExecutor.execute(new Runnable() {
            @Override
            public void run() {
               Size sourceSize = new Size(image.getWidth(), image.getHeight());
               if (ImageUtil.isAspectRatioValid(sourceSize, mTargetRatio)) {
                     image.setCropRect(
                           ImageUtil.computeCropRectFromAspectRatio(sourceSize,
                                    mTargetRatio));
               }
               //真正的回调
               mListener.onCaptureSuccess(image, mRotationDegrees);
            }
         });
   } catch (RejectedExecutionException e) {
         Log.e(TAG, "Unable to post to the supplied executor.");

         // Unable to execute on the supplied executor, close the image.
         image.close();
   }
}

mListener是一个封装Listener,在ImageCapture中实现

Listener

Listener的关系图:

 +-----------------------+
 |                       |
 |ImageCapture.          |
 |OnImageCapturedListener|
 |                       |
 +-----------+-----------+
             |
             |
 +-----------v-----------+      +----------------------+
 |                       |      |                      |
 | ImageSaver.           |      | ImageCapture.        |
 | OnImageSavedListener  +------> OnImageSavedListener |
 |                       |      |                      |
 +-----------------------+      +----------------------+

OnImageCapturedListener的实现,其中通过ImageSaver设置的OnImageSavedListener回调到最上层的OnImageSavedListener

OnImageCapturedListener imageCaptureCallbackWrapper =
   new OnImageCapturedListener() {
      @Override
      public void onCaptureSuccess(ImageProxy image, int rotationDegrees) {
         CameraXExecutors.ioExecutor()
                  .execute(
                           new ImageSaver(
                                 image,
                                 saveLocation,
                                 rotationDegrees,
                                 metadata.isReversedHorizontal,
                                 metadata.isReversedVertical,
                                 metadata.location,
                                 executor,
                                 imageSavedListenerWrapper));
      }
   ...
   };
// ImageSaver是一个 Runnable,主要 run 的实现
final class ImageSaver implements Runnable {
   ...
   @Override
   public void run() {
      ...
      //图像处理
      ...
      if (saveError != null) {
         postError(saveError, errorMessage, exception);
      } else {
         postSuccess();
      }
   }
   ...
   private void postSuccess() {
      mExecutor.execute(new Runnable() {
         @Override
         public void run() {
            //最外层回调
            mListener.onImageSaved(mFile);
         }
      });
   }
}

整个拍照流程和数据回调就讲解完毕了。
通过对 CameraX的 Preview 和 ImageCapture的分析,CameraX对Camera2进行完整的封装,统一参数配置,自动计算Resolution,简化Camera2的开发,并增加了生命周期控制,对外只暴露了简单接口。
使用该库,只需要简单的几行代码就可以实现以前Camera2复杂的操作。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值