android.hardware.Camera

本文介绍如何使用Android Camera类进行图片和视频捕获,包括权限设置、预览显示、拍照及释放资源等步骤,并提供定制相机应用程序的方法。

1. android.hardware.Camera


The Camera class is used to set image capture settings, start/stop preview, snap pictures, and retrieve frames for encoding for video. This class is a client for the Camera service, which manages the actual camera hardware.

To access the device camera, you must declare theCAMERA permission in your Android Manifest. Also be sure to include the<uses-feature> manifest element to declare camera features used by your application. For example, if you use the camera and auto-focus feature, your Manifest should include the following:

 <uses-permission android:name="android.permission.CAMERA" />
 <uses-feature android:name="android.hardware.camera" />
 <uses-feature android:name="android.hardware.camera.autofocus" />

To take pictures with this class, use the following steps:

  1. Obtain an instance of Camera from open(int).
  2. Get existing (default) settings with getParameters().
  3. If necessary, modify the returned Camera.Parameters object and callsetParameters(Camera.Parameters).
  4. If desired, call setDisplayOrientation(int).
  5. Important: Pass a fully initializedSurfaceHolder tosetPreviewDisplay(SurfaceHolder). Without a surface, the camera will be unable to start the preview.
  6. Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture.
  7. When you want, call takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback) to capture a photo. Wait for the callbacks to provide the actual image data.
  8. After taking a picture, preview display will have stopped. To take more photos, callstartPreview() again first.
  9. Call stopPreview() to stop updating the preview surface.
  10. Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately inonPause() (and re-open() it inonResume()).

To quickly switch to video recording mode, use these steps:

  1. Obtain and initialize a Camera and start preview as described above.
  2. Call unlock() to allow the media process to access the camera.
  3. Pass the camera to setCamera(Camera). SeeMediaRecorder information about video recording.
  4. When finished recording, call reconnect() to re-acquire and re-lock the camera.
  5. If desired, restart preview and take more photos or videos.
  6. Call stopPreview() andrelease() as described above.

This class is not thread-safe, and is meant for use from one event thread. Most long-running operations (preview, focus, photo capture, etc) happen asynchronously and invoke callbacks as necessary. Callbacks will be invoked on the event threadopen(int) was called from. This class's methods must never be called from multiple threads at once.

Caution: Different Android-powered devices may have different hardware specifications, such as megapixel ratings and auto-focus capabilities. In order for your application to be compatible with more devices, you should not make assumptions about the device camera specifications.

Developer Guides

For more information about using cameras, read theCamera developer guide.

转自:http://developer.android.com/reference/android/hardware/Camera.html

2. Building a Camera App


Some developers may require a camera user interface that is customized to the look of their application or provides special features. Creating a customized camera activity requires more code than using an intent, but it can provide a more compelling experience for your users.

The general steps for creating a custom camera interface for your application are as follows:

  • Detect and Access Camera - Create code to check for the existence of cameras and request access.
  • Create a Preview Class - Create a camera preview class that extends SurfaceView and implements the SurfaceHolder interface. This class previews the live images from the camera.
  • Build a Preview Layout - Once you have the camera preview class, create a view layout that incorporates the preview and the user interface controls you want.
  • Setup Listeners for Capture - Connect listeners for your interface controls to start image or video capture in response to user actions, such as pressing a button.
  • Capture and Save Files - Setup the code for capturing pictures or videos and saving the output.
  • Release the Camera - After using the camera, your application must properly release it for use by other applications.

Camera hardware is a shared resource that must be carefully managed so your application does not collide with other applications that may also want to use it. The following sections discusses how to detect camera hardware, how to request access to a camera, how to capture pictures or video and how to release the camera when your application is done using it.

Caution: Remember to release the Camera object by calling the Camera.release() when your application is done using it! If your application does not properly release the camera, all subsequent attempts to access the camera, including those by your own application, will fail and may cause your or other applications to be shut down.

 

 

 

 

转自:http://developer.android.com/guide/topics/media/camera.html#custom-camera

 

 

 

 

 

 

 

