camera2

Android自定义视频录制

2018-11-01  本文已影响62人  JaydenWfj

概览

Android 进行录像的一个简单方法是:创建一个MediaStore.ACTION_VIDEO_CAPTURE的Intent来调起一个已有的相机应用。

但有时候我们需要自己定义录制界面,或者需要一些高级的功能,那么Intent方式就不能满足我们的要求的。

因此,我们可以使用Android framework为我们提供的Camera和Camera2 APIs来直接操作相机设备。

本章我们主要介绍,如何使用Camera 、Camera2以及MediaRecorder来录制视频。

权限设置

请求使用相机的权限:

<uses-permission android:name="android.permission.CAMERA" />

在配置文件中声明使用相机功能:

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

具体相机功能可以查看以下链接:

Feature Reference

在配置文件中声明使用相机的自动对焦和闪光灯功能:

<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.flash" android:required="false"/>

请求访问闪光灯权限:

 <uses-permission android:name="android.permission.FLASHLIGHT"/>

要在SD卡上存储获取读取视频 :

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

录制视频和音频权限:

 <uses-permission android:name="android.permission.RECORD_AUDIO"/>
 <uses-permission android:name="android.permission.RECORD_VIDEO"/>

注意:Android6.0及以上需动态权限申请

Camera

涉及相关功能类:

Camera:管理相机API(开启、关闭预览、设置相机参数)

Camera.CameraInfo:相机信息(前置or后置摄像头等)

//i为摄像头的id,通过 Camera.getNumberOfCameras()
Camera.getCameraInfo(i, mCameraInfo);//获取对于摄像头的相机信息

Camera.Parameters :相机特性 (自动对焦、闪光、预览大小、图片格式、图片大小等)

Camera2

涉及相关功能类:

CameraManager:摄像头管理类,用于检测、打开系统摄像头,通过getCameraCharacteristics(cameraId)可以获取摄像头特征

CameraCharacteristics :相机特性类,例如,是否支持自动调焦,是否支持zoom,是否支持闪光灯一系列特征

CameraDevice:相机设备,类似早期的camera类

CameraRequest:一次捕获的请求,可以设置一些列的参数,用于控制预览和拍照参数,例如:对焦模式,曝光模式,zoom参数等等

CameraCaptureSession:用于创建预览、拍照的Session类。通过它的setRepeatingRequest()方法请求连续预览 , 通过它的capture()方法控制拍照动作。

MediaRecorder

用于录制视频和音频的一个类。基于下图的状态机类控制录制过程:

[图片上传失败...(image-4b940a-1541081884311)]

状态说明:

Initial:当new MediaRecorder()或者在除Released状态外的其它状态通过调用reset()方法后,MediaRecorder进入Initial状态

Initialized:在Initial状态下,通过设定视频源setVideoSource()或者音频源setAudioSource()之后,状态切换为Initialized状态

DataSourceConfigured:在Initialized状态下,可以通过setOutputFormat()方法设置输出格式,此时

MediaRecorder转换为DataSourceConfigured状态。 数据源配置状态,这期间可以设定编码方式、输出文件、视频大小、视频帧率、预览显示等等。

Prepared:装备就绪状态,在DataSourceConfigured状态下,调用prepare()方法进入该状态。

Recording:录制状态,在Prepared状态下,调用start()方法进入该状态。通过stop()方法或reset()方法回到Initial状态。

Released:释放状态,可以通过在Initial状态调用release()方法来进入这个状态,这时将会释放和MediaRecorder对象关联的所有资源。

Error:错误状态,当错误发生的时候进入这个状态,它可以通过reset()方法进入Initial状态。

注意:使用MediaRecorder进行视频音频录制时,必须严格按照上面的状态图规定的函数先后调用顺序,在不同的状态调用不同的函数,否则会抛异常IllegalStateException

VCamera

概述:提供视频录制、后滤镜、炫酷 MV 主题、后期强大的 FFmpeg命令行支持,可实现水印、音量控制等诸多功能

使用文档

音视频单独采集

ts片段转mp4

ffmpeg -i concat:/sdcard/WeiXinRecordedDemo/1531060034234/0.ts -c copy -bsf:a aac_adtstoasc -y /sdcard/WeiXinRecordedDemo/1531060034234/0.mp4

预览功能

预览一般步骤流程:

流程说明:

Camera和Camera2各自是如何实现预览功能:

请求访问相机:

Camera实现:

//获取设备物理可用Camera
int count = Camera.getNumberOfCameras();
//检测是哪个相机
for (int i = 0; i < count; i++) {
    Camera.getCameraInfo(i, mCameraInfo);
    if (mCameraInfo.facing == mFacing) {
        mCameraId = i;
        return true;
    }
}
//开启
mCamera = Camera.open(mCameraId);

