2016-02-23 2 views
3

Можно ли использовать видео как текстуру для webGL в Safari (я даже не говорю о iOS Safari)? Я не мог заставить его работать. Вот самый простой код, который я мог бы воспроизвести: https://jsfiddle.net/bmkb6r9h/3/ и он тоже не работает here.HTML5 текстура видео в Safari

Не удается, как только источник видеосигнала поступает из другого домена или поддомена с SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent при прикреплении текстуры видео с помощью texImage2D.

Вот мой код (извините, это немного длиннее, но это то, как идет webGL). Также будем рады прокомментировать, как улучшить webGL. Я получил код от https://github.com/hawksley/eleVR-Web-Player, который представляет собой отличное введение в 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>

вещи работают отлично в Chrome/Firefox.

ответ

4

Это ошибка в Safari. Safari еще не поддерживает поддержку CORS (поддержка кросс-образования) для видео. См. this webkit bug.

Video does work in WebGL in Safari if the video is from the same origin.

+0

Да, похоже, отчет об ошибке. Что заставляет вас сказать, что скоро это будет исправлено? – Guig

+0

Извините, мой плохой. Я снял и увидел патч, но теперь вижу, что это сложнее, чем выглядит. – gman

+0

Хорошо, мы подождем и посмотрим, так как «Apple не комментирует сроки или содержание будущих выпусков» – Guig

Смежные вопросы