初始化

This commit is contained in:
2025-07-30 13:39:32 +08:00
commit d1f2452b28
253 changed files with 32087 additions and 0 deletions

22
vendor/h264-live-player/AUTHORS vendored Normal file
View File

@@ -0,0 +1,22 @@
The following authors have all licensed their contributions to the project
under the licensing terms detailed in LICENSE (MIT style)
# h264-live-player migration to TypeScript
* Sergey Volkov <drauggres@gmail.com>
# h264-live-player
* Francois Leurent @131 <131.js@cloudyks.org>
# Broadway emscriptend h264 (broadway/Decoder.js)
* Michael Bebenita <mbebenita@gmail.com>
* Alon Zakai <alonzakai@gmail.com>
* Andreas Gal <gal@mozilla.com>
* Mathieu 'p01' Henri <mathieu@p01.org>
* Matthias 'soliton4' Behrens <matthias.behrens@gmail.com>
# WebGL canvas helpers
* Sam Leitch @oneam
# AVC player inspiration
* Benjamin Xiao @urbenlegend

6
vendor/h264-live-player/Canvas.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
import Size from './utils/Size';
export default abstract class Canvas {
protected constructor(readonly canvas: HTMLCanvasElement, readonly size: Size) {}
public abstract decode(buffer: Uint8Array, width: number, height: number): void;
}

10
vendor/h264-live-player/LICENSE vendored Normal file
View File

@@ -0,0 +1,10 @@
Copyright (c) 2019, Project Authors (see AUTHORS file)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the names of the Project Authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

49
vendor/h264-live-player/Program.ts vendored Normal file
View File

@@ -0,0 +1,49 @@
import Shader from './Shader';
import assert from './utils/assert';
export default class Program {
public readonly program: WebGLProgram | null;
constructor(readonly gl: WebGLRenderingContext) {
this.program = this.gl.createProgram();
}
public attach(shader: Shader): void {
if (!this.program) {
throw Error(`Program type is ${typeof this.program}`);
}
if (!shader.shader) {
throw Error(`Shader type is ${typeof shader.shader}`);
}
this.gl.attachShader(this.program, shader.shader);
}
public link(): void {
if (!this.program) {
throw Error(`Program type is ${typeof this.program}`);
}
this.gl.linkProgram(this.program);
// If creating the shader program failed, alert.
assert(this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS),
'Unable to initialize the shader program.');
}
public use(): void {
this.gl.useProgram(this.program);
}
public getAttributeLocation(name: string): number {
if (!this.program) {
throw Error(`Program type is ${typeof this.program}`);
}
return this.gl.getAttribLocation(this.program, name);
}
public setMatrixUniform(name: string, array: Float32List): void {
if (!this.program) {
throw Error(`Program type is ${typeof this.program}`);
}
const uniform = this.gl.getUniformLocation(this.program, name);
this.gl.uniformMatrix4fv(uniform, false, array);
}
}

3
vendor/h264-live-player/README.md vendored Normal file
View File

