MediaRecorder + Camera2 视频录制最佳实践

 MediaRecorder 是 Android 官方提供的一个用于音视频录制的类,简化了音频和视频的录制过程,如果只是想单纯的录制视频,MediaRecorder是一个不错的选择

这里采用 Camera2 + MediaRecorder 的方式实现视频录制

步骤:

  1. 获取 CameraManager 实例
  2. 调用 openCamera,打开摄像头
  3. 创建 session
  4. 开启预览
  5. 开启录制
  6. 停止录制

一、获取CameraManager 实例

// 1. 先获取 CameraManager
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

通过 getSystemService(Context.Camera_SERVICE) 即可获取到 CameraManager 的实例,CameraManager 是一个负责查询和建立相机连接的系统服务,Camera2 的所有操作都是从先获取 CameraManager 实例开始

二、调用 openCamera,打开摄像头

// 2. 调用 openCamera,打开摄像头
mCameraManager.openCamera(String.valueOf(mCurrentFacing), new CameraDevice.StateCallback() {
    @Override
    public void onOpened(@NonNull CameraDevice camera) {
        LogUtil.d(TAG, "onOpened: 摄像头链接成功, facing: " + mCurrentFacing);
        // 摄像头成功打开
        mCurrentCameraDevice = camera;
    }
​
    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
        LogUtil.d(TAG, "onDisconnected: 摄像头链接断开");
    }
​
    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
        LogUtil.d(TAG, "onError: 摄像头打开失败, error: " + error);
        camera.close();
    }
}, null);

使用上一步获取到的 CameraManager 实例,调用 openCamera 方法,即可获取到指定摄像头的 CameraDevice 实例,可以对指定摄像头进行操作

三、创建 session

// 3. 创建session,可以看到这里绑定了两个 surface,一个用于承载预览显示,一个用于视频录制
List<Surface> mOutputs = new ArrayList<>();
mOutputs.add(mPreviewSurface);
mOutputs.add(mRecordSurface);
mCurrentCameraDevice.createCaptureSession(mOutputs, new CameraCaptureSession.StateCallback() {
    @Override
    public void onConfigured(@NonNull CameraCaptureSession session) {
        mCurrentCameraCaptureSession = session;
        try {
            // 4. 开启预览
            createPreviewCaptureRequest();
            mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "onConfigured: ", e);
        }
    }
​
    @Override
    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
​
    }
}, null);

Camera2 比较特殊的点就是,所有的操作行为都是在 session 上完成的,所以 打开摄像头之后,通过 CameraDevice 实例创建指定的 session

值得注意的是,在 createSession 的时候有一个绑定 surface 的操作,这关系到后续能在 session 上执行什么操作,如果需要预览,那需要绑定 承载预览流的 previewSurface,如果需要录制视频,需要绑定 承载视频流的 recordSurface,如果需要拍照,则需要绑定 承载拍照数据的 imageReader

这里我们需要预览和录制,所以绑定了两个surface,一个用于预览,一个用于录制

四、开启预览

// 4. 开启预览
createPreviewCaptureRequest();
mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
​
/**
 * 用于预览显示的request
 */
private void createPreviewCaptureRequest() {
    try {
        CaptureRequest.Builder mCurrentPreviewRequestBuilder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mCurrentPreviewRequestBuilder.addTarget(mPreviewSurface);
        mCurrentPreviewRequest = mCurrentPreviewRequestBuilder.build();
    } catch (CameraAccessException e) {
        LogUtil.e(TAG, "createPreviewCaptureRequest: ", e);
    }
}

createSession 成功之后,就可以 创建 CaptureRequest,然后通过 session 的 setRepeatingRequest 方法开始呈现预览了

如果只需要呈现预览,到这里已经完成了,接下来开始录制

五、开启录制

