Files
drags-and-nerds/v1-com-officielle/public/mp4-muxer-main/src/misc.ts
T
vgaNAR6ta 13c91b464f add: PASSAGE V1 COM OFFICIELLE
préparation du template
intégration du fond animé
fusion du style background et style pcp
2026-03-18 20:15:01 +01:00

118 lines
3.3 KiB
TypeScript

import { Sample } from './muxer';
let bytes = new Uint8Array(8);
let view = new DataView(bytes.buffer);
export const u8 = (value: number) => {
return [(value % 0x100 + 0x100) % 0x100];
};
export const u16 = (value: number) => {
view.setUint16(0, value, false);
return [bytes[0], bytes[1]];
};
export const i16 = (value: number) => {
view.setInt16(0, value, false);
return [bytes[0], bytes[1]];
};
export const u24 = (value: number) => {
view.setUint32(0, value, false);
return [bytes[1], bytes[2], bytes[3]];
};
export const u32 = (value: number) => {
view.setUint32(0, value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];
};
export const i32 = (value: number) => {
view.setInt32(0, value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];
};
export const u64 = (value: number) => {
view.setUint32(0, Math.floor(value / 2**32), false);
view.setUint32(4, value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]];
};
export const fixed_8_8 = (value: number) => {
view.setInt16(0, 2**8 * value, false);
return [bytes[0], bytes[1]];
};
export const fixed_16_16 = (value: number) => {
view.setInt32(0, 2**16 * value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];
};
export const fixed_2_30 = (value: number) => {
view.setInt32(0, 2**30 * value, false);
return [bytes[0], bytes[1], bytes[2], bytes[3]];
};
export const ascii = (text: string, nullTerminated = false) => {
let bytes = Array(text.length).fill(null).map((_, i) => text.charCodeAt(i));
if (nullTerminated) bytes.push(0x00);
return bytes;
};
export const last = <T>(arr: T[]) => {
return arr && arr[arr.length - 1];
};
export const lastPresentedSample = (samples: Sample[]): Sample | undefined => {
let result: Sample | undefined = undefined;
for (let sample of samples) {
if (!result || sample.presentationTimestamp > result.presentationTimestamp) {
result = sample;
}
}
return result;
};
export const intoTimescale = (timeInSeconds: number, timescale: number, round = true) => {
let value = timeInSeconds * timescale;
return round ? Math.round(value) : value;
};
export type TransformationMatrix = [number, number, number, number, number, number, number, number, number];
export const rotationMatrix = (rotationInDegrees: number): TransformationMatrix => {
let theta = rotationInDegrees * (Math.PI / 180);
let cosTheta = Math.cos(theta);
let sinTheta = Math.sin(theta);
// Matrices are post-multiplied in MP4, meaning this is the transpose of your typical rotation matrix
return [
cosTheta, sinTheta, 0,
-sinTheta, cosTheta, 0,
0, 0, 1
];
};
export const IDENTITY_MATRIX = rotationMatrix(0);
export const matrixToBytes = (matrix: TransformationMatrix) => {
return [
fixed_16_16(matrix[0]), fixed_16_16(matrix[1]), fixed_2_30(matrix[2]),
fixed_16_16(matrix[3]), fixed_16_16(matrix[4]), fixed_2_30(matrix[5]),
fixed_16_16(matrix[6]), fixed_16_16(matrix[7]), fixed_2_30(matrix[8])
];
};
export const deepClone = <T>(x: T): T => {
if (!x) return x;
if (typeof x !== 'object') return x;
if (Array.isArray(x)) return x.map(deepClone) as T;
return Object.fromEntries(Object.entries(x).map(([key, value]) => [key, deepClone(value)])) as T;
};
export const isU32 = (value: number) => {
return value >= 0 && value < 2**32;
};