試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

zoomeとSMILEVIDEOへアップロードする動画のエンコードに関する追加メモ(2009/8/28現在)

  1. 動きの少ない動画での警告メッセージ
    1. 関連:Quantizer
  2. エンコード支援スクリプト
    1. 色々な注意点
    2. SMILEVIDEO向け
    3. zoome向け

動きの少ない動画での警告メッセージ

mencoderにおけるlibx264の指定ビットレート値が無駄に大きすぎるとき、2passエンコードの2回目のエンコード時に

x264 [warning]: Error: 2pass curve failed to converge
x264 [warning]: target: [指定ビットレート] kbit/s, expected: [予想ビットレート] kbit/s, avg QP: [平均QP]
x264 [warning]: try reducing target bitrate or reducing qp_min (currently [現在のqp_min値])

と出ることがある。このとき、正常に2pass(としての)エンコードはできていない。
動きの少ない(必要なビットレートが低い)動画で起きやすく、このメッセージが出るときには「expected」のところに出てくるビットレートを参考に、それよりも少し低いぐらいのビットレート指定をするとよい?
どのぐらいの値だと大きすぎるのかは対象の動画の内容やフレームレートなどによって異なるため、具体的な数値では示せないが、2回目のエンコードのときにこのメッセージが出るかどうかは確認したほうがよい。
qp_min値については「1」まで下げても(適正範囲は10から30・既定値10)このメッセージが出ることがあり、ビットレートが高いのが原因のことのほうが多い気もするが、場合によってはqp_min値が関係することもあるかもしれない。

関連:Quantizer
「qp」の値(Quantizer値)については
http://www6.atwiki.jp/how_to_use_ffmpegx/pages/13.html
などにもあるように、値が大きいほうが画質が悪くファイルサイズが小さくなり、小さいほうが画質が良くファイルサイズが大きくなるというもので、2passエンコード時のQuantizerの最大値と最小値がそれぞれqp_maxとqp_minとなっている。また、関連する値としてQuantizer値の変動幅に関するqp_stepというものがある。

エンコード支援スクリプト

zoomeとSMILEVIDEOへアップロードする動画の再エンコード回避に関する覚え書き(2009/8/21現在)」に書いた作業をエンコードの度にいちいち端末に入力するのは非常に面倒な上に流れも固定なため、必然的に自動化するという流れになる。
下のスクリプトは入力ファイルと(必要に応じて)幾つかのオプション指定を行うことにより、(H.264 + AAC).mp4な動画ファイルに変換し、作業ディレクトリにoutput.mp4として書き出す。
(2009/11/30)下のスクリプトを改善した新しいバージョンを「zoomeとSMILEVIDEO向けの動画エンコード支援スクリプトを更新(2009/11/30版)」に貼り付けた。
(2009/12/25)更に更新したものを「zoomeとSMILEVIDEO向けの動画エンコード支援スクリプトを更新(2009/12/25版)」に貼り付けた。

色々な注意点
zoomeとSMILEVIDEOへアップロードする動画の再エンコード回避に関する覚え書き(2009/8/21現在)」と同様、

  • x264サポート付きのmencoder
  • libfaacサポート付きのffmpeg
  • GPACのMP4Box

全て揃っているという前提。また、上に書いた「2pass curve failed to converge」のメッセージが出た場合でもそのまま作業を進めてしまうため、特に動きの少ない動画をエンコードする場合は注意(完全に放置とはいかない)。放置したい場合はスクリプト標準エラー出力をファイルに書き出す(「[スクリプトの場所] 2> [書き出すログファイル]」として実行する)と後で確認できる。
SMILEVIDEO用とzoome用を分けているが、違いは既定のビットレート値だけで、このビットレートを含め、幾つかの指定はオプションでいじれるようにしてある。
長さや内容によってオプション指定で適切な値を指定して使用する。
作業は一時ディレクトリを作成後その中で行うが、もし途中でエラーが発生した場合は消さずに残すようにした。
zenityを使用しているので、ない場合は「exec」で始まる行とその後ろのechoコマンドの行を削るかコメントにすると動作するが、システムトレイアイコンの通知はしない。アイコンは変数ICONを実行時に場所指定すると変更もできる。
まだどこかおかしい部分が残っている可能性もあるので注意。

SMILEVIDEO向け
既定の設定では

としたが、動画の長さや用途など、必要に応じて値はオプション指定で調整する。
[任意]ファイル名: encode-video-smilevideo.sh ライセンス: GPL-3

#! /bin/bash

# (H.264 + AAC).mp4 encode support script
# version 20090828
# (C) 2009 kakurasan
# Licensed under GPL-3

PATH=/bin:/usr/bin

BITRATE_AUDIO=96
BITRATE_VIDEO=512
FPS=30

TMP_VIDEO=video.264
TMP_AUDIO=audio.aac
OUTFILE=output.mp4
PASSLOGFILE=2pass.log