private void startRecording(){
    isRecording = true;
    try {
        // 5. 开启录制
        // 先准备 mediaRecorder
        prepareMediaRecorder();
        // 创建录制视频用的 request
        createVideoRecordCaptureRequest();
        // 先将 PreviewRequest 停掉,因为 PreviewRequest 只绑定了一个previewSurface target,录制的时候还需要绑定 recordSurface target
        mCurrentCameraCaptureSession.stopRepeating();
        // 开始 recordRequest 请求
        mCurrentCameraCaptureSession.setRepeatingRequest(mVideoRecordRequest, null, null);
        // 开始录制
        mMediaRecorder.start();
    } catch (CameraAccessException e) {
        LogUtil.e(TAG, "startRecording: ", e);
    }
}
​
private void prepareMediaRecorder(){
    try {
        // 这里很重要的一个点 mediaRecorder 的复用,不需要每次重新 new 一个新的
        if(mMediaRecorder == null){
            mMediaRecorder = new MediaRecorder();
        }else {
            // 如果 mMediaRecorder 存在,只需要重新 reset 就行
            mMediaRecorder.reset();
        }
        // surface 通过 MediaCodec.createPersistentInputSurface() 创建,
        // 然后通过 setInputSurface 的方式设置给 MediaRecorder
        // 这个 surface 也会在 createSession 时和 previewSurface 一起传入,这样开始录制时就不需要重新创建 session
        if(mRecordSurface == null){
            mRecordSurface = MediaCodec.createPersistentInputSurface();
        }
        mMediaRecorder.setInputSurface(mRecordSurface);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        // 设置视频文件地址,需要读写权限
        mMediaRecorder.setOutputFile(mVideoFilePath);
        mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
        mMediaRecorder.setVideoFrameRate(25);
        mMediaRecorder.setOrientationHint(90);
        // prepare 执行之后 才能使用
        mMediaRecorder.prepare();
    } catch (IOException e) {
        LogUtil.e(TAG, "prepareMediaRecorder: ", e);
    }
}
​
/**
 * 用于录制视频的request
 */
private void createVideoRecordCaptureRequest(){
    try {
        CaptureRequest.Builder builder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        // 用于承载录制视频流
        builder.addTarget(mRecordSurface);
        // 用于承载预览显示流
        builder.addTarget(mPreviewSurface);
        mVideoRecordRequest = builder.build();
    } catch (CameraAccessException e) {
        LogUtil.e(TAG, "createVideoRecordCaptureRequest: ", e);
    }
}

对于视频录制,我们用到了 MediaRecorder,先准备好 MediaRecorder,然后调用 start 方法就可以开始录制了,这里有一个点,MediaRecorder 录制所需要的视频流数据从哪里来,如何和 Camera 绑定?

我们可以先创建 surface,和 MediaRecorder 绑定

if(mRecordSurface == null){
    mRecordSurface = MediaCodec.createPersistentInputSurface();
}
mMediaRecorder.setInputSurface(mRecordSurface);

还记得上面我们创建 session 的时候绑定了两个 surface,其中一个就是 mRecorderSurface,通过这种方式

  1. mRecordSurface 通过 RepeatingRequest ,持续的从底层拿到了视频流数据

  2. MediaRecorder 又从 mRecordSurface 中拿到视频流数据合成视频

六、停止录制

private void stopRecording(){
    isRecording = false;
    // 6. 结束录制
    if(mMediaRecorder != null){
        // 停止录制
        mMediaRecorder.stop();
    }
    if(mCurrentCameraCaptureSession != null){
        try {
            // 先将 RecordRequest 请求停掉,因为录制停止之后,只需要一个预览流即可,降低功耗
            mCurrentCameraCaptureSession.stopRepeating();
            mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "stopRecording: ", e);
        }
    }
}

只需要调用 stop 方法,就可以停止视频录制,这里我们还是做了一个功耗优化,停掉了当前的 repeatingRequset,重新只发送只有一个 previewSurface 的 repeatingRequset,这样可以在预览时减少一路流的消耗,降低功耗

完整代码

public class VideoRecord2Activity extends AppCompatActivity {
    private static final String TAG = "VideoRecordActivity";
​
    private Context mContext;
    private CameraManager mCameraManager;
    private int mFacingFront = -1;
    private int mFacingBack = -1;
    private int mCurrentFacing = mFacingFront;
​
    private CameraDevice mCurrentCameraDevice;
    private CaptureRequest mCurrentPreviewRequest;
    private TextureView mTextureView;
    private Surface mPreviewSurface;
    private CameraCaptureSession mCurrentCameraCaptureSession;
​
    private Button mBtnTakePicture;
​
    private Size mVideoSize = new Size(810,720);
​
    private boolean isRecording = false;
    private MediaRecorder mMediaRecorder;
    private Surface mRecordSurface;
    private CaptureRequest mVideoRecordRequest;
    private String mVideoFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/video.mp4";
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_record);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        this.mContext = this;
        initView();
        initCamera();
        mCurrentFacing = mFacingBack;
    }
