Android Camera setRepeatingRequest

发布于:2025-07-26 ⋅ 阅读:(20) ⋅ 点赞:(0)

前情回顾

前面我们我们看了一遍createCaptureSession的过程,知道它的作用是维护会话状态,为后续的捕获请求提供基础,那现在就开始看看setRepeatingRequest,也就是起预览的流程,这个流程是跟配流过程强相关的。

APP 层

既然提到app层,那我们肯定要看下上层如何使用,也就是调用API2的接口的,为了方便描述,还是将完整的打开相机,配流,以及起预览过程代码都写一下,我按顺序摆放了一下,可以直接按顺序看就行,流程一目了然:

    // 重要变量需要注意
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mCaptureSession;
    private CaptureRequest.Builder mPreviewRequestBuilder;
    
    // 打开相机
    private void openCamera() {
        if (mCameraId == null || mCameraManager == null) {
            return;
        }

        try {
            // 检查权限
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                return;
            }

            // 打开相机,传入相机ID、状态回调和后台处理器
            mCameraManager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
            
        } catch (CameraAccessException e) {
            e.printStackTrace();
            runOnUiThread(() -> Toast.makeText(this, "打开相机失败", Toast.LENGTH_SHORT).show());
        }
    }

    // 相机设备状态回调,处理相机打开、关闭、错误等状态,在成功打开回调方法里开始创建捕获会话
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            // 相机成功打开,保存相机设备实例并配置流
            mCameraDevice = camera;
            createCameraCaptureSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            camera.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            camera.close();
            mCameraDevice = null;
            runOnUiThread(() -> Toast.makeText(Camera2PreviewActivity.this,
                    "相机打开失败: " + error, Toast.LENGTH_SHORT).show());
        }
    };

    // 创建相机捕获会话(配流过程)
    private void createCameraCaptureSession() {
        if (mCameraDevice == null || !mTextureView.isAvailable()) {
            return;
        }

        try {
            // 获取TextureView的SurfaceTexture并创建Surface
            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            Surface previewSurface = new Surface(surfaceTexture);

            // 创建预览请求构建器
            mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(
                    CameraDevice.TEMPLATE_PREVIEW);
            // 将Surface作为预览的目标(配流:指定数据输出到哪里)
            mPreviewRequestBuilder.addTarget(previewSurface);

            // 准备输出表面列表(当前只有预览一个流)
            List<Surface> outputSurfaces = new ArrayList<>();
            outputSurfaces.add(previewSurface);

            // 创建相机捕获会话,配置输出流
            mCameraDevice.createCaptureSession(outputSurfaces, mSessionCallback, mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    // 捕获会话状态回调,处理会话创建结果
    private final CameraCaptureSession.StateCallback mSessionCallback =
            new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            // 会话配置成功,开始预览
            mCaptureSession = session;
            startPreview();
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            runOnUiThread(() -> Toast.makeText(Camera2PreviewActivity.this,
                    "预览配置失败", Toast.LENGTH_SHORT).show());
        }
    };
    
    // 启动预览,这也是这篇文章需要说明的对象
    private void startPreview() {
        if (mCameraDevice == null || mCaptureSession == null || mPreviewRequestBuilder == null) {
            return;
        }

        try {
            // 配置自动对焦模式
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            
            // 配置自动曝光模式
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);

            // 发送重复捕获请求以持续预览
            mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                    null, mBackgroundHandler);
            
            runOnUiThread(() -> Toast.makeText(Camera2PreviewActivity.this,
                    "预览已启动", Toast.LENGTH_SHORT).show());

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

到这里应用层的代码实现已经走完了,接下来就是Framework层代码了

Framework

按惯例,我们需要了解一下什么时候回调的onConfigured

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) throws CameraAccessException {
            //让我们回顾一下配流过程,先配流,配流成功返回状态
                try {
                    configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                            operatingMode, sessionParams, createSessionStartTime);
                } catch (CameraAccessException e) {
                }
                // 官方注释引路,说明是在下面代码里面实现了onConfigured回调调用
                // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
                // isConstrainedHighSpeed一般都是false,除非开启特殊慢录模式,这
                //个我们不讨论,但CameraConstrainedHighSpeedCaptureSessionImpl
                //里面也是最终会调用到onConfigured,这里不再赘述,感兴趣的可以自行看下
                if (isConstrainedHighSpeed) {
                    newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
                            callback, executor, this, mDeviceExecutor, configureSuccess,
                            mCharacteristics);
                } else {
                    newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
                            callback, executor, this, mDeviceExecutor, configureSuccess);
                }
            }

