it-swarm.com.de

Android: Kamera wechseln, wenn auf die Schaltfläche geklickt wird

Ich habe eine Methode namens switchCamera. Ich versuche, die Kamera per Knopfdruck in einem fließenden Übergang von vorne nach hinten umzuschalten. Meine Anwendung reagiert nicht mehr, wenn ich diese Methode aufrufe. Ich weiß, dass ich etwas nicht richtig mache. Kann mir hier jemand helfen?

Jede Hilfe wird sehr geschätzt.

public void switchCamera(){
    int camNum = 0;
    camNum = Camera.getNumberOfCameras();
    int camBackId = Camera.CameraInfo.CAMERA_FACING_BACK;
    int camFrontId = Camera.CameraInfo.CAMERA_FACING_FRONT;

    Camera.CameraInfo currentCamInfo = new Camera.CameraInfo();

    //if camera is running
    if (camera != null){
        //and there is more than one camera
        if (camNum > 1){
            //stop current camera
            camera.stopPreview();
            camera.setPreviewCallback(null);
            //camera.takePicture(null, null, PictureCallback);
            camera.release();
            camera = null;
            //stop surfaceHolder?

            if (currentCamInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
                //switch camera to back camera
                camera=Camera.open(camBackId);
            }
            else{
                //switch camera to front camera
                camera=Camera.open(camFrontId);
            }
            //switch camera back on
            //specify surface?
            try {
                camera.setPreviewDisplay(surfaceHolder);
                camera.setPreviewCallback((PreviewCallback) this);
                camera.startPreview();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
37
LKB
Button otherCamera = (Button) findViewById(R.id.OtherCamera);

otherCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (inPreview) {
    camera.stopPreview();
}
//NB: if you don't release the current camera before switching, you app will crash
camera.release();

//swap the id of the camera to be used
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
    currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
    currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);

setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try {

    camera.setPreviewDisplay(previewHolder);
} catch (IOException e) {
    e.printStackTrace();
}
camera.startPreview();
}

Wenn Sie möchten, dass das Kamerabild in derselben Ausrichtung wie das Display angezeigt wird, können Sie den folgenden Code verwenden.

public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, Android.hardware.Camera camera) {
     Android.hardware.Camera.CameraInfo info =
             new Android.hardware.Camera.CameraInfo();
     Android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }
72
mjosh

Zuerst müssen Sie die SurfacePreview der vorherigen Kamera zerstören und dann ein neues Kameraobjekt erstellen (Rückseite/Vorderseite).

`//Code to destroy SurfacePreview
mPreview.surfaceDestroyed(mPreview.getHolder());
mPreview.getHolder().removeCallback(mPreview);
mPreview.destroyDrawingCache();
preview.removeView(mPreview);
mCamera.stopPreview();
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();

//Now create new camera object
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
    mCamera = Camera.open(camIdx);
    mPreview = new CameraPreview(CameraActivity.this, mCamera);
    preview.addView(mPreview);
    mCamera.setPreviewDisplay(mPreview.getHolder());
    mCamera.startPreview();
}`
5

Nach langer Suche kann ich endlich erfolgreich die Kamera wechseln. Die Antwort von mjosh ist eine nützliche Antwort, hat aber bei mir nicht funktioniert. Der Trick, den ich schließlich gefunden habe, ist, eine neue Klasse CameraPreview zu erstellen und sie erneut hinzuzufügen.

Hier ist meine Klasse CameraPreview.

@SuppressLint("ViewConstructor")
class CameraPreview(context: Context?,
                    private var camera: Camera,
                    private val displayRotation: Int) : SurfaceView(context), SurfaceHolder.Callback {
    companion object {
        private const val TAG = "TAG"
        private const val FOCUS_AREA_SIZE = 300
    }

    val surfaceHolder: SurfaceHolder = holder
    private var previewSize: Camera.Size? = null
    private val supportedPreviewSizes: MutableList<Camera.Size>?

    init {
        surfaceHolder.addCallback(this)
        supportedPreviewSizes = camera.parameters.supportedPreviewSizes
    }

    private val surfaceViewTouchListener: View.OnTouchListener = OnTouchListener { v, event ->
        camera.cancelAutoFocus()
        val focusRect = calculateFocusArea(event.x, event.y)
        val parameters = camera.parameters
        if (parameters.focusMode == Camera.Parameters.FOCUS_MODE_AUTO) {
            parameters.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
        }
        if (parameters.maxNumFocusAreas > 0) {
            val areaList = ArrayList<Camera.Area>()
            areaList.add(Camera.Area(focusRect, 1000))
            parameters.focusAreas = areaList
        }
        try {
            camera.cancelAutoFocus()
            camera.parameters = parameters
            camera.startPreview()
            camera.autoFocus { _, cam ->
                if (cam.parameters.focusMode == Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
                    val parameters = cam.parameters;
                    parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE
                    if (parameters.maxNumFocusAreas > 0) {
                        parameters.focusAreas = null
                    }
                    camera.parameters = parameters
                    camera.startPreview()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        [email protected] true
    }

    override fun surfaceCreated(holder: SurfaceHolder?) {
        setOnTouchListener(surfaceViewTouchListener)
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            camera.setPreviewDisplay(holder)
            camera.setDisplayOrientation(displayRotation)
            camera.startPreview()
        } catch (e: IOException) {
            Log.d(TAG, "Error setting camera preview: " + e.message)
        }
    }

    override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (holder?.surface == null) {
            // preview surface does not exist
            return
        }
        // stop preview before making changes
        try {
            camera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }
        // set preview size and make any resize, rotate or
        // reformatting changes here
        // start preview with new settings
        try {
            val parameters = camera.parameters
            val bestPictureSize = getBestPictureSize(width, height, parameters)
            bestPictureSize?.let {
                parameters.setPictureSize(it.width, it.height)
            }
            previewSize?.let {
                parameters.setPreviewSize(it.width, it.height)
            }

            camera.parameters = parameters
            camera.setPreviewDisplay(holder)
            camera.startPreview()
        } catch (e: Exception) {
            Log.d(TAG, "Error starting camera preview: " + e.message)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = View.resolveSize(suggestedMinimumWidth, widthMeasureSpec)
        val height = View.resolveSize(suggestedMinimumHeight, heightMeasureSpec)
        setMeasuredDimension(width, height)
        if (supportedPreviewSizes != null) {
            previewSize = getOptimalPreviewSize(supportedPreviewSizes, width, height)
        }
    }

    private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, w: Int, h: Int): Camera.Size? {
        val ASPECT_TOLERANCE = 0.1
        val targetRatio = h.toDouble() / w
        if (sizes == null) return null
        var optimalSize: Camera.Size? = null
        var minDiff = Java.lang.Double.MAX_VALUE
        for (size in sizes) {
            val ratio = size.width.toDouble() / size.height
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue
            if (Math.abs(size.height - h) < minDiff) {
                optimalSize = size
                minDiff = Math.abs(size.height - h).toDouble()
            }
        }
        if (optimalSize == null) {
            minDiff = Java.lang.Double.MAX_VALUE
            for (size in sizes) {
                if (Math.abs(size.height - h) < minDiff) {
                    optimalSize = size
                    minDiff = Math.abs(size.height - h).toDouble()
                }
            }
        }
        return optimalSize
    }

    override fun surfaceDestroyed(holder: SurfaceHolder?) {
        // no-op
    }

    private fun getBestPictureSize(width: Int, height: Int, parameters: Camera.Parameters): Camera.Size? {
        var bestSize: Camera.Size?
        val sizeList = parameters.supportedPictureSizes
        bestSize = sizeList[0]
        for (i in 1 until sizeList.size) {
            if (sizeList[i].width * sizeList[i].height > bestSize!!.width * bestSize.height) {
                bestSize = sizeList[i]
            }
        }
        return bestSize
    }

    private fun calculateFocusArea(x: Float, y: Float): Rect {
        val left = clamp(Java.lang.Float.valueOf(x / width * 2000 - 1000).toInt(), FOCUS_AREA_SIZE)
        val top = clamp(Java.lang.Float.valueOf(y / height * 2000 - 1000).toInt(), FOCUS_AREA_SIZE)
        return Rect(left, top, left + FOCUS_AREA_SIZE, top + FOCUS_AREA_SIZE)
    }

    private fun clamp(touchCoordinateInCameraReper: Int, focusAreaSize: Int): Int {
        return if (Math.abs(touchCoordinateInCameraReper) + focusAreaSize / 2 > 1000) {
            if (touchCoordinateInCameraReper > 0) {
                1000 - focusAreaSize / 2
            } else {
                -1000 + focusAreaSize / 2
            }
        } else {
            touchCoordinateInCameraReper - focusAreaSize / 2
        }
    }

    fun turnFlashOnOrOff() {
        try {
            camera.stopPreview()
        } catch (e: Exception) {
            // ignore
        }

        val params = camera.parameters
        params?.let {
            if (params.flashMode == Camera.Parameters.FLASH_MODE_TORCH) {
                params.flashMode = Camera.Parameters.FLASH_MODE_OFF
                //flash.setImageResource(R.mipmap.baseline_flash_off_white_24dp)
            } else {
                params.flashMode = Camera.Parameters.FLASH_MODE_TORCH
                //flash.setImageResource(R.mipmap.baseline_flash_on_white_24dp)
            }
            camera.setPreviewDisplay(holder)
            try {
                camera.parameters = params
            } catch (e: Exception) {
                e.printStackTrace()
            }
            camera.startPreview()
        }
    }
}

Meine openCamera Methode, mit der ich die Kamera öffne:

private fun openCamera() {
        camera = CameraUtil.getCameraInstance(getCameraId())
        rotation = getDisplayRotation()
        cameraPreview = CameraPreview(activity, camera!!, rotation)
        fl_camera.addView(cameraPreview)
    }

Bevor Sie CameraPreview erstellen, müssen Sie die Drehung der Kamera berechnen und als displayOrientation festlegen.

private fun getDisplayRotation(): Int {
        val info = Camera.CameraInfo()
        Camera.getCameraInfo(getCameraId(), info)
        val rotation = activity.windowManager.defaultDisplay.rotation
        var degrees = 0
        when (rotation) {
            Surface.ROTATION_0 -> degrees = 0
            Surface.ROTATION_90 -> degrees = 90
            Surface.ROTATION_180 -> degrees = 180
            Surface.ROTATION_270 -> degrees = 270
        }

        var result: Int
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degrees) % 360
            result = (360 - result) % 360 // compensate the mirror
        } else { // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        return result
    }

Und ich erhalte cameraId wie folgt:

private fun getCameraId(): Int {
        val numberOfCameras = Camera.getNumberOfCameras()
        var cameraInfo: Camera.CameraInfo
        for (i in 0 until numberOfCameras) {
            cameraInfo = Camera.CameraInfo()
            Camera.getCameraInfo(i, cameraInfo)
            if (cameraInfo.facing == currentCamera) {
                return i
            }
        }
        return 0
    }

Und zum Schluss funktioniert mein SwtichCamera Button so:

switch_camera.setOnClickListener {
            try {
                camera?.stopPreview()
            } catch (e: Exception) {
                e.printStackTrace()
            }


            camera?.release()


           currentCamera = if (currentCamera === Android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
                Camera.CameraInfo.CAMERA_FACING_FRONT
            } else {
                Camera.CameraInfo.CAMERA_FACING_BACK
            }

            fl_camera.removeView(cameraPreview)
            openCamera()
        }

Dies ist eine funktionierende Lösung für mich. Ich hoffe das hilft dir auch ein paar anderen.

Bearbeiten: Die Kameravorschau kann bei Samsung-Geräten ein Problem darstellen. Hier ist eine alternative Methode, um die beste Vorschaugröße zu erhalten.

private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, w: Int, h: Int): Camera.Size? {

        if (sizes == null) return null

        var optimalSize: Camera.Size? = null
        val ratio = h.toDouble() / w
        var minDiff = Java.lang.Double.MAX_VALUE
        var newDiff: Double
        for (size in sizes) {
            newDiff = Math.abs(size.width.toDouble() / size.height - ratio)
            if (newDiff < minDiff) {
                optimalSize = size
                minDiff = newDiff
            }
        }
        return optimalSize
    }
1
savepopulation