简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
-
-
- [🌻1. 前言](#🌻1. 前言)
- [🌻2. 用法与应用场景](#🌻2. 用法与应用场景)
- [🌻3. 调用流程剖析](#🌻3. 调用流程剖析)
-
- [3.1 核心步骤](#3.1 核心步骤)
- [3.2 涉及核心时序图](#3.2 涉及核心时序图)
- [🌻4. 实战应用案例](#🌻4. 实战应用案例)
- [🌻5. 用法总结](#🌻5. 用法总结)
-
🌻1. 前言
本篇目的:Android16音频深度解析之 MediaRecorder.setVideoSource 调用流程与实战。
在 Android 多媒体录制体系中,MediaRecorder 是实现音视频采集封装的高级组件。setVideoSource 是配置录制管线的首要步骤之一,它决定了视频数据的来源(如物理摄像头或虚拟 Surface)。在 Android 16 中,随着 CameraService 与 MediaServer 架构的进一步演进,理解该接口的底层链路对于处理高性能录制需求至关重要。
🌻2. 用法与应用场景
MediaRecorder.setVideoSource 方法用于指定录制视频的输入源。
- 用法说明 :必须在
MediaRecorder实例处于Initial状态时调用。最常见的参数包括VideoSource.CAMERA(使用系统默认相机)和VideoSource.SURFACE(使用应用提供的 Surface,常用于录屏或 OpenGL 离屏渲染)。 - 运行结果 :录制器状态由
Initial切换至已设置视频源状态,后续可继续设置输出格式。 - 应用场景 :
- 常规视频拍摄 :通过
VideoSource.CAMERA直接捕获摄像头画面。 - 屏幕录制 :配合
MediaProjection接口,使用VideoSource.SURFACE捕获屏幕内容。 - 视频特效录制 :通过 OpenGL 处理画面后,将数据推送到
MediaRecorder提供的Surface中实现实时滤镜录制。 - 副摄像头采集:在多摄像头设备上,通过特定 ID 指定录制源。
- 常规视频拍摄 :通过
🌻3. 调用流程剖析
3.1 核心步骤
- Java 框架校验 :
MediaRecorder.java检查当前状态机。如果状态不是INITIAL,调用将抛出IllegalStateException。 - JNI 与 Native 交互 :通过
android_media_MediaRecorder.cpp将视频源类型(int 值)传递给底层StagefrightRecorder。 - MediaServer 服务端响应 :指令通过 Binder 跨进程送达
MediaServer中的MediaRecorderClient。 - 录制引擎分配 :
StagefrightRecorder根据源类型创建对应的MediaSource对象。如果是SURFACE源,会初始化一个SurfaceMediaSource;如果是CAMERA,则准备与CameraService进行连接。 - HAL 与缓冲区准备:确定视频源后,系统会为后续的编码器(Encoder)准备好缓冲区消费路径(BufferQueue),确保原始视频帧能够高效传输。
3.2 涉及核心时序图
CameraService / Surface StagefrightRecorder MediaRecorderClient (Server) MediaRecorder Native MediaRecorder Java 应用代码层 CameraService / Surface StagefrightRecorder MediaRecorderClient (Server) MediaRecorder Native MediaRecorder Java 应用代码层 alt [如果是 VideoSource.SURFACE] [如果是 VideoSource.CAMERA] 调用 setVideoSource(source) 调用 native_setVideoSource Binder: setVideoSource 传递源类型参数 检查状态并记录 Source 类型 初始化 SurfaceMediaSource 缓冲区 准备连接 Camera2/3 接口 状态更新成功 返回 Result 状态机切换完成
🌻4. 实战应用案例
本案例演示了如何正确初始化 MediaRecorder 并设置视频源,特别展示了从初始化到准备阶段的严格顺序。
java
public class VideoRecordManager {
private MediaRecorder mediaRecorder;
public void initVideoRecorder(Context context, Surface previewSurface) {
// 在 Android 10+ 建议使用带有 Context 的构造函数
mediaRecorder = new MediaRecorder(context);
try {
// 1. 设置视频源 (必须首先调用)
// 如果需要录制音频,还需调用 setAudioSource
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 2. 设置输出格式 (必须在设置源之后)
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 3. 设置视频编码参数
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mediaRecorder.setVideoSize(1920, 1080);
mediaRecorder.setVideoFrameRate(30);
mediaRecorder.setVideoEncodingBitRate(10_000_000);
// 4. 设置预览与输出文件
mediaRecorder.setPreviewDisplay(previewSurface);
String filePath = context.getExternalFilesDir(null).getAbsolutePath() + "/test.mp4";
mediaRecorder.setOutputFile(filePath);
// 5. 进入准备状态
mediaRecorder.prepare();
System.out.println("MediaRecorder 视频源设置成功且准备就绪");
} catch (Exception e) {
e.printStackTrace();
mediaRecorder.reset();
}
}
public void start() {
if (mediaRecorder != null) {
mediaRecorder.start();
}
}
public void stop() {
if (mediaRecorder != null) {
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder = null;
}
}
}
🌻5. 用法总结
| 调用层级 | 核心职责 | 关键报错/结果 |
|---|---|---|
| 应用框架层 | 状态检查与 JNI 分发 | 若非 INITIAL 状态抛出 IllegalStateException |
| 系统服务层 | 跨进程通讯与源类型记录 | 建立 MediaRecorder 与具体 Source 的逻辑关联 |
| 录制引擎层 | 创建 Stagefright 数据源 |
决定了使用 SurfaceMediaSource 还是 CameraSource |
| 多媒体底层 | 缓冲区管理 (BufferQueue) | 为视频原始数据分配内存传输路径 |
| 硬件抽象层 | 提供物理采集能力 | 物理摄像头或屏幕像素数据的提取 |
最优实战方案落地步骤:
- 状态先行 :确保在
new MediaRecorder()之后立即调用setVideoSource,不要执行reset()以外的其他配置操作。 - 顺序严格 :遵循
Source->OutputFormat->Encoder的严格顺序,否则底层Stagefright无法正确初始化编码器组件。 - 权限申请 :若使用
CAMERA源,必须确保Manifest.permission.CAMERA权限已被用户动态授予,否则prepare()阶段会报权限错误。 - 资源回收 :录制结束后必须调用
release(),因为setVideoSource可能会锁定硬件摄像头资源或占用高带宽的Surface缓冲区。