function Texture(gl) { this.gl = gl this.texture = gl.createTexture() gl.bindTexture(gl.TEXTURE_2D, this.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) } Texture.prototype.bind = function(n, program, name) { var gl = this.gl gl.activeTexture([gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2][n]) gl.bindTexture(gl.TEXTURE_2D, this.texture) gl.uniform1i(gl.getUniformLocation(program, name), n) } Texture.prototype.fill = function(width, height, data) { var gl = this.gl gl.bindTexture(gl.TEXTURE_2D, this.texture) gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data) } export function WebGLPlayer(canvas) { this.canvas = canvas this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl") this.initGL() } WebGLPlayer.prototype.initGL = function() { if (!this.gl) { console.log("[ER] WebGL not supported.") return } var gl = this.gl gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1) var program = gl.createProgram() var vertexShaderSource = [ "attribute highp vec4 aVertexPosition;", "attribute vec2 aTextureCoord;", "varying highp vec2 vTextureCoord;", "void main(void) {", " gl_Position = aVertexPosition;", " vTextureCoord = aTextureCoord;", "}" ].join("\n") var vertexShader = gl.createShader(gl.VERTEX_SHADER) gl.shaderSource(vertexShader, vertexShaderSource) gl.compileShader(vertexShader) var fragmentShaderSource = [ "precision highp float;", "varying lowp vec2 vTextureCoord;", "uniform sampler2D YTexture;", "uniform sampler2D UTexture;", "uniform sampler2D VTexture;", "const mat4 YUV2RGB = mat4", "(", " 1.1643828125, 0, 1.59602734375, -.87078515625,", " 1.1643828125, -.39176171875, -.81296875, .52959375,", " 1.1643828125, 2.017234375, 0, -1.081390625,", " 0, 0, 0, 1", ");", "void main(void) {", " gl_FragColor = vec4( texture2D(YTexture, vTextureCoord).x, texture2D(UTexture, vTextureCoord).x, texture2D(VTexture, vTextureCoord).x, 1) * YUV2RGB;", "}" ].join("\n") var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER) gl.shaderSource(fragmentShader, fragmentShaderSource) gl.compileShader(fragmentShader) gl.attachShader(program, vertexShader) gl.attachShader(program, fragmentShader) gl.linkProgram(program) gl.useProgram(program) if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { console.log("[ER] Shader link failed.") } var vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition") gl.enableVertexAttribArray(vertexPositionAttribute) var textureCoordAttribute = gl.getAttribLocation(program, "aTextureCoord") gl.enableVertexAttribArray(textureCoordAttribute) var verticesBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, verticesBuffer) gl.bufferData( gl.ARRAY_BUFFER, new Float32Array([1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0]), gl.STATIC_DRAW ) gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0) var texCoordBuffer = gl.createBuffer() gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer) gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0]), gl.STATIC_DRAW) gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0) gl.y = new Texture(gl) gl.u = new Texture(gl) gl.v = new Texture(gl) gl.y.bind(0, program, "YTexture") gl.u.bind(1, program, "UTexture") gl.v.bind(2, program, "VTexture") } WebGLPlayer.prototype.renderFrame = function(videoFrame, width, height) { if (!this.gl) { console.log("[ER] Render frame failed due to WebGL not supported.") return } var gl = this.gl gl.viewport(0, 0, gl.canvas.width, gl.canvas.height) gl.clearColor(0.0, 0.0, 0.0, 0.0) gl.clear(gl.COLOR_BUFFER_BIT) gl.y.fill(width, height, videoFrame.subarray(0, width * height)) gl.u.fill(width >> 1, height >> 1, videoFrame.subarray(width * height, (width * height * 5) / 4)) gl.v.fill(width >> 1, height >> 1, videoFrame.subarray((width * height * 5) / 4, (width * height * 3) / 2)) gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) } WebGLPlayer.prototype.fullscreen = function() { let canvas = this.canvas.parentNode.parentNode.parentNode if (canvas.RequestFullScreen) { canvas.RequestFullScreen() } else if (canvas.webkitRequestFullScreen) { canvas.webkitRequestFullScreen() } else if (canvas.mozRequestFullScreen) { canvas.mozRequestFullScreen() } else if (canvas.msRequestFullscreen) { canvas.msRequestFullscreen() } else { alert("This browser doesn't supporter fullscreen") } } WebGLPlayer.prototype.exitfullscreen = function() { if (document.exitFullscreen) { document.exitFullscreen() } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen() } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen() } else if (document.msExitFullscreen) { document.msExitFullscreen() } else { alert("Exit fullscreen doesn't work") } }