前提・実現したいこと
Javascript を使って、 MJPG-streamer のストリーミング画像をvideoタグに描画しようとしています。
しかし、 Canvas には画像が出力され、動画のように更新されているものの、 video タグの方では表示されませんでした。
captureStream() を使って video の srcObject とする正しい方法を教えていただけますと幸いです。
以下のリンクを参考に実装しました。
https://zenn.dev/zgw426/articles/ed632c88148183e9b902
https://qiita.com/akmtsyk/items/bb38947f028bf11fe72b
発生している問題・エラーメッセージ
console を確認したところ、エラーは発生していませんでした。
video タグではローディングが続く状態です。
該当のソースコード
##HTML側
以下のコードで MJPEG を video タグに変換して表示させようと試みています。
drawCanvasFromMjpegStrmer()はおそらく問題なく動作しており、 canvas タグは更新されています。
HTML
1 <!-- test.html --> 2 <html> 3 <head> 4 <title>Video Streaming Demonstration</title> 5 </head> 6 <body> 7 <h1>Video Streaming Demonstration</h1> 8 9 <canvas id="canvas", width="1280px", height="720px"></canvas> 10 <video id="player-canvas" controls autoplay loop muted poster="" playsinline width="1280px" height="720px"></video> 11 12 <script type="text/javascript"> 13 let canvasStream = null; 14 15 function drawCanvasFromMjpegStrmer(){ //MJPG-streamer -> CANVAS-TAG 16 const canvas = document.getElementById("canvas"); 17 const ctx = canvas.getContext("2d"); 18 setInterval(() => { 19 if (canvas && ctx){ 20 const chara = new Image(); 21 chara.src = "http://localhost:8000/video_feed"; // MJPG-streamer のURL 22 chara.onload = () => { 23 ctx.drawImage(chara, 0, 0); 24 }; 25 } 26 }, 10000/60); 27 } 28 29 function drawVideoFromCanvas() { // CANVAS-TAG -> VIDEO-TAG 30 const canvas = document.querySelector("canvas"); 31 const video = document.getElementById("player-canvas"); 32 canvasStream = canvas.captureStream(30); 33 video.srcObject = canvasStream; 34 } 35 36 drawCanvasFromMjpegStrmer(); 37 drawVideoFromCanvas(); 38 </script> 39 </body> 40</html>
###サーバー(Python)側
サーバーライブラリには、fastAPI を採用し、実装しています。
Python
1import sys 2import uvicorn 3 4from fastapi import FastAPI, Request 5from fastapi.responses import HTMLResponse, StreamingResponse 6from fastapi.staticfiles import StaticFiles 7from fastapi.templating import Jinja2Templates 8 9import numpy as np 10import cv2 11import time 12 13app = FastAPI() 14 15app.mount("/static", StaticFiles(directory="static"), name="static") 16templates = Jinja2Templates(directory="templates") 17 18 19 20@app.get("/", response_class=HTMLResponse) 21async def index(request: Request): 22 return templates.TemplateResponse('index.html', {"request": request}) 23 24 25def gen(): 26 """Video streaming generator function.""" 27 bw_flag = True 28 # 白黒画像の切り替えを繰り返す 29 while True: 30 if bw_flag: 31 img = np.zeros((1280,720,3), dtype=np.uint8) 32 else: 33 img = np.ones((1280,720,3), dtype=np.uint8) * 255 34 if type(img) == np.ndarray: 35 frame = cv2.imencode('.jpg', img)[1].tobytes() 36 yield (b'--frame\r\n' 37 b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') 38 else: 39 print("img is None.") 40 time.sleep(0.5) 41 bw_flag = not bw_flag # 白黒反転 42 43 44@app.get('/video_feed', response_class=HTMLResponse) 45async def video_feed(): 46 """Video streaming route. Put this in the src attribute of an img tag.""" 47 return StreamingResponse(gen(), 48 media_type='multipart/x-mixed-replace; boundary=frame') 49 50def start_server(): 51 uvicorn.run(app, host="0.0.0.0", port=8000) 52 53if __name__ == "__main__": 54 start_server()
以下のコードはtemplates/index.html
に配置し、localhost:8000
でアクセスしたときに表示される画面です。
HTML
1 <!-- index.html --> 2 <html> 3 <head> 4 <title>Video Streaming Demonstration</title> 5 </head> 6 <body> 7 <h1>Video Streaming Demonstration</h1> 8 <!-- <img src="{{ url_for('video_feed') }}"> --> 9 <canvas id="canvas", width="1280px", height="720px"></canvas> 10 <video id="player-canvas" controls autoplay loop muted poster="" playsinline width="1280px" height="720px"></video> 11 <!-- jinja2のテンプレートの書き方です。/video_feedを呼び出しています。 --> 12 <script type="text/javascript"> 13 function drawCanvasFromMjpeg(){ //MJPG-streamer -> CANVAS-TAG 14 const canvas = document.getElementById("canvas"); 15 const ctx = canvas.getContext("2d"); 16 setInterval(() => { 17 if (canvas && ctx){ 18 const chara = new Image(); 19 chara.src = "{{ url_for('video_feed') }}" // URLをfastapiから取得(localhost:8000/video_feed) 20 chara.onload = () => { 21 ctx.drawImage(chara, 0, 0); 22 }; 23 } 24 }, 10000/60); 25 } 26 27 function drawVideoFromCanvas() { // CANVAS-TAG -> VIDEO-TAG 28 const canvas = document.getElementById("canvas"); 29 const video = document.getElementById("player-canvas"); 30 const ctx = canvas.getContext('2d'); 31 32 // ctx.drawImage(video, 0, 0, canvas.width, canvas.height); 33 canvasStream = canvas.captureStream(30); 34 video.srcObject = canvasStream; 35 } 36 drawCanvasFromMjpeg(); 37 drawVideoFromCanvas(); 38 </script> 39 </body> 40</html>
試したこと
ブラウザの問題かと思い、 Firefox で試しましたが、動作しませんでした。
Fastapi を用いたローカルサーバー上のページ(localhost:8000
)を Chrome で開くと、 video タグ側でも表示されました。
test.html
を直に開くと canvas のみ動画が表示されました。
補足情報(FW/ツールのバージョンなど)
OS: Linux (OpenSUSE Leap 15.3)
Python: 3.8.10(Pyenv)
ブラウザ:
- Google Chrome Stable: ver. 91.0.4472
- Firefox: ver. 78.11.0
皆様のご助力に感謝いたします。
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。