|
@@ -0,0 +1,148 @@
|
|
|
|
+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);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+function WebGLPlayer(canvas, options) {
|
|
|
|
+ this.canvas = canvas;
|
|
|
|
+ this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
|
|
+ this.initGL(options);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+WebGLPlayer.prototype.initGL = function (options) {
|
|
|
|
+ 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, uOffset, vOffset) {
|
|
|
|
+ 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, uOffset));
|
|
|
|
+ gl.u.fill(width >> 1, height >> 1, videoFrame.subarray(uOffset, uOffset + vOffset));
|
|
|
|
+ gl.v.fill(width >> 1, height >> 1, videoFrame.subarray(uOffset + vOffset, videoFrame.length));
|
|
|
|
+
|
|
|
|
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+WebGLPlayer.prototype.fullscreen = function () {
|
|
|
|
+ var canvas = this.canvas;
|
|
|
|
+ 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");
|
|
|
|
+ }
|
|
|
|
+}
|