LovyanGFXとJpgLoopAnimeでM5StackとM5Cameraの全画面WiFi動画ストリーミング実験

LovyanGFXとJpgLoopAnimeを使って、M5CameraとM5Stackの動画ストリーミング実験 M5Stack

こんばんは。

今回は更にスゴイっす!
LovyanGFX と M5Stack_JpgLoopAnime ライブラリを取り入れて、前回記事のM5StackとM5CameraのWiFi動画ストリーミングプログラムを改良したら、メチャメチャ高速で、20~24fpsという高フレームレートが実現できました。
しかも、M5Stackの全画面(320 x 240 pixel)ですよ!!!
JPEG画質を落とせば、常時24~25fps出せたんですよ!!!

スポンサーリンク

それに加えて、カメラ画像のレイテンシ(遅延)がメチャメチャ少ないんですよ!
無線のWiFi通信で、しかも、UDPではなくTCP/IP通信ですよ!
これって凄くないですか?
とにかく以下の動画をご覧ください。

これ、ヤバイですよね。
今までのは何だったんだって感じの脅威的な速度です。

LovyanGFX と M5Stack_JpgLoopAnime ライブラリは、らびやん さんが作ったものです。
Twitterではよくアドバイスを頂き、目から鱗な情報を沢山いただきました。
いつも本当にありがとうございます。
m(_ _)m

前回記事では、私の自前ライブラリを使っていて、JPEGデコードライブラリはArduino core for the ESP32に同梱のTJpgDecライブラリを使っていました。
その時は、240 x 176 pixel で10~15fps程度でした。
それが、今回はM5StackのLCD全画面の320 x 140 pixelで、最高画質で 20~24fps を叩き出せるようになったんですよ!

画質を一段階落とせば、平均24fpsの速度を叩き出せて、かなり安定しました。
WiFiでTCP/IP通信でここまで速度が出せれば、プログラミングとしては最高じゃないでしょうか。
M5CameraのWiFi出力特性上、たぶん25fpsが限界だと思われますので、充分すぎます。

そして、M5Stackのオプションバッテリーを使うと、約3時間の連続動画ストリーミングができました。
以前は2時間半弱がせいぜいだったことを考えると、TCPによる無駄なパケット再送処理が少なくなって、省エネになったという一石二鳥の効果があったと思います。

とにかくスバラシイので、このライブラリを使わない手は無いですね。
ということで、自分のやった方法を紹介します。

因みに何度も言っていますが、私は素人アマチュアですので、何か誤りや勘違い等あるかもしれません。
もし、お気づきの点がありましたらコメント投稿等でご連絡いただけると幸いです。

    【目次】

  1. フレームレートを上げるには受信側の処理が肝だった
  2. LovyanGFXとM5Stack_JpgLoopAnimeを使うと圧倒的に高速だった
  3. 使ったもの
  4. Arduino core for the ESP32のインストール
  5. M5Stack公式ライブラリのインストール
  6. LovyanGFXライブラリのインストール
  7. M5Stack_JpgLoopAnime ライブラリのダウンロード
  8. M5Camera(送信側)の設定
  9. M5Stack(受信側)の設定およびスケッチ
  10. 操作方法
  11. M5Stack用電池モジュール(オプションバッテリー)使用について
  12. 新たに学んだこと
  13. 今回の実験の課題点
  14. 編集後記

フレームレートを上げるには受信側の処理が肝だった

M5CameraとM5StackのWiFi動画ストリーミングのフレームレートを上げる方法について、今までのこの数か月間ずっと個人的に実験した結果、受信側のデバイスがいかに高速で1フレームの画像を描画処理して次のフレームの受信に備えられるかというところが鍵だという結論に至りました。

なぜなら、M5Cameraとパソコンのブラウザとの通信では高速フレームレートなことからも明らかです。
前回記事までの結果だと、M5Stackの画角 240 x 176 pixel でせいぜい15fpsだったのが、パソコンのブラウザの場合は25fpsの速度が出ていたことからも、受信側の処理能力が原因だと分かると思います。

個人的考察だと、M5Camera側の送信フレームレートは 25fpsが最高という結論でした。
イメージセンサOV2640からは50fpsのDMA (Direct Memory Access)でESP32に送られてきて、ESP32が1フレーム受け取ると、次のフレームを間引いてWiFi送信しているからです。
それに、ESP32のWiFi送信は、通信の輻輳の問題もあって、あまり速度を上げられません。
JPEG画質を下げて、1フレームの送信バイト数を下げれば、フレームレートを上げられますが、個人的には 20~25fps出せれば充分スムースな動画ストリーミングだと思います。

