Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: content/test/data/media/getusermedia-depth-capture.html

Issue 2476693002: WebGL & 16-bit video stream: upload to FLOAT texture. (Closed)
Patch Set: Lossless access to 16-bit video stream using WebGL GL_FLOAT texture. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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" src="depth_stream_test_utilities.js"></script> 4 <script type="text/javascript" src="depth_stream_test_utilities.js"></script>
5 <script type="text/javascript"> 5 <script type="text/javascript">
6 6
7 $ = function(id) { 7 $ = function(id) {
8 return document.getElementById(id); 8 return document.getElementById(id);
9 }; 9 };
10 10
11 setAllEventsOccuredHandler(function() { 11 setAllEventsOccuredHandler(function() {
12 reportTestSuccess(); 12 reportTestSuccess();
13 }); 13 });
14 14
15 // testVideoToImageBitmap is a layout test that we run here because 15 // testVideoToImageBitmap is a layout test that we run here because
16 // it requires --use-fake-device-for-media-capture. 16 // it requires --use-fake-device-for-media-capture.
17 function getDepthStreamAndCallCreateImageBitmap() { 17 function getDepthStreamAndCallCreateImageBitmap() {
18 console.log('Calling getDepthStreamAndCallCreateImageBitmap'); 18 console.log('Calling getDepthStreamAndCallCreateImageBitmap');
19 getFake16bitStream().then(function(stream) { 19 getFake16bitStream().then(function(stream) {
20 detectVideoInLocalView1(stream, function() { 20 detectVideoInLocalView1(stream, function() {
21 testVideoToImageBitmap('local-view-1', function() { 21 testVideoToImageBitmap('local-view-1', function() {
22 stream.getVideoTracks()[0].stop(); 22 stream.getVideoTracks()[0].stop();
23 waitForVideoToStop('local-view-1'); 23 waitForVideoToStop('local-view-1');
24 }, failedCallback); 24 }, failedCallback);
25 }); 25 });
26 }, 26 },
27 failedCallback); 27 failedCallback);
28 } 28 }
29
30 // testVideoToWebGLTexture is a layout test that we run here because it
31 // requires --use-fake-device-for-media-capture.
32 function getDepthStreamAndCallGLTexImage2D() {
33 console.log('Calling getDepthStreamAndCallGLTexImage2D');
34 getFake16bitStream().then(function(stream) {
35 detectVideoInLocalView1(stream, function() {
36 testVideoToWebGLTexture('local-view-1', function(skip_info) {
37 if (skip_info) {
38 console.log("SKIP getDepthStreamAndCallGLTexImage2D: " +
39 skip_info);
40 }
41 stream.getVideoTracks()[0].stop();
42 waitForVideoToStop('local-view-1');
43 }, failedCallback);
44 });
45 },
46 failedCallback);
47 }
29 48
30 function failedCallback(error) { 49 function failedCallback(error) {
31 failTest('GetUserMedia call failed with error name ' + error.name); 50 failTest('GetUserMedia call failed with error name ' + error.name);
32 } 51 }
33 52
34 function attachMediaStream(stream, videoElement) { 53 function attachMediaStream(stream, videoElement) {
35 var localStreamUrl = URL.createObjectURL(stream); 54 var localStreamUrl = URL.createObjectURL(stream);
36 $(videoElement).src = localStreamUrl; 55 $(videoElement).src = localStreamUrl;
37 } 56 }
38 57
39 function detectVideoInLocalView1(stream, callback) { 58 function detectVideoInLocalView1(stream, callback) {
40 attachMediaStream(stream, 'local-view-1'); 59 attachMediaStream(stream, 'local-view-1');
41 detectVideoPlaying('local-view-1', callback); 60 detectVideoPlaying('local-view-1', callback);
42 } 61 }
62
63 function testVideoToImageBitmap(videoElementName, success, error)
64 {
phoglund_chromium 2016/11/07 09:20:00 Nit: pull up braces to previous line (apply throug
aleksandar.stojiljkovic 2016/11/16 20:01:24 Done.
65 var bitmaps = {};
66 var video = $(videoElementName);
67 var canvas = document.createElement('canvas');
68 canvas.width = 96;
69 canvas.height = 96;
70 document.body.appendChild(canvas);
71 var p1 = createImageBitmap(video).then(function(imageBitmap) {
72 return runImageBitmapTest(imageBitmap, canvas, false); });
73 var p2 = createImageBitmap(video,
74 {imageOrientation: "none", premultiplyAlpha: "premultiply"}).then(
75 function(imageBitmap) {
76 return runImageBitmapTest(imageBitmap, canvas, false); });
77 var p3 = createImageBitmap(video,
78 {imageOrientation: "none", premultiplyAlpha: "default"}).then(
79 function(imageBitmap) {
80 return runImageBitmapTest(imageBitmap, canvas, false); });
81 var p4 = createImageBitmap(video,
82 {imageOrientation: "none", premultiplyAlpha: "none"}).then(
83 function(imageBitmap) {
84 return runImageBitmapTest(imageBitmap, canvas, false); });
85 var p5 = createImageBitmap(video,
86 {imageOrientation: "flipY", premultiplyAlpha: "premultiply"}).then(
87 function(imageBitmap) {
88 return runImageBitmapTest(imageBitmap, canvas, true); });
89 var p6 = createImageBitmap(video,
90 {imageOrientation: "flipY", premultiplyAlpha: "default"}).then(
91 function(imageBitmap) {
92 return runImageBitmapTest(imageBitmap, canvas, true); });
93 var p7 = createImageBitmap(video,
94 {imageOrientation: "flipY", premultiplyAlpha: "none"}).then(
95 function(imageBitmap) {
96 return runImageBitmapTest(imageBitmap, canvas, true); });
97 return Promise.all([p1, p2, p3, p4, p5, p6, p7]).then(success(), reason => {
98 return error({name: reason});
99 });
100 }
101
102 function runImageBitmapTest(bitmap, canvas, flip_y) {
103 var context = canvas.getContext('2d');
104 context.drawImage(bitmap,0,0);
105 var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
106 // Fake capture device 96x96 depth image is gradient. See also
107 // Draw16BitGradient in fake_video_capture_device.cc.
108 var color_step = 255.0 / (canvas.width + canvas.height);
109 return verifyPixels(imageData.data, canvas.width, canvas.height, flip_y,
110 color_step, 255, 2);
111 }
112
113 function testVideoToWebGLTexture(videoElementName, success, error)
phoglund_chromium 2016/11/07 09:20:00 Will you get clear test errors when any of the sub
aleksandar.stojiljkovic 2016/11/16 20:01:24 Done. The only reason to couple unsigned byte and
114 {
115 var video = $(videoElementName);
116 var canvas = document.createElement('canvas');
117 canvas.width = 96;
118 canvas.height = 96;
119 video.width = 96;
120 video.height = 96;
121 var gl = canvas.getContext('webgl');
122 if(!gl)
123 return error({name:"WebGL is not available."});
124 if(!gl.getExtension("OES_texture_float"))
125 return error({name:"OES_texture_float extension is not available."});
126 var p1 = testVideoToTexture2D(gl, gl.UNSIGNED_BYTE, video);
127 var p2 = testVideoToTextureCubemap(gl, gl.UNSIGNED_BYTE, video);
128 var p3 = testVideoToTexture2D(gl, gl.FLOAT, video);
129 var p4 = testVideoToTextureCubemap(gl, gl.FLOAT, video);
130 return Promise.all([p1, p2, p3, p4]).then(success(), reason => {
131 return error({name: reason});
132 });
133 }
134
135 function testVideoToTexture2D(gl, type, video)
136 {
137 // Premultiply alpha is ignored, so we test it in one iteration only.
138 var p1 = runWebGLTextureTest(gl, gl.TEXTURE_2D, gl.TEXTURE_2D, type, video,
139 false/*sub_image*/, false/*flip_y*/, true/*premultiply_alpha*/);
140 var p2 = runWebGLTextureTest(gl, gl.TEXTURE_2D, gl.TEXTURE_2D, type, video,
141 false/*sub_image*/, true/*flip_y*/, false/*premultiply_alpha*/);
142 var p3 = runWebGLTextureTest(gl, gl.TEXTURE_2D, gl.TEXTURE_2D, type, video,
143 true/*sub_image*/, false/*flip_y*/, false/*premultiply_alpha*/);
144 var p4 = runWebGLTextureTest(gl, gl.TEXTURE_2D, gl.TEXTURE_2D, type, video,
145 true/*sub_image*/, true/*flip_y*/, false/*premultiply_alpha*/);
146 return Promise.all([p1, p2, p3, p4]).then(Promise.resolve(), reason => {
147 return Promise.reject(reason);
148 });
149 }
150
151 function testVideoToTextureCubemap(gl, type, video)
152 {
153 var p1 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
154 gl.TEXTURE_CUBE_MAP_POSITIVE_X, type, video, false/*sub_image*/,
155 false/*flip_y*/, true/*premultiply_alpha*/);
156 var p2 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
157 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, type, video, true/*sub_image*/,
158 false/*flip_y*/, true/*premultiply_alpha*/);
159 var p3 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
160 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, type, video, false/*sub_image*/,
161 true/*flip_y*/, true/*premultiply_alpha*/);
162 var p4 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
163 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, type, video, true/*sub_image*/,
164 true/*flip_y*/, true/*premultiply_alpha*/);
165 var p5 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
166 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, type, video, false/*sub_image*/,
167 false/*flip_y*/, false/*premultiply_alpha*/);
168 var p6 = runWebGLTextureTest(gl, gl.TEXTURE_CUBE_MAP,
169 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, type, video, true/*sub_image*/,
170 true/*flip_y*/, false/*premultiply_alpha*/);
171 return Promise.all([p1, p2, p3, p4, p5, p6]).then(Promise.resolve(),
172 reason => {
173 return Promise.reject(reason);
174 });
175 }
176
177 //For cubemap, binding_target is gl.TEXTURE_CUBE_MAP and target is a face id.
phoglund_chromium 2016/11/07 09:20:00 Nit: Space between // and For; this and next line
aleksandar.stojiljkovic 2016/11/16 20:01:24 Done.
178 //For gl.TEXTURE_2D, binding_target=target=gl.TEXTURE_2D.
179 function runWebGLTextureTest(gl, binding_target, target, type, video,
180 use_sub_image_2d, flip_y, premultiply_alpha) {
181 var tex = gl.createTexture();
phoglund_chromium 2016/11/07 09:20:00 Nit: indent 2 here, not 1
aleksandar.stojiljkovic 2016/11/16 20:01:24 Done.
182 gl.bindTexture(binding_target, tex);
183 gl.texParameteri(binding_target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
184 gl.texParameteri(binding_target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
185 gl.texParameteri(binding_target, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
186 gl.texParameteri(binding_target, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
187
188 // Create framebuffer that we will use for reading back the texture.
189 var fb = gl.createFramebuffer();
190 gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
191 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
192 target, tex, 0);
193
194 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flip_y);
195 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiply_alpha);
196
197 var targets = (binding_target == gl.TEXTURE_CUBE_MAP) ?
198 [gl.TEXTURE_CUBE_MAP_POSITIVE_X,
199 gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
200 gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
201 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
202 gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
203 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z] : [target];
204
205 // Upload the video frame into the texture.
206 for (var i = 0; i < targets.length; ++i) {
207 if (use_sub_image_2d) {
phoglund_chromium 2016/11/07 09:20:00 I don't like this kind of complexity in tests; the
aleksandar.stojiljkovic 2016/11/16 20:01:24 Done. Rewritten, no branching.
208 gl.texImage2D(targets[i], 0, gl.RGBA, video.width, video.height, 0,
209 gl.RGBA, type, null);
210 gl.texSubImage2D(targets[i], 0, 0, 0, gl.RGBA, type, video);
211 } else {
212 gl.texImage2D(targets[i], 0, gl.RGBA, gl.RGBA, type, video);
213 }
214 }
215
216 var arr = (type == gl.FLOAT) ?
217 new Float32Array(video.width * video.height * 4) :
218 new Uint8Array(video.width * video.height * 4);
219 // Read the texture attached to framebuffer.
220 gl.readPixels(0, 0, video.width, video.height, gl.RGBA, type, arr);
221 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
222 gl.deleteTexture(tex);
223 gl.deleteFramebuffer(fb);
224
225 if(type == gl.FLOAT) {
226 var color_step = 1.0 / (video.width + video.height);
227 return verifyPixels(arr, video.width, video.height, flip_y, color_step,
228 1.0 /*wrap_around*/, 1.5/65535 /*tolerance*/);
229 } else {
230 var color_step = 255.0 / (video.width + video.height);
231 return verifyPixels(arr, video.width, video.height, flip_y, color_step,
232 255 /*wrap_around*/, 2 /*tolerance*/);
233 }
234 }
43 </script> 235 </script>
44 </head> 236 </head>
45 <body> 237 <body>
46 <table border="0"> 238 <table border="0">
47 <!-- Canvases are named after their corresponding video elements. -->
48 <tr> 239 <tr>
49 <td><video id="local-view-1" width="96" height="96" autoplay 240 <td><video id="local-view-1" width="96" height="96" autoplay
50 style="display:none"></video></td> 241 style="display:none"></video></td>
242 <!-- The canvas is used to detect when video starts and stops. -->
51 <td><canvas id="local-view-1-canvas" width="96" height="96" 243 <td><canvas id="local-view-1-canvas" width="96" height="96"
52 style="display:none"></canvas></td> 244 style="display:none"></canvas></td>
53 </tr> 245 </tr>
54 </table> 246 </table>
55 </body> 247 </body>
56 </html> 248 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698