YouTube に高音質でアップロードできる動画ファイルを作るシェル・スクリプト (改良 MEncoder 版)

2008-02-17 追記

  • OFPS が指定されない場合のエラーを直した。

改良した

ウェブをさまよってて MEncoder で 2 パス・エンコードする方法がわかったので、"YouTube に高音質でアップロードできる動画ファイルを作るシェル・スクリプト - だらりな。" で書いたシェル・スクリプトをアップデート (ちなみに、ほぼニコニコ動画の転載専用であることに変わりはなし)。他にもいろいろ改良した。

  • MEncoder だけで OK なようにした (前のは FFmpeg も使ってた)。
  • 画質の良くなるエンコード・オプションをつけた (公式ドキュメントの "6.1. Selecting codecs and container formats" の一番下に書いてるやつ)。文字が微妙に読みやすくなったりする感じ。
  • 画質が良くなったかどうかは確認できないけど、なんとなく 3 パス・エンコードするようにした。
  • YouTubeアスペクト比 16:9 の FLV ファイルでも 4:3 で再生しちゃう (縦長になる) みたいなので (sm1852802 で気づいた)、自動で上下に黒い部分を足して 4:3 にするようにした。
  • アスペクト比が設定されてる場合も対応できるようにした (つもりだ) けど、そもそも FLV ファイルではアスペクト比の指定はできないのかもしれない。
  • 静止映像の動画でもシークできるように、10 秒に 1 度はキー・フレームが入るようにした。関係なかった。どうやればシークできるようになるんだろ。
  • いろいろメッセージを出すようにした。
  • しかし、どんくさいシェル・スクリプトであることには変わりなし。非整数の計算方法がわからなかったので、文字列操作で小数点を取り除くとかむちゃくちゃやってる。*1

エンコード例はこんな感じ (結局 The Idolm@ster のリミックスものをエンコードしてる……)。

ところで、YouTube のプレイヤーはデブロッキング・フィルタが入ってるのか (ていうか、それがたぶんふつうなのか)。フィルタを全部はずした MPlayer で見たら、もっとブロック・ノイズが目立ってた。

どんくさいシェル・スクリプト

設定を別ファイルに分離した。いろいろ自動化しても、ある程度は動画ごとにいじる必要があるし。

#! /bin/sh

source ${HOME}/bin/mencoder-youtube.conf

MSG_PREFIX="[MEncoder for YouTube] "

#
# Probe
#

INPUT_FILE=`echo $1 | sed -e 's/"/\\"/g' -e 's/!/\\!/g'`
if [ ! -f "${INPUT_FILE}" ]; then
	echo "${MSG_PREFIX}Can't find \"${INPUT_FILE}\"" >&2 
	exit 1
fi
OUTPUT_FILE=`basename "${INPUT_FILE}" | sed "s/\w\+$/forYouTube.flv/"`

INPUT_AUDIO_FILE=`echo "${INPUT_FILE}" | sed "s/\w\+$/mp3/"`
if [ -f "${INPUT_AUDIO_FILE}" ]; then
	echo "${MSG_PREFIX}Found \"${INPUT_AUDIO_FILE}\""
else
	INPUT_AUDIO_FILE=${INPUT_FILE}
fi

probe () {
	PROBE_DATA=`mplayer -vo null -ao null -frames 0 -identify "$1" 2> /dev/null | grep -e "$2"`
	eval ${PROBE_DATA}
}

probe "${INPUT_AUDIO_FILE}" "^ID_AUDIO"

AUDIO_BITRATE=`expr ${ID_AUDIO_BITRATE} / 1000`
VIDEO_BITRATE=`expr ${TOTAL_BITRATE} - ${AUDIO_BITRATE}`
echo "${MSG_PREFIX}AUDIO_BITRATE: ${AUDIO_BITRATE}; VIDEO_BITRATE: ${VIDEO_BITRATE}"
#exit 0

probe "${INPUT_FILE}" "^ID_VIDEO"

