摘要:一开始想当然地以为只是缺少了部分文件标识信息,以为很容易重建,所以直接把文件拖给 Claude Code,让它用 ffmpeg 修复:
记录一下我今天遇到的问题和解决办法吧。
接下来是折腾过程的记录。
今天早上开会录音,结束后才发现手机没电了。开机发现录音时长只有 1 秒:
点击该录音无法播放,提示「文件已不存在或者文件已损坏」:
然后开始找解决办法。虽然有点波折,但还是成功修复了。
第一次尝试:Claude Code 能做到吗?
一开始想当然地以为只是缺少了部分文件标识信息,以为很容易重建,所以直接把文件拖给 Claude Code,让它用 ffmpeg 修复:
刚开始确实有模有样的,用 ffmpeg 试了不能正常解码,然后用 hexdump 查了字节码,提 raw 数据:
第一轮操作结束之后,倒也输出了一个结果文件,但实际上,文件大小不对,播放也只有沙沙声:
第二次尝试:编译 untrunc、Windows 下使用 untrunc.exe
untrunc 是一个用于修复被截断的 mp4 视频文件的开源项目,前提是需要准备一个由相同设备、相同参数录制成功的文件作为参考。
Github 上有两个 untrunc 库:
ponchio 是原作者,anthwlock fork 之后维护得更久,且 release 了 Windows 版本。
在 Linux/Mac 环境下,untrunc 需要从源代码自己编译。
git clone --recurse-submodules https://github.com/ponchio/untrunccd untrunc/libav./configuremakecd ..Mac 下的编译命令是:
g++ -o untrunc file.cpp main.cpp track.cpp atom.cpp codec_*.cpp codecstats.cpp codec.cpp mp4.cpp log.cpp -I./libav-12.3 -L./libav-12.3/libavformat -lavformat -L./libav-12.3/libavcodec -lavcodec -L./libav-12.3/libavresample -lavresample -L./libav-12.3/libavutil -lavutil -lpthread -lz -framework CoreFoundation -framework CoreVideo -framework VideoDecodeAcceleration -lbz2 -DOSX然后…我编译失败了,我不确实是哪里的问题,但想着既然有 Windows 安装包的版本,干脆不折腾了,换上 GUI:
于是从 Releases · anthwlock/untrunc 下载了安装包,有命令行,也有 GUI。
然后……
第三次(成功):Docker 运行 untrunc
在 Windows 上尝试失败后,我又用 Docker 试了一遍,这也是成功的步骤。
git clone --recurse-submodules https://github.com/ponchio/untruncdocker build -t untrunc .docker image prune --filter label=stage=intermediate -f在拉取 Linux 镜像并编译完成 untrunc 工具后,可以用下面的命令尝试进行修复:
docker run --rm \ -v "$HOME/Downloads:/mnt" \ -w /mnt \ untrunc \ /mnt/reference.m4a /mnt/broken.m4a注意要修改的地方:
$HOME/Downloads:这是存放文件的路径 reference.m4a:参考文件 broken.m4a:需要修复的文件Bingo!成功恢复了完整可播放的音频,源文件 74.3MB,恢复后 76.9MB:
只不过格式转成了 .mp4,可以再用 ffmpeg 提取一次音频。
更简单的做法:在线工具
当然,如果不想自己折腾软件,且录音内容本身没有什么需要保密,不担心泄漏的话,可以直接使用在线工具,如 Repair M4A: Fix Damaged M4A Audio 。
同样的原理,上传损害的文件,同时上传参考文件:
等待转换完成后(会比本地修复耗时多一点),下载修复后的文件:
只不过文件体积大了很多,源文件 74.3MB,恢复后 151.3MB。
修复的原理。
不同的录制软件有不同的实现方式,具体到小米自带的录音机而言,在录音时,会持续向文件的 mdat 里写入数据,但要当结束录制时,才会一次性生成 mdat moov 则是音频帧的索引数据,包含轨道信息、采样表、解码配置等信息。所以修复这种被断电截断的 m4a 文件,主要是重建 moov 部分,也就是需要知道 AAC 音频帧的大小、顺序、采样率、声道、编码配置等信息。MP4/M4A 里的 AAC 是原始帧,字节流中没有同步头的标记;不同设备、不同 App 的编码器配置细节可能不一样。
所以需要用同一设备、同一参数录制一段有效的音频文件,由这个参考文件来提供正确的 moov moov 写会文件,解码器、播放器就能够正常播放音频文件了。顺便一提,想起来以前用 OBS 录制视频,也是同样的问题。
如果选择保存 .mp4,就必须正常结束录制,断电、死机都会因为 moov 未写入导致视频无法播放。如果选择保存 .mkv,数据边录边索引,即使遇到断电,只会丢失最后几秒,前面的内容都是正常可用的。
从这个角度来看,手机上的录音机默认用 m4a 格式其实最脆弱,因为 mp3、wav 虽然体积大一些,但不太怕断电/死机等异常问题。
来源:智慧芯片一点号