一个80后
程序员的笔记

群晖VideoStation支持DTS、EAC3、TrueHD

引言

由于群晖没有获得DTS的版权,因此群晖自带的VideoStation从某个版本开始不支持DTS、EAC3、TrueHD的音频格式,严重影响使用体验。搜索该问题,得到的答案均为将VideoStation降级到2.3.4-1468,但是这个版本的VideoStation不支持HEVC和4K解码,比较鸡肋。本文将利用第三方的ffmpeg替换VideoStation中自带的ffmpeg,实现对全视频格式的支持。

操作方法

安装ffmpeg

  1. 下载对应版本的ffmpeg安装包,其中DS918+对应的版本是apollolake,具体每个机型对应的版本可以在以下连接中找到:https://github.com/SynoCommunity/spksrc/wiki/Architecture-per-Synology-model下载地址:https://github.com/th0ma7/synology/tree/master/packages
  2. 登录DSM,打开套件中心,点击手动安装,选择刚刚下载的文件进行安装。
  3. 在DSM中打开控制面板,选择终端机和SNMP,勾选启动SSH功能,并调整对应的端口号。
  4. 用XSheel等软件以SSH的方式登录到NAS中,执行以下命令:
sudo chmod +s /var/packages/ffmpeg/target/bin/ffmpeg
sudo chmod +s /var/packages/ffmpeg/target/bin/ffprobe
sudo chmod +s /var/packages/ffmpeg/target/bin/vainfo

安装VideoStation

  1. 登录DSM,打开套件中心,安装最新版的VideoStation,本文撰写时,版本为2.4.7-1603,经测试,以下版本适用于本方法,其他版本未测试:2.4.6-15942.4.7-1603
  2. 用XSheel等软件以SSH的方式登录到NAS中,执行以下命令:
# 备份
sudo  sed -i'-BACKUP' -e 's/eac3/ZAAP/' -e 's/dts/ZAP/' -e 's/truehd/ZAPZAP/' /var/packages/VideoStation/target/lib/libsynovte.so
# 注意:ffmpeg的备份名称ffmpeg-BACKUP应与ffmpeg自定义脚本中$bin2保持一致
sudo mv /var/packages/VideoStation/target/bin/ffmpeg /var/packages/VideoStation/target/bin/ffmpeg-BACKUP
sudo mv /var/packages/VideoStation/target/bin/ffprobe /var/packages/VideoStation/target/bin/ffprobe-BACKUP
sudo mv /var/packages/VideoStation/target/bin/vainfo /var/packages/VideoStation/target/bin/vainfo-BACKUP

# 更新/var/packages/VideoStation/target/ffmpeg为自定义脚本,调用第三方的ffmpeg
# 具体脚本信息见附录
sudo su
echo "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" | base64 -d | gunzip > /var/packages/VideoStation/target/bin/ffmpeg
exit

# 更新ffprobe vainfo
sudo ln -s /var/packages/ffmpeg/target/bin/ffprobe /var/packages/VideoStation/target/bin/ffprobe
sudo ln -s /var/packages/ffmpeg/target/bin/vainfo /var/packages/VideoStation/target/bin/vainfo

# 解除对EAC3 DTS TrueHD的屏蔽
sudo sed -i'-BACKUP' -e 's/eac3/ZAAP/' -e 's/dts/ZAP/' -e 's/truehd/ZAPZAP/' /var/packages/VideoStation/target/lib/libsynovte.so

# 调整权限信息
sudo chmod +x /var/packages/VideoStation/target/bin/ffmpeg
sudo chmod +s /var/packages/VideoStation/target/bin/ffmpeg
sudo chown root:VideoStation /var/packages/VideoStation/target/bin/ffmpeg

测试

这里有两个视频文件,分别时EAC3和DTS格式的视频文件,可以在DSM的FileStation中右击播放,查看是否成功。
EAC3:https://gofile.me/51V3S/WbIDHIvUU
DTS:https://gofile.me/51V3S/xp1jYf0W2

关于调试

通过脚本可知,本程序会将ffmpeg的日志输出到/tmp/ffmpeg.log文件中,有需要的可以查看。

附录1:ffmpeg-wrapper脚本内容

由于未知原因,在将ASS等格式的高级字幕转换成SRT格式字幕时,ffmpeg包所提供的ffmpeg可执行文件提示权限不足,导致字幕转换失败。在新版本的ffmpeg-wrapper利用VideoStation自带的ffmpeg可执行文件对字幕进行处理,从而ASS等高级字幕可以播放。由于PGS等图像格式的字幕无法转成文本格式,因此VideoStation不支持PGS等图像格式字幕。

