Цель
Я пытался преобразовать образец кода CameraXBasi c в отдельный класс CapturingProcess
- , который связывает сценарий использования
capture
в new CapturingProcess(context, lifecycleOwner)
- , который предлагает простой метод
requestPicture()
для захвата нескольких изображений (например, по одной в секунду)
Описание ошибки
- Выполнение
requestPicture()
несколько раз дает - 4 обычных изображения JPEG (> 1 МБ)
- все остальные файлы JPEG полностью черный и всегда 192 КБ большой
Действия по воспроизведению
- Оформление заказа и сборка Пример приложения
- Запустите приложение и нажмите кнопку 5-10 раз
- Проверьте изображения в
Android/media/com.example.cameraxblackjpegbug/CameraXBlackJpegBug/
- , вы видите, что только первые 4 изображения Jpeg в порядке
- (только на некоторых устройствах см. Раздел «Проверено») *
Ожидаемый результат * 1 070 *
- Все изображения не повреждены
- каждый раз, когда
capturingProcess.requestPicture()
называется неразбитым Jpeg изображение снимается
Проверено на
- Pixel 3a Andorid 10 (воспроизводит ошибку)
- Примечание. Ранее у меня была похожая ошибка с камерой2, но тогда я не смог ее исправить
- Huawei P smart 2019 Android 9 (ошибка не воспроизводится)
- не имеет функции «ручной датчик»
Известные обходные пути
- Когда я создаю
new CapturingProcess()
, например, после трехкратного нажатия кнопки, ошибка не возникает - , однако это неприемлемо. В моем случае мне нужно делать снимки каждую секунду в течение длительного времени в фоновом режиме, поэтому для экономии ресурсов я не могу каждый раз создавать новый экземпляр.
Соответствующий код
class MainActivity : AppCompatActivity() {
private lateinit var capturingProcess: CapturingProcess
override fun onCreate(savedInstanceState: Bundle?) {
// Create Capturing Process
capturingProcess = CapturingProcess(applicationContext, this)
// Register capture action to button
fab.setOnClickListener { capturingProcess.requestPicture() }
}
}
class CapturingProcess(context: Context, lifecycleOwner: LifecycleOwner) {
private var context: Context = context
private var outputDirectory: File
private var mainExecutor: Executor
private lateinit var cameraControl: CameraControl
private lateinit var cameraInfo: CameraInfo
private var capture: ImageCapture? = null
private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
private var lifecycleOwner: LifecycleOwner = lifecycleOwner
fun requestPicture() {
capture?.let { imageCapture ->
val photoFile = createFile(outputDirectory, FILENAME, PHOTO_EXTENSION)
val metadata = ImageCapture.Metadata().apply {
isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
}
imageCapture.takePicture(photoFile, metadata, mainExecutor, imageSavedListener)
}
}
private fun bindCameraUseCases() {
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this.context)
cameraProviderFuture.addListener(Runnable {
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
capture = ImageCapture.Builder()
.setTargetName("Capture")
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.build()
cameraProvider.unbindAll()
try {
val camera =
cameraProvider.bindToLifecycle(this.lifecycleOwner, cameraSelector, capture)
cameraControl = camera.cameraControl
cameraInfo = camera.cameraInfo
} catch (e: Exception) {
throw IllegalStateException(e)
}
}, this.mainExecutor)
}
private val imageSavedListener = object : ImageCapture.OnImageSavedCallback {
override fun onError(imageCaptureError: Int, message: String, cause: Throwable?) {
Log.e(TAG, "Photo capture failed: $message")
}
override fun onImageSaved(photoFile: File) {
Log.d(TAG, "Photo capture succeeded: ${photoFile.absolutePath}")
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
context.sendBroadcast(
Intent("android.hardware.action.NEW_PICTURE", Uri.fromFile(photoFile))
)
}
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(photoFile.extension)
MediaScannerConnection.scanFile(
context, arrayOf(photoFile.absolutePath), arrayOf(mimeType), null
)
}
}
companion object {
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val PHOTO_EXTENSION = ".jpg"
private const val TAG = "CapturingProcess"
private fun createFile(
baseFolder: File,
@Suppress("SameParameterValue") format: String,
@Suppress("SameParameterValue") extension: String
) = File(
baseFolder,
SimpleDateFormat(
format,
Locale.getDefault()
).format(System.currentTimeMillis()) + extension
)
fun getOutputDirectory(context: Context): File {
val appContext = context.applicationContext
val mediaDir = context.externalMediaDirs.firstOrNull()?.let {
File(it, context.getString(R.string.app_name)).apply { mkdirs() }
}
return if (mediaDir != null && mediaDir.exists()) {
mediaDir
} else {
appContext.filesDir
}
}
}
init {
this.mainExecutor = ContextCompat.getMainExecutor(context)
outputDirectory = getOutputDirectory(context)
bindCameraUseCases()
}
}
Вопрос
- Чтобы уточнить: я хочу найти ошибку в примере кода /project.
- Таким образом, мой вопрос: почему описанная ошибка возникает, когда я выполняю
requestPicture()
> 4 раза на одном и том же экземпляре CapturingProcess
, но не когда я создаю новые экземпляры после его выполнения, например, 3 раза - как это исправить?