OLD | NEW |
---|---|
1 <html> | 1 <html> |
2 <head> | 2 <head> |
3 <script type="text/javascript" src="webrtc_test_utilities.js"></script> | 3 <script type="text/javascript" src="webrtc_test_utilities.js"></script> |
4 <script type="text/javascript"> | 4 <script type="text/javascript"> |
5 $ = function(id) { | 5 $ = function(id) { |
6 return document.getElementById(id); | 6 return document.getElementById(id); |
7 }; | 7 }; |
8 | 8 |
9 var gLocalStream = null; | |
10 | |
11 setAllEventsOccuredHandler(function() { | 9 setAllEventsOccuredHandler(function() { |
12 gLocalStream.stop(); | |
13 reportTestSuccess(); | 10 reportTestSuccess(); |
14 }); | 11 }); |
15 | 12 |
16 function getSources() { | 13 function getSources() { |
17 MediaStreamTrack.getSources(function(devices) { | 14 MediaStreamTrack.getSources(function(devices) { |
18 document.title = 'Media devices available'; | 15 document.title = 'Media devices available'; |
19 sendValueToTest(JSON.stringify(devices)); | 16 sendValueToTest(JSON.stringify(devices)); |
20 }); | 17 }); |
21 } | 18 } |
22 | 19 |
23 // Creates a MediaStream and renders it locally. When the video is detected to | 20 // Creates a MediaStream and renders it locally. When the video is detected to |
24 // be rolling, the stream should be stopped. | 21 // be rolling, the stream should be stopped. |
25 function getUserMediaAndStop(constraints) { | 22 function getUserMediaAndStop(constraints) { |
26 console.log('Calling getUserMediaAndStop.'); | 23 console.log('Calling getUserMediaAndStop.'); |
27 navigator.webkitGetUserMedia( | 24 navigator.webkitGetUserMedia( |
28 constraints, | 25 constraints, |
29 function(stream) { displayAndDetectVideo(stream, stopVideoTrack); }, | 26 function(stream) { |
27 detectVideoInLocalView1(stream, function() { | |
28 stream.getVideoTracks()[0].stop(); | |
29 waitForVideoToStop('local-view-1'); | |
30 }); | |
31 }, | |
30 failedCallback); | 32 failedCallback); |
31 } | 33 } |
32 | 34 |
33 // Requests getusermedia and expects it to fail. The error name is returned | 35 // Requests getusermedia and expects it to fail. The error name is returned |
34 // to the test. | 36 // to the test. |
35 function getUserMediaAndExpectFailure(constraints) { | 37 function getUserMediaAndExpectFailure(constraints) { |
36 console.log('Calling getUserMediaAndExpectFailure.'); | 38 console.log('Calling getUserMediaAndExpectFailure.'); |
37 navigator.webkitGetUserMedia( | 39 navigator.webkitGetUserMedia( |
38 constraints, | 40 constraints, |
39 function(stream) { failTest('Unexpectedly succeeded getUserMedia.'); }, | 41 function(stream) { failTest('Unexpectedly succeeded getUserMedia.'); }, |
40 function(error) { sendValueToTest(error.name); }); | 42 function(error) { sendValueToTest(error.name); }); |
41 } | 43 } |
42 | 44 |
43 function renderClonedMediastreamAndStop(constraints, waitTimeInSeconds) { | 45 function renderClonedMediastreamAndStop(constraints, waitTimeInSeconds) { |
44 console.log('Calling renderClonedMediastreamAndStop.'); | 46 console.log('Calling renderClonedMediastreamAndStop.'); |
45 navigator.webkitGetUserMedia( | 47 navigator.webkitGetUserMedia( |
46 constraints, | 48 constraints, |
47 function(stream) { | 49 function(stream) { |
48 var s = stream.clone(); | 50 var duplicate = stream.clone(); |
49 assertEquals(stream.getVideoTracks().length, 1); | 51 assertEquals(stream.getVideoTracks().length, 1); |
50 assertEquals(s.getVideoTracks().length, 1); | 52 assertEquals(duplicate.getVideoTracks().length, 1); |
51 assertNotEquals(stream.getVideoTracks()[0].id, | 53 assertNotEquals(stream.getVideoTracks()[0].id, |
52 s.getVideoTracks()[0].id); | 54 duplicate.getVideoTracks()[0].id); |
53 displayAndDetectVideo( | 55 detectVideoInLocalView1( |
54 s, | 56 stream, |
55 function() { | 57 function() { |
56 reportTestSuccess(); | 58 reportTestSuccess(); |
57 }); | 59 }); |
58 }, | 60 }, |
59 failedCallback); | 61 failedCallback); |
60 } | 62 } |
61 | 63 |
62 function renderDuplicatedMediastreamAndStop(constraints, waitTimeInSeconds) { | 64 function renderDuplicatedMediastreamAndStop(constraints, waitTimeInSeconds) { |
63 console.log('Calling renderDuplicateMediastreamAndStop.'); | 65 console.log('Calling renderDuplicateMediastreamAndStop.'); |
64 navigator.webkitGetUserMedia( | 66 navigator.webkitGetUserMedia( |
65 constraints, | 67 constraints, |
66 function(stream) { | 68 function(stream) { |
67 s = new webkitMediaStream(stream); | 69 var duplicate = new webkitMediaStream(stream); |
68 assertEquals(stream.getVideoTracks().length, 1); | 70 assertEquals(stream.getVideoTracks().length, 1); |
69 assertEquals(s.getVideoTracks().length, 1); | 71 assertEquals(duplicate.getVideoTracks().length, 1); |
70 assertEquals(stream.getVideoTracks()[0].id, | 72 assertEquals(stream.getVideoTracks()[0].id, |
71 s.getVideoTracks()[0].id); | 73 duplicate.getVideoTracks()[0].id); |
72 displayAndDetectVideo( | 74 detectVideoInLocalView1( |
73 s, | 75 duplicate, |
74 function() { | 76 function() { |
75 reportTestSuccess(); | 77 reportTestSuccess(); |
76 }); | 78 }); |
77 }, | 79 }, |
78 failedCallback); | 80 failedCallback); |
79 } | 81 } |
80 | 82 |
81 function renderSameTrackMediastreamAndStop(constraints, waitTimeInSeconds) { | 83 function renderSameTrackMediastreamAndStop(constraints, waitTimeInSeconds) { |
82 console.log('Calling renderSameTrackMediastreamAndStop.'); | 84 console.log('Calling renderSameTrackMediastreamAndStop.'); |
83 navigator.webkitGetUserMedia( | 85 navigator.webkitGetUserMedia( |
84 constraints, | 86 constraints, |
85 function(stream) { | 87 function(stream) { |
86 s = new webkitMediaStream(); | 88 var duplicate = new webkitMediaStream(); |
87 s.addTrack(stream.getVideoTracks()[0]); | 89 duplicate.addTrack(stream.getVideoTracks()[0]); |
88 assertEquals(s.getVideoTracks().length, 1); | 90 assertEquals(duplicate.getVideoTracks().length, 1); |
89 assertEquals(s.getVideoTracks().length, 1); | 91 assertEquals(duplicate.getVideoTracks().length, 1); |
90 assertEquals(stream.getVideoTracks()[0].id, s.getVideoTracks()[0].id); | 92 assertEquals(stream.getVideoTracks()[0].id, |
91 displayAndDetectVideo( | 93 duplicate.getVideoTracks()[0].id); |
92 s, | 94 detectVideoInLocalView1( |
95 duplicate, | |
93 function() { | 96 function() { |
94 reportTestSuccess(); | 97 reportTestSuccess(); |
95 }); | 98 }); |
96 }, | 99 }, |
97 failedCallback); | 100 failedCallback); |
98 } | 101 } |
99 | 102 |
100 function renderClonedTrackMediastreamAndStop(constraints, waitTimeInSeconds) { | 103 function renderClonedTrackMediastreamAndStop(constraints, waitTimeInSeconds) { |
101 console.log('Calling renderClonedTrackMediastreamAndStop.'); | 104 console.log('Calling renderClonedTrackMediastreamAndStop.'); |
102 navigator.webkitGetUserMedia( | 105 navigator.webkitGetUserMedia( |
103 constraints, | 106 constraints, |
104 function(stream) { | 107 function(stream) { |
105 s = new webkitMediaStream(); | 108 var duplicate = new webkitMediaStream(); |
106 s.addTrack(stream.getVideoTracks()[0].clone()); | 109 duplicate.addTrack(stream.getVideoTracks()[0].clone()); |
107 assertEquals(s.getVideoTracks().length, 1); | 110 assertEquals(duplicate.getVideoTracks().length, 1); |
108 assertEquals(s.getVideoTracks().length, 1); | 111 assertEquals(duplicate.getVideoTracks().length, 1); |
109 assertNotEquals(stream.getVideoTracks()[0].id, | 112 assertNotEquals(stream.getVideoTracks()[0].id, |
110 s.getVideoTracks()[0].id) | 113 duplicate.getVideoTracks()[0].id) |
111 displayAndDetectVideo( | 114 detectVideoInLocalView1( |
112 s, | 115 duplicate, |
113 function() { | 116 function() { |
114 reportTestSuccess(); | 117 reportTestSuccess(); |
115 }); | 118 }); |
116 }, | 119 }, |
117 failedCallback); | 120 failedCallback); |
118 } | 121 } |
119 | 122 |
120 // Creates a MediaStream and renders it locally. When the video is detected to | 123 // Creates a MediaStream and renders it locally. When the video is detected to |
121 // be rolling we return ok-stream-running through the automation controller. | 124 // be rolling we report success. The acquired stream is stored in window |
122 function getUserMediaAndGetStreamUp(constraints, waitTimeInSeconds) { | 125 // under the name |streamName|. |
126 function getUserMediaAndGetStreamUp(constraints, streamName) { | |
123 console.log('Calling getUserMediaAndGetStreamUp.'); | 127 console.log('Calling getUserMediaAndGetStreamUp.'); |
124 navigator.webkitGetUserMedia( | 128 navigator.webkitGetUserMedia( |
125 constraints, | 129 constraints, |
126 function(stream) { | 130 function(stream) { |
127 displayAndDetectVideo( | 131 window[streamName] = stream; |
132 detectVideoInLocalView1( | |
128 stream, | 133 stream, |
129 function() { | 134 function() { |
130 reportTestSuccess(); | 135 reportTestSuccess(); |
131 }); | 136 }); |
132 }, | 137 }, |
133 failedCallback); | 138 failedCallback); |
134 } | 139 } |
135 | 140 |
136 function getUserMediaAndRenderInSeveralVideoTags() { | 141 function getUserMediaAndRenderInSeveralVideoTags() { |
137 navigator.webkitGetUserMedia( | 142 navigator.webkitGetUserMedia( |
(...skipping 15 matching lines...) Expand all Loading... | |
153 function getUserMediaAndClone() { | 158 function getUserMediaAndClone() { |
154 console.log('Calling getUserMediaAndClone.'); | 159 console.log('Calling getUserMediaAndClone.'); |
155 navigator.webkitGetUserMedia({video: true, audio: true}, | 160 navigator.webkitGetUserMedia({video: true, audio: true}, |
156 createAndRenderClone, failedCallback); | 161 createAndRenderClone, failedCallback); |
157 } | 162 } |
158 | 163 |
159 // Creates two MediaStream and renders them locally. When the video of both | 164 // Creates two MediaStream and renders them locally. When the video of both |
160 // streams are detected to be rolling, we stop the local video tracks one at | 165 // streams are detected to be rolling, we stop the local video tracks one at |
161 // the time. | 166 // the time. |
162 function twoGetUserMediaAndStop(constraints) { | 167 function twoGetUserMediaAndStop(constraints) { |
163 console.log('Calling Two GetUserMedia'); | 168 // TODO(phoglund): make gUM requests in parallel; this test is too slow |
perkj_chrome
2014/10/07 13:07:23
its not the actual request that is slow right? It
phoglund_chromium
2014/10/07 13:57:53
No, I mean that the cycle of detect - gum - detect
| |
169 // and flakes on slow bots (http://crbug.com/417756). | |
170 var stream1 = null; | |
171 var stream2 = null; | |
164 navigator.webkitGetUserMedia( | 172 navigator.webkitGetUserMedia( |
165 constraints, | 173 constraints, |
166 function(stream) { | 174 function(stream) { |
167 displayAndDetectVideo(stream, requestSecondGetUserMedia); | 175 stream1 = stream; |
176 detectVideoInLocalView1(stream, requestSecondGetUserMedia); | |
168 }, | 177 }, |
169 failedCallback); | 178 failedCallback); |
170 var requestSecondGetUserMedia = function() { | 179 var requestSecondGetUserMedia = function() { |
171 navigator.webkitGetUserMedia( | 180 navigator.webkitGetUserMedia( |
172 constraints, | 181 constraints, |
173 function(stream) { | 182 function(stream) { |
174 displayIntoVideoElement(stream, | 183 stream2 = stream; |
175 function() { | 184 attachMediaStream(stream, 'local-view-2'); |
176 stopBothVideoTracksAndVerify(stream); | 185 detectVideoPlaying('local-view-2', stopBothVideoTracksAndVerify); |
177 }, | |
178 'local-view-2'); | |
179 }, | 186 }, |
180 failedCallback); | 187 failedCallback); |
181 }; | 188 }; |
182 | 189 |
183 var stopBothVideoTracksAndVerify = function(streamPlayingInLocalView2) { | 190 var stopBothVideoTracksAndVerify = function() { |
184 streamPlayingInLocalView2.getVideoTracks()[0].stop(); | 191 // Stop track 2, ensure that stops track 2 but not track 1, then stop |
192 // track 1. | |
193 stream2.getVideoTracks()[0].stop(); | |
194 waitForVideoToStop('local-view-1'); | |
185 waitForVideoToStop('local-view-2'); | 195 waitForVideoToStop('local-view-2'); |
186 // Make sure the video track in gLocalStream is still playing in | 196 detectVideoInLocalView1(stream1, function() { |
187 // 'local-view1' and then stop it. | 197 stream1.getVideoTracks()[0].stop(); |
188 displayAndDetectVideo(gLocalStream, stopVideoTrack); | 198 }); |
189 }; | 199 }; |
190 } | 200 } |
191 | 201 |
192 function twoGetUserMedia(constraints1, | 202 function twoGetUserMedia(constraints1, |
193 constraints2) { | 203 constraints2) { |
204 // TODO(phoglund): make gUM requests in parallel; this test is too slow | |
205 // and flakes on slow bots (http://crbug.com/417756). | |
194 var result=""; | 206 var result=""; |
195 navigator.webkitGetUserMedia( | 207 navigator.webkitGetUserMedia( |
196 constraints1, | 208 constraints1, |
197 function(stream) { | 209 function(stream) { |
198 displayDetectAndAnalyzeVideoInElement( | 210 displayDetectAndAnalyzeVideoInElement( |
199 stream, | 211 stream, |
200 function(aspectRatio) { | 212 function(aspectRatio) { |
201 result = aspectRatio; | 213 result = aspectRatio; |
202 requestSecondGetUserMedia(); | 214 requestSecondGetUserMedia(); |
203 }, | 215 }, |
204 'local-view'); | 216 'local-view-1'); |
205 }, | 217 }, |
206 failedCallback); | 218 failedCallback); |
207 var requestSecondGetUserMedia = function() { | 219 var requestSecondGetUserMedia = function() { |
208 navigator.webkitGetUserMedia( | 220 navigator.webkitGetUserMedia( |
209 constraints2, | 221 constraints2, |
210 function(stream) { | 222 function(stream) { |
211 displayDetectAndAnalyzeVideoInElement( | 223 displayDetectAndAnalyzeVideoInElement( |
212 stream, | 224 stream, |
213 function(aspectRatio) { | 225 function(aspectRatio) { |
214 result = result + '-' + aspectRatio; | 226 result = result + '-' + aspectRatio; |
215 sendValueToTest(result); | 227 sendValueToTest(result); |
216 }, | 228 }, |
217 'local-view-2'); | 229 'local-view-2'); |
218 }, | 230 }, |
219 failedCallback); | 231 failedCallback); |
220 } | 232 } |
221 } | 233 } |
222 | 234 |
223 // Calls GetUserMedia twice and verify that the frame rate is as expected for | 235 // Calls GetUserMedia twice and verify that the frame rate is as expected for |
224 // both streams. | 236 // both streams. |
225 function twoGetUserMediaAndVerifyFrameRate(constraints1, | 237 function twoGetUserMediaAndVerifyFrameRate(constraints1, |
226 constraints2, | 238 constraints2, |
227 expected_frame_rate1, | 239 expected_frame_rate1, |
228 expected_frame_rate2) { | 240 expected_frame_rate2) { |
241 // TODO(phoglund): make gUM requests in parallell; this test is too slow | |
242 // and flakes on slow bots (http://crbug.com/417756). | |
229 addExpectedEvent(); | 243 addExpectedEvent(); |
230 addExpectedEvent(); | 244 addExpectedEvent(); |
231 var validateFrameRateCallback = function (success) { | 245 var validateFrameRateCallback = function (success) { |
232 if (!success) | 246 if (!success) |
233 failTest("Failed to validate frameRate."); | 247 failTest("Failed to validate frameRate."); |
234 eventOccured(); | 248 eventOccured(); |
235 }; | 249 }; |
236 | 250 |
237 navigator.webkitGetUserMedia( | 251 navigator.webkitGetUserMedia( |
238 constraints1, | 252 constraints1, |
239 function(stream) { | 253 function(stream) { |
240 requestSecondGetUserMedia(); | 254 requestSecondGetUserMedia(); |
241 plugStreamIntoVideoElement(stream, 'local-view'); | 255 attachMediaStream(stream, 'local-view-1'); |
242 detectVideoPlaying('local-view', | 256 detectVideoPlaying('local-view-1', |
243 function() { | 257 function() { |
244 validateFrameRate('local-view', expected_frame_rate1, | 258 validateFrameRate('local-view-1', expected_frame_rate1, |
245 validateFrameRateCallback); | 259 validateFrameRateCallback); |
246 }); | 260 }); |
247 }, | 261 }, |
248 failedCallback); | 262 failedCallback); |
249 var requestSecondGetUserMedia = function() { | 263 var requestSecondGetUserMedia = function() { |
250 navigator.webkitGetUserMedia( | 264 navigator.webkitGetUserMedia( |
251 constraints2, | 265 constraints2, |
252 function(stream) { | 266 function(stream) { |
253 plugStreamIntoVideoElement(stream, 'local-view-2'); | 267 attachMediaStream(stream, 'local-view-2'); |
254 detectVideoPlaying('local-view-2', | 268 detectVideoPlaying('local-view-2', |
255 function() { | 269 function() { |
256 validateFrameRate('local-view-2', expected_frame_rate2, | 270 validateFrameRate('local-view-2', expected_frame_rate2, |
257 validateFrameRateCallback); | 271 validateFrameRateCallback); |
258 }); | 272 }); |
259 }, | 273 }, |
260 failedCallback); | 274 failedCallback); |
261 } | 275 } |
262 } | 276 } |
263 | 277 |
264 function failedCallback(error) { | 278 function failedCallback(error) { |
265 failTest('GetUserMedia call failed with code ' + error.code); | 279 failTest('GetUserMedia call failed with code ' + error.code); |
266 } | 280 } |
267 | 281 |
268 function plugStreamIntoVideoElement(stream, videoElement) { | 282 function attachMediaStream(stream, videoElement) { |
269 gLocalStream = stream; | |
270 var localStreamUrl = URL.createObjectURL(stream); | 283 var localStreamUrl = URL.createObjectURL(stream); |
271 $(videoElement).src = localStreamUrl; | 284 $(videoElement).src = localStreamUrl; |
272 } | 285 } |
273 | 286 |
274 function displayIntoVideoElement(stream, callback, videoElement) { | 287 function detectVideoInLocalView1(stream, callback) { |
275 plugStreamIntoVideoElement(stream, videoElement); | 288 attachMediaStream(stream, 'local-view-1'); |
276 detectVideoPlaying(videoElement, callback); | 289 detectVideoPlaying('local-view-1', callback); |
277 } | |
278 | |
279 function displayAndDetectVideo(stream, callback) { | |
280 displayIntoVideoElement(stream, callback, 'local-view'); | |
281 } | 290 } |
282 | 291 |
283 function displayDetectAndAnalyzeVideo(stream) { | 292 function displayDetectAndAnalyzeVideo(stream) { |
284 displayDetectAndAnalyzeVideoInElement(stream, | 293 displayDetectAndAnalyzeVideoInElement(stream, |
285 function(aspectRatio) { | 294 function(aspectRatio) { |
286 sendValueToTest(aspectRatio); | 295 sendValueToTest(aspectRatio); |
287 }, | 296 }, |
288 'local-view'); | 297 'local-view-1'); |
289 } | 298 } |
290 | 299 |
291 function displayDetectAndAnalyzeVideoInElement( | 300 function displayDetectAndAnalyzeVideoInElement( |
292 stream, callback, videoElement) { | 301 stream, callback, videoElement) { |
293 plugStreamIntoVideoElement(stream, videoElement); | 302 attachMediaStream(stream, videoElement); |
294 detectAspectRatio(callback, videoElement); | 303 detectAspectRatio(callback, videoElement); |
295 } | 304 } |
296 | 305 |
297 function createAndRenderClone(stream) { | 306 function createAndRenderClone(stream) { |
298 gLocalStream = stream; | |
299 // TODO(perkj): --use-fake-device-for-media-stream do not currently | 307 // TODO(perkj): --use-fake-device-for-media-stream do not currently |
300 // work with audio devices and not all bots has a microphone. | 308 // work with audio devices and not all bots has a microphone. |
301 new_stream = new webkitMediaStream(); | 309 newStream = new webkitMediaStream(); |
302 new_stream.addTrack(stream.getVideoTracks()[0]); | 310 newStream.addTrack(stream.getVideoTracks()[0]); |
303 assertEquals(new_stream.getVideoTracks().length, 1); | 311 assertEquals(newStream.getVideoTracks().length, 1); |
304 if (stream.getAudioTracks().length > 0) { | 312 if (stream.getAudioTracks().length > 0) { |
305 new_stream.addTrack(stream.getAudioTracks()[0]); | 313 newStream.addTrack(stream.getAudioTracks()[0]); |
306 assertEquals(new_stream.getAudioTracks().length, 1); | 314 assertEquals(newStream.getAudioTracks().length, 1); |
307 new_stream.removeTrack(new_stream.getAudioTracks()[0]); | 315 newStream.removeTrack(newStream.getAudioTracks()[0]); |
308 assertEquals(new_stream.getAudioTracks().length, 0); | 316 assertEquals(newStream.getAudioTracks().length, 0); |
309 } | 317 } |
310 | 318 |
311 var newStreamUrl = URL.createObjectURL(new_stream); | 319 detectVideoInLocalView1(newStream, reportTestSuccess); |
312 $('local-view').src = newStreamUrl; | |
313 waitForVideo('local-view'); | |
314 } | 320 } |
315 | 321 |
316 function stopVideoTrack() { | 322 // Calls stop on |stream|'s video track after a delay and reports success. |
317 gLocalStream.getVideoTracks()[0].stop(); | 323 function waitAndStopVideoTrack(stream, waitTimeInSeconds) { |
318 waitForVideoToStop('local-view'); | 324 setTimeout(function() { |
319 } | 325 stream.getVideoTracks()[0].stop(); |
320 | 326 reportTestSuccess(); |
321 function waitAndStopVideoTrack(waitTimeInSeconds) { | 327 }, waitTimeInSeconds * 1000); |
322 setTimeout(stopVideoTrack, waitTimeInSeconds * 1000); | |
323 } | 328 } |
324 | 329 |
325 // This test make sure multiple video renderers can be created for the same | 330 // This test make sure multiple video renderers can be created for the same |
326 // local video track and make sure a renderer can still render if other | 331 // local video track and make sure a renderer can still render if other |
327 // renderers are paused. See http://crbug/352619. | 332 // renderers are paused. See http://crbug/352619. |
328 function createMultipleVideoRenderersAndPause(stream) { | 333 function createMultipleVideoRenderersAndPause(stream) { |
329 function createDetectableRenderer(stream, id) { | 334 function createDetectableRenderer(stream, id) { |
330 var video = document.createElement('video'); | 335 var video = document.createElement('video'); |
331 document.body.appendChild(video); | 336 document.body.appendChild(video); |
332 var localStreamUrl = URL.createObjectURL(stream); | 337 var localStreamUrl = URL.createObjectURL(stream); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
441 console.log(result); | 446 console.log(result); |
442 callback(result); | 447 callback(result); |
443 } | 448 } |
444 } | 449 } |
445 var detectorInterval = setInterval(detectorFunction, 50); | 450 var detectorInterval = setInterval(detectorFunction, 50); |
446 } | 451 } |
447 </script> | 452 </script> |
448 </head> | 453 </head> |
449 <body> | 454 <body> |
450 <table border="0"> | 455 <table border="0"> |
456 <!-- Canvases are named after their corresponding video elements. --> | |
451 <tr> | 457 <tr> |
452 <td><video width="320" height="240" id="local-view" | 458 <td><video id="local-view-1" width="320" height="240" autoplay |
453 autoplay="autoplay" style="display:none"></video></td> | 459 style="display:none"></video></td> |
454 <td><canvas id="local-view-canvas" | 460 <td><canvas id="local-view-1-canvas" width="320" height="240" |
455 style="display:none"></canvas></td> | 461 style="display:none"></canvas></td> |
456 </tr> | 462 </tr> |
457 <tr> | 463 <tr> |
458 <td><video width="320" height="240" id="local-view-2" | 464 <td><video id="local-view-2" width="320" height="240" autoplay |
459 autoplay style="display:none"></video></td> | 465 style="display:none"></video></td> |
460 <!-- Canvases are named after their corresponding video elements. --> | 466 <td><canvas id="local-view-2-canvas" width="320" height="240" |
461 <td><canvas width="320" height="240" id="local-view-2-canvas" | |
462 style="display:none"></canvas></td> | 467 style="display:none"></canvas></td> |
463 </tr> | 468 </tr> |
464 </table> | 469 </table> |
465 </body> | 470 </body> |
466 </html> | 471 </html> |
OLD | NEW |