raspbian にて mjpg-streamer で mjpeg を使う

Pocket

以前、mjpg_streamer を使っていた時に、UVC カメラで MJPEG で配信できた気がするのにできなくなりました

症状としては、mjpg_streamer コマンドは MJPEG で起動できるが画像が表示されない
環境としては、 x86 のマシンから raspberry pi に移ってはいるし、3年くらい経過はしている

他のサイトとか調べてみると

MJPEG を使えないなら YUYV にする -y オプションを付けろ

というサイトばかりでした。
カメラ自体も V4L2 でドライブレコーダーデーモン書いた時は MJPEG 使えていたので・・・

この苦労を覚書として書いておきます

環境

使っているカメラは以前と同じで下記の通り

<br />
$ sudo v4l2-ctl --info<br />
Driver Info (not using libv4l2):<br />
Driver name : uvcvideo<br />
Card type : UCAM-DLX300B<br />
Bus info : usb-3f980000.usb-1.3<br />
Driver version: 4.1.6<br />
Capabilities : 0x84200001<br />
Video Capture<br />
Streaming<br />
Device Capabilities<br />
Device Caps : 0x04200001<br />
Video Capture<br />
Streaming<br />

ELECOM のこちらのカメラで、もう売ってません・・・

今回のマシンは raspbian で Raspberry Pi 2 model b です

インストールしたが動かない

まずは、mjpg_streamer のインストール

<br />
$ svn co http://svn.code.sf.net/p/mjpg-streamer/code/mjpg-streamer mjpg-streamer<br />
$ cd mjpg-streamer<br />

mjpg-streamer には scripts/make_dep.sh という dep パッケージを作成するスクリプトが入ってます
ですが、そのままでは MJPEG が使えません

MJPEG は video4linux2 でないと取得できないのですが、
そのままの make_dep.sh では video4linux2 が使われません

<br />
$ vi script/make_dep.sh<br />

このため、改造

<br />
#!/bin/sh</p>
<p># update via SVN<br />
svn up</p>
<p># find out the current revision<br />
SVNVERSION=&quot;$(export LANG=C &amp;amp;amp;&amp;amp;amp; export LC_ALL=C &amp;amp;amp;&amp;amp;amp; echo $(svn info | awk '/^Revision:/ { print $2 }'))&quot;</p>
<p># use checkinstall to create the DEB package<br />
sudo checkinstall -D \<br />
--pkgname &quot;mjpg-streamer&quot; \<br />
--pkgversion &quot;r$SVNVERSION&quot; \<br />
--pkgrelease &quot;1&quot; \<br />
--maintainer &quot;tom_stoeveken@users.sourceforge.net&quot; \<br />
--requires &quot;libjpeg62&quot; \<br />
--nodoc \<br />
make USE_LIBV4L2=true DESTDIR=/usr install<br />

改造結果は上記の通り

<br />
USE_LIBV4L2=true<br />

を付けるだけ

<br />
$ sudo dpkg -r mjpg-streamer<br />
$ make clean<br />
$ sudo sh scripts/make_dep.sh<br />

そして、上記コマンドでインストール

<br />
$ sudo /usr/bin/mjpg_streamer -i &quot;/usr/lib/input_uvc.so -d /dev/video0 -r 320x240 -f 3 -n&quot; -o &quot;/usr/lib/output_http.so -p 8080 -w /usr/www&quot;<br />

と実行しても YUYV でしか取得できません

違うコマンドで MJPEG を取得

MJPEG を取得できる CUI コマンドとして fswebcam があります

<br />
$ sudo fswebcam -p MJPEG -v --log hoge.log a.jpg<br />

と実行してみると、MJPEG で取得できてるし、画像も問題なし

つまり、mjpg-streamer がオカシイのがわかりました

まぁ、自分でCで書いたドライブレコーダープログラムでは動いていたし…

パッチを発見

日本語のサイトでは、YUYV オプションを使えというのしか出てきません

諦めかけたところ、こちらの Raspberry Pi のフォーラムで MJPEG で配信できない問題が議論されてました

使っている Raspbian のカーネルのバージョンは 4.1.6-v7+ なので、該当するであろうと考え、パッチを当ててみると

<br />
$ cd mjpg-streamer/plugins/input_uvc<br />
$ vi input_uvc.patch<br />
# クリップボードでパッチの本文をコピー<br />
$ patch -p2 input_uvc.patch<br />
(Patch is indented 4 spaces.)<br />
patching file input_uvc.c<br />
(Patch is indented 4 spaces.)<br />
patching file v4l2uvc.c<br />
(Patch is indented 4 spaces.)<br />
patching file v4l2uvc.h<br />