可以看到下面是实例化了CameraCaptureSessionImpl,那这里面是怎么调用到onConfigured的呢,接着往下看它的构造函数:
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) {
               //那传入的configureSuccess肯定是true啊,那顺理成章就会回调到onConfigured了
               if (configureSuccess) {
                   mStateCallback.onConfigured(this);
                   if (DEBUG) Log.v(TAG, mIdString + "Created session successfully");
                   mConfigureSuccess = true;
               } else {
                   mStateCallback.onConfigureFailed(this);
                   mClosed = true; // do not fire any other callbacks, do not allow any other work
                   Log.e(TAG, mIdString + "Failed to create capture session; configuration failed");
                    mConfigureSuccess = false;
                }
            }

OK,看到这里就知道何时调用到onConfigured,如何调用到onConfigured,并且知道回调给的参数其实就是CameraCaptureSessionImpl,也就是app层提到的mCaptureSession是CameraCaptureSessionImpl实例, 这里我们可以开始我们的主线任务了,在回调到onConfigured之后,就会调用到关键函数setRepeatingRequest,对应app层代码里面的

   // 发送重复捕获请求以持续预览
   mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(),
                    null, mBackgroundHandler);

那就继续看下面的代码
frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java

    @Override
    public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
            Handler handler) throws CameraAccessException {
        checkRepeatingRequest(request);

        synchronized (mDeviceImpl.mInterfaceLock) {
            checkNotClosed();

            handler = checkHandler(handler, callback);

            if (DEBUG) {
                Log.v(TAG, mIdString + "setRepeatingRequest - request " + request + ", callback " +
                        callback + " handler" + " " + handler);
            }

            return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
                    createCaptureCallbackProxy(handler, callback), mDeviceExecutor));
        }
    }

需要注意的是他有一个请求,预览请求相关变量是CameraDevice.TEMPLATE_PREVIEW,前面app层也展现过,想了解可以回顾一下,那继续以主线跳转往下跟踪

    /**
     * Notify the session that a pending capture sequence has just been queued.
     *
     * <p>During a shutdown/close, the session waits until all pending sessions are finished
     * before taking any further steps to shut down itself.</p>
     *
     * @see #finishPendingSequence
     */
    private int addPendingSequence(int sequenceId) {
        mSequenceDrainer.taskStarted(sequenceId);
        return sequenceId;
    }

到这里咋不按套路出牌了呢,看注释意思是一个待处理的捕获序列刚刚已入队,啥啊,这里我们先放一下,回头看看这具体干啥的,先回头看看上一步是不是漏了什么

            return addPendingSequence(mDeviceImpl.setRepeatingRequest(request,
                    createCaptureCallbackProxy(handler, callback), mDeviceExecutor));

可以看到上一步里面其实传了个看起来像是起预览的操作,只不过是调用mDeviceImpl里面的setRepeatingRequest函数,那我们直接过去看看怎么个事儿

frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java

    public int setRepeatingRequest(CaptureRequest request, CaptureCallback callback,
            Executor executor) throws CameraAccessException {
        List<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
        requestList.add(request);
        return submitCaptureRequest(requestList, callback, executor, /*streaming*/true);
    }

