chore: Move onFrame
into Callback on Android (#2458)
* Separate to onFrame * Restructure FP * Move lib loading into `CameraViewModule`
This commit is contained in:
parent
02bc8a979c
commit
af14f912fb
@ -14,6 +14,7 @@ import com.mrousavy.camera.core.CameraSession
|
||||
import com.mrousavy.camera.core.CodeScannerFrame
|
||||
import com.mrousavy.camera.core.PreviewView
|
||||
import com.mrousavy.camera.extensions.installHierarchyFitter
|
||||
import com.mrousavy.camera.frameprocessor.Frame
|
||||
import com.mrousavy.camera.frameprocessor.FrameProcessor
|
||||
import com.mrousavy.camera.types.CameraDeviceFormat
|
||||
import com.mrousavy.camera.types.CodeScannerOptions
|
||||
@ -39,7 +40,7 @@ import kotlinx.coroutines.launch
|
||||
class CameraView(context: Context) :
|
||||
FrameLayout(context),
|
||||
CoroutineScope,
|
||||
CameraSession.CameraSessionCallback {
|
||||
CameraSession.Callback {
|
||||
companion object {
|
||||
const val TAG = "CameraView"
|
||||
}
|
||||
@ -96,10 +97,6 @@ class CameraView(context: Context) :
|
||||
private var currentConfigureCall: Long = System.currentTimeMillis()
|
||||
|
||||
internal var frameProcessor: FrameProcessor? = null
|
||||
set(value) {
|
||||
field = value
|
||||
cameraSession.frameProcessor = frameProcessor
|
||||
}
|
||||
|
||||
override val coroutineContext: CoroutineContext = CameraQueues.cameraQueue.coroutineDispatcher
|
||||
|
||||
@ -230,6 +227,10 @@ class CameraView(context: Context) :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFrame(frame: Frame) {
|
||||
frameProcessor?.call(frame)
|
||||
}
|
||||
|
||||
override fun onError(error: Throwable) {
|
||||
invokeOnError(error)
|
||||
}
|
||||
|
@ -26,6 +26,17 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
|
||||
companion object {
|
||||
const val TAG = "CameraView"
|
||||
var sharedRequestCode = 10
|
||||
|
||||
init {
|
||||
try {
|
||||
// Load the native part of VisionCamera.
|
||||
// Includes the OpenGL VideoPipeline, as well as Frame Processor JSI bindings
|
||||
System.loadLibrary("VisionCamera")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.e(VisionCameraProxy.TAG, "Failed to load VisionCamera C++ library!", e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.Default) // TODO: or Dispatchers.Main?
|
||||
|
@ -37,6 +37,7 @@ import com.mrousavy.camera.extensions.getPreviewTargetSize
|
||||
import com.mrousavy.camera.extensions.getVideoSizes
|
||||
import com.mrousavy.camera.extensions.openCamera
|
||||
import com.mrousavy.camera.extensions.setZoom
|
||||
import com.mrousavy.camera.frameprocessor.Frame
|
||||
import com.mrousavy.camera.frameprocessor.FrameProcessor
|
||||
import com.mrousavy.camera.types.Flash
|
||||
import com.mrousavy.camera.types.Orientation
|
||||
@ -55,7 +56,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
class CameraSession(private val context: Context, private val cameraManager: CameraManager, private val callback: CameraSessionCallback) :
|
||||
class CameraSession(private val context: Context, private val cameraManager: CameraManager, private val callback: Callback) :
|
||||
CameraManager.AvailabilityCallback(),
|
||||
Closeable,
|
||||
CoroutineScope {
|
||||
@ -383,7 +384,8 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
size.height,
|
||||
video.config.pixelFormat,
|
||||
isSelfie,
|
||||
video.config.enableFrameProcessor
|
||||
video.config.enableFrameProcessor,
|
||||
callback
|
||||
)
|
||||
val output = VideoPipelineOutput(videoPipeline, video.config.enableHdr)
|
||||
outputs.add(output)
|
||||
@ -615,7 +617,6 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
private fun updateVideoOutputs() {
|
||||
val videoOutput = videoOutput ?: return
|
||||
Log.i(TAG, "Updating Video Outputs...")
|
||||
videoOutput.videoPipeline.setFrameProcessorOutput(frameProcessor)
|
||||
videoOutput.videoPipeline.setRecordingSessionOutput(recording)
|
||||
}
|
||||
|
||||
@ -720,8 +721,9 @@ class CameraSession(private val context: Context, private val cameraManager: Cam
|
||||
}
|
||||
}
|
||||
|
||||
interface CameraSessionCallback {
|
||||
interface Callback {
|
||||
fun onError(error: Throwable)
|
||||
fun onFrame(frame: Frame)
|
||||
fun onInitialized()
|
||||
fun onStarted()
|
||||
fun onStopped()
|
||||
|
@ -14,7 +14,7 @@ class CodeScannerPipeline(
|
||||
val size: Size,
|
||||
val format: Int,
|
||||
val configuration: CameraConfiguration.CodeScanner,
|
||||
val callback: CameraSession.CameraSessionCallback
|
||||
val callback: CameraSession.Callback
|
||||
) : Closeable {
|
||||
companion object {
|
||||
// We want to have a buffer of 2 images, but we always only acquire one.
|
||||
|
@ -31,26 +31,13 @@ class VideoPipeline(
|
||||
val height: Int,
|
||||
val format: PixelFormat = PixelFormat.NATIVE,
|
||||
private val isMirrored: Boolean = false,
|
||||
enableFrameProcessor: Boolean = false
|
||||
enableFrameProcessor: Boolean = false,
|
||||
private val callback: CameraSession.Callback
|
||||
) : SurfaceTexture.OnFrameAvailableListener,
|
||||
Closeable {
|
||||
companion object {
|
||||
private const val MAX_IMAGES = 3
|
||||
private const val TAG = "VideoPipeline"
|
||||
|
||||
init {
|
||||
try {
|
||||
System.loadLibrary("VisionCamera")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"Failed to load VisionCamera C++ library! " +
|
||||
"OpenGL GPU VideoPipeline cannot be used.",
|
||||
e
|
||||
)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
@ -60,16 +47,13 @@ class VideoPipeline(
|
||||
private var transformMatrix = FloatArray(16)
|
||||
private var isActive = true
|
||||
|
||||
// Output 1
|
||||
private var frameProcessor: FrameProcessor? = null
|
||||
|
||||
// Output 2
|
||||
private var recordingSession: RecordingSession? = null
|
||||
|
||||
// Input
|
||||
private val surfaceTexture: SurfaceTexture
|
||||
val surface: Surface
|
||||
|
||||
// Output
|
||||
private var recordingSession: RecordingSession? = null
|
||||
|
||||
// If Frame Processors are enabled, we go through ImageReader first before we go thru OpenGL
|
||||
private var imageReader: ImageReader? = null
|
||||
private var imageWriter: ImageWriter? = null
|
||||
@ -115,7 +99,7 @@ class VideoPipeline(
|
||||
frame.incrementRefCount()
|
||||
|
||||
try {
|
||||
frameProcessor?.call(frame)
|
||||
callback.onFrame(frame)
|
||||
|
||||
if (hasOutputs) {
|
||||
// If we have outputs (e.g. a RecordingSession), pass the frame along to the OpenGL pipeline
|
||||
@ -141,7 +125,6 @@ class VideoPipeline(
|
||||
isActive = false
|
||||
imageWriter?.close()
|
||||
imageReader?.close()
|
||||
frameProcessor = null
|
||||
recordingSession = null
|
||||
surfaceTexture.release()
|
||||
}
|
||||
@ -180,20 +163,6 @@ class VideoPipeline(
|
||||
else -> ImageFormat.PRIVATE
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Pipeline to also call the given [FrameProcessor] (or null).
|
||||
*/
|
||||
fun setFrameProcessorOutput(frameProcessor: FrameProcessor?) {
|
||||
synchronized(this) {
|
||||
if (frameProcessor != null) {
|
||||
Log.i(TAG, "Setting $width x $height FrameProcessor Output...")
|
||||
} else {
|
||||
Log.i(TAG, "Removing FrameProcessor Output...")
|
||||
}
|
||||
this.frameProcessor = frameProcessor
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Pipeline to also write Frames to a Surface from a `MediaRecorder` (or null)
|
||||
*/
|
||||
|
@ -17,14 +17,6 @@ import java.lang.ref.WeakReference
|
||||
class VisionCameraProxy(context: ReactApplicationContext) {
|
||||
companion object {
|
||||
const val TAG = "VisionCameraProxy"
|
||||
init {
|
||||
try {
|
||||
System.loadLibrary("VisionCamera")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.e(TAG, "Failed to load VisionCamera C++ library!", e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
|
Loading…
Reference in New Issue
Block a user