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