ffmpeg 之 time lapse 改进版

之前的脚本基本是 copy&paste 最后我就面临着各种问题,想来写原先脚本的人对于 ffmpeg 的功能也不甚了解,最后给出的脚本比较“笨拙”。那么这里我谈谈新的设计。

其实 ffmpeg 处理视频文件的基本操作是通过各种 filter 来实现的,因此通过几个 ffmpeg 命令串行几个不同的逻辑并不是一个聪明的做法。因为 ffmpeg 本身提供了 filter 的组合方式。也就是说我们可以通过一个 ffmpeg 命令将需要的 filter 一次性应用出去,这样可以极大的减少多次调用 ffmpeg 的代价。不过使用 filter 的最大的代价就是转码:比如输入的格式可能是 h265,这时会转码到无损的视频(h264 crf=0),然后应用这些 filter,最后存放到中间结果,最后 concat 并且编码为需要的格式(比如 h265 crf=28)。在没有硬件加速的情况下,这会非常的慢。

另一个原因大约是每个 dashcam 似乎都有一套自己的 logic 来切分录制的视频:

  • 原文作者大约有 3 帧的重合,他用了一个非常难以理解的 -ss 0.12(而不是使用 trim filter)
  • 我手上的 BlackVue 是文件名表示了重合的大小,如后缀为 EF.mp4 的具有 5s 的重合
  • Yi 录制的视频似乎没有什么特别的需要

因此,我们需要重新设计 make_tl.sh 的实现。一个简化的版本如下

#!/usr/bin/env bash

# All supported methods accepts
#   $1: input file name
function concat() {
  echo "setpts=$SPEED*PTS"
}

function blackvue() {
  local __input="$1"
  if [[ "$__input" == *EF.mp4 ]]; then
    echo "trim=start=5.0,setpts=PTS-STARTPTS,setpts=$SPEED*PTS"
  else
    echo "setpts=$SPEED*PTS"
  fi
}

function is_function() {
  if [[ $(type -t $1) == 'function' ]]; then
    echo true
  else
    echo false
  fi
}

function execute() {
  if [[ $DRY_RUN = true ]]; then
    echo $@
  else
    $* </dev/null || exit 2
  fi
}

DEFAULT_METHOD=concat
DEFAULT_SPEED=0.10

METHOD="$DEFAULT_METHOD"
SPEED="$DEFAULT_SPEED"
CONCAT_ONLY=false
DRY_RUN=false

while getopts ':hdcm:s:' opt; do
  case "$opt" in
    h)
      echo "Usage: $0 [-m method] line-of-video-file-name"
      echo "  Default method: concat; {concat, blackvue}"
      exit 0
      ;;
    d)
      echo "Dry run mode: "
      DRY_RUN=true
      ;;
    c)
      CONCAT_ONLY=true
      ;;
    m)
      METHOD="$OPTARG"
      if [[ $(is_function $METHOD) = 'false' ]]; then
        echo '-m must refer to an existing function name, such as concat, blackvue'
        exit 1  
      fi
      ;;
    s)
      SPEED="$OPTARG"
      ;;
    🙂
      echo "Invalid option: -$OPTARG requires an argument"
      exit 1
      ;;
    \?)
      echo "Invalid option: -$OPTARG"
      exit 1
      ;;
    esac
done
shift $((OPTIND - 1))

BASE_DIR=$(dirname "$1")
BASE_NAME=$(basename "$1")
FILTER_DIR="$BASE_DIR/filter-$BASE_NAME"
OUTPUT_FILES="$BASE_DIR/concat-$BASE_NAME"
OUTPUT="$1.MP4"

if [[ $CONCAT_ONLY = "true" ]]; then
  echo "Concatenating files only"
  rm -f "$OUTPUT"
else
  execute rm -R -f "$FILTER_DIR"
  execute mkdir "$FILTER_DIR"
  rm -f "$OUTPUT_FILES"
  execute rm -f "$OUTPUT"
  while read i; do
    CUR_FILE=$(basename "$i")
    execute ffmpeg -i "$i" -filter_complex "$($METHOD $CUR_FILE)" \
            -an "$FILTER_DIR/$CUR_FILE" 
    echo "file '$PWD/$FILTER_DIR/$CUR_FILE'" >> "$OUTPUT_FILES"
  done  < "$1"
fi

execute ffmpeg -f concat -safe 0 -i "$PWD/$OUTPUT_FILES" \
	-c:v libx265 -crf 28 "$OUTPUT"

几点想法

  • filter_complex 支持多文件输入,我们应该可以通过一个命令读入 N 个文件,然后同时处理所有的,这样可能能更进一步优化执行效率
  • 可以尝试 ffmpeg 的硬件加速,但是 WSL 里面似乎不行,只能用原生的
  • 可以尝试使用不同的 crf 进一步调整视频的 quality,现在感觉似乎有点太好了 =.=
  • 可以考虑使用 bash OO framework 来进一步改进这个设计,不过为什么不直接使用 ffmpeg 的 python interface 换到一个更接近 OOP 的语言呢?

