首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Camera2 API:在提交请求后4-5秒拍摄图片。

Camera2 API:在提交请求后4-5秒拍摄图片。
EN

Stack Overflow用户
提问于 2019-01-28 12:09:14
回答 1查看 188关注 0票数 0

目标很简单:只需使用前端相机拍摄一张照片即可。图片应固定在照片请求发送的时刻。预览甚至不需要,因此CameraSession是使用来自ImageReader的单个表面实例化的。但问题是,在一些设备上,图片是只在4-5秒后捕捉到的。以下是一些日志:

照片是在13时47分29.049索取的。 在13时47分29.062被要求逮捕 文件被写入,在13:47:33.313将文件发送到通道。 照片档案于13:47:33.339收到。 照片是在13时47分39.073索取的。 在13时47分39.074被要求逮捕 文件被写入,在13:47:43.199将文件发送到通道。 照片档案于13:47:43.215收到。

问题是,这张照片是在4秒后捕捉到的,自动对焦功能不受支持(在小米MI-5上测试)。如何在捕获之前消除如此长的延迟或执行焦点锁定?或者这里可能有另一个解决方案来消除这个问题?

值得一提的是,ASUS的平板日志:

照片是在07:07:03.443索取的。 在07:07:03.454被要求逮捕 文件被写入,并在07:07:03.907将文件发送到频道。 照片档案在07:07:03.944收到。 照片是在07:07:08.449索取的。 在07:07:08.449被要求逮捕 文件被写入,并在07:07:08.635将文件发送到频道。 照片档案在07:07:08.651收到。

以下是代码:

ViewModel:

代码语言:javascript
复制
private fun makePhoto() {
    GlobalScope.launch(Main) {
        Log.i("Photo", "Photo was requested at ${LocalTime.now()}")
        val picture: File = camera.makePhoto()
        Log.i("Photo", "Photo file was received at ${LocalTime.now()}")
        //process the file somehow
    }
}

PhotoCamera:

代码语言:javascript
复制
//the method is called in onStart of an Activity or Fragment instance
override suspend fun open() {
    val surfaces = listOf(outputSurface) //surface of an ImageReader instance, comes into object's constructor
    cameraDevice =
        suspendCoroutine { cameraManager.openCamera(specification.id, SuspendingCameraStateCallback(it), handler) } //callback just resumes the coroutine with CameraDevice when onOpened method was called.
    session = suspendCoroutine { cameraDevice.createCaptureSession(surfaces, SuspendSessionCallback(it), handler) } //same, just resumes the continuation with the session that comes into onConfigured method
}

override suspend fun makePhoto(): File {
    return suspendCoroutine {
        session.apply {
            stopRepeating()
            abortCaptures()
            Log.i("Photo", "Capture was requested on ${LocalTime.now()}")
            capture(createCaptureRequest(outputSurface), captureAwaitFactory.createListener(it), handler)
        }
    }
}

private fun createCaptureRequest(target: Surface): CaptureRequest {
    val requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
    requestBuilder.addTarget(target)
    requestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO)
    requestBuilder.set(CaptureRequest.JPEG_ORIENTATION, orientation.rotation)
    return requestBuilder.build()
}

使用ImageReader附加的setOnImageAvailableListener监听器代码:

代码语言:javascript
复制
override fun onImageAvailable(reader: ImageReader) {
    reader.acquireLatestImage().use { image: Image ->
        val byteBuffer = image.planes[0].buffer
        val byteArray = ByteArray(byteBuffer.capacity())
        byteBuffer.get(byteArray)
        val outputFile = createOutputFile()
        FileOutputStream(outputFile).use { stream: FileOutputStream -> stream.write(byteArray) }
        Log.i("Photo", "File was written, sending file to the channel on ${LocalTime.now()}")
        scope.launch {
            fileChannel.send(outputFile)
        }
    }
}

private fun createOutputFile() = //creates a unique file

工厂的createListener实现:

代码语言:javascript
复制
override fun createListener(continuation: Continuation<File>): CameraCaptureSession.CaptureCallback {
    return CoroutineCaptureCallback(channel, this, continuation)
}

CoroutineCaptureCallback的代码:

代码语言:javascript
复制
internal class CoroutineCaptureCallback(
    private val channel: ReceiveChannel<File>,
    private val scope: CoroutineScope,
    private val continuation: Continuation<File>
) : CameraCaptureSession.CaptureCallback() {

    override fun onCaptureCompleted(
        session: CameraCaptureSession,
        request: CaptureRequest,
        result: TotalCaptureResult
    ) {
        super.onCaptureCompleted(session, request, result)
        scope.launch {
            continuation.resume(channel.receive())
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-29 21:04:42

在创建捕获会话时运行的代码不包括在内,因此很难知道此时您要做什么。

也就是说,您应该发出一个重复的捕获请求,以聚合自动曝光和自动对焦,否则您的图像捕获可能会使用非常糟糕的值。为此,我建议添加第二个Surface目标,比如一个虚拟的SurfaceTexture (使用一些随机的纹理ID作为参数创建;只是不要在上面调用updateTexImage,您不需要GL上下文或任何东西)。

这样,一旦你发出你的照片捕捉请求,一切都准备好并旋转起来。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54401728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档