demo_hq.mp4
SINTEL (Trailer)
Creative Commons Attribution 3.0
© copyright Blender Foundation | www.sintel.org
再生の為にデータ形式を改変しています。
動画ファイルを専用の形式 (gmv) へ変換したファイルを SD からストリーミング再生するアプリケーションです。
マルチコアを使用して DMA による描画と、音声再生を行っています。
旧形式である gcf + wav 再生可能です(但し PSRAM 非搭載機では音声再生制限あり)
依存するライブラリが動作して、SDカードを搭載している物。
- M5Stack Basic 2.6 以降
- M5Stack Gray
- M5Stack Core2
- M5Stack CoreS3
- TJpgDec Lovyan03 さんの改造板
Env | 説明 |
---|---|
release | 基本設定 |
release_DisplayModule | ディスプレイモジュール対応 |
release_SdUpdater | SD-Updater 対応 |
release_SdUpdater_DisplayModule | ディスプレイモジュールと SD-Updater 対応 |
Env | 説明 |
---|---|
S3_release | 基本設定 |
S3_release_DisplayModule | ディスプレイモジュール 対応 |
sample_003.zip をダウンロードして SD カードの /gcf へコピーしてください。
インストール方法などは各ウェブページを参照してください。
データはターミナル上で作成します。
動画データは FFmpeg で処理できる物であればフォーマットは問いません。
- 任意に作ったデータ作成用ディレクトリに動画データをコピーする
- 同ディレクトリに conv.sh と gmv.py をコピーする
- シェルスクリプトを次のように指定して実行する。
bash conv.sh move_file_path frame_rate [ jpeg_maxumu,_size (無指定時は 7168) ]
引数 | 必須? | 説明 |
---|---|---|
move_file_path | YES | 元となる動画 |
frame_rate | YES | 出力されるデータの FPS (1 - 30) |
jpeg_maximum_size | NO | JPEG 1枚あたりの最大ファイルサイズ( 1024 - 10240) 大きいと品質が維持されやすいがクラッシュする可能性が高くなる(既知の問題参照) |
- 動画ファイル名.gmv が出力される。
- gmv ファイルを SD カードの /gcf にコピーする。
例)
mkdir foo
cp bar.mp4 foo
cp script/conv.sh foo
cp script/gcf.py foo
cd foo
bash conv.sh bar.mp4 24
cp bar.gmv your_sd_card_path/gcf
- 動画から指定されたフレームレートでJPEG画像を出力する。
出力ディレクトリとして ./jpg+PID を作成します。これにより複数のターミナルで並行して変換できます。 - 出力された JPEG ファイルのサイズが、指定サイズを超えていたら収まるように再コンバートする。
- 動画から音声データを出力し、平滑化する。
- gmv.py で画像と音声を合成した専用ファイルを作成する。
ffmpeg -i $1 -r $2 -vf scale=320:-1,dejudder -qmin 1 -q 1 jpg$$/%06d.jpg
出力品質や、フィルター等、変更することでお好みのものにできます。元となる動画によって最適なパラメータは異なるので、FFmpeg の情報を参考にして行ってください。
-
wav データの品質 (8KHz 符号なし 8bit mono)
処理負荷軽減の為、音声データの品質は下げています。
スクリプトを編集して品質を上げることは可能ですが、処理負荷によってクラッシュする場合が生じるかもしれません。(既知の問題参照) -
画像サイズとフレームレート
動画から JPEG 化する際には幅 320p 高さはアスペクト比を維持した値で出力します。
現在の所 320 x 240 で 24 FPS 程度、 320 x 180 で 30 FPS 程度の再生が可能です。
画像サイズを変更したい場合は conv.sh の FFmpeg へ与えているパラメータを変更してください。 (scale=)
実行中にリセットがかかった場合 Serial モニタに assert で引っ掛かった旨が表示されているはずです。
原因は描画が所定の時間内に終わらず、 SD と Lcd のバスが衝突した事による物です。
動画の特定箇所で発生する場合はデータ側を修正することで回避することができます。
またごく稀に SD からの読み込みに時間がかかる時があり、それによって上記と同様にリセットがかかる場合があります。
これは原因がわかっていません。 SD カードの相性かフォーマット状態に問題があるかもしれません。
OS utilities should not be used for formatting SD cards. FAT16/FAT32 has lots of options for file system layout. In addition to the cluster size there are options for aligning file structures.
The SD Association has a standard layout for each size SD card. Cards are designed to optimize performance for the standard layout. For example, flash chip boundaries are aligned with file system structures.
My SdFormatter example produces the standard layout. On a PC use the SD Association Formatter.
You should not be getting errors due to the format. The correct format will only enhance performance, not reduce errors.
I rarely see the type errors you are having. Most users either have solid errors or no errors.
I have seen this type error when another SPI device interferes with the SD or when there are noisy or poor SPI signals.
[意訳]
SD カードのフォーマットに、各 OS のユーティリティを使わないでください。 FAT16/32 のファイルシステムレイアウトは多岐にわたっており、様々なオプションが存在します。
SD アソシエーションによって各サイズの SD カードに対して標準的なレイアウトが制定されています。カードは標準的なレイアウトに対して最適化されています。例えばフラッシュチップの境界はファイルシステムの構造に合わせて整列されます。
SD Formater サンプル、または SD Association Formatter を使用することで標準レイアウトが生成されます。
(以下略)
- 再生フレームレートを減らす
bash conv.sh video.mp4 30 # 30 FPS
bash conv.sh video.mp4 24 # Reduce to 24
- JPEG ファイルサイズを小さくする
bash conv.sh video.mp4 30 # 7168 as default
bash conv.sh video.mp4 30 5120 # Reduce to 5120
- 画像サイズを小さくする
conv.sh
# ...
#ffmpeg -i $1 -r $2 -vf scale=320:-1,dejudder -qmin 1 -q 1 jpg$$/%06d.jpg # 320 x n pixel
ffmpeg -i $1 -r $2 -vf scale=240:-1,dejudder -qmin 1 -q 1 jpg$$/%06d.jpg # 240 x n pixel
# ...
- マルチコア再生をシングルコア再生に切り替える
main.cpp の該当箇所をシングルコア使用の物に切り替えます。
再生速度は落ちますが、バス競合を確実に避けるようになります。
src/main.cpp
static void loopRender()
{
// ...
{
ScopedProfile(drawCycle);
//mainClass.drawJpg(buffers[(bufferIndex - 1 + NUMBER_OF_BUFFERS) % NUMBER_OF_BUFFERS], JPG_BUFFER_SIZE); // Process on multiple cores
mainClass.drawJpg(buffers[(bufferIndex - 1 + NUMBER_OF_BUFFERS) % NUMBER_OF_BUFFERS], JPG_BUFFER_SIZE, false); // Process on single core. Try it, if If assert occurs on xQueueSend call. (However, FPS will be reduced)
}
// ...
}
ボタン | 説明 |
---|---|
Aボタンクリック | 前のファイルへ |
Bボタンクリック | 再生開始 |
Cボタンクリック | 次のファイルへ |
Aボタン長押し | 再生種別変更 |
Cボタン長押し | 再生種別変更 |
ボタン(Basic,Gray,Core2) | 画面タッチ(CoreS3) | 説明 |
---|---|---|
Aボタン押下 | 画面左 1/3 | 音量下げる |
Bボタンクリック | 画面真ん中 1/3 | 再生停止してメニューへ |
Cボタン押下 | 画面右 1/3 | 音量上げる |
現在の所、旧形式(gcf + wav) も再生できますが、 変換用 Pyhton スクリプト gcf_to_gmv.py と、カレントディレクトリのファイル群の変換の為のシェルスクリプト convert_gcf_to_gmv.sh を用意しました。
# gcf_dir has gcf + wav files
cp script/gcf_to_gmv.py gcf_dir
cp script/convert_gcf_to_gmv.sh gcf_dir
cd gcf_dir
bash convert_gcf_to_gmv.sh
cp *.gmv your_sd_card_path/gcf
SD カードのファイルのオープンとシークにはそれなりの時間がかかります。
1 枚ずつの JPEG ファイルを逐次開いて表示する場合、その速度がボトルネックとなるのです。
そこで物理メディア(フロッピーディスク等)、光学メディア(CD 等) で有効だった、一つにまとめた大きなファイルをシーケンシャルに読み込み続ける手法を採用し、カードアクセスの時間を短縮しています。
当初は unzipLIB で、無圧縮 ZIP ファイルから読み込んでいたのですが、内部でシークが 1 回行われる為、シーク無しにシーケンシャルに読み込むことを前提としたオリジナルのファイル形式を策定し、それを利用する事でシークを無くすことができました。
1 画像あたりの読み込み処理時間は逐次オープンだと数十 ms だったものが 数 ms となっています。
元々は ZIP ファイルを扱いたくて unzipLIB を色々試していました。使い方の習得を兼ねて画像ファイルをまとめた物をパラパラ漫画のように再生しようと思ったのが始まりです。
(結局 unzipLIB を使わない形になってしまったわけですが (´・ω・`) )
これって MotionJPEG とは違うの?
定義によればこれも MJPEG と呼んで差し支えないようです。しかし MJPEG はファイルフォーマットとしての統一形式はないので、このアプリケーションはあくまで gmv 形式再生機です。
- src/gob_jpg_sprite.hpp
- src/gob_jpg_sprite.cpp
画面ではなく LGFX_Sprite にマルチコアを使用して JPEG を出力するためのクラスです。
色々試行錯誤していた時に作ったのですが、結局使用しない事になりました。
もったいないので同梱します。
先人としてパラパラ再生をされている方々。お二人に刺激を受けて当アプリケーションは誕生しました。
- 6jiro さん
https://smile-dental-clinic.info/wordpress/?p=10904 - PocketGriffon さん
https://pocketgriffon.hatenablog.com/entry/2023/02/27/103329
TJepgDec の作者
当アプリケーションの母体となった物です。TJpegDec を使用して画面に DMA 描画するロジックを拝借しました。
技術的なアドバイスもたくさんいただきました。
M5Unified, M5GFX の作者でもあります。