遠隔のコンテナで生成された各種メディア(音声・画像・映像)を、手元で再生/表示するやり方ですーー大きく2コのパターンがあり、[1]そのままダイレクトに(ストリームで)再生/表示する方法、[2]ファイルに落として再生/表示する方法、を解説します。
関連
- ◯
- 高機能のウィンドウシステム:X Window System (XQuartz) , Docker, OpenGL, Tcl/Tk, Xvfb, x11vnc
検証
- ◯
- ローカル
- ・
- OS:macOS 11
- ・
- ウィンドウシステム:XQuartz 2.8
- ・
- プレイヤ/ビューア:Preview, VLC, Google Chrome
- ・
- 同期アプリ:rsync
- ・
- マウント・アプリ:sshfs 2.10
- ◯
- リモート
- ・
- OS:Ubuntu 20.04
- ・
- コンテナ:Dcoker 20.10
- ・
- ウィンドウシステム:X window
- ・
- プレイヤ/ビューア:display
- ・
- インタプリタ:Python 3.8
- ・
- ライブラリ:OpenCV, PIL/Pillow, tkinter
- ・
- ウェブサーバ:nginx
そのままダイレクトに → リモート側のリソースを使う:専用のプレイヤ/ビューワなど
リモート側にあるプレイヤ/ビューワ・アプリ(Xクライアント)を使い、ローカル側のXサーバで再生するやり方です:
- ◯
- 送信:ストリーム
- ◯
- 再生:リモートのリソース:画像:X window, Unix (Linux (Ubuntu)) , display
- ・
- 設置:リモート:コンテナ
$ apt install graphicsmagick-imagemagick-compat
- ・
- 利用:ローカル
$ ssh ${user_remote}@${server_remote} docker -i --rm ${image_other} ${command} | \ ssh -X ${user_remote}@${server_remote} docker -i --rm ${image} display -
- ※1
- display は、PIL/Pillow がshow()関数から呼び出す、標準の画像ビューアのひとつです。
そのままダイレクトに → リモート側のリソースを使う:かんたんなスクリプトを書く
リモート側で再生するスクリプト(Xクライアント)を書き、ローカル側のXウィンドウサーバで再生するやり方です(メディアのストリームを標準入力から受け取り〜再生する、という形になります):
- ◯
- 送信:ストリーム
- ◯
- 再生:リモートのリソース:画像:X window, Unix, Python, PIL/Pillow, Tk (tkinter)
- ・
- 作成:リモート:コンテナ:imgwin_tkw.py
#!/usr/bin/python import sys import tkinter from PIL import Image,ImageTk window=tkinter.Tk() pilimg=Image.open(sys.stdin.buffer) tkwimg=ImageTk.PhotoImage(image=pilimg) canvas=tkinter.Canvas(width=pilimg.width,height=pilimg.height) canvas.place(x=0,y=0) canvas.create_image(0,0,image=tkwimg,anchor=tkinter.NW) window.title("") window.geometry(str(pilimg.width) + "x" + str(pilimg.height)) window.mainloop()
- ・
- 利用:ローカル
$ ssh ${user_remote}@${server_remote} docker -i --rm ${image_other} ${command} | \ ssh -X ${user_remote}@${server_remote} docker -i --rm ${image} imgwin_tkw.py
- ◯
- 送信:ストリーム
- ◯
- 再生:リモートのリソース:画像:X window, Unix, Python, OpenCV[※2]
- ・
- 作成:リモート:コンテナ:imgwin_ocv.py
#!/usr/bin/python import sys import numpy import cv2 strimg=sys.stdin.buffer.read() arrimg=numpy.frombuffer(strimg,dtype=numpy.uint8) matimg=cv2.imdecode(arrimg,cv2.IMREAD_COLOR) cv2.imshow("",matimg) cv2.waitKey(0) cv2.destroyAllWindows()
- ・
- 利用:ローカル
$ ssh ${user_remote}@${server_remote} docker -i --rm ${image_other} ${command} | \ ssh -X ${user_remote}@${server_remote} docker -i --rm ${image} imgwin_ocv.py
- ※1
- 拡散モデルの画像生成フレームワークのDiffusers は、生成画像の形式にPIL を採用しています。なので、表示側もそれを使えば対称性があるので、コードが分かりやすくなるかもしれません。
- ※2
- コードは短くなりますが、OpenCVは画像解析・画像処理のライブラリなので、大量の依存ライブラリがあります。なのでたんに画像を表示するためだけに使うなら、オーバースペックかもしれません。
そのままダイレクトに → ローカル側のリソースを使う
リモート側のメディアをそのまま流して、ローカル側のプレイヤ/ビューワで再生するやり方です。[※1]
- ◯
- 送信:ストリーム
- ◯
- 再生:ローカルのリソース:画像:Unix (BSD (macOS)) , Preview
- ・
- 利用:ローカル
$ ssh ${user_remote}@${server_remote} docker -i --rm ${image_other} ${command} | \ open -f -a Preview
- ※1
- ssh とdockerコマンドを使い、リモート側のメディアを、ストリームとして標準出力〜標準入力に流し、ローカル側のプレイヤ/ビューワに送り込みます(なのでローカル側のプレイヤ/ビューワは、標準入力からの入力に対応している必要があります)。
ファイルに落として → ローカル側のリソースを使う:フォルダを同期する
コンテナと共有するリモートのフォルダを、ローカルのフォルダに同期させます:[※1]
- ◯
- 送信:ファイル:同期:rsync
- ◯
- 再生:ローカルのリソース
- ・
- 利用:ローカル
$ rsync --archive --delete --rsh ssh ${user_remote}@${server_remote}:${diretory_remote}/ ${directory_local}
- ※1
- オプション「--delete」は、送信元と送信先を完全に同期させます(ないものは削除する)。なので同期の方向を誤ると、意図しない形でファイルが消えることがあります[要注意]。
ファイルに落として → ローカル側のリソースを使う:フォルダをマウントする
コンテナと共有するリモートのフォルダを、ローカルのフォルダにマウントします:[※1][※2]
- ◯
- 送信:ファイル:マウント:sshfs
- ◯
- 再生:ローカルのリソース
- ・
- 利用:ローカル
$ sshfs ${user_remote}@${server_remote}:${diretory_remote} ${directory_local} $ umount ${d}
- ※1
- これは遠隔のファイルが手元に同期されるタイミングが微妙なので、使い勝手がいいとはいえないかもしれません(とくにサイズが大きくなるファイルほど)。
- ※2
- このアプリを開発していたNikratio氏がプロジェクトから手を引いたようで、後継を募集しています(2022.05):
- ・
- https://github.com/libfuse/sshfs
ファイルに落として → ローカル側のリソースを使う:ウェブサーバとウェブブラウザを使う
あつかうメディアの種類が増えると、それにともなって(リモート側にせよローカル側にせよ)必要なプレイヤ/ビューア/スクリプトが増えていきます。
ウェブブラウザは、さまざまなメディアをあつえる、おそらくもっとも手近にあるプレイヤ/ビューアですーーコンテナを使えば、ウェブサーバも数ステップで導入できるので、プライベートでテンポラリな使い方をするなら、選択肢に入るかもしれません。[※1][※2]
- ◯
- 送信:ファイル:ウェブサーバ:UNIX, nginx
- ◯
- 再生:ローカルのリソース
- ・
- 設置:リモート
$ docker pull nginx:latest
- ・
- 利用:リモート
$ docker run -d --rm -p 8080:80 -v ${directory}:/usr/share/nginx/html --name ${container} nginx:latest
- ・
- 利用:ローカル
# 画像 $ open http://${server_remote}:8080/${file}.png $ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome http://${server_remote}:8080/${file}.png # 映像 $ open http://${server_remote}:8080/${file}.mp4 $ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome http://${server_remote}:8080/${file}.mp4 $ /Applications/VLC.app/Contents/MacOS/VLC http://${server_remote}:8080/${file}.mp4
- ※1
- 不特定多数に公開するサーバなら、セキュリティやパフォーマンスを考えなければなりませんーーしかしプライベートでテンポラリな利用に限定するなら、ある程度セキュリティをゆるくしてもかまない、といった考え方もあるかもしれません。
- ※2
- とはいえ完全にオープンにしていると、アドレスやポートの番号が分かれば、不特定多数がすべてのファイルを閲覧できてしまいますーーみられるとマズイものがあるなら、最低限のアクセス制限(ダイジェスト認証)はかけておいた方が無難です。
ファイルに落として → ローカル側のリソースを使う:ウェブサーバとウェブブラウザを使う:Jupyter Notebook
フォルダ機能をもつウェブサーバアプリ(Jupyter Notebook, etc.)を使えば、コンテナと共有するリモートのフォルダに生成した画像などを、ローカルのウェブブラウザで表示できます:[※1]
- ・
- 設置:リモート:コンテナ
$ pip install jupyterlab
- ・
- 利用:リモート
$ docker run -d -p 8888:8888 --rm -v ${directory_host}:{$directory_container} --name ${container} ${image} jupyter lab --ip=0.0.0.0 --allow-root --NotebookApp.token=''
- ・
- 利用:ローカル
$ open http://${server_remote}:8888/lab
- ※1
- この場合も、なんの対策もしなれば、ウェブサーバアプリはどこからでもアクセスできる状態になりますーーホスト側のポート番号を既定のものから変え、コンテナでパスワードやトークンを設定しておく、など、最低限の対策はしておいた方が無難です。