jiangdongguo / AndroidUSBCamera

🔥🔥🔥Flexible and useful UVC camera engine on Android platform, supporting multi-road cameras!
https://juejin.cn/post/7115229806844706847
Apache License 2.0
2.35k stars 802 forks source link

can this library be used with jetpack compose? #455

Closed shanerodrigues closed 2 years ago

shanerodrigues commented 2 years ago

Hello, I'm new to android development. I have a jetpack compose project and want to use AUSBC to use my external camera in the app to take photos. Is it possible to use AUSBC with jetpack compose? If so, can you provide some info on how to do it?

jiangdongguo commented 2 years ago

Maybe, it can, but I haven't learn about jetpack compose.

shanerodrigues commented 2 years ago

Ok, thanks for your help.

jiangdongguo commented 2 years ago

It's ok!

Luke-Tang commented 2 years ago

Yes, it can. I am using it in compose.

shanerodrigues commented 2 years ago

@Luke-Tang, thanks for letting me know! I would really appreciate it if you could provide an example of how you did it.

Luke-Tang commented 2 years ago

@shanerodrigues The code is roughly as follows, remember grant camera permission.

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            YourAppTheme(darkTheme = true) {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    YourApp()
                }
            }
        }
    }
}

@Composable
fun rememberCameraClient(context: Context): CameraClient = remember {
    CameraClient.newBuilder(context).apply {
        setEnableGLES(true)
        setRawImage(false)
        setCameraStrategy(CameraUvcStrategy(context))
        setCameraRequest(
            CameraRequest.Builder()
                .setFrontCamera(true)
                .setPreviewWidth(960)
                .setPreviewHeight(720)
                .create()
        )
        openDebug(true)
    }.build()
}

@Composable
fun YourApp() {
    val context = LocalContext.current
    Box(modifier = Modifier.fillMaxSize()) {
        UVCCameraPreview(rememberCameraClient(context))
    }
}

@Composable
fun UVCCameraPreview(cameraClient : CameraClient) {
    AndroidView(
        factory = { ctx ->
            AspectRatioSurfaceView(ctx).apply {
                this.holder.addCallback(object : Callback {
                    override fun surfaceCreated(holder: SurfaceHolder) {
                        cameraClient.openCamera(this@apply)
                    }

                    override fun surfaceChanged(
                        holder: SurfaceHolder,
                        format: Int,
                        width: Int,
                        height: Int
                    ) {
                        cameraClient.setRenderSize(width, height)
                    }

                    override fun surfaceDestroyed(holder: SurfaceHolder) {
                        cameraClient.closeCamera()
                    }
                })
            }
        }
    ) {

    }
}
shanerodrigues commented 2 years ago

@Luke-Tang, thank you very much for your help. I've got it working perfectly! in case anyone wants a working compose version, here's the link to the repo https://github.com/shanerodrigues/compose-uvc-camera

shanerodrigues commented 2 years ago

@Luke-Tang one last question, if you don't mind. I'm not sure how to implement captureImage. I've got this code, any tips on how to do it?

fun YourApp() {

    var cClient = rememberCameraClient(LocalContext.current)

    val context = LocalContext.current
    Box(modifier = Modifier.fillMaxSize()) {
        UVCCameraPreview(rememberCameraClient(context))
        Column(
            modifier = Modifier.fillMaxSize(),
            verticalArrangement = Arrangement.Bottom,
            horizontalAlignment = Alignment.CenterHorizontally,
        ){
            Button(onClick={clickPhoto(cClient)}){
                Text("Take Picture")
            }
        }

    }

}

fun clickPhoto(cameraClient : CameraClient){
    Log.i("check", "inside click photo")
    ToastUtils.show("inside click photo")
    cameraClient?.captureImage(object : ICaptureCallBack {

        override fun onBegin() {
            ToastUtils.show("OnBegin")
            Log.i(TAG, "onBegin")
        }

        override fun onError(error: String?) {
            ToastUtils.show(error ?: "未知异常")
            Log.i(TAG, "onError")
        }

        override fun onComplete(path: String?) {
            ToastUtils.show("OnComplete")
            Log.i(TAG, "onComplete")
        }
    })
}
Luke-Tang commented 2 years ago

