即时切换后置/前置摄像头
Posted
技术标签:
【中文标题】即时切换后置/前置摄像头【英文标题】:switch back/front camera on fly 【发布时间】:2011-09-29 18:40:23 【问题描述】:如果我只使用 CAMERA_FACING_BACK
或 CAMERA_FACING_FRONT
一切正常。
我在从 CAMERA_FACING_BACK
切换到 CAMERA_FACING_FRONT
时遇到问题。
我的代码sn-p:
public class PhotoCameraActivity extends Activity implements OnClickListener
private SurfaceView cameraView;
private Button turnButton;
private Camera camera = null;
private Callback listener;
private static int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_camera_main);
prepareActivity();
private void prepareActivity()
cameraView = (SurfaceView) findViewById(R.id.photo_camera_surface_view);
turnButton = (ImageButton) findViewById(R.id.turn_button);
turnButton.setOnClickListener(this);
@Override
public void onClick(View v)
if (v.equals(turnButton))
if (Camera.getNumberOfCameras() > 1 && camId < Camera.getNumberOfCameras() - 1)
startCamera(camId + 1);
else
startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
@Override
protected void onResume()
startCamera(camId);
super.onResume();
@Override
protected void onPause()
stopCamera();
super.onPause();
private void startCamera(int cameraId)
if (camera != null)
stopCamera();
holder = cameraView.getHolder();
listener = new Callback()
@Override
public void surfaceDestroyed(SurfaceHolder holder)
@Override
public void surfaceCreated(SurfaceHolder holder)
try
camera.setPreviewDisplay(holder);
camera.startPreview();
catch (IOException e)
e.printStackTrace();
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
;
holder.addCallback(listener);
camId = cameraId;
camera = Camera.open(cameraId);
Camera.Parameters params = camera.getParameters();
if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
params.setPreviewSize(1280, 800);
else
params.setPreviewSize(640, 480);
camera.setParameters(params);
private void stopCamera()
System.out.println("stopCamera method");
if (camera != null)
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
holder.removeCallback(listener);
holder = null;
【问题讨论】:
您遇到的“麻烦”的性质是什么? 如果我尝试停止相机,取景器会冻结并且不显示来自其他相机的图像。但是,如果我按“返回”然后再次启动此活动,相机会切换到前面,它会再次正常工作。我认为我在关闭相机和释放资源方面遇到了问题。 我遇到了同样的问题 一次只能打开一个摄像头,所以如果要切换摄像头,请先调用 camera.recycle() 此代码是wrong:… 摄像头朝向不一定与摄像头索引相同。例如,我的平板电脑只有一个摄像头(索引:0)但面向前方(面对索引:1)。因此使用像 Camera.open(CameraInfo.CAMERA_FACING_FRONT) 这样的简单代码是没有意义的 【参考方案1】:在我的活动的 onCreate() 中,我将以下 onClick 侦听器添加到覆盖在我的 Preview SurfaceView 上的按钮(网络上有许多示例用于预览):
ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1)
useOtherCamera.setVisibility(View.INVISIBLE);
else
useOtherCamera.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);
//Code snippet for this method from somewhere on android developers, i forget where
setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try
//this step is critical or preview on new camera will no know where to render to
camera.setPreviewDisplay(previewHolder);
catch (IOException e)
e.printStackTrace();
camera.startPreview();
在我的测试设备上,后置摄像头的 ID 为 0,前置摄像头的 ID 为 1。我建议使用 Camera.CameraInfo 静态变量作为摄像头 ID,而不是硬编码值。我确信这只会在其他设备上引起问题。
【讨论】:
+1 我错过了 camera.setPreviewDisplay(previewHolder); 此代码是wrong:… 摄像头朝向不一定与摄像头索引相同。例如,我的平板电脑只有一个摄像头(索引:0)但面向前方(面对索引:1)。因此使用像 Camera.open(CameraInfo.CAMERA_FACING_FRONT) 这样的简单代码是没有意义的 @AlexCohn 我不会说这段代码是错误的,事实上它工作得很好,并展示了如何停止摄像头并开始一个新的摄像头。程序员需要理解代码并根据自己的需要进行调整。 @Merlevede:这段代码在非常具体的意义上是错误。请把我的评论读到最后,我不反对相机停止和重启的方式(尽管这不是最佳的,所以如果你想学习最佳实践,请随时搜索或询问)。 @Alex Cohn,您能否说明一下这样做的正确方法是什么?【参考方案2】:我使用 cameraId = 2 重新启动 Activity,这可以正常工作。
【讨论】:
@Dmitriy_Boichenko..我也面临同样的问题..你能分享你的代码吗? 如何在按钮点击时重启活动 任何尝试过这个答案的人都应该记住,几年前这可能在一些未指定的设备上工作。这不是 cameraId 预期的行为方式。【参考方案3】:我在布局中删除并重新添加了 SurfaceView,所以它起作用了。
public void switchCamera(int cameraType)
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT))
if(Camera.getNumberOfCameras() > cameraType)
// Set selected camera
this.cameraType = cameraType;
else
// Set default camera (Rear)
this.cameraType = Camera.CameraInfo.CAMERA_FACING_BACK;
if(mCamera != null)
// Destroy previuos Holder
surfaceDestroyed(holder);
holder.removeCallback(this);
// Remove and re-Add SurfaceView
ViewGroup rootLayout = (ViewGroup) surface.getParent();
rootLayout.removeView(surface);
surface = new SurfaceView(context);
holder = surface.getHolder();
holder.addCallback(this);
rootLayout.addView(surface, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
【讨论】:
我确实忘记删除视图所以我无法看到切换的相机视图。感谢这有帮助【参考方案4】:在添加新的之前,我必须删除表面预览:
if (mPreview != null)
mPreview.surfaceDestroyed(mPreview.getHolder());
mPreview.getHolder().removeCallback(mPreview);
mPreview.destroyDrawingCache();
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_frame);
preview.removeView(mPreview);
mPreview.mCamera = null;
mPreview = null;
//then add your preview
【讨论】:
【参考方案5】:使用此代码:
if (mCamera != null)
mCamera.stopPreview();
mCamera.release();
mCamera = null;
//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;
try
mCamera = Camera.open(currentCameraId);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
catch (Exception e) e.printStackTrace();
【讨论】:
此代码是wrong:… 摄像头朝向不一定与摄像头索引相同。例如,我的平板电脑只有一个摄像头(索引:0)但面向前方(面对索引:1)。因此使用像 Camera.open(CameraInfo.CAMERA_FACING_FRONT) 这样的简单代码是没有意义的【参考方案6】:尝试使用这个:
camera.stopPreview();
if(camera != null)
camera.release();
try
camera = Camera.open(/*new id*/);
camera.setPreviewDisplay(holder);
camera.startPreview();
catch (Exception ex) ex.printStackTrace();
【讨论】:
以上是关于即时切换后置/前置摄像头的主要内容,如果未能解决你的问题,请参考以下文章
android Camera如何判断当前使用的摄像头是前置还是后置