├── .gitignore ├── led-movie-player ├── sample ├── ポプテピピック_OP.mp3 ├── ポプテピピック_OP.mp4 ├── NEW-FUKUSHIMA ZONE.mp3 └── NEW-FUKUSHIMA ZONE.mp4 ├── .gitmodules ├── Makefile ├── LICENSE.txt ├── led-movie-convert ├── README.md └── led-movie-player.cc /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *~ 4 | *.so 5 | -------------------------------------------------------------------------------- /led-movie-player: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsukumijima/LED-Movie-Player/master/led-movie-player -------------------------------------------------------------------------------- /sample/ポプテピピック_OP.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsukumijima/LED-Movie-Player/master/sample/ポプテピピック_OP.mp3 -------------------------------------------------------------------------------- /sample/ポプテピピック_OP.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsukumijima/LED-Movie-Player/master/sample/ポプテピピック_OP.mp4 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "matrix"] 2 | path = matrix 3 | url = https://github.com/hzeller/rpi-rgb-led-matrix.git 4 | -------------------------------------------------------------------------------- /sample/NEW-FUKUSHIMA ZONE.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsukumijima/LED-Movie-Player/master/sample/NEW-FUKUSHIMA ZONE.mp3 -------------------------------------------------------------------------------- /sample/NEW-FUKUSHIMA ZONE.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsukumijima/LED-Movie-Player/master/sample/NEW-FUKUSHIMA ZONE.mp4 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ 2 | 3 | OBJS=led-movie-player.o 4 | TARGET=led-movie-player 5 | 6 | CXXFLAGS=-std=c++11 7 | RGB_INCDIR=matrix/include 8 | RGB_LIBDIR=matrix/lib 9 | RGB_LIBRARY_NAME=rgbmatrix 10 | RGB_LIBRARY=$(RGB_LIBDIR)/lib$(RGB_LIBRARY_NAME).a 11 | LDFLAGS+=-L$(RGB_LIBDIR) -l$(RGB_LIBRARY_NAME) -lrt -lm -lpthread -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_videoio -lSDL -lSDL_mixer 12 | 13 | all: $(TARGET) 14 | 15 | $(RGB_LIBRARY): 16 | $(MAKE) -C $(RGB_LIBDIR) 17 | 18 | $(TARGET): $(OBJS) $(RGB_LIBRARY) 19 | $(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDFLAGS) 20 | 21 | %.o : %.cc 22 | $(CXX) -I$(RGB_INCDIR) $(CXXFLAGS) -c -o $@ $< 23 | 24 | install: 25 | cp led-movie-convert /usr/local/bin/led-movie-convert 26 | cp $(TARGET) /usr/local/bin/$(TARGET) 27 | 28 | clean: 29 | rm -f $(OBJECTS) $(TARGET) 30 | $(MAKE) clean 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2020 tsukumi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /led-movie-convert: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # エンコード後のファイルを置くフォルダ 4 | path="/home/pi/movieplayer/" 5 | # バージョン 6 | version="2.2" 7 | 8 | if [ $# -eq 5 ]; then 9 | # 動画の幅 10 | width=$5 11 | # 動画の高さ 12 | height=$6 13 | else 14 | # 動画の幅 15 | width=192 16 | # 動画の高さ 17 | height=108 18 | fi 19 | 20 | mkdir -p ${path} 21 | 22 | if [ $# -ne 4 -a $# -ne 6 ]; then 23 | echo "" 1>&2 24 | echo "---------------------------------------------------" 1>&2 25 | echo " Error: Argument is missing or too many." 1>&2 26 | echo " Usage: Download :" 1>&2 27 | echo " 1. led-movie-convert [Download URL] download auto false" 1>&2 28 | echo " 2. led-movie-convert [Download URL] download auto true" 1>&2 29 | echo " 3. led-movie-convert [Download URL] download \"[File name (no extension)]\" false" 1>&2 30 | echo " 4. led-movie-convert [Download URL] download \"[File name (no extension)]\" true" 1>&2 31 | echo " 5. led-movie-convert [Download URL] download \"[File name (no extension)]\" false" 1>&2 32 | echo " [Movie width] [Movie height]" 1>&2 33 | echo " 6. led-movie-convert [Download URL] download \"[File name (no extension)]\" true" 1>&2 34 | echo " [Movie width] [Movie height]" 1>&2 35 | echo " Localfile :" 1>&2 36 | echo " 1. led-movie-convert [Localfile path] file auto false" 1>&2 37 | echo " 2. led-movie-convert [Localfile path] file auto true" 1>&2 38 | echo " 3. led-movie-convert [Localfile path] file \"[File name (no extension)]\" false" 1>&2 39 | echo " 4. led-movie-convert [Localfile path] file \"[File name (no extension)]\" true" 1>&2 40 | echo " 5. led-movie-convert [Localfile path] file \"[File name (no extension)]\" false" 1>&2 41 | echo " [Movie width] [Movie height]" 1>&2 42 | echo " 6. led-movie-convert [Localfile path] file \"[File name (no extension)]\" true" 1>&2 43 | echo " [Movie width] [Movie height]" 1>&2 44 | echo "" 1>&2 45 | echo " Please Retry... m(__)m" 1>&2 46 | echo "---------------------------------------------------" 1>&2 47 | echo "" 1>&2 48 | exit 1 49 | fi 50 | 51 | echo "" 52 | echo "---------------------------------------------------" 53 | echo " LED-Movie-Convert v"${version} 54 | echo "---------------------------------------------------" 55 | 56 | if [ "$2" = "download" ]; then 57 | 58 | echo " Downloading..." 59 | echo "" 60 | 61 | if [ "$3" = "auto" ]; then 62 | filename="${path}$(youtube-dl --get-title $1)" 63 | else 64 | filename=${path}$3 65 | fi 66 | 67 | youtube-dl -c -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/" -o "${filename}_orig.mp4" $1 68 | 69 | echo "" 70 | 71 | elif [ "$2" = "file" ]; then 72 | 73 | if [ "$3" = "auto" ]; then 74 | replace=$(echo "$1" | sed 's/\.[^\.]*$//') 75 | filename=$1 76 | filename_=${path}$(basename "${replace}") 77 | else 78 | filename=$1 79 | filename_=${path}$3 80 | fi 81 | 82 | fi 83 | 84 | if [ "$4" = "true" ]; then 85 | contrast=",eq=saturation=1.4:contrast=1.5:brightness=-0.2" 86 | else 87 | contrast="" 88 | fi 89 | 90 | echo " Filename: "${filename} 91 | echo " Width : "${width} 92 | echo " Height : "${height} 93 | echo "---------------------------------------------------" 94 | echo " Converting..." 95 | echo "" 96 | 97 | if [ "$2" = "download" ]; then 98 | 99 | ffmpeg -y -i "${filename}_orig.mp4" -vcodec libx264 -vf scale=${width}:${height}${contrast} "${filename}.mp4" 100 | echo "" 101 | ffmpeg -y -i "${filename}_orig.mp4" -vn -af dynaudnorm -ac 2 -ar 44100 -ab 128k "${filename}.mp3" 102 | rm -r "${filename}_orig.mp4" 103 | 104 | elif [ "$2" = "file" ]; then 105 | 106 | ffmpeg -y -i "${filename}" -vcodec libx264 -vf scale=${width}:${height}${contrast} "${filename_}.mp4" 107 | echo "" 108 | ffmpeg -y -i "${filename}" -vn -af dynaudnorm -ac 2 -ar 44100 -ab 128k "${filename_}.mp3" 109 | 110 | fi 111 | 112 | echo "" 113 | echo "---------------------------------------------------" 114 | echo " Convert: " 115 | if [ "$2" = "download" ]; then 116 | echo " ${filename}.mp4" 117 | echo " ${filename}.mp3" 118 | elif [ "$2" = "file" ]; then 119 | echo " ${filename_}.mp4" 120 | echo " ${filename_}.mp3" 121 | fi 122 | echo "---------------------------------------------------" 123 | echo "" 124 | 125 | exit 0 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # LED-Movie-Player 3 | 4 | 動画・音声を読み込んで LED マトリクスパネル上で再生させるラズパイ用ソフト 5 | ( https://qiita.com/cstoku/items/eb17d111225d3e35ec61 の記事上のコードより改造)です。 6 | 7 | 必要なものや配線等は [こちら](https://blog.tsukumijima.net/article/ledmatrix-movie/) の記事も参考にしてください。 8 | 9 | ## 同梱物 10 | 11 | - led-movie-player … Raspberry Pi 3 B+ 上でビルドした実行ファイル 12 | - 基本的に Linux では実行ファイルに拡張子が付きません 13 | - Raspberry Pi 3 B+ にてビルドしています 14 | - 他の機種では動かないかもしれません・自ビルドする事を推奨します(後述) 15 | - led-movie-player.cc … ソース( C++ )ファイル 16 | - 表示・再生部分のコードを前述の記事よりお借りしています 17 | - led-movie-convert … YouTube 等の動画やラズパイ上の動画を変換して LED-Movie-Player で再生出来る形式にするソフト 18 | - 中身はバッチファイルです(後述) 19 | - Makefile … ビルド手順等を記述したスクリプトファイル 20 | - README.md … このファイル 21 | - sample/ … LEDで流せるサイズにエンコードしたサンプルの mp4 と mp3 を入れてあります 22 | - 再生させる場合は一式 /home/pi/movieplayer/ にコピーして下さい 23 | - matrix/ … [rpi-rgb-lex-matrix](https://github.com/hzeller/rpi-rgb-led-matrix) を submodule として使っています 24 | 25 | ## ビルド手順 26 | 27 | 一応ビルド済みのファイルも同梱していますが、出来るだけビルドすることを推奨します 28 | 29 | 1. 予め必要なパッケージ(ライブラリ)をインストールしておきましょう 30 | - `sudo apt update -y && sudo apt upgrade -y` 31 | - `sudo apt install -y python3 python3-pip ffmpeg gcc g++ make libopencv-dev libsdl1.2-dev libsdl2-dev libsdl-mixer1.2-dev libsdl2-mixer-dev` 32 | - `sudo pip3 install youtube-dl` 33 | 2. led-movie-player ディレクトリに移動したあと、 34 | - `git submodule init` 35 | - `git submodule update` 36 | - と実行すると submodule がダウンロードされるので、正常にビルドできるようになるはずです。 37 | 3. make でビルドします 38 | - `make` 39 | - ビルドに失敗する場合、ライブラリがうまくインストール出来ていない可能性があります 40 | 4. make install でパスの通った場所にインストールします 41 | - `sudo make install` 42 | - ちゃんと sudo をつけましょう 43 | 5. その他、デフォルトではラズパイの bcm2835 サウンドカードを無効化する必要があります(ハードウェアパルスの生成に必要なため) 44 | - そのため、別途 USB サウンドカードを購入し、USB サウンドカードで再生できる(ラズパイ内蔵サウンドカードを使わない)状態にする必要があります 45 | - ハードウェアパルスを生成せずソフトウェアパルスで再生する事も可能ですが、ちらつきが発生するため非推奨です 46 | - ハードウェアパルスを無効化して再生させたい場合は、led-movie-player.cc 中の options.disable_hardware_pulsing = false; を options.disable_hardware_pulsing = true; に書き換え、もう一度ビルドしてください 47 | - 詳細な手順は [こちら](https://blog.tsukumijima.net/article/ledmatrix-movie/#toc11) の項目に記載してあります、参考にしてください 48 | 49 | ## 使い方 50 | 51 | 1. 動画は最大 192 × 108 までにリサイズした .mp4 形式、音声はサンプリングレート 44100kHz にした .mp3 形式にし、同じファイル名で /home/pi/movieplayer/ に保存します 52 | - LED-Movie-Convert を使うと、動画・音声の変換を自動化できます 53 | - /home/pi/movieplayer/ 以外に置くことも可能ですが、その場合は led-movie-player.cc ソース内の記述を変更してください 54 | 2. sudo led-movie-player "[ 拡張子なしファイル名 ]" と入力して実行すると、再生できます 55 | - 拡張子なしファイル名は、予め /home/pi/movieplayer/ に置いてあるファイルのものにしてください 56 | - 例えば /home/pi/movieplayer/ に example.mp4 と example.mp3 を置いた場合、[ 拡張子なしファイル名 ] には "example" を入れます 57 | - ファイル名にスペースが含まれる場合は、"example video" のように必ず "" で囲うようにしてください 58 | - sudo をつけないとエラーになります、必ず sudo をつけて root で実行してください 59 | - 最後のコマンド以外はデフォルトで 64 × 64 パネルを 2 個直列に接続している事を想定して再生します 60 | - 解像度が異なるパネルの場合は、led-movie-player.cc ソース内の記述( 155 行目あたり)を変更してください 61 | - sudo led-movie-player "[ 拡張子なしファイル名 ]" 0 と入力して実行すると、無限ループで再生します 62 | - sudo led-movie-player "[ 拡張子なしファイル名 ]" [ ループ回数 ] と入力して実行すると、引数に記載された回数だけ有限ループで再生します 63 | - sudo led-movie-player "[ 拡張子なしファイル名 ]" [ ループ回数 ] [ LED パネルの縦幅 ] [ LED パネルの横幅 ] [ LED パネルの直列接続数 ] [ LED パネルの並列接続数 ] 64 | と入力して実行すると、引数に記載されたパラメータで再生を実行します 65 | 3. Ctrl+C を押すと中断できます 66 | 67 | ## 使用例 68 | - 基本:sudo led-movie-player "example" 69 | - 無限ループ:sudo led-movie-player "example" 0 70 | - 有限ループ:sudo led-movie-player "example" 15 71 | - 引数を全て指定:sudo led-movie-player "example" 1 64 64 2 1 72 | 73 | ## 注意 74 | - 64 × 64 のパネルを 2 個直列につないだ LED パネルを想定しています 75 | - 他の解像度のパネルでは動かないかもしれません 76 | - 動作確認は Raspberry Pi 3 B+ 上の Raspbian で行っています 77 | - もしかすると、他のラズパイではそのままのコードでは動かない、という事があるかもしれません 78 | - コマンドラインから実行します( GUI はありません) 79 | - ラズパイ自体が非力なため、GUI があるとかえって描画が重くなります 80 | - ろくに検証もしていない自分用ソフトです 他の環境で動くかはかなり微妙… 81 | - ソースに変更を加えた場合、当然ですが再度ビルドしないと変更は反映されません 82 | - たまに Ctrl+C を押しても動画が流れ続ける場合があります(プロセスが裏で動きっぱなしになる) 83 | - その場合は、`ps aux | grep "led-movie-player.*" | grep -v grep | awk '{ print "sudo kill -9", $2 }' | sh` と実行すると LED-Movie-Player を強制終了できます 84 | 85 | ## 動画・音声のエンコード 86 | 87 | 前述の通り、LED パネルで再生させる動画や音声は、予め LED-Movie-Player で再生できる形式に変換する必要があります。 88 | 89 | - 動画 90 | - .mp4 形式 91 | - 最大でも 192 × 108 にリサイズする 92 | - 720p とかの動画をそのまま突っ込むと重すぎてスロー再生状態になります 93 | - 160 × 90 の方が音ズレしません 94 | - 192 × 108 はギリギリです 95 | - 音声は mp3 から再生するのであってもなくても可 96 | - 音声 97 | - .mp3 形式 98 | - ビットレートを128kbpsにする 99 | - 192kbps とかでもいけるかもしれませんが一応 100 | - サンプルレートを必ず44100kHzにする 101 | - 48000kHz だと音がバグる… 102 | 103 | LED-Movie-Convert を利用して、YouTube 等の動画やラズパイ上にある動画を自動で変換させることができます。 104 | 出来るだけこちらを利用する事をお勧めします(後述) 105 | 106 | 手動でエンコードする場合、ffmpeg で予め変換しておきましょう( Windows でも動くので、PC でエンコードしてラズパイに移すのもありです) 107 | 108 | 動画のエンコードコマンド例: ffmpeg -i "Movie.mp4" -vf scale=192:108 "Movie-led.mp4" 109 | 音声のエンコードコマンド例: ffmpeg -i "Movie.mp3" -vn -af dynaudnorm -ac 2 -ar 44100 -ab 128k "Movie-led.mp3" 110 | 111 | 変換が終わったら、変換後のファイルをラズパイの /home/pi/movieplayer/ 以下にコピーしてください。 112 | 前述の通り、led-movie-player.cc ソース内の記述を変更し、フォルダを変更することも可能です 113 | 114 | ## LED-Movie-Convert 115 | 116 | ### 注意 117 | 118 | - バッチファイルです (パスの通った場所に置けばコマンド同様に実行できます) 119 | - sudo make installする際についででパスの通った場所にインストールされます 120 | - ラズパイのスペックが低い関係でエンコードに時間がかかります、気長に待ちましょう 121 | - エンコード中は負荷が非常に高くなるので、エンコード中に LED-Movie-Player で再生させようとするとスロー再生になってしまう事があります 122 | - (ラズパイの性能が低いため LED パネルへの表示処理が実際の再生スピードに追い付かない) 123 | 124 | ### 使い方 125 | - 第一引数… ソース元を指定します ( URL or ファイルパス) 126 | - 第二引数… ソースの種類を選択します ( URL からダウンロードするなら download 、ファイルパスからなら file ) 127 | - 第三引数… ファイル名を設定します (ファイル名を動画名 or ファイル名から取るなら auto 、それ以外なら拡張子なしのファイル名を入れる) 128 | - 第四引数… 彩度とコントラストを上げるかどうか(上げるなら true・上げないなら false ) 129 | - アニメなど、彩度・コントラストの低い動画は上げたほうがより鮮明に、より綺麗に再生できます 130 | - 第五引数(オプション)… 動画の横幅を指定(例: 160 ) 131 | - 第六引数(オプション)… 動画の高さを指定(例: 90 ) 132 | 133 | ### 使用例 134 | 135 | - YouTube 等からダウンロードする場合 136 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download auto false 137 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download auto true 138 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download "Some Videos" false 139 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download "Some Videos" true 140 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download "Some Videos" false 192 108 141 | - led-movie-convert https://www.youtube.com/watch?v=xxxxxxxxx download "Some Videos" true 192 108 142 | - ローカルファイルから変換する場合 143 | - led-movie-convert "/home/pi/example video.mp4" file auto false 144 | - led-movie-convert "/home/pi/example video.mp4" file auto true 145 | - led-movie-convert "/home/pi/example video.mp4" file "example" false 146 | - led-movie-convert "/home/pi/example video.mp4" file "example" true 147 | - led-movie-convert "/home/pi/example video.mp4" file "example" false 160 90 148 | - led-movie-convert "/home/pi/example video.mp4" file "example" true 160 90 149 | 150 | ## 謝辞 151 | 152 | 改造元の記事( https://qiita.com/cstoku/items/eb17d111225d3e35ec61 )の著者の cstoku さん、素晴らしいコードを本当にありがとうございます… 153 | (私だけではまず書けないコードでした・表示処理はほぼそのままです) 154 | 155 | ## License 156 | [MIT Licence](LICENSE.txt) 157 | -------------------------------------------------------------------------------- /led-movie-player.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "led-matrix.h" 13 | #include "graphics.h" 14 | #include 15 | #include 16 | 17 | 18 | using namespace std; 19 | using namespace rgb_matrix; 20 | 21 | // LEDマトリクスで動画を再生する関数 22 | // 引数1: 動画のファイル名 23 | // 引数2: 音声のファイル名 24 | // 引数3: 個々のLEDパネルの縦幅 25 | // 引数4: 個々のLEDパネルの横幅 26 | // 引数5: 直列に繋いでいるLEDパネルの数 27 | // 引数6: 並列に繋いでいるLEDパネルの数 28 | 29 | int play(std::string movie_file, std::string audio_file, int rows, int cols, int chain, int parallel){ 30 | 31 | // LEDパネルのパラメータをOptionsに設定 32 | RGBMatrix::Options options; 33 | options.rows = rows; 34 | options.cols = cols; 35 | options.chain_length = chain; 36 | options.parallel = parallel; 37 | // ハードウェアパルス生成を無効にする 38 | // この値を false にしてハードウェアパルス生成を有効にする場合、 39 | // ラズパイに載っている音声モジュールを無効にする必要がある 40 | // この値を true にしてハードウェアパルス生成を無効にする場合、 41 | // 画面にちらつきが出る事があるので非推奨らしい 42 | options.disable_hardware_pulsing = false; 43 | 44 | // GPIOを初期化 45 | GPIO io; 46 | 47 | if (!io.Init()) 48 | return 1; 49 | 50 | // 音声の読み込み 51 | 52 | SDL_Init(SDL_INIT_AUDIO); // SDLを初期化 53 | Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096); // ミキサーAPIを初期化・音声ファイルのサンプルレートと第一引数が異なると音ズレする 54 | Mix_Music *music = Mix_LoadMUS(audio_file.c_str()); // 音声ファイルをロード 55 | if (!music) 56 | return 1; 57 | 58 | // LEDマトリクスの初期化 59 | 60 | RGBMatrix *matrix = new RGBMatrix(&io, options); // RGBMatrixを初期化 61 | matrix->set_luminance_correct(true); 62 | matrix->SetBrightness(100); 63 | matrix->SetPWMBits(11); 64 | FrameCanvas *canvas = matrix->CreateFrameCanvas(); // 描画Canvasを初期化 65 | const int width = canvas->width(); 66 | const int height = canvas->height(); 67 | 68 | // 動画の読み込み 69 | 70 | cv::Mat src_img; 71 | cv::Mat dst_img(height, width, src_img.type()); 72 | cv::VideoCapture cap(movie_file.c_str()); // VideoCaptureを初期化 73 | 74 | auto fps = cap.get(CV_CAP_PROP_FPS); // 動画のfpsを取得 75 | long fps_ustime = 1000000.0 / (double)fps + 0.5; 76 | 77 | const auto hoseicount = (int)fps * 10; 78 | auto hcnt = 0; 79 | 80 | // 音声を再生する 81 | 82 | if (Mix_PlayMusic(music, 1) == -1) { 83 | printf(" Mix_PlayMusic: %s\n", Mix_GetError()); 84 | return 1; 85 | } 86 | auto pre_dc = 1ll; 87 | 88 | // 動画を再生する 89 | 90 | auto frame_cnt = cap.get(CV_CAP_PROP_FRAME_COUNT) - 1; // Magic!!! 91 | auto start = std::chrono::system_clock::now(); 92 | 93 | // 1フレームごとに処理 94 | while (true){ 95 | 96 | auto fpos = cap.get(CV_CAP_PROP_POS_FRAMES); 97 | // fposが総フレーム数を超えたら再生を終了する 98 | if(!(fpos < frame_cnt)){ 99 | std::wcout << " Stoping Play the Movie." << std::endl; 100 | break; 101 | } 102 | 103 | // フレームを取得(Capture) 104 | cap >> src_img; 105 | 106 | // LEDマトリクスに描画 107 | auto pos = cap.get(CV_CAP_PROP_POS_MSEC); 108 | auto r = (double) height / src_img.rows; 109 | auto w = (int) (src_img.cols * r); 110 | auto d = (width - w) / 2; 111 | cv::resize(src_img, dst_img, cv::Size(w, height), cv::INTER_AREA); // LEDマトリクスのサイズに合わせて取得したフレームをリサイズする 112 | for (int y = 0; y < height; y++){ 113 | for (int x = 0; x < w; x++){ 114 | cv::Vec3b bgr = dst_img.at(y, x); 115 | canvas->SetPixel(x + d, y, bgr[2], bgr[1], bgr[0]); // 1ピクセルごとに描画 116 | } 117 | } 118 | 119 | // 同期を取る 120 | matrix->SwapOnVSync(canvas); 121 | auto end = std::chrono::system_clock::now(); 122 | 123 | auto delaytime = std::chrono::duration_cast(end - start).count(); 124 | 125 | auto delaycount = pos * 1000 - delaytime; 126 | if (delaycount > 0) { 127 | usleep(delaycount); 128 | } 129 | } 130 | 131 | // 終了処理 132 | 133 | matrix->Clear(); 134 | Mix_HaltMusic(); 135 | Mix_FreeMusic(music); 136 | Mix_CloseAudio(); 137 | SDL_Quit(); 138 | 139 | delete matrix; 140 | 141 | } 142 | 143 | // エントリーポイント 144 | 145 | int main(int argc, char *argv[]){ 146 | 147 | int cols; // 個々のLEDパネルの横幅 148 | int rows; // 個々のLEDパネルの縦幅 149 | int chain; // 直列に繋いでいるLEDパネルの数 150 | int parallel; // 並列に繋いでいるLEDパネルの数 151 | int loop; // ループ回数 152 | std::string loopstr; // 諸問題で文字列型のループ回数 153 | int loopflg; // ループフラグ 154 | std::string version = "2.3"; // バージョン 155 | std::string file; // ファイル(拡張子なし) 156 | struct stat st; 157 | 158 | // 引数確認 159 | // 変数argvは文字列なのでatoiでint型に変換しておく 160 | 161 | if (argc == 2){ // 引数が3個(コマンド名と動画ファイル名指定のみ) 162 | 163 | // デフォルト値で再生 164 | file = argv[1]; 165 | loopstr = "none"; 166 | 167 | cols = 64; // 個々のLEDパネルの横幅・適宜変更してください 168 | rows = 64; // 個々のLEDパネルの縦幅・適宜変更してください 169 | chain = 2; // 直列に繋いでいるLEDパネルの数・適宜変更してください 170 | parallel = 1; // 並列に繋いでいるLEDパネルの数・適宜変更してください 171 | 172 | } else if (argc == 3){ // 引数が3個(コマンド名と動画ファイル名とループ指定のみ) 173 | 174 | // デフォルト値で再生 175 | file = argv[1]; 176 | loop = atoi( argv[2] ); 177 | loopstr = argv[2]; //0が入るとNULLと判断されてしまうため敢えて文字型 178 | 179 | cols = 64; // 個々のLEDパネルの横幅・適宜変更してください 180 | rows = 64; // 個々のLEDパネルの縦幅・適宜変更してください 181 | chain = 2; // 直列に繋いでいるLEDパネルの数・適宜変更してください 182 | parallel = 1; // 並列に繋いでいるLEDパネルの数・適宜変更してください 183 | 184 | } else if (argc == 7){ // 引数が6個(LEDパネルの幅・高さ・個数等も指定) 185 | 186 | // 指定サイズで再生 187 | file = argv[1]; 188 | loop = atoi( argv[2] ); 189 | loopstr = argv[2]; // 0が入るとNULLと判断されてしまうため文字型にする 190 | cols = atoi( argv[3] ); 191 | rows = atoi( argv[4] ); 192 | chain = atoi( argv[5] ); 193 | parallel = atoi( argv[6] ); 194 | 195 | } else { // それ以外はエラー吐いて終了 196 | 197 | std::wcout << " " << std::endl; 198 | std::wcout << "---------------------------------------------------" << std::endl; 199 | std::wcout << " Error: Argument is missing or too many." << std::endl; 200 | std::wcout << " Usage: 1: sudo led-movie-player [File name (no extension)]" << std::endl; 201 | std::wcout << " ... Play" << std::endl; 202 | std::wcout << " 2: sudo led-movie-player [File name (no extension)] 0" << std::endl; 203 | std::wcout << " ... Play (Infinite loop)" << std::endl; 204 | std::wcout << " 3: sudo led-movie-player [File name (no extension)] [Number of loops]" << std::endl; 205 | std::wcout << " ... Play (Specified number of loops)" << std::endl; 206 | std::wcout << " 4: sudo led-movie-player [File name (no extension)] [Number of loops]" << std::endl; 207 | std::wcout << " [LED panel vertical width] [LED panel horizontal width]" << std::endl; 208 | std::wcout << " [Chain LED panels] [Parallel LED panels]" << std::endl; 209 | std::wcout << " ... Play (Specify all arguments)" << std::endl; 210 | std::wcout << " " << std::endl; 211 | std::wcout << " Please retry... m(__)m" << std::endl; 212 | std::wcout << "---------------------------------------------------" << std::endl; 213 | std::wcout << " " << std::endl; 214 | return 1; 215 | } 216 | 217 | int panelwidth = cols * chain ; // LEDパネルの横幅の合計 218 | int panelheight = rows * parallel ; // LEDパネルの縦幅の合計 219 | 220 | // 検索ディレクトリ・適宜変更してください 221 | std::string path = "/home/pi/movieplayer/"; 222 | 223 | // 再生するファイルを検索して代入 224 | std::string movie_file = path + file + ".mp4"; // 動画ファイル 225 | std::string audio_file = path + file + ".mp3"; // 音声ファイル(MP3・M4Aなど他の形式に変えても読み込める) 226 | 227 | // sudoで実行されてなかったら(Rootでないなら)エラー吐いて終了 228 | if (geteuid() != 0){ 229 | std::wcout << " " << std::endl; 230 | std::wcout << "---------------------------------------------------" << std::endl; 231 | std::wcout << " Error: It must be run with Root privileges." << std::endl; 232 | std::wcout << " Please add 'sudo' at the beginning" << std::endl; 233 | std::wcout << " of the command and retry... m(__)m." << std::endl; 234 | std::wcout << "---------------------------------------------------" << std::endl; 235 | std::wcout << " " << std::endl; 236 | return 1; 237 | } 238 | 239 | // ファイルがなかったらエラー吐いて終了 240 | if (stat(movie_file.c_str(), &st) != 0 || stat(audio_file.c_str(), &st) != 0){ 241 | std::wcout << " " << std::endl; 242 | std::wcout << "---------------------------------------------------" << std::endl; 243 | std::wcout << " Error: Specified file Not found." << std::endl; 244 | std::wcout << " Please retry... m(__)m" << std::endl; 245 | std::wcout << "---------------------------------------------------" << std::endl; 246 | std::wcout << " " << std::endl; 247 | return 1; 248 | } 249 | 250 | // ループ判別 251 | if (loopstr == "none"){ // ループ再生ではないとき 252 | loopflg = 0; 253 | } else if (loop == 0){ // 無限ループ 254 | loopflg = 1; 255 | } else if (loop >= 1){ // 有限ループ 256 | loopflg = 2; 257 | } else { 258 | loopflg = 0; //パラメータ変だったら取りあえず一回だけ 259 | } 260 | 261 | // 表示部分 262 | 263 | std::wcout.imbue(std::locale("ja_JP.utf8")); 264 | std::wcout << " " << std::endl; 265 | std::wcout << "---------------------------------------------------" << std::endl; 266 | std::wcout << " LED-Movie-Player v" << version.c_str() << std::endl; 267 | std::wcout << "---------------------------------------------------" << std::endl; 268 | std::wcout << " Chain LED Panels : " << chain << std::endl; 269 | std::wcout << " Parallel LED Panels : " << parallel << std::endl; 270 | std::wcout << " One LED Panel Size : " << cols << "x" << rows << std::endl; 271 | std::wcout << " All LED Panel Sizes : " << panelwidth << "x" << panelheight << std::endl; 272 | std::wcout << " " << std::endl; 273 | if (loopflg == 0){ 274 | std::wcout << " Press Ctrl + C to stop the movie." << std::endl; 275 | } else if (loopflg == 1 || loopflg == 2){ 276 | std::wcout << " If you want to stop loop, Press Ctrl + C." << std::endl; 277 | } 278 | std::wcout << "---------------------------------------------------" << std::endl; 279 | 280 | if (loopflg == 0){ // ループ再生しない 281 | 282 | // 表示 283 | std::wcout << " Start playing movie..." << std::endl; 284 | std::wcout << " " << std::endl; 285 | std::wcout << " Now playing..." << std::endl; 286 | std::wcout << "---------------------------------------------------" << std::endl; 287 | 288 | // 再生を実行 289 | int result = play(movie_file, audio_file, rows, cols, chain, parallel); 290 | 291 | // 終了 292 | std::wcout << " See You!!" << std::endl; 293 | 294 | } else if (loopflg == 1){ // 無限ループ 295 | 296 | while (1){ // 無限ループ実行 297 | 298 | // 表示 299 | std::wcout << " Start playing movie..." << std::endl; 300 | std::wcout << " " << std::endl; 301 | std::wcout << " Now Playing..." << std::endl; 302 | std::wcout << "---------------------------------------------------" << std::endl; 303 | 304 | // 再生実行 305 | int result = play(movie_file, audio_file, rows, cols, chain, parallel); 306 | 307 | // 少し待つ 308 | std::wcout << " Now looping..." << std::endl; 309 | std::wcout << "---------------------------------------------------" << std::endl; 310 | int second = 300000; 311 | usleep(second); 312 | } 313 | 314 | } else if (loopflg == 2){ // 有限ループ 315 | 316 | for (int i = 1; i <= loop; i++){ // ループ実行 317 | 318 | // 表示 319 | std::wcout << " Start playing movie..." << std::endl; 320 | std::wcout << " Number of loops : " << loop << std::endl; 321 | std::wcout << " Current loop count: " << i << std::endl; 322 | std::wcout << " " << std::endl; 323 | std::wcout << " Now Playing..." << std::endl; 324 | std::wcout << "---------------------------------------------------" << std::endl; 325 | 326 | // 再生実行 327 | int result = play(movie_file, audio_file, rows, cols, chain, parallel); 328 | 329 | if (i < loop){ 330 | // 少し待つ 331 | std::wcout << " Now looping..." << std::endl; 332 | std::wcout << "---------------------------------------------------" << std::endl; 333 | int second = 300000; 334 | usleep(second); 335 | } else if (i == loop){ // 最後のループなら 336 | std::wcout << " See You!!" << std::endl; 337 | } 338 | 339 | } 340 | 341 | } 342 | 343 | std::wcout << "---------------------------------------------------" << std::endl; 344 | std::wcout << " " << std::endl; 345 | 346 | } 347 | 348 | --------------------------------------------------------------------------------