@@ -0,0 +1,3 @@
Based on client code from [131/h264-live-player](https://github.com/131/h264-live-player/tree/6966af8/vendor)
See [License](LICENSE)

29
vendor/h264-live-player/Script.ts vendored Normal file
View File

@@ -0,0 +1,29 @@
export default class Script {
constructor(public type: string, public source: string) {
}
public static createFromElementId(id: string): Script {
const script = document.getElementById(id);
// Didn't find an element with the specified ID, abort.
if (!script) {
throw Error('Could not find shader with ID: ' + id);
}
// Walk through the source element's children, building the shader source string.
let source = '';
let currentChild = script.firstChild;
while (currentChild) {
if (currentChild.nodeType === 3) {
source += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
return new Script((script as HTMLScriptElement).type, source);
}
public static createFromSource(type: string, source: string): Script {
return new Script(type, source);
}
}

35
vendor/h264-live-player/Shader.ts vendored Normal file
View File

@@ -0,0 +1,35 @@
import Script from './Script';
import error from './utils/error';
export default class Shader {
public readonly shader?: WebGLShader | null;
constructor(readonly gl: WebGLRenderingContext, readonly script: Script) {
// Now figure out what type of shader script we have, based on its MIME type.
if (script.type === 'x-shader/x-fragment') {
this.shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (script.type === 'x-shader/x-vertex') {
this.shader = gl.createShader(gl.VERTEX_SHADER);
} else {
error(`Unknown shader type: ${script.type}`);
return;
}
if (!this.shader) {
error(`Shader is ${typeof this.shader}`);
return;
}
// Send the source to the shader object.
gl.shaderSource(this.shader, script.source);
// Compile the shader program.
gl.compileShader(this.shader);
// See if it compiled successfully.
if (!gl.getShaderParameter(this.shader, gl.COMPILE_STATUS)) {
error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(this.shader));
return;
}
}
}

61
vendor/h264-live-player/Texture.ts vendored Normal file
View File

@@ -0,0 +1,61 @@
import Size from './utils/Size';
import assert from './utils/assert';
import Program from './Program';
export default class Texture {
public readonly texture: WebGLTexture | null;
public readonly format: GLenum;
private textureIDs: number[];
static create (gl: WebGLRenderingContext, format: number): Texture {
return new Texture(gl, undefined, format);
}
constructor(readonly gl: WebGLRenderingContext, readonly size?: Size, format?: GLenum) {
this.texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.texture);
this.format = format ? format : gl.LUMINANCE;
if (size) {
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, size.w, size.h, 0, this.format, gl.UNSIGNED_BYTE, null);
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
this.textureIDs = [gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2];
}
public fill(textureData: Uint8Array, useTexSubImage2D?: boolean, w?: number, h?: number): void {
if (typeof w === 'undefined' || typeof h === 'undefined') {
if (!this.size) {
return;
}
w = this.size.w;
h = this.size.h;
}
const gl = this.gl;
assert(textureData.length >= w * h,
'Texture size mismatch, data:' + textureData.length + ', texture: ' + w * h);
gl.bindTexture(gl.TEXTURE_2D, this.texture);
if (useTexSubImage2D) {
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, w, h, this.format, gl.UNSIGNED_BYTE, textureData);
} else {
// texImage2D seems to be faster, thus keeping it as the default
gl.texImage2D(gl.TEXTURE_2D, 0, this.format, w, h, 0, this.format, gl.UNSIGNED_BYTE, textureData);
}
}
public image2dBuffer (buffer: Uint8Array, width: number, height: number) {
this.fill(buffer, false, width, height);
}
public bind(n: number, program: Program, name: string): void {
const gl = this.gl;
if (!program.program) {
return;
}
gl.activeTexture(this.textureIDs[n]);
gl.bindTexture(gl.TEXTURE_2D, this.texture);
gl.uniform1i(gl.getUniformLocation(program.program, name), n);
}
}

305
vendor/h264-live-player/WebGLCanvas.ts vendored Normal file
View File

@@ -0,0 +1,305 @@
import Size from './utils/Size';
import Texture from './Texture';
import error from './utils/error';
// @ts-ignore
import { Matrix, Vector } from 'sylvester.js';
import Program from './Program';
import Shader from './Shader';
import { makePerspective } from './utils/glUtils';
import Script from './Script';
import Canvas from './Canvas';
export default abstract class WebGLCanvas extends Canvas {
protected static vertexShaderScript: Script = Script.createFromSource('x-shader/x-vertex', `
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
`);
protected static fragmentShaderScript: Script = Script.createFromSource('x-shader/x-fragment', `
precision highp float;
varying highp vec2 vTextureCoord;
uniform sampler2D texture;
void main(void) {
gl_FragColor = texture2D(texture, vTextureCoord);
}
`);
public quadVPBuffer?: WebGLBuffer | null;
public quadVTCBuffer?: WebGLBuffer | null;
public mvMatrix: Matrix;
public glNames?: Record<string, string>;
public textureCoordAttribute?: number;
public vertexPositionAttribute?: number;
public perspectiveMatrix: Matrix;
protected gl?: WebGLRenderingContext | null;
protected framebuffer?: WebGLFramebuffer | null;
protected framebufferTexture?: Texture;
protected texture?: Texture;
protected program?: Program;
constructor(readonly canvas: HTMLCanvasElement, readonly size: Size, useFrameBuffer: boolean) {
super(canvas, size);
this.canvas.width = size.w;
this.canvas.height = size.h;
this.onInitWebGL();
this.onInitShaders();
this.initBuffers();
if (useFrameBuffer) {
this.initFramebuffer();
}
this.onInitTextures();
this.initScene();
}
protected initFramebuffer(): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
// Create framebuffer object and texture.
this.framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
this.framebufferTexture = new Texture(gl, this.size, gl.RGBA);
// Create and allocate renderbuffer for depth data.
const renderbuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.size.w, this.size.h);
// Attach texture and renderbuffer to the framebuffer.
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.framebufferTexture.texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
}
protected initBuffers(): void {
let tmp;
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
// Create vertex position buffer.
this.quadVPBuffer = gl.createBuffer();
if (!this.quadVPBuffer) {
error(`quadVPBuffer type is ${typeof gl}`);
return;
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVPBuffer);
tmp = [
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
-1.0, -1.0, 0.0];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmp), gl.STATIC_DRAW);
// (this.quadVPBuffer as any).itemSize = 3;
// (this.quadVPBuffer as any).numItems = 4;
/*
+--------------------+
| -1,1 (1) | 1,1 (0)
| |
| |
| |
| |
| |
| -1,-1 (3) | 1,-1 (2)
+--------------------+
*/
const scaleX = 1.0;
const scaleY = 1.0;
// Create vertex texture coordinate buffer.
this.quadVTCBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVTCBuffer);
tmp = [
scaleX, 0.0,
0.0, 0.0,
scaleX, scaleY,
0.0, scaleY
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(tmp), gl.STATIC_DRAW);
}
protected mvIdentity() : void {
this.mvMatrix = Matrix.I(4);
}
protected mvMultiply(m: number): void {
this.mvMatrix = this.mvMatrix.x(m);
}
protected mvTranslate(m: number[]): void {
const $V = Vector.create;
this.mvMultiply(Matrix.Translation($V([m[0], m[1], m[2]])).ensure4x4());
}
protected setMatrixUniforms(): void {
if (!this.program) {
error(`Program type is ${typeof this.program}`);
return;
}
this.program.setMatrixUniform('uPMatrix', new Float32Array(this.perspectiveMatrix.flatten()));
this.program.setMatrixUniform('uMVMatrix', new Float32Array(this.mvMatrix.flatten()));
}
protected initScene(): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
// Establish the perspective with which we want to view the
// scene. Our field of view is 45 degrees, with a width/height
// ratio of 640:480, and we only want to see objects between 0.1 units
// and 100 units away from the camera.
this.perspectiveMatrix = makePerspective(45, 1, 0.1, 100.0);
// Set the drawing position to the 'identity' point, which is
// the center of the scene.
this.mvIdentity();
// Now move the drawing position a bit to where we want to start
// drawing the square.
this.mvTranslate([0.0, 0.0, -2.4]);
// Draw the cube by binding the array buffer to the cube's vertices
// array, setting attributes, and pushing it to GL.
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVPBuffer as WebGLBuffer);
gl.vertexAttribPointer(this.vertexPositionAttribute as number, 3, gl.FLOAT, false, 0, 0);
// Set the texture coordinates attribute for the vertices.
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVTCBuffer as WebGLBuffer);
gl.vertexAttribPointer(this.textureCoordAttribute as number, 2, gl.FLOAT, false, 0, 0);
this.onInitSceneTextures();
this.setMatrixUniforms();
if (this.framebuffer) {
console.log('Bound Frame Buffer');
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
}
}
public toString(): string {
return 'WebGLCanvas Size: ' + this.size;
}
protected checkLastError(operation: string): void {
if (!this.gl || !this.glNames) {
return;
}
const err = this.gl.getError();
if (err !== this.gl.NO_ERROR) {
let name = this.glNames[err];
name = (name !== undefined) ? name + '(' + err + ')' :
('Unknown WebGL ENUM (0x' + err.toString(16) + ')');
if (operation) {
console.log('WebGL Error: %s, %s', operation, name);
} else {
console.log('WebGL Error: %s', name);
}
console.trace();
}
}
protected onInitWebGL(): void {
try {
this.gl = this.canvas.getContext('experimental-webgl', {
preserveDrawingBuffer: true
}) as WebGLRenderingContext;
} catch (e: any) {
}
if (!this.gl) {
error('Unable to initialize WebGL. Your browser may not support it.');
return;
}
if (this.glNames) {
return;
}
this.glNames = {};
for (const propertyName in this.gl) {
if (this.gl.hasOwnProperty(propertyName)) {
const value = (this.gl as unknown as Record<string, number>)[propertyName];
if (typeof value === 'number') {
this.glNames[value] = propertyName;
}
}
}
}
protected onInitShaders(): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
this.program = new Program(gl);
this.program.attach(new Shader(gl, WebGLCanvas.vertexShaderScript));
this.program.attach(new Shader(gl, WebGLCanvas.fragmentShaderScript));
this.program.link();
this.program.use();
this.vertexPositionAttribute = this.program.getAttributeLocation('aVertexPosition');
gl.enableVertexAttribArray(this.vertexPositionAttribute as number);
this.textureCoordAttribute = this.program.getAttributeLocation('aTextureCoord');
gl.enableVertexAttribArray(this.textureCoordAttribute as number);
}
protected onInitTextures(): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
this.texture = new Texture(gl, this.size, gl.RGBA);
}
protected onInitSceneTextures(): void {
if (!this.texture) {
error(`texture type is ${typeof this.texture}`);
return;
}
if (!this.program) {
error(`program type is ${typeof this.texture}`);
return;
}
this.texture.bind(0, this.program, 'texture');
}
protected drawScene(): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
protected readPixels(buffer: Uint8Array): void {
const gl = this.gl;
if (!gl) {
error(`gl type is ${typeof gl}`);
return;
}
gl.readPixels(0, 0, this.size.w, this.size.h, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
}
}

