概述
Camera2之拍照
Android框架包括支持各种相机和相机的特性 设备,允许您捕获照片和视频在您的应用程序。 本文讨论了 快速、简单的图像和视频捕获方法,并概述了一个先进的方法来创建 为用户自定义相机的经验。
1.在清单文件中声明
权限
<uses-permission android:name="android.permission.CAMERA" />
如果保存照片,录视频还要添加两个权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
相机功能:相机的特性,例如
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
还有很多如下:
android.hardware.camera
应用使用设备的后置相机。只有前置相机的设备不会列出该功能,因此如果您的应用可与任何朝向的相机通信,请改用 android.hardware.camera.any 功能。
android.hardware.camera.any
应用使用设备的其中一个相机或用户为设备连接的外置相机。 如果您的应用不要求相机必须是后置式,请使用此值来替代 android.hardware.camera。
android.hardware.camera.autofocus
应用使用设备相机支持的自动对焦功能。
应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。
android.hardware.camera.capability.manual_post_processing
应用使用设备相机支持的 MANUAL_POST_PROCESSING 功能。
您的应用可以通过该功能替换相机的自动白平衡功能。 使用 android.colorCorrection.transform、android.colorCorrection.gains 以及 TRANSFORM_MATRIX 的 android.colorCorrection.mode。
android.hardware.camera.capability.manual_sensor
应用使用设备相机支持的 MANUAL_SENSOR 功能。
该功能隐含对自动曝光锁定 (android.control.aeLock) 的支持,该支持可以让相机的曝光时间和灵敏度一直固定在特定值。
android.hardware.camera.capability.raw
应用使用设备相机支持的 RAW 功能。
该功能暗示设备可以保存 DNG(原始)文件,并且设备的相机提供您的应用直接处理这些原始图像所需的 DNG 相关元数据。
android.hardware.camera.external
应用与用户为设备连接的外置相机通信。 但该功能不能保证外置相机可供您的应用使用。
android.hardware.camera.flash
应用使用设备相机支持的闪光功能。
应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。
android.hardware.camera.front
应用使用设备的前置相机。
应用通过使用该功能暗示其还使用 android.hardware.camera 功能,除非这个父功能在声明时使用了 android:required="false"。
android.hardware.camera.level.full
应用使用设备的至少一个相机提供的 FULL 级图像捕捉支持。 提供 FULL 支持的相机可提供快速捕捉功能、逐帧控制和手动后期处理控制。
1.本文是利用textureview预览视图数据的。在xml文件中定义textureview组件
创建handler线程,创建handler;
给textureview设置监听
mPreviewView = (TextureView) findViewById(R.id.textureview);
mThreadHandler = new HandlerThread("CAMERA2");
mThreadHandler.start();
mHandler = new Handler(mThreadHandler.getLooper());
mPreviewView.setSurfaceTextureListener(surfaceTextureListener);
在textureveiw监听中可以看到以下方法;创建时,尺寸改变时,销毁时,更新时。
我们在textureview初始化的时候创建初始化相机功能,这里先要检察权限,没有权限要去申请权限。
private TextureView.SurfaceTextureListener surfaceTextureListener=new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
checkPermission();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
public void checkPermission()
{
//检查是否有权限
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 0);
}else{
initCamera();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 0:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initCamera();
}
break;
}
}
2.初始化相机功能
获得相机设备要通过相机服务CameraManager
通过相机id获得相机的参数类CameraCharactoristics对象,这个对象封装了相机相关的支持动能参数,例如支持的分辨率,摄像头旋转角度
通过cameraManager传入相机的id打开相机,设置回调
public void initCamera()
{
cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
try {
//获取可用相机设备id列表
String[] CameraIdList = cameraManager.getCameraIdList();
//获得前置摄像头的属性对象。
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(CameraIdList[0]);
//这可用流配置 相机设备支持; 还包括最低帧持续时间 和每个格式的停滞时间/大小组合。
//
characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
//分辨率:
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
android.util.Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG);
for(android.util.Size size:outputSizes)
{
list.add(size.getWidth()+"*"+size.getHeight());
Log.e("fbl",size.getWidth()+"*"+size.getHeight());
}
//获取摄像头的旋转角度
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
ArrayAdapter arr_adapter= new ArrayAdapter(Camera2Activity.this, R.layout.spinner_item_layout, list);
arr_adapter.setDropDownViewResource(R.layout.spinner_item_layout);
spinner.setAdapter(arr_adapter);
//
spinner.setSelection(5);
//就像这样
cameraManager.openCamera(CameraIdList[0], mCameraDeviceStateCallback, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
在回调中有打开,失去连接,错误方法的回调
在开发相机回调中设置spinner的监听,对于选择不同的分辨率下创建不同尺寸的ImageReader对象,这个对象是封装了拍照数据的类,设置拍照监听回调后保存照片
开始预览,创建捕捉会议
/**
* 相机监听,这个回调不是运行在ui线程的,不能更新UI
*/
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCaera = camera;
mFile = new File(Environment.getExternalStorageDirectory(),"TTT.jpg");
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
TextView tv= (TextView) view;
String
text = (String) tv.getText();
String[] split = text.split("\*");
imageReader = ImageReader.newInstance(Integer.parseInt(split[1]), Integer.parseInt(split[0]), ImageFormat.JPEG, /*maxImages*/2);
imageReader.setOnImageAvailableListener(mOnImageAvailableListener, mHandler);
ViewGroup.LayoutParams layoutParams = mPreviewView.getLayoutParams();
layoutParams.width=min;
layoutParams.height=Integer.parseInt(split[0])*min/Integer.parseInt(split[1]);
mPreviewView.setLayoutParams(layoutParams);
try {
if(mSession!=null){
mSession.close();
}
startPreview(mCaera);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
@Override
public void onDisconnected(CameraDevice camera) {}
@Override
public void onError(CameraDevice camera, int error) {}
};
3.创建捕捉会议,开始预览
获得预览的surface,图片缓存的surface
设置会议监听
会议监听中通过会议发送请求,这只请求监听
4.通过点击事件触发拍照
/**
* 开始预览
* @param camera
* @throws CameraAccessException
*/
private void startPreview(CameraDevice camera) throws CameraAccessException {
SurfaceTexture texture = mPreviewView.getSurfaceTexture();
//我们将默认缓冲区的大小配置为我们想要的相机预览的大小。
texture.setDefaultBufferSize(mPreviewView.getWidth(), mPreviewView.getHeight());
surface = new Surface(texture);
//我们设置了一个具有输出Surface的CaptureRequest.Builder。
try {
mPreviewBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewBuilder.addTarget(surface);
} catch (CameraAccessException e) {
e.printStackTrace();
}
//创建捕捉会议
camera.createCaptureSession(Arrays.asList(surface,imageReader.getSurface()), mSessionStateCallback, mHandler);
}
/**
* 会议状态监听
*/
private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
//session.capture(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
mSession = session;
//这句是预览的真正代码
session.setRepeatingRequest(mPreviewBuilder.build(), mSessionCaptureCallback, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {}
};
private CameraCaptureSession.CaptureCallback mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback()
{
@Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)
{
}
@Override
public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult){
}
};
4.通过点击事件触发拍照
创建捕捉请求操作就会在ImageReader的surface中获取一张照片,然后之前设置的拍照监听中去处理图片
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.bt_cut:
takePicture();
break;
case R.id.imagebutton:
break;
}
}
public void takePicture(){
try {
CaptureRequest.Builder captureRequestBuilder = mCaera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
// 将imageReader的surface作为CaptureRequest.Builder的目标
captureRequestBuilder.addTarget(imageReader.getSurface());
// 自动对焦
captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
// 获取手机方向
int rotation = getWindowManager().getDefaultDisplay().getRotation();
// 根据设备方向计算设置照片的方向
captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
//拍照
CaptureRequest mCaptureRequest = captureRequestBuilder.build();
mSession.stopRepeating();
mSession.capture(mCaptureRequest, null, mHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
5.处理保存图片
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
= new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
MyToast.makeText(Camera2Activity.this,"拍照成功");
mHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
}
};
/**
* 保存图片
*/
private static class ImageSaver implements Runnable {
/**
* The JPEG image
*/
private final Image mImage;
/**
* The file we save the image into.
*/
private final File mFile;
public ImageSaver(Image image, File file) {
mImage = image;
mFile = file;
}
@Override
public void run() {
ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
FileOutputStream output = null;
try {
output = new FileOutputStream(mFile);
output.write(bytes);
} catch (IOException e) {
e.printStackTrace();
} finally {
mImage.close();
if (null != output) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
6.关闭摄像头,释放资源
@Override
protected void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
public void closeCamera()
{
if(mSession!=null)
{
mSession.close();
mSession=null;
}
if (null != mCaera) {
mCaera.close();//关掉摄像头
mCaera = null;
}
}
/**
* Stops the background thread and its {@link Handler}.
*/
private void stopBackgroundThread() {
mThreadHandler.quitSafely();//线程安全停止
try {
mThreadHandler.join();
mThreadHandler = null;
mHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
总体比5.0以前的相机操作复杂很多,很多回调监听。
本文参考官方提供的demo:
https://github.com/googlesamples/android-Camera2Basic
最后
以上就是甜美指甲油为你收集整理的Android开发 之 Camera2之拍照Camera2之拍照的全部内容,希望文章能够帮你解决Android开发 之 Camera2之拍照Camera2之拍照所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复