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

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

OpenGL/ALSA環境向けキャプチャツールglcの(H.264+AAC).mp4向けエンコード支援スクリプトを更新(2010/1/6版)

OpenGL/ALSA環境向けキャプチャツールglcの(H.264+AAC).mp4向けエンコード支援スクリプトを作成」で作成したglc向けエンコード支援スクリプトを更新した。主な変更点は「zoomeとSMILEVIDEO向けの動画エンコード支援スクリプトを更新(2009/12/25版)」でのエンコード支援スクリプトの機能を移植したものとなる。

  • 映像の1passエンコード対応(-1)
  • MEncoderのlibx264オプションの見直し
  • 映像2passエンコード時の1pass目の出力ログファイルを指定して2pass目から開始するオプション指定(-p)
  • エンコード済みの.h264ファイルを指定してオーディオのエンコードから開始するオプション指定(-2)
  • エンコード処理の端末への出力をファイル化し、任意のX端末(-mで指定)でtailによりリアルタイムでログを参照
  • 位置(-s)や指定領域の切り取り(-r)のオプション指定
  • 出力ファイルの場所を指定可に(-o)

特に、一度途中でエンコードを中止した後、1pass目のログやエンコード済みの映像ファイルを次回のエンコード時に用いることができるのは、単純なエンコードよりもCPU資源を多く消費する(時間がかかる)glc形式からの変換では役に立つ場面がありそう。
以下がスクリプトの内容となるが、おかしな部分が残っている可能性はある。SMILEVIDEO向けとzoome向けを分けているが、異なるのは既定のビットレートのみで、これらはオプション指定で変更可。

SMILEVIDEO向け

既定の設定では

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

#! /bin/bash

# glc -> (H.264 + AAC).mp4 convert/encode script
# version 20100106
# (C) 2009-2010 kakurasan
# Licensed under GPLv3+

PATH=/bin:/usr/bin

STREAM_AUDIO=1
STREAM_VIDEO=1

BITRATE_AUDIO=96
BITRATE_VIDEO=512
FPS=30

TMP_VIDEO=video.h264
TMP_AUDIO_AAC=audio.aac
TMP_AUDIO_WAV=audio.wav
OUTFILE=../glc2mp4-output.mp4
PASSLOGFILE=2pass.log

print_usage()
{
  printf "Usage: %s ( [OPTIONS...] ) INPUT
  -1               1pass video encode
  -2 VIDEO         start from audio encoding using VIDEO
  -a NUM           use audio stream NUM
  -b BITRATE       use BITRATE for audio (default: %s)
  -c WIDTH:HEIGHT  scale to WIDTHxHEIGHT
  -d NUM           use video stream NUM
  -f FPS           set frame rate to FPS (default: %s)
  -h               print help
  -i BITRATE       use BITRATE for video (default: %s)
  -m TERM          display log using TERM (X terminal emulator)
  -o OUTFILE       set output location
  -p PASSLOGFILE   start from 2nd pass (video) using PASSLOGFILE
  -r W:H:X:Y       crop (size:WxH, pos:X,Y)
  -s POS           seek to POS
  -t DURATION      set DURATION(hh:mm:ss)
  -v               video only
  -x OPTION...     set extra x264 options
" ${0} ${BITRATE_AUDIO} ${FPS} ${BITRATE_VIDEO}
}

