trtc-electron-sdk
Version:
trtc electron sdk
281 lines (280 loc) • 12.4 kB
JavaScript
"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;