本文分享自己在视频录制播放过程中遇到的一些问题,主要包括:
- 视频录制流程
- 视频预览及SurfaceHolder
- 视频清晰度及文件大小
- 视频文件旋转
1、视频录制流程
以微信为例,其录制触发为按下(住)录制按钮,结束录制的触发条件为松开录制按钮或录制时间结束,其流程大概可以用下图来描述。
1.1、开始录制
根据上述流程及项目的编程惯例,可在onCreate()定义如下函数来完成功能:
初始化过程主要包括View,Data以及Listener三部分。在初始化View时,添加摄像头预览,添加倒计时文本组件,设置初始状态UI组件的可见;初始化Data时,从Intent中获取初始数据;初始化Listener时,分别对录制触发按钮,保存/取消视频录制按钮以及视频预览界面添加监听。
当系统初始化成功后,等待用户按下录制按钮,因此在录制按钮的监听中,需要完成以下功能:录制,计时,更新界面组件。
if(isRecording) {
mMediaRecorder.stop();
releaseMediaRecorder();
mCamera.lock();
isRecording = false;
}
if(startRecordVideo()) {
startTimeVideoRecord();
isRecording = true;
}
首先判断当前录制状态,如果正在录制,则先停止录制,释放MediaRecorder资源,锁定摄像头,置位录制状态;然后开始视频录制startRecordVideo,其boolean型返回值表征是否启动成功,启动成功后,开始视频录制计时,并且置位录制状态。startRecordVideo涉及MediaRecorder的配置,准备以及启动。
翻译成代码如下:
private boolean startRecordVideo() {
configureMediaRecorder();
if(!prepareConfiguredMediaRecorder()) {
return false;
}
mMediaRecorder.start();
return true;
}
1.2、结束录制
根据上述流程图可知,结束录制的触发条件为松开录制按钮或计时时间到。在结束录制方法中,需要释放MediaRecorder,开始循环播放已录制视频,设置界面更新等。
翻译成代码如下:
private void stopRecordVideo() {
releaseMediaRecorder();
// 录制视频文件处理
if(currentRecordProgress < MIN_RECORD_TIME) {
Toast.makeText(VideoInputActivity.this, "录制时间太短", Toast.LENGTH_SHORT).show();
} else {
startVideoPlay();
isPlaying = true;
setUiDisplayAfterVideoRecordFinish();
}
currentRecordProgress = 0;
updateProgressBar(currentRecordProgress);
releaseTimer();
// 状态设置
isRecording = false;
}
2、视频预览及SurfaceHolder
视频预览采用SurfaceView,相比于普通的View,SurfaceView在一个新起的单独线程中绘制画面,该实现的优点是更新画面不会阻塞UI主线程,缺点是会带来事件同步的问题。当然,这涉及到UI事件的传递以及线程同步,这里不做详细说明,有兴趣的可以参考链接:http://wugengxin.cn/download/pdf/android/PRE_andevcon_mastering-the-android-touch-system.pdf
在实现中,通过继承SurfaceView组件来实现自定义预览控件。首先,SurfaceView的getHolder()方法会返回SurfaceHolder,需要为SurfaceHolder添加SurfaceHolder.Callback回调;其次,重写surfaceCreated、surfaceChanged和surfaceDestroyed实现。
2.1、构造器
构造器包含了初始化域以及添加上述回调的过程。
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes