Commit Graph

3 Commits

Author SHA1 Message Date
Skyler Lehmkuhl ce151ffd61 Pack video into .beam and stream frames + audio from the blob
Video was the only media type always kept external (VideoClip.file_path),
so a project with video wasn't self-contained. Now video packs into the
SQLite container under the same large-media policy as audio (pack < 2 GB
unless the user chose Reference), and both the frames and the embedded audio
track decode by streaming directly from the blob — no temp files.

- New crate ffmpeg-blob-io: an AVIOContext-over-Read+Seek shim (BlobInput)
  that lets ffmpeg demux from an arbitrary byte source. Isolates all the
  unsafe FFI + ffmpeg ABI coupling (version-pinned =8.0.0/=8.0.1). Manual
  Drop teardown order; AVSEEK_SIZE restores the read position (FFmpeg assumes
  a size query doesn't move it — required for MP4 moov-at-end).
- Schema/save/load: VideoClip.media_id; save_beam packs/references video as
  MediaKind::Video (keyed by clip id); load resolves packed vs referenced and
  reports missing sources. A packed clip points its linked video-audio pool
  entry's media_id at the video row so the audio streams from the same blob.
- Frames: video.rs VideoSource{Path,Packed} threaded through new/seek/scan/
  probe/thumbnails (a fresh BlobReader per open); editor builds the source
  from current_file_path (now set before register_loaded_videos).
- Audio: VideoAudioReader::open_source via BlobInput; the disk_reader
  StreamSource block on packed video-audio is removed; the engine's existing
  factory activation routes it unchanged.

Tests: ffmpeg-blob-io AVIO unit tests (WAV via Cursor, seek, open/drop loop);
core packed_video_stream (blob->AVIO->Input) and beam_archive video round-trip;
daw-backend open_source test (compiles; links/runs only off-container).
Runtime-verified: a packed video plays frames + audio after the source file
is removed.
2026-06-22 09:17:10 -04:00
Skyler Lehmkuhl 34eee3a620 Fix .beam save quirks: real sample rate, drop dead fields
Address the code smells flagged in the .beam format spec:

- Write the project's actual sample rate on save instead of a hardcoded 48000
  (add AudioProject::sample_rate()).
- Remove the vestigial RasterKeyframe.media_path field (it was only used by the
  legacy ZIP loader, which now derives "media/raster/<id>.png" from the keyframe
  id) and the dead buffer_path_at_time accessor. Backward-compatible: older files
  carrying media_path deserialize fine (the field is ignored).
- Drop the unused SaveSettings fields auto_embed_threshold_bytes / force_embed_all
  / force_link_all; only large_media_mode was ever consulted. Un-prefix the now-used
  `settings` parameter.

Update BEAM_FILE_FORMAT.md to match. The remaining notes (reserved MediaKind::Video,
exact-match version check) are design choices, left as-is.
2026-06-21 23:21:48 -04:00
Skyler Lehmkuhl 5f0d5354ed Document the .beam SQLite format and port the inspector
The .beam container moved from ZIP to SQLite, but the docs/tooling still
described the old ZIP format.

- Rewrite BEAM_FILE_FORMAT.md as a normative spec of the current SQLite
  container: file-magic identification, the four-table schema, the two version
  numbers, the media model (kinds, packed/referenced storage, 4 MiB chunking),
  derived media-id formulas, project.json top-level + key entities, save/load
  semantics, the legacy-ZIP format + migration, large-media policy, conformance
  and security sections, and known quirks.
- Port beam_inspector.py to read SQLite (auto-detecting container by magic,
  with the legacy ZIP path preserved): a --media store view, packed/referenced
  storage detection, and chunk-reassembling media extraction.
- Update beam_inspector_README.md to match.
2026-06-21 23:08:15 -04:00