javascript safari html5-canvas html5-video webgl

javascript - Textura de video HTML5 en Safari



html5-canvas html5-video (1)

¿Es posible usar videos como textura para webGL en Safari (ni siquiera estoy hablando de iOS Safari)? No podría hacerlo funcionar. Aquí está el código más simple que pude encontrar para reproducir: https://jsfiddle.net/bmkb6r9h/3/ y tampoco funciona aquí .

Falla tan pronto como la fuente de video proviene de otro dominio o subdominio con SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent al adjuntar la textura de video con texImage2D .

Aquí está mi código (lo siento, es un poco largo, pero así es como va el webGL) También me complace recibir comentarios sobre cómo mejorar el webGL. He tomado el código de https://github.com/hawksley/eleVR-Web-Player que es una gran introducción al reproductor de video 360.

// get DOM elements videoContainer = document.getElementById(''video-container''); video = document.getElementById(''video''); canvas = document.getElementById(''glcanvas''); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // load the video, and play on ready video.load(); video.oncanplaythrough = function() { video.play(); drawScene(); }; gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); // create and attach the shader program to the webGL context var attributes, uniforms, program; var attachShader = function(params) { // compile the shaders from the shaders scripts var getShaderByName = function(id) { var shaderScript = document.getElementById(id); var theSource = ""; var currentChild = shaderScript.firstChild; while(currentChild) { if (currentChild.nodeType === 3) { theSource += currentChild.textContent; } currentChild = currentChild.nextSibling; } var result; if (shaderScript.type === "x-shader/x-fragment") { result = gl.createShader(gl.FRAGMENT_SHADER); } else { result = gl.createShader(gl.VERTEX_SHADER); } gl.shaderSource(result, theSource); gl.compileShader(result); if (!gl.getShaderParameter(result, gl.COMPILE_STATUS)) { alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(result)); return null; } return result; }; fragmentShader = getShaderByName(params.fragmentShaderName); vertexShader = getShaderByName(params.vertexShaderName); program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(program)); } gl.useProgram(program); // get the location of attributes and uniforms attributes = {}; for (var i = 0; i < params.attributes.length; i++) { var attributeName = params.attributes[i]; attributes[attributeName] = gl.getAttribLocation(program, attributeName); gl.enableVertexAttribArray(attributes[attributeName]); } uniforms = {}; for (i = 0; i < params.uniforms.length; i++) { var uniformName = params.uniforms[i]; uniforms[uniformName] = gl.getUniformLocation(program, uniformName); gl.enableVertexAttribArray(attributes[uniformName]); } }; attachShader({ fragmentShaderName: ''shader-fs'', vertexShaderName: ''shader-vs'', attributes: [''aVertexPosition''], uniforms: [''uSampler''], }); // some webGL initialization gl.clearColor(0.0, 0.0, 0.0, 0.0); gl.clearDepth(1.0); gl.disable(gl.DEPTH_TEST); positionsBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionsBuffer); var positions = [ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); verticesIndexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, verticesIndexBuffer); var vertexIndices = [ 0, 1, 2, 0, 2, 3, ]; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndices), gl.STATIC_DRAW); texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.bindTexture(gl.TEXTURE_2D, null); // update the texture from the video updateTexture = function() { gl.bindTexture(gl.TEXTURE_2D, texture); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); // the next line fails in Safari if the video is coming from another domain or subdomain gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, video); gl.bindTexture(gl.TEXTURE_2D, null); }; // draw stuff in the canvas drawScene = function() { updateTexture(); gl.useProgram(program); gl.bindBuffer(gl.ARRAY_BUFFER, positionsBuffer); gl.vertexAttribPointer(attributes[''aVertexPosition''], 2, gl.FLOAT, false, 0, 0); // Specify the texture to map onto the faces. gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(uniforms[''uSampler''], 0); // Draw gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, verticesIndexBuffer); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); // keep looping requestAnimationFrame(drawScene); };

<!-- Fragmend shader program --> <script id="shader-fs" type="x-shader/x-fragment"> varying mediump vec2 vDirection; uniform sampler2D uSampler; void main(void) { gl_FragColor = texture2D(uSampler, vec2(vDirection.x * 0.5 + 0.5, vDirection.y * 0.5 + 0.5)); } </script> <!-- Vertex shader program --> <script id="shader-vs" type="x-shader/x-vertex"> attribute mediump vec2 aVertexPosition; varying mediump vec2 vDirection; void main(void) { gl_Position = vec4(aVertexPosition, 1.0, 1.0) * 2.0; vDirection = aVertexPosition; } </script> <div id="video-container" style="width: 100vw; height: 100vh;"> <canvas id="glcanvas"></canvas> <video preload="auto" id="video" loop="true" webkit-playsinline crossOrigin="anonymous" style=" width: 300px; height: 200px;" controls> <source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4"> </video> </div>

Las cosas funcionan perfectamente en Chrome / Firefox.