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

背景

某回放视频在客户端播放或拖动进度后提示"加载失败"。客户端日志显示播放器进入错误状态,表现为 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 之前。

相关推荐
雨白4 小时前
嵌套 ScrollView 滑动冲突实战:实现内部优先滚动
android
阿pin4 小时前
Android随笔-IntentService详解(了解)
android·intentservice
海天鹰4 小时前
content://com.android.externalstorage.documents/document/primary%3A
android
阿pin5 小时前
Android随笔-WorkManager 与 AlarmManager
android·alarmmanager·workmanager
帅帅的记忆6 小时前
uniapp项目调用原生android studio的sdk文件(即aar文件)
android·uni-app·android studio
天才少年曾牛6 小时前
Android16在状态栏顶部新增图标(SystemUI)
android·frameworks
用户69371750013846 小时前
Kimi K3 综合能力处于全球第一梯队
android·前端·后端
阿pin6 小时前
Android随笔-BroadcastReceiver
android·broadcast
pengyu8 小时前
【Kotlin 协程修仙录 · 金丹境 · 后阶】 | 异常防火墙:supervisorScope 与异常隔离的终极奥义
android·kotlin