• 沒有找到結果。

您开发相机相关的功能,可以参考相机开发进行开发。

7.2.1 Camera API

使用流程:

1. 检查相机权限(android.permission.CAMERA);

2. Camera.getNumberOfCameras():获取相机硬件数量IdeaHub默认1个,cameraId 为“0”;

3. Camera.getCameraInfo():获取指定相机信息;

4. Camera.open():打开指定相机;

5. camera.getParameters():获取相机参数并设置;(ImageFormat.NV21始终受支 持);

6. camera.setPreviewTexture(SurfaceTexture surfaceTexture):设置用于相机预览的 surfaceTexutre;

7. camera.setDisplayOrientation(degrees):设置预览旋转角度;

8. camera.startPreview():开始预览;

关键类:

1. Camera 相机类,定义了open、startPreview、takePicture、AutoFocus、

setDisplayOrientation、setPreviewTexture等方法;

2. 实例方式:mCamera = Camera.open(cameraId);

3. Camera.CameraInfo 相机信息类,元数据获取;

4. Camera.Parameters 相机参数类,参数设置,定义了setFocusMode,

setPreviewSize、setFlashMode等方法,通过mCamera.getParameters()获取;

以下为关键函数的具体调用方法:

(1)初始化SurfaceviewHolder,并添加回调方法;获取摄像头,开始预览。

private void init() {

previewSurfaceHolder = previewSurfaceview.getHolder();

previewSurfaceHolder.addCallback(this);

if (camera == null) { camera = Camera.open(0);

startCamera(camera);

}}

(2) 给SurfaceViewHolder对象添加回调函数;

@Override

public void surfaceCreated(SurfaceHolder holder) { if (holder == previewSurfaceHolder) {

this.previewSurfaceInit = true;

}if (this.previewSurfaceInit) { camera = Camera.open(0);

startCamera(camera);

}}

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if (!checkPermissionAllGranted(PERMISSIONS_STORAGE)) {

return;

}}

@Override

public void surfaceDestroyed(SurfaceHolder holder) { if (holder == previewSurfaceHolder && null != camera) { camera.setPreviewCallback(null);

camera.stopPreview();

camera.release();

camera = null;

}}

说明

首先对mSurfaceHolder添加了一个回调,这个回调会告诉我们SurfaceView中surface的变化;

在surfaceCreated 回调中打开相机。因为相机开始预览的时候,如果SurfaceView中的surface还 没有创建,就会抛出异常,所以我们在surface创建后再对相机进行操作。

(3) 开始预览

/*** 开始预览相机内容

*/private void startCamera(Camera mCamera) { if (mCamera == null) {

return;

}try {

parameters = mCamera.getParameters();

parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO); // 自动白平衡 parameters.setPreviewFormat(ImageFormat.NV21); // 预览格式

parameters.setPreviewSize(width, height); // 预览大小

mCamera.setPreviewCallback(this);

mCamera.setParameters(parameters);

mCamera.setPreviewDisplay(previewSurfaceHolder);

mCamera.startPreview();

} catch (IOException e) { e.printStackTrace();

}}

说明

预览前可以设置预览相关的一些参数,目前IdeaHub不支持自动对焦,不支持白平衡。

7.2.2 Camera2 API

使用流程:

1. 检查相机权限(android.permission.CAMERA);

2. cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);

3. cameraManager.getCameraIdList():获取相机硬件id集合;

4. cameraManager.getCameraCharacteristics(cameraId):获取相机信息;

5. cameraManager.openCamera(cameraId,cameraCallback,null); 开启相机;

6. CameraDevice.StateCallback回调中获取cameraDevice;

7. cameraDevice.createCaptureSession(surfaces,new

CameraCaptureSession.StateCallback(),null) 创建捕获会话,surfaces作为捕获的图 像数据的输出的目标;

8. CaptureRequest.Builder 创建请求,通过键值对的方式设置参数;

9. cameraCaptureSession.setRepeatingRequest(previewRequest, captureCallback, null);发送请求;

关键类:

1. CameraManager 相机管理器,在Camera打开之前主要操作CameraManager,打 开后主要操作CameraCaptureSession;

2. getSystemService(Context.CAMERA_SERVICE);

3. CameraCharacteristics 摄像头属性,相当于Camera1的CameraInfo。 通过获取 Camera属性信息,配置Camera输出,如FPS,大小,旋转等;

4. mCameraManager.getCameraCharacteristics(currentCameraId);

5. CameraDevice 用于创建CameraCaptureSession和关闭摄像头;

6. cameraManager.openCamera(cameraId,cameraCallback,null);cameraCallback 的回调中获取到实例对象;

7. CameraCaptureSession 相机捕获会话,CameraCaptureSession建立了一个和 Camera硬件设备的会话通道,可以通过这个会话向Camera发送请求获取图像;

setRepeatingRequest():控制预览;capture():控制拍照;

8. CaptureRequest.Builder 请求构造器,Map,以键值对的方式设置请求参数;

9. CaptureRequest 预览或拍照,都需要CaptureRequest参数。CaptureRequest代表 了一次捕获请求,其中包含了捕获图片的参数设置,比如对焦模式、曝光模式等;

以下为关键函数的具体调用方法:

