Camera2 implementation fails with any tutorial I follow

0

I'm pretty new to programming with Kotlin, and I'm trying to make an app that takes videos. I tried following the steps outlined here and here, but in both cases I'm getting the same unknown error from Android Studio (shown in this image - exit code 1073741819 (0xC0000005)). I'm not sure what I'm doing wrong, but I don't even know where to begin to solve my problem. I have a decent computer and both my RAM and GPU aren't in use before I run this code, so I don't think it's a hardware issue. Here is my code for both tutorials:

First tutorial (uses a TextureView):

    class CameraActivity : AppCompatActivity()
    {
        // JLELSE CODE
        private val CAMERA_REQUEST_CODE = 200
        private var cameraManager: CameraManager? = null
        private var cameraFacing: Int = 0
        private var surfaceTextureListener: TextureView.SurfaceTextureListener? = null
        private var previewSize: Size? = null
        private var cameraId: String = ""
        private var backgroundThread: HandlerThread? = null
        private var backgroundHandler: Handler? = null
        private var cameraDevice: CameraDevice? = null
        private var captureRequestBuilder: CaptureRequest.Builder? = null
        private var captureRequest: CaptureRequest? = null
        private var cameraCaptureSession: CameraCaptureSession? = null

        override fun onCreate(savedInstanceState: Bundle?)
        {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_camera)

            // JLELSE CODE
            ActivityCompat.requestPermissions(this, Array<String>(1) { Manifest.permission.CAMERA }, this.CAMERA_REQUEST_CODE)

            this.cameraManager = getSystemService(Context.CAMERA_SERVICE) as? CameraManager
            this.cameraFacing = CameraCharacteristics.LENS_FACING_BACK

            surfaceTextureListener = object: TextureView.SurfaceTextureListener
            {
                override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int)
                {
                    //Log.d(TAG, "width: $width height: $height")

                    setUpCamera()
                    openCamera()
                }

                override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int)
                {

                }

                override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean
                {
                    return false
                }

                override fun onSurfaceTextureUpdated(surface: SurfaceTexture?)
                {

                }
            }
        }

        private fun setUpCamera()
        {
            try
            {
                for (cameraId in cameraManager?.cameraIdList!!)
                {
                    var cameraCharacteristics = cameraManager!!.getCameraCharacteristics(cameraId)

                    if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == cameraFacing)
                    {
                        var streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

                        this.previewSize = streamConfigurationMap?.getOutputSizes(SurfaceTexture::class.java)?.get(0)

                        this.cameraId = cameraId
                    }
                }
            }
            catch (e: CameraAccessException)
            {
                e.printStackTrace()
            }
        }

        private fun openCamera()
        {
            try
            {
                if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
                {
                    cameraManager?.openCamera(cameraId, object: CameraDevice.StateCallback()
                    {
                        override fun onOpened(cameraDevice: CameraDevice) {
                            this@CameraActivity.cameraDevice = cameraDevice
                            createPreviewSession()
                        }

                        override fun onDisconnected(cameraDevice: CameraDevice) {
                            cameraDevice.close()
                            this@CameraActivity.cameraDevice = null
                        }

                        override fun onError(cameraDevice: CameraDevice, error: Int) {
                            cameraDevice.close()
                            this@CameraActivity.cameraDevice = null
                        }
                    }, backgroundHandler)
                }

            }
            catch (e: CameraAccessException)
            {
                e.printStackTrace()
            }
        }

        private fun openBackgroundThread()
        {
            backgroundThread = object: HandlerThread("camera_background_thread") { }
            (backgroundThread as HandlerThread).start()
            backgroundHandler = object: Handler((backgroundThread as HandlerThread).looper) { }
        }

        override fun onResume()
        {
            super.onResume()
            openBackgroundThread()

            if (textureView.isAvailable)
            {
                setUpCamera()
                openCamera()
            }
            else
            {
                textureView.surfaceTextureListener = surfaceTextureListener
            }
        }

        override fun onStop()
        {
            super.onStop()

            closeCamera()
            closeBackgroundThread()
        }

        private fun closeCamera()
        {
            if (cameraCaptureSession != null)
            {
                cameraCaptureSession!!.close()
                cameraCaptureSession = null
            }

            if (cameraDevice != null)
            {
                cameraDevice!!.close()
                cameraDevice = null
            }
        }

        private fun closeBackgroundThread()
        {
            if (backgroundHandler != null)
            {
                backgroundThread!!.quitSafely()
                backgroundThread = null
                backgroundHandler = null
            }
        }

        private fun createPreviewSession()
        {
            try
            {
                var surfaceTexture = textureView.surfaceTexture
                surfaceTexture.setDefaultBufferSize(previewSize!!.width, previewSize!!.height)

                var previewSurface = object: Surface(surfaceTexture) {}
                captureRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
                captureRequestBuilder!!.addTarget(previewSurface)

                cameraDevice!!.createCaptureSession(mutableListOf(previewSurface) as List<Surface>, object: CameraCaptureSession.StateCallback()
                {
                    override fun onConfigured(cameraCaptureSession: CameraCaptureSession)
                    {
                        if (cameraDevice == null)
                        {
                            return
                        }

                        try
                        {
                            captureRequest = captureRequestBuilder!!.build()
                            this@CameraActivity.cameraCaptureSession = cameraCaptureSession
                            this@CameraActivity.cameraCaptureSession!!.setRepeatingRequest(captureRequest!!, null, backgroundHandler)
                        }
                        catch (e: Exception)
                        {
                            e.printStackTrace()
                        }
                    }

                    override fun onConfigureFailed(session: CameraCaptureSession)
                    {
                        //TODO("Not yet implemented")
                    }
                }, backgroundHandler)
            }
            catch (e: Exception)
            {
                e.printStackTrace()
            }
        }
    }

