Added zstd to video

This commit is contained in:
Boofdev 2025-05-04 16:54:31 +02:00
parent 176c22c16f
commit 5438fd02ee
5 changed files with 38 additions and 15 deletions

View File

@ -48,6 +48,7 @@
"remark-rehype": "^11.1.1",
"svelte-meta-tags": "^4.1.0",
"tone": "^15.0.4",
"unified": "^11.0.5"
"unified": "^11.0.5",
"zstddec": "^0.1.0"
}
}

8
pnpm-lock.yaml generated
View File

@ -65,6 +65,9 @@ importers:
unified:
specifier: ^11.0.5
version: 11.0.5
zstddec:
specifier: ^0.1.0
version: 0.1.0
devDependencies:
'@sveltejs/adapter-auto':
specifier: ^3.3.1
@ -1699,6 +1702,9 @@ packages:
zimmerframe@1.1.2:
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
zstddec@0.1.0:
resolution: {integrity: sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==}
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
@ -3398,4 +3404,6 @@ snapshots:
zimmerframe@1.1.2: {}
zstddec@0.1.0: {}
zwitch@2.0.4: {}

View File

@ -48,7 +48,7 @@ export interface TextVideo2 {
fps: number;
width: number;
height: number;
compression: "gzip" | "none" | "";
compression: "gzip" | "zstd" | "none" | "";
}
frames: {
data: Uint8Array;

View File

@ -1,8 +1,6 @@
import type { StdlibType, TextVideo2, Video2WorkerResponse, Video2WorkerMessage } from "./types";
import * as Tone from "tone";
import axios, { type AxiosResponse } from "axios";
import { unpack, pack } from 'msgpackr';
import Pako from "pako";
import video2Worker from "./video2.worker?worker";
type PlayOptions = {
@ -48,9 +46,9 @@ export async function play(
video = unpack(uint8Array)
if (video.format_version !== 1) {
if (video.format_version !== 1 && video.format_version !== 2) {
stdlib.print(
"Unsupported format version, expected 1, got " + video.format_version
"Unsupported format version, expected 1 or 2, got " + video.format_version
);
return;
}
@ -89,11 +87,13 @@ export async function play(
break;
case "stats":
console.log(`Received stats from worker: ${data.stats}`);
break;
}
};
// Send the video data and oneBit option to the worker for decoding.
worker.postMessage({ type: "init", video, oneBit: options.oneBit} as Video2WorkerMessage);
worker.postMessage({ type: "init", video, oneBit: options.oneBit} as Video2WorkerMessage);
stdlib.print(
"Your video will start in 5 seconds, if the video looks weird then you might need to zoom out."

View File

@ -1,9 +1,11 @@
import Pako from 'pako';
import { ZSTDDecoder } from 'zstddec';
import type { Video2WorkerMessage, Video2WorkerResponse, TextVideo2 } from './types';
let frameBuffer: string[] = [];
let video = {} as TextVideo2;
let oneBit = false;
const zstdDecoder = new ZSTDDecoder();
// Build the pixel-to-char lookup table (LUT)
function createLUT(oneBit: boolean): string[] {
@ -36,9 +38,14 @@ function addFrameToBuffer(index: number, options: { addEvenIfpresent?: boolean }
const lut = createLUT(oneBit);
const frame = video.frames[index];
let frameData: Uint8Array;
if (video.video_info.compression === 'gzip') {
frameData = Pako.inflate(frame.data);
} else {
switch (video.video_info.compression) {
case "gzip":
frameData = Pako.inflate(frame.data);
break;
case "zstd":
frameData = zstdDecoder.decode(frame.data, video.video_info.width * video.video_info.height);
break;
default:
frameData = frame.data;
}
const textFrame = pixelsToChars(frameData, video.video_info.width, video.video_info.height, lut);
@ -52,22 +59,29 @@ function add5sOfFramesToBuffer(index: number) {
}
}
self.onmessage = function (e) {
self.onmessage = async function (e) {
let data = e.data as Video2WorkerMessage;
switch (data.type) {
case 'init':
video = data.video;
oneBit = data.oneBit || false;
if (data.video.video_info.compression === "zstd") {
await zstdDecoder.init();
}
add5sOfFramesToBuffer(0);
break;
case 'requestFrame':
if (!frameBuffer[data.index]) {
addFrameToBuffer(data.index);
}
let frame = frameBuffer[data.index];
if (frame) {
postMessage({ type: 'frame', index: data.index, text: frame });
}
add5sOfFramesToBuffer(data.index);
postMessage({ type: 'frame', index: data.index, text: frame });
add5sOfFramesToBuffer(data.index+1);
break;
case 'stats':
postMessage({ type: 'stats', stats: { buffer: { size: frameBuffer.length, max: video.frames.length }}} as Video2WorkerResponse);
}
};