界面显示的时候调用onResume方法,在onResume方法里开启相机操作线程,添加 TextureViewSurface的监听方法,在TextureView准备好的时候,打开相机。

private final TextureView.SurfaceTextureListener mSurfaceTextureListener

= new TextureView.SurfaceTextureListener() {

@Override

public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { openCamera(width, height);

}@Override

public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) { configureTransform(width, height);

}@Override

publicboolean onSurfaceTextureDestroyed(SurfaceTexture texture) { return true;

}@Override

public void onSurfaceTextureUpdated(SurfaceTexture texture) { }};

(1) 初始化相机配置,打开相机。

private void openCamera(int width, int height) {

if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)

!= PackageManager.PERMISSION_GRANTED) { requestCameraPermission();

return;

}setUpCameraOutputs(width, height);

configureTransform(width, height);

Activity activity = getActivity();

CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);

try {

if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Time out waiting to lock camera opening.");

}manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

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

} catch (InterruptedException e) {

throw new RuntimeException("Interrupted while trying to lock camera opening.", e);

}}

说明

1、 首先,获取权限;

2、 配置相机参数时,要获取到 CameraManager 实例;

3、 通过循环遍历设备中可用的相机,通过 mCameraManager.getCameraCharacteristics(id) 获取到相机的各种信息;

4、 mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) 获取到相机 传感器的方向;

5、 通过 configurationMap.getOutputSizes(ImageFormat.JPEG) 和

configurationMap.getOutputSizes(SurfaceTexture::class.java) 获取到相机支持的预览尺寸和保 存图片的尺寸;

6、 exchangeWidthAndHeight(displayRotation: Int, sensorOrientation: Int)方法的作用是根据 屏幕方向和摄像头方向确定是否需要交换宽高;

7、 比如我们手机竖屏放置,设置的预览宽高是 720 * 1280 ,我们希望设置的是宽为 720,高 为 1280 。 而后置摄像头相对于竖直方向是 90°,也就说 720 相对于是摄像头来说是它的高 度,1280 是它的宽度,这跟我们想要设置的刚好相反。所以,我们通过

exchangeWidthAndHeight这个方法得出来是否需要交换宽高值,如果需要,那变成了把 1280

* 720 设置给摄像头,即它的宽为 720,高为 1280 。这样就与我们预期的宽高值一样了;

8、 通过 getBestSize(targetWidth: Int, targetHeight: Int, maxWidth: Int, maxHeight: Int, sizeList: List<Size>) 方法获取到最优的宽和高。 根据传入的 目标宽高值、最大宽高值(即屏幕 大小)和 相机支持的尺寸列表,从相机支持的尺寸列表中得到一个最优值;

mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /*maxImages*/

2);mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

创建一个ImageReader对象,并设置回调函数。前两个参数代表保存图片的宽高,第三个参数是 保存图片的格式,第四个参数代表用户同时可以得到的图片最大数。

(2) 打开相机后触发回调方法stateCallBack,回调中onOpen方法中开启预览。

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

@Override

public void onOpened(@NonNull CameraDevice cameraDevice) {

// This method is called when the camera is opened. We start camera preview here.

mCameraOpenCloseLock.release();

mCameraDevice = cameraDevice;

createCameraPreviewSession();

}@Override

public void onDisconnected(@NonNull CameraDevice cameraDevice) { mCameraOpenCloseLock.release();

cameraDevice.close();

mCameraDevice = null;

}@Override

public void onError(@NonNull CameraDevice cameraDevice, int error) { mCameraOpenCloseLock.release();

cameraDevice.close();

mCameraDevice = null;

Activity activity = getActivity();

if (null != activity) { activity.finish();

}} };

(3) 创建预览会话。

private void createCameraPreviewSession() { try {

SurfaceTexture texture = mTextureView.getSurfaceTexture();

assert texture != null;

texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

// This is the output Surface we need to start preview.

Surface surface = new Surface(texture);

// We set up a CaptureRequest.Builder with the output Surface.

mPreviewRequestBuilder

= mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

mPreviewRequestBuilder.addTarget(surface);

// Here, we create a CameraCaptureSession for camera preview.

mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {

@Override

public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { // The camera is already closed

if (null == mCameraDevice) { return;

}// When the session is ready, we start displaying the preview.

mCaptureSession = cameraCaptureSession;

try {

// Auto focus should be continuous for camera preview.

mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

// Flash is automatically enabled when necessary.

setAutoFlash(mPreviewRequestBuilder);

// Finally, we start displaying the camera preview.

mPreviewRequest = mPreviewRequestBuilder.build();

mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);

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

}}

@Override

public void onConfigureFailed(

@NonNull CameraCaptureSession cameraCaptureSession) { showToast("Failed");

}}, null

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

}}

说明

1、 通过cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) 创建一个 用于预览的Builder对象;

2、 为该Builder对象添加一个Surface对象,并设置各种相关参数;

3、 通过cameraDevice.createCaptureSession创建一个会话,第一个参数中传了一个 surface 和 mImageReader.getSurface()。这表明了这次会话的图像数据的输出到这两个对象;

4、 当会话创建成功时,通过 session.setRepeatingRequest(captureRequestBuilder.build(), mCaptureCallBack, mCameraHandler) 发起预览请求。

相關文件