SCALE=0
USE_X264_EXTRA_OPTS=0
SET_DURATION=0
VIDEOONLY=0
VIDEO_1PASS=0
SKIP_1STPASS_VIDEO=0
SKIP_VIDEO=0
POS=0
CROP=0
USE_XTERM=0
while getopts '12:a:b:c:d:f:hi:m:o:p:r:s:t:vx:' OPT
do
  case ${OPT} in
   1)
    VIDEO_1PASS=1
    ;;
   2)
    VIDEOFILE="${OPTARG}"
    if [ ! -f "${VIDEOFILE}" ]; then
      echo "Error: Cannot open \"${VIDEOFILE}\"" >&2
      exit 1
    fi
    VIDEOFILE=$(cd $(dirname "${VIDEOFILE}") && pwd)/$(basename "${VIDEOFILE}")  # rel.p->abs.p
    SKIP_VIDEO=1
    ;;
   a)
    STREAM_AUDIO=${OPTARG}
    ;;
   b)
    BITRATE_AUDIO=${OPTARG}
    ;;
   c)
    SCALE=1
    SIZE=${OPTARG}
    ;;
   d)
    STREAM_VIDEO=${OPTARG}
    ;;
   f)
    FPS=${OPTARG}
    ;;
   i)
    BITRATE_VIDEO=${OPTARG}
    ;;
   m)
    USE_XTERM=1
    TERMINAL=${OPTARG}
    ;;
   o)
    OUTFILE="${OPTARG}"
    OUTDIR="$(dirname ${OUTFILE})"
    if [ ! -d "${OUTDIR}" ]; then
      if ! mkdir -p "${OUTDIR}"; then
        echo "Error: Cannot create output directory \"${OUTDIR}\"" >&2
        exit 1
      fi
    fi
    OUTFILE=$(cd $(dirname "${OUTFILE}") && pwd)/$(basename "${OUTFILE}")
    ;;
   p)
    SKIP_1STPASS_VIDEO=1
    PASSLOGFILE="${OPTARG}"
    if [ ! -f "${PASSLOGFILE}" ]; then
      echo "Error: Cannot open \"${PASSLOGFILE}\"" >&2
      exit 1
    fi
    PASSLOGFILE=$(cd $(dirname "${PASSLOGFILE}") && pwd)/$(basename "${PASSLOGFILE}")
    ;;
   r)
    CROP=1
    CROPPARAMS=${OPTARG}
    ;;
   s)
    POS=${OPTARG}
    ;;
   t)
    SET_DURATION=1
    DURATION=${OPTARG}
    ;;
   v)
    VIDEOONLY=1
    ;;
   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 "Error: input file \"${INFILE}\" not found." >&2
  exit 1
fi

LOGFILE="$(printf ../glc2mp4-%s-%s.log "$(basename "${INFILE}")" $(date +%Y%m%d%H%M%S))"

TMPDIR=$(mktemp -d glc2mp4.XXXXXXXX)
if [ ${?} -ne 0 ]; then
  echo "Error: cannot create tempdir" >&2
  exit 1
fi
INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})
cd ${TMPDIR}

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

GLCPLAY="glc-play"
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="-demuxer y4m -nosound -ovc x264 -vf ${VFOPTS} -ofps ${FPS}"
CMD_VIDEO_CONV="${GLCPLAY} ${INFILE} -o - -y ${STREAM_VIDEO}"
CMD_VIDEO="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:subq=7 - -of rawvideo -o ${TMP_VIDEO}"
CMD_VIDEO1="${MENCODER} ${MENCODEROPT_COMMON} -passlogfile ${PASSLOGFILE} -x264encopts ${X264OPTS}:pass=1:turbo=1 - -of rawvideo -o /dev/null"
CMD_VIDEO2="${MENCODER} ${MENCODEROPT_COMMON} -passlogfile ${PASSLOGFILE} -x264encopts ${X264OPTS}:pass=2:subq=7 - -of rawvideo -o ${TMP_VIDEO}"
CMD_AUDIO_CONV="${GLCPLAY} -a ${STREAM_AUDIO} ${INFILE} -o ${TMP_AUDIO_WAV}"
CMD_AUDIO_ENC="${FFMPEG} -i ${TMP_AUDIO_WAV} -y -vn -acodec libfaac -ab ${BITRATE_AUDIO}k ${TMP_AUDIO_AAC}"

