1+ package com.foke.together.external.camera.internal
2+
3+ import android.content.Context
4+ import android.graphics.Bitmap
5+ import android.graphics.Matrix
6+ import android.hardware.camera2.CaptureRequest
7+ import android.os.SystemClock
8+ import android.util.Log
9+ import android.util.Range
10+ import android.util.Size
11+ import androidx.annotation.OptIn
12+ import androidx.camera.camera2.Camera2Config
13+ import androidx.camera.camera2.interop.Camera2Interop
14+ import androidx.camera.camera2.interop.ExperimentalCamera2Interop
15+ import androidx.camera.core.AspectRatio
16+ import androidx.camera.core.CameraSelector
17+ import androidx.camera.core.CameraXConfig
18+ import androidx.camera.core.ImageAnalysis
19+ import androidx.camera.lifecycle.ProcessCameraProvider
20+ import dagger.Module
21+ import dagger.Provides
22+ import dagger.hilt.InstallIn
23+ import dagger.hilt.components.SingletonComponent
24+ import kotlinx.coroutines.flow.Flow
25+ import kotlinx.coroutines.flow.flow
26+ import java.util.concurrent.ExecutorService
27+ import java.util.concurrent.Executors
28+ import java.util.concurrent.TimeUnit
29+ import javax.inject.Singleton
30+
31+ @Module
32+ @InstallIn(SingletonComponent ::class )
33+ object CameraModule {
34+ private val TAG = CameraModule ::class .java.simpleName
35+ private var cameraExecutorService : ExecutorService ? = null
36+
37+
38+ // CameraX ImageAnalyzer용 백그라운드 서비스
39+ @Provides
40+ @Singleton
41+ fun clearCameraExecutor (): Boolean {
42+ cameraExecutorService?.shutdown()
43+ cameraExecutorService?.awaitTermination(Long .MAX_VALUE , TimeUnit .NANOSECONDS )
44+ cameraExecutorService = null
45+ return cameraExecutorService == null
46+ }
47+
48+ @Provides
49+ @Singleton
50+ fun provideCameraSelector (cameraIdx : Int ): CameraSelector {
51+ return CameraSelector .Builder ()
52+ .requireLensFacing(cameraIdx)
53+ .build()
54+ }
55+
56+ @Provides
57+ @Singleton
58+ fun provideCameraProvider (
59+ context : Context ,
60+ ): ProcessCameraProvider {
61+ return ProcessCameraProvider .getInstance(context).get()
62+ }
63+
64+ @OptIn(ExperimentalCamera2Interop ::class )
65+ @Provides
66+ @Singleton
67+ fun provideImageAnalysis (
68+ rotation : Int
69+ ): ImageAnalysis {
70+ val iaBuilder = ImageAnalysis .Builder ()
71+ .setBackpressureStrategy(ImageAnalysis .STRATEGY_KEEP_ONLY_LATEST )
72+ .setOutputImageFormat(ImageAnalysis .OUTPUT_IMAGE_FORMAT_RGBA_8888 )
73+ .setTargetRotation(rotation)
74+ .setTargetAspectRatio(AspectRatio .RATIO_4_3 )
75+ return iaBuilder.build()
76+ }
77+
78+ @Provides
79+ @Singleton
80+ fun provideCameraExecutor (): ExecutorService {
81+ if (cameraExecutorService == null ){
82+ cameraExecutorService = Executors .newSingleThreadExecutor()
83+ }
84+ return cameraExecutorService!!
85+ }
86+
87+ fun shutdown (){
88+ if (cameraExecutorService != null ) {
89+ cameraExecutorService?.shutdown()
90+ cameraExecutorService?.awaitTermination(Long .MAX_VALUE , TimeUnit .NANOSECONDS )
91+ cameraExecutorService = null
92+ }
93+ }
94+
95+ @Provides
96+ @Singleton
97+ fun provideCameraXConfig (): CameraXConfig {
98+ return CameraXConfig .Builder
99+ .fromConfig(Camera2Config .defaultConfig())
100+ .setMinimumLoggingLevel(Log .ERROR )
101+ .build()
102+ }
103+
104+ @Provides
105+ @Singleton
106+ fun provideCameraStatus (): Flow <Boolean > = flow {
107+ emit(cameraExecutorService != null )
108+ }
109+
110+ // 미디어 파이프 제공하기 위함
111+ // @Provides
112+ // @Singleton
113+ // fun provideMPImageAnalyzer(
114+ // handLandMarker: HandLandmarker,
115+ // setCameraFrame: (Bitmap) -> Unit,
116+ // cameraCropScale: Float = DEFAULT_CROP_SCALE,
117+ // drawCameraInIndicator: Boolean = false
118+ // ) = ImageAnalysis.Analyzer{ imageProxy ->
119+ // val frameTime = SystemClock.uptimeMillis()
120+ // // Copy out RGB bits from the frame to a bitmap buffer
121+ // val bitmapBuffer =
122+ // Bitmap.createBitmap(
123+ // imageProxy.width,
124+ // imageProxy.height,
125+ // Bitmap.Config.ARGB_8888
126+ // )
127+ // imageProxy.use { bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer) }
128+ // imageProxy.close()
129+ // val newWidth = imageProxy.width / cameraCropScale
130+ // val newHeight = imageProxy.height / cameraCropScale
131+ // val newX = ( imageProxy.width - newWidth ) / 2
132+ // val newY = ( imageProxy.height - newHeight ) / 2
133+ // // if crop scale = 1.0f , not use new bitmap
134+ // var crop = bitmapBuffer
135+ // if ( cameraCropScale > 1.5f ) {
136+ // crop = Bitmap.createBitmap( bitmapBuffer, newX.toInt(), newY.toInt(), newWidth.toInt(), newHeight.toInt() )
137+ // }
138+ //
139+ // // Convert the input Bitmap object to an MPImage object to run inference
140+ // val mpImage = BitmapImageBuilder(crop).build()
141+ // handLandMarker.detectAsync(mpImage, frameTime)
142+ // }
143+ }
0 commit comments