Skip to content

Instantly share code, notes, and snippets.

@sorah
Last active December 17, 2015 06:59
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sorah/5569668 to your computer and use it in GitHub Desktop.
Save sorah/5569668 to your computer and use it in GitHub Desktop.

録画の話

ハードウェア構成

  • HP ProLiant MicroServer http://h50146.www5.hp.com/products/servers/proliant/micro/

    • ちっこいやつ。18000 円くらいで手に入る。低消費電力だけど CPU が Atom 相当なのでそれなりに遅い。
  • CPU model name: AMD Turion(tm) II Neo N40L Dual-Core Processor

  • CPU MHz: 800.000

  • RAM: 2GB

  • HDD:

  NAME                       SIZE TYPE MODEL
  sda                      232.9G disk VB0250EAVER
  ├─sda1                   228.2G part # rootfs. そろそろ USB に移したい
  └─sda2                     4.7G part # swap
  sdb                        1.8T disk WDC WD20EARX-00P
  └─sdb1                     1.8T part # 録画メイン
  sdc                        1.8T disk WDC WD20EARS-00M
  └─sdc1                     1.8T part # Time Machine バックアップおよび録画バックアップ
  sdd                        2.7T disk WDC WD30EFRX-68A
  └─sdd1                     2.7T part # 諸々ファイル置き場, 録画バックアップ
  sde                        2.7T disk My Book 1140 (USB)
  ├─sde1                     128M part
  └─sde2                     2.7T part # 録画バックアップ
  sdf                        1.8T disk EZRX-00D8PB0 (USB)
  └─sdf1                     1.8T part
    └─chihiro-izumi (dm-0)   1.8T lvm  # 録画バックアップ

最近 LVM を使いはじめた。

  • 録画カード: PT3 x1
  • ICカードリーダ: SCR3310-NTTCom

ソフトウェア構成

スクリプト郡

https://github.com/sorah/sorah-rec-utils もあわせてどうぞ。

