[Armadillo:07432] Re: Armadillo-420 MJPG-streamer の画像乱れ問題について

Yasuhisa Nakamura email@hidden
2011年 7月 29日 (金) 02:00:51 JST


中村です。

数年前、Armadillo-220でこのカメラを使うのに苦労しました。

たまたま今、手元に借り物のこのカメラ(の旧型)があるので、
夕方あたりからArmadillo-440につないで、ちょっと調べてました。

#A-220のときには、VIDIOC_DQBUFのioctl()が帰って来なく
#なることがあるのでその前にselect()でタイムアウトを
#付ける必要があったりとか、古賀さんが説明されているような、
#圧縮がかかりにくい被写体で画像のお尻が、ある解像度以上で
#切れる、という問題がありましたが、どちらも今回の現象とは
#関係はありませんので、その内容は省略。

今回の再現は簡単にできました。
  input_uvc.so -f 10 -r 960x720
が、いい(再現しやすい)ようです。

花田さん worte:
> その上で、化け頻度が顕著&mjpg-streamer自体がエラー終了してしまうことは、
> mjpg-streamer動作上の問題(不具合)であると言えそうです。

今まで誰も気づかなかったのはなぜ?と思うような、単純バグでした。
uvcvideoドライバのsyslogへのトレース[*1]をsyslogに出してみて、
気づきました。
「解」は、このメールの最後で。。。。

[*1]
  # echo 16 > /sys/module/uvcvideo/parameters/trace


> mjpg-streamerのinput_uvc周りのコードを精査した結果、
> 毎回(余分に)メモリコピーしていることがわかりました。
>
>  v4l2でDQUEUE→バッファをtmpにコピー→(再)QUEUE→tmpからネットワーク送出→

これ非常に効率悪いですし、「なんかおかしいぁ〜」という部分が
mjpg-streamerにはたくさんあります。
構造体でデータ管理してますが、構造体に入れず一時的な変数や
バッファでよいものもたくさんありますし。。。。
その元はuvccaptureというソフトのようです。

それから、memcpy_picture()とis_huffman()という関数がありますが、
これは使われていません。でも、これを使わないとダメな、
V4L2_PIX_FMT_MJPEG な UVC カメラも過去に遭遇してます。


> jpegデータが切り詰められすぎている(JPEGヘッダサイズ以下)際は
> データコピーをしない…こんな処理がもともと入っていたのですが、
> これが発生した時に再QUEUEされない不具合があり、結果的に一定回数
> (ドライバで用意されたバッファ数分)のエラーが発生するとDQUEUEできるデータが
> なくなり終了してしまう…これがmjpg_streamerが落ちる原因のようです。

4回(v4l2uvc.h で define されている NB_BUFFER)
 Ignoring empty buffer ...
が出ると、そこで落ちますね。


> 前述した正常データ判定に失敗した時も含め、正しく(早く)再QUEUEされるよう修正。

私はこうやりました。
小さなデータを受信してしまったときにre-queueしていないという
単純だけど見落としやすいバグってことで。

--- v4l2uvc.c-orig      2011-03-26 12:37:26.000000000 +0900
+++ v4l2uvc.c   2011-07-29 01:14:08.000000000 +0900
@@ -322,7 +322,7 @@
       if (vd->buf.bytesused <= HEADERFRAME1) {    /* Prevent crash
                                                   * on empty image */
         fprintf(stderr, "Ignoring empty buffer ...\n");
-        return 0;
+        goto requeue;
       }

       /* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
@@ -350,6 +350,7 @@
     break;
   }

+requeue:
   ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
   if (ret < 0) {
     perror("Unable to requeue buffer");

-- 
なかむら




armadillo メーリングリストの案内