パッチ自体はこちら

<br />
--- plugins/input_uvc/input_uvc.c (revision 174)<br />
+++ plugins/input_uvc/input_uvc.c (working copy)<br />
@@ -405,9 +405,13 @@<br />
if(pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;formatIn == V4L2_PIX_FMT_YUYV) {<br />
DBG(&quot;compressing frame from input: %d\n&quot;, (int)pcontext-&amp;amp;gt;id);<br />
pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].size = compress_yuyv_to_jpeg(pcontext-&amp;amp;gt;videoIn, pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].buf, pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;framesizeIn, gquality);<br />
+ /* copy this frame's timestamp to user space */<br />
+ pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].timestamp = pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;buf.timestamp;<br />
} else {<br />
DBG(&quot;copying frame from input: %d\n&quot;, (int)pcontext-&amp;amp;gt;id);<br />
- pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].size = memcpy_picture(pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].buf, pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;tmpbuffer, pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;buf.bytesused);<br />
+ pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].size = memcpy_picture(pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].buf, pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;tmpbuffer, pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;tmpbytesused);<br />
+ /* copy this frame's timestamp to user space */<br />
+ pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].timestamp = pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;tmptimestamp;<br />
}</p>
<p>#if 0<br />
@@ -418,8 +422,6 @@<br />
prev_size = global-&amp;amp;gt;size;<br />
#endif</p>
<p>- /* copy this frame's timestamp to user space */<br />
- pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].timestamp = pcontext-&amp;amp;gt;videoIn-&amp;amp;gt;buf.timestamp;</p>
<p>/* signal fresh_frame */<br />
pthread_cond_broadcast(&amp;amp;amp;pglobal-&amp;amp;gt;in[pcontext-&amp;amp;gt;id].db_update);<br />
Index: plugins/input_uvc/v4l2uvc.c<br />
===================================================================<br />
--- plugins/input_uvc/v4l2uvc.c (revision 174)<br />
+++ plugins/input_uvc/v4l2uvc.c (working copy)<br />
@@ -450,6 +450,8 @@<br />
*/</p>
<p>memcpy(vd-&amp;amp;gt;tmpbuffer, vd-&amp;amp;gt;mem[vd-&amp;amp;gt;buf.index], vd-&amp;amp;gt;buf.bytesused);<br />
+ vd-&amp;amp;gt;tmpbytesused = vd-&amp;amp;gt;buf.bytesused;<br />
+ vd-&amp;amp;gt;tmptimestamp = vd-&amp;amp;gt;buf.timestamp;</p>
<p>if(debug)<br />
fprintf(stderr, &quot;bytes in used %d \n&quot;, vd-&amp;amp;gt;buf.bytesused);<br />
Index: plugins/input_uvc/v4l2uvc.h<br />
===================================================================<br />
--- plugins/input_uvc/v4l2uvc.h (revision 174)<br />
+++ plugins/input_uvc/v4l2uvc.h (working copy)<br />
@@ -28,6 +28,7 @@</p>
<p>#include &amp;amp;lt;stdio.h&amp;amp;gt;<br />
+#include &amp;amp;lt;stdint.h&amp;amp;gt;<br />
#include &amp;amp;lt;string.h&amp;amp;gt;<br />
#include &amp;amp;lt;fcntl.h&amp;amp;gt;<br />
#include &amp;amp;lt;unistd.h&amp;amp;gt;<br />
@@ -105,6 +106,8 @@<br />
int framecount;<br />
int recordstart;<br />
int recordtime;<br />
+ uint32_t tmpbytesused;<br />
+ struct timeval tmptimestamp;<br />
};</p>
<p>/* context of each camera thread */<br />

<br />
$ cd ../../<br />
$ make clean<br />
$ dpkg -r mjpg_streamer<br />
$ sudo sh scripts/make_dep.sh<br />

あとは、dep ファイルを作成し、インストール
起動してみたら無事動いた!

リソース消費確認

YUYV だと 640×480 を 3FPS で取得しようとすると、CPU リソースを 20%消費してましたが、
MJPEG にした途端 6FPS でも 5% くらいになりました

スマホで見る

Androidなら CamBuddy と言うアプリが使えます

アプリ設定のURL に

<br />
http://example.com:8080/?action=stream<br />

のようにすればストリームで閲覧できます!

1件のコメント

  1. 正解です!
    ありがとうございます。

コメントを残す