Bilibili 新版客户端缓存的视频不再以一个视频文件(```数字.blv```)存储,而改成了 ```audio.m4s``` 和 ```video.m4s```。 这两个文件是什么?赶紧用 FFmpeg 一探究竟。 ``` blockcity@linux-l0yv:/tmpfs> for i in */*/*/*.m4s; do ffprobe $i; done 2>&1 | grep Stream Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 2 kb/s (default) Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 9 kb/s, 24 fps, 24 tbr, 16k tbn, 48 tbc (default) Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 3 kb/s (default) Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 23 kb/s, 30 fps, 30 tbr, 16k tbn, 60 tbc (default) Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 0 kb/s (default) Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 0 kb/s, 24 fps, 24 tbr, 16k tbn, 48 tbc (default) Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 1 kb/s (default) Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709/unknown/unknown), 852x480 [SAR 640:639 DAR 16:9], 9 kb/s, 25 fps, 25 tbr, 16k tbn, 50 tbc (default) blockcity@linux-l0yv:/tmpfs> ``` 把音视频流分开存储可以做到让客户端只播放音频,但是这种存储方式绝对不方便我们传输和播放。 好在视频和音频都用了很常见的编码器,可以直接合并不用考虑那么多兼容性的问题。 # 使用 FFmpeg 命令行手动合并 把 Bilibili 缓存中的两个文件取到你的电脑上。假如这两个文件在当前目录下,直接在终端模拟器中输入: ```ffmpeg -i video.m4s -i audio.m4s -c copy output.mp4``` [ffmpeg](https://ffmpeg.org/) 是一个用于处理多媒体的强大工具。 ```-i``` 选项用来指定文件;```-c copy``` 表示直接复制流,不重新编码;后面是输出文件的名字。 等待几秒,合并好的文件就出现了。 # 编写合并脚本 机器能做好的事怎么能让人做呢? ~~我几乎写不好 shell 脚本,能用就行。希望可以给不熟悉 shell 的同学提供方便。~~ ~~JSON 好难搞~~ 新版本 Bilibili 的缓存目录(通常是 ```/sdcard/Android/data/tv.danmaku.bili/download/``` )复制到你的电脑上,在此目录下运行这个 shell 脚本,以得自动化合并视频。*新旧版本Bilibili缓存的结构不同。* ``` #!/bin/bash output_dir=$1 #如果运行时加了参数,创建与参数同名的输出目录 if [ -n "$output_dir" ] then test -d $output_dir if [ ${?} != 0 ] then mkdir $output_dir fi fi #枚举视频目录,用 ffmpeg 转换。我不会写复杂正则表达式和 sed 脚本,所以给视频命名的部分写得比较乱 for i in */* do cd $i ffmpeg -i */audio.m4s -i */video.m4s -c copy "../../$output_dir/$(cut -d ":" -f 39 entry.json|sed "s/\"//g"|sed "s/}//g").mp4" cd ../.. done ``` 如果你有安装 Termux ,也可以在 Termux 安装 ffmpeg 并运行。