agora-electron-sdk 4.5.1 → 4.5.2-dev.2
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/CHANGELOG.md +23 -0
- package/js/Decoder/gpu-utils.js +74 -0
- package/js/Decoder/index.js +172 -0
- package/js/Private/AgoraBase.js +15 -3
- package/js/Private/extension/AgoraBaseExtension.js +1 -0
- package/js/Private/internal/IrisApiEngine.js +20 -7
- package/js/Private/internal/RtcEngineExInternal.js +31 -16
- package/js/Private/ipc/main.js +21 -0
- package/js/Private/ipc/renderer.js +21 -0
- package/js/Renderer/CapabilityManager.js +99 -0
- package/js/Renderer/IRenderer.js +40 -11
- package/js/Renderer/IRendererCache.js +75 -0
- package/js/Renderer/RendererCache.js +26 -63
- package/js/Renderer/RendererManager.js +259 -38
- package/js/Renderer/WebCodecsRenderer/index.js +109 -0
- package/js/Renderer/WebCodecsRendererCache.js +115 -0
- package/js/Renderer/WebGLRenderer/index.js +115 -67
- package/js/Renderer/YUVCanvasRenderer/index.js +5 -3
- package/js/Renderer/index.js +0 -1
- package/js/Types.js +51 -1
- package/js/Utils.js +47 -7
- package/package.json +28 -11
- package/scripts/checkElectron.js +4 -2
- package/scripts/download.js +102 -0
- package/scripts/downloadPrebuild.js +2 -1
- package/scripts/synclib.js +2 -2
- package/ts/Decoder/gpu-utils.ts +92 -0
- package/ts/Decoder/index.ts +206 -0
- package/ts/Private/AgoraBase.ts +18 -4
- package/ts/Private/IAgoraRtcEngine.ts +6 -7
- package/ts/Private/IAgoraRtcEngineEx.ts +2 -1
- package/ts/Private/extension/AgoraBaseExtension.ts +14 -1
- package/ts/Private/internal/IrisApiEngine.ts +21 -7
- package/ts/Private/internal/RtcEngineExInternal.ts +27 -8
- package/ts/Private/ipc/main.ts +22 -0
- package/ts/Private/ipc/renderer.ts +21 -0
- package/ts/Renderer/CapabilityManager.ts +126 -0
- package/ts/Renderer/IRenderer.ts +52 -17
- package/ts/Renderer/IRendererCache.ts +96 -0
- package/ts/Renderer/RendererCache.ts +42 -85
- package/ts/Renderer/RendererManager.ts +342 -52
- package/ts/Renderer/WebCodecsRenderer/index.ts +145 -0
- package/ts/Renderer/WebCodecsRendererCache.ts +137 -0
- package/ts/Renderer/WebGLRenderer/index.ts +153 -107
- package/ts/Renderer/YUVCanvasRenderer/index.ts +24 -22
- package/ts/Renderer/index.ts +0 -1
- package/ts/Types.ts +130 -7
- package/ts/Utils.ts +53 -7
- package/types/Decoder/gpu-utils.d.ts +21 -0
- package/types/Decoder/gpu-utils.d.ts.map +1 -0
- package/types/Decoder/index.d.ts +26 -0
- package/types/Decoder/index.d.ts.map +1 -0
- package/types/Private/AgoraBase.d.ts +18 -4
- package/types/Private/AgoraBase.d.ts.map +1 -1
- package/types/Private/IAgoraRtcEngine.d.ts +6 -7
- package/types/Private/IAgoraRtcEngine.d.ts.map +1 -1
- package/types/Private/IAgoraRtcEngineEx.d.ts +2 -1
- package/types/Private/IAgoraRtcEngineEx.d.ts.map +1 -1
- package/types/Private/extension/AgoraBaseExtension.d.ts +13 -1
- package/types/Private/extension/AgoraBaseExtension.d.ts.map +1 -1
- package/types/Private/internal/IrisApiEngine.d.ts +2 -0
- package/types/Private/internal/IrisApiEngine.d.ts.map +1 -1
- package/types/Private/internal/RtcEngineExInternal.d.ts +2 -0
- package/types/Private/internal/RtcEngineExInternal.d.ts.map +1 -1
- package/types/Private/ipc/main.d.ts +2 -0
- package/types/Private/ipc/main.d.ts.map +1 -0
- package/types/Private/ipc/renderer.d.ts +3 -0
- package/types/Private/ipc/renderer.d.ts.map +1 -0
- package/types/Renderer/CapabilityManager.d.ts +20 -0
- package/types/Renderer/CapabilityManager.d.ts.map +1 -0
- package/types/Renderer/IRenderer.d.ts +8 -7
- package/types/Renderer/IRenderer.d.ts.map +1 -1
- package/types/Renderer/IRendererCache.d.ts +26 -0
- package/types/Renderer/IRendererCache.d.ts.map +1 -0
- package/types/Renderer/RendererCache.d.ts +6 -18
- package/types/Renderer/RendererCache.d.ts.map +1 -1
- package/types/Renderer/RendererManager.d.ts +49 -15
- package/types/Renderer/RendererManager.d.ts.map +1 -1
- package/types/Renderer/WebCodecsRenderer/index.d.ts +14 -0
- package/types/Renderer/WebCodecsRenderer/index.d.ts.map +1 -0
- package/types/Renderer/WebCodecsRendererCache.d.ts +15 -0
- package/types/Renderer/WebCodecsRendererCache.d.ts.map +1 -0
- package/types/Renderer/WebGLRenderer/index.d.ts +5 -3
- package/types/Renderer/WebGLRenderer/index.d.ts.map +1 -1
- package/types/Renderer/YUVCanvasRenderer/index.d.ts +1 -1
- package/types/Renderer/YUVCanvasRenderer/index.d.ts.map +1 -1
- package/types/Renderer/index.d.ts +0 -1
- package/types/Renderer/index.d.ts.map +1 -1
- package/types/Types.d.ts +99 -8
- package/types/Types.d.ts.map +1 -1
- package/types/Utils.d.ts +4 -0
- package/types/Utils.d.ts.map +1 -1
- package/js/Renderer/IRendererManager.js +0 -229
- package/scripts/publishCN/common.sh +0 -19
- package/scripts/publishCN/rewrite-dep.sh +0 -22
- package/scripts/publishCN/rewrite-example.sh +0 -22
- package/ts/Renderer/IRendererManager.ts +0 -316
- package/types/Renderer/IRendererManager.d.ts +0 -56
- package/types/Renderer/IRendererManager.d.ts.map +0 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import createAgoraRtcEngine from '../AgoraSdk';
|
|
2
|
+
import { WebCodecsDecoder } from '../Decoder/index';
|
|
3
|
+
import { EncodedVideoFrameInfo, VideoStreamType } from '../Private/AgoraBase';
|
|
4
|
+
import { IRtcEngineEx } from '../Private/IAgoraRtcEngineEx';
|
|
5
|
+
import { AgoraElectronBridge } from '../Private/internal/IrisApiEngine';
|
|
6
|
+
|
|
7
|
+
import { RendererContext, RendererType } from '../Types';
|
|
8
|
+
import { AgoraEnv, logInfo } from '../Utils';
|
|
9
|
+
|
|
10
|
+
import { IRendererCache, isUseConnection } from './IRendererCache';
|
|
11
|
+
import { WebCodecsRenderer } from './WebCodecsRenderer/index';
|
|
12
|
+
|
|
13
|
+
export class WebCodecsRendererCache extends IRendererCache {
|
|
14
|
+
private _decoder?: WebCodecsDecoder | null;
|
|
15
|
+
private _engine?: IRtcEngineEx;
|
|
16
|
+
private _firstFrame = true;
|
|
17
|
+
|
|
18
|
+
constructor(context: RendererContext) {
|
|
19
|
+
super(context);
|
|
20
|
+
this._engine = createAgoraRtcEngine();
|
|
21
|
+
this._decoder = new WebCodecsDecoder(
|
|
22
|
+
this.renderers as WebCodecsRenderer[],
|
|
23
|
+
this.onDecoderError.bind(this),
|
|
24
|
+
context
|
|
25
|
+
);
|
|
26
|
+
this.draw();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
onDecoderError(e: any) {
|
|
30
|
+
logInfo('webCodecsDecoder decode failed, fallback to native decoder', e);
|
|
31
|
+
AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
onEncodedVideoFrameReceived(...[data, buffer]: any) {
|
|
35
|
+
let _data: any;
|
|
36
|
+
try {
|
|
37
|
+
_data = JSON.parse(data) ?? {};
|
|
38
|
+
} catch (e) {
|
|
39
|
+
_data = {};
|
|
40
|
+
}
|
|
41
|
+
if (
|
|
42
|
+
Object.keys(_data).length === 0 ||
|
|
43
|
+
!this._decoder ||
|
|
44
|
+
this.cacheContext.uid !== _data.uid
|
|
45
|
+
)
|
|
46
|
+
return;
|
|
47
|
+
if (this._firstFrame) {
|
|
48
|
+
for (let renderer of this.renderers) {
|
|
49
|
+
if (renderer.rendererType !== RendererType.WEBCODECSRENDERER) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
renderer.bind(renderer.context.view);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
this._decoder.decoderConfigure(_data.videoEncodedFrameInfo);
|
|
57
|
+
} catch (error: any) {
|
|
58
|
+
logInfo(error);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this._firstFrame = false;
|
|
62
|
+
}
|
|
63
|
+
if (this.shouldFallback(_data.videoEncodedFrameInfo)) {
|
|
64
|
+
AgoraEnv.AgoraRendererManager?.handleWebCodecsFallback(this.cacheContext);
|
|
65
|
+
} else {
|
|
66
|
+
this._decoder.decodeFrame(
|
|
67
|
+
buffer,
|
|
68
|
+
_data.videoEncodedFrameInfo,
|
|
69
|
+
new Date().getTime()
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public draw() {
|
|
75
|
+
if (isUseConnection(this.cacheContext)) {
|
|
76
|
+
this._engine?.setRemoteVideoSubscriptionOptionsEx(
|
|
77
|
+
this.cacheContext.uid!,
|
|
78
|
+
{
|
|
79
|
+
type: VideoStreamType.VideoStreamHigh,
|
|
80
|
+
encodedFrameOnly: true,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
channelId: this.cacheContext.channelId,
|
|
84
|
+
localUid: this.cacheContext.localUid,
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
} else {
|
|
88
|
+
this._engine?.setRemoteVideoSubscriptionOptions(this.cacheContext.uid!, {
|
|
89
|
+
type: VideoStreamType.VideoStreamHigh,
|
|
90
|
+
encodedFrameOnly: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
AgoraElectronBridge.OnEvent(
|
|
94
|
+
`call_back_with_encoded_video_frame_${this.cacheContext.uid}`,
|
|
95
|
+
(...params: any) => {
|
|
96
|
+
try {
|
|
97
|
+
this.onEncodedVideoFrameReceived(...params);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.error(e);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public shouldFallback(frameInfo: EncodedVideoFrameInfo): boolean {
|
|
106
|
+
let shouldFallback = false;
|
|
107
|
+
if (!frameInfo.codecType) {
|
|
108
|
+
shouldFallback = true;
|
|
109
|
+
logInfo('codecType is not supported, fallback to native decoder');
|
|
110
|
+
} else {
|
|
111
|
+
const mapping =
|
|
112
|
+
AgoraEnv.CapabilityManager?.frameCodecMapping[frameInfo.codecType];
|
|
113
|
+
if (mapping === undefined) {
|
|
114
|
+
shouldFallback = true;
|
|
115
|
+
logInfo('codecType is not supported, fallback to native decoder');
|
|
116
|
+
} else if (
|
|
117
|
+
mapping.minWidth >= frameInfo.width! &&
|
|
118
|
+
mapping.minHeight >= frameInfo.height! &&
|
|
119
|
+
mapping.maxWidth <= frameInfo.width! &&
|
|
120
|
+
mapping.maxHeight <= frameInfo.height!
|
|
121
|
+
) {
|
|
122
|
+
shouldFallback = true;
|
|
123
|
+
logInfo('frame size is not supported, fallback to native decoder');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return shouldFallback;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public release(): void {
|
|
130
|
+
AgoraElectronBridge.UnEvent(
|
|
131
|
+
`call_back_with_encoded_video_frame_${this.cacheContext.uid}`
|
|
132
|
+
);
|
|
133
|
+
this._decoder?.release();
|
|
134
|
+
this._decoder = null;
|
|
135
|
+
super.release();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { VideoFrame } from '../../Private/AgoraMediaBase';
|
|
2
|
-
import {
|
|
2
|
+
import { RendererType } from '../../Types';
|
|
3
|
+
import { AgoraEnv, logWarn } from '../../Utils';
|
|
3
4
|
import { IRenderer } from '../IRenderer';
|
|
4
5
|
|
|
5
6
|
export type WebGLFallback = (renderer: WebGLRenderer, error: Error) => void;
|
|
@@ -7,59 +8,72 @@ export type WebGLFallback = (renderer: WebGLRenderer, error: Error) => void;
|
|
|
7
8
|
const createProgramFromSources =
|
|
8
9
|
require('./webgl-utils').createProgramFromSources;
|
|
9
10
|
|
|
10
|
-
const vertexShaderSource =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const yuvShaderSource =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
11
|
+
const vertexShaderSource = `
|
|
12
|
+
attribute vec2 a_position;
|
|
13
|
+
attribute vec2 a_texCoord;
|
|
14
|
+
uniform vec2 u_resolution;
|
|
15
|
+
varying vec2 v_texCoord;
|
|
16
|
+
void main() {
|
|
17
|
+
vec2 zeroToOne = a_position / u_resolution;
|
|
18
|
+
vec2 zeroToTwo = zeroToOne * 2.0;
|
|
19
|
+
vec2 clipSpace = zeroToTwo - 1.0;
|
|
20
|
+
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
|
|
21
|
+
v_texCoord = a_texCoord;
|
|
22
|
+
}`;
|
|
23
|
+
const yuvShaderSource = `
|
|
24
|
+
precision mediump float;
|
|
25
|
+
uniform sampler2D Ytex;
|
|
26
|
+
uniform sampler2D Utex;
|
|
27
|
+
uniform sampler2D Vtex;
|
|
28
|
+
uniform sampler2D Atex;
|
|
29
|
+
uniform bool hasAlpha;
|
|
30
|
+
varying vec2 v_texCoord;
|
|
31
|
+
void main(void) {
|
|
32
|
+
float nx,ny,r,g,b,y,u,v,a;
|
|
33
|
+
mediump vec4 txl,ux,vx;
|
|
34
|
+
nx=v_texCoord[0];
|
|
35
|
+
ny=v_texCoord[1];
|
|
36
|
+
y=texture2D(Ytex,vec2(nx,ny)).r;
|
|
37
|
+
u=texture2D(Utex,vec2(nx,ny)).r;
|
|
38
|
+
v=texture2D(Vtex,vec2(nx,ny)).r;
|
|
39
|
+
if (hasAlpha) {
|
|
40
|
+
a=texture2D(Atex,vec2(nx,ny)).r;
|
|
41
|
+
} else {
|
|
42
|
+
a=1.0;
|
|
43
|
+
}
|
|
44
|
+
y=1.1643*(y-0.0625);
|
|
45
|
+
u=u-0.5;
|
|
46
|
+
v=v-0.5;
|
|
47
|
+
r=y+1.5958*v;
|
|
48
|
+
g=y-0.39173*u-0.81290*v;
|
|
49
|
+
b=y+2.017*u;
|
|
50
|
+
gl_FragColor=vec4(r,g,b,a);
|
|
51
|
+
}`;
|
|
44
52
|
|
|
45
53
|
export class WebGLRenderer extends IRenderer {
|
|
46
|
-
gl
|
|
47
|
-
program
|
|
54
|
+
gl: WebGLRenderingContext | WebGL2RenderingContext | null;
|
|
55
|
+
program: WebGLProgram | null;
|
|
48
56
|
positionLocation?: number;
|
|
49
57
|
texCoordLocation?: number;
|
|
50
58
|
yTexture: WebGLTexture | null;
|
|
51
59
|
uTexture: WebGLTexture | null;
|
|
52
60
|
vTexture: WebGLTexture | null;
|
|
61
|
+
aTexture: WebGLTexture | null;
|
|
62
|
+
hasAlpha: WebGLUniformLocation | null;
|
|
53
63
|
texCoordBuffer: WebGLBuffer | null;
|
|
54
64
|
surfaceBuffer: WebGLBuffer | null;
|
|
55
65
|
fallback?: WebGLFallback;
|
|
56
66
|
|
|
57
67
|
constructor(fallback?: WebGLFallback) {
|
|
58
68
|
super();
|
|
59
|
-
this.gl =
|
|
69
|
+
this.gl = null;
|
|
70
|
+
this.rendererType = RendererType.WEBGL;
|
|
71
|
+
this.program = null;
|
|
60
72
|
this.yTexture = null;
|
|
61
73
|
this.uTexture = null;
|
|
62
74
|
this.vTexture = null;
|
|
75
|
+
this.aTexture = null;
|
|
76
|
+
this.hasAlpha = null;
|
|
63
77
|
this.texCoordBuffer = null;
|
|
64
78
|
this.surfaceBuffer = null;
|
|
65
79
|
this.fallback = fallback;
|
|
@@ -87,10 +101,10 @@ export class WebGLRenderer extends IRenderer {
|
|
|
87
101
|
const context = this.canvas?.getContext(contextName, {
|
|
88
102
|
depth: true,
|
|
89
103
|
stencil: true,
|
|
90
|
-
alpha:
|
|
104
|
+
alpha: true,
|
|
91
105
|
antialias: false,
|
|
92
106
|
premultipliedAlpha: true,
|
|
93
|
-
preserveDrawingBuffer:
|
|
107
|
+
preserveDrawingBuffer: !AgoraEnv.encodeAlpha,
|
|
94
108
|
powerPreference: 'default',
|
|
95
109
|
failIfMajorPerformanceCaveat: false,
|
|
96
110
|
});
|
|
@@ -112,11 +126,15 @@ export class WebGLRenderer extends IRenderer {
|
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
// Set clear color to black, fully opaque
|
|
115
|
-
this.gl.clearColor(0.0, 0.0, 0.0,
|
|
129
|
+
this.gl.clearColor(0.0, 0.0, 0.0, 0.0);
|
|
116
130
|
// Enable depth testing
|
|
117
131
|
this.gl.enable(this.gl.DEPTH_TEST);
|
|
118
132
|
// Near things obscure far things
|
|
119
133
|
this.gl.depthFunc(this.gl.LEQUAL);
|
|
134
|
+
// Enable blending
|
|
135
|
+
this.gl.enable(this.gl.BLEND);
|
|
136
|
+
// Set blending function
|
|
137
|
+
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
120
138
|
// Clear the color as well as the depth buffer.
|
|
121
139
|
this.gl.clear(
|
|
122
140
|
this.gl.COLOR_BUFFER_BIT |
|
|
@@ -147,7 +165,7 @@ export class WebGLRenderer extends IRenderer {
|
|
|
147
165
|
);
|
|
148
166
|
|
|
149
167
|
this.releaseTextures();
|
|
150
|
-
this.gl =
|
|
168
|
+
this.gl = null;
|
|
151
169
|
|
|
152
170
|
super.unbind();
|
|
153
171
|
}
|
|
@@ -162,6 +180,7 @@ export class WebGLRenderer extends IRenderer {
|
|
|
162
180
|
uBuffer,
|
|
163
181
|
vBuffer,
|
|
164
182
|
rotation,
|
|
183
|
+
alphaBuffer,
|
|
165
184
|
}: VideoFrame) {
|
|
166
185
|
this.rotateCanvas({ width, height, rotation });
|
|
167
186
|
this.updateRenderMode();
|
|
@@ -206,57 +225,81 @@ export class WebGLRenderer extends IRenderer {
|
|
|
206
225
|
|
|
207
226
|
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1);
|
|
208
227
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// Should use xWidth instead of width here (yStide)
|
|
216
|
-
xWidth,
|
|
217
|
-
height!,
|
|
218
|
-
0,
|
|
219
|
-
this.gl.LUMINANCE,
|
|
220
|
-
this.gl.UNSIGNED_BYTE,
|
|
221
|
-
yBuffer!
|
|
222
|
-
);
|
|
228
|
+
type TextureInfo = {
|
|
229
|
+
texture: WebGLTexture | null;
|
|
230
|
+
stride: number;
|
|
231
|
+
height: number;
|
|
232
|
+
pixels: ArrayBufferView | null;
|
|
233
|
+
};
|
|
223
234
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
this.gl.LUMINANCE,
|
|
230
|
-
uStride!,
|
|
231
|
-
height! / 2,
|
|
232
|
-
0,
|
|
233
|
-
this.gl.LUMINANCE,
|
|
234
|
-
this.gl.UNSIGNED_BYTE,
|
|
235
|
-
uBuffer!
|
|
236
|
-
);
|
|
235
|
+
const activeTexture = (
|
|
236
|
+
textureIndex: number,
|
|
237
|
+
{ texture, stride, height, pixels }: TextureInfo
|
|
238
|
+
) => {
|
|
239
|
+
if (!this.gl) return;
|
|
237
240
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
241
|
+
this.gl.activeTexture(textureIndex);
|
|
242
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
243
|
+
this.gl.texImage2D(
|
|
244
|
+
this.gl.TEXTURE_2D,
|
|
245
|
+
0,
|
|
246
|
+
this.gl.LUMINANCE,
|
|
247
|
+
stride,
|
|
248
|
+
height,
|
|
249
|
+
0,
|
|
250
|
+
this.gl.LUMINANCE,
|
|
251
|
+
this.gl.UNSIGNED_BYTE,
|
|
252
|
+
pixels
|
|
253
|
+
);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const textures: Record<number, TextureInfo> = {
|
|
257
|
+
[this.gl.TEXTURE0]: {
|
|
258
|
+
texture: this.yTexture,
|
|
259
|
+
stride: yStride!,
|
|
260
|
+
height: height!,
|
|
261
|
+
pixels: yBuffer!,
|
|
262
|
+
},
|
|
263
|
+
[this.gl.TEXTURE1]: {
|
|
264
|
+
texture: this.uTexture,
|
|
265
|
+
stride: uStride!,
|
|
266
|
+
height: height! / 2,
|
|
267
|
+
pixels: uBuffer!,
|
|
268
|
+
},
|
|
269
|
+
[this.gl.TEXTURE2]: {
|
|
270
|
+
texture: this.vTexture,
|
|
271
|
+
stride: vStride!,
|
|
272
|
+
height: height! / 2,
|
|
273
|
+
pixels: vBuffer!,
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
if (alphaBuffer) {
|
|
277
|
+
textures[this.gl.TEXTURE3] = {
|
|
278
|
+
texture: this.aTexture,
|
|
279
|
+
stride: width!,
|
|
280
|
+
height: height!,
|
|
281
|
+
pixels: alphaBuffer,
|
|
282
|
+
};
|
|
283
|
+
this.gl.uniform1i(this.hasAlpha, 1);
|
|
284
|
+
} else {
|
|
285
|
+
this.gl.uniform1i(this.hasAlpha, 0);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
for (const textureIndex in textures) {
|
|
289
|
+
if (textures.hasOwnProperty(textureIndex)) {
|
|
290
|
+
activeTexture(+textureIndex, textures[textureIndex]!);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
251
293
|
|
|
252
294
|
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
|
|
295
|
+
|
|
253
296
|
super.drawFrame();
|
|
254
297
|
}
|
|
255
298
|
|
|
256
299
|
protected override rotateCanvas({ width, height, rotation }: VideoFrame) {
|
|
257
300
|
super.rotateCanvas({ width, height, rotation });
|
|
258
301
|
|
|
259
|
-
if (!this.gl) return;
|
|
302
|
+
if (!this.gl || !this.program) return;
|
|
260
303
|
|
|
261
304
|
this.gl.viewport(0, 0, width!, height!);
|
|
262
305
|
|
|
@@ -328,34 +371,40 @@ export class WebGLRenderer extends IRenderer {
|
|
|
328
371
|
);
|
|
329
372
|
|
|
330
373
|
const resolutionLocation = this.gl.getUniformLocation(
|
|
331
|
-
this.program
|
|
374
|
+
this.program,
|
|
332
375
|
'u_resolution'
|
|
333
376
|
);
|
|
334
377
|
this.gl.uniform2f(resolutionLocation, width!, height!);
|
|
335
378
|
}
|
|
336
379
|
|
|
337
380
|
private initTextures() {
|
|
338
|
-
if (!this.gl) return;
|
|
381
|
+
if (!this.gl || !this.program) return;
|
|
339
382
|
|
|
340
383
|
this.positionLocation = this.gl.getAttribLocation(
|
|
341
|
-
this.program
|
|
384
|
+
this.program,
|
|
342
385
|
'a_position'
|
|
343
386
|
);
|
|
344
387
|
this.texCoordLocation = this.gl.getAttribLocation(
|
|
345
|
-
this.program
|
|
388
|
+
this.program,
|
|
346
389
|
'a_texCoord'
|
|
347
390
|
);
|
|
348
391
|
|
|
392
|
+
this.hasAlpha = this.gl.getUniformLocation(this.program, 'hasAlpha');
|
|
393
|
+
|
|
349
394
|
this.surfaceBuffer = this.gl.createBuffer();
|
|
350
395
|
this.texCoordBuffer = this.gl.createBuffer();
|
|
351
396
|
|
|
352
|
-
const createTexture = (
|
|
353
|
-
|
|
397
|
+
const createTexture = (
|
|
398
|
+
texture: number,
|
|
399
|
+
textureIndex: number,
|
|
400
|
+
textureName: string
|
|
401
|
+
) => {
|
|
402
|
+
if (!this.gl || !this.program) return null;
|
|
354
403
|
|
|
355
404
|
// Create a texture.
|
|
356
|
-
this.gl.activeTexture(
|
|
357
|
-
const
|
|
358
|
-
this.gl.bindTexture(this.gl.TEXTURE_2D,
|
|
405
|
+
this.gl.activeTexture(texture);
|
|
406
|
+
const textureObj = this.gl.createTexture();
|
|
407
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D, textureObj);
|
|
359
408
|
// Set the parameters so we can render any size
|
|
360
409
|
this.gl.texParameteri(
|
|
361
410
|
this.gl.TEXTURE_2D,
|
|
@@ -377,26 +426,23 @@ export class WebGLRenderer extends IRenderer {
|
|
|
377
426
|
this.gl.TEXTURE_MAG_FILTER,
|
|
378
427
|
this.gl.NEAREST
|
|
379
428
|
);
|
|
380
|
-
return texture;
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
this.yTexture = createTexture(this.gl.TEXTURE0);
|
|
384
|
-
this.uTexture = createTexture(this.gl.TEXTURE1);
|
|
385
|
-
this.vTexture = createTexture(this.gl.TEXTURE2);
|
|
386
429
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
430
|
+
this.gl.uniform1i(
|
|
431
|
+
this.gl.getUniformLocation(this.program, textureName),
|
|
432
|
+
textureIndex
|
|
433
|
+
); /* Bind Ytex to texture unit index */
|
|
434
|
+
return textureObj;
|
|
435
|
+
};
|
|
392
436
|
|
|
393
|
-
|
|
394
|
-
this.gl.
|
|
437
|
+
this.yTexture = createTexture(this.gl.TEXTURE0, 0, 'Ytex');
|
|
438
|
+
this.uTexture = createTexture(this.gl.TEXTURE1, 1, 'Utex');
|
|
439
|
+
this.vTexture = createTexture(this.gl.TEXTURE2, 2, 'Vtex');
|
|
440
|
+
this.aTexture = createTexture(this.gl.TEXTURE3, 3, 'Atex');
|
|
395
441
|
}
|
|
396
442
|
|
|
397
443
|
private releaseTextures() {
|
|
398
|
-
this.gl?.deleteProgram(this.program
|
|
399
|
-
this.program =
|
|
444
|
+
this.gl?.deleteProgram(this.program);
|
|
445
|
+
this.program = null;
|
|
400
446
|
|
|
401
447
|
this.positionLocation = undefined;
|
|
402
448
|
this.texCoordLocation = undefined;
|
|
@@ -24,35 +24,37 @@ export class YUVCanvasRenderer extends IRenderer {
|
|
|
24
24
|
uBuffer,
|
|
25
25
|
vBuffer,
|
|
26
26
|
rotation,
|
|
27
|
+
alphaBuffer,
|
|
27
28
|
}: VideoFrame) {
|
|
28
29
|
this.rotateCanvas({ width, height, rotation });
|
|
29
30
|
this.updateRenderMode();
|
|
30
31
|
|
|
31
32
|
if (!this.frameSink) return;
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
YUVBuffer.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
)
|
|
34
|
+
const frame = YUVBuffer.frame(
|
|
35
|
+
YUVBuffer.format({
|
|
36
|
+
width,
|
|
37
|
+
height,
|
|
38
|
+
chromaWidth: width! / 2,
|
|
39
|
+
chromaHeight: height! / 2,
|
|
40
|
+
cropLeft: yStride! - width!,
|
|
41
|
+
}),
|
|
42
|
+
{
|
|
43
|
+
bytes: yBuffer,
|
|
44
|
+
stride: yStride,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
bytes: uBuffer,
|
|
48
|
+
stride: uStride,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
bytes: vBuffer,
|
|
52
|
+
stride: vStride,
|
|
53
|
+
}
|
|
55
54
|
);
|
|
55
|
+
frame.a = alphaBuffer;
|
|
56
|
+
this.frameSink.drawFrame(frame);
|
|
57
|
+
|
|
56
58
|
super.drawFrame();
|
|
57
59
|
}
|
|
58
60
|
|
package/ts/Renderer/index.ts
CHANGED