Java 安卓:点击按钮时切换摄像头
我有一个叫做switchCamera的方法,我试着在一个平滑的过渡中,点击一个按钮,从前面切换到后面。当我调用这个方法时,我的应用程序冻结了——我知道我做的事情不对。有人能帮我吗 非常感谢您的帮助Java 安卓:点击按钮时切换摄像头,java,android,button,camera,Java,Android,Button,Camera,我有一个叫做switchCamera的方法,我试着在一个平滑的过渡中,点击一个按钮,从前面切换到后面。当我调用这个方法时,我的应用程序冻结了——我知道我做的事情不对。有人能帮我吗 非常感谢您的帮助 public void switchCamera(){ int camNum = 0; camNum = Camera.getNumberOfCameras(); int camBackId = Camera.CameraInfo.CAMERA_FACING_BACK;
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();
}
}
}
}
如果要使摄影机图像以与相同的方向显示
显示时,可以使用以下代码
首先,您需要销毁以前相机的表面预览,然后需要创建相机的新对象(后/前)
经过长时间的搜索,我终于成功地切换了相机。mjosh的回答是一个有用的答案,但对我来说并不奏效。我最后发现的诀窍是创建新的
CameraPreview
类并再次添加它
这是我的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()
}
return@OnTouchListener 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()
}
}
}
在创建CameraPreview
之前,必须计算摄像机的旋转,并将其设置为displayOrientation
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
}
我得到如下cameraId
:
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
}
最后,我的SwtichCamera
按钮是这样工作的:
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()
}
这对我来说是一个有效的解决方案。我希望这也能对你和其他人有所帮助
编辑:相机预览可能是三星设备的问题。下面是获得最佳预览大小的另一种方法
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
}
private fun getoptimalizepreviewSize(大小:List?,w:Int,h:Int):相机。大小?{
if(size==null)返回null
变量大小:摄影机。大小?=null
val比率=h.toDouble()/w
var minDiff=java.lang.Double.MAX_值
var newDiff:双
用于(以大小为单位){
newDiff=Math.abs(size.width.toDouble()/size.height-ratio)
if(newDiff
这可能会有帮助:您能在logcat冻结之前在它中粘贴一些日志吗?完整回答,但有一个问题…Camera.CameraInfo.Camera\u face\u BACK/FRONT需要API级别9。在旧版本中我们该怎么办?我的相机图片在纵向模式下仍然没有正确旋转。在横向模式下,它工作得很好。太棒了-你刚刚用这个漂亮的定位方法为我节省了很多时间!您在哪里设置了currentCameraId
?@ryderdcurrentCameraId
是在活动中设置的任意变量,用于跟踪当前设置。可以将其设置为分配给整个活动的私有变量,也可以将其设置为同一方法内的变量(如果在其他地方未使用)。
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
}
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
}
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()
}
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
}