@shanerodrigues Yes, that's correct. You may be pay attention to storage permision, especially target version greater than android10. The build target of this library is 27。

shanerodrigues commented 2 years ago

@Luke-Tang would you know how to take a high-resolution photo? In rememberCameraClient I've set the resolution to 2592x1944 which my camera supports, but the photos are taken with the preview width of 800x600. Does it have something to do with the AspectRatioSurfaceView?

sheenhill commented 9 months ago

compose demo. From 3.2.9


class Test6Activity : ComponentActivity() {

    lateinit var client: MultiCameraClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        client = MultiCameraClient(this, object : IDeviceConnectCallBack {
            override fun onAttachDev(device: UsbDevice?) {
                LogUtil.d("onAttachDev >>> $device")
                if (device != null) {
                    LogUtil.d("device.id >>> ${device.productId}")
                }
                device ?: return
                if (mCameraMap.containsKey(device.productId)) {
                    return
                }
                CameraUVC(this@Test6Activity, device).apply {
                    mCameraMap[device.productId] = this
                    client.requestPermission(device)
                }
            }

            override fun onDetachDec(device: UsbDevice?) {
                LogUtil.d("onDetachDec >>> $device")
            }

            override fun onConnectDev(device: UsbDevice?, ctrlBlock: USBMonitor.UsbControlBlock?) {
                LogUtil.d("onConnectDev >>> $device")
                mCameraMap[device?.productId]?.apply {
                    setUsbControlBlock(ctrlBlock)
                }
            }

            override fun onDisConnectDec(
                device: UsbDevice?, ctrlBlock: USBMonitor.UsbControlBlock?
            ) {
                LogUtil.d("onDisConnectDec >>> $device")
            }

            override fun onCancelDev(device: UsbDevice?) {
                LogUtil.d("onCancelDev >>> $device")
            }

        })
        client.register()
        setContent {
            CloudCanteenPlusTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background
                ) {
                    MyApp()
                }
            }
        }
    }

    private val mCameraMap = hashMapOf<Int, MultiCameraClient.ICamera>()

    @Composable
    private fun MyApp() {
        Box(modifier = Modifier.fillMaxWidth()) {
            var device1 by remember {
                mutableStateOf<MultiCameraClient.ICamera?>(null)
            }
            LaunchedEffect(key1 = true, block = {
                delay(1000)
                device1 = mCameraMap[1002] // 1002 自己的摄像头
            })
            LogUtil.d("MyApp  device1 >>> $device1")
            device1?.let {
                UVCCameraPreview(
                    modifier = Modifier.fillMaxSize(),
                    it
                )
            }

        }
    }

    @Composable
    private fun UVCCameraPreview(
        modifier: Modifier = Modifier,
        cameraClient: MultiCameraClient.ICamera
    ) {
        Box(
            modifier = modifier
                .aspectRatio(4f / 3f)
        ) {
            AndroidView(factory = { ctx ->
                AspectRatioSurfaceView(ctx).apply {
                    this.holder.addCallback(object : SurfaceHolder.Callback {
                        override fun surfaceCreated(holder: SurfaceHolder) {
                            val request = CameraRequest.Builder()
                                .setPreviewWidth(640)
                                .setPreviewHeight(480)
                                .create()
                            cameraClient.openCamera(this@apply, request)
                            cameraClient.addPreviewDataCallBack(object : IPreviewDataCallBack {
                                override fun onPreviewData(
                                    data: ByteArray?,
                                    width: Int,
                                    height: Int,
                                    format: IPreviewDataCallBack.DataFormat
                                ) {
                                    //  data:4915207  width:1280  height:960  format:RGBA
                                    LogUtil.d("onPreviewData >>> data:${data?.size}  width:$width  height:$height  format:$format")
                                    // Receive Data
                                }
                            })
                        }

                        override fun surfaceChanged(
                            holder: SurfaceHolder, format: Int, width: Int, height: Int
                        ) {
                            cameraClient.setRenderSize(width, height)
                        }

                        override fun surfaceDestroyed(holder: SurfaceHolder) {
                            cameraClient.closeCamera()
                        }
                    })
                }
            }) {}
        }
    }
}