继续

    private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
            Executor executor, boolean repeating) throws CameraAccessException {
                //这里会看请求是不是带了surface的,没带的会执行报错的,所以app层的addTarget()是必要步骤
                // Make sure that there all requests have at least 1 surface; all surfaces are non-null;
                for (CaptureRequest request : requestList) {
                    if (request.getTargets().isEmpty()) {
                        throw new IllegalArgumentException(
                                "Each request must have at least one Surface target");
                    }
		       
                    for (Surface surface : request.getTargets()) {
                        if (surface == null) {
                            throw new IllegalArgumentException("Null Surface targets are not allowed");
                        }
                    }
                }
		        //传入的是true,需要先停止前面的repeating
                if (repeating) {
                    stopRepeating();
                }
                //关键函数,后面继续从这里跟踪起预览过程,这里就开始进入native服务了,不再多解释,
                //不了解的话可以重新跟一下前面的文章,我想早点“下班”了,休假咋都在写文章啊我
                requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
                return requestInfo.getRequestId();
            }

然后就通过binder调用到这里了
frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

binder::Status CameraDeviceClient::submitRequestList(
        const std::vector<hardware::camera2::CaptureRequest>& requests,
        bool streaming,
        /*out*/
        hardware::camera2::utils::SubmitInfo *submitInfo) {
           if (streaming) {
               //预览环节
               err = mDevice->setStreamingRequestList(metadataRequestList, surfaceMapList,
                       &(submitInfo->mLastFrameNumber));
           } else {
               //拍照环节
               err = mDevice->captureList(metadataRequestList, surfaceMapList,
                       &(submitInfo->mLastFrameNumber));
           }
           return res;
}

直接上高速,加速中

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

status_t Camera3Device::setStreamingRequestList(
        const List<const PhysicalCameraSettingsList> &requestsList,
        const std::list<const SurfaceMap> &surfaceMaps, int64_t *lastFrameNumber) {
    ATRACE_CALL();

    return submitRequestsHelper(requestsList, surfaceMaps, /*repeating*/true, lastFrameNumber);
}
status_t Camera3Device::submitRequestsHelper(
        const List<const PhysicalCameraSettingsList> &requests,
        const std::list<const SurfaceMap> &surfaceMaps,
        bool repeating,
        /*out*/
        int64_t *lastFrameNumber) {
             if (repeating) {
                 //预览流程
                 res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber);
             } else {
                 //拍照流程
                 res = mRequestThread->queueRequestList(requestList, lastFrameNumber);
             }
             return res;
        }

继续预览流程

status_t Camera3Device::RequestThread::setRepeatingRequests(
        const RequestList &requests,
        /*out*/
        int64_t *lastFrameNumber) {
    ATRACE_CALL();
    Mutex::Autolock l(mRequestLock);
    if (lastFrameNumber != NULL) {
        *lastFrameNumber = mRepeatingLastFrameNumber;
    }
    mRepeatingRequests.clear();
    mFirstRepeating = true;
    // mRepeatingRequests: 类型为RequestList,预览请求队列,这次请求添加之后,等待后续执行消费
    mRepeatingRequests.insert(mRepeatingRequests.begin(),
            requests.begin(), requests.end());

    unpauseForNewRequests();

    mRepeatingLastFrameNumber = hardware::camera2::ICameraDeviceUser::NO_IN_FLIGHT_REPEATING_FRAMES;
    return OK;
}

所以相当于到这里先告一段落了,现在要去跟踪怎么去消费添加到队列的预览请求
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

bool Camera3Device::RequestThread::threadLoop() {
      //省略n行代码,直接找重点
      submitRequestSuccess = sendRequestsBatch();
      return submitRequestSuccess;      
}

然后看sendRequestsBatch对应实现

bool Camera3Device::RequestThread::sendRequestsBatch() {
    res = mInterface->processBatchCaptureRequests(requests, &numRequestProcessed);
    return true;
}
status_t Camera3Device::HalInterface::processBatchCaptureRequests(
        std::vector<camera_capture_request_t*>& requests,/*out*/uint32_t* numRequestProcessed) {
                err = mHidlSession->processCaptureRequest(captureRequests, cachesToRemove,
                                                  resultCallback);
}

HAL 层

熟悉吧,这是跳转到最终函数
hardware/qcom/camera/msm8998/QCamera2/HAL3/QCamera3HWI.cpp

