如何在录制中断后恢复录制而不丢失数据?
解读
国内面试场景下,这道题既考察候选人对 Android 音视频框架的深度理解,也暗含“用户付费录制中途来电、切后台、被杀进程、存储空间不足”等真实痛点。面试官期望听到一条“从用户点击恢复到最终文件可播放”的完整技术链路,重点在于“数据不丢”与“体验无缝”。若只回答“用 MediaRecorder 重新 start”会被视为初级;必须体现对文件格式、缓存策略、容错机制、权限变更、国产 ROM 管控的系统性思考。
知识点
- 容器格式与 moov 原子:MP4 的 moov 写在文件尾,异常中断即无索引,文件无法播放。
- MPEG4Writer 的 setNextOutputFile()/setMaxFileSize():Android 10 以上官方支持的“分段 MP4”机制,可生成可独立播放的 sdcard/DCIM/.pending 片段。
- 录制引擎选型:MediaRecorder 状态机简单但不可控;MediaCodec+MediaMuxer 组合可手工 flush,实现“内存缓存 + 分段落盘”。
- 缓存策略:环形 FIFO 的 AudioRecord/VideoEncoder 缓冲区,在 Application 被强杀前通过 Service.onTaskRemoved() 把最后一帧写进临时文件;利用 FFmpeg 的 moov_rear 前置工具可在下次启动时修复。
- 国产 ROM 后台限制:华为/小米/opPO 的“后台录音”权限需引导用户手动加白;前台 Service + 媒体通知栏保活是标配。
- 存储与权限:Android 11 分区存储下,临时片段只能写在 Context.getFilesDir()/cache,恢复后通过 MediaStore.createWriteRequest() 一次性合并到公共目录,避免“权限掉落”导致文件不可见。
- 断电续录协议:自定义索引文件(json)记录每段起始 pts、文件路径、旋转角度,恢复时用 MediaMuxer.addTrack() 重新对齐时间戳,保证音视频同步。
- 性能与 GC:录制中断常因内存不足触发;使用 mmap 写文件、复用 MediaCodec 的 ByteBuffer,减少 Java 堆抖动。
答案
分三层实现“零丢失”恢复:
-
录制架构
采用“MediaCodec 硬编 + 自研封装层”方案,放弃 MediaRecorder。音频线程与视频线程分别把编码后的数据送进一个“阻塞队列 + 环形缓存”,由 muxer 线程异步写盘。
设置 MPEG4Writer.setNextOutputFile(),每 50 MB 或 30 s 自动切分一段可播 MP4,文件名带起始 pts。
同时在应用私有目录生成 record.index,实时追加 JSON 行:{"seq":n,"path":"...","startPts":xxx,"rotation":0},每写成功一次 fsync 一次,确保断电不丢。 -
中断检测与现场保存
在 Service 内注册 PhoneStateListener、Activity 生命周期回调及 onTrimMemory()。
一旦收到来电、切后台或内存不足,立即向编码线程发送 EOS 信号,muxer 线程收到后停止当前段,调用 MediaMuxer.stop(),保证 moov 正常写入。
若进程被强杀,利用 JobScheduler 设定 0 网络约束的“恢复任务”,系统将在 1–2 min 内拉起应用;拉起后读取 record.index 找到最后一段,继续录制。 -
恢复与合并
用户点击“继续”后,新建下一段 MP4,沿用相同音频采样率、视频分辨率,时间戳从上一段 lastPts 开始累加。
所有分段录制完成后,在后台线程用 MediaMuxer 二次合并:按 index 顺序 addTrack(),重新计算 pts,保持音视频同步;合并完删除临时分段,只保留最终文件。
最后通过 MediaStore API 插入公共 Video 目录,发送系统扫描广播,确保相册即时可见。
通过以上流程,即使中途来电、杀进程、存储空间告警,用户再次打开 App 也能“一键继续”,最终文件可无缝播放,真正做到“数据零丢失”。
拓展思考
- 如果业务场景是“直播”而非“本地录制”,中断恢复需引入 RTMP/RTC 的“秒开重推 + GOP 缓存”策略,与本地分段落盘思路不同。
- 对于 Android 14 的“前台服务必须指定类型”新规,录制型 FGS 需声明 mediaProjection 类型,并在 6 小时内停止,否则系统抛 Fatal;面试时可主动提及,以体现对新版本适配的敏感度。
- 若目标设备为车载或 Wear,存储介质可能是只读闪存,需改用 SQLite 存储索引 + 低码率 TS 分段,避免频繁写放大;同时利用 Automotive OS 的 CarService 申请驾驶状态权限,防止行驶中弹窗干扰。