2021-02-19 20:41:49 +01:00
|
|
|
package com.mrousavy.camera
|
2021-02-19 16:28:14 +01:00
|
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
|
import androidx.camera.core.VideoCapture
|
|
|
|
import com.facebook.react.bridge.*
|
2021-02-26 10:56:20 +01:00
|
|
|
import com.mrousavy.camera.utils.makeErrorMap
|
2021-02-19 16:28:14 +01:00
|
|
|
import kotlinx.coroutines.*
|
|
|
|
import java.io.File
|
|
|
|
|
|
|
|
data class TemporaryFile(val path: String)
|
|
|
|
|
|
|
|
@SuppressLint("RestrictedApi")
|
|
|
|
suspend fun CameraView.startRecording(options: ReadableMap, onRecordCallback: Callback): TemporaryFile {
|
2021-02-26 10:56:20 +01:00
|
|
|
if (videoCapture == null) {
|
|
|
|
throw CameraNotReadyError()
|
|
|
|
}
|
|
|
|
if (options.hasKey("flash")) {
|
|
|
|
val enableFlash = options.getString("flash") == "on"
|
|
|
|
// overrides current torch mode value to enable flash while recording
|
|
|
|
camera!!.cameraControl.enableTorch(enableFlash)
|
|
|
|
}
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
@Suppress("BlockingMethodInNonBlockingContext") // in withContext we are not blocking. False positive.
|
|
|
|
val videoFile = withContext(Dispatchers.IO) {
|
|
|
|
File.createTempFile("video", ".mp4", context.cacheDir).apply { deleteOnExit() }
|
|
|
|
}
|
|
|
|
val videoFileOptions = VideoCapture.OutputFileOptions.Builder(videoFile)
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
videoCapture!!.startRecording(
|
|
|
|
videoFileOptions.build(), recordVideoExecutor,
|
|
|
|
object : VideoCapture.OnVideoSavedCallback {
|
|
|
|
override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
|
|
|
|
val map = Arguments.createMap()
|
|
|
|
map.putString("path", videoFile.absolutePath)
|
2021-03-17 19:29:03 +01:00
|
|
|
// TODO: duration and size - see https://github.com/cuvent/react-native-vision-camera/issues/77
|
2021-02-26 10:56:20 +01:00
|
|
|
onRecordCallback(map, null)
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
// reset the torch mode
|
|
|
|
camera!!.cameraControl.enableTorch(torch == "on")
|
|
|
|
}
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
|
|
|
|
val error = when (videoCaptureError) {
|
|
|
|
VideoCapture.ERROR_ENCODER -> VideoEncoderError(message, cause)
|
|
|
|
VideoCapture.ERROR_FILE_IO -> FileIOError(message, cause)
|
|
|
|
VideoCapture.ERROR_INVALID_CAMERA -> InvalidCameraError(message, cause)
|
|
|
|
VideoCapture.ERROR_MUXER -> VideoMuxerError(message, cause)
|
|
|
|
VideoCapture.ERROR_RECORDING_IN_PROGRESS -> RecordingInProgressError(message, cause)
|
|
|
|
else -> UnknownCameraError(Error(message, cause))
|
2021-02-19 16:28:14 +01:00
|
|
|
}
|
2021-02-26 10:56:20 +01:00
|
|
|
val map = makeErrorMap("${error.domain}/${error.id}", error.message, error)
|
|
|
|
onRecordCallback(null, map)
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
// reset the torch mode
|
|
|
|
camera!!.cameraControl.enableTorch(torch == "on")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
return TemporaryFile(videoFile.absolutePath)
|
|
|
|
}
|
2021-02-19 16:28:14 +01:00
|
|
|
|
|
|
|
@SuppressLint("RestrictedApi")
|
|
|
|
fun CameraView.stopRecording() {
|
2021-02-26 10:56:20 +01:00
|
|
|
if (videoCapture == null) {
|
|
|
|
throw CameraNotReadyError()
|
|
|
|
}
|
2021-02-19 16:28:14 +01:00
|
|
|
|
2021-02-26 10:56:20 +01:00
|
|
|
videoCapture!!.stopRecording()
|
|
|
|
// reset torch mode to original value
|
|
|
|
camera!!.cameraControl.enableTorch(torch == "on")
|
2021-02-19 16:28:14 +01:00
|
|
|
}
|