RaspberryPiでストリーミングしながら動画をループ再生する

1080pなHDMI出力が某弊社新製品のテスト用にいっぱい、且つ、できれ安めに欲しいって話があって、素直にビデオカメラを用意できればそれでいいんですが、1080pまでを出すのになると意外と中古でも2万円くらいの価格帯になってしまって高くつきます、というのに対応したもののメモ。

で、解決策は、ビデオカメラでなくてもよいから安い方法なんかないかなぁということで思いついたのが、RaspberryPiってちゃんとしたHDMIっぽいので、これで適当な動画を延々とループ再生すれば良いのではないのかという話。9割趣味、1割仕事という感じで軽い息抜き的なノリでさくっとやってみました。

手順メモ

とりあえず結局こうやったという手順をメモとして。

  • Raspbian入れる

Raspbianじゃないといけない理由はないですが、Recommendedって書いているしなくらいでこれを選択。実はXMBCも動くやつもあったっぽかったけどそこまでみずに入れちゃいました。まあ結果として起動時にスクリプト走らせたりするので、変にいろいろ入れず自分で書く方が早かったのでよしということで。

  • lv入れる

apt-getで一発です。

apt-get install lv

単にlvがないと生きていけないだけ。

  • とりあえず初期設定みたいなのをやる sshdの起動設定くらいだけど

NOOBSLiteを経由していれたからかもしれませんが、とりあえずDebianっぽい設定画面がでてくるので最低限SSHが起動するようにしときます。HDMI出力は動画再生をするのでSSH経由での制御のほうがなにかと楽です。

  • ユーザpiでSSHで接続できることを確認してこのユーザをそのまま使います

piのパスワードの設定は上記の初期設定で決めるのでそれをつかってSSHでログインします。ディスプレイ出力のコンソールつかってもいいのですが、動画再生しはじめると画面が占有されてしまうので、とりあえずSSHで作業しちゃうのがおすすめ。

  • omxplayerを再生用には使う

Raspbianだとはじめから入ってたのでそのままつかいます。mplayerとかでもいけるっぽかったですが、試したかぎりでは、H.264/AACであればomxplayerでそのままなんの問題もなくハードウェアの支援も使えるようで、深く考えずにこのままomxplayerでよさげです。

  • podcastのxmlをパースするスクリプト書く

ループするための動画ファイルをどこに置くかですが、今回は自宅の録画サーバからHTTPストリーミングする形で再生します。どうやってURLを列挙しようかなぁとおもったんですが、今自分のサーバにはpodcast向けにXMLを吐く機能があったのでこれを流用します。

  • XMLをコマンドラインで解析

で、要はURLが取得できればよいのでコマンドラインでサクッとXPathを指定して抽出する方向でいきます。ざっと検索してxpathっていうそのまんまなコマンドがあってこれを使う方向にしました。(が、使ってみるとPerlで書かれていてxpathがRaspberryPi程度の性能では、すげー時間かかってしまう感じで他のつかったほうがいいかも。xmllintとかxalanとかですかね。)

apt-get install libxml-xpath-perl

XPath的には、enclosureタグのurl属性を列挙できればよいんですが、どうもurl=”http://xxx.xxx.xxx.xxx/hoge.MP4“的な形でしかxpathコマンドでは抽出できなかったため、その後、awkで=を分割、sedで”“を除去します。

で、結果、ざっくり、スクリプトの流れは下記のような感じ。/home/pi/playloop.shとして保存します。

#!/bin/sh

while true; do
    if ps ax | grep -v grep | grep omxplayer > /dev/null
    then
        sleep 1
    else
        for entry in `curl "http://xxx.xxx.xxx.xxx/recorded/folcast.php?tid=3045&mode=6" 2>/dev/null | xpath -e //item/enclosure/@url 2>/dev/null | awk -F"=" '{ print $2}'`
        do
            clear
            omxplayer -o hdmi `echo $entry | sed -e 's/[^"]*"\([^"]*\)".*/\1/'` > /dev/null
        done
    fi
done

