Android SurfaceView录像

引言

在开发Android应用程序时,我们经常需要使用摄像头来进行视频录制。而SurfaceView是一个用于在屏幕上绘制图像的视图,通常用于显示相机预览。在本篇文章中,我们将介绍如何使用Android的SurfaceView来录制视频。

准备工作

在开始之前,确保你已经创建了一个Android项目,并且具备基本的Android开发知识。同时,你还需要在AndroidManifest.xml文件中添加相应的权限:

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

这些权限将允许我们访问摄像头、录制音频和保存录像文件。

创建SurfaceView布局

首先,我们需要在布局文件中创建一个用于显示相机预览的SurfaceView。在activity_main.xml文件中添加如下代码:

<SurfaceView
    android:id="@+id/surfaceView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

初始化相机

接下来,在MainActivity.java中初始化相机。我们需要在onCreate()方法中添加以下代码:

private Camera mCamera;
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mSurfaceView = findViewById(R.id.surfaceView);
    mSurfaceHolder = mSurfaceView.getHolder();
    mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mCamera = Camera.open();
            try {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            } catch (IOException e) {
                Log.e(TAG, "Error setting camera preview: " + e.getMessage());
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if (mSurfaceHolder.getSurface() == null) {
                return;
            }

            try {
                mCamera.stopPreview();
            } catch (Exception e) {
                Log.e(TAG, "Error stopping camera preview: " + e.getMessage());
            }

            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
                mCamera.startPreview();
            } catch (Exception e) {
                Log.e(TAG, "Error starting camera preview: " + e.getMessage());
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    });
}

private static final String TAG = "MainActivity";

在上述代码中,我们打开了相机,并将预览显示在SurfaceView上。在SurfaceHolder的回调方法中,我们处理了SurfaceView的创建、改变和销毁事件。

录制视频

接下来,我们需要在MainActivity.java中添加方法来录制视频。我们将创建一个startRecording()方法来开始录制,以及一个stopRecording()方法来停止录制。添加以下代码:

private MediaRecorder mMediaRecorder;
private boolean isRecording = false;

private void startRecording() {
    if (isRecording) {
        return;
    }

    mCamera.unlock();
    mMediaRecorder = new MediaRecorder();
    mMediaRecorder.setCamera(mCamera);
    mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
    mMediaRecorder.setOutputFile(getOutputMediaFile().toString());
    mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

    try {
        mMediaRecorder.prepare();
        mMediaRecorder.start();
        isRecording = true;
    } catch (IOException e) {
        Log.e(TAG, "Error starting MediaRecorder: " + e.getMessage());
    }
}

private void stopRecording() {
    if (!isRecording) {
        return;
    }

    mMediaRecorder.stop();
    mMediaRecorder.reset();
    mMediaRecorder.release();
    mMediaRecorder = null;
    mCamera.lock();
    isRecording = false;
}

private File getOutputMediaFile() {
    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_MOVIES), "MyVideos");

    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.e(TAG, "Failed to create directory.");
            return null;
        }
    }

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    return new File(media