exec 3> >(zenity --notification --listen ${ICON:+--window-icon }${ICON:-})
touch "${LOGFILE}"
if [ ${USE_XTERM} -eq 1 ]; then
  ${TERMINAL} -e tail -f "${LOGFILE}" &
  PID=${!}
fi
if [ ${SKIP_VIDEO} -eq 0 ]; then
  # do video encoding
  if [ ${VIDEO_1PASS} -eq 1 ]; then
    # 1pass
    echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO}" >&3
    echo "${CMD_VIDEO_CONV} | ${CMD_VIDEO}" >> "${LOGFILE}"
    ${CMD_VIDEO_CONV} | ${CMD_VIDEO} >> "${LOGFILE}" 2>&1 || exit 1
    echo "message: video: done" >&3
  else
    # 2pass
    if [ ${SKIP_1STPASS_VIDEO} -eq 0 ]; then
      # pass#1
      echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO1}" >&3
      echo ${CMD_VIDEO_CONV} | ${CMD_VIDEO1} >> "${LOGFILE}"
      ${CMD_VIDEO_CONV} | ${CMD_VIDEO1} >> "${LOGFILE}" 2>&1 || exit 1
      echo "message: video pass 1 / 2 done" >&3
    fi
    # pass#2
    echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO2}" >&3
    echo ${CMD_VIDEO_CONV} | ${CMD_VIDEO2} >> "${LOGFILE}" 2>&1
    ${CMD_VIDEO_CONV} | ${CMD_VIDEO2} >> "${LOGFILE}" 2>&1 || exit 1
    echo "message: video: pass 2 / 2 done" >&3
  fi
else
  # skip video encoding
  ln -s "${VIDEOFILE}" ${TMP_VIDEO}
fi
if [ ${VIDEOONLY} -eq 0 ]; then
  echo "tooltip: ${CMD_AUDIO_CONV}" >&3
  ${CMD_AUDIO_CONV} >> "${LOGFILE}" 2>&1 || exit 1
  if [ ! -f ${TMP_AUDIO_WAV} ]; then
    echo "audio not found"
    exit 1
  fi
  echo "tooltip: ${CMD_AUDIO_ENC}" >&3
  ${CMD_AUDIO_ENC} >> "${LOGFILE}" 2>&1 || exit 1
  echo "message: audio: done" >&3
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -add ${TMP_AUDIO_AAC} -new "${OUTFILE}" >> "${LOGFILE}" 2>&1
else
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -new "${OUTFILE}" >> "${LOGFILE}" 2>&1
fi
echo "message: mp4: done" >&3
if [ ${USE_XTERM} -eq 1 ]; then
  kill ${PID}
fi
cd ..
rm ${TMPDIR} -fr

zoome向け

既定の設定では

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

#! /bin/bash

# glc -> (H.264 + AAC).mp4 convert/encode script
# version 20100106
# (C) 2009-2010 kakurasan
# Licensed under GPLv3+

PATH=/bin:/usr/bin

STREAM_AUDIO=1
STREAM_VIDEO=1

BITRATE_AUDIO=128
BITRATE_VIDEO=1344
FPS=30

TMP_VIDEO=video.h264
TMP_AUDIO_AAC=audio.aac
TMP_AUDIO_WAV=audio.wav
OUTFILE=../glc2mp4-output.mp4
PASSLOGFILE=2pass.log

print_usage()
{
  printf "Usage: %s ( [OPTIONS...] ) INPUT
  -1               1pass video encode
  -2 VIDEO         start from audio encoding using VIDEO
  -a NUM           use audio stream NUM
  -b BITRATE       use BITRATE for audio (default: %s)
  -c WIDTH:HEIGHT  scale to WIDTHxHEIGHT
  -d NUM           use video stream NUM
  -f FPS           set frame rate to FPS (default: %s)
  -h               print help
  -i BITRATE       use BITRATE for video (default: %s)
  -m TERM          display log using TERM (X terminal emulator)
  -o OUTFILE       set output location
  -p PASSLOGFILE   start from 2nd pass (video) using PASSLOGFILE
  -r W:H:X:Y       crop (size:WxH, pos:X,Y)
  -s POS           seek to POS
  -t DURATION      set DURATION(hh:mm:ss)
  -v               video only
  -x OPTION...     set extra x264 options
" ${0} ${BITRATE_AUDIO} ${FPS} ${BITRATE_VIDEO}
}