​
    private void initView() {
        mTextureView = findViewById(R.id.view_camera_texture);
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
                // 这里解释一下,为什么摄像头打开的时候没有马上打开预览,因为预览画面的展示需要 surface 承载,所以需要等 surface 准备好才行
                surface.setDefaultBufferSize(mVideoSize.getWidth(),mVideoSize.getHeight());
                // 预览所需的 previewSurface
                mPreviewSurface = new Surface(surface);
                // 准备视频录制时所需的 recordSurface
                prepareMediaRecorder();
                startPreview();
            }
​
            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
​
            }
​
            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                mPreviewSurface.release();
                mPreviewSurface = null;
                return false;
            }
​
            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
​
            }
        });
​
        mBtnTakePicture = findViewById(R.id.btn_take_picture);
        mBtnTakePicture.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LogUtil.d(TAG, "onClick: 点击拍照");
                if(isRecording){
                    stopRecording();
                    mBtnTakePicture.setText("录制");
                }else {
                    startRecording();
                    mBtnTakePicture.setText("停止");
                }
            }
        });
    }
​
    private void initCamera() {
        // 1. 先获取 CameraManager
        mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        if (mCameraManager == null) {
            return;
        }
        try {
            for (String cameraId : mCameraManager.getCameraIdList()) {
                CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
                int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing == CameraCharacteristics.LENS_FACING_FRONT) {
                    mFacingFront = Integer.parseInt(cameraId);
                    int supportLEVEL = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
                    LogUtil.d(TAG, "testCamera2: 当前是前摄,supportLEVEL: " + supportLEVEL);
                } else if (facing == CameraCharacteristics.LENS_FACING_BACK) {
                    mFacingBack = Integer.parseInt(cameraId);
                    int supportLEVEL = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
                    LogUtil.d(TAG, "testCamera2: 当前是后摄,supportLEVEL: " + supportLEVEL);
                }
            }
        } catch (CameraAccessException e) {
            Log.e(TAG, "testCamera2: ", e);
        }
    }
​
    private void openCamera(){
        closeCamera();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        try {
            // 2. 调用 openCamera,打开摄像头
            mCameraManager.openCamera(String.valueOf(mCurrentFacing), new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    LogUtil.d(TAG, "onOpened: 摄像头链接成功, facing: " + mCurrentFacing);
                    // 摄像头成功打开
                    mCurrentCameraDevice = camera;
                }
​
                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    LogUtil.d(TAG, "onDisconnected: 摄像头链接断开");
                }
​
                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    LogUtil.d(TAG, "onError: 摄像头打开失败, error: " + error);
                    camera.close();
                }
            }, null);
        } catch (CameraAccessException e) {
            Log.e(TAG, "openCamera: ", e);
        }
    }
​
    private void startPreview(){
        if(mCurrentCameraDevice == null){
            return;
        }
        if(mPreviewSurface == null){
            return;
        }
        try {
            // 3. 创建session,可以看到这里绑定了两个 surface,一个用于承载预览显示,一个用于视频录制
            List<Surface> mOutputs = new ArrayList<>();
            mOutputs.add(mPreviewSurface);
            mOutputs.add(mRecordSurface);
            mCurrentCameraDevice.createCaptureSession(mOutputs, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mCurrentCameraCaptureSession = session;
                    try {
                        // 4. 开启预览
                        createPreviewCaptureRequest();
                        mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
                    } catch (CameraAccessException e) {
                        LogUtil.e(TAG, "onConfigured: ", e);
                    }
                }
​
                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
​
                }
            }, null);
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "startPreview: ", e);
        }
    }
​
    /**
     * 用于预览显示的request
     */
    private void createPreviewCaptureRequest() {
        try {
            CaptureRequest.Builder mCurrentPreviewRequestBuilder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mCurrentPreviewRequestBuilder.addTarget(mPreviewSurface);
            mCurrentPreviewRequest = mCurrentPreviewRequestBuilder.build();
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "createPreviewCaptureRequest: ", e);
        }
    }
​
    /**
     * 用于录制视频的request
     */
    private void createVideoRecordCaptureRequest(){
        try {
            CaptureRequest.Builder builder = mCurrentCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 用于承载录制视频流
            builder.addTarget(mRecordSurface);
            // 用于承载预览显示流
            builder.addTarget(mPreviewSurface);
            mVideoRecordRequest = builder.build();
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "createVideoRecordCaptureRequest: ", e);
        }
    }