int QCamera3HardwareInterface::processCaptureRequest(
                    camera3_capture_request_t *request,
                    List<InternalRequest> &internallyRequestedStreams)
{
        if (mRawDumpChannel) {
            rc = mRawDumpChannel->initialize(IS_TYPE_NONE);
            if (rc != NO_ERROR) {
                LOGE("Error: Raw Dump Channel init failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
        }
        if (mHdrPlusRawSrcChannel) {
            rc = mHdrPlusRawSrcChannel->initialize(IS_TYPE_NONE);
            if (rc != NO_ERROR) {
                LOGE("Error: HDR+ RAW Source Channel init failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
        }
        if (mSupportChannel) {
            rc = mSupportChannel->initialize(IS_TYPE_NONE);
            if (rc < 0) {
                LOGE("Support channel initialization failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
        }
        if (mAnalysisChannel) {
            rc = mAnalysisChannel->initialize(IS_TYPE_NONE);
            if (rc < 0) {
                LOGE("Analysis channel initialization failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
        }
        if (mDummyBatchChannel) {
            rc = mDummyBatchChannel->setBatchSize(mBatchSize);
            if (rc < 0) {
                LOGE("mDummyBatchChannel setBatchSize failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
            rc = mDummyBatchChannel->initialize(IS_TYPE_NONE);
            if (rc < 0) {
                LOGE("mDummyBatchChannel initialization failed");
                pthread_mutex_unlock(&mMutex);
                goto error_exit;
            }
        }

        if (mState == CONFIGURED && mChannelHandle) {
            //Then start them.
            LOGH("Start META Channel");
            rc = mMetadataChannel->start();
            if (rc < 0) {
                LOGE("META channel start failed");
                pthread_mutex_unlock(&mMutex);
                return rc;
            }

            if (mAnalysisChannel) {
                rc = mAnalysisChannel->start();
                if (rc < 0) {
                    LOGE("Analysis channel start failed");
                    mMetadataChannel->stop();
                    pthread_mutex_unlock(&mMutex);
                    return rc;
                }
            }

            if (mSupportChannel) {
                rc = mSupportChannel->start();
                if (rc < 0) {
                    LOGE("Support channel start failed");
                    mMetadataChannel->stop();
                    /* Although support and analysis are mutually exclusive today
                       adding it in anycase for future proofing */
                    if (mAnalysisChannel) {
                        mAnalysisChannel->stop();
                    }
                    pthread_mutex_unlock(&mMutex);
                    return rc;
	         }

             for (List<stream_info_t *>::iterator it = mStreamInfo.begin();
                      it != mStreamInfo.end(); it++) {
                    QCamera3Channel *channel = (QCamera3Channel *)(*it)->stream->priv;
                    LOGH("Start Processing Channel mask=%d",
                            channel->getStreamTypeMask());
                    rc = channel->start();  //最终在这里开启预览通道
                    if (rc < 0) {
                        LOGE("channel start failed");
                        pthread_mutex_unlock(&mMutex);
                        return rc;
                    }
             }
        }               
}

说明一下上面开启的几个辅助通道:

分析通道(Analysis Channel,即代码中的 mAnalysisChannel):用于将相机数据传递给上层进行算法分析(如人脸检测、条码识别等),不直接参与屏幕显示。

元数据通道(Metadata Channel,即 mMetadataChannel):专门处理相机的元数据(如曝光时间、ISO、对焦距离等),用于控制和反馈相机参数。

支持通道(Support Channel,mSupportChannel):辅助功能通道,可能用于特定硬件的扩展功能(如多摄像头协同、特殊模式处理等)。

通道的启动思路:先启动控制 / 辅助通道:确保元数据处理、算法分析等基础能力就绪。
再启动数据流通道,在辅助通道就绪后,启动实际的图像数据传输(如预览、拍照),保证数据处理链路完整。

QCamera3RegularChannel,QCamera3PicChannel这些通道存储在 stream->priv 中,每个通道对应一个具体的相机流(如预览流、拍照流),负责处理实际的图像数据传输(如预览画面、照片数据)

收工!

总结

终于算是告一段落了,后面有时间再优化一下,目前先这样,此文仅仅是了解起预览的过程,再后面就是拍照和录制视频流程了,看了前面的几章,我们基本了解相机子系统了。


网站公告

今日签到

点亮在社区的每一天
去签到