#!/bin/bash

rev="12"

_log(){
	echo "$(date '+%Y-%m-%d %H:%M:%S') - ${streamid} - $1" >> /tmp/ffmpeg.log
}

_log_para(){
	echo "$1" | fold -w 120 | sed "s/^.*$/$(date '+%Y-%m-%d %H:%M:%S') - ${streamid} -          = &/" >> /tmp/ffmpeg.log
}

_term(){
	rm /tmp/ffmpeg-${streamid}.stderr
	_log "*** KILLCHILD ***"
	kill -TERM "$childpid" 2>/dev/null
}

trap _term SIGTERM

arch=`uname -a | sed 's/.*synology_//' | cut -d '_' -f 1`
nas=`uname -a | sed 's/.*synology_//' | cut -d '_' -f 2`
pid=$$
paramvs=$@
stream="${@: -1}"
streamid="FFM$pid"
bin1=/var/packages/ffmpeg/target/bin/ffmpeg
bin2=/var/packages/VideoStation/target/bin/ffmpeg-BACKUP
args=()

vcodec="KO"

while [[ $# -gt 0 ]]
do
case "$1" in
	-i)
		shift
		movie="$1"
		args+=("-i" "$1")
	;;
	-hwaccel)
		shift
		hwaccel="$1"
		args+=("-hwaccel" "$1")
	;;
	-scodec)
		shift
		scodec="$1"
		args+=("-scodec" "$1")
	;;
	-f)
		shift
		fcodec="$1"
		args+=("-f" "$1")
	;;
	-map)
		shift
		args+=("-map" "$1")
		idmap=`echo $1 | cut -d : -f 2`
		if [ "$vcodec" = "KO" ]; then
			vcodec=`/var/packages/ffmpeg/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
			vcodecprofile=`/var/packages/ffmpeg/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=profile -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
		else
			acodec=`/var/packages/ffmpeg/target/bin/ffprobe -v error -select_streams $idmap -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$movie" | head -n 1`
		fi
	;;
	*)
		args+=("$1")
	;;
esac
shift
done

_log "*** PROCESS START REV $rev DS$nas ($arch) PID $pid ***"

streamdir=`dirname "$stream"`
device=`cat ${streamdir}/video_metadata | jq -r '.device'`
_log "DEVICE   = $device"
_log "MOVIE    = $movie"

set -- "${args[@]}"

argsnew=()
args1sv=()
args2sv=()
args1vs=()
args2vs=()

