Android中自定义相机Camera2的使用

在之前的博客中我介绍了Camera在单拍和连拍上的使用。大家应该有所了解了。但如果你运行了博客中的例子,或者自己根据讲解写了一个Demo,你会发现拍出的照片并不是很清晰,很大的一个原因是我们的照片支持的最大分辨率是1920*1080,所以对于现在动辄2000往上的分辨率来说却是不是很清晰。所以Android 5.0之后Camera2也应用而生。而和Camera2配合的显示控件也变成了TextureView。下面我们分别对这两个内容一一进行讲解。并在最后给出一个利用Camera2制作的自定义相机示例。

1.纹理视图TextureView常用方法

  • lockCanvas:锁定并获取画布。 
  • unlockCanvasAndPost:解锁并刷新画布。
  • setSurfaceTextureListener:设置表面纹理的监听器。该方法相当于SurfaceHolder的addCallback方法,用来监控表面纹理的状态变化事件。方法参数为SurfaceTextureListener监听器对象,需重写一下四个方法。

onSurfaceTextureAvailable

在表面纹理可用时触发,可在此进行打开相机等操作。
onSurfaceTextureSizeChanged在表面纹理尺寸变化时触发。
onSurfaceTextureDestroyed在表面纹理销毁时触发。
onSurfaceTextureUpdated在表面纹理更新时触发。
  • isAvailable:判断表面纹理是否可用。
  • getSurfaceTexture:获取表面纹理。

2.SurfaceView洗白背景的方法

//下面两行设置背景为透明,因为SurfaceView默认背景是黑色
setZOrderOnTop(true);
mHolder.setFormat(PixelFormat.TRANSLUCENT);

3.Camera2新特性

  • 支持每秒30帧的全高清连拍。
  • 支持在每帧之间使用不同的设置。
  • 支持原生格式的图像输出。
  • 支持零延迟快门和电影速拍。
  • 支持相机在其他方面的手动控制,比如设置噪音消除的级别。

4.Camera2新架构结构划分

Camera2在架构上做了大幅改造,原先的Camera类被拆分为多个管理类,主要有如下几个部分:

  • 相机管理器CameraManager
  • 相机设备CameraDevice
  • 相机拍照会话CameraCaptureSession
  • 图像读取器ImageReader

5.相机管理器CameraManager

<1>相机管理器的作用

相机管理器用于获取可用摄像头列表、打开摄像头等,对象从系统服务CAMERA_SERVICE获取。

<2>相机管理器常用方法

  • getCameraIdList:获取相机列表。通常返回两条记录,一条是后置摄像头,另一条是前置摄像头。
  • getCameraCharacteristics:获取相机的参数信息。包括相机的支持级别、照片的尺寸等。
  • openCamera:打开指定摄像头,第一个参数为指定摄像头的id,第二个参数为设备状态监听器,该监听器需实现接口CameraDevice.StateCallback的onOpend方法(方法内部再调用CameraDevice对象的createCaptureRequest方法)。
  • setTorchMode:在不打开摄像头的情况下,开启或关闭闪光灯。为true表示开启闪光灯,为false表示关闭闪光灯。

<3>检查当前手机是否支持Camera2

// 从系统服务中获取相机管理器
CameraManager cm = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
// 获取可用相机设备列表
CameraCharacteristics cc = cm.getCameraCharacteristics(cameraid);
// 检查相机硬件的支持级别
// CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL表示完全支持
// CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED表示有限支持
// CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY表示遗留的
int level = cc.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL){
    ToastUtil.toastWord(mContext,"完全支持");
}else if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED){
    ToastUtil.toastWord(mContext,"有限支持");
}else if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY){
    ToastUtil.toastWord(mContext,"不建议使用");
}

6.相机设备CameraDevice

<1>相机设备的作用

相机设备用于创建拍照请求、添加预览界面、创建拍照会话等。

<2>相机设备常用方法

  • createCaptureRequest:创建拍照请求,第二个参数为会话状态的监听器,该监听器需实现会话状态回调接口CamereCaptureSession.StateCallback的onConfigured方法(方法内部再调用CameraCaptureSession对象的setRepeatingRequest方法,将预览影像输出到屏幕)。createCaptureRequest方法返回一个CaptureRequest的预览对象。
  • close:关闭相机。