SCALE=0
USE_X264_EXTRA_OPTS=0
SET_DURATION=0
VIDEOONLY=0
VIDEO_1PASS=0
SKIP_1STPASS_VIDEO=0
SKIP_VIDEO=0
POS=0
CROP=0
USE_XTERM=0
while getopts '12:a:b:c:d:f:hi:m:o:p:r:s:t:vx:' OPT
do
  case ${OPT} in
   1)
    VIDEO_1PASS=1
    ;;
   2)
    VIDEOFILE="${OPTARG}"
    if [ ! -f "${VIDEOFILE}" ]; then
      echo "Error: Cannot open \"${VIDEOFILE}\"" >&2
      exit 1
    fi
    VIDEOFILE=$(cd $(dirname "${VIDEOFILE}") && pwd)/$(basename "${VIDEOFILE}")  # rel.p->abs.p
    SKIP_VIDEO=1
    ;;
   a)
    STREAM_AUDIO=${OPTARG}
    ;;
   b)
    BITRATE_AUDIO=${OPTARG}
    ;;
   c)
    SCALE=1
    SIZE=${OPTARG}
    ;;
   d)
    STREAM_VIDEO=${OPTARG}
    ;;
   f)
    FPS=${OPTARG}
    ;;
   i)
    BITRATE_VIDEO=${OPTARG}
    ;;
   m)
    USE_XTERM=1
    TERMINAL=${OPTARG}
    ;;
   o)
    OUTFILE="${OPTARG}"
    OUTDIR="$(dirname ${OUTFILE})"
    if [ ! -d "${OUTDIR}" ]; then
      if ! mkdir -p "${OUTDIR}"; then
        echo "Error: Cannot create output directory \"${OUTDIR}\"" >&2
        exit 1
      fi
    fi
    OUTFILE=$(cd $(dirname "${OUTFILE}") && pwd)/$(basename "${OUTFILE}")
    ;;
   p)
    SKIP_1STPASS_VIDEO=1
    PASSLOGFILE="${OPTARG}"
    if [ ! -f "${PASSLOGFILE}" ]; then
      echo "Error: Cannot open \"${PASSLOGFILE}\"" >&2
      exit 1
    fi
    PASSLOGFILE=$(cd $(dirname "${PASSLOGFILE}") && pwd)/$(basename "${PASSLOGFILE}")
    ;;
   r)
    CROP=1
    CROPPARAMS=${OPTARG}
    ;;
   s)
    POS=${OPTARG}
    ;;
   t)
    SET_DURATION=1
    DURATION=${OPTARG}
    ;;
   v)
    VIDEOONLY=1
    ;;
   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 "Error: input file \"${INFILE}\" not found." >&2
  exit 1
fi

LOGFILE="$(printf ../glc2mp4-%s-%s.log "$(basename "${INFILE}")" $(date +%Y%m%d%H%M%S))"

TMPDIR=$(mktemp -d glc2mp4.XXXXXXXX)
if [ ${?} -ne 0 ]; then
  echo "Error: cannot create tempdir" >&2
  exit 1
fi
INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})
cd ${TMPDIR}

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

