为了让指向博客的链接增多,这篇帖子复制自我的博客
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 是一个用于处理多媒体的强大工具。
-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 并运行。