​
    private void closeCamera(){
        if(mCurrentCameraDevice != null){
            mCurrentCameraDevice.close();
            mCurrentCameraDevice = null;
        }
    }
​
    @Override
    protected void onResume() {
        super.onResume();
        openCamera();
    }
​
    @Override
    protected void onPause() {
        super.onPause();
        closeCamera();
        if(mMediaRecorder != null){
            mMediaRecorder.release();
            mMediaRecorder = null;
        }
        if(mRecordSurface != null){
            mRecordSurface.release();
            mRecordSurface = null;
        }
    }
​
    private void prepareMediaRecorder(){
        try {
            // 这里很重要的一个点 mediaRecorder 的复用,不需要每次重新 new 一个新的
            if(mMediaRecorder == null){
                mMediaRecorder = new MediaRecorder();
            }else {
                // 如果 mMediaRecorder 存在,只需要重新 reset 就行
                mMediaRecorder.reset();
            }
            // surface 通过 MediaCodec.createPersistentInputSurface() 创建,
            // 然后通过 setInputSurface 的方式设置给 MediaRecorder
            // 这个 surface 也会在 createSession 时和 previewSurface 一起传入,这样开始录制时就不需要重新创建 session
            if(mRecordSurface == null){
                mRecordSurface = MediaCodec.createPersistentInputSurface();
            }
            mMediaRecorder.setInputSurface(mRecordSurface);
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            // 设置视频文件地址,需要读写权限
            mMediaRecorder.setOutputFile(mVideoFilePath);
            mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
            mMediaRecorder.setVideoFrameRate(25);
            mMediaRecorder.setOrientationHint(90);
            // prepare 执行之后 才能使用
            mMediaRecorder.prepare();
        } catch (IOException e) {
            LogUtil.e(TAG, "prepareMediaRecorder: ", e);
        }
    }
​
    private void startRecording(){
        isRecording = true;
        try {
            // 5. 开启录制
            // 先准备 mediaRecorder
            prepareMediaRecorder();
            // 创建录制视频用的 request
            createVideoRecordCaptureRequest();
            // 先将 PreviewRequest 停掉,因为 PreviewRequest 只绑定了一个previewSurface target,录制的时候还需要绑定 recordSurface target
            mCurrentCameraCaptureSession.stopRepeating();
            // 开始 recordRequest 请求
            mCurrentCameraCaptureSession.setRepeatingRequest(mVideoRecordRequest, null, null);
            // 开始录制
            mMediaRecorder.start();
        } catch (CameraAccessException e) {
            LogUtil.e(TAG, "startRecording: ", e);
        }
    }
​
    private void stopRecording(){
        isRecording = false;
        // 6. 结束录制
        if(mMediaRecorder != null){
            // 停止录制
            mMediaRecorder.stop();
        }
        if(mCurrentCameraCaptureSession != null){
            try {
                // 先将 RecordRequest 请求停掉,因为录制停止之后,只需要一个预览流即可,降低功耗
                mCurrentCameraCaptureSession.stopRepeating();
                mCurrentCameraCaptureSession.setRepeatingRequest(mCurrentPreviewRequest, null, null);
            } catch (CameraAccessException e) {
                LogUtil.e(TAG, "stopRecording: ", e);
            }
        }
    }
}