while [[ $# -gt 0 ]]
do
case "$1" in
	-ss)
		shift
		argsnew+=("-ss" "$1")
		args1sv+=("-ss" "$1")
		args1sv+=("-noaccurate_seek")
		args1vs+=("-ss" "$1")
		args1vs+=("-noaccurate_seek")
		args2sv+=("-analyzeduration" "10000000")
		args2vs+=("-analyzeduration" "10000000")
	;;
	-i)
		shift
		argsnew+=("-i" "$1")
		args1sv+=("-i" "$1")
		args2sv+=("-i" "pipe:0" "-map" "0")
		args1vs+=("-i" "$1")
		args2vs+=("-i" "pipe:0" "-map" "0")
	;;
	-vf)
		shift
		if [ "$hwaccel" = "vaapi" ] && [ "$vcodecprofile" = "Main 10" ]; then
			scale_w=`echo "${1}" | sed -e 's/.*=w=//g' | sed -e 's/:h=.*//g'`
			scale_h=`echo "${1}" | sed -e 's/.*:h=//g'`
			if let ${scale_w} AND let ${scale_h}; then
				argsnew+=("-vf" "scale_vaapi=w=${scale_w}:h=${scale_h}:format=nv12,hwupload,setsar=sar=1")
			else
				argsnew+=("-vf" "scale_vaapi=format=nv12,hwupload,setsar=sar=1")
			fi
		else
			argsnew+=("-vf" "$1")
		fi
		args2sv+=("-vf" "$1")
		args1vs+=("-vf" "$1")
	;;
	-vcodec)
		shift
		argsnew+=("-vcodec" "$1")
		args1sv+=("-vcodec" "copy")
		args2sv+=("-vcodec" "$1")
		args1vs+=("-vcodec" "$1")
		args2vs+=("-vcodec" "copy")
	;;
	-acodec)
		shift
		if [ "$1" = "libfaac" ]; then
			argsnew+=("-acodec" "aac")
			args1sv+=("-acodec" "aac")
			args2vs+=("-acodec" "aac")
		else
			argsnew+=("-acodec" "$1")
			args1sv+=("-acodec" "$1")
			args2vs+=("-acodec" "$1")
		fi
		args2sv+=("-acodec" "copy")
		args1vs+=("-acodec" "copy")
	;;
	-ab)
		shift
		argsnew+=("-ab" "$1")
		args1sv+=("-ab" "$1")
		args2vs+=("-ab" "$1")
	;;
	-ac)
		shift
		argsnew+=("-ac" "$1")
		args1sv+=("-ac" "$1")
		args2vs+=("-ac" "$1")
	;;
	-f)
		shift
		argsnew+=("-f" "$1")
		args1sv+=("-f" "mpegts")
		args2sv+=("-f" "$1")
		args1vs+=("-f" "mpegts")
		args2vs+=("-f" "$1")
	;;
	-segment_format)
		shift
		argsnew+=("-segment_format" "$1")
		args2vs+=("-segment_format" "$1")
		args2sv+=("-segment_format" "$1")
	;;
	-segment_list_type)
		shift
		argsnew+=("-segment_list_type" "$1")
		args2vs+=("-segment_list_type" "$1")
		args2sv+=("-segment_list_type" "$1")
	;;
	-hls_seek_time)
		shift
		argsnew+=("-hls_seek_time" "$1")
		args2vs+=("-hls_seek_time" "$1")
		args2sv+=("-hls_seek_time" "$1")
	;;
	-segment_time)
		shift
		argsnew+=("-segment_time" "$1")
		args2vs+=("-segment_time" "$1")
		args2sv+=("-segment_time" "$1")
	;;
	-segment_time_delta)
		shift
		argsnew+=("-segment_time_delta" "$1")
		args2vs+=("-segment_time_delta" "$1")
		args2sv+=("-segment_time_delta" "$1")
	;;
	-segment_start_number)
		shift
		argsnew+=("-segment_start_number" "$1")
		args2vs+=("-segment_start_number" "$1")
		args2sv+=("-segment_start_number" "$1")
	;;
	-individual_header_trailer)
		shift
		argsnew+=("-individual_header_trailer" "$1")
		args2vs+=("-individual_header_trailer" "$1")
		args2sv+=("-individual_header_trailer" "$1")
	;;
	-avoid_negative_ts)
		shift
		argsnew+=("-avoid_negative_ts" "$1")
		args2vs+=("-avoid_negative_ts" "$1")
		args2sv+=("-avoid_negative_ts" "$1")
	;;
	-break_non_keyframes)
		shift
		argsnew+=("-break_non_keyframes" "$1")
		args2vs+=("-break_non_keyframes" "$1")
		args2sv+=("-break_non_keyframes" "$1")
	;;
	-max_muxing_queue_size)
		shift
		args2vs+=("-max_muxing_queue_size" "$1")
		args2sv+=("-max_muxing_queue_size" "$1")
	;;
	-map)
		shift
		argsnew+=("-map" "$1")
		args1sv+=("-map" "$1")
		args1vs+=("-map" "$1")
	;;
	*)
		argsnew+=("$1")
		if [ "$stream" = "$1" ]; then
			args1sv+=("-bufsize" "1024k" "pipe:1")
			args2sv+=("$1")
			args1vs+=("-bufsize" "1024k" "pipe:1")
			args2vs+=("$1")
		else
			args2sv+=("$1")
			args1vs+=("$1")
		fi
	;;
esac
shift
done

sed -i -e "s/{\"PID\":${pid},\"hardware_transcode\":true,/{\"PID\":${pid},\"hardware_transcode\":false,/" /tmp/VideoStation/enabled

startexectime=`date +%s`

if [ "$scodec" = "subrip" ]; then	

	_log "FFMPEG   = $bin2"
	_log "CODEC    = $scodec"
	_log "PARAMVS  ="
	_log_para "$paramvs"
	
	$bin2 "${args[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

elif [ "$fcodec" = "mjpeg" ]; then	

	_log "FFMPEG   = $bin2"
	_log "CODEC    = $fcodec"
	_log "PARAMVS  ="
	_log_para "$paramvs"
	
	$bin2 "${args[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

else

	_log "VCODEC   = $vcodec ($vcodecprofile)"
	_log "ACODEC   = $acodec"
	_log "PARAMVS  ="
	_log_para "$paramvs"
	_log "MODE     = WRAP"
	_log "FFMPEG   = $bin1"
	_log "PARAMWP  ="
	param1=${argsnew[@]}
	_log_para "$param1"

	$bin1 "${argsnew[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

