success
This commit is contained in:
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="uts.sdk.modules.XFCameraUTS">
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="true" />
|
||||
<uses-feature android:name="android.hardware.camera.any" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.flash" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="true" />
|
||||
<application android:requestLegacyExternalStorage="true">
|
||||
<meta-data android:name="ScopedStorage" android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"minSdkVersion": "19",
|
||||
"dependencies": [
|
||||
"androidx.camera:camera-core:1.4.0-alpha04",
|
||||
"androidx.camera:camera-camera2:1.4.0-alpha04",
|
||||
"androidx.camera:camera-lifecycle:1.4.0-alpha04",
|
||||
"androidx.camera:camera-video:1.4.0-alpha04",
|
||||
"androidx.camera:camera-view:1.4.0-alpha04"
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"name": "xf-camera",
|
||||
"class": "uts.sdk.modules.SkinCameraUTS.XfCameraComponent"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+745
@@ -0,0 +1,745 @@
|
||||
@file:Suppress("UNCHECKED_CAST", "USELESS_CAST", "INAPPLICABLE_JVM_NAME", "UNUSED_ANONYMOUS_PARAMETER", "NAME_SHADOWING", "UNNECESSARY_NOT_NULL_ASSERTION")
|
||||
package uts.sdk.modules.SkinCameraUTS
|
||||
import android.content.Context
|
||||
import android.graphics.ImageFormat
|
||||
import android.util.Size
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import androidx.camera.core.CameraControl
|
||||
import androidx.camera.core.CameraSelector
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.camera.core.ImageCapture
|
||||
import androidx.camera.core.ImageCaptureException
|
||||
import androidx.camera.core.ImageProxy
|
||||
import androidx.camera.core.MirrorMode
|
||||
import androidx.camera.core.Preview
|
||||
import androidx.camera.core.UseCaseGroup
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.camera.video.FileOutputOptions
|
||||
import androidx.camera.video.Quality
|
||||
import androidx.camera.video.QualitySelector
|
||||
import androidx.camera.video.Recorder
|
||||
import androidx.camera.video.Recording
|
||||
import androidx.camera.video.VideoCapture
|
||||
import androidx.camera.video.VideoRecordEvent
|
||||
import androidx.camera.view.PreviewView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import io.dcloud.uniapp.*
|
||||
import io.dcloud.uniapp.UniSDKEngine
|
||||
import io.dcloud.uniapp.appframe.PageProxy
|
||||
import io.dcloud.uniapp.dom.node.DomNode
|
||||
import io.dcloud.uniapp.dom.node.PageNode
|
||||
import io.dcloud.uniapp.extapi.*
|
||||
import io.dcloud.uniapp.framework.*
|
||||
import io.dcloud.uniapp.interfaces.INodeData
|
||||
import io.dcloud.uniapp.runtime.*
|
||||
import io.dcloud.uniapp.ui.component.IComponentData
|
||||
import io.dcloud.uniapp.vue.*
|
||||
import io.dcloud.uniapp.vue.shared.*
|
||||
import io.dcloud.uts.*
|
||||
import io.dcloud.uts.Map
|
||||
import io.dcloud.uts.Set
|
||||
import io.dcloud.uts.UTSAndroid
|
||||
import io.dcloud.uts.component.*
|
||||
import io.dcloud.uts.component.UTSComponent
|
||||
import java.io.File
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.properties.Delegates
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
open class GeneralCallbackResult (
|
||||
@JsonNotNull
|
||||
open var errMsg: String,
|
||||
) : UTSObject()
|
||||
open class TakePhotoSuccessCallbackResult (
|
||||
@JsonNotNull
|
||||
open var tempImagePath: String,
|
||||
@JsonNotNull
|
||||
open var quality: String,
|
||||
@JsonNotNull
|
||||
open var errMsg: String,
|
||||
) : UTSObject()
|
||||
typealias TakePhotoFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias TakePhotoSuccessCallback = (result: TakePhotoSuccessCallbackResult) -> Unit
|
||||
typealias TakePhotoCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
open class TakePhotoOption (
|
||||
open var complete: TakePhotoCompleteCallback? = null,
|
||||
open var fail: TakePhotoFailCallback? = null,
|
||||
open var quality: String? = null,
|
||||
open var selfieMirror: Boolean? = null,
|
||||
open var success: TakePhotoSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
open class SetZoomSuccessCallbackResult (
|
||||
@JsonNotNull
|
||||
open var zoom: Number,
|
||||
@JsonNotNull
|
||||
open var errMsg: String,
|
||||
) : UTSObject()
|
||||
typealias SetZoomCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias SetZoomFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias CameraContextSetZoomSuccessCallback = (result: SetZoomSuccessCallbackResult) -> Unit
|
||||
open class CameraContextSetZoomOption (
|
||||
@JsonNotNull
|
||||
open var zoom: Number,
|
||||
open var complete: SetZoomCompleteCallback? = null,
|
||||
open var fail: SetZoomFailCallback? = null,
|
||||
open var success: CameraContextSetZoomSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
open class StartRecordTimeoutCallbackResult (
|
||||
@JsonNotNull
|
||||
open var tempVideoPath: String,
|
||||
) : UTSObject()
|
||||
typealias StartRecordCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StartRecordFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StartRecordTimeoutCallback = (result: StartRecordTimeoutCallbackResult) -> Unit
|
||||
typealias CameraContextStartRecordSuccessCallback = (res: GeneralCallbackResult) -> Unit
|
||||
open class CameraContextStartRecordOption (
|
||||
open var complete: StartRecordCompleteCallback? = null,
|
||||
open var fail: StartRecordFailCallback? = null,
|
||||
open var selfieMirror: Boolean? = null,
|
||||
open var success: CameraContextStartRecordSuccessCallback? = null,
|
||||
open var timeout: Number? = null,
|
||||
open var timeoutCallback: StartRecordTimeoutCallback? = null,
|
||||
) : UTSObject()
|
||||
open class StopRecordSuccessCallbackResult (
|
||||
@JsonNotNull
|
||||
open var tempVideoPath: String,
|
||||
@JsonNotNull
|
||||
open var errMsg: String,
|
||||
) : UTSObject()
|
||||
typealias StopRecordCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StopRecordFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias CameraContextStopRecordSuccessCallback = (result: StopRecordSuccessCallbackResult) -> Unit
|
||||
open class CameraContextStopRecordOption (
|
||||
open var complete: StopRecordCompleteCallback? = null,
|
||||
open var compressed: Boolean? = null,
|
||||
open var fail: StopRecordFailCallback? = null,
|
||||
open var success: CameraContextStopRecordSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
typealias OnCameraFrameCallback = (result: OnCameraFrameCallbackResult) -> Unit
|
||||
open class OnCameraFrameCallbackResult (
|
||||
@JsonNotNull
|
||||
open var data: Any,
|
||||
@JsonNotNull
|
||||
open var height: Number,
|
||||
@JsonNotNull
|
||||
open var width: Number,
|
||||
) : UTSObject()
|
||||
typealias StartSuccessCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StartFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StartCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
open class CameraFrameListenerStartOption (
|
||||
open var complete: StartCompleteCallback? = null,
|
||||
open var fail: StartFailCallback? = null,
|
||||
open var success: StartSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
typealias StopCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StopFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias StopSuccessCallback = (res: GeneralCallbackResult) -> Unit
|
||||
open class StopOption (
|
||||
open var complete: StopCompleteCallback? = null,
|
||||
open var fail: StopFailCallback? = null,
|
||||
open var success: StopSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
typealias FlashMode = String
|
||||
typealias DevicePosition = String
|
||||
typealias Resolution = String
|
||||
typealias FrameSize = String
|
||||
typealias QualityType = String
|
||||
open class CameraConfig (
|
||||
open var flash: FlashMode? = null,
|
||||
open var devicePosition: DevicePosition? = null,
|
||||
open var resolution: Resolution? = null,
|
||||
open var frameSize: FrameSize? = null,
|
||||
) : UTSObject()
|
||||
typealias SwitchCompleteCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias SwitchFailCallback = (res: GeneralCallbackResult) -> Unit
|
||||
typealias SwitchSuccessCallback = (res: GeneralCallbackResult) -> Unit
|
||||
open class SwitchOption (
|
||||
@JsonNotNull
|
||||
open var position: DevicePosition,
|
||||
open var complete: SwitchCompleteCallback? = null,
|
||||
open var fail: SwitchFailCallback? = null,
|
||||
open var success: SwitchSuccessCallback? = null,
|
||||
) : UTSObject()
|
||||
open class OnCameraFrameListenerOption (
|
||||
open var success: OnCameraFrameCallback? = null,
|
||||
) : UTSObject()
|
||||
typealias TakePhoto = (options: TakePhotoOption) -> Unit
|
||||
typealias SetZoom = (options: CameraContextSetZoomOption) -> Unit
|
||||
typealias StartRecord = (options: CameraContextStartRecordOption) -> Unit
|
||||
typealias StopRecord = (options: CameraContextStopRecordOption) -> Unit
|
||||
typealias StartCameraFrame = (options: CameraFrameListenerStartOption) -> Unit
|
||||
typealias StopCameraFrame = (options: StopOption) -> Unit
|
||||
typealias SwitchCamera = (options: SwitchOption) -> Unit
|
||||
val FLASH_MODE_MAP = Map<String, Int>(_uA(
|
||||
_uA(
|
||||
"auto",
|
||||
ImageCapture.FLASH_MODE_AUTO
|
||||
),
|
||||
_uA(
|
||||
"on",
|
||||
ImageCapture.FLASH_MODE_ON
|
||||
),
|
||||
_uA(
|
||||
"torch",
|
||||
ImageCapture.FLASH_MODE_ON
|
||||
),
|
||||
_uA(
|
||||
"off",
|
||||
ImageCapture.FLASH_MODE_OFF
|
||||
)
|
||||
))
|
||||
val DEVICE_POSITION_MAP = Map<String, Int>(_uA(
|
||||
_uA(
|
||||
"back",
|
||||
CameraSelector.LENS_FACING_BACK
|
||||
),
|
||||
_uA(
|
||||
"front",
|
||||
CameraSelector.LENS_FACING_FRONT
|
||||
)
|
||||
))
|
||||
val RESOLUTION_MAP = Map<String, Quality>(_uA(
|
||||
_uA(
|
||||
"low",
|
||||
Quality.LOWEST
|
||||
),
|
||||
_uA(
|
||||
"medium",
|
||||
Quality.HD
|
||||
),
|
||||
_uA(
|
||||
"high",
|
||||
Quality.HIGHEST
|
||||
)
|
||||
))
|
||||
val QUALITY_MAP = Map<String, Int>(_uA(
|
||||
_uA(
|
||||
"high",
|
||||
ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
|
||||
),
|
||||
_uA(
|
||||
"low",
|
||||
ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
|
||||
)
|
||||
))
|
||||
val MIRROR_MODE = Map<Boolean, Int>(_uA(
|
||||
_uA(
|
||||
true,
|
||||
MirrorMode.MIRROR_MODE_ON
|
||||
),
|
||||
_uA(
|
||||
false,
|
||||
MirrorMode.MIRROR_MODE_OFF
|
||||
)
|
||||
))
|
||||
open class CameraView : FrameLayout {
|
||||
private var previewView: PreviewView
|
||||
open var cameraProvider: ProcessCameraProvider? = null
|
||||
open var cameraControl: CameraControl? = null
|
||||
private var imageCapture: ImageCapture? = null
|
||||
private var videoCapture: VideoCapture<Recorder>? = null
|
||||
private var recording: Recording? = null
|
||||
private var comp: UTSComponent<CameraView>
|
||||
private var flashMode: FlashMode = "auto"
|
||||
private var devicePosition: DevicePosition = "back"
|
||||
private var resolution: Resolution = "medium"
|
||||
private var quality: QualityType = "normal"
|
||||
private var videoFile: File? = null
|
||||
open var maxZoom: Float = 1.toFloat()
|
||||
open var minZoom: Float = 1.toFloat()
|
||||
private var initialized: Boolean = false
|
||||
private var isListening: Boolean = false
|
||||
private var videoSelfieMirror: Boolean? = null
|
||||
private var cameraContextStopRecordOption: CameraContextStopRecordOption? = null
|
||||
private var onCameraFrameCallback: OnCameraFrameCallback? = null
|
||||
private var cameraExecutor: ExecutorService? = null
|
||||
private var onCameraFrameListenerOption: OnCameraFrameListenerOption? = null
|
||||
constructor(context: Context, comp: UTSComponent<CameraView>, config: CameraConfig = CameraConfig()) : super(context) {
|
||||
this.comp = comp
|
||||
this.flashMode = config.flash ?: "auto"
|
||||
this.devicePosition = config.devicePosition ?: "back"
|
||||
this.resolution = config.resolution ?: "medium"
|
||||
this.previewView = PreviewView(context)
|
||||
var layoutParam = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
this.addView(this.previewView, layoutParam)
|
||||
this.setupCamera()
|
||||
}
|
||||
open fun setupCamera() {
|
||||
var cameraProviderFuture = ProcessCameraProvider.getInstance(UTSAndroid.getUniActivity()!!)
|
||||
cameraProviderFuture.addListener(fun(){
|
||||
try {
|
||||
this.cameraProvider = cameraProviderFuture.get()
|
||||
this.bindCamera()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
var ret: Map<String, Any> = Map()
|
||||
ret.set("errMsg", JSON.stringify(e))
|
||||
this.comp.`$emit`("error", ret)
|
||||
}
|
||||
}
|
||||
, ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!!))
|
||||
}
|
||||
open fun bindCamera() {
|
||||
var targetResolution = RESOLUTION_MAP.get(this.resolution) ?: Quality.HD
|
||||
var captureMode = QUALITY_MAP.get(this.quality) ?: ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
|
||||
var preview = Preview.Builder().build()
|
||||
preview.setSurfaceProvider(this.previewView.getSurfaceProvider())
|
||||
var imageCapture = ImageCapture.Builder().setFlashMode(FLASH_MODE_MAP.get(this.flashMode)!!).setCaptureMode(captureMode).build()
|
||||
var cameraSelector = CameraSelector.Builder().requireLensFacing(DEVICE_POSITION_MAP.get(this.devicePosition)!!).build()
|
||||
var recorder = Recorder.Builder().setQualitySelector(QualitySelector.from(targetResolution))
|
||||
var mirrorMode = if (this.videoSelfieMirror == null) {
|
||||
MirrorMode.MIRROR_MODE_ON_FRONT_ONLY
|
||||
} else {
|
||||
MIRROR_MODE.get(this.videoSelfieMirror!!)
|
||||
}
|
||||
var videoCapture = VideoCapture.Builder(recorder.build()).setMirrorMode(mirrorMode!!).build()
|
||||
this.videoCapture = videoCapture
|
||||
this.imageCapture = imageCapture
|
||||
this.cameraProvider!!.unbindAll()
|
||||
var imageAnalysis = ImageAnalysis.Builder().setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build()
|
||||
var viewPort = this.previewView.getViewPort()!!
|
||||
var useCaseGroup = UseCaseGroup.Builder().addUseCase(preview).addUseCase(imageAnalysis).addUseCase(imageCapture).addUseCase(videoCapture).setViewPort(viewPort).build()
|
||||
this.cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
var _this = this
|
||||
open class Analyzer : ImageAnalysis.Analyzer {
|
||||
constructor(){}
|
||||
override fun analyze(image: ImageProxy) {
|
||||
if (_this.isListening) {
|
||||
var imageFormat = image.getFormat()
|
||||
var width = image.width
|
||||
var height = image.height
|
||||
if (imageFormat == ImageFormat.YUV_420_888) {
|
||||
_this.onCameraFrameCallback?.invoke(OnCameraFrameCallbackResult(width = width, height = height, data = image))
|
||||
_this.onCameraFrameListenerOption?.success?.invoke(OnCameraFrameCallbackResult(width = width, height = height, data = image))
|
||||
}
|
||||
}
|
||||
image.close()
|
||||
}
|
||||
override fun getDefaultTargetResolution(): Size {
|
||||
return Size(640, 480)
|
||||
}
|
||||
}
|
||||
imageAnalysis.setAnalyzer(this.cameraExecutor!!, Analyzer() as ImageAnalysis.Analyzer)
|
||||
var camera = this.cameraProvider!!.bindToLifecycle(UTSAndroid.getUniActivity()!! as LifecycleOwner, cameraSelector, useCaseGroup)
|
||||
this.cameraControl = camera.getCameraControl()
|
||||
if (!this.initialized) {
|
||||
this.initialized = true
|
||||
var zoomState = camera.getCameraInfo().getZoomState().getValue()
|
||||
this.maxZoom = zoomState?.getMaxZoomRatio() ?: 1.toFloat()
|
||||
this.minZoom = zoomState?.getMinZoomRatio() ?: 1.toFloat()
|
||||
var maxZoom = this.maxZoom
|
||||
var ret: Map<String, Any> = Map()
|
||||
ret.set("maxZoom", maxZoom)
|
||||
this.comp.`$emit`("ready", ret)
|
||||
}
|
||||
}
|
||||
open fun unbindCamera() {
|
||||
this.cameraProvider?.unbindAll()
|
||||
this.cameraExecutor?.shutdown()
|
||||
}
|
||||
open fun setConfig(config: CameraConfig = CameraConfig()) {
|
||||
this.flashMode = config.flash ?: "auto"
|
||||
this.devicePosition = config.devicePosition ?: "back"
|
||||
this.resolution = config.resolution ?: "medium"
|
||||
}
|
||||
open fun setFlash(mode: FlashMode) {
|
||||
this.flashMode = mode
|
||||
if (FLASH_MODE_MAP.get(mode) == null || this.imageCapture == null) {
|
||||
return
|
||||
}
|
||||
this.imageCapture!!.setFlashMode(FLASH_MODE_MAP.get(mode)!!)
|
||||
}
|
||||
open fun switchCamera(position: DevicePosition) {
|
||||
this.devicePosition = position
|
||||
if (DEVICE_POSITION_MAP.get(position) == null || this.cameraProvider == null) {
|
||||
return
|
||||
}
|
||||
this.unbindCamera()
|
||||
this.bindCamera()
|
||||
}
|
||||
open fun isResolutionSupported(context: Context, cameraSelector: CameraSelector, targetResolution: Size): Boolean {
|
||||
return true
|
||||
}
|
||||
open fun takePhoto(option: TakePhotoOption) {
|
||||
var quality = option.quality ?: "high"
|
||||
this.quality = quality
|
||||
if (quality == "low") {
|
||||
this.unbindCamera()
|
||||
this.bindCamera()
|
||||
}
|
||||
var privateDir = UTSAndroid.getAppCachePath()!!
|
||||
val tempFile = File(privateDir)
|
||||
if (!tempFile.exists()) {
|
||||
tempFile.mkdirs()
|
||||
}
|
||||
val photoFile = File(privateDir, Date.now() + ".png")
|
||||
var metadata = ImageCapture.Metadata()
|
||||
metadata.setReversedHorizontal(option.selfieMirror ?: DEVICE_POSITION_MAP.get(this.devicePosition)!! == CameraSelector.LENS_FACING_FRONT)
|
||||
val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).setMetadata(metadata).build()
|
||||
open class OnImageSavedCallback : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
option.success?.invoke(TakePhotoSuccessCallbackResult(tempImagePath = photoFile.getAbsolutePath(), quality = quality, errMsg = "ok"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
}
|
||||
override fun onError(err: ImageCaptureException) {
|
||||
val result = GeneralCallbackResult(errMsg = err.toString())
|
||||
option.fail?.invoke(result)
|
||||
option.complete?.invoke(result)
|
||||
}
|
||||
override fun onCaptureStarted() {}
|
||||
}
|
||||
this.imageCapture!!.takePicture(outputOptions, ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!!), OnImageSavedCallback() as ImageCapture.OnImageSavedCallback)
|
||||
}
|
||||
open fun setZoom(option: CameraContextSetZoomOption) {
|
||||
if (this.cameraControl != null) {
|
||||
try {
|
||||
this.cameraControl!!.setZoomRatio(option.zoom.toFloat())
|
||||
option.success?.invoke(SetZoomSuccessCallbackResult(zoom = option.zoom, errMsg = "ok"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
} catch (e: Throwable) {
|
||||
val result = GeneralCallbackResult(errMsg = e.toString())
|
||||
option.complete?.invoke(result)
|
||||
option.fail?.invoke(result)
|
||||
}
|
||||
} else {
|
||||
val result = GeneralCallbackResult(errMsg = "相机不存在")
|
||||
option.complete?.invoke(result)
|
||||
option.fail?.invoke(result)
|
||||
}
|
||||
}
|
||||
open fun startRecord(option: CameraContextStartRecordOption) {
|
||||
if (option.selfieMirror != null && this.videoSelfieMirror != option.selfieMirror) {
|
||||
this.videoSelfieMirror = option.selfieMirror
|
||||
this.unbindCamera()
|
||||
this.bindCamera()
|
||||
}
|
||||
if (this.recording != null || this.videoCapture == null) {
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "已经在录制或相机不存在"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "已经在录制或相机不存在"))
|
||||
return
|
||||
}
|
||||
var privateDir = UTSAndroid.getAppCachePath()!!
|
||||
this.videoFile = File(privateDir, Date.now() + "video.mp4")
|
||||
var outputFileOptions = FileOutputOptions.Builder(this.videoFile!!).build()
|
||||
this.recording = this.videoCapture!!.output.prepareRecording(UTSAndroid.getUniActivity()!!, outputFileOptions).withAudioEnabled().start(ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!!), fun(recordEvent: VideoRecordEvent){
|
||||
if (recordEvent is VideoRecordEvent.Start) {
|
||||
option.success?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
if (option.timeout != null && option.timeout!! > 0) {
|
||||
setTimeout(fun(){
|
||||
this.recording?.stop()
|
||||
}
|
||||
, option.timeout!!)
|
||||
}
|
||||
} else if (recordEvent is VideoRecordEvent.Finalize) {
|
||||
this.recording?.close()
|
||||
this.recording = null
|
||||
var tempVideoPath = this.videoFile?.getAbsolutePath()!!
|
||||
this.cameraContextStopRecordOption?.success?.invoke(StopRecordSuccessCallbackResult(tempVideoPath = tempVideoPath, errMsg = "ok"))
|
||||
option.timeoutCallback?.invoke(StartRecordTimeoutCallbackResult(tempVideoPath = tempVideoPath))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun stopRecord(option: CameraContextStopRecordOption) {
|
||||
if (this.recording == null) {
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未开始录制"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未开始录制"))
|
||||
return
|
||||
}
|
||||
this.cameraContextStopRecordOption = option
|
||||
this.recording?.stop()
|
||||
}
|
||||
open fun onCameraFrame(callback: OnCameraFrameCallback? = null) {
|
||||
this.onCameraFrameCallback = callback
|
||||
}
|
||||
open fun onCameraFrameListener(option: OnCameraFrameListenerOption) {
|
||||
this.onCameraFrameListenerOption = option
|
||||
}
|
||||
open fun cameraFrameOnStart(option: CameraFrameListenerStartOption?) {
|
||||
this.isListening = true
|
||||
option?.success?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
}
|
||||
open fun cameraFrameOnStop(option: StopOption?) {
|
||||
this.isListening = false
|
||||
option?.success?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
}
|
||||
}
|
||||
open class CameraManager {
|
||||
private var cameraView: CameraView? = null
|
||||
public open fun setCameraView(cameraView: CameraView?): Unit {
|
||||
this.cameraView = cameraView!!
|
||||
}
|
||||
public open fun getCameraView(): CameraView? {
|
||||
return this.cameraView
|
||||
}
|
||||
public open fun dispose(): Unit {
|
||||
this.cameraView = null
|
||||
}
|
||||
companion object {
|
||||
private var instance: CameraManager? = null
|
||||
public fun getInstance(): CameraManager {
|
||||
if (CameraManager.instance == null) {
|
||||
CameraManager.instance = CameraManager()
|
||||
}
|
||||
return CameraManager.instance!!
|
||||
}
|
||||
}
|
||||
}
|
||||
open class XfCameraComponent : UTSComponent<CameraView> {
|
||||
constructor(proxy: PageProxy, componentData: IComponentData) : super(proxy, componentData)
|
||||
open var mode: String = "normal"
|
||||
open var resolution: String = "medium"
|
||||
open var position: String = "back"
|
||||
open var flash: String = "auto"
|
||||
open var frameSize: String = "medium"
|
||||
override fun created() {}
|
||||
override fun NVBeforeLoad() {}
|
||||
override fun NVLoad(): CameraView {
|
||||
var previewView = CameraView(this.`$androidContext`!!, this)
|
||||
previewView.setTag("9527")
|
||||
CameraManager.getInstance().setCameraView(previewView)
|
||||
return previewView
|
||||
}
|
||||
override fun NVLoaded() {}
|
||||
override fun NVLayouted() {
|
||||
this.`$el`?.setConfig(CameraConfig(resolution = this.resolution, frameSize = this.frameSize, flash = this.flash))
|
||||
this.`$el`?.switchCamera(this.position)
|
||||
}
|
||||
override fun NVBeforeUnload() {
|
||||
var ret: Map<String, Any> = Map()
|
||||
this.`$emit`("stop", ret)
|
||||
this.`$el`?.unbindCamera()
|
||||
}
|
||||
override fun NVUnloaded() {
|
||||
CameraManager.getInstance().dispose()
|
||||
}
|
||||
override fun unmounted() {}
|
||||
override fun `$init`() {
|
||||
this.`$watch`<String>("position", fun(newValue, _){
|
||||
this.`$el`?.switchCamera(newValue)
|
||||
}
|
||||
)
|
||||
this.`$watch`<String>("flash", fun(newValue, _){
|
||||
this.`$el`?.setFlash(newValue)
|
||||
}
|
||||
)
|
||||
}
|
||||
companion object {
|
||||
var name = "xf-camera"
|
||||
init {
|
||||
io.dcloud.uniapp.UniSDKEngine.registerUniComponent("xf-camera", XfCameraComponent::class.java, XfCameraElement::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
open class XfCameraElement : DomNode {
|
||||
constructor(data: INodeData, pageNode: PageNode) : super(data, pageNode)
|
||||
}
|
||||
open class CameraFrameListener {
|
||||
open lateinit var context: CameraContext
|
||||
constructor(context: CameraContext){
|
||||
this.context = context
|
||||
}
|
||||
open fun start(): Unit {
|
||||
this.start(null)
|
||||
}
|
||||
open fun start(option: CameraFrameListenerStartOption?) {
|
||||
this.context.getCamera().then(fun(camera: CameraView){
|
||||
camera.cameraFrameOnStart(option)
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun stop(): Unit {
|
||||
this.stop(null)
|
||||
}
|
||||
open fun stop(option: StopOption?) {
|
||||
this.context.getCamera().then(fun(camera: CameraView){
|
||||
camera.cameraFrameOnStop(option)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
open class CameraContext {
|
||||
private var mCameraFrameListener: CameraFrameListener? = null
|
||||
constructor(){}
|
||||
open fun getCamera(): UTSPromise<CameraView> {
|
||||
var cameraPreview = CameraManager.getInstance().getCameraView()
|
||||
if (cameraPreview != null) {
|
||||
return UTSPromise.resolve<CameraView>(cameraPreview)
|
||||
}
|
||||
var resolveFunc: ((res: CameraView) -> Unit)? = null
|
||||
var rejectFunc: ((res: String) -> Unit)? = null
|
||||
var maxAttempts: Number = 5
|
||||
var currentAttempt: Number = 0
|
||||
fun attemptGetCamera() {
|
||||
var camera = CameraManager.getInstance().getCameraView()
|
||||
if (camera != null) {
|
||||
resolveFunc?.invoke(camera)
|
||||
} else if (currentAttempt < maxAttempts) {
|
||||
currentAttempt++
|
||||
setTimeout(fun(){
|
||||
attemptGetCamera()
|
||||
}, 100)
|
||||
} else {
|
||||
rejectFunc?.invoke("Camera not found after multiple attempts")
|
||||
}
|
||||
}
|
||||
return UTSPromise<CameraView>(fun(resolve, reject){
|
||||
resolveFunc = resolve
|
||||
rejectFunc = reject
|
||||
attemptGetCamera()
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun takePhoto(option: TakePhotoOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.takePhoto(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun setZoom(option: CameraContextSetZoomOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.setZoom(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun startRecord(option: CameraContextStartRecordOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.startRecord(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun stopRecord(option: CameraContextStopRecordOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.stopRecord(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun onCameraFrame(): CameraFrameListener {
|
||||
return this.onCameraFrame(null)
|
||||
}
|
||||
open fun onCameraFrame(callback: OnCameraFrameCallback? = null): CameraFrameListener {
|
||||
if (this.mCameraFrameListener == null) {
|
||||
this.mCameraFrameListener = CameraFrameListener(this)
|
||||
}
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.onCameraFrame(callback)
|
||||
}
|
||||
)
|
||||
return this.mCameraFrameListener!!
|
||||
}
|
||||
open fun onCameraFrameListener(option: OnCameraFrameListenerOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.onCameraFrameListener(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
console.log("未找到相机")
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun cameraFrameOnStart(option: CameraFrameListenerStartOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.cameraFrameOnStart(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun cameraFrameOnStop(option: StopOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.cameraFrameOnStop(option)
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
open fun switchCamera(option: SwitchOption) {
|
||||
this.getCamera().then(fun(camera: CameraView){
|
||||
camera.switchCamera(option.position)
|
||||
option.success?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "ok"))
|
||||
}
|
||||
).`catch`(fun(){
|
||||
option.fail?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
option.complete?.invoke(GeneralCallbackResult(errMsg = "未找到相机"))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
var context: CameraContext = CameraContext()
|
||||
fun createCameraContext(): CameraContext {
|
||||
return context
|
||||
}
|
||||
val takePhoto: TakePhoto = fun(options: TakePhotoOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.takePhoto(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val setZoom: SetZoom = fun(options: CameraContextSetZoomOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.setZoom(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val startRecord: StartRecord = fun(options: CameraContextStartRecordOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.startRecord(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val stopRecord: StopRecord = fun(options: CameraContextStopRecordOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.stopRecord(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
fun onCameraFrameListener(options: OnCameraFrameListenerOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.onCameraFrameListener(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val startCameraFrame: StartCameraFrame = fun(options: CameraFrameListenerStartOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.cameraFrameOnStart(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val stopCameraFrame: StopCameraFrame = fun(options: StopOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.cameraFrameOnStop(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
val switchCamera: SwitchCamera = fun(options: SwitchOption) {
|
||||
UTSAndroid.getDispatcher("main").async(fun(_) {
|
||||
context.switchCamera(options)
|
||||
}
|
||||
, null)
|
||||
}
|
||||
Reference in New Issue
Block a user