UNPKG

trtc-electron-sdk

Version:

trtc electron sdk

281 lines (280 loc) 12.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // import { createProgramFromSources } from './webgl-utils.js'; const util_1 = require("../util"); const logger_1 = __importDefault(require("../../logger")); const createProgramFromSources = require('./webgl-utils').createProgramFromSources; const vertexShaderSource = 'attribute vec2 a_position;' + 'attribute vec2 a_texCoord;' + 'uniform vec2 u_resolution;' + 'varying vec2 v_texCoord;' + 'void main() {' + 'vec2 zeroToOne = a_position / u_resolution;' + ' vec2 zeroToTwo = zeroToOne * 2.0;' + ' vec2 clipSpace = zeroToTwo - 1.0;' + ' gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);' + 'v_texCoord = a_texCoord;' + '}'; const yuvShaderSource = 'precision mediump float;' + 'uniform sampler2D Ytex;' + 'uniform sampler2D Utex,Vtex;' + 'varying vec2 v_texCoord;' + 'void main(void) {' + ' float nx,ny,r,g,b,y,u,v;' + ' mediump vec4 txl,ux,vx;' + ' nx=v_texCoord[0];' + ' ny=v_texCoord[1];' + ' y=texture2D(Ytex,vec2(nx,ny)).r;' + ' u=texture2D(Utex,vec2(nx,ny)).r;' + ' v=texture2D(Vtex,vec2(nx,ny)).r;' + ' y=1.1643*(y-0.0625);' + ' u=u-0.5;' + ' v=v-0.5;' + ' r=y+1.5958*v;' + ' g=y-0.39173*u-0.81290*v;' + ' b=y+2.017*u;' + ' gl_FragColor=vec4(r,g,b,1.0);' + '}'; const createGL = function (canvas) { const errMsg = 'Create WebGL context failed'; let isSuccess = true; let gl = null; try { gl = canvas.getContext('webgl', { preserveDrawingBuffer: true }) || canvas.getContext("experimental-webgl"); } catch (err) { logger_1.default.warn('createGL error:', err); isSuccess = false; } if (!isSuccess || !gl) { throw new Error(errMsg); } return gl; }; class I420Canvas3DRenderer { constructor(canvas) { this.positionLocation = null; this.texCoordLocation = null; this.surfaceBuffer = null; this.texCoordBuffer = null; this.yTexture = null; this.uTexture = null; this.vTexture = null; try { this.gl = createGL(canvas); this.gl.enable(this.gl.DEPTH_TEST); this.gl.depthFunc(this.gl.LEQUAL); this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); this.glProgram = createProgramFromSources(this.gl, [vertexShaderSource, yuvShaderSource]); this.gl.useProgram(this.glProgram); this._initTextures(); logger_1.default.debug('gl created', this.gl, canvas); } catch (err) { logger_1.default.warn('I420RenderContextCreator.constructor() failed.', err); throw new Error('create WebGL context failed'); } } draw(data, width, height) { try { if (this.gl) { const yLength = width * height; const uLength = width * height / 4; const yPlane = new Uint8Array(data.buffer || data, 0, yLength); const uPlane = new Uint8Array(data.buffer || data, yLength, uLength); const vPlane = new Uint8Array(data.buffer || data, yLength + uLength, uLength); this._updateTexCoordLocation(); this._updateYUVTexImage2D(width, height, yPlane, uPlane, vPlane); this._updatePositionLocation(width, height); this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); } else { throw new Error('WebGL context is null'); } } catch (err) { logger_1.default.warn('I420Canvas3DRenderer.draw error:', err); } } destroy() { try { if (this.gl) { const glExtension = this.gl.getExtension('WEBGL_lose_context'); if (glExtension) { glExtension.loseContext(); } logger_1.default.debug('I420Canvas3DRenderer isContextLost:', this.gl.isContextLost()); } } catch (err) { logger_1.default.warn('I420Canvas3DRenderer.destroy', err); } this._deleteProgram(this.glProgram); this.glProgram = null; this.positionLocation = null; this.texCoordLocation = null; this._deleteTexture(this.yTexture); this._deleteTexture(this.uTexture); this._deleteTexture(this.vTexture); this.yTexture = null; this.uTexture = null; this.vTexture = null; this._deleteBuffer(this.texCoordBuffer); this._deleteBuffer(this.surfaceBuffer); this.texCoordBuffer = null; this.surfaceBuffer = null; this.gl = null; } _initTextures() { if (this.gl && this.glProgram) { this.positionLocation = this.gl.getAttribLocation(this.glProgram, 'a_position'); this.texCoordLocation = this.gl.getAttribLocation(this.glProgram, 'a_texCoord'); this.surfaceBuffer = this.gl.createBuffer(); this.texCoordBuffer = this.gl.createBuffer(); this.gl.activeTexture(this.gl.TEXTURE0); this.yTexture = this.gl.createTexture(); this.gl.bindTexture(this.gl.TEXTURE_2D, this.yTexture); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); this.gl.activeTexture(this.gl.TEXTURE1); this.uTexture = this.gl.createTexture(); this.gl.bindTexture(this.gl.TEXTURE_2D, this.uTexture); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); this.gl.activeTexture(this.gl.TEXTURE2); this.vTexture = this.gl.createTexture(); this.gl.bindTexture(this.gl.TEXTURE_2D, this.vTexture); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); const y = this.gl.getUniformLocation(this.glProgram, 'Ytex'); this.gl.uniform1i(y, 0); const u = this.gl.getUniformLocation(this.glProgram, 'Utex'); this.gl.uniform1i(u, 1); const v = this.gl.getUniformLocation(this.glProgram, 'Vtex'); this.gl.uniform1i(v, 2); } } _updateTexCoordLocation() { if (this.gl && this.texCoordLocation !== null) { // Update texCoord location this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer); this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([ 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1 ]), this.gl.STATIC_DRAW); this.gl.enableVertexAttribArray(this.texCoordLocation); this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 0, 0); } } _updatePositionLocation(width, height) { if (this.gl && this.positionLocation !== null && this.glProgram) { this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.surfaceBuffer); this.gl.enableVertexAttribArray(this.positionLocation); this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 0, 0); const p1 = { x: 0, y: 0 }; const p2 = { x: width, y: 0 }; const p3 = { x: width, y: height }; const p4 = { x: 0, y: height }; let pp1 = p1, pp2 = p2, pp3 = p3, pp4 = p4; // if (isNeedRotate) { // switch (rotation) { // case 0: // break; // case 90: // pp1 = p2; // pp2 = p3; // pp3 = p4; // pp4 = p1; // break; // case 180: // pp1 = p3; // pp2 = p4; // pp3 = p1; // pp4 = p2; // break; // case 270: // pp1 = p4; // pp2 = p1; // pp3 = p2; // pp4 = p3; // break; // default: // } // } this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([ pp1.x, pp1.y, pp2.x, pp2.y, pp4.x, pp4.y, pp4.x, pp4.y, pp2.x, pp2.y, pp3.x, pp3.y ]), this.gl.STATIC_DRAW); const resolutionLocation = this.gl.getUniformLocation(this.glProgram, 'u_resolution'); this.gl.uniform2f(resolutionLocation, width, height); } } _updateYUVTexImage2D(width, height, yplane, uplane, vplane) { if (this.gl) { let e; this.gl.activeTexture(this.gl.TEXTURE0); this.gl.bindTexture(this.gl.TEXTURE_2D, this.yTexture); this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1); this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width, height, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, yplane); if (util_1.config.getDebugMode()) { e = this.gl.getError(); if (e != this.gl.NO_ERROR) { logger_1.default.warn('upload y plane ', width, height, yplane.byteLength, ' error', e); } } this.gl.activeTexture(this.gl.TEXTURE1); this.gl.bindTexture(this.gl.TEXTURE_2D, this.uTexture); this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width / 2, height / 2, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, uplane); if (util_1.config.getDebugMode()) { e = this.gl.getError(); if (e != this.gl.NO_ERROR) { logger_1.default.warn('upload u plane ', width, height, uplane.byteLength, ' error', e); } } this.gl.activeTexture(this.gl.TEXTURE2); this.gl.bindTexture(this.gl.TEXTURE_2D, this.vTexture); this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width / 2, height / 2, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, vplane); if (util_1.config.getDebugMode()) { e = this.gl.getError(); if (e != this.gl.NO_ERROR) { logger_1.default.warn('upload v plane ', width, height, vplane.byteLength, ' error', e); } } } } _deleteTexture(texture) { if (texture && this.gl) { this.gl.deleteTexture(texture); } } _deleteBuffer(buffer) { if (buffer && this.gl) { this.gl.deleteBuffer(buffer); } } _deleteProgram(program) { if (program && this.gl) { this.gl.deleteProgram(program); } } } exports.default = I420Canvas3DRenderer;