print_usage()
{
  printf "Usage: %s ( [OPTIONS...] ) INPUT
  -b BITRATE       use BITRATE for audio (default: %d)
  -c WIDTH:HEIGHT  scale to WIDTHxHEIGHT
  -f FPS           set frame rate to FPS (default: %d)
  -h               print help
  -i BITRATE       use BITRATE for video (default: %d)
  -o               video only
  -r W:H:X:Y       crop (size:WxH, pos:X,Y)
  -t DURATION      set DURATION(hh:mm:ss)
  -x OPTION...     set extra x264 options
" ${0} ${BITRATE_AUDIO} ${FPS} ${BITRATE_VIDEO}
}

SCALE=0
USE_X264_EXTRA_OPTS=0
SET_DURATION=0
VIDEOONLY=0
CROP=0
while getopts 'b:c:f:hi:or:t:x:' OPT
do
  case ${OPT} in
   b)
    BITRATE_AUDIO=${OPTARG}
    ;;
   c)
    SCALE=1
    SIZE=${OPTARG}
    ;;
   f)
    FPS=${OPTARG}
    ;;
   i)
    BITRATE_VIDEO=${OPTARG}
    ;;
   o)
    VIDEOONLY=1
    ;;
   r)
    CROP=1
    CROPPARAMS=${OPTARG}
    ;;
   t)
    SET_DURATION=1
    DURATION=${OPTARG}
    ;;
   x)
    USE_X264_EXTRA_OPTS=1
    X264_EXTRA_OPTS=${OPTARG}
    ;;
   ?)
    print_usage
    exit 1
    ;;
  esac
done
shift $((${OPTIND} - 1))
if [ ${#} -lt 1 ]; then
  print_usage
  exit 1
fi
INFILE=${1}
if [ ! -f ${INFILE} ]; then
  echo "input file \"${INFILE}\" not found."
  exit 1
fi

TMPDIR=$(mktemp -d encode-video.XXXXXXXX)
if [ ${?} -ne 0 ]; then
  echo "cannot create tempdir"
  exit 1
fi
INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})  # rel.p->abs.p
cd ${TMPDIR}

X264OPTS="bitrate=${BITRATE_VIDEO}:bframes=4:b_pyramid:me=umh:weight_b:frameref=6:nofast_pskip:nodct_decimate"
if [ ${USE_X264_EXTRA_OPTS} -eq 1 ]; then
  X264OPTS=${X264OPTS}:${X264_EXTRA_OPTS}
fi

MENCODER="mencoder"
FFMPEG="ffmpeg"
MP4BOX="MP4Box"
if [ ${SET_DURATION} -eq 1 ]; then
  MENCODER="${MENCODER} -endpos ${DURATION}"
  FFMPEG="${FFMPEG} -t ${DURATION}"
fi
if [ ${SCALE} -eq 1 ]; then
  VFOPTS="scale=${SIZE},harddup"
else
  VFOPTS="harddup"
fi
if [ ${CROP} -eq 1 ]; then
  VFOPTS="${VFOPTS},crop=${CROPPARAMS}"
fi
MENCODEROPT_COMMON="-passlogfile ${PASSLOGFILE} -nosound -ovc x264 -vf ${VFOPTS} -ofps ${FPS}"
CMD_VIDEO1="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:pass=1:turbo=1 ${INFILE} -of rawvideo -o /dev/null"
CMD_VIDEO2="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:pass=2:subq=7 ${INFILE} -of rawvideo -o ${TMP_VIDEO}"
CMD_AUDIO="${FFMPEG} -i ${INFILE} -y -vn -acodec libfaac -ab ${BITRATE_AUDIO}k ${TMP_AUDIO}"

exec 3> >(zenity --notification --listen ${ICON:+--window-icon }${ICON:-})
echo "tooltip: ${CMD_VIDEO1}" >&3
${CMD_VIDEO1} || exit 1
echo "message: video pass 1 / 2 done" >&3
echo "tooltip: ${CMD_VIDEO2}" >&3
${CMD_VIDEO2} || exit 1
echo "message: video: pass 2 / 2 done" >&3
if [ ${VIDEOONLY} -eq 0 ]; then
  echo "tooltip: ${CMD_AUDIO}" >&3
  ${CMD_AUDIO} || exit 1
  echo "message: audio: done" >&3
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -add ${TMP_AUDIO} -new ../${OUTFILE}
else
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -new ../${OUTFILE}
fi
echo "message: mp4: done" >&3
cd ..
rm ${TMPDIR} -fr

zoome向け
既定の設定では

としたが、映像ビットレートが高くなりすぎないように注意。
[任意]ファイル名: encode-video-zoome.sh ライセンス: GPL-3

#! /bin/bash

# (H.264 + AAC).mp4 encode support script
# version 20090828
# (C) 2009 kakurasan
# Licensed under GPL-3

PATH=/bin:/usr/bin

BITRATE_AUDIO=128
BITRATE_VIDEO=1344
FPS=30