M5Stackの能力的にパソコンの処理能力には到底及ばないので、前回記事の段階では15fpsが限界かなと思っていました。
でも、今回、全画面 320 x 240 pixel のJPEG最高画質で 20 ~ 24fps を叩き出せたということは、パソコンのブラウザに迫る能力が引き出せたのではないかと思っています。
すんごいですよね~。。。

LovyanGFXとM5Stack_JpgLoopAnimeを使うと圧倒的に高速だった

らびやん さんが作ったLCD関連ライブラリは、M5Stack等を使う場合はとにかくお勧めです。
らびやん さんの一連のツイートを見れば分かるのですが、毎日のようにLCDの高速化を探求していて、ほんとに頭が下がります。

M5StackのLCDにイメージセンサのカメラ画像をWiFi動画ストリーミングする場合は、LovyanGFXとM5Stack_JpgLoopAnimeを使った方が圧倒的に高速でした。

実は、LovyanGFXのJPEG描画だけでテストしてみたのですが、その場合は 2~4fpsしか出ませんでした。
そこで、M5Stack_JpgLoopAnime のJPEGデコード部分を組み合わせたら、なんと、20fps以上という圧倒的な高速表示を叩き出せたんです。

GitHubのLovyanGFX ソースコードを見ると、C++特有の定義や標準関数で埋め尽くされていて、「なんじゃこりゃ?」っていう感じでした。
異次元プログラミングの世界を見た感じで、とっても刺激になりましたね。
そして、M5Stackだけでなく、他のデバイスへの移植性も考えて作られているので、変数や引数の定義を見ても、とっても勉強になりますね。

では、何で M5Stack_JpgLoopAnime を組み合わせると高速になったのか。。。

JPEGデコードライブラリ TJpgDec はカスタマイズした方が断然高速だった

前回記事では、Arduino core for the ESP32 に同梱のJPEGデコードライブラリ TJpgDec をデフォルトで使いました。
ただ、今回の実験では、それを外側に出してカスタマイズした方が断然高速処理になることが分かったんです。

実は、 らびやん さんからアドバイスを受け、まずは、ESP32_ScreenShotReceiver ソースコードを参考にして、TJpgDec ライブラリを改変する挑戦をしました。
ESP32_ScreenShotReceiver ライブラリは、ブロック毎単位のWiFiでJPEGデータ受信して、マルチタスクでLCD描画している構造だと思います。
私の勝手な解釈だと、パソコン側のSenderアプリで送られるデータは、MotionJPEG (MJPEG) とは異なる方式を使っていて、1ブロック描画を終えると”JPG”というテキストデータ をアプリに送って次のデータを送信要求する方式なのだと思われました。

私もそれに習って、TJpgDec ライブラリを別途取り入れて、C++基準に合わせて変数を最適化したり、マルチタスク化したりしていると、明らかにスピードアップできたんです。
WiFi受信しながらLCDにマルチタスク並列処理で描画させると、240 x 176 pixel の画角で、15fps から 19fps まで速度アップできました。

ただ、私はブラウザとの通信ができる MotionJPEG (MJPEG) が捨て難く、それに沿った改造は私の頭では無理でした。
それをTwitterで何気につぶやいたら、らびやん さんから M5Stack_JpgLoopAnime ライブラリのマルチタスク化したJPEGデコードを試してみてはどうかというアドバイスを頂きました。
これは、JPEGデコードにWiFi通信が絡んでいないので、MotionJPEG (MJPEG) に組み込みやすいからです。

そして、実際試してみたら、ビックリ!!!
めちゃめちゃ高速じゃないですか!!!

そんでもって、M5Stack_JpgLoopAnime のソースコードを見てみると、JPEGデータをブロックごとに分けてデコードしながらLCDにマルチタスク並列処理で描画していることが分かります。
元々、TJpgDec ライブラリは、JPEGデータをブロックごとに分割してデコードしているので、それをうまく利用したと思われます。
C++でESP32用に最適化されてはいますが、それだけでこんなに大幅な速度アップができるとは驚きですね。
らびやん さんの脳ミソに感服です。

みなさんも是非ためしてみてください。

ところで、M5Stack_JpgLoopAnime のtjpgdClass.cppファイルのmultitask_begin関数にtask_outputというタスクがありますが、それは core 0 タスクでした。
私の M5Stack 側のコードでは、WiFi受信を core 0 で処理しているので、マルチコアの意味がないだろうと思って、task_outputをcore 1 に変えてみました。
しかし、そっちの方が速度が遅くなりました。

逆にWiFi受信をcore 1 にして、task_outputをcore 0 にしたりもしましたが、結局のところ一番安定して高速だったのが、task_outputがcore 0 で、WiFi受信も同じ core 0 だったのです。
これについては、この記事を書いた後、らびやん さんからTwitter上で回答いただきました。
ただ、私が勉強不足で未だ理解できずにいます。
やっぱりこのライブラリは高度過ぎました。。。

