使用 MediaRecorder实现分段录制视频
使用 MediaCodec 和 MediaMuxer 也可以实现分段录制视频,而也是一直这样做,但是遇到一个问题,就是 MediaMuxer 的 OutputFormat 支持 4 种格式,分别是 MUXER_OUTPUT_MPEG_4、MUXER_OUTPUT_WEBM、MUXER_OUTPUT_3GPP、MUXER_OUTPUT_HEIF,一般经常用的也就是 MUXER_OUTPUT_MPEG_4,录制 .mp4 格式的文件。
但是在录制时,有一个情况,就是我的设备突然断电时,最后录制的那段视频是损坏的,无法播放。合作伙伴的录像是录出 .ts 文件格式,设备突然断电文件依然可以正常播放,公司领导让我调研一下。我发现 MediaRecorder 可以录制 .ts 视频,MediaRecorder 的 OutputFormat 包含 MPEG_2_TS 这个格式,也就可以录制 .ts 文件,确实录制 .ts 文件过程中,中途给设备断电,最后那段文件依然可以播放。
但是在实现分段录制时,遇到了各种各样的情况,首先官方 api 提供了 setMaxDuration 的方法,到了设定的时间,会有回调方法进行通知,但是,通知收到后,MediaRecorder 就进入了 stop 状态,无法继续录制,想要继续录制,要重新初始化 MediaRecorder。
下面是我最终实现的解决方法,代码中有我的注释,有不对的地方请帮忙指出。
private void initMediaRecorder() {
mediaRecorder = new MediaRecorder();
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);// 这里我是用的 surface 作为源,一般这里设置 camera
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);// 设置 ts 格式
mediaRecorder.setVideoFrameRate(25);
mediaRecorder.setVideoSize(1920, 1080);
mediaRecorder.setVideoEncodingBitRate(2097152);// 2M 码率
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 这里有一个问题,当我的格式设置成 ts 格式时,下面的 MaxDuration 就不起作用了,不知道为什么,MPEG_4 格式就可以。
// mediaRecorder.setMaxDuration(1000 * 10);// 测试 10 秒钟路一段
// mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
// @Override
// public void onInfo(MediaRecorder mr, int what, int extra) {
// Log.e("WillWolf", "onInfo-->" + what);
// if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
// // 官方文档说明,设置了最大时长时,回调会进入 stop 状态,如果需要继续录制,则需要重新初始化
// mediaRecorder.stop();
// mediaRecorder.reset();
// mediaRecorder.release();
// mediaRecorder = null;
// isFirstStart = false;
// initMediaRecorder();
// }
// }
// });
mediaRecorder.setOutputFile("/sdcard/" + System.currentTimeMillis() + ".ts");
try {
mediaRecorder.prepare();
mediaRecorderSurface = mediaRecorder.getSurface();
mediaRecorder.start();
// 我改用 handler 测试分段,10 秒种后,handler 录制下一段。
handler.sendEmptyMessageDelayed(1, 10 * 1000);
} catch (IOException e) {
e.printStackTrace();
Log.e("WillWolf", "mediaRecorder-->" + e.toString());
}
}
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
if (msg.what == 1) {
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
mediaRecorder = null;
isFirstStart = false;
initMediaRecorder();
}
return false;
}
});
这也算是曲线救国了,测试程序看起来可以录制 .ts 文件,并且实现了分段录制,当意外断电时,最后的 .ts 文件依然可以播放。