trtc-electron-sdk 10.3.402 → 10.3.403
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/liteav/Render/I420VideoRenderer/index.js +0 -9
- package/liteav/Render/util.js +0 -1
- package/liteav/Renderer/Canvas2DRenderer/index.d.ts +24 -0
- package/liteav/Renderer/Canvas2DRenderer/index.js +213 -0
- package/liteav/Renderer/Canvas3DRenderer/I420Canvas3DRenderer.d.ts +23 -0
- package/liteav/Renderer/Canvas3DRenderer/I420Canvas3DRenderer.js +276 -0
- package/liteav/Renderer/Canvas3DRenderer/ICanvas3DRenderer.d.ts +4 -0
- package/liteav/Renderer/Canvas3DRenderer/ICanvas3DRenderer.js +2 -0
- package/liteav/Renderer/Canvas3DRenderer/RGBACanvas3DRenderer.d.ts +8 -0
- package/liteav/Renderer/Canvas3DRenderer/RGBACanvas3DRenderer.js +163 -0
- package/liteav/Renderer/Canvas3DRenderer/index.d.ts +27 -0
- package/liteav/Renderer/Canvas3DRenderer/index.js +201 -0
- package/liteav/Renderer/Canvas3DRenderer/webgl-utils.js +1337 -0
- package/liteav/Renderer/IRenderer.d.ts +6 -0
- package/liteav/Renderer/IRenderer.js +2 -0
- package/liteav/Renderer/VideoRenderer/index.d.ts +25 -0
- package/liteav/Renderer/VideoRenderer/index.js +148 -0
- package/liteav/Renderer/index.d.ts +3 -0
- package/liteav/Renderer/index.js +38 -0
- package/liteav/Renderer/types.d.ts +19 -0
- package/liteav/Renderer/types.js +2 -0
- package/liteav/Renderer/util.d.ts +52 -0
- package/liteav/Renderer/util.js +181 -0
- package/liteav/Renderer/yuv-buffer.d.ts +189 -0
- package/liteav/Renderer/yuv-buffer.js +264 -0
- package/liteav/trtc.d.ts +6 -9
- package/liteav/trtc.js +100 -265
- package/package.json +7 -8
|
@@ -70,15 +70,6 @@ class I420VideoRenderer {
|
|
|
70
70
|
containerWidth: this.element.clientWidth,
|
|
71
71
|
containerHeight: this.element.clientHeight,
|
|
72
72
|
});
|
|
73
|
-
if (global.i420Frames) {
|
|
74
|
-
global.i420Frames.push(frameData);
|
|
75
|
-
if (global.i420Frames.length > 100) {
|
|
76
|
-
global.i420Frames.shift();
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
global.i420Frames = [frameData];
|
|
81
|
-
}
|
|
82
73
|
try {
|
|
83
74
|
const vf = new VideoFrame(frameData.data, {
|
|
84
75
|
format: 'I420',
|
package/liteav/Render/util.js
CHANGED
|
@@ -128,7 +128,6 @@ function calcVideoStyle(options = {
|
|
|
128
128
|
exports.calcVideoStyle = calcVideoStyle;
|
|
129
129
|
exports.config = new Config();
|
|
130
130
|
function allocBuffer(length, userId, streamType) {
|
|
131
|
-
console.debug('trtc:alloc buffer:', length, userId, streamType);
|
|
132
131
|
if (length >= 1) {
|
|
133
132
|
return Buffer.alloc(length);
|
|
134
133
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TRTCVideoFillMode, TRTCVideoPixelFormat } from "../../trtc_define";
|
|
2
|
+
import IRenderer from "../IRenderer";
|
|
3
|
+
import { TFrameData } from "../types";
|
|
4
|
+
declare class Canvas2dRenderer implements IRenderer {
|
|
5
|
+
private pixelFormat;
|
|
6
|
+
private viewContainer;
|
|
7
|
+
private contentMode;
|
|
8
|
+
private canvas;
|
|
9
|
+
private viewWrapper;
|
|
10
|
+
private cacheCanvasOptions;
|
|
11
|
+
private yuv;
|
|
12
|
+
constructor(pixelFormat: TRTCVideoPixelFormat, view: HTMLElement);
|
|
13
|
+
setContentMode(mode?: TRTCVideoFillMode): void;
|
|
14
|
+
private bind;
|
|
15
|
+
private unbind;
|
|
16
|
+
drawFrame(frameData: TFrameData): void;
|
|
17
|
+
_drawFrameI420(frameData: TFrameData): void;
|
|
18
|
+
private _drawFrameRGBA;
|
|
19
|
+
private _drawFrameBGRA;
|
|
20
|
+
private _updateCanvasStyle;
|
|
21
|
+
private _correctI420Data;
|
|
22
|
+
destroy(): void;
|
|
23
|
+
}
|
|
24
|
+
export default Canvas2dRenderer;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
|
|
7
|
+
const yuv_canvas_1 = __importDefault(require("yuv-canvas"));
|
|
8
|
+
const yuv_buffer_1 = __importDefault(require("../yuv-buffer"));
|
|
9
|
+
const trtc_define_1 = require("../../trtc_define");
|
|
10
|
+
const util_1 = require("../util");
|
|
11
|
+
class Canvas2dRenderer {
|
|
12
|
+
constructor(pixelFormat, view) {
|
|
13
|
+
this.pixelFormat = pixelFormat;
|
|
14
|
+
this.viewContainer = view;
|
|
15
|
+
this.contentMode = trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit;
|
|
16
|
+
const viewWrapper = document.createElement('div');
|
|
17
|
+
viewWrapper.className = 'trtc-2d';
|
|
18
|
+
Object.assign(viewWrapper.style, {
|
|
19
|
+
width: '100%',
|
|
20
|
+
height: '100%',
|
|
21
|
+
display: 'flex',
|
|
22
|
+
justifyContent: 'center',
|
|
23
|
+
alignItems: 'center'
|
|
24
|
+
});
|
|
25
|
+
this.viewWrapper = viewWrapper;
|
|
26
|
+
this.canvas = document.createElement('canvas');
|
|
27
|
+
this.viewWrapper.appendChild(this.canvas);
|
|
28
|
+
this.cacheCanvasOptions = {};
|
|
29
|
+
this.bind(view);
|
|
30
|
+
}
|
|
31
|
+
setContentMode(mode = trtc_define_1.TRTCVideoFillMode.TRTCVideoFillMode_Fit) {
|
|
32
|
+
this.contentMode = mode;
|
|
33
|
+
}
|
|
34
|
+
bind(viewContainer) {
|
|
35
|
+
this.viewContainer = viewContainer;
|
|
36
|
+
if (this.viewWrapper) {
|
|
37
|
+
this.viewContainer.appendChild(this.viewWrapper);
|
|
38
|
+
if (this.pixelFormat === trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420) {
|
|
39
|
+
this.yuv = yuv_canvas_1.default.attach(this.canvas, { webGL: false });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
unbind() {
|
|
44
|
+
this.viewWrapper && this.viewContainer && this.viewContainer.removeChild(this.viewWrapper);
|
|
45
|
+
this.viewContainer = null;
|
|
46
|
+
this.yuv = null;
|
|
47
|
+
}
|
|
48
|
+
drawFrame(frameData) {
|
|
49
|
+
switch (this.pixelFormat) {
|
|
50
|
+
case trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_I420:
|
|
51
|
+
this._drawFrameI420(frameData);
|
|
52
|
+
break;
|
|
53
|
+
case trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_RGBA32:
|
|
54
|
+
this._drawFrameRGBA(frameData);
|
|
55
|
+
break;
|
|
56
|
+
case trtc_define_1.TRTCVideoPixelFormat.TRTCVideoPixelFormat_BGRA32:
|
|
57
|
+
this._drawFrameBGRA(frameData);
|
|
58
|
+
break;
|
|
59
|
+
default:
|
|
60
|
+
console.warn('trtc:Canvas2dRenderer.drawFrame error. Not support video format:', this.pixelFormat);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
_drawFrameI420(frameData) {
|
|
64
|
+
try {
|
|
65
|
+
const { data, width, height, timestamp, rotation, isNeedRotate } = frameData;
|
|
66
|
+
if (width <= 0 || height <= 0) {
|
|
67
|
+
throw new Error(`wrong video parameter width:${width} or height:${height}`);
|
|
68
|
+
}
|
|
69
|
+
const yLength = width * height;
|
|
70
|
+
const uLength = width * height / 4;
|
|
71
|
+
const yPlane = new Uint8Array(data.buffer || data, 0, yLength);
|
|
72
|
+
const uPlane = new Uint8Array(data.buffer || data, yLength, uLength);
|
|
73
|
+
const vPlane = new Uint8Array(data.buffer || data, yLength + uLength, uLength);
|
|
74
|
+
const newFrameData = this._correctI420Data({ width, height, yUint8Array: yPlane, uUint8Array: uPlane, vUint8Array: vPlane });
|
|
75
|
+
const { width: newWidth, yUint8Array, uUint8Array, vUint8Array } = newFrameData;
|
|
76
|
+
if (this.viewWrapper && this.yuv) {
|
|
77
|
+
this._updateCanvasStyle({
|
|
78
|
+
contentWidth: newWidth,
|
|
79
|
+
contentHeight: height,
|
|
80
|
+
containerWidth: this.viewWrapper.clientWidth,
|
|
81
|
+
containerHeight: this.viewWrapper.clientHeight,
|
|
82
|
+
contentMode: this.contentMode,
|
|
83
|
+
rotation,
|
|
84
|
+
isNeedRotate,
|
|
85
|
+
isNeedMirror: false,
|
|
86
|
+
});
|
|
87
|
+
const format = yuv_buffer_1.default.format({
|
|
88
|
+
width: newWidth,
|
|
89
|
+
height,
|
|
90
|
+
chromaWidth: newWidth / 2,
|
|
91
|
+
chromaHeight: height / 2
|
|
92
|
+
});
|
|
93
|
+
const y = yuv_buffer_1.default.lumaPlane(format, yUint8Array);
|
|
94
|
+
const u = yuv_buffer_1.default.chromaPlane(format, uUint8Array);
|
|
95
|
+
const v = yuv_buffer_1.default.chromaPlane(format, vUint8Array);
|
|
96
|
+
const frame = yuv_buffer_1.default.frame(format, y, u, v);
|
|
97
|
+
this.yuv.drawFrame(frame);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw new Error('renderer container element is null');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error('trtc:Canvas2dRenderer._drawFrameI420 error:', err);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
_drawFrameRGBA(frameData) {
|
|
108
|
+
try {
|
|
109
|
+
const { data, width, height, timestamp, rotation, isNeedRotate } = frameData;
|
|
110
|
+
if (width <= 0 || height <= 0) {
|
|
111
|
+
throw new Error(`wrong video parameter width:${width} or height:${height}`);
|
|
112
|
+
}
|
|
113
|
+
if (this.viewWrapper && this.canvas) {
|
|
114
|
+
this._updateCanvasStyle({
|
|
115
|
+
contentWidth: width,
|
|
116
|
+
contentHeight: height,
|
|
117
|
+
containerWidth: this.viewWrapper.clientWidth,
|
|
118
|
+
containerHeight: this.viewWrapper.clientHeight,
|
|
119
|
+
contentMode: this.contentMode,
|
|
120
|
+
rotation,
|
|
121
|
+
isNeedRotate,
|
|
122
|
+
isNeedMirror: false,
|
|
123
|
+
});
|
|
124
|
+
const newImage = new ImageData(new Uint8ClampedArray(data.buffer || data), width, height);
|
|
125
|
+
const tempCanvas = document.createElement('canvas');
|
|
126
|
+
tempCanvas.width = width;
|
|
127
|
+
tempCanvas.height = height;
|
|
128
|
+
const tempCtx = tempCanvas.getContext('2d');
|
|
129
|
+
if (tempCtx) {
|
|
130
|
+
tempCtx.putImageData(newImage, 0, 0);
|
|
131
|
+
let ctx = this.canvas.getContext("2d");
|
|
132
|
+
if (ctx) {
|
|
133
|
+
ctx.drawImage(tempCanvas, 0, 0);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
throw new Error('draw video to canvas failed');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw new Error('draw video to temp canvas failed');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
throw new Error('renderer container element is null');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
console.error('trtc:Canvas2dRenderer._drawFrameRGBA error:', err);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
_drawFrameBGRA(frameData) {
|
|
152
|
+
this._drawFrameRGBA(Object.assign(Object.assign({}, frameData), { data: (0, util_1.transferBGRA2RGBA)(frameData.data, frameData.width, frameData.height) }));
|
|
153
|
+
}
|
|
154
|
+
_updateCanvasStyle(options) {
|
|
155
|
+
if (this.canvas) {
|
|
156
|
+
if ((0, lodash_isequal_1.default)(this.cacheCanvasOptions, options)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
this.cacheCanvasOptions = Object.assign({}, options);
|
|
160
|
+
const { width, height, transform } = (0, util_1.calcCanvasStyle)(options);
|
|
161
|
+
this.canvas.width = width;
|
|
162
|
+
this.canvas.height = height;
|
|
163
|
+
this.canvas.style.transform = transform;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
throw new Error('canvas element not exist');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
_correctI420Data(data) {
|
|
170
|
+
const { width, height, yUint8Array, uUint8Array, vUint8Array } = data;
|
|
171
|
+
const widthBase = 8;
|
|
172
|
+
const w8Modulo = width % widthBase;
|
|
173
|
+
if (w8Modulo !== 0) {
|
|
174
|
+
const newWidth = width - w8Modulo;
|
|
175
|
+
const newYSize = newWidth * height;
|
|
176
|
+
const newYArrayBuffer = new ArrayBuffer(newYSize);
|
|
177
|
+
const newYUint8Array = new Uint8Array(newYArrayBuffer);
|
|
178
|
+
let oldIndex = -1, newIndex = -1;
|
|
179
|
+
for (let h = 0; h < height; h += 1) {
|
|
180
|
+
for (let w = 0; w < newWidth; w += 1) {
|
|
181
|
+
oldIndex = width * h + w;
|
|
182
|
+
newIndex = newWidth * h + w;
|
|
183
|
+
newYUint8Array[newIndex] = yUint8Array[oldIndex];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
const oldChromaWidth = width / 2;
|
|
187
|
+
const newChromaWidth = newWidth / 2;
|
|
188
|
+
const chromaHeight = height / 2;
|
|
189
|
+
const newChromaSize = newChromaWidth * chromaHeight;
|
|
190
|
+
const newUArrayBuffer = new ArrayBuffer(newChromaSize);
|
|
191
|
+
const newUInt8Array = new Uint8Array(newUArrayBuffer);
|
|
192
|
+
const newVArrayBuffer = new ArrayBuffer(newChromaSize);
|
|
193
|
+
const newVInt8Array = new Uint8Array(newVArrayBuffer);
|
|
194
|
+
for (let h = 0; h < chromaHeight; h += 1) {
|
|
195
|
+
for (let w = 0; w < newChromaWidth; w += 1) {
|
|
196
|
+
oldIndex = oldChromaWidth * h + w;
|
|
197
|
+
newIndex = newChromaWidth * h + w;
|
|
198
|
+
newUInt8Array[newIndex] = uUint8Array[oldIndex];
|
|
199
|
+
newVInt8Array[newIndex] = vUint8Array[oldIndex];
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return Object.assign(Object.assign({}, data), { width: newWidth, height, yUint8Array: newYUint8Array, uUint8Array: newUInt8Array, vUint8Array: newVInt8Array });
|
|
203
|
+
}
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
destroy() {
|
|
207
|
+
this.unbind();
|
|
208
|
+
this.viewWrapper = null;
|
|
209
|
+
this.canvas = null;
|
|
210
|
+
this.cacheCanvasOptions = null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.default = Canvas2dRenderer;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ICanvas3DRenderer from './ICanvas3DRenderer';
|
|
2
|
+
declare class I420Canvas3DRenderer implements ICanvas3DRenderer {
|
|
3
|
+
private gl;
|
|
4
|
+
private glProgram;
|
|
5
|
+
private positionLocation;
|
|
6
|
+
private texCoordLocation;
|
|
7
|
+
private surfaceBuffer;
|
|
8
|
+
private texCoordBuffer;
|
|
9
|
+
private yTexture;
|
|
10
|
+
private uTexture;
|
|
11
|
+
private vTexture;
|
|
12
|
+
constructor(canvas: HTMLCanvasElement);
|
|
13
|
+
draw(data: ArrayBufferView, width: number, height: number): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
private _initTextures;
|
|
16
|
+
private _updateTexCoordLocation;
|
|
17
|
+
private _updatePositionLocation;
|
|
18
|
+
private _updateYUVTexImage2D;
|
|
19
|
+
private _deleteTexture;
|
|
20
|
+
private _deleteBuffer;
|
|
21
|
+
private _deleteProgram;
|
|
22
|
+
}
|
|
23
|
+
export default I420Canvas3DRenderer;
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// import { createProgramFromSources } from './webgl-utils.js';
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const createProgramFromSources = require('./webgl-utils').createProgramFromSources;
|
|
6
|
+
const vertexShaderSource = 'attribute vec2 a_position;'
|
|
7
|
+
+ 'attribute vec2 a_texCoord;'
|
|
8
|
+
+ 'uniform vec2 u_resolution;'
|
|
9
|
+
+ 'varying vec2 v_texCoord;'
|
|
10
|
+
+ 'void main() {'
|
|
11
|
+
+ 'vec2 zeroToOne = a_position / u_resolution;'
|
|
12
|
+
+ ' vec2 zeroToTwo = zeroToOne * 2.0;'
|
|
13
|
+
+ ' vec2 clipSpace = zeroToTwo - 1.0;'
|
|
14
|
+
+ ' gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);'
|
|
15
|
+
+ 'v_texCoord = a_texCoord;'
|
|
16
|
+
+ '}';
|
|
17
|
+
const yuvShaderSource = 'precision mediump float;'
|
|
18
|
+
+ 'uniform sampler2D Ytex;'
|
|
19
|
+
+ 'uniform sampler2D Utex,Vtex;'
|
|
20
|
+
+ 'varying vec2 v_texCoord;'
|
|
21
|
+
+ 'void main(void) {'
|
|
22
|
+
+ ' float nx,ny,r,g,b,y,u,v;'
|
|
23
|
+
+ ' mediump vec4 txl,ux,vx;'
|
|
24
|
+
+ ' nx=v_texCoord[0];'
|
|
25
|
+
+ ' ny=v_texCoord[1];'
|
|
26
|
+
+ ' y=texture2D(Ytex,vec2(nx,ny)).r;'
|
|
27
|
+
+ ' u=texture2D(Utex,vec2(nx,ny)).r;'
|
|
28
|
+
+ ' v=texture2D(Vtex,vec2(nx,ny)).r;'
|
|
29
|
+
+ ' y=1.1643*(y-0.0625);'
|
|
30
|
+
+ ' u=u-0.5;'
|
|
31
|
+
+ ' v=v-0.5;'
|
|
32
|
+
+ ' r=y+1.5958*v;'
|
|
33
|
+
+ ' g=y-0.39173*u-0.81290*v;'
|
|
34
|
+
+ ' b=y+2.017*u;'
|
|
35
|
+
+ ' gl_FragColor=vec4(r,g,b,1.0);'
|
|
36
|
+
+ '}';
|
|
37
|
+
const createGL = function (canvas) {
|
|
38
|
+
const errMsg = 'Create WebGL context failed';
|
|
39
|
+
let isSuccess = true;
|
|
40
|
+
let gl = null;
|
|
41
|
+
try {
|
|
42
|
+
gl = canvas.getContext('webgl', { preserveDrawingBuffer: true })
|
|
43
|
+
|| canvas.getContext("experimental-webgl");
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
console.warn('trtc:createGL error:', err);
|
|
47
|
+
isSuccess = false;
|
|
48
|
+
}
|
|
49
|
+
if (!isSuccess || !gl) {
|
|
50
|
+
throw new Error(errMsg);
|
|
51
|
+
}
|
|
52
|
+
return gl;
|
|
53
|
+
};
|
|
54
|
+
class I420Canvas3DRenderer {
|
|
55
|
+
constructor(canvas) {
|
|
56
|
+
this.positionLocation = null;
|
|
57
|
+
this.texCoordLocation = null;
|
|
58
|
+
this.surfaceBuffer = null;
|
|
59
|
+
this.texCoordBuffer = null;
|
|
60
|
+
this.yTexture = null;
|
|
61
|
+
this.uTexture = null;
|
|
62
|
+
this.vTexture = null;
|
|
63
|
+
try {
|
|
64
|
+
this.gl = createGL(canvas);
|
|
65
|
+
this.gl.enable(this.gl.DEPTH_TEST);
|
|
66
|
+
this.gl.depthFunc(this.gl.LEQUAL);
|
|
67
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
|
|
68
|
+
this.glProgram = createProgramFromSources(this.gl, [vertexShaderSource, yuvShaderSource]);
|
|
69
|
+
this.gl.useProgram(this.glProgram);
|
|
70
|
+
this._initTextures();
|
|
71
|
+
console.debug('trtc:gl created', this.gl, canvas);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.warn('trtc:I420RenderContextCreator.constructor() failed.', err);
|
|
75
|
+
throw new Error('create WebGL context failed');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
draw(data, width, height) {
|
|
79
|
+
try {
|
|
80
|
+
if (this.gl) {
|
|
81
|
+
const yLength = width * height;
|
|
82
|
+
const uLength = width * height / 4;
|
|
83
|
+
const yPlane = new Uint8Array(data.buffer || data, 0, yLength);
|
|
84
|
+
const uPlane = new Uint8Array(data.buffer || data, yLength, uLength);
|
|
85
|
+
const vPlane = new Uint8Array(data.buffer || data, yLength + uLength, uLength);
|
|
86
|
+
this._updateTexCoordLocation();
|
|
87
|
+
this._updateYUVTexImage2D(width, height, yPlane, uPlane, vPlane);
|
|
88
|
+
this._updatePositionLocation(width, height);
|
|
89
|
+
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw new Error('WebGL context is null');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.warn('trtc:I420Canvas3DRenderer.draw error:', err);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
destroy() {
|
|
100
|
+
try {
|
|
101
|
+
if (this.gl) {
|
|
102
|
+
const glExtension = this.gl.getExtension('WEBGL_lose_context');
|
|
103
|
+
if (glExtension) {
|
|
104
|
+
glExtension.loseContext();
|
|
105
|
+
}
|
|
106
|
+
console.debug('trtc:I420Canvas3DRenderer isContextLost:', this.gl.isContextLost());
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
console.warn('trtc:I420Canvas3DRenderer.destroy', err);
|
|
111
|
+
}
|
|
112
|
+
this._deleteProgram(this.glProgram);
|
|
113
|
+
this.glProgram = null;
|
|
114
|
+
this.positionLocation = null;
|
|
115
|
+
this.texCoordLocation = null;
|
|
116
|
+
this._deleteTexture(this.yTexture);
|
|
117
|
+
this._deleteTexture(this.uTexture);
|
|
118
|
+
this._deleteTexture(this.vTexture);
|
|
119
|
+
this.yTexture = null;
|
|
120
|
+
this.uTexture = null;
|
|
121
|
+
this.vTexture = null;
|
|
122
|
+
this._deleteBuffer(this.texCoordBuffer);
|
|
123
|
+
this._deleteBuffer(this.surfaceBuffer);
|
|
124
|
+
this.texCoordBuffer = null;
|
|
125
|
+
this.surfaceBuffer = null;
|
|
126
|
+
this.gl = null;
|
|
127
|
+
}
|
|
128
|
+
_initTextures() {
|
|
129
|
+
if (this.gl && this.glProgram) {
|
|
130
|
+
this.positionLocation = this.gl.getAttribLocation(this.glProgram, 'a_position');
|
|
131
|
+
this.texCoordLocation = this.gl.getAttribLocation(this.glProgram, 'a_texCoord');
|
|
132
|
+
this.surfaceBuffer = this.gl.createBuffer();
|
|
133
|
+
this.texCoordBuffer = this.gl.createBuffer();
|
|
134
|
+
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
135
|
+
this.yTexture = this.gl.createTexture();
|
|
136
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.yTexture);
|
|
137
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
138
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
139
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
140
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
141
|
+
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
142
|
+
this.uTexture = this.gl.createTexture();
|
|
143
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.uTexture);
|
|
144
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
145
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
146
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
147
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
148
|
+
this.gl.activeTexture(this.gl.TEXTURE2);
|
|
149
|
+
this.vTexture = this.gl.createTexture();
|
|
150
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.vTexture);
|
|
151
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
152
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
153
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
|
|
154
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
|
|
155
|
+
const y = this.gl.getUniformLocation(this.glProgram, 'Ytex');
|
|
156
|
+
this.gl.uniform1i(y, 0);
|
|
157
|
+
const u = this.gl.getUniformLocation(this.glProgram, 'Utex');
|
|
158
|
+
this.gl.uniform1i(u, 1);
|
|
159
|
+
const v = this.gl.getUniformLocation(this.glProgram, 'Vtex');
|
|
160
|
+
this.gl.uniform1i(v, 2);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
_updateTexCoordLocation() {
|
|
164
|
+
if (this.gl && this.texCoordLocation !== null) {
|
|
165
|
+
// Update texCoord location
|
|
166
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
|
|
167
|
+
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
|
|
168
|
+
0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1
|
|
169
|
+
]), this.gl.STATIC_DRAW);
|
|
170
|
+
this.gl.enableVertexAttribArray(this.texCoordLocation);
|
|
171
|
+
this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
_updatePositionLocation(width, height) {
|
|
175
|
+
if (this.gl && this.positionLocation !== null && this.glProgram) {
|
|
176
|
+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.surfaceBuffer);
|
|
177
|
+
this.gl.enableVertexAttribArray(this.positionLocation);
|
|
178
|
+
this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 0, 0);
|
|
179
|
+
const p1 = { x: 0, y: 0 };
|
|
180
|
+
const p2 = { x: width, y: 0 };
|
|
181
|
+
const p3 = { x: width, y: height };
|
|
182
|
+
const p4 = { x: 0, y: height };
|
|
183
|
+
let pp1 = p1, pp2 = p2, pp3 = p3, pp4 = p4;
|
|
184
|
+
// if (isNeedRotate) {
|
|
185
|
+
// switch (rotation) {
|
|
186
|
+
// case 0:
|
|
187
|
+
// break;
|
|
188
|
+
// case 90:
|
|
189
|
+
// pp1 = p2;
|
|
190
|
+
// pp2 = p3;
|
|
191
|
+
// pp3 = p4;
|
|
192
|
+
// pp4 = p1;
|
|
193
|
+
// break;
|
|
194
|
+
// case 180:
|
|
195
|
+
// pp1 = p3;
|
|
196
|
+
// pp2 = p4;
|
|
197
|
+
// pp3 = p1;
|
|
198
|
+
// pp4 = p2;
|
|
199
|
+
// break;
|
|
200
|
+
// case 270:
|
|
201
|
+
// pp1 = p4;
|
|
202
|
+
// pp2 = p1;
|
|
203
|
+
// pp3 = p2;
|
|
204
|
+
// pp4 = p3;
|
|
205
|
+
// break;
|
|
206
|
+
// default:
|
|
207
|
+
// }
|
|
208
|
+
// }
|
|
209
|
+
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
|
|
210
|
+
pp1.x,
|
|
211
|
+
pp1.y,
|
|
212
|
+
pp2.x,
|
|
213
|
+
pp2.y,
|
|
214
|
+
pp4.x,
|
|
215
|
+
pp4.y,
|
|
216
|
+
pp4.x,
|
|
217
|
+
pp4.y,
|
|
218
|
+
pp2.x,
|
|
219
|
+
pp2.y,
|
|
220
|
+
pp3.x,
|
|
221
|
+
pp3.y
|
|
222
|
+
]), this.gl.STATIC_DRAW);
|
|
223
|
+
const resolutionLocation = this.gl.getUniformLocation(this.glProgram, 'u_resolution');
|
|
224
|
+
this.gl.uniform2f(resolutionLocation, width, height);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
_updateYUVTexImage2D(width, height, yplane, uplane, vplane) {
|
|
228
|
+
if (this.gl) {
|
|
229
|
+
let e;
|
|
230
|
+
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
231
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.yTexture);
|
|
232
|
+
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);
|
|
233
|
+
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width, height, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, yplane);
|
|
234
|
+
if (util_1.config.getDebugMode()) {
|
|
235
|
+
e = this.gl.getError();
|
|
236
|
+
if (e != this.gl.NO_ERROR) {
|
|
237
|
+
console.log('trtc:upload y plane ', width, height, yplane.byteLength, ' error', e);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
this.gl.activeTexture(this.gl.TEXTURE1);
|
|
241
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.uTexture);
|
|
242
|
+
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width / 2, height / 2, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, uplane);
|
|
243
|
+
if (util_1.config.getDebugMode()) {
|
|
244
|
+
e = this.gl.getError();
|
|
245
|
+
if (e != this.gl.NO_ERROR) {
|
|
246
|
+
console.log('trtc:upload u plane ', width, height, uplane.byteLength, ' error', e);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
this.gl.activeTexture(this.gl.TEXTURE2);
|
|
250
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, this.vTexture);
|
|
251
|
+
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.LUMINANCE, width / 2, height / 2, 0, this.gl.LUMINANCE, this.gl.UNSIGNED_BYTE, vplane);
|
|
252
|
+
if (util_1.config.getDebugMode()) {
|
|
253
|
+
e = this.gl.getError();
|
|
254
|
+
if (e != this.gl.NO_ERROR) {
|
|
255
|
+
console.log('trtc:upload v plane ', width, height, vplane.byteLength, ' error', e);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
_deleteTexture(texture) {
|
|
261
|
+
if (texture && this.gl) {
|
|
262
|
+
this.gl.deleteTexture(texture);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
_deleteBuffer(buffer) {
|
|
266
|
+
if (buffer && this.gl) {
|
|
267
|
+
this.gl.deleteBuffer(buffer);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
_deleteProgram(program) {
|
|
271
|
+
if (program && this.gl) {
|
|
272
|
+
this.gl.deleteProgram(program);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
exports.default = I420Canvas3DRenderer;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import ICanvas3DRenderer from "./ICanvas3DRenderer";
|
|
2
|
+
declare class RGBACanvas3DRenderer implements ICanvas3DRenderer {
|
|
3
|
+
private gl;
|
|
4
|
+
constructor(canvas: HTMLCanvasElement);
|
|
5
|
+
draw(data: ArrayBufferView, width: number, height: number): void;
|
|
6
|
+
destroy(): void;
|
|
7
|
+
}
|
|
8
|
+
export default RGBACanvas3DRenderer;
|