48
vendor/h264-live-player/YUVCanvas.ts vendored Normal file
View File

@@ -0,0 +1,48 @@
import Size from './utils/Size';
import Canvas from './Canvas';
export default class YUVCanvas extends Canvas {
private canvasCtx: CanvasRenderingContext2D;
private canvasBuffer: ImageData;
constructor(readonly canvas: HTMLCanvasElement, readonly size: Size) {
super(canvas, size);
this.canvasCtx = this.canvas.getContext('2d') as CanvasRenderingContext2D;
this.canvasBuffer = this.canvasCtx.createImageData(size.w, size.h);
}
public decode(buffer: Uint8Array, width: number, height: number): void {
if (!buffer) {
return;
}
const lumaSize = width * height;
const chromaSize = lumaSize >> 2;
const ybuf = buffer.subarray(0, lumaSize);
const ubuf = buffer.subarray(lumaSize, lumaSize + chromaSize);
const vbuf = buffer.subarray(lumaSize + chromaSize, lumaSize + 2 * chromaSize);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const yIndex = x + y * width;
const uIndex = ~~(y / 2) * ~~(width / 2) + ~~(x / 2);
const vIndex = ~~(y / 2) * ~~(width / 2) + ~~(x / 2);
const R = 1.164 * (ybuf[yIndex] - 16) + 1.596 * (vbuf[vIndex] - 128);
const G = 1.164 * (ybuf[yIndex] - 16) - 0.813 * (vbuf[vIndex] - 128) - 0.391 * (ubuf[uIndex] - 128);
const B = 1.164 * (ybuf[yIndex] - 16) + 2.018 * (ubuf[uIndex] - 128);
const rgbIndex = yIndex * 4;
this.canvasBuffer.data[rgbIndex + 0] = R;
this.canvasBuffer.data[rgbIndex + 1] = G;
this.canvasBuffer.data[rgbIndex + 2] = B;
this.canvasBuffer.data[rgbIndex + 3] = 0xff;
}
}
this.canvasCtx.putImageData(this.canvasBuffer, 0, 0);
// const date = new Date();
// console.log('WSAvcPlayer: Decode time: ' + (date.getTime() - this.rcvtime) + ' ms');
}
}