Camera2实现:

//获取设备物理可用Camera
final String[] ids = mCameraManager.getCameraIdList();
...省略部分代码

//找到我们想要的那个Camera
for (String id : ids) {
    CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
    ...
    Integer internal = characteristics.get(CameraCharacteristics.LENS_FACING);
    if (internal == null) {
        return false;
    }
    if (internal == internalFacing) {
        mCameraId = id;
        mCameraCharacteristics = characteristics;
        return true;
    }
}

通过CameraManager对象,调用openCamera方法开启相机:

try {
    mCameraManager.openCamera(mCameraId, mCameraDeviceCallback, null);
    return true;
} catch (CameraAccessException e) {
    //throw new RuntimeException("Failed to open camera: " + mCameraId, e);
    return false;
}

需要三个参数:

String cameraId:相机设备的唯一标识符
CameraDevice.StateCallback callback:相机打开的回调方法
Handler handler:回调方法在哪个线程处理

获取相关参数:

相机特性:

 1. Camera.Parameters mCameraParameters = mCamera.getParameters()
 
 2. CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);

获取支持的预览大小列表、视频大小列表、图片大小列表:

 1. mCameraParameters = mCamera.getParameters();
  List<Size> previewSizeList = mCameraParameters.getSupportedPreviewSizes();
  视频列表:
  List<Size> videoSizeList = mCameraParameters.getSupportedVideoSizes();
  图片列表:
  List<Size> pictureSizeList =  mCameraParameters.getSupportedPictureSizes()
  
 2.  StreamConfigurationMap map =        mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 
  Size[] previewSizeList = map.getOutputSizes(mPreview.getOutputClass());
  视频列表:
  Size[] videoSizeList = map.getOutputSizes(MediaRecorder.class)
  图片列表:
  Size[] pictureSizeList = map.getOutputSizes(SurfaceTexture.class)

设置参数:

Camera主要设置在Camera.Parameters 
mCameraParameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(mCameraParameters);

Camera2主要设置在CaptureRequest.Builder
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);

设置预览View:

Camera实现:

try {
    if (mPreview.getOutputClass() == SurfaceHolder.class) {
        ...
        mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
        ...
    } else {//Android 4.0(API 14)及以上
        mCamera.setPreviewTexture((SurfaceTexture) mPreview.getSurfaceTexture());
    }
} catch (IOException e) {
    //throw new RuntimeException(e);
}

Camera2实现:

try {
    mPreview.setBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());//Camera2 API有效
    Surface surface = mPreview.getSurface();

    //图像内容将输出到Preview的surface和ImageReader的surface中
    mPreviewRequestBuilder.addTarget(surface);
    mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
} catch (CameraAccessException e) {
}

开启预览:

Camera实现:

mCamera.startPreview();

Camera2实现:

//调用CameraDevicea的createCaptureRequest创建一个请求
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), mSessionCallback, null);

//调用如下方法才能不断预览
 mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);

接收预览每帧数据:

//Camera实现:
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        mCallback.onPreviewData(data);//预览每帧数据回调
    }
});

//Camera2
  mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),
                ImageFormat.YUV_420_888, /*maxImages*/2);//如果是预览则图片格式不要设置为JPEG,否则会一直拍照,造成预览卡
  mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, null);
  
  private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {

        @Override
        public void onImageAvailable(ImageReader reader) {
            Image image = reader.acquireNextImage();
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            mCallback.onPreviewData(bytes);//预览每帧数据回调
            image.close();//记得关闭,否则 抛出异常java.lang.IllegalStateException: maxImages (2) has //                           already been acquired, call #close before acquiring more.
        }
    };
  

停止预览:

//Camera实现:
if (mCamera != null) {
    mCamera.stopPreview();
}

//Camera2
if (mCaptureSession != null) {
    mCaptureSession.close();
    mCaptureSession = null;
}

正确释放相机资源:

//Camera实现:
public void release() {
    if (mCamera != null) {
        mCamera.setPreviewCallback(null);
        mCamera.release();
        mCamera = null;
    }
}

//Camera2
public void release() {
    if (mCamera != null) {
        mCamera.close();
        mCamera = null;
    }
}

视频录制

Camera实现视频录制,必须严格按照一定的调用顺序。具体可查看Capturing videos

  1. 开启相机:Camera.open()
  2. 设置预览View:setPreviewDiaplay()
  3. 开启预览:startPreview()
  4. 开始录制:
    1. unlock camera
    2. 配置MediaRecorder
    3. MediaRecorder prepare
    4. 开启录制
  5. 停止录制
  6. 停止预览
  7. 释放相机

Camera和Camera2使用MediaRecorder录制视频的流程对比:

上一篇 下一篇

猜你喜欢

热点阅读