GLCPLAY="glc-play"
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="-demuxer y4m -nosound -ovc x264 -vf ${VFOPTS} -ofps ${FPS}"
CMD_VIDEO_CONV="${GLCPLAY} ${INFILE} -o - -y ${STREAM_VIDEO}"
CMD_VIDEO="${MENCODER} ${MENCODEROPT_COMMON} -x264encopts ${X264OPTS}:subq=7 - -of rawvideo -o ${TMP_VIDEO}"
CMD_VIDEO1="${MENCODER} ${MENCODEROPT_COMMON} -passlogfile ${PASSLOGFILE} -x264encopts ${X264OPTS}:pass=1:turbo=1 - -of rawvideo -o /dev/null"
CMD_VIDEO2="${MENCODER} ${MENCODEROPT_COMMON} -passlogfile ${PASSLOGFILE} -x264encopts ${X264OPTS}:pass=2:subq=7 - -of rawvideo -o ${TMP_VIDEO}"
CMD_AUDIO_CONV="${GLCPLAY} -a ${STREAM_AUDIO} ${INFILE} -o ${TMP_AUDIO_WAV}"
CMD_AUDIO_ENC="${FFMPEG} -i ${TMP_AUDIO_WAV} -y -vn -acodec libfaac -ab ${BITRATE_AUDIO}k ${TMP_AUDIO_AAC}"

exec 3> >(zenity --notification --listen ${ICON:+--window-icon }${ICON:-})
touch "${LOGFILE}"
if [ ${USE_XTERM} -eq 1 ]; then
  ${TERMINAL} -e tail -f "${LOGFILE}" &
  PID=${!}
fi
if [ ${SKIP_VIDEO} -eq 0 ]; then
  # do video encoding
  if [ ${VIDEO_1PASS} -eq 1 ]; then
    # 1pass
    echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO}" >&3
    echo "${CMD_VIDEO_CONV} | ${CMD_VIDEO}" >> "${LOGFILE}"
    ${CMD_VIDEO_CONV} | ${CMD_VIDEO} >> "${LOGFILE}" 2>&1 || exit 1
    echo "message: video: done" >&3
  else
    # 2pass
    if [ ${SKIP_1STPASS_VIDEO} -eq 0 ]; then
      # pass#1
      echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO1}" >&3
      echo ${CMD_VIDEO_CONV} | ${CMD_VIDEO1} >> "${LOGFILE}"
      ${CMD_VIDEO_CONV} | ${CMD_VIDEO1} >> "${LOGFILE}" 2>&1 || exit 1
      echo "message: video pass 1 / 2 done" >&3
    fi
    # pass#2
    echo "tooltip: ${CMD_VIDEO_CONV} | ${CMD_VIDEO2}" >&3
    echo ${CMD_VIDEO_CONV} | ${CMD_VIDEO2} >> "${LOGFILE}" 2>&1
    ${CMD_VIDEO_CONV} | ${CMD_VIDEO2} >> "${LOGFILE}" 2>&1 || exit 1
    echo "message: video: pass 2 / 2 done" >&3
  fi
else
  # skip video encoding
  ln -s "${VIDEOFILE}" ${TMP_VIDEO}
fi
if [ ${VIDEOONLY} -eq 0 ]; then
  echo "tooltip: ${CMD_AUDIO_CONV}" >&3
  ${CMD_AUDIO_CONV} >> "${LOGFILE}" 2>&1 || exit 1
  if [ ! -f ${TMP_AUDIO_WAV} ]; then
    echo "audio not found"
    exit 1
  fi
  echo "tooltip: ${CMD_AUDIO_ENC}" >&3
  ${CMD_AUDIO_ENC} >> "${LOGFILE}" 2>&1 || exit 1
  echo "message: audio: done" >&3
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -add ${TMP_AUDIO_AAC} -new "${OUTFILE}" >> "${LOGFILE}" 2>&1
else
  ${MP4BOX} -fps ${FPS} -add ${TMP_VIDEO} -new "${OUTFILE}" >> "${LOGFILE}" 2>&1
fi
echo "message: mp4: done" >&3
if [ ${USE_XTERM} -eq 1 ]; then
  kill ${PID}
fi
cd ..
rm ${TMPDIR} -fr

関連記事:

使用したバージョン: