📜  Android 相机教程(1)

📅  最后修改于: 2023-12-03 14:59:16.672000             🧑  作者: Mango

Android 相机教程

Android 中的相机是一个非常重要的功能,可以让我们的应用程序有更多的互动性和创造力。在本教程中,我们将介绍如何使用Android相机实现拍照,录制视频等功能。

1. 权限

首先,在使用相机之前,我们需要在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" /> <!-- 写入SD卡 -->
2. 相机预览

在使用相机之前,我们需要先获取相机预览。相机预览需要SurfaceView(或者TextureView)来进行展示。我们需要实现SurfaceHolder.Callback接口来控制SurfaceView的生命周期。具体代码如下:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // 添加SurfaceHolder回调
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 在surface被创建时打开相机预览
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "相机预览失败: " + e.getMessage());
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // 在销毁surface之前,停止相机预览
        mCamera.stopPreview();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 在surface尺寸被改变时,更新相机预览尺寸
        if (mHolder.getSurface() == null) {
            return;
        }
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // 忽略异常
        }
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (Exception e) {
            Log.e(TAG, "预览尺寸更改失败: " + e.getMessage());
        }
    }
}
3. 拍照

在预览界面中添加一个按钮,点击按钮即可拍照。具体代码如下:

public class MainActivity extends AppCompatActivity {
    private Camera mCamera;
    private CameraPreview mPreview;

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

        // 创建相机实例
        mCamera = getCameraInstance();

        // 创建相机预览
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = findViewById(R.id.preview);
        preview.addView(mPreview);

        // 拍照按钮
        Button captureButton = findViewById(R.id.capture);
        captureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mCamera.takePicture(null, null, mPicture);
            }
        });
    }

    /** 获取相机实例 */
    public static Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e) {
            Log.e(TAG, "相机打开失败: " + e.getMessage());
        }
        return c;
    }

    // 拍照回调
    private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            // 处理照片数据,保存到文件或者显示在界面上
        }
    };
}
4. 录制视频

同样是在预览界面中添加一个按钮,点击按钮即可开始、暂停、停止录制视频。具体代码如下:

public class MainActivity extends AppCompatActivity {
    private Camera mCamera;
    private CameraPreview mPreview;
    private MediaRecorder mMediaRecorder;
    private boolean isRecording = false;

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

        // 创建相机实例
        mCamera = getCameraInstance();

        // 创建相机预览
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = findViewById(R.id.preview);
        preview.addView(mPreview);

        // 录制视频按钮
        Button captureButton = findViewById(R.id.capture);
        captureButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    stopRecording();
                } else {
                    startRecording();
                }
            }
        });
    }

    /** 获取相机实例 */
    public static Camera getCameraInstance() {
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e) {
            Log.e(TAG, "相机打开失败: " + e.getMessage());
        }
        return c;
    }

    /** 开始录制视频 */
    private void startRecording() {
        // 准备MediaRecorder
        mMediaRecorder = new MediaRecorder();
        mCamera.unlock();
        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.setVideoSize(640, 480);
        mMediaRecorder.setVideoFrameRate(30);
        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

        // 开始录制
        try {
            mMediaRecorder.prepare();
            mMediaRecorder.start();
            isRecording = true;
        } catch (Exception e) {
            Log.e(TAG, "录制视频失败: " + e.getMessage());
            releaseMediaRecorder();
        }
    }

    /** 停止录制视频 */
    private void stopRecording() {
        // 停止录制
        try {
            mMediaRecorder.stop();
        } catch (Exception e) {
            Log.e(TAG, "停止录制视频失败: " + e.getMessage());
        }
        releaseMediaRecorder();
        mCamera.lock();
        isRecording = false;
    }

    /** 释放MediaRecorder */
    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();
            mMediaRecorder.release();
            mMediaRecorder = null;
        }
    }

    /** 获取输出媒体文件 */
    private static Uri getOutputMediaFileUri(int type) {
        return Uri.fromFile(getOutputMediaFile(type));
    }

    /** 获取输出媒体文件 */
    private static File getOutputMediaFile(int type) {
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), "MyCameraApp");
        if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) {
            return null;
        }

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4");
        } else {
            return null;
        }

        return mediaFile;
    }
}
结论

通过本教程,我们了解了在Android中使用相机的方法。我们实现了相机预览,拍照以及录制视频三个功能。根据自己的需求,我们可以选择相应的实现。同时,在实际开发中,我们还需要注意相机资源的释放和异常处理等问题。