使用ffmpeg压缩电视录像

使用Plex和HDHomeRun录制电视节目,文件都非常大,动则数GB,甚至十几个GB。为了节省空间,决定把录制的mpeg2.ts文件转换为x264格式的mp4文件。方式如下:

ffmpeg -i input.ts -c:v libx264 -c:a copy output.mp4

然而当我打算批处理所有ts文件时,发现两个小问题。首先,Plex存储的目录和文件名里有空格和括号,如Premier League Soccer (2019)/Season 2019/Premier League Soccer (2019) – 2019-10-19 05 00 00 – Crystal Palace vs. Manchester City.ts,没办法用for循环加find的方式:for ts in $(find . -name “*.ts”); do echo “$ts”; done。

搜索后学了一招复杂的处理方法:

find . -name "*.ts" -print0 |
while IFS= read -r -d '' ts

do
mp4filename="$(basename "$ts" .ts).mp4"
relative_filename="$(dirname "$ts")/$mp4filename"
if [ -e "$relative_filename" ]
then
echo "find $relative_filename. skip conversion."
continue
fi
echo -n "converting '$ts' to '$mp4filename'…"
ffmpeg -loglevel quiet -i "$ts" -c:v libx264 -c:a copy "$relative_filename" >/dev/null 2>&1
echo "done"
done

然而发现一个诡异的现象,这段脚本能够正常处理第一个文件,但是第二个文件的路径名前面几个字符被截断了,ffmpeg报错说找不到文件。调试加搜索后得知,ffmpeg在转换视频格式的时候,还会读取stdin,导致下一个文件的路径名前面几个字符被吃掉了,需要使用-nostdin选项来禁止这种行为。

find . -name "*.ts" -print0 |
while IFS= read -r -d '' ts
do
mp4filename="$(basename "$ts" .ts).mp4"
relative_filename="$(dirname "$ts")/$mp4filename"
if [ -e "$relative_filename" ]
then
echo "find $relative_filename. skip conversion."
continue
fi
echo -n "converting '$ts' to '$mp4filename'…"
ffmpeg -nostdin -loglevel quiet -i "$ts" -c:v libx264 -c:a copy "$relative_filename" >/dev/null 2>&1
echo "done"
done

压缩率因文件而异,总体来讲,从1.2TB降到400GB以下,约为原来的1/3。

视频

空战游戏

这是一个空战游戏,A, S, D, W控制方向,空格发射子弹,一共两关。由于Scratch平台限制,只能在电脑上玩。

寒假没有安排出游,在家里跟儿子一起编写游戏,每天半个小时到一个小时。假期结束后只能每个周末开发一次,直到上个月终止开发。

之前一直让儿子照葫芦画瓢,把书上的例子临摹一遍。这回是第一次脱稿,边开发边创作。跟儿子开发游戏的念头来自Game Development for Kids,重在参与,适当动手。事实证明,儿子的参与程度经常让我吃惊,许多游戏素材都是他从之前的程序里找出来的。