View File

@@ -0,0 +1,120 @@
import WebGLCanvas from './WebGLCanvas';
import Size from './utils/Size';
import Program from './Program';
import Shader from './Shader';
import Script from './Script';
import Texture from './Texture';
export default class YUVWebGLCanvas extends WebGLCanvas {
protected static vertexShaderScript: Script = Script.createFromSource('x-shader/x-vertex', `
attribute vec3 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying highp vec2 vTextureCoord;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vTextureCoord = aTextureCoord;
}
`);
protected static fragmentShaderScript: Script = Script.createFromSource('x-shader/x-fragment', `
precision highp float;
varying highp vec2 vTextureCoord;
uniform sampler2D YTexture;
uniform sampler2D UTexture;
uniform sampler2D VTexture;
const mat4 YUV2RGB = mat4
(
1.1643828125, 0, 1.59602734375, -.87078515625,
1.1643828125, -.39176171875, -.81296875, .52959375,
1.1643828125, 2.017234375, 0, -1.081390625,
0, 0, 0, 1
);
void main(void) {
gl_FragColor = vec4(
texture2D(YTexture, vTextureCoord).x,
texture2D(UTexture, vTextureCoord).x,
texture2D(VTexture, vTextureCoord).x,
1
) * YUV2RGB;
}`);
private YTexture?: Texture;
private UTexture?: Texture;
private VTexture?: Texture;
constructor(readonly canvas: HTMLCanvasElement, readonly size: Size) {
super(canvas, size, false);
}
protected onInitShaders(): void {
if (!this.gl) {
return;
}
this.program = new Program(this.gl);
this.program.attach(new Shader(this.gl, YUVWebGLCanvas.vertexShaderScript));
this.program.attach(new Shader(this.gl, YUVWebGLCanvas.fragmentShaderScript));
this.program.link();
this.program.use();
this.vertexPositionAttribute = this.program.getAttributeLocation('aVertexPosition');
this.gl.enableVertexAttribArray(this.vertexPositionAttribute as number);
this.textureCoordAttribute = this.program.getAttributeLocation('aTextureCoord');
this.gl.enableVertexAttribArray(this.textureCoordAttribute as number);
}
protected onInitTextures(): void {
if (!this.gl) {
return;
}
this.YTexture = new Texture(this.gl, this.size);
this.UTexture = new Texture(this.gl, this.size.getHalfSize());
this.VTexture = new Texture(this.gl, this.size.getHalfSize());
}
protected onInitSceneTextures(): void {
if (!this.program) {
return;
}
if (!this.YTexture || !this.UTexture || !this.VTexture) {
return;
}
this.YTexture.bind(0, this.program, 'YTexture');
this.UTexture.bind(1, this.program, 'UTexture');
this.VTexture.bind(2, this.program, 'VTexture');
}
protected fillYUVTextures(y: Uint8Array, u: Uint8Array, v: Uint8Array): void {
if (!this.YTexture || !this.UTexture || !this.VTexture) {
return;
}
this.YTexture.fill(y);
this.UTexture.fill(u);
this.VTexture.fill(v);
}
public decode(buffer: Uint8Array, width: number, height: number): void {
if (!buffer) {
return;
}
if (!this.YTexture || !this.UTexture || !this.VTexture) {
return;
}
const lumaSize = width * height;
const chromaSize = lumaSize >> 2;
this.fillYUVTextures(
buffer.subarray(0, lumaSize),
buffer.subarray(lumaSize, lumaSize + chromaSize),
buffer.subarray(lumaSize + chromaSize, lumaSize + 2 * chromaSize)
);
this.drawScene();
}
public toString(): string {
return 'YUVCanvas Size: ' + this.size;
}
}

