You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

CameraAwesome 2.5.0:解决下拉通知栏/应用后台时录制中断及暂停恢复导致视频损坏的问题

CameraAwesome 2.5.0:解决下拉通知栏/应用后台时录制中断及暂停恢复导致视频损坏的问题

我之前用CameraAwesome做录制应用时,也碰到过几乎一模一样的问题——下拉通知栏就断录,改了暂停恢复后视频又莫名损坏。结合你的代码和日志,我来一步步拆解问题和解决方案:

先揪出你代码里的明显小坑

看你修改后的生命周期代码,AppLifecycleState.paused的case后面没加break!这会导致逻辑穿透:执行完stopRecording()后直接跳到detached的break,和你之前的暂停逻辑冲突,这是视频损坏的潜在诱因之一。

另外,你同步调用了pauseRecording/resumeRecording这些方法,但CameraAwesome的这些操作其实是异步的——如果不等它们把缓冲区的帧写完就切换应用状态,直接会导致帧丢失,最后视频自然缺了一大段内容。

针对“下拉通知栏不中断录制”的正确生命周期处理

首先得搞清楚Android的状态触发逻辑:

  • 下拉通知栏/弹出系统弹窗时,触发的是AppLifecycleState.inactive(应用临时失焦,但还在前台)
  • 按Home键退到后台时,触发的是AppLifecycleState.paused(应用完全进入后台,Android 10+会强制限制相机权限)

所以我们要对两个状态做差异化处理:inactive时暂停录制,回到应用后恢复;paused时必须停止录制(否则系统会强制收回相机资源,反而更容易导致视频损坏)。

这里给你修正后的异步版生命周期代码:

@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
  final mediaCapture = _cameraContext.mediaCaptureController.value;
  final isRecording = mediaCapture != null && mediaCapture.isRecording;

  switch (state) {
    case AppLifecycleState.resumed:
      // 仅当之前处于暂停状态的录制任务,才执行恢复操作
      if (isRecording && mediaCapture.isPaused) {
        await _cameraContext.state.when(
          onVideoRecordingMode: (mode) => mode.resumeRecording(mediaCapture),
        );
      }
      break;
    case AppLifecycleState.inactive:
      // 下拉通知栏触发此状态,此时暂停录制(需确保正在录制且未暂停)
      if (isRecording && !mediaCapture.isPaused) {
        await _cameraContext.state.when(
          onVideoRecordingMode: (mode) => mode.pauseRecording(mediaCapture),
        );
      }
      break;
    case AppLifecycleState.paused:
      // 应用完全退到后台,必须停止录制(Android后台相机权限限制)
      if (isRecording) {
        await _cameraContext.state.when(
          onVideoRecordingMode: (mode) => mode.stopRecording(),
        );
      }
      break;
    case AppLifecycleState.detached:
    case AppLifecycleState.hidden:
      // 应用被销毁/隐藏,强制停止录制
      if (isRecording) {
        await _cameraContext.state.when(
          onVideoRecordingMode: (mode) => mode.stopRecording(),
        );
      }
      break;
  }
  super.didChangeAppLifecycleState(state);
}

这段代码的核心改进:

  • 给生命周期方法加上async/await,确保媒体操作完全执行完再切换状态,避免帧丢失
  • 修复了case穿透的问题(每个状态分支都加了break)
  • 增加了录制状态校验(isRecording/isPaused),避免错误调用暂停/恢复方法,比如在未录制时触发恢复操作

解读你看到的错误日志

你日志里的关键信息其实已经点明了问题:

  • W/GraphicBufferSource: onFrameAvailable: EOS is sent, ignoring frame:编码器收到了「流结束」信号,导致后续的帧直接被丢弃,这就是视频缺30/60秒内容的直接原因
  • I/MPEG4Writer: The mp4 file will not be streamable:这个其实不影响播放,只是说明视频的moov原子在文件末尾,不能流式播放,不是视频损坏的根本原因

出现EOS信号的原因,就是你之前同步调用暂停/恢复,编码器还在处理帧的时候就被强制切换状态,误以为录制已经结束,所以发送了流结束信号。用await等待操作完成就能解决这个问题。

关于“后台持续录制”的替代方案

如果你的需求是应用退到后台后还能继续录制,那仅靠暂停恢复是行不通的——Android 10+明确禁止后台应用访问相机。这时候需要:

  1. Android前台服务承载相机录制逻辑,申请android.permission.FOREGROUND_SERVICE_CAMERA(Android 12+)权限
  2. 把CameraAwesome的相机控制逻辑移到前台服务中,确保服务在前台运行(必须显示一个持续的通知)
  3. 严格管理前台服务的生命周期,避免内存泄漏

不过这个方案比较复杂,需要修改CameraAwesome的底层适配逻辑。如果只是想解决下拉通知栏的中断问题,前面的生命周期修正就完全足够了。

最后验证步骤

  1. 替换为修正后的代码,确保所有异步操作都加了await
  2. 测试下拉通知栏:此时录制应该暂停,回到应用后自动恢复
  3. 测试退到后台:录制会自动停止,生成完整的视频文件
  4. 检查日志,确认没有EOS is sent的警告

内容来源于stack exchange

火山引擎 最新活动