[ ! ${WIDTH} ] && WIDTH=${ID_VIDEO_WIDTH}

ID_VIDEO_ASPECT_X10000=`echo ${ID_VIDEO_ASPECT} | sed "s/\.//"`
if [ ${ID_VIDEO_ASPECT_X10000} -eq 0 ]; then
	SCALE_HEIGHT=`expr ${ID_VIDEO_HEIGHT} \* ${WIDTH} / ${ID_VIDEO_WIDTH}`
else
	SCALE_HEIGHT=`expr ${WIDTH} \* ${ID_VIDEO_ASPECT_X10000} / 10000`
fi

EXPAND_HEIGHT=`expr ${WIDTH} \* 3 / 4`

[ ! ${OFPS} ] && OFPS=${ID_VIDEO_FPS}

echo "${MSG_PREFIX}WIDTH: ${WIDTH}; SCALE_HEIGHT: ${SCALE_HEIGHT}; EXPAND_HEIGHT: ${EXPAND_HEIGHT}; OFPS: ${OFPS}"
#exit 0

#
# Encode
#

MSGLEVEL="all=1"
VF="${VF_PP}scale=${WIDTH}:${SCALE_HEIGHT},expand=${WIDTH}:${EXPAND_HEIGHT}"
#VF="${VF_PP}scale=320:180,expand=320:240"
OFPS_INT=`echo ${OFPS} | sed "s/\..*//"`; KEYINT=":keyint=`expr ${OFPS_INT} \* 10`"
LAVCOPTS="vcodec=flv:vbitrate=${VIDEO_BITRATE}:mbd=2:mv0:trell:v4mv:cbp:last_pred=3${KEYINT}"
PASSLOGFILE="mencoder-youtube-pass.log"

encode () {
	mencoder -msglevel ${MSGLEVEL} -of lavf -oac copy -ovc lavc -ofps ${OFPS} -vf ${VF} -lavcopts ${LAVCOPTS}:vpass=$1 -passlogfile ${PASSLOGFILE}\
		-o "${OUTPUT_FILE}" -audiofile "${INPUT_AUDIO_FILE}" "${INPUT_FILE}"
}

echo "${MSG_PREFIX}Encoding \"${INPUT_FILE}\" (pass 1/3)"
encode 1
echo "${MSG_PREFIX}Encoding \"${INPUT_FILE}\" (pass 2/3)"
encode 3
echo "${MSG_PREFIX}Encoding \"${INPUT_FILE}\" (pass 3/3)"
encode 3

OUTPUT_FILE_SIZE_BYTE=`ls -l "${OUTPUT_FILE}" | cut -d " " -f 5`
OUTPUT_FILE_SIZE_BIT_X100=`expr ${OUTPUT_FILE_SIZE_BYTE} \* 8 \* 100`
probe "${OUTPUT_FILE}" "^ID_LENGTH"
OUTPUT_FILE_LENGTH_X100=`echo ${ID_LENGTH} | sed "s/\.//"`
echo "${MSG_PREFIX}TOTAL_BITRATE: `expr ${OUTPUT_FILE_SIZE_BIT_X100} / ${OUTPUT_FILE_LENGTH_X100}` bps"

[ -f ${PASSLOGFILE} ] && rm ${PASSLOGFILE}

exit 0

設定用ファイル。WIDTH と OFPS については、全部コメントアウトすると元動画の設定を読む。

TOTAL_BITRATE=340
#TOTAL_BITRATE=244	# 音声 128000 bps なのに 32000 bps と自己申請する動画用
#TOTAL_BITRATE=276	# 音声 96000 bps なのに 32000 bps と自己申請する動画用

WIDTH=320

#OFPS=1	# 静止映像動画でビットレートをかせぎたいとき用
#OFPS=7
#OFPS=10
#OFPS=12
OFPS=15

#VF_PP=""
VF_PP="pp=ac,"
#VF_PP="pp=md/ac,"	# インターレース解除してない動画用

*1:bc ってのは使いかたがわからなくて、awk でできるのがわかったけど、もうやめた。