分布式x264编码的简易实现
无论是x264工具本身,还是ffmpeg好像都没有分布式的实现。但是现实场景中,我们可能需要分布式的编码环境,因为现在高质量的视频需求,对比低下的编码速度,实在是令人发指。好在,伟大的GNU提供了一个通用的分布式实现工具”parallel”,借助这个简易的工具,配合另外一些工具,我们可以很轻易的实现分布式编码。
// 现在我把代码放在github上了,下面的演示代码是比较古老的版本
所有需要的工具:
– parallel
– rsync
– x264
– ffmpeg(optional)
– mkvtoolnix
其中rsync是被parallel所需要。我个人的需求场景是把视频编码任务分布到服务器上,本机(笔记本)并不承担视频编码任务。由于音频的编码速度较快(基本音速),而且nero的音频编码器没有64位元的二进制文件(然而服务器是64位的)所以由本机承担。然而实际部署到集群的话,肯定是需要任意节点同时承担视频音频编码任务,终端只做提交。下面的代码只作演示。
#!/bin/bash
function argnumb() {
echo $#
}
function vencode() {(
COPTS="-vcodec libx264 -tune psnr -preset placebo"
if [ "$FOPTS" ]; then
COPTS="$FOPTS $COPTS"
fi
ffmpeg -y -v quiet -i $1 $COPTS $2
)}
function encodec() {(
# 在本地编码音频流
if [ ! $ANONE ] && [ $ACOPY ]; then
ffmpeg -v quiet -i $1 -vn -codec copy .$1.tmp.m4a
elif [ ! $ANONE ]; then
ffmpeg -v quiet -i $1 -vn -f wav - |
neroAacEnc -q 0.3 -ignorelength -if - -of .$1.tmp.m4a
fi
# 在本地分割视频流
mkvmerge -q --no-audio -o .$1.tmp.mkv --split 2048k $1
# 任务分布到服务器
find . -name ".$1.tmp*mkv" |
parallel --env vencode \
--env FOPTS \
-S 1/root@one.mengcraft.com \
-S 1/root@three.mengcraft.com \
-S 1/root@four.mengcraft.com \
-S 1/root@five.mengcraft.com \
--trc {.}.target.mkv \
vencode {} {.}.target.mkv
# 计算合并视频参数
R=`find . -name ".$1.tmp*target.mkv" | sort`
T=`argnumb $R`
J=0
for I in $R; do
S="$S -S -T --no-global-tags --no-chapters"
if [[ $J > 0 ]]; then
S="$S + "
fi
S="$S $I"
J=$[J+1]
done
# 开始合并视频文件
mkvmerge -q -o .$1.tmp.mkv $S
# 备份原视音频文件
if [ "$1" = "$2" ]; then
mv $1 ${1}.bak
fi
# 混流视频音频轨道
if [ $ANONE ]; then
ffmpeg -y -v quiet -i .$1.tmp.mkv -codec copy $2
else
ffmpeg -y -v quiet -i .$1.tmp.mkv -i .$1.tmp.m4a -codec copy $2
fi
# 删除不用了的文件
rm -rf .$1.tmp*
)}
if [[ $# < 1 ]]; then
echo "No input file(s) define."
exit 1
fi
export -f argnumb
export -f vencode
export -f encodec
parallel encodec {} {.}.mp4 ::: $@
在实践过程中,出现的几个坑提一下。
– 分割文件的事后容器选MKV,这个玩意通用程度比较高的。
– encodec函数前后用括号括起来,否则会被拆成行平行执行。
– 合并输出走sort再排序下,偶尔find出来的文件是乱序的。
– 在CentOS6用ffmpeg替代x264,因为libc版本太低了。
– mkvmerge的合并参数远没有那么简单,很多博客都说错了。