raspbian にて mjpg-streamer で mjpeg を使う

Pocket

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

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

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

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

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

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

環境

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

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

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

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

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

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

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

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

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

$ vi script/make_dep.sh

このため、改造

#!/bin/sh

# update via SVN
svn up

# find out the current revision
SVNVERSION="$(export LANG=C && export LC_ALL=C && echo $(svn info | awk '/^Revision:/ { print $2 }'))"

# use checkinstall to create the DEB package
sudo checkinstall -D \
--pkgname "mjpg-streamer" \
--pkgversion "r$SVNVERSION" \
--pkgrelease "1" \
--maintainer "tom_stoeveken@users.sourceforge.net" \
--requires "libjpeg62" \
--nodoc \
make USE_LIBV4L2=true DESTDIR=/usr install

改造結果は上記の通り

USE_LIBV4L2=true

を付けるだけ

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

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

$ sudo /usr/bin/mjpg_streamer -i "/usr/lib/input_uvc.so -d /dev/video0 -r 320x240 -f 3 -n" -o "/usr/lib/output_http.so -p 8080 -w /usr/www"

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

違うコマンドで MJPEG を取得

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

$ sudo fswebcam -p MJPEG -v --log hoge.log a.jpg

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

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

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

パッチを発見

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

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

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

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

パッチ自体はこちら

--- plugins/input_uvc/input_uvc.c (revision 174)
+++ plugins/input_uvc/input_uvc.c (working copy)
@@ -405,9 +405,13 @@
if(pcontext->videoIn->formatIn == V4L2_PIX_FMT_YUYV) {
DBG("compressing frame from input: %d\n", (int)pcontext->id);
pglobal->in[pcontext->id].size = compress_yuyv_to_jpeg(pcontext->videoIn, pglobal->in[pcontext->id].buf, pcontext->videoIn->framesizeIn, gquality);
+ /* copy this frame's timestamp to user space */
+ pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp;
} else {
DBG("copying frame from input: %d\n", (int)pcontext->id);
- pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->buf.bytesused);
+ pglobal->in[pcontext->id].size = memcpy_picture(pglobal->in[pcontext->id].buf, pcontext->videoIn->tmpbuffer, pcontext->videoIn->tmpbytesused);
+ /* copy this frame's timestamp to user space */
+ pglobal->in[pcontext->id].timestamp = pcontext->videoIn->tmptimestamp;
}

#if 0
@@ -418,8 +422,6 @@
prev_size = global->size;
#endif

- /* copy this frame's timestamp to user space */
- pglobal->in[pcontext->id].timestamp = pcontext->videoIn->buf.timestamp;

/* signal fresh_frame */
pthread_cond_broadcast(&pglobal->in[pcontext->id].db_update);
Index: plugins/input_uvc/v4l2uvc.c
===================================================================
--- plugins/input_uvc/v4l2uvc.c (revision 174)
+++ plugins/input_uvc/v4l2uvc.c (working copy)
@@ -450,6 +450,8 @@
*/

memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
+ vd->tmpbytesused = vd->buf.bytesused;
+ vd->tmptimestamp = vd->buf.timestamp;

if(debug)
fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
Index: plugins/input_uvc/v4l2uvc.h
===================================================================
--- plugins/input_uvc/v4l2uvc.h (revision 174)
+++ plugins/input_uvc/v4l2uvc.h (working copy)
@@ -28,6 +28,7 @@

#include <stdio.h>
+#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
@@ -105,6 +106,8 @@
int framecount;
int recordstart;
int recordtime;
+ uint32_t tmpbytesused;
+ struct timeval tmptimestamp;
};

/* context of each camera thread */
$ cd ../../
$ make clean
$ dpkg -r mjpg_streamer
$ sudo sh scripts/make_dep.sh

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

リソース消費確認

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

スマホで見る

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

アプリ設定のURL に

http://example.com:8080/?action=stream

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

1件のコメント

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

コメントを残す