1、录制前的预览
一般而言,我们在录制之前,都需要预览。
我们来回归下利用Camera2进行预览的步骤:
- 通过CameraManager获取可用的相机设备列表。
- 通过CameraManager拿到对应相机的参数
- 调用openCamera打开相机。
- 在回调中创建CaptureRequestBuilder与CameraCaptureSession。其中,要将我们的Surface添加到CaptureRequestBuilder中,这里我们还是使用TextureView,通过其SurfaceTexture来创建Surface。
- 调用CameraCaptureSession的setRepeatingRequest来开启预览。
总得来说,预览是比较简单的,拍照与录制时的预览没区别
而安卓上录制有2种方式:
- 利用系统api MediaRecorder ;
- 使用MediaCodeC 自定义录制;
第一种方式比第二种简单很多,下面先来学习第一种方式。
2、利用MediaRecorder 进行录制
MediaRecorder是Android Frameworl提供给开发者的一套用于音频或视频录制的API。我们可以通过它来录制音频或者视频。当然录制视频的时候就需要Camera来配合了,下面我们来看下怎么来配置一个可以录制视频的MediaRecorder。
音频与视频的来源
setAudioSource(int audio_source)
在MediaRecorder里面有一个内部类AudioSource,里面定义了一些静态常量来表示各个音频的来源,我们这里用AudioSource.MIC(麦克风)
setVideoSource(int video_source)
同样的在MediaRecorder中有一个VideoSource的内部类,它只有三个静态常量,DEFAULT、CAMERA、SURFACE。CAMERA是与Camera搭配使用的,它需要给MediaRecord通过setCamera(Camera camera)传一个Camera过来,这里我们用Camera2,所以需要用SURFACE作为视频源,还记得我们上一篇总结的,Camera是通过CaptureRequest和CameraCaptureSession来将图像数据发送到一些我们设置的目标Surface中,所以这里我们用VideoSource.SURFACE。后面我们就可以通过MediaRecorder的getSurface()方法来拿到它的Surface。
这两个方法都需要在setOutputFormat之前调用,如果在之后调用就会抛IllegalStateException异常。
输出格式
setOutputFormat(int output_format)
设置录制过程中输出文件的格式,它需要在setAudioSource()/setVideoSource()之后调用,在prepare()之前调用,同时需要在设置录制参数和解码器之前调用。同样MediaRecorder中的内部类OutputFormat定义了一些静态常量来表示媒体格式。当用H.263视频解码器和AMR音频解码器时,推荐使用3GP格式,对用OutputFormat.THREE_GPP。
输出目录
setOutputFile(String path)
在setOutputFormat()之后,prepare()之前调用
视频的尺寸
setVideoSize(int width, int height)
设置录制视频的宽高
视频码率
setVideoEncodingBitRate(int bitRate)
视频帧率
setVideoFrameRate(int rate)
注意:在某些自动帧率的设备上,这个设置将作为最大帧率而不是一个固定的帧率,实际的帧率会随着光照条件变化而变化。
音频编码器
setAudioEncoder(int audio_encoder)
设置录制的音频编码器,如果没有设置,则输出文件中将不会包含音轨,在setOutputFormat之后prepare之前调用此方法。下面是所有的音频编码器的值
3、录制
介绍完所需要的设置参数后,下面我们来实战一下,测试代码如下:
class VideoRecorder {
private static final String OUTPUT_FILE_PATH = "/sdcard/test_jq.mp4";
private TextureView mTextureView;
private MediaRecorder mMediaRecorder;
private Camera mCamera;
public VideoRecorder(TextureView textureView) {
mTextureView = textureView;
mMediaRecorder = new MediaRecorder();
initCamera();
}
public void start() {
configRecorder();
try {
mMediaRecorder.prepare();
mMediaRecorder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
public void pause() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder.pause();
}
}
public void resume() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder.resume();
}
}
public void stop() {
mMediaRecorder.stop();
}
public void destroy() {
mMediaRecorder.stop();
mMediaRecorder.release();
mCamera.lock();
}
private void configRecorder() {
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoFrameRate(30); //录制的视频帧率
mMediaRecorder.setVideoSize(1280,1920); //录制视频分辨率
mMediaRecorder.setVideoEncodingBitRate(8*1920*1080);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mMediaRecorder.setOutputFile(new File(OUTPUT_FILE_PATH));
}
}
private void initCamera() {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
mCamera.setParameters(parameters);
//设置旋转角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了
mCamera.setDisplayOrientation(90);
mCamera.unlock();
}
总结
其实视频录制的过程还是比较清晰的,首先,预览跟拍照没什么区别,就是录制的时候构建一个MediaRecorder,然后重新创建CaptureRequest与CameraCaptureSession,然后将MediaRecorder的Surface传进去,这样当CameraCaptureSession创建好之后图像数据就会渲染后MediaRecorder的Surface中去,然后调用MediaRecorder的start()方法开始录制。最后停止录制的时候调用MediaRecorder的stop()方法停止录制,并重新创建预览的CaptureRequest和CameraCaptureSession重新开启预览。更多细节可以参考https://github.com/googlesamples/android-Camera2Video。