Android16进阶之MediaRecorder.setVideoSource调用流程与实战(二百五十六)

简介: 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 中,随着 CameraServiceMediaServer 架构的进一步演进,理解该接口的底层链路对于处理高性能录制需求至关重要。


🌻2. 用法与应用场景

MediaRecorder.setVideoSource 方法用于指定录制视频的输入源。

  • 用法说明 :必须在 MediaRecorder 实例处于 Initial 状态时调用。最常见的参数包括 VideoSource.CAMERA(使用系统默认相机)和 VideoSource.SURFACE(使用应用提供的 Surface,常用于录屏或 OpenGL 离屏渲染)。
  • 运行结果 :录制器状态由 Initial 切换至已设置视频源状态,后续可继续设置输出格式。
  • 应用场景
    1. 常规视频拍摄 :通过 VideoSource.CAMERA 直接捕获摄像头画面。
    2. 屏幕录制 :配合 MediaProjection 接口,使用 VideoSource.SURFACE 捕获屏幕内容。
    3. 视频特效录制 :通过 OpenGL 处理画面后,将数据推送到 MediaRecorder 提供的 Surface 中实现实时滤镜录制。
    4. 副摄像头采集:在多摄像头设备上,通过特定 ID 指定录制源。

🌻3. 调用流程剖析

3.1 核心步骤
  1. Java 框架校验MediaRecorder.java 检查当前状态机。如果状态不是 INITIAL,调用将抛出 IllegalStateException
  2. JNI 与 Native 交互 :通过 android_media_MediaRecorder.cpp 将视频源类型(int 值)传递给底层 StagefrightRecorder
  3. MediaServer 服务端响应 :指令通过 Binder 跨进程送达 MediaServer 中的 MediaRecorderClient
  4. 录制引擎分配StagefrightRecorder 根据源类型创建对应的 MediaSource 对象。如果是 SURFACE 源,会初始化一个 SurfaceMediaSource;如果是 CAMERA,则准备与 CameraService 进行连接。
  5. 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) 为视频原始数据分配内存传输路径
硬件抽象层 提供物理采集能力 物理摄像头或屏幕像素数据的提取

最优实战方案落地步骤:

  1. 状态先行 :确保在 new MediaRecorder() 之后立即调用 setVideoSource,不要执行 reset() 以外的其他配置操作。
  2. 顺序严格 :遵循 Source -> OutputFormat -> Encoder 的严格顺序,否则底层 Stagefright 无法正确初始化编码器组件。
  3. 权限申请 :若使用 CAMERA 源,必须确保 Manifest.permission.CAMERA 权限已被用户动态授予,否则 prepare() 阶段会报权限错误。
  4. 资源回收 :录制结束后必须调用 release(),因为 setVideoSource 可能会锁定硬件摄像头资源或占用高带宽的 Surface 缓冲区。
相关推荐
Android系统攻城狮1 天前
Android16进阶之MediaRecorder.setVideoEncoder调用流程与实战(二百五十八)
mediarecorder·android16·android音频进阶
Android系统攻城狮2 天前
Android tinyalsa深度解析之pcm_params_get_period_size_max调用流程与实战(一百七十二)
android·pcm·tinyalsa·音频进阶
Android系统攻城狮2 天前
Android tinyalsa深度解析之pcm_params_set_min调用流程与实战(一百六十九)
android·pcm·tinyalsa·音频进阶
Android系统攻城狮7 天前
Android16进阶之MediaPlayer.deselectTrack调用流程与实战(二百五十一)
mediaplayer·android16·音频进阶·mediaplyer
loitawu8 天前
Rockchip Android16 系统裁剪指南
android·android16·android裁剪·系统裁剪·rockchip app
Android系统攻城狮19 天前
Android16进阶之MediaPlayer.setAudioSessionId调用流程与实战(二百三十八)
mediaplayer·android16·音频进阶
Android系统攻城狮19 天前
Android16进阶之MediaPlayer.getAudioSessionId调用流程与实战(二百三十七)
多媒体·mediaplayer·android16·android音频进阶
Android系统攻城狮19 天前
Android16进阶之MediaPlayer.setAudioAttributes调用流程与实战(二百三十六)
gitee·android16·音频进阶·android hal
Android系统攻城狮1 个月前
Android16进阶之MediaPlayer.isLooping调用流程与实战(二百三十二)
android16·音频进阶·android hal·audio hal·多媒体进阶