7.相机拍照会话CameraCaptureSession

<1>相机拍照会话的作用

相机拍照会话用于设置单拍会话(每次只拍一张照片)、连拍会话(自动连续拍摄多张照片)等。

<2>相机拍照会话常用方法

  • getDevice:获得该会话的相机设备对象。
  • capture:拍照并输出到指定目标。输出目标为CaptureRequest对象时,表示显示在屏幕上;输出目标为ImageReader对象时,表示要保存照片。
  • setRepeatingRequest:设置连拍请求并输出到指定目标。输出目标为CaptureRequest对象时,表示显示在屏幕上;输出目标为ImageReader对象时,表示要保存照片。
  • stopRepeating:停止连拍。

8.图像读取器ImageReader

<1>图像读取器作用

图像读取器用于获取并保存照片信息,一旦有图像数据生成,立刻触发onImageAvailable方法。

<2>图像读取器常用方法

  • getSurface:获得图像读取的表面对象。
  • setOnImageAvailableListener:设置图像数据的可用监听器。该监听器需实现接口ImageReader.OnImageAvailableListener的onImageAvailable方法。

9.Camera2使用示例

Camera2View.java

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.ImageReader.OnImageAvailableListener;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import com.hao.baselib.utils.PathGetUtil;
import com.hao.baselib.utils.ToastUtil;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Camera2View extends TextureView {

    private static final String TAG = "Camera2View";
    private Context mContext; // 声明一个上下文对象
    private Handler mHandler;
    private HandlerThread mThreadHandler;
    private CaptureRequest.Builder mPreviewBuilder; // 声明一个拍照请求构建器对象
    private CameraCaptureSession mCameraSession; // 声明一个相机拍照会话对象
    private CameraDevice mCameraDevice; // 声明一个相机设备对象
    private ImageReader mImageReader; // 声明一个图像读取器对象
    private Size mPreViewSize; // 预览画面的尺寸
    private int mCameraType = CameraCharacteristics.LENS_FACING_FRONT; // 摄像头类型
    private int mTakeType = 0; // 拍摄类型。0为单拍,1为连拍

    public Camera2View(Context context) {
        this(context, null);
    }

    public Camera2View(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mThreadHandler = new HandlerThread("camera2");
        mThreadHandler.start();
        mHandler = new Handler(mThreadHandler.getLooper());
    }

    // 打开指定摄像头的相机视图
    public void open(int camera_type) {
        mCameraType = camera_type;
        // 设置表面纹理变更监听器
        setSurfaceTextureListener(mSurfacetextlistener);
    }

    private String mPhotoPath; // 照片的保存路径
    // 获取照片的保存路径
    public String getPhotoPath() {
        return mPhotoPath;
    }

    // 执行拍照动作
    public void takePicture() {
        Log.d(TAG, "正在拍照");
        mTakeType = 0;
        try {
            CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 把图像读取器添加到预览目标
            builder.addTarget(mImageReader.getSurface());
            // 设置自动对焦模式
            builder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_AUTO);
            // 设置自动曝光模式
            builder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 开始对焦
            builder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                    CameraMetadata.CONTROL_AF_TRIGGER_START);
            // 设置照片的方向
            builder.set(CaptureRequest.JPEG_ORIENTATION, (mCameraType == CameraCharacteristics.LENS_FACING_FRONT) ? 90 : 270);
            // 拍照会话开始捕获相片
            mCameraSession.capture(builder.build(), null, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private ArrayList<String> mShootingArray; // 连拍的相片保存路径列表
    // 获取连拍的相片保存路径列表
    public ArrayList<String> getShootingList() {
        Log.d(TAG, "mShootingArray.size()=" + mShootingArray.size());
        return mShootingArray;
    }

    // 开始连拍
    public void startShooting(int duration) {
        Log.d(TAG, "正在连拍");
        mTakeType = 1;
        mShootingArray = new ArrayList<String>();
        try {
            // 停止连拍
            mCameraSession.stopRepeating();
            // 把图像读取器添加到预览目标
            mPreviewBuilder.addTarget(mImageReader.getSurface());
            // 设置连拍请求。此时预览画面会同时发给手机屏幕和图像读取器
            mCameraSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler);
            // duration小等于0时,表示持续连拍,此时外部要调用stopShooting方法来结束连拍
            if (duration > 0) {
                // 延迟若干秒后启动拍摄停止任务
                mHandler.postDelayed(mStop, duration);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    // 停止连拍
    public void stopShooting() {
        try {
            // 停止连拍
            mCameraSession.stopRepeating();
            // 移除图像读取器的预览目标
            mPreviewBuilder.removeTarget(mImageReader.getSurface());
            // 设置连拍请求。此时预览画面只会发给手机屏幕
            mCameraSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        Toast.makeText(mContext, "已完成连拍,按返回键回到上页查看照片。", Toast.LENGTH_SHORT).show();
    }

    // 定义一个拍摄停止任务
    private Runnable mStop = new Runnable() {
        @Override
        public void run() {
            stopShooting();
        }
    };

    // 打开相机
    private void openCamera() {
        // 从系统服务中获取相机管理器
        CameraManager cm = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        String cameraid = mCameraType + "";
        try {
            // 获取可用相机设备列表
            CameraCharacteristics cc = cm.getCameraCharacteristics(cameraid);
            // 检查相机硬件的支持级别
            // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL表示完全支持
            // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED表示有限支持
            // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY表示遗留的
            int level = cc.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
            if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL){
                ToastUtil.toastWord(mContext,"完全支持");
            }else if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED){
                ToastUtil.toastWord(mContext,"有限支持");
            }else if (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY){
                ToastUtil.toastWord(mContext,"不建议使用");
            }
            StreamConfigurationMap map = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizeByArea());
            // 获取预览画面的尺寸
            mPreViewSize = map.getOutputSizes(SurfaceTexture.class)[0];
            // 创建一个JPEG格式的图像读取器
            mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, 10);
            // 设置图像读取器的图像可用监听器,一旦捕捉到图像数据就会触发监听器的onImageAvailable方法
            mImageReader.setOnImageAvailableListener(onImageAvaiableListener, mHandler);
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                // 开启摄像头
                cm.openCamera(cameraid, mDeviceStateCallback, mHandler);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    // 关闭相机
    private void closeCamera() {
        if (null != mCameraSession) {
            mCameraSession.close(); // 关闭相机拍摄会话
            mCameraSession = null;
        }
        if (null != mCameraDevice) {
            mCameraDevice.close(); // 关闭相机设备
            mCameraDevice = null;
        }
        if (null != mImageReader) {
            mImageReader.close(); // 关闭图像读取器
            mImageReader = null;
        }
    }

    // 定义一个表面纹理变更监听器。TextureView准备就绪后,立即开启相机
    private SurfaceTextureListener mSurfacetextlistener = new SurfaceTextureListener() {
        // 在纹理表面可用时触发
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            openCamera(); // 打开相机
        }

        // 在纹理表面的尺寸发生改变时触发
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}

        // 在纹理表面销毁时触发
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            closeCamera(); // 关闭相机
            return true;
        }

        // 在纹理表面更新时触发
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
    };

    // 创建相机预览会话
    private void createCameraPreviewSession() {
        // 获取纹理视图的表面纹理
        SurfaceTexture texture = getSurfaceTexture();
        // 设置表面纹理的默认缓存尺寸
        texture.setDefaultBufferSize(mPreViewSize.getWidth(), mPreViewSize.getHeight());
        // 创建一个该表面纹理的表面对象
        Surface surface = new Surface(texture);
        try {
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 把纹理视图添加到预览目标
            mPreviewBuilder.addTarget(surface);
            // 设置自动对焦模式
            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            // 设置自动曝光模式
            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 开始对焦
            mPreviewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                    CameraMetadata.CONTROL_AF_TRIGGER_START);
            // 设置照片的方向
            mPreviewBuilder.set(CaptureRequest.JPEG_ORIENTATION, (mCameraType == CameraCharacteristics.LENS_FACING_FRONT) ? 90 : 270);
            // 创建一个相片捕获会话。此时预览画面显示在纹理视图上
            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    mSessionStateCallback, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    // 相机准备就绪后,开启捕捉影像的会话
    private CameraDevice.StateCallback mDeviceStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            mCameraDevice = cameraDevice;
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(CameraDevice cameraDevice, int error) {
            cameraDevice.close();
            mCameraDevice = null;
        }
    };

    // 影像配置就绪后,将预览画面呈现到手机屏幕上
    private CameraCaptureSession.StateCallback mSessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(CameraCaptureSession session) {
            try {
                Log.d(TAG, "onConfigured");
                mCameraSession = session;
                // 设置连拍请求。此时预览画面只会发给手机屏幕
                mCameraSession.setRepeatingRequest(mPreviewBuilder.build(), null, mHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onConfigureFailed(CameraCaptureSession session) {}
    };

    // 一旦有图像数据生成,立刻触发onImageAvailable事件
    private OnImageAvailableListener onImageAvaiableListener = new OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader imageReader) {
            Log.d(TAG, "onImageAvailable");
            mHandler.post(new ImageSaver(imageReader.acquireNextImage()));
        }
    };

    // 定义一个图像保存任务
    private class ImageSaver implements Runnable {
        private Image mImage;

        public ImageSaver(Image reader) {
            mImage = reader;
        }

        @Override
        public void run() {
            // 获取本次拍摄的照片保存路径
            //获取本次拍摄的照片路径
            List<String> listPath = new ArrayList<>();
            listPath.add("myCamera");
            listPath.add("photos");
            String path = PathGetUtil.getLongwayPath(mContext, listPath);
            File fileDir = new File(path);
            if (!fileDir.exists()) {
                fileDir.mkdirs();
            }
            File filePic = new File(path, "ww" + System.currentTimeMillis() + ".jpg");
            if (!filePic.exists()) {
                try {
                    filePic.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 保存图片文件
            saveImage(filePic.getPath(), mImage.getPlanes()[0].getBuffer());
            //BitmapUtil.setPictureDegreeZero(path);
            if (mImage != null) {
                mImage.close();
            }
            if (mTakeType == 0) { // 单拍
                mPhotoPath = path;
            } else { // 连拍
                mShootingArray.add(path);
            }
            Log.d(TAG, "完成保存图片 path=" + path);
        }
    }

    public static void saveImage(String path, ByteBuffer byteBuffer){
        try {
            File file = new File(path);
            boolean append = false;
            FileChannel wChannel = new FileOutputStream(file, append).getChannel();
            wChannel.write(byteBuffer);
            wChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class CompareSizeByArea implements java.util.Comparator<Size> {
        @Override
        public int compare(Size lhs, Size rhs) {
            return Long.signum((long) lhs.getWidth() * lhs.getHeight()
                    - (long) rhs.getWidth() * rhs.getHeight());
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <com.example.cameraself.Camera2View
        android:id="@+id/camera2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_alignParentBottom="true">
        <Button
            android:id="@+id/one"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="单拍"/>

        <Button
            android:id="@+id/two"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="连拍"
            android:layout_marginLeft="10dp"/>
    </LinearLayout>

</RelativeLayout>

MainActivity.java

import android.hardware.camera2.CameraCharacteristics;
import android.os.Build;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.hao.baselib.base.WaterPermissionActivity;

public class MainActivity extends WaterPermissionActivity<MainModel>
        implements MainCallback, View.OnClickListener {

    private Button one;
    private Button two;
    private Camera2View camera2;

    @Override
    protected MainModel getModelImp() {
        return new MainModel(this, this);
    }

    @Override
    protected int getContentLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initWidget() {
        one = findViewById(R.id.one);
        two = findViewById(R.id.two);
        camera2 = findViewById(R.id.camera2);
        one.setOnClickListener(this);
        two.setOnClickListener(this);
        requestPermission(READ_EXTERNAL_STORAGE);
    }

    @Override
    protected void doSDRead() {
        requestPermission(WRITE_EXTERNAL_STORAGE);
    }

    @Override
    protected void doSDWrite() {
        requestPermission(CAMERA);
    }

    @Override
    protected void doCamera() {
        // 获取前一个页面传来的摄像头类型
//        int camera_type = CameraCharacteristics.LENS_FACING_BACK;
        int camera_type = CameraCharacteristics.LENS_FACING_FRONT;
        // 设置二代相机视图的摄像头类型
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            camera2.open(camera_type);
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.one:
                // 命令二代相机视图执行单拍操作
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    camera2.takePicture();
                }
                // 拍照需要完成对焦、图像捕获、图片保存等一系列动作,因而要留足时间给系统处理
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "已完成拍照", Toast.LENGTH_SHORT).show();
                    }
                }, 1500);
                break;
            case R.id.two:
                // 命令二代相机视图执行连拍操作
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    camera2.startShooting(7000);
                }
                break;
        }
    }
}

