视频源文件音频轨异常分析记录

背景

某回放视频在客户端播放或拖动进度后提示"加载失败"。客户端日志显示播放器进入错误状态,表现为 ExoPlayer 音频解码失败。

本文记录该类问题的分析过程、关键证据和可复用排查指令。

现象

客户端播放回放视频时,起播可以成功,拖动到后半段或某个固定时间点之后会快速失败。

典型日志特征如下:

text 复制代码
MediaCodecAudioRenderer error
format=audio/mp4a-latm, mp4a.40.2, 64000, [1, 44100]
format_supported=YES
Decoder failed: c2.android.aac.decoder
ERROR_CODE_DECODING_FAILED
MediaCodec$CodecException: Error 0xe

这类日志说明:

  • 音频格式为 AAC-LC,播放器和系统认为格式受支持。
  • 失败发生在解码阶段,不是普通网络加载失败。
  • 报错模块是音频渲染器 MediaCodecAudioRenderer,不是视频渲染器。

分析结论

源文件本身存在音轨/封装异常。

实际有效视频轨只有约 3377s,即约 56分17秒。但音频轨末尾存在异常 AAC packet,其 duration 被写成约 5011s,导致音频轨和容器总时长被错误拉长到约 8651s,即约 2小时24分

因此,当客户端播放或 seek 到 3377s 之后时:

  • 视频轨已经没有正常画面数据。
  • 音频轨进入异常拖尾区间。
  • 系统 AAC decoder 解码异常音频数据失败。
  • 播放器收到 ERROR_CODE_DECODING_FAILED,进入 error 状态。

准确描述是:3377 秒之后没有视频轨数据;音频轨还有异常拖尾,但不是正常可播放音频。

排查过程

1. 查看源文件基础信息

bash 复制代码
ffprobe -hide_banner -v error \
  -show_format \
  -show_streams \
  /path/to/input.mp4

重点关注:

  • format.duration
  • 视频流 duration
  • 音频流 duration
  • 音频编码、采样率、声道数

异常文件的典型表现:

text 复制代码
video duration ~= 3377s
audio duration ~= 8651s
format duration ~= 8651s
audio codec = aac
sample_rate = 44100
channels = 1

视频轨和音频轨时长严重不一致,是本问题的重要线索。

2. 检查异常时间点附近的音频 packet

bash 复制代码
ffprobe -hide_banner -v error \
  -select_streams a:0 \
  -show_packets \
  -read_intervals 3376%+5 \
  -show_entries packet=pts_time,dts_time,duration_time,size,flags,pos \
  /path/to/input.mp4

正常 AAC packet 的时长通常约为 0.023s。异常文件在末尾会出现类似:

text 复制代码
pts_time=3377.050000
duration_time=5011.263991
size=188

这说明音频轨最后出现了一个异常长 duration 的 packet,直接把音频轨和容器总时长拖长。

3. 单独验证音频解码

bash 复制代码
ffmpeg -hide_banner -v error \
  -ss 3376 \
  -t 10 \
  -i /path/to/input.mp4 \
  -map 0:a:0 \
  -f null -

异常文件会报类似错误:

text 复制代码
[aac] channel element 2.8 is not allocated
Error submitting packet to decoder: Invalid data found when processing input

这说明问题可以在本地通过 FFmpeg 解码复现,不依赖客户端环境。

4. 单独验证视频轨

bash 复制代码
ffmpeg -hide_banner -v error \
  -ss 3376 \
  -t 10 \
  -i /path/to/input.mp4 \
  -map 0:v:0 \
  -f null -

若视频轨无报错,同时音频轨报错,则可以进一步确认主问题在音频轨/封装。

5. 客户端现场日志验证

通过 ADB 抓取播放现场日志:

bash 复制代码
adb devices -l
adb -s <device_serial> logcat -c
adb -s <device_serial> logcat -v threadtime > full.log

同时过滤播放器关键日志:

bash 复制代码
adb -s <device_serial> logcat -v threadtime \
  | rg --line-buffered 'JZMediaExo|JzvdPro|ExoPlayer|MediaCodecAudioRenderer|MediaCodec|CodecException|Decoder failed|ERROR_CODE_DECODING_FAILED|onPlayerError|Audio Codec Error|seekTo|onError'

现场日志中如果出现以下组合,基本可以和源文件异常对齐:

text 复制代码
seekTo <大于视频轨实际时长的时间点>
Audio Codec Error
MediaCodecAudioRenderer error
Decoder failed: c2.android.aac.decoder
ERROR_CODE_DECODING_FAILED
onError 1000 - 1000

修复验证

如果只需要保留有效视频内容,可裁掉异常音频拖尾:

bash 复制代码
ffmpeg -hide_banner -y -v error \
  -i /path/to/input.mp4 \
  -to 3377.027 \
  -map 0:v:0 -map 0:a:0 \
  -c copy -movflags +faststart \
  /path/to/output_trimmed.mp4

验证裁剪后的文件:

bash 复制代码
ffprobe -hide_banner -v error \
  -show_format \
  -show_streams \
  /path/to/output_trimmed.mp4

ffmpeg -hide_banner -v error \
  -i /path/to/output_trimmed.mp4 \
  -f null -

预期结果:

  • 输出文件总时长约 3377s,即 56分17秒
  • 视频轨和音频轨时长基本一致。
  • 全量解码不再报 AAC 解码错误。

注意:-shortest 对这类问题不一定有效,因为异常音频 packet 可能仍会保留在输出文件中。更可靠的方式是裁剪到坏 packet 之前。

相关推荐
Mr YiRan3 小时前
网络请求API监控与网络切换埋点
android·网络
美狐美颜sdk6 小时前
直播APP开发技术栈详解:视频美颜SDK、人脸识别与实时渲染
android·人工智能·音视频·美颜sdk·直播美颜sdk
奈斯先生Vector12 小时前
当模型版本不断变化,RelayRouter 能否帮助 AI 应用摆脱深度绑定
android·java·人工智能·开源·aigc
TimeFine12 小时前
让强模型做“总工”,让高性价比模型写代码
android
又见情义13 小时前
RK3568 Android 13 屏蔽 healthd 电池日志经验分享
android
古法安卓16 小时前
Android-Fork 机制详解
android·java·android studio
Android打工仔17 小时前
不要在 Data 层随意把 Cold Flow 转换成 Hot Flow
android·架构·kotlin
峥嵘life17 小时前
2026免费的 opencode 使用分享:Windows端 + 服务器CLI 实战总结
android·大数据·开发语言
杉氧18 小时前
拒绝重复造轮子:我写了一个生产级的 Kotlin 协程与 Flow 工具库(CoroutineKit)
android·kotlin·workflow
恋猫de小郭18 小时前
Flutter GSoC 2026 提案进度解读,补上 DevTools、FFI 和原生平台的关键缺口
android·前端·flutter