Skip to content

分段后处理中的弹幕压制

WARNING

弹幕压制对硬件要求较高,硬件性能越高压制越快,硬件性能过低不建议尝试。

下面是一个简单的分段后处理中压制弹幕的 Python 脚本示例,保存到 biliup 运行目录,赋予可执行权限。

  • 使用 DanmakuFactory,自行下载或编译,复制到脚本同目录,并赋予可执行权限。
  • 弹幕样式设置,请查看 DanmakuFactory 官方文档。
  • 非 Termux 使用,请自行设置合适的 -hwaccel 参数(或者直接使用 auto)和 h264 编码器。

参考命令(查找硬件加速器和编解码器):

bash
ffmpeg -hwaccels                   # 查看硬件加速器
ffmpeg -codecs | grep h264         # 查看 h264 编解码器 (Linux)
ffmpeg -codecs | findstr h264      # 查看 h264 编解码器 (Windows)
  • Windows 中建议使用 d3d11va,不在意 CPU 使用率可使用 openclvulkan 硬件加速。
  • 测试骁龙 865 使用脚本中的参数压制 1080p 视频的速度可达 2x。
  • 注意源视频文件的扩展名以防止文件覆盖。
  • 编码参数 -profile-level 最好同时指定,仅指定 -profile 在部分设备上会出现编码失败。
python
import os
import sys
import glob
import subprocess
import datetime

def is_termux():
    return 'com.termux' in os.getenv('PREFIX', '')

def encode():
    # 读取标准输入的内容
    video = sys.stdin.readline().strip()
    xml = sys.stdin.readline().strip()

    mp4 = os.path.splitext(video)[0] + '.mp4'
    # 避免 Windows 中绝对路径的转义问题
    ass = os.path.splitext(os.path.basename(xml))[0] + '.ass'

    # 查找当前文件夹 DanmakuFactory 可执行文件
    danmaku_file = None
    for file in glob.glob(os.path.join(os.getcwd(), 'DanmakuFactory*')):
        if os.path.isfile(file):
            danmaku_file = file
            break

    subprocess.run(
        f'{danmaku_file} -i {xml} -o {ass} -S 50 -O 230 --ignore-warnings',
        shell=True, check=True, stdout=subprocess.DEVNULL
    )
    print("开始压制时间:", datetime.datetime.now())
    subprocess.run(
        f'ffmpeg -hwaccel mediacodec -i {video} -vf ass={ass} '
        f'-c:v h264_mediacodec -c:a copy -crf 18 -b:v 12M '
        f'-profile:v high -level 4.2 -v quiet -y {mp4}',
        shell=True, check=True, stdout=subprocess.DEVNULL
    )
    print("结束压制时间:", datetime.datetime.now())
    os.remove(ass)
    os.remove(video)
    os.remove(xml)

if __name__ == "__main__":
    if is_termux():
        try:
            subprocess.run('termux-wake-lock', shell=True, check=True)
            encode()
        except Exception as e:
            print(f"error: {e}")
            sys.exit(1)
        finally:
            subprocess.run('termux-wake-unlock', shell=True, check=True)
    else:
        try:
            encode()
        except Exception as e:
            print(f"error: {e}")
            sys.exit(1)

基于 Rust + Python + Next.js 构建