Jetson NanoからWebカメラの映像をMJPEGでFlutterアプリに表示させる方法
はじめに
Jetson NanoにつないだWebカメラからMotion JPEG(MJPEG)でストリーミング配信を行い、Flutterのアプリケーションで表示させる方法について述べる。
MJPEGとは下記の通り。
MJPEGとは動画を構成する1枚1枚のJPEG画像をパラパラ漫画のように連続させ動画データとする方式。
特徴として、動きが激しいケースで対応可能で、1フレームを鮮明に取り出すことができる。 - ビデオ圧縮形式とは
Jetson Nano側の設定
こちらの記事を参考にした。その記事を参考にしながら補足説明を行う。
まずMJPEGをHTTPでストリーミングするオープンソース「mjpg-streamer」をJetson Nanoに導入する。
インストール方法はこちらのwikiを参考にする。
# Update & Install Tools
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install build-essential git imagemagick libv4l-dev libjpeg-dev cmake -y
# Clone Repo in /tmp
cd /tmp
git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
# Make
make
sudo make install
アプリケーションの起動は下記のコマンドを利用する。ただしインストール方法はRaspberry Piを想定したものであることに注意する。
# Run
/usr/local/bin/mjpg_streamer -i "input_uvc.so -r 1280x720 -d /dev/video0 -f 30" -o "output_http.so -p 8080 -w /usr/local/share/mjpg-streamer/www"
上記のwebサーバーの起動部分は下記のようなスクリプトをつくって、それを実行しても良い。例えばファイル名をrun_mjpg-streamer.shとする。
#!/bin/sh
input=/usr/local/lib/mjpg-streamer/input_uvc.so
output=/usr/local/lib/mjpg-streamer/output_http.so
port=8080
device=/dev/video0
webroot=/usr/local/share/mjpg-streamer/www
mjpg_streamer -i "$input -d $device -r 640x480 -f 1" -o "$output -p $port -w $webroot"
下記は「shebang」と呼ばれシェルスクリプトを使う際のおまじない。
スクリプトを読み込むインタープリタを指定する事ができ、実行時に shやbashを指定する必要がなくなる。
#!/bin/sh
つまりrun_mjpg-streamer.shを実行するとき、本来は
/bin/sh ./run_mjpg-streamer.sh
とする必要があったが、下記のようにするだけシェルスクリプトを実行することができる。
./run_mjpg-streamer.sh
実行時にアクセス権限がないと言われた場合、そのファイルがあるディレクトリで、下記を実行する。その後、もう一度実行すると良い。
chmod 775 run_mjpg-streamer.sh
実行したあと、下記のアドレスにアクセスするとWebカメラからの動画を確認することができる。ただし、今回の場合指定しているポートは8080である。
http://【Jetson NanoのIPアドレス】:【指定したポート】/
IPアドレスはターミナルから、下記を入力してwlan0のinet部分表示されるIPアドレスを利用する。
ifconfig
そしてURLにアクセスすると下記のような画面が現れれば成功。
Flutterのコード
Flutterアプリ上でMJPEGを利用するにはライブラリ「flutter_mjpeg」を使用すると良い。ライブラリはターミナルで使用するアプリのディレクトリに移動し、下記のようにコマンド実行すると適用される。
flutter pub add flutter_mjpeg
flutter pub get
まずは「Example」にあるサンプルコードを動かしてみる。
サンプルコードは下記の通り。
example/lib/main.dart
```dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_mjpeg/flutter_mjpeg.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends HookWidget {
@override
Widget build(BuildContext context) {
final isRunning = useState(true);
return Scaffold(
appBar: AppBar(
title: Text('Flutter Demo Home Page'),
),
body: Column(
children: <Widget>[
Expanded(
child: Center(
child: Mjpeg(
isLive: isRunning.value,
error: (context, error, stack) {
print(error);
print(stack);
return Text(error.toString(), style: TextStyle(color: Colors.red));
},
stream:
'http://91.133.85.170:8090/cgi-bin/faststream.jpg?stream=half&fps=15&rand=COUNTER', //'http://192.168.1.37:8081',
),
),
),
Row(
children: <Widget>[
RaisedButton(
onPressed: () {
isRunning.value = !isRunning.value;
},
child: Text('Toggle'),
),
RaisedButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(),
)));
},
child: Text('Push new route'),
),
],
),
],
),
);
}
}
```
サンプルコードでは下記のようにURLを指定している。
stream: 'http://91.133.85.170:8090/cgi-bin/faststream.jpg?stream=half&fps=15&rand=COUNTER', //'http://192.168.1.37:8081',
こちらをmjpg-streamerで「videoLAN」で表示されているURLに置き換えるとアプリ上で映像が表示される。
シミュレーター上では下記のようになる。
おわりに
割と簡単にJetson NanoにつないだWebカメラの映像をFlutterアプリ上で表示することができた。他のことにも応用できそう。
Discussion