Second tutorial (uses SurfaceView):

/** Helper to ask camera permission. */
    object CameraPermissionHelper
    {
        private const val CAMERA_PERMISSION_CODE = 0
        private const val CAMERA_PERMISSION = Manifest.permission.CAMERA

        /** Check to see we have the necessary permissions for the app. */
        fun hasCameraPermission(activity: Activity): Boolean
        {
            return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) == PackageManager.PERMISSION_GRANTED
        }

        /** Check to see we have the necessary permissions for the app, and ask them if we don't. */
        fun requestCameraPermission(activity: Activity)
        {
            ActivityCompat.requestPermissions(activity, arrayOf(CAMERA_PERMISSION), CAMERA_PERMISSION_CODE)
        }

        /** Check to see if we need to show the rationale for this permission. */
        fun shouldShowRequestPermissionRationale(activity: Activity): Boolean
        {
            return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION)
        }

        /** Launch Application Setting to grant permission. */
        fun launchPermissionSettings(activity: Activity)
        {
            val intent = Intent()
            intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
            intent.data = Uri.fromParts("package", activity.packageName, null)

            activity.startActivity(intent)
        }
    }

    // MEDIUM CODE
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray )
    {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if (!CameraPermissionHelper.hasCameraPermission(this))
        {
            Toast.makeText(this, "Camera permission is needed to run this application", Toast.LENGTH_LONG).show()

            if (!CameraPermissionHelper.shouldShowRequestPermissionRationale((this)))
            {
                // Permission denied with checking "Do not ask again."
                CameraPermissionHelper.launchPermissionSettings(this)
            }

            finish()
        }

        recreate()
    }

    // MEDIUM CODE
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_camera)


        if (!CameraPermissionHelper.hasCameraPermission(this))
        {
            CameraPermissionHelper.requestCameraPermission(this)

            return
        }

        surfaceView.holder.addCallback(surfaceReadyCallback)
    }

    // MEDIUM CODE
    private fun startCameraSession()
    {
        val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager

        if (cameraManager.cameraIdList.isEmpty())
        {
            // no cameras
            return
        }

        val firstCamera = cameraManager.cameraIdList[0]

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
        {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return
        }
        cameraManager.openCamera(firstCamera, object: CameraDevice.StateCallback()
        {
            override fun onDisconnected(cameraDevice: CameraDevice)
            {
                //cameraDevice.close()
                //CameraActivity.this.cameraDevice = null
            }

            override fun onError(cameraDevice: CameraDevice, error: Int)
            {
                //cameraDevice.close()
                //CameraActivity.this.cameraDevice = null
            }

            override fun onOpened(cameraDevice: CameraDevice)
            {
                // use the camera
                val cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraDevice.id)

                cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]?.let { streamConfigurationMap ->
                    streamConfigurationMap.getOutputSizes(ImageFormat.YUV_420_888)?.let { yuvSizes ->
                        val previewSize = yuvSizes.last() // lowest resolution size

                        val displayRotation = windowManager.defaultDisplay.rotation

                        val swappedDimensions = areDimensionsSwapped(displayRotation, cameraCharacteristics)

                        // swap width and height if needed
                        val rotatedPreviewWidth = if (swappedDimensions) previewSize.height else previewSize.width
                        val rotatedPreviewHeight = if (swappedDimensions) previewSize.width else previewSize.height

                        surfaceView.holder.setFixedSize(rotatedPreviewWidth, rotatedPreviewHeight)

                        val previewSurface = surfaceView.holder.surface

                        val captureCallback = object: CameraCaptureSession.StateCallback()
                        {
                            override fun onConfigureFailed(session: CameraCaptureSession)
                            {
                                //TODO("Not yet implemented")
                            }

                            override fun onConfigured(session: CameraCaptureSession)
                            {
                                /*
                                if (cameraDevice == null)
                                {
                                    return
                                }
                                */
                                // session configured
                                val previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
                                    addTarget(previewSurface)
                                }

                                session.setRepeatingRequest(previewRequestBuilder.build(), object: CameraCaptureSession.CaptureCallback() {}, Handler { true })
                            }
                        }

                        cameraDevice.createCaptureSession(mutableListOf(previewSurface), captureCallback, Handler { true })

                    }
                }
            }
        }, Handler { true })
    }

    // MEDIUM CODE
    private fun areDimensionsSwapped(displayRotation: Int, cameraCharacteristics: CameraCharacteristics): Boolean
    {
        var swappedDimensions = false

        when (displayRotation)
        {
            Surface.ROTATION_0, Surface.ROTATION_180 ->
            {
                if (cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) == 90 || cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) == 270)
                {
                    swappedDimensions = true
                }
            }

            Surface.ROTATION_90, Surface.ROTATION_270 ->
            {
                if (cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) == 0 || cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) == 180)
                {
                    swappedDimensions = true
                }
            }

            else ->
            {
                // invalid display rotation
            }
        }

        return swappedDimensions
    }

    // MEDIUM CODE
    private val surfaceReadyCallback = object: SurfaceHolder.Callback
    {
        override fun surfaceChanged( holder: SurfaceHolder?, format: Int, width: Int, height: Int)
        {

        }

        override fun surfaceDestroyed(holder: SurfaceHolder?)
        {

        }

        override fun surfaceCreated(holder: SurfaceHolder?)
        {
            startCameraSession()
        }
    }
android
kotlin
runtime-error
android-camera2
asked on Stack Overflow Apr 23, 2020 by Ibrahim Mahmoud • edited Apr 23, 2020 by Ibrahim Mahmoud

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0