mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
craft-math-function-scripts
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
471abca087 |
craft-media: MPEG-2 transport and program stream demuxer from FilmCraft (mpegts) (#861)
* craft-media: MPEG-2 transport and program stream demuxer from FilmCraft (feature `mpegts`) Moves filmcraft-mpegts (storytold/filmcraft@4bec22b) into craft_media::mpegts. ByteSource is the crate's trait, Error is written without thiserror so the feature has no dependencies, and Codec::codec_id() and Stream::codec_params() map streams to CodecId. Adds Container::MpegTs and Container::MpegPs, an ffprobe oracle test over ten ffmpeg-made files, and hostile-input tests. * craft-media: module order after merging main |
||
|
|
d3bc790aba |
craft-media: MXF demuxer and writer from FilmCraft (feature mxf) (#877)
Moves filmcraft-mxf (storytold/filmcraft@4bec22b) into craft_media::mxf. ByteSource is the crate's trait, Codec::codec_id() and EssenceTrack::codec_params() map tracks to CodecId, and the writer names craft-media as company and product unless the caller sets them. Fixes two panics: EssenceTrack::sync_before on a track without picture samples, and Timecode::format for a drop-frame start near i64::MAX. Adds Container::Mxf, an ffprobe/ffmpeg oracle test for the reader and the writer, and hostile-input tests. |
||
|
|
de1daefe8c |
craft-media: AVI and OpenDML demuxer from FilmCraft (feature avi) (#856)
Moves filmcraft-avi (storytold/filmcraft@4bec22b) into craft_media::avi. ByteSource is the crate's trait, Error::Io holds the io::Error, and Stream::codec_params() maps the FourCC and the WAVEFORMATEX tag to a CodecId. Adds Container::Avi and tests for the stream, header-size, nesting and OpenDML index limits. |
||
|
|
9c5cc064e9 |
craft-media: Ogg oracle tests against ffprobe (#579)
* craft-media: Ogg oracle tests against ffprobe oracle_ogg.rs compares the Ogg demuxer with ffprobe on ffmpeg-made fixtures, like oracle_matroska.rs: every packet byte for byte (Adler-32 from `-show_data_hash`), codec, rate, channels and Theora picture size, and OpusTiming's starts, durations, pre-skip and total against ffmpeg's pts, durations and Skip Samples side data. Fixtures: Opus (stereo, mono 16 kHz with 2.5 ms frames, 60 ms frames with an odd length, 5.1, one 10 ms page, a page per packet), Vorbis, FLAC in Ogg, Theora + Vorbis, grouped streams and a chained file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: Ogg oracle compares Opus starts on ffmpeg's clock OpusTiming's starts now equal ffprobe's pts as they are, not relative to the first packet, so a shift of every start fails the test; a stream that starts at granule 0 also starts at -pre_skip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6865897f14 |
craft-media: add Ogg demuxer (#440)
* craft-media: Ogg demuxer
FilmCraft's `filmcraft-ogg` as `craft_media::ogg`, behind the opt-in
`ogg` feature: pages (CRC-32 checked, damage skipped by searching for
the next `OggS`), logical streams, packets across pages, and the Ogg
Opus, Vorbis and FLAC mappings. `OpusTiming` gives each Opus packet's
start, the pre-skip and the final page's end trimming.
`Stream::codec_params()` returns `CodecParams` like the other
containers; for FLAC each stream keeps its own header count, and an
unstated count is bounded (it ends at the first audio frame, or at
32 MiB with a warning). `ogg::ByteSource` is `craft_media::ByteSource`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* craft-media: Ogg review fixes: bounded recovery, lost pages, chained links, caps
From the review of the Ogg demuxer (storytold/craft-libs#440):
- The damage scan charges the positions it examines, not a whole 1 MiB read,
reads 64 KiB at a time, and says when the 64 MiB budget runs out. A file
with many damaged pages lost its tail without a warning.
- A page whose lacing claims more bytes than the file has left is skipped
and the scan resumes, instead of ending the parse.
- A gap in a stream's page sequence numbers drops the packet the lost page
continued; its two ends were joined into one corrupted packet.
- A beginning-of-stream page for a serial already seen starts a new stream,
so a chained file whose links reuse a serial no longer hands the second
link's headers to the decoder as audio.
- The packets kept from a file are capped by its size (as Matroska caps
frames), so zero lacing values cannot make the packet lists many times the
file. FLAC metadata under an unstated header count must be a block of the
length its header states, and at most 1024 are kept.
- A packet over 4 GiB is dropped instead of overflowing its size.
- OpusTiming saturates, so hostile granule positions cannot overflow, and a
clip whose only audio page is also the last is trimmed at the end
(RFC 7845 §4.5) instead of at the start.
- Speex streams read extra_headers (offset 68) for their header count.
codec_params gives Theora its Xiph-laced headers and Speex its header,
rate and channels; the FLAC extradata flags exactly the last block.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* craft-media: Ogg damage recovery charges every page it reads and hashes
From CodeRabbit's review of
|
||
|
|
006b50d2ae |
craft-media: shared codec identifiers, one ByteSource, the testkit (1/10) (#439)
* craft-media: shared codec identifiers, one ByteSource, the testkit The types a codec crate needs to describe a file and configure a decoder, ahead of craft-audio: - `Container`, `CodecId`, `PcmFormat` and `CodecParams` (`id.rs`), always built, with optional serde. - `codec_params()` on `isobmff::Track` and `matroska::Track`, both returning `CodecParams` in the same form; `extradata` follows Matroska's `CodecPrivate`. - One `ByteSource` trait (`source.rs`), with `ReadSeekSource`; `isobmff::ByteSource` and `matroska::ByteSource` are that trait. - craft-media-testkit (`publish = false`): the ffmpeg oracle helpers from craft-media's tests, so the codec crates share one copy. The existing tests prove the refactor; the new types have their own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: APV extradata is the bare record; reseek after a poisoned lock An MP4 apvC track gave CodecParams.extradata with the 4-byte FullBox header in front, where Matroska's V_APV CodecPrivate is the bare APVDecoderConfigurationRecord. ApvConfig::record_bytes serializes the record alone and extradata uses it. ReadSeekSource kept its tracked position after recovering a poisoned lock or a failed seek, so a reader moved by a panic was read from the wrong offset with no error. Both now force a seek on the next read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: MP4 codec params per sample description Track::codec_params always described the first stsd entry, while each sample selects its own through description_index. It now describes the first sample's entry; codec_params_for gives the parameters of any entry, and has_mixed_descriptions says whether one set covers every sample. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: test file-backed ByteSources; a File read past i64::MAX is an EOF A File and a ReadSeekSource over a file now have the buffer's test: the same bytes at the same offsets, and UnexpectedEof past the end. The test found that a File read at an offset past i64::MAX failed with the OS's InvalidInput instead of the UnexpectedEof the trait promises; it now reports the end of the source like the other implementations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: Matroska codec params match MP4 for ALAC, DNx and Opus Matroska's codec_params gave Unknown for A_ALAC and for DNxHD/DNxHR stored as V_MS/VFW/FOURCC (AVdn, AVdh), where MP4 gives Alac and Dnxhd; ALAC's extradata is the CodecPrivate, the ALACSpecificConfig MP4's alac box holds. Opus now reports 48 kHz from Matroska as from MP4, whatever rate the muxer declared. ReadSeekSource clears the poison when it recovers the lock, so one panicked read costs one recovery instead of a seek on every later read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * craft-media: MP4 reports the MPEG audio layer the first frame names An MP4 track with MPEG audio reported CodecId::Mp3 whatever the layer, since mp4a + 0x69/0x6B names none (ffmpeg stores MP2 that way), while Matroska reports Mp1/Mp2/Mp3 from its CodecID. open() now reads the frame header of each such entry's first sample and codec_params() reports the layer it names; without a valid header, QuickTime's .mp2 gives Mp2 and anything else Mp3 as before. CodecConfig::Mp3 is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
07047b7221 |
Add craft-media: shared MP4/MOV, Matroska and bitstream code from FilmCraft (#182)
* media: add craft-media with bitstream and isobmff from FilmCraft Moves filmcraft-bitstream and filmcraft-isobmff (storytold/filmcraft@6c3948a) into one crate with a feature per module. The public API matches FilmCraft's so its crates can become re-exports. Tests, oracle tests and fuzzing come along; the ffmpeg discovery helpers replace filmcraft-testkit. Out-of-contract inputs no longer panic: bit widths above 32, a zero NAL length prefix width, and PCM frame sizes that overflow u32. Adds BitReader::read_ue_plus from DeckCraft's copy. * media: public ISO BMFF box reader (isobmff::boxes) Make the demuxer's box iterator and big-endian reader public as isobmff::boxes::{BoxIter, BoxRef, BoxHeader, Reader}, for walkers of boxes the demuxer does not model (CR3 uuid boxes, HEIF meta items, JPEG 2000). BoxIter::within keeps offsets relative to the outer slice, and allow_truncated yields a cut last box. The fuzz test walks every box of each mutated file. * media: matroska feature from FilmCraft's filmcraft-matroska Port storytold/filmcraft@6c3948a crates/matroska as craft_media::matroska behind the opt-in feature matroska, with the same public API so FilmCraft can make filmcraft-matroska a re-export. Its unit and ffprobe oracle tests come with it, on craft-media's test helpers. From DeckCraft's copy: cluster and block timestamps no longer overflow; they saturate at i64::MAX. MuxingApp and the default WritingApp name craft-media. New tests: block additions and mutation fuzzing. The oracle skips the duration of a track's last packet when ffmpeg 8 shortened it. * media: MOV PCM uses lpcm v2 above 16.16 rates and for unsigned 16-bit; signed 8-bit as twos Version 0 sound descriptions store the rate as 16.16 fixed point, so 88.2 kHz and higher were written as 0 Hz. 8-bit signed PCM was labelled raw (unsigned) and 16-bit unsigned as twos/sowt (signed). The reader also took raw under a sound handler for uncompressed video. * media: stop the top-level box scan at a box that runs past the end of the file A 64-bit box size near u64::MAX saturated the scan offset, and the next offset + 8 overflowed. * media: one sample budget for the whole ISO BMFF file The sample cap and the file-length bound on samples without table entries (constant-size stsz, trun without per-sample fields) applied per track or per trun, so repeating a small trak or trun multiplied the allocation. Both are now shared by all tracks and fragments. * media: set_sample_entry rejects entries that change the track's media type or PCM frame size The handler, stsz constant size and PCM timescale check are fixed at add_track; a replacement that changed them produced a corrupt file. A bad track index returns NoSuchTrack like the other writer methods. * media: saturate the sample end in MkvFile::duration_ns Cluster timestamps saturate at i64::MAX, so pts + duration could overflow for files without Info/Duration. * media: checked add for the Matroska cue cluster position CueClusterPosition comes from the file; an add past u64::MAX panicked in debug builds and wrapped in release. Such a cue now falls back to the index. * media: cap the Matroska TimestampScale at 2^32 and saturate tick conversions A scale near 2^64 overflowed u128/i128 in the per-lace split and in Track::ticks_to_ns. A BlockDuration near u64::MAX also overflowed the tick difference at the default scale. Larger scales are ignored like a zero scale, and tick and nanosecond values outside i64 saturate. * media: Matroska fixture generation no longer truncates the shared subtitle inputs Parallel tests generating subs.mkv or webvtt.webm could read in.srt or in.vtt while another thread rewrote it, and cache a fixture with missing packets. * media: rustfmt parse_moof signature * ci: add craft-media workflow covering feature sets, WASM and ffmpeg oracles The lint job runs fmt, clippy for each feature set (none, bitstream, isobmff, matroska, all) and a wasm32 check. The test job runs the all-features tests with Ubuntu's ffmpeg and CRAFT_MEDIA_REQUIRE_ORACLES=1, installing ffmpeg while the tests compile. * media: Matroska lacing keeps timestamp gaps A laced frame's timestamp is implied by the block's and the track's DefaultDuration, so lacing collapsed gaps in the input. A frame now joins a lace only when that implied tick equals its own, and tracks without a DefaultDuration do not lace. The laced remux oracle compares timestamps. * media: required oracles fail on fixture generator and ffprobe failures Every path that gave up on an oracle check (missing tool, failed fixture generator, failed ffprobe run) goes through one helper that prints SKIPPED, or fails the test with CRAFT_MEDIA_REQUIRE_ORACLES=1. Fixture generators of both containers share run_generator, which takes the required flag explicitly so tests can exercise it without changing the process environment. * media: use US spelling * media: a failed ffprobe probe skips the optional oracle check * media: the Matroska oracle compares the last subtitle cue's duration |