エンコードまわり

  • libx264-hq-ts.ffpreset: ffmpeg 用設定ファイル。/usr/share/ffmpeg/ とかに置く。
  • encode.rb: redis の BLPOP でジョブを取得して、設定ファイルの内容にそって所定の手段でファイルを取得、encode-scripts/*.sh を呼び、終わったら成果物を設定ファイルの内容にそって配置しまたジョブを待つスクリプト
    • remote, local でそれぞれ別だったのをちょっと前に一本化した。
    • これを Core i7-2600 のマシン上でうごいている Windows ホストの Linux VM でぶん回している。

ろくがまわり

  • do-record.sh: epgrec で使っているエンコード用スクリプト。実際に動かしてる奴にコメントつけて一部加工しています。

  • sd-hd.rb: @eagletmt 作の TOKYO MX アクロバティック解像度変更対策 (720p の状態が録画先頭だと後続の 1080p 切り替えで ffmpeg の挙動があやしくなる) → https://gist.github.com/eagletmt/5810946

munin まわり

zabbix へ移行したのであまり使ってない。まだtv_signalはUserParameterみたいなの用意してないんだよな。

  • munin_tv_signal: checksignal コマンドを利用して電波レベルを munin に記録させてる。GR18 はお住まいの地域に合わせて変えてください。

ディスクまわり

  • list-backup.rb: 諸々バックアップディレクトリとかをなめて作品・話毎の冗長性の確認や、重複チェックなどをしてレポートとして markdown を吐くスクリプト
    • しょぼいカレンダーをみています
    • BSと地上波で撮ってあって問題なく回っていれば BS 以外を捨てるとか
    • 片方にテロップ残ってたり失敗してたら何も捨てないとか

まとめ

適当にやると dirty なスクリプトになります。 今書いてるのはちゃんとテストも用意して安全に書き換えられるようにして綺麗に維持したい。

#!/bin/bash
echo "CHANNEL : $CHANNEL"
echo "DURATION: $DURATION"
echo "OUTPUT : $OUTPUT"
echo "TUNER : $TUNER"
echo "SID: $SID"
echo "TYPE : $TYPE"
echo "MODE : $MODE"
RECORDER=/usr/local/bin/recpt1
# /dev/pt3video[01] が BS、 /dev/pt3video[23] が地上波のチューナなので
# TYPE 環境変数 (GR か BS) を見てチューナをきめる
# TUNER 環境変数は BS か地上波ばらばらで 0 か 1 どっちを使うかがくるので (それぞれ 2 つずつ存在する設定にした時)、それで重複を調整
if [ "$TYPE" == "GR" ]; then
let devno=2+$TUNER
LNB=""
else
let devno=0+$TUNER
# BS の場合は recpt1 に --lnb 15 を渡して BS チューナに電源が行くようにする
LNB="--lnb 15"
fi
# キャラクタデバイスファイル名を突っ込む
DEVICE=/dev/pt3video${devno}
echo "DEVICE: $DEVICE"
# FIXME: 見苦しい所。 MODE で拡張子わけたりとか epgrec ができるようになってたけど、
# 昔は MODE=1 で 760p.mp4 を吐くようにしていたので TS の出力は 760p.mp4.ts
# みたいにするようにしてた。いまは MODE=1 でも .ts を吐くようにしているけど
# .ts が被らないように .ts.ts になったら .ts になるように修正している
if [ "$MODE" == "1" ]; then
OUTPUT_TS="$(echo "${OUTPUT}.ts"|sed -e 's/\.ts\.ts$/.ts/g')"
else
OUTPUT_TS="${OUTPUT}"
fi
# .progress を後ろにつける事でエンコードキューに録画中のファイルが引っかからないように考慮
OUTPUT_TS_PROGRESS="${OUTPUT_TS}.progress"
export PATH=/home/sorah/.rbenv/bin:/home/sorah/.rbenv/shims:$PATH
function tweet() {
# fluent-tweet: fluentd-logger wrapper
[ `dirname "${OUTPUT}"` != "/tmp" ] && fluent-tweet "rec $*"
}
tweet "録画開始: $(basename "${OUTPUT}")"
success=0
while true; do
# コマンドを叩いた時の UNIX タイムを記録しとく
ruby -e'p Time.now.to_i' > "/tmp/elapsed-$$"
# SID ありなしで分岐して --sid $SID つけるかどうか決めてるけど、明らかにリファクタリングできるよね...
if [ "$SID" == "" ]; then
echo "$RECORDER $LNB --device $DEVICE --b25 --strip $CHANNEL $DURATION ${OUTPUT_TS_PROGRESS}" >>/tmp/do-record.log
echo "==== $RECORDER $LNB --device $DEVICE --b25 --strip $CHANNEL $DURATION ${OUTPUT_TS_PROGRESS}"|tee -a ${OUTPUT}.log
# ↓実際にコマンドたたいてるのはここ。
$RECORDER $LNB --device $DEVICE --b25 --strip $CHANNEL $DURATION "${OUTPUT_TS_PROGRESS}" 2>&1|tee -a ${OUTPUT}.log
else
echo "$RECORDER $LNB --device $DEVICE --b25 --strip --sid $SID $CHANNEL $DURATION ${OUTPUT_TS_PROGRESS}" >>/tmp/do-record.log
echo "==== $RECORDER $LNB --device $DEVICE --b25 --strip --sid $SID $CHANNEL $DURATION ${OUTPUT_TS_PROGRESS}"|tee -a ${OUTPUT}.log
# ↓実際にコマンドたたいてるのはここ。
$RECORDER $LNB --device $DEVICE --b25 --strip --sid $SID $CHANNEL $DURATION "${OUTPUT_TS_PROGRESS}" 2>&1|tee -a ${OUTPUT}.log
fi
# リトライ周りの処理
# recpt1 の終了ステータスを取る
success=$?
# 録画する時間がもともと 60 秒未満 OR
# 上できろくしたコマンドを実行した時間から 10 秒以上経過してれば
# 0 、そうでなければ 1 になる。録画が想定より早く終わっている場合は 1 になる
dur="$(cat /tmp/elapsed-$$|ruby -e"print((${DURATION} < 60 || 10 <= (Time.now.to_i - STDIN.read.to_i)) ? 0 : 1)")"
# /tmp ディレクトリへの出力ならリトライしないのでループを抜ける
[ `dirname "${OUTPUT}"` == "/tmp" ] && break
if tail -n1 ${OUTPUT}.log|grep "Cannot open tuner device" >/dev/null; then
# Cannot open tuner device, チューナが利用中だった場合
# epgrec はバカなのでたまに利用中のチューナ番号を渡してくる (主に書きなおそうと思った要因)
sleep 2
tweet "@sora_her Cannot open tuner device: $(basename "${OUTPUT}") ($(date))"
# チューナ2個でいまんところ決め打ちなので1だったら0、0だったら1を利用するようにする
if [ "$TUNER" = "1" ]; then
TUNER=0
else
TUNER=1
fi
# うえのほうの処理と DRY だけど再度デバイスファイル名をセットする
if [ "$TYPE" == "GR" ]; then
let devno=2+$TUNER
LNB=""
else
let devno=0+$TUNER
LNB="--lnb 15"
fi
DEVICE=/dev/pt3video${devno}
# (ループなので勝手にやり直される)
else
# 指定した時間より早く終了してしまった場合の異常終了対策
# 上でつくった dur が 0 だったらリトライしなくてよさそうなのでループを抜ける。
[ "$dur" = "0" ] && break
# 長さを調整する。既に録画で経過した時間を引いてちょっと足す。
let DURATION-="$(cat /tmp/elapsed-$$|ruby -e"print(Time.now.to_i - STDIN.read.to_i)")"
let DURATION+=2
# 一回録画が止まってしまったファイルは別の名前にリネームして退避
mv "${OUTPUT_TS_PROGRESS}" "${OUTPUT_TS}.fail$(date '+%s')"
# (ループなので勝手にリトライされる)
fi
done
# TOKYO MX (GR16) の録画なら sd-hd.rb を呼ぶ
if [ "$CHANNEL" = "16" -a "$TYPE" = "GR" ]; then
echo "==== ruby sd-hd.rb ${OUTPUT_TS_PROGRESS} --write"|tee -a ${OUTPUT}.log
ruby sd-hd.rb "${OUTPUT_TS_PROGRESS}" --write 2>&1 | tee -a ${OUTPUT}.log
fi
# .ts.progress を .ts にリネーム
mv "${OUTPUT_TS_PROGRESS}" "${OUTPUT_TS}"
if [ "$success" == "0" ]; then
tweet "録画終了: $(basename "${OUTPUT}"), HDD $(df -h /dev/sdb1|tail -n1|sed -e 's/ \+/\t/g'|cut -f 4) 残り"
else
tweet "録画失敗: $(basename "${OUTPUT}")"
fi
[ -f "/tmp/elapsed-$$" ] && rm "/tmp/elapsed-$$"
# tmp 以下 ( == getepg ) への録画じゃなければ unwatched.txt にファイル名を追記(未読管理)
if [ `dirname "${OUTPUT}"` != "/tmp" ]; then
echo "$OUTPUT_TS" >> unwatched.txt
fi
level=41
coder=1
flags=+loop
cmp=+chroma
partitions=+parti8x8+parti4x4+partp8x8+partb8x8
me_method=umh
subq=7
qdiff=15
me_range=16
g=150
keyint_min=25
sc_threshold=40
i_qfactor=0.71
b_strategy=1
qmin=10
rc_eq='blurCplx^(1-qComp)'
bf=16
bidir_refine=1
deblockalpha=0
deblockbeta=0
#!/bin/bash
case $1 in
config)
cat <<'EOM'
graph_title TV Signal Level
graph_vlabel C/N (dB)
graph_args -l 0
graph_category recorder
graph_scale no
bs.label BS101
gr.label GR18
EOM
exit 0;;
esac
#echo -n "ffmpeg.value "
#ps aux|grep ffmpeg|grep -v ' \(/usr/bin/\)\?time'|grep -v grep|grep -v ffmpeg_processes|wc -l
echo -n "bs.value "
/usr/local/bin/checksignal-oneshot BS 101
echo -n "gr.value "
/usr/local/bin/checksignal-oneshot GR 18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment