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")
|
}
|
}
|