@havue/solutions 1.1.1 → 1.2.0
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/bc-connect/__tests__/bc-connect.spec.ts +73 -0
- package/bc-connect/dist/bc-connect.mjs +89 -73
- package/bc-connect/dist/bc-connect.umd.js +89 -73
- package/bc-connect/dist/types/src/manager.d.ts +72 -62
- package/bc-connect/package.json +1 -1
- package/bc-connect/src/manager.ts +103 -78
- package/dist/solutions.full.js +156 -127
- package/dist/solutions.full.min.js +4 -4
- package/dist/solutions.full.min.js.map +1 -1
- package/dist/types/bc-connect/src/manager.d.ts +72 -62
- package/dist/types/ws-video-manager/src/loader/websocket-loader.d.ts +13 -10
- package/dist/types/ws-video-manager/src/manager/index.d.ts +54 -37
- package/dist/types/ws-video-manager/src/render/drawer.d.ts +7 -7
- package/dist/types/ws-video-manager/src/render/index.d.ts +35 -19
- package/package.json +4 -4
- package/vite.config.ts +1 -1
- package/ws-video-manager/dist/types/src/loader/websocket-loader.d.ts +13 -10
- package/ws-video-manager/dist/types/src/manager/index.d.ts +54 -37
- package/ws-video-manager/dist/types/src/render/drawer.d.ts +7 -7
- package/ws-video-manager/dist/types/src/render/index.d.ts +35 -19
- package/ws-video-manager/dist/ws-video-manager.mjs +67 -54
- package/ws-video-manager/dist/ws-video-manager.umd.js +67 -54
- package/ws-video-manager/package.json +1 -1
- package/ws-video-manager/src/loader/websocket-loader.ts +15 -11
- package/ws-video-manager/src/manager/index.ts +57 -40
- package/ws-video-manager/src/render/drawer.ts +22 -20
- package/ws-video-manager/src/render/index.ts +61 -27
- package/ws-video-manager/src/render/mp4box.ts +1 -1
|
@@ -15,21 +15,31 @@ import { CanvasDrawer } from '../render/drawer'
|
|
|
15
15
|
|
|
16
16
|
// #region typedefine
|
|
17
17
|
export type WsVideoManaCstorOptionType = {
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* websocket流连接数量限制, 移动端默认10个,pc端默认32个
|
|
20
|
+
* Limit the number of websocket streaming connections to 10 by default for mobile and 32 by default for pc
|
|
21
|
+
*/
|
|
19
22
|
connectLimit?: number
|
|
20
|
-
/** WebSocketLoader
|
|
23
|
+
/** WebSocketLoader configuration */
|
|
21
24
|
wsOptions?: WebSocketOptionsType
|
|
22
25
|
/**
|
|
23
26
|
* websocket重连时,重新解析视频编码方式,
|
|
24
27
|
* 默认 true
|
|
28
|
+
*
|
|
29
|
+
* When the websocket reconnects, the video encoding is reparsed.
|
|
30
|
+
* The default is true
|
|
25
31
|
*/
|
|
26
32
|
reparseMimeOnReconnect?: boolean
|
|
27
33
|
/** Render 实例配置 */
|
|
28
34
|
renderOptions?: Partial<RenderConstructorOptionType>
|
|
29
35
|
/**
|
|
30
|
-
* 是否使用WebGL,
|
|
31
|
-
*
|
|
32
|
-
*
|
|
36
|
+
* 是否使用WebGL,默认 false,
|
|
37
|
+
* WebGL在不同游览器,以及受限于显存,不能同时创建过多WebGL上下文,一般8-16个
|
|
38
|
+
*
|
|
39
|
+
* Whether to use WebGL, false by default,
|
|
40
|
+
* WebGL can not be created too many WebGL contexts at the same time in different browsers,
|
|
41
|
+
* and due to the limitations of video memory, usually 8-16 WebGL contexts
|
|
42
|
+
*/
|
|
33
43
|
useWebgl?: boolean
|
|
34
44
|
}
|
|
35
45
|
|
|
@@ -44,11 +54,11 @@ const DEFAULT_OPTIONS: Required<WsVideoManaCstorOptionType> = Object.freeze({
|
|
|
44
54
|
})
|
|
45
55
|
|
|
46
56
|
type WsInfoType = {
|
|
47
|
-
/** 需要绘制的canvas
|
|
57
|
+
/** 需要绘制的canvas map | canvas map to be drawn */
|
|
48
58
|
canvasMap: Map<HTMLCanvasElement, CanvasDrawer>
|
|
49
|
-
/** WebSocketLoader
|
|
59
|
+
/** WebSocketLoader instance */
|
|
50
60
|
socket: WebSocketLoader
|
|
51
|
-
/**
|
|
61
|
+
/** Render instance */
|
|
52
62
|
render: Render
|
|
53
63
|
}
|
|
54
64
|
|
|
@@ -72,7 +82,7 @@ export const WsVideoManagerEventEnums = Object.assign({}, EventEnums, RenderEven
|
|
|
72
82
|
// #endregion typedefine
|
|
73
83
|
|
|
74
84
|
export class WsVideoManager extends EventBus<Events> {
|
|
75
|
-
/** socket
|
|
85
|
+
/** socket相关信息map | map of socket information */
|
|
76
86
|
private _wsInfoMap: Map<string, WsInfoType> = new Map()
|
|
77
87
|
|
|
78
88
|
private _option: Required<WsVideoManaCstorOptionType> = DEFAULT_OPTIONS
|
|
@@ -116,8 +126,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
116
126
|
}
|
|
117
127
|
|
|
118
128
|
/**
|
|
119
|
-
* 添加socket
|
|
120
|
-
* @param url socket
|
|
129
|
+
* 添加socket连接 | Adding a socket connection
|
|
130
|
+
* @param url socket url
|
|
121
131
|
* @returns
|
|
122
132
|
*/
|
|
123
133
|
private _addSocket(url: string, renderOptions?: Partial<RenderConstructorOptionType>) {
|
|
@@ -148,9 +158,9 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
148
158
|
}
|
|
149
159
|
|
|
150
160
|
/**
|
|
151
|
-
* 绑定render事件
|
|
152
|
-
* @param url 连接地址
|
|
153
|
-
* @param render Render
|
|
161
|
+
* 绑定render事件 | Binding the render event
|
|
162
|
+
* @param url 连接地址 | websocket url
|
|
163
|
+
* @param render Render instance
|
|
154
164
|
*/
|
|
155
165
|
private _bindRenderEvent(url: string, render: Render) {
|
|
156
166
|
render.on(RenderEventsEnum.AUDIO_STATE_CHANGE, (state) => {
|
|
@@ -165,8 +175,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
/**
|
|
168
|
-
*
|
|
169
|
-
* @param url socket
|
|
178
|
+
* Destroying the socket connect
|
|
179
|
+
* @param url socket url
|
|
170
180
|
*/
|
|
171
181
|
private _removeSocket(url: string) {
|
|
172
182
|
const wsInfo = this._wsInfoMap.get(url)
|
|
@@ -181,9 +191,9 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
181
191
|
}
|
|
182
192
|
|
|
183
193
|
/**
|
|
184
|
-
* 绑定socket事件
|
|
185
|
-
* @param url
|
|
186
|
-
* @param socket WebSocketLoader
|
|
194
|
+
* 绑定socket事件 | Binding socket events
|
|
195
|
+
* @param url websocket url
|
|
196
|
+
* @param socket WebSocketLoader instance
|
|
187
197
|
*/
|
|
188
198
|
private _bindSocketEvent(socket: WebSocketLoader, render: Render, url: string) {
|
|
189
199
|
socket.on('close', () => {
|
|
@@ -217,8 +227,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
217
227
|
}
|
|
218
228
|
|
|
219
229
|
/**
|
|
220
|
-
* url对应的 socket实例是否已存在
|
|
221
|
-
* @param url
|
|
230
|
+
* url对应的 socket实例是否已存在 | Whether the socket instance for the url already exists
|
|
231
|
+
* @param url websocket url
|
|
222
232
|
* @returns boolean
|
|
223
233
|
*/
|
|
224
234
|
private _isSocketExist(url: string): boolean {
|
|
@@ -227,8 +237,9 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
227
237
|
|
|
228
238
|
/**
|
|
229
239
|
* 添加url对应socket,以及需要绘制的canvas元素
|
|
230
|
-
*
|
|
231
|
-
* @param
|
|
240
|
+
* Add the socket for the url and the canvas element to draw
|
|
241
|
+
* @param canvas canvas
|
|
242
|
+
* @param url websocket url
|
|
232
243
|
*/
|
|
233
244
|
public addCanvas(canvas: HTMLCanvasElement, url: string, renderOptions?: Partial<RenderConstructorOptionType>) {
|
|
234
245
|
this._addSocket(url, renderOptions)
|
|
@@ -250,8 +261,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
250
261
|
}
|
|
251
262
|
|
|
252
263
|
/**
|
|
253
|
-
* 初始化canvas背景
|
|
254
|
-
* @param canvas canvas
|
|
264
|
+
* 初始化canvas背景 | Initialize the canvas background
|
|
265
|
+
* @param canvas canvas
|
|
255
266
|
* @returns
|
|
256
267
|
*/
|
|
257
268
|
// private _setupCanvas(canvas: HTMLCanvasElement) {
|
|
@@ -264,8 +275,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
264
275
|
// }
|
|
265
276
|
|
|
266
277
|
/**
|
|
267
|
-
* 删除canvas元素
|
|
268
|
-
* @param canvas canvas
|
|
278
|
+
* 删除canvas元素 || Remove the canvas element
|
|
279
|
+
* @param canvas canvas
|
|
269
280
|
*/
|
|
270
281
|
public removeCanvas(canvas: HTMLCanvasElement) {
|
|
271
282
|
const entries = this._wsInfoMap.entries()
|
|
@@ -284,8 +295,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
284
295
|
}
|
|
285
296
|
|
|
286
297
|
/**
|
|
287
|
-
*
|
|
288
|
-
* @param canvas canvas
|
|
298
|
+
* 获取canvas是否已经添加过 | Gets whether the canvas has already been added
|
|
299
|
+
* @param canvas canvas
|
|
289
300
|
* @returns boolean
|
|
290
301
|
*/
|
|
291
302
|
public isCanvasExist(canvas: HTMLCanvasElement): boolean {
|
|
@@ -295,14 +306,14 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
295
306
|
})
|
|
296
307
|
}
|
|
297
308
|
|
|
298
|
-
/** 设置全部render静音状态 */
|
|
309
|
+
/** 设置全部render静音状态 | Mute all render */
|
|
299
310
|
public setAllVideoMutedState(muted: boolean) {
|
|
300
311
|
this._wsInfoMap.forEach((wsInfo) => {
|
|
301
312
|
wsInfo.render.muted = muted
|
|
302
313
|
})
|
|
303
314
|
}
|
|
304
315
|
|
|
305
|
-
/** 更新单个render实例的配置 */
|
|
316
|
+
/** 更新单个render实例的配置 | Update the configuration of a single render instance */
|
|
306
317
|
public updateRenderOptions(url: string, options?: Partial<RenderConstructorOptionType>) {
|
|
307
318
|
if (options) {
|
|
308
319
|
const wsInfo = this._wsInfoMap.get(url)
|
|
@@ -311,9 +322,9 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
311
322
|
}
|
|
312
323
|
|
|
313
324
|
/**
|
|
314
|
-
* 设置单个render静音状态
|
|
325
|
+
* 设置单个render静音状态 | Set a single render to be silent
|
|
315
326
|
* @param url
|
|
316
|
-
* @param muted
|
|
327
|
+
* @param {boolean} muted 是否静音 | Muted or not
|
|
317
328
|
*/
|
|
318
329
|
public setOneMutedState(url: string, muted: boolean) {
|
|
319
330
|
const wsInfo = this._wsInfoMap.get(url)
|
|
@@ -325,7 +336,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
325
336
|
|
|
326
337
|
/**
|
|
327
338
|
* 获取url对应render video元素是否静音
|
|
328
|
-
*
|
|
339
|
+
* Gets whether the render video element of the url is muted
|
|
340
|
+
* @param url websocket url
|
|
329
341
|
*/
|
|
330
342
|
public getOneMutedState(url: string) {
|
|
331
343
|
const wsInfo = this._wsInfoMap.get(url)
|
|
@@ -337,7 +349,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
337
349
|
|
|
338
350
|
/**
|
|
339
351
|
* 单个解除静音,其他未静音的变成静音,只播放一个
|
|
340
|
-
*
|
|
352
|
+
* Unmute a single video and mute all other videos
|
|
353
|
+
* @param url websocket url
|
|
341
354
|
*/
|
|
342
355
|
public playOneAudio(url: string) {
|
|
343
356
|
this.setAllVideoMutedState(true)
|
|
@@ -346,6 +359,7 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
346
359
|
|
|
347
360
|
/**
|
|
348
361
|
* 设置单个render是否继续处理ws数据
|
|
362
|
+
* Sets whether a single render continues to process ws data
|
|
349
363
|
* @param url
|
|
350
364
|
*/
|
|
351
365
|
public setOneVideoPausedState(url: string, paused: boolean) {
|
|
@@ -356,7 +370,7 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
356
370
|
wsInfo.render.paused = paused
|
|
357
371
|
}
|
|
358
372
|
|
|
359
|
-
/** 设置全部render是否继续处理ws数据 */
|
|
373
|
+
/** 设置全部render是否继续处理ws数据 | Sets whether all render continues to process ws data */
|
|
360
374
|
public setAllVideoPausedState(paused: boolean) {
|
|
361
375
|
this._wsInfoMap.forEach((wsInfo) => {
|
|
362
376
|
wsInfo.render.paused = paused
|
|
@@ -364,8 +378,9 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
364
378
|
}
|
|
365
379
|
|
|
366
380
|
/**
|
|
367
|
-
* 获取url对应render video
|
|
368
|
-
*
|
|
381
|
+
* 获取url对应render video元素的播放状态
|
|
382
|
+
* Get the playback status of the render video element corresponding to the url
|
|
383
|
+
* @param url websocket url
|
|
369
384
|
*/
|
|
370
385
|
public getOneVideoPausedState(url: string) {
|
|
371
386
|
const wsInfo = this._wsInfoMap.get(url)
|
|
@@ -377,7 +392,8 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
377
392
|
|
|
378
393
|
/**
|
|
379
394
|
* 单个视频继续播放,其他暂停处理数据
|
|
380
|
-
*
|
|
395
|
+
* A single video continues to play while others pause to process data
|
|
396
|
+
* @param url websocket url
|
|
381
397
|
*/
|
|
382
398
|
public playOneVideo(url: string) {
|
|
383
399
|
this.setAllVideoPausedState(true)
|
|
@@ -386,6 +402,7 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
386
402
|
|
|
387
403
|
/**
|
|
388
404
|
* 刷新socket,以及播放时间
|
|
405
|
+
* Refresh the socket, and the playback time
|
|
389
406
|
*/
|
|
390
407
|
public refresh(url?: string) {
|
|
391
408
|
if (url) {
|
|
@@ -407,7 +424,7 @@ export class WsVideoManager extends EventBus<Events> {
|
|
|
407
424
|
}
|
|
408
425
|
|
|
409
426
|
/**
|
|
410
|
-
* 销毁
|
|
427
|
+
* 销毁 | Destroy
|
|
411
428
|
*/
|
|
412
429
|
public destroy() {
|
|
413
430
|
this._wsInfoMap.forEach((wsInfo) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 绘制视频到canvas中
|
|
2
|
+
* 绘制视频到canvas中 | Draw video into canvas
|
|
3
3
|
*/
|
|
4
4
|
class CanvasDrawer {
|
|
5
5
|
private _canvas: HTMLCanvasElement | null = null
|
|
@@ -36,12 +36,12 @@ class CanvasDrawer {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* 初始化 webgl
|
|
39
|
+
* 初始化 webgl | Initialize webgl
|
|
40
40
|
*/
|
|
41
41
|
private initGl() {
|
|
42
42
|
if (!this._canvas) return
|
|
43
43
|
|
|
44
|
-
// 初始化 gl
|
|
44
|
+
// 初始化 gl | Initialize gl
|
|
45
45
|
this._gl = this._canvas.getContext('webgl') || this._canvas.getContext('webgl2')
|
|
46
46
|
if (!this._gl) {
|
|
47
47
|
console.error('WebGL not supported')
|
|
@@ -61,17 +61,17 @@ class CanvasDrawer {
|
|
|
61
61
|
|
|
62
62
|
if (!program) return
|
|
63
63
|
|
|
64
|
-
// 坐标缓冲
|
|
64
|
+
// 坐标缓冲 | Position buffer
|
|
65
65
|
const positionBuffer = gl.createBuffer()
|
|
66
66
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
|
|
67
67
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW)
|
|
68
68
|
|
|
69
|
-
// 纹理坐标缓冲
|
|
69
|
+
// 纹理坐标缓冲 | Texture coordinate buffer
|
|
70
70
|
const texCoordBuffer = gl.createBuffer()
|
|
71
71
|
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer)
|
|
72
72
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]), gl.STATIC_DRAW)
|
|
73
73
|
|
|
74
|
-
// 纹理
|
|
74
|
+
// 纹理 | Texture
|
|
75
75
|
const texture = gl.createTexture()
|
|
76
76
|
gl.bindTexture(gl.TEXTURE_2D, texture)
|
|
77
77
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
|
@@ -79,12 +79,12 @@ class CanvasDrawer {
|
|
|
79
79
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
|
80
80
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
|
81
81
|
|
|
82
|
-
// 着色器变量的引用
|
|
82
|
+
// 着色器变量的引用 | References to shader variables
|
|
83
83
|
const positionLocation = gl.getAttribLocation(program, 'a_position')
|
|
84
84
|
const texCoordLocation = gl.getAttribLocation(program, 'a_texCoord')
|
|
85
85
|
const textureLocation = gl.getUniformLocation(program, 'u_texture')
|
|
86
86
|
|
|
87
|
-
// 缓存数据
|
|
87
|
+
// 缓存数据 | Caching data
|
|
88
88
|
this._program = program
|
|
89
89
|
this._positionBuffer = positionBuffer
|
|
90
90
|
this._texCoordBuffer = texCoordBuffer
|
|
@@ -93,15 +93,15 @@ class CanvasDrawer {
|
|
|
93
93
|
this._texCoordLocation = texCoordLocation
|
|
94
94
|
this._textureLocation = textureLocation
|
|
95
95
|
|
|
96
|
-
// 设置标志
|
|
96
|
+
// 设置标志 | gl is Ready
|
|
97
97
|
this._glReady = true
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
101
|
-
* 创建着色器源码
|
|
101
|
+
* 创建着色器源码 | Create shader source code
|
|
102
102
|
*/
|
|
103
103
|
private createShaderSource(gl: WebGLRenderingContext, type: number) {
|
|
104
|
-
// 顶点着色器
|
|
104
|
+
// 顶点着色器 | Vertex shaders
|
|
105
105
|
const vertexShaderSource = `
|
|
106
106
|
attribute vec2 a_position;
|
|
107
107
|
attribute vec2 a_texCoord;
|
|
@@ -112,7 +112,7 @@ class CanvasDrawer {
|
|
|
112
112
|
}
|
|
113
113
|
`
|
|
114
114
|
|
|
115
|
-
// 片段着色器
|
|
115
|
+
// 片段着色器 | Fragment shader
|
|
116
116
|
const fragmentShaderSource = `
|
|
117
117
|
precision mediump float;
|
|
118
118
|
varying vec2 v_texCoord;
|
|
@@ -130,7 +130,7 @@ class CanvasDrawer {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
* 创建着色器
|
|
133
|
+
* 创建着色器 | Create shaders
|
|
134
134
|
*/
|
|
135
135
|
private createShader(gl: WebGLRenderingContext, type: number, source: string) {
|
|
136
136
|
const shader = gl.createShader(type)
|
|
@@ -154,7 +154,7 @@ class CanvasDrawer {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* 创建着色器程序
|
|
157
|
+
* 创建着色器程序 | Create program
|
|
158
158
|
*/
|
|
159
159
|
private createProgram(gl: WebGLRenderingContext, vertexShader: WebGLShader, fragmentShader: WebGLShader) {
|
|
160
160
|
const program = gl.createProgram()
|
|
@@ -179,7 +179,7 @@ class CanvasDrawer {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
|
-
* 绘制
|
|
182
|
+
* 绘制 | draw
|
|
183
183
|
*/
|
|
184
184
|
public draw(video: HTMLVideoElement) {
|
|
185
185
|
if (this._useGl) {
|
|
@@ -193,22 +193,23 @@ class CanvasDrawer {
|
|
|
193
193
|
const texCoordLocation = this._texCoordLocation
|
|
194
194
|
const textureLocation = this._textureLocation!
|
|
195
195
|
|
|
196
|
-
// 更新视口区域
|
|
196
|
+
// 更新视口区域 | Update the viewport area
|
|
197
197
|
gl.viewport(0, 0, this._canvas.width, this._canvas.height)
|
|
198
198
|
|
|
199
199
|
if (video.readyState < HTMLMediaElement.HAVE_CURRENT_DATA) return
|
|
200
200
|
|
|
201
|
-
// 更新纹理
|
|
201
|
+
// 更新纹理 | Update texture
|
|
202
202
|
gl.bindTexture(gl.TEXTURE_2D, texture)
|
|
203
203
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video)
|
|
204
204
|
|
|
205
|
-
// 清理画布
|
|
205
|
+
// 清理画布 | Clean the canvas
|
|
206
206
|
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
207
207
|
|
|
208
|
-
// 使用着色器程序
|
|
208
|
+
// 使用着色器程序 | Use shader programs
|
|
209
209
|
gl.useProgram(program)
|
|
210
210
|
|
|
211
211
|
// 设置着色器变量对应的 buffer 数据
|
|
212
|
+
// Set the buffer corresponding to the shader variable
|
|
212
213
|
gl.enableVertexAttribArray(positionLocation)
|
|
213
214
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
|
|
214
215
|
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)
|
|
@@ -220,6 +221,7 @@ class CanvasDrawer {
|
|
|
220
221
|
gl.uniform1i(textureLocation, 0)
|
|
221
222
|
|
|
222
223
|
// 绘制(两个三角形六个顶点, 组成一个矩形)
|
|
224
|
+
// Draw (two triangles with six vertices, forming a rectangle)
|
|
223
225
|
gl.drawArrays(gl.TRIANGLES, 0, 6)
|
|
224
226
|
} else {
|
|
225
227
|
const ctx = this._ctx2d
|
|
@@ -234,7 +236,7 @@ class CanvasDrawer {
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
/**
|
|
237
|
-
* 销毁
|
|
239
|
+
* 销毁 | Destroy
|
|
238
240
|
*/
|
|
239
241
|
public destroy() {
|
|
240
242
|
this._canvas = null
|
|
@@ -3,11 +3,21 @@ import { EventBus } from '@havue/shared'
|
|
|
3
3
|
|
|
4
4
|
// #region typedefine
|
|
5
5
|
export type RenderConstructorOptionType = {
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* 当前播放currentTime和最新视频时长最多相差 秒数,默认0.3s
|
|
8
|
+
* The delay of currentTime relative to the latest video duration is 0.3s by default
|
|
9
|
+
*/
|
|
7
10
|
liveMaxLatency: number
|
|
8
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* 最多缓存ws传输的未处理的buffer数据大小, 默认200kb。
|
|
13
|
+
* The maximum amount of unprocessed buffer data to be cached for websocket transfers.
|
|
14
|
+
* 200kb by default
|
|
15
|
+
*/
|
|
9
16
|
maxCacheBufByte: number
|
|
10
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* 最多存储的时间,用于清除在currentTime之前x秒时间节点前的buffer数据, 默认10s
|
|
19
|
+
* The maximum amount of time used to clear the buffer before a time node x seconds before currentTime (default 10s)
|
|
20
|
+
*/
|
|
11
21
|
maxCache: number
|
|
12
22
|
}
|
|
13
23
|
|
|
@@ -52,32 +62,35 @@ export type RenderEvents = {
|
|
|
52
62
|
// let curPosY = 0
|
|
53
63
|
|
|
54
64
|
export class Render extends EventBus<RenderEvents> {
|
|
55
|
-
/** video元素 */
|
|
65
|
+
/** video元素 | videw element */
|
|
56
66
|
private _videoEl: HTMLVideoElement | undefined = undefined
|
|
57
|
-
/** mp4box
|
|
67
|
+
/** mp4box file */
|
|
58
68
|
private _mp4box: MP4Box = MP4Box.createFile()
|
|
59
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* mp4box onFragment获取的视频数据buffer数组
|
|
71
|
+
* mp4box onFragment gets a buffer array of audio and video data
|
|
72
|
+
*/
|
|
60
73
|
private _audioBufsQueue: ArrayBuffer[] = []
|
|
61
74
|
private _videoBufsQueue: ArrayBuffer[] = []
|
|
62
|
-
/** MediaSource
|
|
75
|
+
/** MediaSource instance */
|
|
63
76
|
private _mediaSource: MediaSource | undefined
|
|
64
|
-
/** SourceBuffer
|
|
77
|
+
/** SourceBuffer instance */
|
|
65
78
|
private _audioSourceBuffer: SourceBuffer | undefined
|
|
66
79
|
private _videoSourceBuffer: SourceBuffer | undefined
|
|
67
80
|
|
|
68
81
|
private _audioTrackId: number | undefined
|
|
69
82
|
private _videoTrackId: number | undefined
|
|
70
|
-
/** 用于MediaSource的mimeType */
|
|
83
|
+
/** 用于MediaSource的mimeType | mime type of the video */
|
|
71
84
|
private _mimeType: string = ''
|
|
72
85
|
private _audioMimeType: string = ''
|
|
73
86
|
private _videoMimeType: string = ''
|
|
74
|
-
/** 是否暂停播放 */
|
|
87
|
+
/** 是否暂停播放 | Pause or not */
|
|
75
88
|
private _paused: boolean = false
|
|
76
89
|
private _options: RenderConstructorOptionType
|
|
77
90
|
|
|
78
91
|
private _cacheAnimationID: number | undefined = undefined
|
|
79
92
|
|
|
80
|
-
/** fmp4初始化片段是否已经添加 */
|
|
93
|
+
/** fmp4初始化片段是否已经添加 | fmp4 Initializes whether the fragment has been added */
|
|
81
94
|
private _isAudioInitSegmentAdded: boolean = false
|
|
82
95
|
private _isVideoInitSegmentAdded: boolean = false
|
|
83
96
|
private _offset: number = 0
|
|
@@ -122,7 +135,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
122
135
|
return this._videoEl
|
|
123
136
|
}
|
|
124
137
|
|
|
125
|
-
/** 更新实例配置 */
|
|
138
|
+
/** 更新实例配置 | Update configuration */
|
|
126
139
|
public updateOptions(option: Partial<RenderConstructorOptionType> = {}) {
|
|
127
140
|
Object.assign(this._options, {
|
|
128
141
|
...option
|
|
@@ -130,7 +143,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
130
143
|
}
|
|
131
144
|
|
|
132
145
|
/**
|
|
133
|
-
* 添加视频流buffer数据
|
|
146
|
+
* 添加视频流buffer数据 | Add video stream buffer data
|
|
134
147
|
* @param buf
|
|
135
148
|
*/
|
|
136
149
|
public appendMediaBuffer(bufs: Array<ArrayBuffer & { fileStart: number }>) {
|
|
@@ -146,8 +159,8 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
146
159
|
}
|
|
147
160
|
|
|
148
161
|
/**
|
|
149
|
-
* mp4box解析完成
|
|
150
|
-
* @param info mp4box解析信息
|
|
162
|
+
* mp4box解析完成 | handle Mp4box onReady
|
|
163
|
+
* @param info mp4box解析信息 | mp4box parses the information
|
|
151
164
|
*/
|
|
152
165
|
private _onMp4boxReady(info: any) {
|
|
153
166
|
console.log('onMp4boxReady', info)
|
|
@@ -206,7 +219,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
206
219
|
}
|
|
207
220
|
const sourceBuffer = isVideo ? this._videoSourceBuffer : this._audioSourceBuffer
|
|
208
221
|
bufQueue.push(buffer)
|
|
209
|
-
// 清除已使用的samples
|
|
222
|
+
// 清除已使用的samples | Clear the used samples
|
|
210
223
|
this._mp4box.releaseUsedSamples(id, sampleNumber)
|
|
211
224
|
this._mp4box.removeUsedSamples(id)
|
|
212
225
|
const segmentAdded = isAudio ? this._isAudioInitSegmentAdded : this._isVideoInitSegmentAdded
|
|
@@ -230,7 +243,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
230
243
|
}
|
|
231
244
|
|
|
232
245
|
/**
|
|
233
|
-
* 初始化视频元素
|
|
246
|
+
* 初始化视频元素 | Initialize the video element
|
|
234
247
|
*/
|
|
235
248
|
private _setupVideo() {
|
|
236
249
|
this._videoEl = document.createElement('video')
|
|
@@ -269,11 +282,19 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
269
282
|
})
|
|
270
283
|
|
|
271
284
|
/**
|
|
272
|
-
* bug: 因预监画面播放一段时间后,
|
|
285
|
+
* @bug : 因预监画面播放一段时间后,
|
|
273
286
|
* 虽然视频时间在走,但video的画面会暂停,
|
|
274
287
|
* 发现将视频元素添加到视口中,画面就不会暂停,
|
|
275
288
|
* 可能与浏览器的资源优化策略有关,先将video标签添加到视口中,
|
|
276
289
|
* 后面有时间寻找一下是否有其他解决方案
|
|
290
|
+
*
|
|
291
|
+
* @bug :After the pre-monitoring screen plays for a period of time,
|
|
292
|
+
* although the video time is running, the video screen will pause.
|
|
293
|
+
* It is found that the video element is added to the viewport,
|
|
294
|
+
* and the screen will not pause.
|
|
295
|
+
* This may be related to the resource optimization strategy of the browser,
|
|
296
|
+
* so the video tag will be added to the viewport first,
|
|
297
|
+
* and then we have time to find out whether there are other solutions
|
|
277
298
|
*/
|
|
278
299
|
// this._videoEl.controls = true
|
|
279
300
|
document.body.appendChild(this._videoEl)
|
|
@@ -314,6 +335,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
314
335
|
|
|
315
336
|
/**
|
|
316
337
|
* 是否支持Media Source Extention
|
|
338
|
+
* whether Media Source Extention is supported
|
|
317
339
|
* @returns boolean
|
|
318
340
|
*/
|
|
319
341
|
public isSupportMSE() {
|
|
@@ -321,7 +343,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
321
343
|
}
|
|
322
344
|
|
|
323
345
|
/**
|
|
324
|
-
* 初始化MSE
|
|
346
|
+
* 初始化MSE | Init MSE
|
|
325
347
|
* @returns
|
|
326
348
|
*/
|
|
327
349
|
private _setupMSE(): void {
|
|
@@ -346,14 +368,14 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
346
368
|
return
|
|
347
369
|
}
|
|
348
370
|
|
|
349
|
-
// 音频轨
|
|
371
|
+
// 音频轨 | Audio track
|
|
350
372
|
if (this._audioMimeType) {
|
|
351
373
|
this._audioSourceBuffer = this._mediaSource.addSourceBuffer(this._audioMimeType)
|
|
352
374
|
this._audioSourceBuffer.mode = 'sequence'
|
|
353
375
|
this._setupSourceBuffer(this._audioSourceBuffer, false)
|
|
354
376
|
}
|
|
355
377
|
|
|
356
|
-
// 视频轨
|
|
378
|
+
// 视频轨 | Video track
|
|
357
379
|
if (this._videoMimeType) {
|
|
358
380
|
this._videoSourceBuffer = this._mediaSource.addSourceBuffer(this._videoMimeType)
|
|
359
381
|
this._videoSourceBuffer.mode = 'sequence'
|
|
@@ -379,13 +401,22 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
379
401
|
|
|
380
402
|
if (sourceBuffer.buffered.length > 0) {
|
|
381
403
|
let bufferedLen = sourceBuffer.buffered.length
|
|
382
|
-
/**
|
|
404
|
+
/**
|
|
405
|
+
* 是否需要删除sourceBuffer中的buffer段
|
|
406
|
+
* Whether the buffer section in sourceBuffer should be removed
|
|
407
|
+
*/
|
|
383
408
|
const needDelBuf = bufferedLen > 1
|
|
384
409
|
/**
|
|
385
410
|
* sourceBuffer中有多个buffered,时间不连续
|
|
386
411
|
* 导致视频播放到其中一个buffer最后就暂停了
|
|
387
412
|
* 如果出现多个buffered,删除之前有的buffer
|
|
388
413
|
* 使用最新的视频buffer进行播放
|
|
414
|
+
*
|
|
415
|
+
* There are multiple buffers in the sourceBuffer,
|
|
416
|
+
* and the time is not continuous,
|
|
417
|
+
* so the video playback will be paused at the end of one of the buffers.
|
|
418
|
+
* If there are multiple buffers,
|
|
419
|
+
* delete the previous buffers and use the latest video buffer to play
|
|
389
420
|
*/
|
|
390
421
|
if (needDelBuf && currentTime) {
|
|
391
422
|
const lastIndex = bufferedLen - 1
|
|
@@ -411,12 +442,12 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
411
442
|
const end = sourceBuffer.buffered.end(bufferedLen - 1)
|
|
412
443
|
|
|
413
444
|
if (isVideo) {
|
|
414
|
-
// 设置开始时间
|
|
445
|
+
// 设置开始时间 | Set the start time
|
|
415
446
|
if (!currentTime && start) {
|
|
416
447
|
this._videoEl.currentTime = start
|
|
417
448
|
}
|
|
418
449
|
|
|
419
|
-
// 限制最低延迟时间
|
|
450
|
+
// 限制最低延迟时间 | Limit the minimum latency
|
|
420
451
|
if (this._options.liveMaxLatency) {
|
|
421
452
|
const offsetMaxLatency = this._options.liveMaxLatency
|
|
422
453
|
|
|
@@ -426,7 +457,8 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
426
457
|
}
|
|
427
458
|
}
|
|
428
459
|
|
|
429
|
-
//
|
|
460
|
+
// 移除最大缓存时间之前的buffer
|
|
461
|
+
// Remove buffers before the maximum cache time
|
|
430
462
|
if (!sourceBuffer!.updating && currentTime - start > this._options.maxCache) {
|
|
431
463
|
sourceBuffer?.remove(0, currentTime - this._options.maxCache / 2)
|
|
432
464
|
}
|
|
@@ -436,6 +468,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
436
468
|
|
|
437
469
|
/**
|
|
438
470
|
* 将_bufsQueue中的数据添加到SourceBuffer中
|
|
471
|
+
* Add the data from _bufsQueue to the SourceBuffer
|
|
439
472
|
* @returns
|
|
440
473
|
*/
|
|
441
474
|
private _cache(isVideo: boolean = false) {
|
|
@@ -491,6 +524,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
491
524
|
|
|
492
525
|
/**
|
|
493
526
|
* 刷新播放时间为最新
|
|
527
|
+
* Refresh the playback time to the latest
|
|
494
528
|
*/
|
|
495
529
|
public refresh() {
|
|
496
530
|
if (this._videoEl && this._videoEl.buffered.length) {
|
|
@@ -499,7 +533,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
499
533
|
}
|
|
500
534
|
}
|
|
501
535
|
|
|
502
|
-
/** 重置解析的视频mime type */
|
|
536
|
+
/** 重置解析的视频mime type | Reset the parsed video mime type */
|
|
503
537
|
public resetMimeType() {
|
|
504
538
|
this.destroyMp4box()
|
|
505
539
|
this.destroyMediaSource()
|
|
@@ -553,7 +587,7 @@ export class Render extends EventBus<RenderEvents> {
|
|
|
553
587
|
}
|
|
554
588
|
|
|
555
589
|
/**
|
|
556
|
-
* 销毁
|
|
590
|
+
* 销毁 | Destroy
|
|
557
591
|
*/
|
|
558
592
|
public destroy() {
|
|
559
593
|
if (this._videoEl) {
|
|
@@ -2,7 +2,7 @@ import MP4Box from 'mp4box'
|
|
|
2
2
|
|
|
3
3
|
function ExtendMp4box() {
|
|
4
4
|
const MP4BoxFile = MP4Box.createFile().constructor
|
|
5
|
-
// 清空samples
|
|
5
|
+
// 清空samples | Clear samples
|
|
6
6
|
MP4BoxFile.prototype.removeUsedSamples = function (id: number) {
|
|
7
7
|
const track = this.getTrackById(id)
|
|
8
8
|
const samples = track.samples
|