TMP_VIDEO=video.264
TMP_AUDIO=audio.aac
OUTFILE=output.mp4
PASSLOGFILE=2pass.log

print_usage()
{
  printf "Usage: %s ( [OPTIONS...] ) INPUT
  -b BITRATE       use BITRATE for audio (default: %d)
  -c WIDTH:HEIGHT  scale to WIDTHxHEIGHT
  -f FPS           set frame rate to FPS (default: %d)
  -h               print help
  -i BITRATE       use BITRATE for video (default: %d)
  -o               video only
  -r W:H:X:Y       crop (size:WxH, pos:X,Y)
  -t DURATION      set DURATION(hh:mm:ss)
  -x OPTION...     set extra x264 options
" ${0} ${BITRATE_AUDIO} ${FPS} ${BITRATE_VIDEO}
}

SCALE=0
USE_X264_EXTRA_OPTS=0
SET_DURATION=0
VIDEOONLY=0
CROP=0
while getopts 'b:c:f:hi:or:t:x:' OPT
do
  case ${OPT} in
   b)
    BITRATE_AUDIO=${OPTARG}
    ;;
   c)
    SCALE=1
    SIZE=${OPTARG}
    ;;
   f)
    FPS=${OPTARG}
    ;;
   i)
    BITRATE_VIDEO=${OPTARG}
    ;;
   o)
    VIDEOONLY=1
    ;;
   r)
    CROP=1
    CROPPARAMS=${OPTARG}
    ;;
   t)
    SET_DURATION=1
    DURATION=${OPTARG}
    ;;
   x)
    USE_X264_EXTRA_OPTS=1
    X264_EXTRA_OPTS=${OPTARG}
    ;;
   ?)
    print_usage
    exit 1
    ;;
  esac
done
shift $((${OPTIND} - 1))
if [ ${#} -lt 1 ]; then
  print_usage
  exit 1
fi
INFILE=${1}
if [ ! -f ${INFILE} ]; then
  echo "input file \"${INFILE}\" not found."
  exit 1
fi

TMPDIR=$(mktemp -d encode-video.XXXXXXXX)
if [ ${?} -ne 0 ]; then
  echo "cannot create tempdir"
  exit 1
fi
INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})  # rel.p->abs.p
cd ${TMPDIR}

X264OPTS="bitrate=${BITRATE_VIDEO}:bframes=4:b_pyramid:me=umh:weight_b:frameref=6:nofast_pskip:nodct_decimate"
if [ ${USE_X264_EXTRA_OPTS} -eq 1 ]; then
  X264OPTS=${X264OPTS}:${X264_EXTRA_OPTS}
fi

MENCODER="mencoder"
FFMPEG="ffmpeg"
MP4BOX="MP4Box"
if [ ${SET_DURATION} -eq 1 ]; then
  MENCODER="${MENCODER} -endpos ${DURATION}"
  FFMPEG="${FFMPEG} -t ${DURATION}"
fi
if [ ${SCALE} -eq 1 ]; then
  VFOPTS="scale=${SIZE},harddup"
else
  VFOPTS="harddup"
fi
if [ ${CROP} -eq 1 ]; then
  VFOPTS="${VFOPTS},crop=${CROPPARAMS}"
fi
MENCODEROPT_COMMON="-passlogfile ${PASSLOGFILE} -nosound -ovc x264 -vf ${VFOPTS} -ofps ${FPS}"
CMD_VIDEO1="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:pass=1:turbo=1 ${INFILE} -of rawvideo -o /dev/null"
CMD_VIDEO2="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:pass=2:subq=7 ${INFILE} -of rawvideo -o ${TMP_VIDEO}"
CMD_AUDIO="${FFMPEG} -i ${INFILE} -y -vn -acodec libfaac -ab ${BITRATE_AUDIO}k ${TMP_AUDIO}"

exec 3> >(zenity --notification --listen ${ICON:+--window-icon }${ICON:-})
echo "tooltip: ${CMD_VIDEO1}" >&3
${CMD_VIDEO1} || exit 1
echo "message: video pass 1 / 2 done" >&3
echo "tooltip: ${CMD_VIDEO2}" >&3
${CMD_VIDEO2} || exit 1
echo "message: video: pass 2 / 2 done" >&3
if [ ${VIDEOONLY} -eq 0 ]; then
  echo "tooltip: ${CMD_AUDIO}" >&3
  ${CMD_AUDIO} || exit 1
  echo "message: audio: done" >&3
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -add ${TMP_AUDIO} -new ../${OUTFILE}
else
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -new ../${OUTFILE}
fi
echo "message: mp4: done" >&3
cd ..
rm ${TMPDIR} -fr

使用したバージョン:

  • MPlayer,MEncoder 1.0-1.rc2.18.2plf2009.0
  • FFmpeg 0.4.9-3.pre1.14161.1.1plf2009.0
  • libfaac 1.26-4plf2009.0
  • libx264 0.59.2245-1plf2009.0
  • GPAC 0.4.5-1plf2009.1