Commit Graph
136 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 9e6332ea27 Merge main into #1739; keep both footage re-exports (Cineon + VIDEO_EXTENSIONS) and main's gaps.md localization row with the PR's AVI row
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 07:44:20 +07:00
tylerjenningsw 852f98d6a5 Merge enhance/filmcraft-avi-backend into enhance/avi-import
# Conflicts:
#	crates/export/tests/it/movie_bytes.rs
2026-10-29 18:58:57 -04:00
bflatasticandClaude Opus 5.5 4bdb68a812 Import: an MP4 lasts as long as its video edit list shows (#2592)
The reader reports a track's media duration (mdhd). For H.264 with
B-frames that runs past the last shown frame by the encoder delay the
edit list trims, so a 75-frame 25 fps clip imported as 76 frames / 3.04 s.
The footage's duration now follows the video track's edit list when it
is shorter (never longer; a delayed start keeps the reader's duration),
as the frame rate is already corrected from the header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 05:54:16 +07:00
tylerjenningsw c9a91d9ddf Merge remote-tracking branch 'origin/main' into pr1736-avi-backend 2026-10-29 18:49:01 -04:00
tylerjenningsw aecdffecb0 Media: read the LATM configuration only when FilmCraft plays that MPEG stream, not an ADTS one before it (#1701) 2026-10-29 18:44:34 -04:00
tylerjenningsw 800b555e51 Media: read the AAC configuration of the MP4 or Matroska track FilmCraft plays, not an empty one before it (#1701) 2026-10-29 18:44:05 -04:00
tylerjenningsw 799303ad68 Media tests: read ffmpeg 4.2's PCE fixtures with their real channel count (#1701)
ffmpeg 4.2 writes 2 in the sample entry of an AAC PCE layout and FilmCraft
decodes as many channels as that names, so the 6.1 check now reads a copy
naming all seven instead of skipping. Configuration 12 moves to the
synthetic layout tests.
2026-10-29 18:20:09 -04:00
tylerjenningsw ec86f24afe Media tests: every AAC layout mixes by speaker in MP4, Matroska and ADTS (#1701)
Tones encoded with FilmCraft's AAC encoder, with the configuration rewritten
to 11, 12 or ffmpeg's 6.1 PCE where the coded elements fit it, so nothing
depends on ffmpeg or skips. Expected gains come from each channel's speaker.
2026-10-29 18:20:09 -04:00
tylerjenningsw e675df7cab Media: downmix AAC by where each decoded channel plays (#1701)
The gains of an AAC source now come from the configuration FilmCraft decodes
it with, read from MP4/MOV (esds), Matroska (CodecPrivate) and LATM in MPEG
TS/PS (its first StreamMuxConfig). Channel configurations 3 to 6, 11 and 12
arrive reordered to WAVE order, 4 as L R C Cs, 7 in element order. A program
config element goes by its element positions, except the six structures in
which ffmpeg's encoder fills its own channel order across them (an LFE in a
side SCE, a back centre in a side pair), recognised by its "Lavc" comment.
ADTS can only signal configurations 1 to 7 that FilmCraft decodes, which the
channel count tells apart. A decode of fewer channels than the layout keeps
its first ones (7 of configuration 7's 8 in MPEG-TS LATM).
2026-10-29 18:20:08 -04:00
BFlat dac865f134 Merge pull request #1423 from nanox333/fix/1417-wav-markers
#1417: WAV markers show on the audio layer
2026-10-30 05:08:00 +07:00
tylerjenningsw 8bb5dbb81e Media: downmix AAC in the order its channel configuration decodes in (#1701)
FilmCraft reorders AAC configurations 3 to 6, 11 and 12 to WAVE/SMPTE order
and leaves configuration 7 and program config elements as coded, so the
channel count alone can't say which order arrives: ffmpeg writes 7.1 as
configuration 7 (C L R first) and 6.1 as a PCE it fills in its own order
(L R C LFE Cs Ls Rs), while FilmCraft's encoder writes a centre-first PCE.
The order is now read from an MP4/MOV's AudioSpecificConfig when the source
opens; other containers keep a channel-count guess.

The ffmpeg oracle test gains configuration 12 (ffmpeg's 7.1 relabelled) and
skips PCE files ffmpeg 4.2 marks as stereo, which FilmCraft reads as two
channels.
2026-10-29 17:52:57 -04:00
tylerjenningsw 3390e2fff7 Merge remote-tracking branch 'origin/main' into pr1736-avi-backend
# Conflicts:
#	crates/media/src/pool.rs
2026-10-29 17:11:16 -04:00
BFlat fbd7bcd957 Merge pull request #2608 from storytold/fix/2141-header-sized-allocations
Media: header-sized EXR windows and audio sample rates are bounded (#2141)
2026-10-30 03:36:36 +07:00
bflatasticandClaude Opus 5.5 4f20c31c37 Media: header-sized EXR windows and audio sample rates are bounded (#2141)
An EXR's display window sizes a plane per channel, so 60000² over a 1×1 data window
was a multi-gigabyte allocation per channel; past 16384² (the vector footage limit)
the file is refused. An audio header's sample rate scales the samples read, so
0xFFFFFFFF Hz made one conform chunk about 47 GB; rates outside 1–768 kHz are an
error, and the audio reads as silence as for any unreadable source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 03:36:06 +07:00
bflatasticandClaude Opus 5.5 2510e17421 Footage reads refuse anything that isn't a regular file (#2134)
A project can name /dev/zero, a FIFO or a folder as footage; reading those whole
never ended (or ran out of memory). The media layer's whole-file reads (probe,
pool, model side files) and the engine's FsServices::read_file now open the file,
refuse a non-regular one, and reserve its length fallibly, so a sparse file that
claims more than memory is an error too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 03:33:47 +07:00
bflatasticandClaude Opus 5.5 592b96ed2e Media: vector footage past 16384×16384 is an error, not an abort (#2136)
An SVG or PDF declaring up to 30000×30000 was drawn into one 14 GB image whose failed
allocation aborted the app. Decoding now refuses sizes past what Continuously Rasterize
draws (16384 a side, shared as MAX_VECTOR_SIDE) with an error naming the size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 03:19:12 +07:00
tylerjenningsw 4439770a05 Merge main into enhance/avi-import
Conflicts:
- viewer.rs: the undecodable-footage notice moved into phase_scene on main; it now
  collects its layers in footage_problems, which keeps the proxy and collapsed-precomp
  rules of #1701.
- project.rs: main's row layout, with the problem marker going by item_problem.
- movie_bytes.rs: the H.264 pin is FilmCraft 09aaf9b's bytes plus main's 19-byte
  BT.709 colr box (104_322 + 19 = 104_341).
render/footage.rs imports ItemKind now that main names its imports.
2026-10-29 15:11:20 -04:00
BFlat c31e651e82 Merge pull request #1504 from midasmatterhorn/fix/issue-1274-obj-sibling-textures
model: OBJ/MTL references from another machine find the file next to the model, and a missing one is logged
2026-10-30 01:22:54 +07:00
Kaedo17 949736fe36 review: the H.264 oracle fixture uses options the picked encoder accepts
CodeRabbit's leftover nitpick: h264_mp4 hard-coded -preset medium -crf 18 for
whatever encoder the build ships, but libopenh264 (and the hardware backends)
reject both — so a build whose picked encoder is not libx264 failed the fixture
and silently skipped every check gated on it. libx264 keeps its constant-quality
pair; everything else gets -b:v. Pinned by a small test over the option sets.
2026-10-30 01:30:53 +08:00
Kaedo17 123095b6df export: tag BT.709 limited-range nclx; the ffmpeg oracles pick decoders by name and skip unbuildable fixtures
- Exported HEVC/AV1 nclx says BT.709 and limited range where the pipeline
  means it, matching what the players we tested assume; the round-trip
  tests pin the box values.
- The ffmpeg oracle helpers no longer read the flags column of
  `ffmpeg -decoders` for "is a decoder" — every row of that listing is a
  decoder, and the trailing D there is "supports direct rendering method
  1", which a build's hevc decoder may legitimately lack. Decoders are
  matched by the codec-name column alone.
- Fixtures a given ffmpeg build cannot actually encode (a listed encoder
  that fails at run time: hardware backends without their device, the
  noopenh264 stub) skip with a note instead of failing the run.
2026-10-30 01:30:53 +08:00
bflatastic a1d8cb675f Merge remote-tracking branch 'origin/main' into HEAD 2026-10-29 23:17:33 +07:00
Claude 0dd14e2706 Merge main into fix/1417-wav-markers
Footage.markers is added to the split footage.rs (#2491); the host integration test joins the
shared tests/it binary.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDvxCS8xcR28VArjzn1x7U
2026-10-29 10:12:23 +00:00
Dylan M. Taylor 8d34f1d449 Refactor media for strict Clippy checks 2026-10-28 06:09:20 +00:00
tylerjenningsw 74b309e6cf Merge remote-tracking branch 'origin/main' into enhance/avi-import
# Conflicts:
#	crates/project/src/lib.rs
#	crates/render/src/lib.rs
#	crates/ui-egui/src/menus.rs
2026-10-27 14:13:31 -04:00
midasmatterhorn e60f654cc6 media: a model reference into another machine finds its file beside the model, so the pool test asserts the local lookup 2026-10-27 02:53:11 +03:00
skylar taylor-barrick 69b9ce2bd1 M0.37: reconcile shared docking and qualify migration follow-up 2026-10-26 06:47:07 +01:00
tylerjenningsw a2f3ac41b1 Merge main into enhance/avi-import 2026-10-25 14:26:28 -04:00
tylerjenningsw 42b44c460a Merge main into enhance/filmcraft-avi-backend 2026-10-25 14:13:46 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 4e9fa51f12 sonar: method paths instead of closures (rust:S1612)
Poison recovery, OsStr::to_str and char predicates only; S4325 casts are
f64 to f32 and stay.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:17:16 +00:00
aiongg 83af3ac56c Batch fix: media: the zero-rate audio test asserts that the read succeeds (#2182) 2026-10-24 00:37:13 +00:00
aiongg 662b620be4 Merge #2182: Regression tests for #354, #382, #979 and #1497 (@skylartaylor) 2026-10-23 23:32:52 +00:00
aiongg 74f7e76f41 Merge #1917: #1812: stills at reduced resolution are resampled once, and their layers cached (@ded-achtung) 2026-10-23 21:34:54 +00:00
skylar taylor-barrick b0c9d47725 Merge remote-tracking branch 'origin/main' into test/backfill-regression-tests 2026-10-23 12:09:54 -06:00
aiongg 89b8db7718 Footage, Lottie and models: resolve stored paths with craft-docpath's resolve_absolute (#1975)
* Footage: use resolve_absolute for stored paths

* Lottie and models: use resolve_absolute for linked files

* CI: release only with git dependencies from storytold

* Use the shared git-sources check and pin checkout in release.yml

* Resolve a model's side files through resolve_absolute; report C:\x as invalid

* CI: parse cargo config, including the legacy .cargo/config, in the git-sources check
2026-10-23 13:02:36 -04:00
aiongg 0173abde8c CI: dev-profile gate, one test binary per crate, nextest, line tables only (#2235)
* Dev profile: line tables only for workspace crates, no debug info for dependencies

* xtask ci: dev-profile gate, nextest, tests without examples, wasm --keep-going

* One integration-test binary per crate

* xtask ci: run effectcraft-gpu's shared-device tests in one cargo test process

* xtask ci: run every stage and report all failures

* xtask ci: name the stage type (clippy type_complexity)

* xtask ci: run every test pass and report all failures

* cargo fmt
2026-10-23 12:59:51 -04:00
skylar taylor-barrick 1c3522be4a #382: test that audio decoding at a zero mix rate does not divide by zero
Resampling footage audio divided by the requested mix rate, so a rate of 0 panicked. The test decodes a 44.1 kHz WAV at rate 0 and expects a read of the requested length. Without the guard it panics with 'attempt to divide by zero'.
2026-10-22 18:55:49 -06:00
dedandClaude Opus 5.5 4cf6580b19 G5: a reduced still's cache key includes its nominal size (#1812)
Review: two footage items of one file with different nominal sizes could share a sized entry,
though one is resampled and the other kept as decoded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:42:22 +03:00
dedandClaude Opus 5.5 ea1f2fe984 G5: a still decoded larger than its nominal size is resampled like the renderer does (#1812)
Review: still_at_size returned a smart object's pixels unresampled when they differed from the
footage's nominal size. It now follows footage_buf: pixels larger than nominal are resampled to
the requested size, smaller ones are left for the renderer to scale up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:21:14 +03:00
dedandClaude Opus 5.5 c33d5c20df G5: a still asked for at its own size is the unsized frame (#1812)
Review: frame_at_size at a still's native size made a second cache key, so the pool decoded
and kept a second full-size copy of a frame thumbnail() or frame() already had.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 04:01:07 +03:00
dedandClaude Opus 5.5 57326dc6a7 G5: stills at a reduced render size are resampled once and kept at that size (#1812)
The media pool honoured the requested size only for movies; stills came back
at full size and the renderer resampled them on every frame. A 21120 px wide
plate at Quarter was re-filtered each frame, and four of them (1.85 GB as f32)
did not fit the 1 GiB pool, so they were also decoded again and again.

Stills are now resampled once with effectcraft_raster::resample (the same
call the renderer made, so pixels are unchanged) and the pool keeps the
reduced copy under the sized key.

#1812 project at Quarter, CLI bench: 410 ms -> 33 ms a frame (26 ms with the
layer cache); desktop playback 2% -> 60-99% of real time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 03:43:33 +03:00
Kristian MyramandClaude Sonnet 5.5 620d340d15 WAV markers: read RF64 files and bound the adtl list
Two findings from the review of #1423.

RF64 (WAVs over 4 GB): a chunk too big for 32 bits has a size field of
0xFFFFFFFF and its real size in the file's `ds64` chunk. The reader took the
field literally, so it stopped at the `data` chunk and never reached the
`cue ` and `_PMX` chunks that follow it. It now resolves such sizes through
`ds64` (the `data` size, and a table of other chunks, capped at 1,024 entries),
with checked arithmetic, and leaves the field as it was when there is no
usable `ds64`.

The `adtl` list: every `labl` record scanned the growing list of names, which
is quadratic in the number of records, and nothing bounded how many were
kept. The cue points are now read first, names and lengths are kept only for
those ids in hash maps, and at most 40,000 `adtl` sub-chunks are looked at.
The duplicate check between the cue and XMP markers uses a set instead of a
scan. What a file yields is unchanged for any file within the bounds: a `labl`
still wins over a `note`, and the first `ltxt` still gives the length.

Tests: an RF64 file whose markers follow a sentinel-sized `data` chunk, sizes
taken from the `ds64` table (and not taken when the table has no entry),
hostile `ds64` sizes and tables and every truncation of an RF64 file, and a
100,000-record `adtl` list that is read in linear time, with the cap applied.
The RF64 tests fail with the previous reader.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 00:56:32 +02:00
tylerjenningsw d2ae0bd503 Merge main into enhance/avi-import 2026-10-18 12:45:36 -04:00
Charles BaumerandClaude Opus 5.5 bd961131a4 Media tests: ffmpeg fixtures survive concurrent first runs on Windows
Tests that share a fixture each generate it on a first run and rename
their temp file into place. On Windows the losing rename fails with
PermissionDenied while the winner has the file open. Treat a failed
rename as "another test made it first" when the fixture exists, as
`png_sequence` already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 16:23:28 +00:00
Claude bccbc666a2 #1417: WAV markers show on the audio layer
A WAV's markers were never read, so its audio layer showed none. The importer
now reads the file's cue points (`cue ` chunk named by `LIST/adtl` `labl` and
`note`, sized by `ltxt`) and Adobe's XMP markers (`_PMX` chunk, `xmpDM:markers`
entries as elements or attributes, in frames of the track's `xmpDM:frameRate`).
A marker present in both encodings is listed once. The reader is bounds-checked
and caps the marker count and XMP size.

- `Footage.markers` (optional in the file format) holds them at footage time; a
  layer made from the footage starts with them.
- Layer ▸ Markers ▸ Update Markers From Source also works on footage layers.
- Markers from a file have no label colour.

Tests: reader unit tests (cue, note, ltxt, both XMP forms, both encodings,
truncated and hostile files), a probe test, and an end-to-end test through the
fully wired session. Not checked against a WAV written by Adobe's tools.

Claude-Session: https://claude.ai/code/session_013fTnVxnXTv2MBW6uj2PPyU
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-18 17:38:44 +02:00
Brandon ThomasandClaude Opus 5.5 f3f24ef189 Land batch: fix clippy lints and the #1424 test after #1413 changed layer_menu
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:42:33 -04:00
Brandon Thomas 0867d837d4 Merge pull request #1753 2026-10-18 09:35:35 -04:00
Brandon Thomas 25f8bb17f4 Merge pull request #1216 2026-10-18 09:35:32 -04:00
tylerjenningsw bed49c4959 Media: import AVI (#1701)
One list of movie extensions, in effectcraft-project, with AVI added:
FilmCraft reads AVI 1.0 / OpenDML. Tests against ffmpeg fixtures: Motion
JPEG with PCM audio, an unsupported codec (imports and says why it has no
picture), a file that isn't an AVI (an import error), and a damaged one
(a truncated recording imports as far as it goes; a garbled packet loses
its own frame only).
2026-10-17 11:35:05 -04:00
tylerjenningsw ca724a3d84 Media: downmix 7.1 AAC in the order FilmCraft now delivers it (#1701)
FilmCraft reorders AAC channel configuration 12 (7.1) to WAVE/SMPTE order,
as it does 3 to 6, so 7.1 AAC's left channel was mixed as the centre. The
downmix oracle test gains 6.1 (a program config element, left in AAC's
order) and 7.1 AAC fixtures.
2026-10-17 10:53:05 -04:00
tylerjenningsw 01ad187b97 Media: drop the AIFF workaround dependency (#1701)
FilmCraft's codecs now turn on symphonia's AIFF reader themselves.
2026-10-17 10:53:04 -04:00