Commit Graph
116 Commits
Author SHA1 Message Date
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
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
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
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
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
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
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
aiongg 816ca95800 Footage: follow stored footage paths only on this computer or the project's share
Footage paths stored in a project are resolved through craft-docpath against
the project file when it is opened or imported: relative paths are taken from
the project's folder, and an item whose path is on another computer, names a
device or is a non-file URL is marked missing without being looked at. The
footage check, the changed-on-disk scan, Reload Footage, Relink, Edit Original
and Reveal in Finder resolve the path again before touching the file, and the
Project panel, Metadata panel and waveforms read no file details of missing
footage.

Lottie image assets are resolved against the Lottie file; one on another
computer is skipped with a warning. Files a 3D model names are read only when
local or on the model's own share.

Reveal in Finder refuses a folder that would open as an app or other bundle.

Files imported or relinked in this session are opened as given.
2026-10-16 17:43:58 +00:00
BFlat cbdd12b27a Merge pull request #1431 from marcoarnulfo/fix/aiff-import
Import: AIFF files import, including EffectCraft's own AIFF renders
2026-10-16 18:08:33 +07:00
arnav-hiwarkarandClaude Opus 5.5 2d216151c6 Import: Composition - Retain Layer Sizes for PDF / Illustrator files (#1536)
The PDF / Illustrator import dialog now offers Composition - Retain Layer
Sizes. Each file layer's footage is cropped to its artwork bounds (fills,
stroke outlines, images, clips) and positioned to keep its place on the
page. Decoding, continuous rasterisation, shape conversion and reload share
one crop (effectcraft_pdf::layer_doc_with_sizes), so they agree.

Also collapses a match guard in the STL reader for current stable clippy.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 13:33:50 +05:30
tylerjenningsw 36a905293b Media: tests for the averaged MP4 frame rate (#1442) 2026-10-14 11:33:49 -04:00
tylerjenningsw eb95f732e5 Media: millisecond-rounded MP4 frame times read at the rate they average to (#1442)
Phones and messaging apps store frame times rounded to whole milliseconds
(33/34 ms at 30 fps, 16/17 ms at 60 fps). FilmCraft's reader takes the
median duration, so such clips imported at 30.303 or 58.824 fps, and New
Comp from Selection and renders followed that rate. When the median is no
standard rate, the durations near it are averaged and snapped to the
standard rate within 0.5 %; exact and variable rates keep the reader's
estimate.
2026-10-14 11:33:49 -04:00
Marco Arnulfo 78b4fe4170 Import: AIFF files import, including EffectCraft's own AIFF renders (fixes #1428) 2026-10-14 13:44:59 +02:00
Kristian Myram 037a21d5a6 #1200: allow TGA proxies and add import regressions 2026-10-13 10:09:51 +00:00
Brandon ThomasandClaude Opus 5.5 6baff9f5fe Integration fixes for the community batch
- Footage sources: the cancellable wrapper (#784) forwards frame_with (#752 float curves)
  and problem (#887); problem's default lives on the trait.
- Media: a called-off decode (#784) is not a footage problem (#887).
- Effect Controls rename (#953): Escape cancels (egui drops focus on Escape the same
  frame), the Rename item is translated; regression test.
- i18n (#873): drop the /out-i18n/ ignore rule and the note about an uncommitted script.
- Tests: text range selector caps (#926) re-borrow the layer; the RAM preview test (#793)
  sets the comp's own Resolution (#462).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:27:59 -04:00
Brandon Thomas 02c134fb41 Merge pull request #904 from vangel76/fix-903-multichannel-downmix
#903: downmix 5.1 and other multichannel audio to stereo

# Conflicts:
#	crates/media/src/lib.rs
2026-10-12 04:20:49 -04:00
Brandon Thomas ab12890a9e Merge pull request #887 from vangel76/fix-886-unsupported-video-notice
#886: say why footage the decoders can't read shows no picture

# Conflicts:
#	crates/media/src/pool.rs
#	crates/media/tests/footage.rs
#	crates/render/src/lib.rs
2026-10-12 04:20:43 -04:00
Brandon ThomasandClaude Opus 5.5 6d4e721d2c Media: Targa/HDR stills keep their Exif orientation; DPX test accepts a stated transfer
#755 decoded stills of an extension-decided format with load_from_memory_with_format,
bypassing #827's oriented decode: load_oriented now takes the format.
The DPX ffmpeg oracle test expected the bare codec name; ffmpeg builds that write
the transfer characteristic make it "DPX 8-bit RGB, linear".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:45:49 -04:00
Brandon ThomasandClaude Opus 5.5 42ef79a2fd Media: movies opened in place keep their orientation (#796 × #827)
Opening movies in place (#796) skipped the whole-file bytes #827 read the
track matrix from, so the pool and the probe lost the turn for movies on
disk. stream::movie_header reads just the ftyp and moov boxes (bounded,
positional reads) and both in-place paths derive the orientation from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 03:37:34 -04:00
Brandon Thomas c11740f461 Merge pull request #827 from pravdomil/claude/import-exif-orientation
Import: stills and movies respect their orientation

# Conflicts:
#	crates/media/src/pool.rs
2026-10-12 03:23:08 -04:00
Brandon Thomas 4e8e6e10b1 Merge pull request #796 from vangel76/fix-stream-video-open
#794: open movies in place instead of reading them whole

# Conflicts:
#	crates/media/src/lib.rs
2026-10-12 03:22:57 -04:00
Brandon Thomas 565fd4118d Merge pull request #784 from vangel76/fix-329-seek-latency
#329: scrubbing a long movie: superseded viewer frames call off their decodes

# Conflicts:
#	crates/media/tests/footage.rs
2026-10-12 03:22:50 -04:00
Brandon Thomas 1210ba91f4 Merge pull request #768 from vangel76/fix-762-animated-webp
#762: import animated WebP as footage with its frames

# Conflicts:
#	docs/file-format-parity.md
2026-10-12 03:22:30 -04:00
Brandon Thomas 78b32b61d4 Merge pull request #769 from vangel76/gap-mxf-import
#767: import MXF (OP1a / OP-Atom) footage

# Conflicts:
#	crates/ui-egui/src/menus.rs
#	docs/gaps.md
2026-10-12 03:20:05 -04:00
Brandon Thomas 3d02e65f2b Merge pull request #765 from vangel76/gap-dpx-import
#756: import DPX and Cineon stills and sequences

# Conflicts:
#	crates/media/tests/footage.rs
#	crates/ui-egui/src/menus.rs
#	docs/file-format-parity.md
#	docs/gaps.md
2026-10-12 03:20:04 -04:00