M5StickCにM5Cameraからの動画を表示する

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">M5camera の画像を、Lovyangfx 使ってM5stickC PLUSに表示。<br>すごい早い<a href="https://twitter.com/hashtag/M5stickC?src=hash&amp;ref_src=twsrc%5Etfw">#M5stickC</a> <a href="https://twitter.com/hashtag/M5Camera?src=hash&amp;ref_src=twsrc%5Etfw">#M5Camera</a> <a href="https://t.co/whDOTgj0ae">pic.twitter.com/whDOTgj0ae</a></p>&mdash; sull (@sullblue) <a href="https://twitter.com/sullblue/status/1338800202820415488?ref_src=twsrc%5Etfw">December 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#はじめに
「__LovyanGFXグラフィックライブラリ__は描画がめちゃ早い」
といううわさを聞いたので、M5StickC PLUSで使ってみました。
M5Cameraの画像を動画で表示しています。
#コード
上の動画では画面のサイズが合ってませんが、以下のコードではM5StickC PLUSを横にした画面にちょうど良くなるよう変更してあります。

```
#include <WiFi.h>
#include <HTTPClient.h>

#define  LGFX_AUTODETECT // (1)
#include <LovyanGFX.hpp>
#include <M5StickCPlus.h>

// 接続先のSSIDとパスワード
const char ssid[] = "YOURM5CAMERASSID";
const char passwd[] = "YOURCAMERAPASSWORD";

HTTPClient http;
int httpCode;
String response;
uint8_t buff[64 * 1024] = { 0 };// カメラの画像を受け取る用のバッファ。十分な大きさが必要

static LGFX lcd;


void setup() {
    Serial.begin(115200);

    lcd.init();
    lcd.setRotation(1);
    lcd.setBrightness(128);
    lcd.fillScreen(TFT_BLACK);

    // WiFi つなぐ
    connectWiFi();

    // カメラのフレームサイズを設定する
    cameraInit();  // (2)

    // カメラの準備ができるのを待つ。数字は適当です
    delay(1000); 
}

// メインループ
void loop() {

    if ( WiFi.status() != WL_CONNECTED ) {
        // WiFi切れたらつなぎなおす
         connectWiFi();
         cameraInit();
         delay(1000);
    } else {
        // 画像を受け取って表示する
         draw_captureimage();
    }
    // このdelay(1)は必要
    delay(1);
}

// WiFiに繋ぐ処理
void connectWiFi()
{
    WiFi.begin(ssid, passwd);
    Serial.print("WiFi connecting..");
    while(WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(100);
    }
    Serial.print(" connected. ");
    Serial.println(WiFi.localIP());
}

// M5Cameraからの画像を受け取って表示する処理
void draw_captureimage(){
    http.begin("http://192.168.4.1/capture"); // GET
    httpCode = http.GET();
    if (httpCode > 0) {
        int len = http.getSize();
        Serial.printf("[HTTP] size: %d\n", len);
        if (len <= 0) {
          Serial.printf("[HTTP] Unknow content size: %d\n", len);
        } else {
          // create buffer for read
          //uint8_t buff[len] = { 0 };
          // get tcp stream
          WiFiClient * stream = http.getStreamPtr();
          Serial.printf("[HTTP] strm ptr: %x\n", stream);
          // read all data from server
          uint8_t* p = buff;
          int l = len;
          while (http.connected() && (l > 0 || len == -1)) {
            // get available data size
            size_t size = stream->available();
            if (size) {
              int s = ((size > sizeof(buff)) ? sizeof(buff) : size);
              int c = stream->readBytes(p, s);
              p += c;
              Serial.printf("[HTTP] read: %d\n", c);
              if (l > 0) {
                l -= c;
              }
            }
          }
        }
        lcd.drawJpg(buff,sizeof(buff)); // 画像の描画 (3)
    } else {
        Serial.println("Error on HTTP request");
        Serial.println(httpCode);
    }
    http.end();
    Serial.println();
    Serial.print("[HTTP] connection closed.\n");
}

// カメラのフレームサイズを設定 (2)
void cameraInit(){
    // 画像サイズをQVGAに設定
    // これがM5StickC PLUSの画面にちょうどいいサイズ感
    http.begin("http://192.168.4.1/control?var=framesize&val=3");
    httpCode = http.GET();
    if (httpCode > 0) {
        Serial.println("status");
        response = http.getString();
        Serial.println(httpCode);
        Serial.println(response);
    } else {
        Serial.println("Error on HTTP request");
        Serial.println(httpCode);
    }
    http.end();
}
```
#ちょっとだけ説明
(1)#define  LGFX_AUTODETECT
LovyanGFXがLCDのサイズを自動的に判別するという定義。
現在は次の定義でもいけるそうです。(LovyanGFX 0.3.4情報)
`#define  LGFX_M5STICK_C`

(2)カメラのフレームサイズをQVGAに設定
もっと大きなサイズでも取得はできますが、LCDに収まらないので一部しか見れません。
大きな画像を受け取りたいときはバッファサイズも変更したほうがいいと思います。

(3)lcd.drawJpg(buff,sizeof(buff));
__これを使うためにLovyanGFXを導入したのだ__

#実行結果
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">設定変えてみた。こっちのほうがいいっぽいな <a href="https://t.co/9nfvs4HIFC">pic.twitter.com/9nfvs4HIFC</a></p>&mdash; sull (@sullblue) <a href="https://twitter.com/sullblue/status/1338839427661975552?ref_src=twsrc%5Etfw">December 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#おわりに
上にも書きましたが、LovyanGFXを使うと決めたのは__drawJpg()__が使えるようになるからです。
M5StickCのライブラリにはdrawJpg()がないんです！
M5Stackにはあるのに！
>(追記)
GitHubのソースを追ってみたのですが、どうもM5StickC PLUSはソースにはdrawJpg()あるけど使うことはできないという状況みたいです。謎。

M5Cameraの画像はjpeg形式で送られてくるわけで、それが描画できないというのはけっこう問題でした。

それと、先人のブログなどを拝見していると皆さん__画像表示の遅さ__には苦労しておられるようで...
それがLovyanGFXの登場で圧倒的に早くなったわけですから、これは是非やってみたいと思った次第でした。

先人の皆様と、ライブラリ作者の[@lovyan03](https://twitter.com/lovyan03)さんに深く感謝です。

###参考文献
[github - LovyanGFX](https://github.com/lovyan03/LovyanGFX)
[Androidのカメラ映像をMotionJPEGで配信する](https://qiita.com/Yukio-Ichikawa/items/cf93c4851f871003a0f2)
[ESP32でビットマップ画像ファイルを生成し、ブラウザに連続送信してMotion JPEGならぬMotion BMP動画ストリーミングする実験](https://www.mgo-tec.com/blog-entry-esp32-mjpeg-bmp.html)

#おまけ
IMU × LovyanGFX
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">理解が深まってきた<a href="https://twitter.com/hashtag/M5stickC?src=hash&amp;ref_src=twsrc%5Etfw">#M5stickC</a> <a href="https://t.co/nKXoYCkwcC">pic.twitter.com/nKXoYCkwcC</a></p>&mdash; sull (@sullblue) <a href="https://twitter.com/sullblue/status/1337933545956728832?ref_src=twsrc%5Etfw">December 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>