10. 视频录制基础:MediaRecorder配置、设置视频编码参数、开始/停止录制
好,咱们今天来聊聊视频录制。Android 上做视频采集,MediaRecorder 是绕不开的一个组件。说实话,这玩意儿 API 看起来简单,但坑是真不少。我最早接触它的时候,以为就是 new 一个对象,调几个方法就完事了。结果呢?录出来的视频要么没声音,要么画面卡成 PPT,要么文件根本打不开。
嗯,咱们今天就把这块彻底捋清楚。从配置到编码参数,再到开始和停止录制,每一步我都会把我在项目中踩过的坑讲给你听。
10.1 MediaRecorder 的基本配置流程
先看一个最基础的配置流程。你想想看,MediaRecorder 就像一个录像机,你得先告诉它:用什么摄像头、录什么格式、存到哪里去。
// 创建实例
MediaRecorder mediaRecorder = new MediaRecorder();
// 设置音频源(麦克风)
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置视频源(摄像头)
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 设置输出格式
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 设置音频编码
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
// 设置视频编码
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 设置输出文件路径
mediaRecorder.setOutputFile(getOutputFilePath());
// 准备录制
mediaRecorder.prepare();
// 开始录制
mediaRecorder.start();
这个顺序是固定的,千万别乱调。我见过有人把 setAudioSource 放在 setOutputFormat 后面,结果直接崩溃。为什么?因为 MediaRecorder 内部的状态机要求你必须按这个顺序来。
核心要点:配置顺序必须严格遵守:setAudioSource → setVideoSource → setOutputFormat → setAudioEncoder → setVideoEncoder → setOutputFile → prepare → start。
10.2 视频编码参数详解
光配个编码器名字还不够。你得告诉它码率、帧率、分辨率这些参数。说白了,这些参数决定了视频的质量和文件大小。
| 参数 | 方法 | 说明 | 推荐值 |
|---|---|---|---|
| 视频码率 | setVideoEncodingBitRate | 每秒传输的数据量,越高画质越好,文件越大 | 2-8 Mbps(1080p) |
| 视频帧率 | setVideoFrameRate | 每秒显示的帧数,越高越流畅 | 24-30 fps |
| 视频分辨率 | setVideoSize | 画面的宽高像素数 | 1920x1080 或 1280x720 |
| 音频码率 | setAudioEncodingBitRate | 音频的采样数据量 | 128-192 kbps |
| 音频采样率 | setAudioSamplingRate | 每秒采集音频样本数 | 44100 Hz |
// 设置视频参数
mediaRecorder.setVideoEncodingBitRate(5_000_000); // 5 Mbps
mediaRecorder.setVideoFrameRate(30); // 30 fps
mediaRecorder.setVideoSize(1920, 1080); // 1080p
// 设置音频参数
mediaRecorder.setAudioEncodingBitRate(128_000); // 128 kbps
mediaRecorder.setAudioSamplingRate(44100); // 44.1 kHz
我的经验:码率不是越高越好。我曾经在一个项目里把码率设到 20 Mbps,结果录了 5 分钟,手机烫得能煎鸡蛋。对于大多数场景,1080p 配 5 Mbps 就够用了。如果你做的是短视频 App,甚至可以降到 3 Mbps,用户肉眼基本看不出区别。
10.3 开始录制与停止录制
配置完了,就该干活了。开始录制很简单,调 start() 就行。但停止录制的时候,有个细节很多人会忽略。
// 开始录制
mediaRecorder.start();
// ... 录制过程中 ...
// 停止录制
try {
mediaRecorder.stop();
} catch (RuntimeException e) {
// 如果录制时间太短,stop() 可能会抛异常
e.printStackTrace();
} finally {
mediaRecorder.release();
mediaRecorder = null;
}
为什么要加 try-catch?因为如果录制时间太短(比如不到 1 秒),MediaRecorder 可能还没写入足够的文件头信息,这时候调 stop() 会直接抛 RuntimeException。我第一次遇到这个问题时,找了半天 bug,最后发现是用户点了一下录制按钮就松开了。
注意:stop() 之后必须调 release() 释放资源。否则下次再创建 MediaRecorder 时,可能会因为底层资源没释放而失败。另外,release() 之后要把对象置为 null,避免内存泄漏。
10.4 录制过程中的状态管理
MediaRecorder 内部有一套完整的状态机。你想想看,如果录制过程中突然来个电话,或者用户按了 Home 键,这时候该怎么办?
我的做法是在 Activity 或 Fragment 的生命周期里做处理:
@Override
protected void onPause() {
super.onPause();
if (mediaRecorder != null) {
try {
mediaRecorder.stop();
} catch (RuntimeException e) {
// 忽略异常,文件可能不完整
}
mediaRecorder.release();
mediaRecorder = null;
}
}
嗯,这里要注意。如果你在 onPause 里直接 stop,录制的文件可能是不完整的。更好的做法是给用户一个提示,或者把当前片段保存下来,等回到前台时继续录制。不过那是进阶话题了,咱们后面会讲到。
10.5 核心流程总览
说了这么多,咱们用一张图把整个流程串起来。这样你脑子里会有一个清晰的脉络。
这张图把整个流程分成了四个阶段:配置、准备、录制、结束。每个阶段都有固定的操作,跳过一个或者顺序错了,都会出问题。
10.6 常见问题与避坑指南
- 录制出来的视频没有声音:检查一下有没有申请 RECORD_AUDIO 权限。Android 6.0 以上需要运行时权限,很多人会漏掉。
- 视频文件打不开:大概率是 stop() 之前没有写入足够的文件头。确保录制时间至少 2 秒以上。
- 画面卡顿:帧率设太高了。有些低端设备撑不住 60 fps,老老实实用 30 fps。
- 录制过程中崩溃:检查一下是不是在子线程调了 MediaRecorder 的方法。这玩意儿不是线程安全的,必须在主线程操作。
我曾经踩过的坑:有一次在三星某款机型上,录制出来的视频总是绿屏。查了两天,最后发现是 setVideoSize 设了一个该设备不支持的尺寸。从那以后,我每次都会用 CamcorderProfile 来获取设备支持的参数,而不是硬编码。
嗯,今天就先聊这么多。MediaRecorder 的基础配置和录制流程,说白了就是一套固定的套路。你只要记住配置顺序、参数含义、以及生命周期处理,大部分场景都能搞定。后面咱们会深入讲 Camera2 结合 MediaRecorder 做更精细的控制,那才是真正有意思的地方。
公众号:蓝海资料掘金营,微信deep3321