16
vendor/h264-live-player/utils/Size.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
/**
* Represents a 2-dimensional size value.
*/
export default class Size {
constructor(public w: number, public h: number) {}
toString() {
return '(' + this.w + ', ' + this.h + ')';
}
getHalfSize() {
return new Size(this.w >>> 1, this.h >>> 1);
}
length() {
return this.w * this.h;
}
}

View File

@@ -0,0 +1,8 @@
import error from './error';
export default function assert(condition: boolean, message: string): void {
if (!condition) {
error(message);
throw new Error(message);
}
}

View File

@@ -0,0 +1,4 @@
export default function error(message: string): void {
console.error(message);
console.trace();
}

113
vendor/h264-live-player/utils/glUtils.ts vendored Normal file
View File

@@ -0,0 +1,113 @@
// @ts-ignore
import { Matrix, Vector } from 'sylvester.js';
const $M = Matrix.create;
// augment Sylvester some
Matrix.Translation = function(v: Matrix): Matrix {
if (v.elements.length === 2) {
const r = Matrix.I(3);
r.elements[2][0] = v.elements[0];
r.elements[2][1] = v.elements[1];
return r;
}
if (v.elements.length === 3) {
const r = Matrix.I(4);
r.elements[0][3] = v.elements[0];
r.elements[1][3] = v.elements[1];
r.elements[2][3] = v.elements[2];
return r;
}
throw Error('Invalid length for Translation');
};
Matrix.prototype.flatten = function(): number[] {
const result = [];
/* tslint:disable: no-invalid-this prefer-for-of */
if (this.elements.length === 0) {
return [];
}
for (let j = 0; j < this.elements[0].length; j++) {
for (let i = 0; i < this.elements.length; i++) {
result.push(this.elements[i][j]);
}
}
/* tslint:enable */
return result;
};
Matrix.prototype.ensure4x4 = function(): Matrix | null {
/* tslint:disable: no-invalid-this */
if (this.elements.length === 4 && this.elements[0].length === 4) {
return this;
}
if (this.elements.length > 4 || this.elements[0].length > 4) {
return null;
}
for (let i = 0; i < this.elements.length; i++) {
for (let j = this.elements[i].length; j < 4; j++) {
if (i === j) {
this.elements[i].push(1);
} else {
this.elements[i].push(0);
}
}
}
for (let i = this.elements.length; i < 4; i++) {
if (i === 0) {
this.elements.push([1, 0, 0, 0]);
} else if (i === 1) {
this.elements.push([0, 1, 0, 0]);
} else if (i === 2) {
this.elements.push([0, 0, 1, 0]);
} else if (i === 3) {
this.elements.push([0, 0, 0, 1]);
}
}
return this;
/* tslint:enable */
};
Vector.prototype.flatten = function(): number[] {
/* tslint:disable: no-invalid-this */
return this.elements;
/* tslint:enable */
};
//
// gluPerspective
//
export function makePerspective(fovy: number, aspect: number, znear: number, zfar: number): Matrix {
const ymax = znear * Math.tan(fovy * Math.PI / 360.0);
const ymin = -ymax;
const xmin = ymin * aspect;
const xmax = ymax * aspect;
return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar);
}
//
// glFrustum
//
function makeFrustum(left: number, right: number,
bottom: number, top: number,
znear: number, zfar: number): Matrix {
const X = 2 * znear / (right - left);
const Y = 2 * znear / (top - bottom);
const A = (right + left) / (right - left);
const B = (top + bottom) / (top - bottom);
const C = -(zfar + znear) / (zfar - znear);
const D = -2 * zfar * znear / (zfar - znear);
return $M([[X, 0, A, 0],
[0, Y, B, 0],
[0, 0, C, D],
[0, 0, -1, 0]]);
}