使ったもの

M5Stack

このブログではお馴染みの ESP32 を搭載した、技適取得済み全部入りモジュールです。
これを過去に分解して紹介した記事があるので、参照してみてください。

M5Stackを分解したり電源を入れてみて、いろいろ思ったこと

(追記)
M5Stack Basicは、この記事を書いた当時より格段にバージョンアップしております。
以下のスイッチサイエンスさんの公式サイトをご参照ください。
https://www.switch-science.com/collections/%E5%85%A8%E5%95%86%E5%93%81/products/9010

※M5Stack Gray(9軸IMU搭載)現在は販売終了しております

 

M5Camera

もう1年くらい持続してこれで遊んでいます。
これは、OmniVision 製イメージセンサ OV2640 を搭載し、ESP32-WROVER搭載のWiFi & Bluetoothマイコンモジュールです。
これも過去に分解した記事があるので、そちらも参照してみてください。

M5Camera をレビューしてみた。分解したり、Arduino IDE でスマホに映したりする実験

これはスイッチサイエンスウェブショップで販売しています。

https://www.switch-science.com/catalog/5207/

オプションバッテリー

後で述べていますが、これを使う場合はちょっと注意が必要かもしれません。
なぜなら、M5Stackのボトムと併用すると、バッテリーの寿命が低下するという情報があったからです。
M5Stack公式やスイッチサイエンスさんからはそういう情報が出ていないので、私自身は何とも言えません。
気になる方は、M5Stackのボトムを外して使用した方が良いかも知れません。

(※2021年11月時点では、バッテリー容量は750 mAhになっています)
M5Stack用電池モジュール

WiFi環境

できるだけ高速のWiFiルーターを使って下さい。
私の場合は、ホテル用ルーターを使いました。
以下の製品は最新バージョンのものです。

事前にM5StackやM5CameraがWiFiルーターに接続できるようにセットアップを済ませておいてください。

パソコンおよびUSBケーブル

USBケーブルはできるだけ良質で、太く短いものを使って下さい。
M5Camera は特に電力消費が大きいので、粗悪なUSBケーブルだとまともに動作しません。
私が使っている良質なUSBケーブルは以下の物です。

Arduino core for the ESP32のインストール

各バージョンは以下で動作確認しております。

Arduino IDE ver 1.8.13
Arduino core for the ESP32 ver 1.0.4

Arduino core for the ESP32 のインストール方法は以下の記事を参照してください。

Arduino core for the ESP32 のインストール方法

M5Stack公式ライブラリのインストール

ボタン操作の為だけに M5Stack公式ライブラリを使います。。
ver 0.3.0 で動作確認しています。

M5Stack公式ライブラリのインストールは以下の記事を参照してください。

M5Stack ライブラリインストール方法 ( Arduino IDE 用)

LovyanGFXライブラリのインストール

らびやん さん作成のLovyanGFXライブラリをArduino IDEにインストールします。
これは、M5StackのLCD(液晶ディスプレイ)に高速表示させるためのライブラリです。
ver 0.1.15 で動作確認しています。

インターネットに接続しておき、下図の様に、「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」を選択します。

すると、下図の様にライブラリマネージャが開くので、検索欄に「Lovyan」と入力して、LovyanGFXを表示させて、最新バージョンを選択し、「インストール」ボタンをクリックすればインストールできます。

インストールし終わったら、念のためArduino IDEを再起動した方が良いと思います。

M5Stack_JpgLoopAnime ライブラリのダウンロード

次に、同じく らびやん さん作成の M5Stack_JpgLoopAnime ライブラリをダウンロードします。
これはライブラリマネージャを使わず、ZIPファイルをダウンロードします。

まず、GitHubの以下のリンクを開きます。

https://github.com/lovyan03/M5Stack_JpgLoopAnime

そのサイトを開くと、下図のように表示されるので、「Code」のところをクリックすると、プルダウンメニューが表示されるので、「Download ZIP」をクリックするとZIPファイルがダウンロードされます。

GitHubがMicrosoftに買収される前は違う表示だったので、久々に見るとちょっと戸惑いますね。

では、次はM5CameraやM5Stackのスケッチ(プログラムソースコード)を紹介します。