<think>我们讨论的是AndroidCamera类的setPreviewTexture方法。这个方法用于将相机的预览画面输出到一个SurfaceTexture上。在Android中,Camera类(android.hardware.Camera)是旧版相机API,在API21之后被Camera2API取代。但在一些旧项目中仍然可能使用。setPreviewTexture方法签名:publicfinalvoidsetPreviewTexture(SurfaceTexturesurfaceTexture)throwsIOException作用:设置相机预览使用的SurfaceTexture。SurfaceTexture是一个可以在其他线程(如OpenGL线程)中更新和消费的纹理。使用步骤:1.获取Camera实例。2.设置相机参数(可选)。3.创建一个SurfaceTexture,并指定纹理ID(通常由OpenGL生成)。4.将SurfaceTexture设置给相机。5.开始预览。注意:由于Camera是旧API,需要处理很多细节,比如正确的生命周期处理、异常捕获等。下面是一个使用Camera和SurfaceTexture的示例代码:</think>### Android Camera setPreviewTexture 详解 `android.hardware.Camera.setPreviewTexture()` 是旧版 Camera API 中用于将相机预览输出到 SurfaceTexture 的关键方法。以下是如何正确使用它的全面指南: #### 核心概念 1. **SurfaceTexture**: - 将图像流作为 OpenGL ES 纹理消费的特殊对象 - 允许将相机预览绑定到 OpenGL ES 渲染管道 2. **setPreviewTexture() 作用**: - 将相机预览帧输出到指定的 SurfaceTexture - 替代传统的 `setPreviewDisplay()`(用于 SurfaceView) #### 完整实现代码 ```java import android.hardware.Camera; import android.graphics.SurfaceTexture; import android.opengl.GLES20; import android.util.Log; public class CameraPreviewHelper { private static final String TAG = "CameraPreview"; private Camera mCamera; private SurfaceTexture mPreviewTexture; private int mTextureId = -1; // 初始化相机和纹理 public void initCamera() { try { // 1. 打开相机(后置) mCamera = Camera.open(); // 2. 创建OpenGL纹理 int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); mTextureId = textures[0]; // 3. 配置纹理参数 GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureId); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); // 4. 创建SurfaceTexture绑定到纹理 mPreviewTexture = new SurfaceTexture(mTextureId); // 5. 设置相机参数 Camera.Parameters params = mCamera.getParameters(); // 设置预览尺寸(选择支持的尺寸) List<Camera.Size> sizes = params.getSupportedPreviewSizes(); Camera.Size optimalSize = getOptimalPreviewSize(sizes, ...); params.setPreviewSize(optimalSize.width, optimalSize.height); mCamera.setParameters(params); // 6. 设置预览纹理 mCamera.setPreviewTexture(mPreviewTexture); // 7. 设置帧可用回调 mPreviewTexture.setOnFrameAvailableListener(surfaceTexture -> { // 当新帧可用时调用 updateTexture(); }); // 8. 开始预览 mCamera.startPreview(); } catch (IOException e) { Log.e(TAG, "Error setting camera preview: " + e.getMessage()); } } // 获取最佳预览尺寸 private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int viewWidth, int viewHeight) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) viewWidth / viewHeight; if (sizes == null) return null; Camera.Size optimalSize = null; double minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - viewHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - viewHeight); } } if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Camera.Size size : sizes) { if (Math.abs(size.height - viewHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - viewHeight); } } } return optimalSize; } // 更新纹理(在渲染线程调用) public void updateTexture() { synchronized (this) { // 更新SurfaceTexture mPreviewTexture.updateTexImage(); // 获取变换矩阵 float[] mtx = new float[16]; mPreviewTexture.getTransformMatrix(mtx); // 将矩阵传递给着色器 // renderWithTexture(mTextureId, mtx); } } // 释放资源 public void releaseCamera() { if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } if (mPreviewTexture != null) { mPreviewTexture.release(); mPreviewTexture = null; } if (mTextureId != -1) { int[] textures = {mTextureId}; GLES20.glDeleteTextures(1, textures, 0); mTextureId = -1; } } } ``` #### 关键步骤详解 1. **创建 OpenGL ES 纹理**: - 使用 `glGenTextures()` 生成纹理 ID - 必须绑定为 `GL_TEXTURE_EXTERNAL_OES` 类型(特殊扩展纹理) 2. **配置 SurfaceTexture**: ```java mPreviewTexture = new SurfaceTexture(mTextureId); mPreviewTexture.setOnFrameAvailableListener(surfaceTexture -> { // 通知渲染器有新帧 }); ``` 3. **设置相机预览纹理**: ```java try { mCamera.setPreviewTexture(mPreviewTexture); } catch (IOException e) { // 处理异常 } ``` 4. **处理新帧**: ```java public void onDrawFrame() { if (frameAvailable) { mPreviewTexture.updateTexImage(); mPreviewTexture.getTransformMatrix(mtx); // 使用mtx渲染纹理 } } ``` #### 常见问题解决方案 **问题 1:黑屏/无预览** ```java // 检查步骤: // 1. 确保相机权限已获取 // 2. 验证纹理是否正确创建 if (!GLES20.glIsTexture(mTextureId)) { Log.e(TAG, "Invalid texture ID"); } // 3. 检查预览尺寸是否支持 List<Camera.Size> sizes = mCamera.getParameters().getSupportedPreviewSizes(); for (Camera.Size size : sizes) { Log.d(TAG, "Supported size: " + size.width + "x" + size.height); } ``` **问题 2:纹理变形** ```java // 解决方案:正确应用变换矩阵 public void drawTexture(int program, float[] mtx) { int mtxHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix"); GLES20.glUniformMatrix4fv(mtxHandle, 1, false, mtx, 0); // 顶点着色器示例: // uniform mat4 uMVPMatrix; // attribute vec4 vPosition; // attribute vec2 vTexCoord; // varying vec2 texCoord; // // void main() { // gl_Position = uMVPMatrix * vPosition; // texCoord = vTexCoord; // } } ``` **问题 3:内存泄漏** ```java @Override protected void onPause() { super.onPause(); releaseCamera(); } @Override protected void onDestroy() { super.onDestroy(); releaseCamera(); } ``` #### 最佳实践 1. **线程管理**: ```java // 在GL线程创建SurfaceTexture glThread.post(() -> { mPreviewTexture = new SurfaceTexture(textureId); mainHandler.post(() -> { // 在主线程设置到相机 try { mCamera.setPreviewTexture(mPreviewTexture); } catch (IOException e) { e.printStackTrace(); } }); }); ``` 2. **帧同步**: ```java private final Object mFrameSync = new Object(); public void updateTexture() { synchronized (mFrameSync) { mPreviewTexture.updateTexImage(); // ... } } ``` 3. **自适应方向**: ```java public void setCameraOrientation() { Camera.CameraInfo info = new Camera.CameraInfo(); 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; // 镜像 } else { result = (info.orientation - degrees + 360) % 360; } mCamera.setDisplayOrientation(result); } ``` #### Camera2 API 替代方案 对于 Android 5.0+ 设备,建议使用 Camera2 API: ```java // 使用SurfaceTexture创建Surface SurfaceTexture texture = new SurfaceTexture(textureId); Surface surface = new Surface(texture); // 配置Camera2预览 CaptureRequest.Builder builder = cameraDevice.createCaptureRequest( CameraDevice.TEMPLATE_PREVIEW); builder.addTarget(surface); // 创建会话 cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { try { session.setRepeatingRequest(builder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } }, null); ``` ### 总结 使用 `Camera.setPreviewTexture()` 的关键点: 1. 正确创建和绑定 OpenGL ES 纹理 (`GL_TEXTURE_EXTERNAL_OES`) 2. 合理管理 SurfaceTexture 生命周期 3. 处理预览尺寸和方向问题 4. 在渲染线程使用 `updateTexImage()` 更新纹理 5. 应用变换矩阵解决图像变形问题 对于新项目,建议迁移到 CameraX 或 Camera2 API,它们提供更现代的相机操作方式并自动处理纹理更新。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值