### 回答1: 安卓camera2拍照录制视频demo是基于安卓相机API的一个示例应用程序,用于演示如何使用安卓相机2 API来实现拍照和录制视频功能。 在此示例应用程序中,首先需要初始化相机设备并获取相机特性、参数等信息。然后,可以通过创建一个用于预览的SurfaceView或TextureView,并将其设置为相机的预览输出目标。 在拍照功能方面,可以通过设置拍照的一些参数,如图片格式、拍照模式、闪光灯模式等。然后,可以通过调用相机的拍照方法,触发相机拍照操作,并在拍照完成后保存图片。 在录制视频功能方面,需要创建一个用于录制视频MediaRecorder对象,并设置视频的输出格式、编码格式、视频大小等参数。然后,可以通过设置相机的预览输出目标为MediaRecorder的Surface,并调用MediaRecorder的start方法开始录制视频,调用stop方法停止录制。 此外,在实际开发中,还需要处理相机权限的获取和申请,以及相机的生命周期管理,如在Activity的onResume和onPause方法中初始化和释放相机等。还可以根据需要添加其他功能,如自动对焦、曝光调节等。 总之,安卓camera2拍照录制视频demo提供了一个基本的框架和实现思路,供开发者参考和借鉴,在此基础上可以根据实际需求进行扩展和定制。 ### 回答2: 安卓Camera2是用于在安卓设备上进行相机操作的API。它提供了更多的功能和控制选项,可以实现更高级的相机操作,比如手动对焦、曝光控制、帧率控制等。 要编写一个拍照录制视频的Demo,首先需要获取相机的权限。在AndroidManifest.xml文件中添加相机权限的声明: <uses-permission android:name="android.permission.CAMERA" /> 然后,在布局文件中添加一个相机预览的SurfaceView: <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> 接下来,在Activity中获取相机实例并进行相关配置。首先创建一个CameraManager对象,通过它来获取相机ID和打开相机: CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); String cameraId = cameraManager.getCameraIdList()[0]; cameraManager.openCamera(cameraId, cameraStateCallback, null); 在相机状态回调中,可以配置相机预览的Surface和启动预览: CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { try { // 设置相机预览的Surface CaptureRequest.Builder requestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); requestBuilder.addTarget(surfaceView.getHolder().getSurface()); // 启动预览 session.setRepeatingRequest(requestBuilder.build(), null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 配置失败处理 } }; 最后,编写点击拍照和录制视频的逻辑。点击拍照时,创建一个ImageReader对象,设置监听器来处理拍照结果: ImageReader imageReader = ImageReader.newInstance(imageWidth, imageHeight, ImageFormat.JPEG, 1); imageReader.setOnImageAvailableListener(onImageAvailableListener, null); ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { // 处理拍照结果 } }; 点击开始录制视频时,创建一个MediaRecorder对象,并配置输出文件、音频源、视频源等参数。然后使用CameraCaptureSession进行录制会话: MediaRecorder mediaRecorder = new MediaRecorder(); mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 配置输出文件,视频尺寸等参数 sessionStateCallback.onConfigured(cameraCaptureSession); // 启动预览 mediaRecorder.prepare(); mediaRecorder.start(); 以上是一个简单的安卓Camera2拍照录制视频Demo的实现。通过Camera2 API可以实现更多的相机功能和控制选项,可以根据实际需求进行更多的定制和扩展。 ### 回答3: 安卓的Camera2 API是一个强大的相机框架,可以实现高效的拍照和录制视频功能。 首先,我们需要在AndroidManifest.xml文件中声明相机和音频录制权限。例如: <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> 然后,我们需要在Activity或Fragment中创建一个CameraManager对象来管理相机设备。例如: private CameraManager mCameraManager; mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 接下来,我们需要获取可用的相机列表,并选择一个需要使用的相机设备。例如: String cameraId = null; try { for (String id : mCameraManager.getCameraIdList()) { CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id); int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing == CameraCharacteristics.LENS_FACING_BACK) { cameraId = id; break; } } } catch (CameraAccessException e) { e.printStackTrace(); } 然后,我们可以打开相机设备并开始预览。例如: try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { mCameraManager.openCamera(cameraId, mCameraStateCallback, null); } } catch (CameraAccessException e) { e.printStackTrace(); } 在相机预览过程中,我们可以设置一些相机参数,例如预览尺寸、拍照尺寸、闪光灯模式等。例如: CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureBuilder.addTarget(mPreviewSurface); captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); 然后,我们可以通过调用CameraCaptureSession的capture方法来拍照。例如: mCameraCaptureSession.capture(captureBuilder.build(), mCaptureCallback, null); 如果要录制视频,可以通过MediaRecorder来实现。例如: private void startRecording() throws IOException { mMediaRecorder = new MediaRecorder(); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(mOutputFile.getAbsolutePath()); // 设置视频参数 mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight()); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置音频参数 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); mMediaRecorder.setAudioChannels(1); mMediaRecorder.setAudioSamplingRate(16000); mMediaRecorder.setAudioEncodingBitRate(32000); mMediaRecorder.prepare(); mMediaRecorder.start(); } 最后,我们可以在相机的onClosed方法中释放相机资源和停止录制。例如: @Override public void onClosed(CameraDevice camera) { mCameraDevice.close(); mCameraDevice = null; if (mMediaRecorder != null) { mMediaRecorder.stop(); mMediaRecorder.reset(); mMediaRecorder.release(); mMediaRecorder = null; } } 通过上述步骤,我们可以实现一个简单的安卓Camera2拍照和录制视频的demo。希望对你有所帮助!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值