fi

childpid=$!
_log "CHILDPID = $childpid"
wait $childpid

if grep "Conversion failed!" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr; then

	_log "*** CHILD END ***"
	startexectime=`date +%s`
	_log "STDOUT   ="
	_log_para "`tail -n 15 /tmp/ffmpeg-${streamid}.stderr`"
	_log "MODE     = PIPE SV"
	_log "FFMPEG1  = $bin1"
	_log "FFMPEG2  = $bin2"
	_log "PARAM1   ="
	param1=${args1sv[@]}
	_log_para "$param1"
	_log "PARAM2   ="
	param2=${args2sv[@]}
	_log_para "$param2"

	$bin1 "${args1sv[@]}" | $bin2 "${args2sv[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

	childpid=$!
	_log "CHILDPID = $childpid"
	wait $childpid

fi

if grep "Conversion failed!" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr; then

	_log "*** CHILD END ***"
	startexectime=`date +%s`
	_log "STDOUT   ="
	_log_para "`tail -n 15 /tmp/ffmpeg-${streamid}.stderr`"
	_log "MODE     = PIPE VS"
	_log "FFMPEG1  = $bin2"
	_log "FFMPEG2  = $bin1"
	_log "PARAM1   ="
	param1=${args1vs[@]}
	_log_para "$param1"
	_log "PARAM2   ="
	param2=${args2vs[@]}
	_log_para "$param2"

	$bin2 "${args1vs[@]}" | $bin1 "${args2vs[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

	childpid=$!
	_log "CHILDPID = $childpid"
	wait $childpid

fi

if grep "Conversion failed!" /tmp/ffmpeg-${streamid}.stderr || grep "Error opening filters!" /tmp/ffmpeg-${streamid}.stderr || grep "Unrecognized option" /tmp/ffmpeg-${streamid}.stderr || grep "Invalid data found when processing input" /tmp/ffmpeg-${streamid}.stderr; then

	_log "*** CHILD END ***"
	startexectime=`date +%s`
	_log "STDOUT   ="
	_log_para "`tail -n 15 /tmp/ffmpeg-${streamid}.stderr`"
	_log "MODE     = ORIG"
	_log "FFMPEG   = $bin2"

	$bin2 "${args[@]}" &> /tmp/ffmpeg-${streamid}.stderr &

	childpid=$!
	_log "CHILDPID = $childpid"
	wait $childpid

fi

stopexectime=`date +%s`
if test $((stopexectime-startexectime)) -lt 10; then
	_log "STDOUT   ="
	_log_para "`tail -n 15 /tmp/ffmpeg-${streamid}.stderr`"
fi

_log "*** CHILD END ***"
_log "*** PROCESS END ***"

rm /tmp/ffmpeg-${streamid}.stderr

附录2:原ffmpeg-wrapper脚本内容(已经弃用)

#!/bin/bash
bin="exec /var/packages/ffmpeg/target/bin/ffmpeg"

# DEBUG
echo "$@" >> /tmp/ffmpeg.log

args=()
while [[ $# -gt 0 ]]
do
case "$1" in
    -vprofile)
       shift
       args+=("-x264profile" "$1")
       ;;
    -vf)
       shift
       #vf=$(echo "$1" | sed -e 's/format=nv12.*scale_vaapi/scale_vaapi/g' -e 's/$/:format=nv12/')
           # DEBUG
       vf=$(echo "$1" | tee -a /tmp/ffmpeg.log | sed -e 's/format=nv12.*scale_vaapi/scale_vaapi/g' -e 's/$/:format=nv12/
')
           echo "vf: [$vf]" >> /tmp/ffmpeg.log
       args+=("-vf" "$vf")
       ;;
    -i)
       shift
       movie="$1"
       args+=("-i" "$1")
       # DEBUG
       echo "movie=[$movie]" >> /tmp/ffmpeg.log
       ;;
    *)
       args+=("$1")
       ;;
esac
shift
done

set -- "${args[@]}"

# DEBUG
echo $bin "$@" >> /tmp/ffmpeg.log
echo >> /tmp/ffmpeg.log
$bin "$@" 2>>/tmp/ffmpeg.log

#$bin "$@"
赞(0) 打赏
未经允许不得转载:FoolTiger笔记本 » 群晖VideoStation支持DTS、EAC3、TrueHD
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