测试一下

Advertisements
ffmpeg 之 time lapse 改进版

Ford Focus 的现代化之路

当初购入 Ford Focus SE Hatchback 大概是因为低廉的售价,不过作为“最低配置”怎么能满足我们这些“折腾”之人。除了常规的 dashcam、radar detector、HUD、auto dimming mirror 之外,这次又看上了一个中控台,居然还是个 Android 系统。几经折腾以后,它终于可以点亮,替换掉了原厂很古老的版本,暂时还在探索状态。

  • 这是 dasaita / hotaudio 的中控台,国内厂商做的,没有什么售后,主要靠 xda 论坛发布一些相关的软件升级,还算是比较勤快的厂商
  • 这个定制后的 Android 可以用 google play store 安装其他的程序;厂商塞了一些基本的程序,比如蓝牙、音乐还有收音机。对我来说比较有用的大约是 google maps、AFIM(播放器)
  • 暂时没能把 LINE IN 弄出来,需要内置 AVIN 程序配合,但是怀疑没有 LINE IN 到 AUX IN(RCA)的线路或者怎么
  • 方向盘上快捷按钮可用,比如控制音量跳歌什么的,控制台上车锁和双闪也可用,开关门也会有提示
  • 没有倒车影像,需要另外安装摄像头,但是留有视频输入的端口,可以后面看情况扩展
  • GPS 和 wifi 都有,GPS 可以和内置地图软件或者 google map 一起工作
  • 支持 USB 设备,可以挂一块外置硬盘上去

现在几个不满的地方:

  • 开机太慢,大约要半分钟,希望能做到 10s 以内
  • 不知道能不能平时关闭屏幕,需要的时候再点亮,似乎也没有光感自动调节亮度
  • 没能实现手机镜像功能或者 android auto / apple car play,也许还得捉摸一阵
Ford Focus 的现代化之路

BlackVue DR900S 之实验

鉴于对 Yi Ultra Dashcam 2.7k 的失望,同时对 4k 拍摄还是有很高的期望值,几经研究只有 BlackVue 这个韩国产的 dashcam 实际生成的是 4k 的视频并且支持 H.265 编码。尽管价格不是那么友好,最后还是狠心剁手了。

到手之后发现几个比较不那么令人满意的地方:

  • 电源竟然不是使用 USB 供电,而是直接接入车载的 12V DC,因而其使用的插头也是一个比较奇怪的 3.5mm / 1.5mm 的插头,而另一端需要直接连接到点烟器,它提供的线缆非常的长,你说是为了 hard wire 吧,最后还要插点烟器呢。结果这样一来直接插点烟器又嫌线太长。最后的解决方案竟然是买个国产 radar detector 用的线缆(只有 1.2m),两头的接头都匹配
  • windshield mount 很奇葩,这个圆柱形的外观给 mount 的设计带来了一些挑战,不过让人不解的是官方的 mount 竟然是通过粘胶贴上的,看见不少人最后由于脱胶都得再去找别的方式,难道就不能弄个好用的非粘胶的 mount 吗?查了一下,有个 blend mount 可以隐藏在后视镜后面,可是 100$ 的价格也是跪了,人一个 dashcam 要了 300+ 并不意味着一个 third party mount 就可以要将近 1/3 的价格啊,这是坑爹呢!不过好在它形状规则,不就是个圆筒吗,加上一个正常的 dashcam mount 也许就能行了?于是找来之前为现在的 dashcam 购入的 8$ 的 universal mount,里面有个倒 T 形状的玩意,这不就可以直接 3d 打印一个了吗?查了查网上其他人的做法,还真有志同道合的弄了个 GoPro 的 mount 的。
  • app support 很奇葩。现在多数的 dashcam 都支持 app 连接,但是这么贵的 blackvue 居然 app 支持奇差,Pixel 2 XL 装好了 app 硬是找不到它的 WIFI,据说是因为它用了个偏门的 5G channel 做 SSID 广播,只能先通过 tf 卡升级固件,然后再换会 2.4G,有这么傻的吗?app 功能似乎也比较一般,跟小蚁比起来差了好远,导出的能力也比较有限。
  • 官网真的很烂,下载程序或者固件都会获得不完整的文件,搞得我只好找来了古老的 FlashGet 反复下载了几次才获得完整的版本
  • 尽管 4k 的分辨率很赞,但是它非常蛋疼的把视频重复的存储在相邻的 clip 里面,这使得后期拼接又多出来一步。基本规律大概是 EF 结尾的文件与前一个文件大约有 5s 的 overlap。

为了解决 mount 脱胶的问题,专门设计了个 mount,可以与常规的普适 mount 搭配,需要的可以去 thingsiverse 下载

Blackvue DR900S 与自己打印的 mount

这是个简单的测试视频

BlackVue DR900S 之实验