Bilibili 新版客户端缓存的视频不再以一个视频文件(数字.blv)存储,而改成了 audio.m4svideo.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 并运行。