whileで無限ループをつくって、podcast xml→URLリストに変換してforで順次omxplayerに渡すだけです。ただ、最後までいってしまうとループを抜けてまだ再生が終わってないみたいなケースもあるかもなーということで、omxplayerというプロセスがいた場合は1秒スリープします、という感じで延々と再生します。ただ、PodcastのXMLを順に再生するので、重複チェックとかないので、追加されたりしたとしても、その動画だけが再生されるわけではなく、延々と重複が出るのはご愛敬。

  • ストリーミングはIPv6でやる

で、ここまでやって気づいたのが、はじめは適当にIPv4をつかって自宅からストリーミングをためしていたのですが、これ電源いれっぱなしで放置すると、確実に上り帯域をつかいまくってISPから怒られることに気づいてしまったので、その回避の意味と実際速度もレイテンシもよくなるので、IPv6でアクセスするように変更します。

サーバ自体はすでにv6対応しているんで、RaspberryPi側がv6使えるようにすればよいだけです。といっても、Raspbianの場合、v6もモジュールになってるだけなので、modprobe ipv6ってやればOKのようです。なので、次の起動時のところで、modprobe ipv6とやってしまうという適当な感じで。

  • 起動時に動くように/etc/rc.localに/home/pi/playloop.shを書いてしまう

で、この後は、起動しただけで、このスクリプトを実行して勝手に再生し続けるようにするのが次の手順。init.dなスクリプトとかを書くといいかなーとおもいつつ、めんどくさいので、/etc/rc.localにさくっと追加してしまいます。

modprobe ipv6
sleep 3
/home/pi/playloop.sh

RAでipv6のアドレスとれるまでの時間がよくわからんので適当にsleepを3秒いれます。適当すぎますね、もうすこしまともに書いたほうがいいかもしれません。

  • HDMIの出力を調整

HDMIは1080p音有り、RGBに固定します。/boot/config.txtの設定を書き換えます。

hdmi_group=1
hdmi_mode=16
hdmi_drive=2
hdmi_force_hotplug=1
hdmi_pixel_encoding=1
config_hdmi_boost=4
disable_overscan=1
  • 結果はtvservice -sで確認
state 0x12001a [HDMI CEA (16) RGB lim 16:9], 1920x1080 @ 60Hz, progressive

こんな感じならOKです。 このへんは使ってるディスプレイに合わせて適宜調整するのがよいです。raspberry pi /boot/config.txtとかやると解説がいっぱいでてきます。

ちなみに、ちゃんとtvserviceを使えばEDIDの確認もできます。ディスプレイの解像度に合わせた出力も確認できますね。

EDIDをファイルにダンプ
$ tvservice -d /tmp/edid.dat
ダンプしたものをparseして内容列挙
$ edidparser /tmp/edid.dat

これで、上記のhdmi_modeなども確認できるので、これを見ながら解像度を調整するのがたぶん一般的な手順。

  • 若干オーバークロックしておく 意味ないけど
core_freq=250
sdram_freq=450
over_voltage=2

/boot/config.txtの解説を読んでて見つけたので試しにやってみました。体感するほどの差はないですね。

おわり

ざーっと手順を舐めましたが、まあ一度設定してしまえばSDカードをDDで量産できるのでテスト用にはかなりアリかもしれないです。ちなみに、動画のビットレートがむやみやたらと高いとサーバ側が泣く日がくるかもしれないので、10台とか使うときには毎回ストリーミングは微妙ですね。

すなおにPodcastのXMLを解析しているところをはじめからSDカードに動画ファイルを置いておいてfindしてxargsとかに渡せば解決するのでそれで良い気がします。ストリーミングしてるのは更新されれば勝手に内容変わるほうがおもしろいかもなーくらいのノリでしかないので。

という感じで、Raspberry PiはちゃんとHDMIの出力をいろいろいじれるので、特定の解像度で出力を固定したいとかにわざわざお高いジェネレータを使わなくても良いのが魅力ですね。ちなみに、tvserviceだとかedidparserを使えばちゃんとEDIDを見れるので、ディスプレイが対応してる解像度一覧とかみたいみたいな用途にも向いているかも。

という、いつかの未来にまた設定したい場合のための備忘録メモでした。