这样我们就实现了利用Camera2来制作自定义相机的目的。实际测试中发现,Camera2确实比Camera拍出来的照片要清晰很多,并且分辨率和照片的最终大小都有所提升,但是和系统相机比还是要差一些,和微信等主流应用的自定义相机还相距甚远,因为这其中还有很多算法优化,硬件支持等相关的内容。不过基本已经可以满足我们开发中一部分的需求了。所以如果我们只是简单的需要拍照上传图片,建议还是调用系统的相机功能。如果必须要自定义拍照界面我们再使用这种方法。之后有机会我还会研究一下Jetpack中的CameraX并写一篇博文。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: Android自定义相机Camera2是一种基于Android Camera2 API的相机应用程序开发技术。相比于旧版Camera API,Camera2 API提供了更多的控制权和更高的性能。使用Camera2 API,开发者可以自定义相机的各种参数,如曝光时间、ISO、焦距等,从而实现更加精细的相机控制。同时,Camera2 API还支持RAW格式的图像输出,使得开发者可以更加灵活地处理相机输出的图像数据。 ### 回答2: Android自定义相机Camera2是基于Android 5.0之后提供的新一代相机API,相比较Camera1,它提供了更加丰富和灵活的功能。在使用Camera2 API时,需要使用一些异步的回调接口,通过监听器来处理相机的各种状态和数据。 Camera2 API 的使用分为三个阶段:预览、拍照和保存图片。其,预览是最基本的功能,也是所有相机功能的基础。可以通过创建CameraDevice,设置相机的参数和预览界面,再通过ImageReader获取相机捕获的数据,最后进行图像显示。 在拍照功能,需要使用相机的Capture请求和CaptureSession会话来进行捕获相片的操作。首先需要创建相机的CaptureRequest.Builder对象,设置拍照相关的参数。然后,需要使用CaptureRequest.Builder构建捕获请求CaptureRequest,再将捕获请求加入到CaptureSession,通过光圈控制、曝光时间、ISO值、白平衡等参数控制相机的拍摄效果。 最后,在保存图片时,需要使用ImageReader对象从相机捕获的数据获取图片数据,然后将其保存到文件或者显示到界面上。 总之,使用Camera2 API自定义相机可以在相机的预览、拍照和保存等各个环节上实现更加灵活的控制,能够充分发挥相机的功能,达到更好的拍照效果。 ### 回答3: Android自定义相机成为了越来越多开发者关注和学习的领域,其相机API2(Camera2)是我们不可忽视的一部分。Android Lollipop时代,Google引入了Camera2 API,它是原来的相机API(Camera)的替代品,提供了很多强大的功能和灵活的控制权,包括更高的FPS、更低的延迟和更好的控制,让我们可以更精确地控制相机硬件,实现更好的相机+应用程序的体验。 使用Camera2 API, 我们可以: 1. 使用更高质量的图像传感器. 2. 以流的方式更容易访问图像预览数据. 3. 支持高帧率的视频录制,甚至支持高达120fps. 4. 可以在更广泛的控制选项(如焦距,曝光等)进行定制,以实现更具创意的摄影模式。 5. 显着提高了拍摄速度和唤醒速度。 然而,相较于Camera API, Camera2 API一个更复杂和庞大的API,需要更多的配置和使用,刚开始可能会让些开发者望而却步,然而掌握Camera2 API后,它将为您带来更多的好处。开始使用Camera2 API不仅需要对Android摄像头架构有很好的理解,还需要一定的Java编程经验和计算机图形知识。 总之,Android自定义相机Camera2是非常复杂和庞大的API,需要开发人员掌握许多技能。但是,一旦掌握,它将为开发人员带来更高的图像质量,更精确的控制和更多的相机配置选项,这将为开发人员提高用户体验的基础,满足客户的各种摄影需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值