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 核心流程总览

说了这么多,咱们用一张图把整个流程串起来。这样你脑子里会有一个清晰的脉络。

MediaRecorder 视频录制核心流程 第一阶段:配置 setAudioSource → setVideoSource → setOutputFormat setAudioEncoder → setVideoEncoder → setOutputFile prepare() 第二阶段:录制 start() → 录制中... → 处理生命周期事件(onPause/onResume) 可在此阶段动态调整参数(部分设备支持) stop() → release() → 置 null

这张图把整个流程分成了四个阶段:配置、准备、录制、结束。每个阶段都有固定的操作,跳过一个或者顺序错了,都会出问题。

10.6 常见问题与避坑指南

  • 录制出来的视频没有声音:检查一下有没有申请 RECORD_AUDIO 权限。Android 6.0 以上需要运行时权限,很多人会漏掉。
  • 视频文件打不开:大概率是 stop() 之前没有写入足够的文件头。确保录制时间至少 2 秒以上。
  • 画面卡顿:帧率设太高了。有些低端设备撑不住 60 fps,老老实实用 30 fps。
  • 录制过程中崩溃:检查一下是不是在子线程调了 MediaRecorder 的方法。这玩意儿不是线程安全的,必须在主线程操作。

我曾经踩过的坑:有一次在三星某款机型上,录制出来的视频总是绿屏。查了两天,最后发现是 setVideoSize 设了一个该设备不支持的尺寸。从那以后,我每次都会用 CamcorderProfile 来获取设备支持的参数,而不是硬编码。

嗯,今天就先聊这么多。MediaRecorder 的基础配置和录制流程,说白了就是一套固定的套路。你只要记住配置顺序、参数含义、以及生命周期处理,大部分场景都能搞定。后面咱们会深入讲 Camera2 结合 MediaRecorder 做更精细的控制,那才是真正有意思的地方。


公众号:蓝海资料掘金营,微信deep3321