質問編集履歴

2

コードのミスを修正しました。

2021/07/05 03:06

投稿

harukat
harukat

スコア1

test CHANGED
File without changes
test CHANGED
@@ -176,8 +176,6 @@
176
176
 
177
177
  def gen():
178
178
 
179
- global browser
180
-
181
179
  """Video streaming generator function."""
182
180
 
183
181
  bw_flag = True
@@ -268,7 +266,7 @@
268
266
 
269
267
  <script type="text/javascript">
270
268
 
271
- function drawCanvasFromMjpegStrmer(){ //MJPG-streamer -> CANVAS-TAG
269
+ function drawCanvasFromMjpeg(){ //MJPG-streamer -> CANVAS-TAG
272
270
 
273
271
  const canvas = document.getElementById("canvas");
274
272
 
@@ -314,7 +312,7 @@
314
312
 
315
313
  }
316
314
 
317
- drawCanvasFromMjpegStrmer();
315
+ drawCanvasFromMjpeg();
318
316
 
319
317
  drawVideoFromCanvas();
320
318
 

1

Python サーバー部分に関して追記しました。

2021/07/05 03:06

投稿

harukat
harukat

スコア1

test CHANGED
@@ -1 +1 @@
1
- MJPG-streamer のストリーミング画像canvasStream を使って video タグに描画できな
1
+ Python の FastAPI で出力した MJPG-streamer を video タグに描画した
test CHANGED
@@ -1,10 +1,10 @@
1
- ### 前提・実現したいこと
1
+ # 前提・実現したいこと
2
2
 
3
3
  Javascript を使って、 MJPG-streamer のストリーミング画像をvideoタグに描画しようとしています。
4
4
 
5
5
  しかし、 Canvas には画像が出力され、動画のように更新されているものの、 video タグの方では表示されませんでした。
6
6
 
7
- captureStream() を使って video の srcObject とする正しい方法を教えていただけますと幸いです。
7
+ **captureStream()** を使って video の srcObject とする正しい方法を教えていただけますと幸いです。
8
8
 
9
9
 
10
10
 
@@ -16,20 +16,234 @@
16
16
 
17
17
 
18
18
 
19
- ### 発生している問題・エラーメッセージ
19
+ # 発生している問題・エラーメッセージ
20
20
 
21
21
  console を確認したところ、エラーは発生していませんでした。
22
22
 
23
23
  video タグではローディングが続く状態です。
24
24
 
25
+
26
+
27
+
28
+
29
+ # 該当のソースコード
30
+
31
+ ##HTML側
32
+
33
+ 以下のコードで MJPEG を video タグに変換して表示させようと試みています。
34
+
25
35
  drawCanvasFromMjpegStrmer()はおそらく問題なく動作しており、 canvas タグは更新されています。
26
36
 
27
- ### 該当のソースコード
28
-
29
-
30
-
31
37
  ```HTML
32
38
 
39
+ <!-- test.html -->
40
+
41
+ <html>
42
+
43
+ <head>
44
+
45
+ <title>Video Streaming Demonstration</title>
46
+
47
+ </head>
48
+
49
+ <body>
50
+
51
+ <h1>Video Streaming Demonstration</h1>
52
+
53
+
54
+
55
+ <canvas id="canvas", width="1280px", height="720px"></canvas>
56
+
57
+ <video id="player-canvas" controls autoplay loop muted poster="" playsinline width="1280px" height="720px"></video>
58
+
59
+
60
+
61
+ <script type="text/javascript">
62
+
63
+ let canvasStream = null;
64
+
65
+
66
+
67
+ function drawCanvasFromMjpegStrmer(){ //MJPG-streamer -> CANVAS-TAG
68
+
69
+ const canvas = document.getElementById("canvas");
70
+
71
+ const ctx = canvas.getContext("2d");
72
+
73
+ setInterval(() => {
74
+
75
+ if (canvas && ctx){
76
+
77
+ const chara = new Image();
78
+
79
+ chara.src = "http://localhost:8000/video_feed"; // MJPG-streamer のURL
80
+
81
+ chara.onload = () => {
82
+
83
+ ctx.drawImage(chara, 0, 0);
84
+
85
+ };
86
+
87
+ }
88
+
89
+ }, 10000/60);
90
+
91
+ }
92
+
93
+
94
+
95
+ function drawVideoFromCanvas() { // CANVAS-TAG -> VIDEO-TAG
96
+
97
+ const canvas = document.querySelector("canvas");
98
+
99
+ const video = document.getElementById("player-canvas");
100
+
101
+ canvasStream = canvas.captureStream(30);
102
+
103
+ video.srcObject = canvasStream;
104
+
105
+ }
106
+
107
+
108
+
109
+ drawCanvasFromMjpegStrmer();
110
+
111
+ drawVideoFromCanvas();
112
+
113
+ </script>
114
+
115
+ </body>
116
+
117
+ </html>
118
+
119
+ ```
120
+
121
+
122
+
123
+ ###サーバー(Python)側
124
+
125
+ サーバーライブラリには、fastAPI を採用し、実装しています。
126
+
127
+ ```Python
128
+
129
+ import sys
130
+
131
+ import uvicorn
132
+
133
+
134
+
135
+ from fastapi import FastAPI, Request
136
+
137
+ from fastapi.responses import HTMLResponse, StreamingResponse
138
+
139
+ from fastapi.staticfiles import StaticFiles
140
+
141
+ from fastapi.templating import Jinja2Templates
142
+
143
+
144
+
145
+ import numpy as np
146
+
147
+ import cv2
148
+
149
+ import time
150
+
151
+
152
+
153
+ app = FastAPI()
154
+
155
+
156
+
157
+ app.mount("/static", StaticFiles(directory="static"), name="static")
158
+
159
+ templates = Jinja2Templates(directory="templates")
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+ @app.get("/", response_class=HTMLResponse)
168
+
169
+ async def index(request: Request):
170
+
171
+ return templates.TemplateResponse('index.html', {"request": request})
172
+
173
+
174
+
175
+
176
+
177
+ def gen():
178
+
179
+ global browser
180
+
181
+ """Video streaming generator function."""
182
+
183
+ bw_flag = True
184
+
185
+ # 白黒画像の切り替えを繰り返す
186
+
187
+ while True:
188
+
189
+ if bw_flag:
190
+
191
+ img = np.zeros((1280,720,3), dtype=np.uint8)
192
+
193
+ else:
194
+
195
+ img = np.ones((1280,720,3), dtype=np.uint8) * 255
196
+
197
+ if type(img) == np.ndarray:
198
+
199
+ frame = cv2.imencode('.jpg', img)[1].tobytes()
200
+
201
+ yield (b'--frame\r\n'
202
+
203
+ b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
204
+
205
+ else:
206
+
207
+ print("img is None.")
208
+
209
+ time.sleep(0.5)
210
+
211
+ bw_flag = not bw_flag # 白黒反転
212
+
213
+
214
+
215
+
216
+
217
+ @app.get('/video_feed', response_class=HTMLResponse)
218
+
219
+ async def video_feed():
220
+
221
+ """Video streaming route. Put this in the src attribute of an img tag."""
222
+
223
+ return StreamingResponse(gen(),
224
+
225
+ media_type='multipart/x-mixed-replace; boundary=frame')
226
+
227
+
228
+
229
+ def start_server():
230
+
231
+ uvicorn.run(app, host="0.0.0.0", port=8000)
232
+
233
+
234
+
235
+ if __name__ == "__main__":
236
+
237
+ start_server()
238
+
239
+ ```
240
+
241
+
242
+
243
+ 以下のコードは`templates/index.html`に配置し、`localhost:8000`でアクセスしたときに表示される画面です。
244
+
245
+ ```HTML
246
+
33
247
  <!-- index.html -->
34
248
 
35
249
  <html>
@@ -44,20 +258,16 @@
44
258
 
45
259
  <h1>Video Streaming Demonstration</h1>
46
260
 
47
-
261
+ <!-- <img src="{{ url_for('video_feed') }}"> -->
48
262
 
49
263
  <canvas id="canvas", width="1280px", height="720px"></canvas>
50
264
 
51
265
  <video id="player-canvas" controls autoplay loop muted poster="" playsinline width="1280px" height="720px"></video>
52
266
 
53
-
267
+ <!-- jinja2のテンプレートの書き方です。/video_feedを呼び出しています。 -->
54
268
 
55
269
  <script type="text/javascript">
56
270
 
57
- let canvasStream = null;
58
-
59
-
60
-
61
271
  function drawCanvasFromMjpegStrmer(){ //MJPG-streamer -> CANVAS-TAG
62
272
 
63
273
  const canvas = document.getElementById("canvas");
@@ -70,7 +280,7 @@
70
280
 
71
281
  const chara = new Image();
72
282
 
73
- chara.src = "http://localhost:8000/video_feed"; // MJPG-streamer のURL
283
+ chara.src = "{{ url_for('video_feed') }}" // URLをfastapiから取得(localhost:8000/video_feed
74
284
 
75
285
  chara.onload = () => {
76
286
 
@@ -88,18 +298,22 @@
88
298
 
89
299
  function drawVideoFromCanvas() { // CANVAS-TAG -> VIDEO-TAG
90
300
 
91
- const canvas = document.querySelector("canvas");
301
+ const canvas = document.getElementById("canvas");
92
302
 
93
303
  const video = document.getElementById("player-canvas");
94
304
 
305
+ const ctx = canvas.getContext('2d');
306
+
307
+
308
+
309
+ // ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
310
+
95
311
  canvasStream = canvas.captureStream(30);
96
312
 
97
313
  video.srcObject = canvasStream;
98
314
 
99
315
  }
100
316
 
101
-
102
-
103
317
  drawCanvasFromMjpegStrmer();
104
318
 
105
319
  drawVideoFromCanvas();
@@ -112,22 +326,22 @@
112
326
 
113
327
  ```
114
328
 
115
-
116
-
117
- ### 試したこと
329
+ # 試したこと
118
330
 
119
331
 
120
332
 
121
333
  ブラウザの問題かと思い、 Firefox で試しましたが、動作しませんでした。
122
334
 
123
- **Fastapi を用いたローカルサーバー上のページを Chrome で開くと、 video タグ側でも表示されました。**
335
+ **Fastapi を用いたローカルサーバー上のページ(`localhost:8000`)を Chrome で開くと、 video タグ側でも表示されました。**
336
+
124
-
337
+ `test.html`を直に開くと canvas のみ動画が表示されました。
125
-
126
338
 
127
339
  ### 補足情報(FW/ツールのバージョンなど)
128
340
 
129
341
  OS: Linux (OpenSUSE Leap 15.3)
130
342
 
343
+ Python: 3.8.10(Pyenv)
344
+
131
345
  ブラウザ:
132
346
 
133
347
  - Google Chrome Stable: ver. 91.0.4472