コメント

  1. なかむら より:

    はじめまして。私はM5stackを楽しんでいる初心者です。
    プログラミングは苦手で、ほとんどはサンプルを少し弄る
    程度です。

    貴サイトの動画表示記事に興味があり、TimwerCameraFとM5stack(Basic)で
    チャレンジしています。
    ですが、ソースコードをarduino1.8.19にてコンパイルしているのですが
    下記のエラーになります。

    >exit status 1
    >’LGFX’ does not name a type

    エラー個所は
    >15:static LGFX lcd;
    です。

    ソースファイルと3つのヘッダファイルは同じフォルダに置いてます。

    何か原因※ありますでしょうか?。
    アドバイスを頂ければ幸いです。

    ※arduino2.0 IDEは、「ping timeout」でコンパイルが止まります。

    • mgo-tec mgo-tec より:

      なかむらさん

      記事をご覧いただき、ありがとうございます。

      初心者なのに、こんな難解なコードにチャレンジされたというのには、正直驚いています。

      今の私はESP32やM5Stackから離れて、まったく触っていませんので、かなり忘れてしまいました。
      ですから、あまり的確なアドバイスできないかも知れません。

      まず、TimwerCameraF とは、
      ESP32 PSRAM Timer Camera F (OV3660)
      のことでしょうか?
      ご存知かと思いますが、この記事はM5Camera(OV2640)を使っている為、OV3660で動くかどうかは私には分かりません。

      また、ご使用の環境が不明なことが多いので、
      Arduino core for the ESP32 のバージョンや、M5Stackライブラリ、LovyanGFXライブラリのバージョンはどれをお使いでしょうか?

      Arduino core for the ESP32は、1.0.4 で検証していますので、それを使って下さい。
      また、M5Stackライブラリのバージョンも同様に、0.3.0 を使って下さい。
      LovyanGFXライブラリも同様に 0.1.15 を使って下さい。

      ライブラリは最新バージョンでは動かない可能性が大きいです。

  2. なかむら より:

    丁寧なご回答をありがとうございます。
    説明不足で申し訳ありません。
    カメラは、ESP32 PSRAM Timer Camera F (OV3660)です。
    ご指摘の通りセンサーが異なるので、動作しなくても仕方ないです。
    ※ブラウザでは表示できていますが。

    ライブラリのバージョンは気にしていませんでした。

    ・M5Stackのライブラリは0.3.0でした。
    ・ボードマネージャ Arduino core for the ESP32
     1.0.4→これはちょっとわかりませんでした。
     
    ・LovyanLGFXのライブラリを1.1.12(最新)→0.1.15 に変更したところ
     先のエラーは消えました。
     が、新たなエラーになりました。

    >cannot declare ‘::main’ to be a global variable

    >16 static MainClass main;

    >C:\Users\chuhy\Documents\Arduino\TImerCameraF-viewer\TImerCameraF-viewer.ino: >At global scope:
    >TImerCameraF-viewer:16:18: error: cannot declare ‘::main’ to be a global >>>>variable static MainClass main;

    うーん、難しいですね。
    これ以上は自分の技量では追えそうにないので諦めます。
    お忙しい中、ありがとうございました。

    • mgo-tec mgo-tec より:

      なかむらさん

      以下の件、
      >・ボードマネージャ Arduino core for the ESP32
      >1.0.4→これはちょっとわかりませんでした。

      以下のサイトを参照してください。
      Arduino core ESP32 インストール方法

      Arduino IDE の環境設定で、「追加のボードマネージャのURL」という欄にURLを貼り付けて、「OK」をクリックします。
      そして、ボードマネージャの検索欄に「esp32」と入力すれば、「esp32 by Espressif Systems」という項目が見えます。
      その「バージョンを選択」で 1.0.4 を選択してインストールし直してみて下さい。
      うまくいかなかったら、今のバージョンを一度「削除」ボタンを押して削除してから、Arduino IDEを閉じて、再起動してから、1.0.4をインストールしてみてください。

  3. 通りすがりの尾和 より:

    同じ問題に遭遇したものですが、自己解決しました。
    新しいLovyanLGFXでは、
    #include
    こちらを加えると、上記のerrorが消えます。

    • mgo-tec mgo-tec より:

      通りすがりの尾和さん

      コメント投稿ありがとうございます。

      ただ、#include以降が消去されてしまいました。
      半角の<>があると、セキュリティ上、それ以降は消去されてしまいますので、全角にしていただけますでしょうか?

  4. 通りすがりの尾和(ぽこちゃ技術枠) より:

    #define LGFX_USE_V1
    #include <LovyanGFX.hpp>
    #include <LGFX_AUTODETECT.hpp>
    LGFX lcd;
    とすればよいかと思います

    • mgo-tec mgo-tec より:

      通りすがりの尾和さん

      再コメント、お手数おかけしました。
      全角の<>は当方で半角に修正してアップしました。

      LovyanGFXはしばらく使っていなかったので、大変参考になりました。
      ありがとうございま~す!
      m(_ _)m

タイトルとURLをコピーしました