Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@zephyra/blackvideo-codec SDK

Standalone Node.js/TypeScript library implementing Zephyra's Exporter and Deconstructor. No UI, no host assumptions — this package only knows how to turn a base video + layer instructions into a normal, playable video file with the original source embedded inside it, and how to read that back out byte-for-byte.

Install

npm install zephyra-codec
pnpm install zephyra-codec

Requires ffmpeg on PATH (or pass ffmpegPath explicitly). Node.js LTS (>=18).

Usage

import { Exporter, Deconstructor } from "zephyra-codec";

const exporter = new Exporter();
const result = await exporter.export({
  baseVideoPath: "./raw/interview.mp4",
  layers: [
    {
      id: "lower-third",
      type: "text",
      startTime: 2,
      endTime: 8,
      transform: { x: 40, y: 400, scale: 1, rotation: 0 },
      opacity: 1,
      data: { text: "Jane Doe, CTO", fontsize: 28, fontcolor: "white" },
    },
  ],
  outputPath: "./out/interview.zephyra.mp4",
});
// result.outputPath is a completely normal, playable mp4.

const deconstructor = new Deconstructor();
const restored = await deconstructor.deconstruct({
  inputPath: "./out/interview.zephyra.mp4",
  outDir: "./restored",
});
// restored.baseVideoPath is byte-identical to ./raw/interview.mp4
// restored.timeline.layers is the original layers array

How it works

  1. Exporter renders a standard flattened video with ffmpeg, then appends a single unknown-typed top-level box (zeph) to the end of the ISO-BMFF (mp4) container. Standard players and demuxers iterate the box list and skip types they don't recognize — this is the same mechanism vendor metadata boxes use today, not a hack specific to this SDK. Appending at the end never shifts the byte offsets of anything already written, so nothing inside moov needs to be rewritten.
  2. The zeph box payload is the original base video's raw bytes plus the layer instructions, MessagePack-encoded and gzip-compressed.
  3. Deconstructor never touches ffmpeg. It scans the box list, finds zeph, decompresses and decodes it, and writes the base video bytes back out untouched. This is why restoration is byte-exact — the original bytes were never re-encoded, only carried along for the ride.

Design notes / deliberate scope decisions

  • Zero runtime dependencies. The MessagePack codec (src/serialization/msgpack.ts) and the ffmpeg process wrapper (src/ffmpeg/ffmpegBinary.ts) are hand-rolled rather than pulled in via msgpackr/fluent-ffmpeg. Both are wire/behavior compatible with their namesake libraries (MessagePack is a standard spec; the ffmpeg wrapper is just spawn + arg building), so a host is free to swap them in later — but keeping the dependency tree empty removes the biggest source of friction when this package is eventually bundled into a pkg/nexe sidecar binary.
  • Core vs. I/O separation. Exporter/Deconstructor are the only filesystem-touching pieces. Everything they call — encodePayload/decodePayload, appendBox/findTopLevelBox — is a pure function operating on Buffers in memory. These are re-exported from src/index.ts specifically so a future HTTP/WebSocket wrapper can call them directly against request bodies without going through disk.
  • No AI, no approximation in Deconstructor. Restoration is pure ISO-BMFF box scanning + decompression. The round-trip test (test/roundtrip.test.ts) is the acceptance bar: export → deconstruct → Buffer.compare against the original source must be 0, every time.

Scripts

npm run build       # tsc -> dist/
npm test            # runs the full test suite (node:test via tsx), including the round-trip test
npm run typecheck   # tsc --noEmit

Public API

  • Exporter.export(options: ExportOptions): Promise<ExportResult>
  • Deconstructor.deconstruct(options: DeconstructOptions): Promise<DeconstructResult>
  • Pure helpers: encodePayload, decodePayload, appendBox, findTopLevelBox, readBoxPayload, listTopLevelBoxes, stripTopLevelBox, msgpackEncode, msgpackDecode
  • Types: LayerInstruction, ZephyraTimeline, ZephyraPayload, ExportOptions, ExportResult, DeconstructOptions, DeconstructResult, ZephyraFormatError

See src/types.ts for full type definitions.

Out of scope (by design, per the project brief)

No UI, no Tauri, no desktop shell — this package assumes nothing about who calls it. It's meant to be imported directly by a Node host, compiled into a sidecar binary, or wrapped in an HTTP/WebSocket server, none of which are implemented here.

About

Deterministic encode/decode engine for Zephyra's layered video format – losslessly embeds source video + timeline data inside a standard, playable mp4 via acustom ISO-BMFF box. Byte-exact round-trip, zero runtime dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages