707 Commits
Author SHA1 Message Date
Vanilagy f767b6f601 Fix AVC software decoder sometimes dropping B-frames (fixes #488) 2026-09-09 16:55:06 +02:00
Vanilagy b2b408749c Surface repeated keys are string[] for Vorbis-style metadata (fixes #490) 2026-09-09 14:01:31 +02:00
Vanilagy 4f88d71277 Add handleUnhandledError to most sources (closes #489) 2026-09-08 17:42:23 +02:00
Vanilagy 6e6785e5fc Add more conversion tests for trimming wholly outside of the available media range 2026-09-08 17:20:14 +02:00
Vanilagy 450c5def97 Fix incorrect use of Content-Length when the server compresses the content (fixes #487) 2026-09-08 17:19:32 +02:00
Vanilagy b560977b50 Fix empty audio trim range crashing conversion (fixes #486) 2026-09-08 16:19:56 +02:00
Vanilagy a1ba54d337 Implement more powerful copy conversions, add conversion copy config, add OutputFormat.negativeTimestampSupport, fix Matroska duration from metadata computation 2026-09-08 14:42:03 +02:00
Vanilagy 34733015cb Add negative timestamp support to MPEG-TS 2026-09-04 15:27:19 +02:00
Vanilagy 9726b0cb4e Add negative timestamp muxing support to Matroska 2026-09-04 12:17:33 +02:00
Vanilagy 3c94d062d2 Allow negative timestamps in media sources, add negative timestamp support to ISOBMFF muxer 2026-09-04 11:48:50 +02:00
hi.jack2eeandGitHub 6c88763a5c Terminate sample iterators before throwing so late-decoded samples are closed (#484)
for await never calls return() on an iterator whose next() threw, so the
error branches in mediaSamplesInRange / mediaSamplesAtTimestamps left the
iteration un-terminated: the pump's decoder callback kept queueing decoded
samples that no consumer or cleanup path could ever close, orphaning them
until GC ("A VideoSample was garbage collected without first being closed").

Set terminated (and ended, where the pump gates on it) before throwing in
both the InputDisposedError and out-of-band error branches of both sample
generators - samples emitted after the throw are then closed on arrival by
the existing checks in the decoder callbacks.

Observed on iOS Safari when the hardware VideoDecoder dies mid-iteration
("Decoding task did not complete"): 3-14 samples orphaned per failing
iterator; with this change, at most the single sample already in flight
during the error microtask window.
2026-09-04 10:01:18 +02:00
Vanilagy cf2edfada2 Relax audio track assert for esds box (fixes #481) 2026-09-02 09:32:06 +02:00
Vanilagy 23f5e96afd Rely not only on FinalizationRegistry 2026-08-31 14:05:33 +02:00
Vanilagy 9e203c0c8a Manually close file readers to avoid indefinite memory leak (fixes #144) 2026-08-31 13:44:58 +02:00
Vanilagy dec669163f Add reliable AudioSample.copyTo() fallback for unsupported destination formats (fixes #479) 2026-08-30 12:49:22 +02:00
Vanilagy e16b01a4c6 Fix Infinity not being allowed where it should be (fixes #478) 2026-08-30 12:19:25 +02:00
Vanilagy da18ceeb24 Add smpte170m vp9 test for CI stability, add missing VP9 color spaces in parser 2026-08-29 20:08:57 +02:00
Vanilagy 3c4c2a459c Remove Chromium version check 2026-08-29 19:53:42 +02:00
Vanilagy 7d1eb5b063 Fall back to color space information from bitstream, fill missing color space fields when passing it to Chromium's VideoDecoder, fix AV1 Sequence Header OBU parsing, fix vpcC box generation, still mux partial color space info into container (fixes #474, closes #475) 2026-08-29 19:48:20 +02:00
Vanilagy 42196e9f64 Add proper non-null check 2026-08-28 15:11:31 +02:00
Vanilagy d44253c7d3 Fix incomplete parsing and generation of AacAudioSpecificConfig (fixes #471) 2026-08-26 13:40:14 +02:00
Vanilagy c10f93ab8c Recognize fMP4 segments starting with an emsg box (or similar) (fixes #473) 2026-08-26 11:59:22 +02:00
Vanilagy 14fb7d0119 Add ducktyped Promise checks (fixes #472) 2026-08-26 11:24:24 +02:00
0f9dc1f91b Fix tenc fallback for encrypted ISOBMFF files (#470)
* fix tenc fallback

* Add test case

---------

Co-authored-by: Vanilagy <[email protected]>
2026-08-24 14:12:04 +02:00
Vanilagy 656c7e70a8 Merge branch 'main' of https://github.com/Vanilagy/mediabunny 2026-08-21 20:06:29 +02:00
Vanilagy 3c4f4c27a3 Slightly restructure code 2026-08-21 20:06:28 +02:00
Vanilagy 166298df2c Make WebCodecs missing error message more helpful (fixes #466) 2026-08-20 23:22:28 +02:00
Jasmine Minter fdfab4660f Support missing or empty avcC chunk 2026-08-20 13:28:50 +10:00
Vanilagy e8162f483f Add @mediabunny/dts extension package 2026-08-15 17:50:47 +02:00
Vanilagy 914907b5db Define DTS codec, add muxing and demuxing support across ISOBMFF, Matroska, and MPEG-TS, add DTS encode/decode support to @mediabunny/server 2026-08-15 16:19:12 +02:00
Vanilagy 39f49de96d Add explanatory doc comment 2026-08-14 11:15:25 +02:00
Vanilagy dc068a0aa8 Add computeFrameRateMetrics and heuristics to determine a video's true frame rate 2026-08-12 16:10:28 +02:00
Vanilagy a08e262dfc Work around WebKit not respecting TypedArray offets for FileSystemWritableFileStream data (fixes #459) 2026-08-11 12:46:33 +02:00
Vanilagy 5b22c8c17d Fix HLS writing an incomplete init segment for sparse segments, improve decoder config validation, fix getFirstTimestamp() for Inputs with zero-packet tracks, allow zero-track muxing for some formats that allow it, add new track metadata that allows you to specify the decoder config early (enables zero-packet tracks), fix trafIndices in sparse fragmented MP4s, fix assertion errors in MPEG-TS demuxer 2026-08-08 17:00:36 +02:00
Vanilagy 7ec538e175 Add special-cased HLS muxer behavior with single-file mode and fMP4 in order to create a standalone playable fMP4 file (closes #394) 2026-08-07 23:03:48 +02:00
Vanilagy b0a8802918 Fixed missing mipmapping in the VideoSample transform case, now guaranteed via a manual mipmap algo 2026-08-06 16:31:46 +02:00
Vanilagy 3023c5f7bd Adjust UrlSource behavior when reading non-range responses, it now honors the cache size and behaves like a ReadableStreamSource (fixes #457) 2026-08-06 14:02:28 +02:00
Vanilagy 4e4e6eed0c Fix encodability checks throwing due to unsupported config feature set; now counts as not supported (fixes #456) 2026-08-06 11:07:15 +02:00
Vanilagy 445911edd0 Fix ISOBMFF muxer track alternate groups (fixes #454), fixed mutex race condition in Output 2026-08-03 14:50:36 +02:00
Vanilagy a0e18ffde0 Use imageSmoothingQuality high when doing canvas-based resizes 2026-07-31 15:52:28 +02:00
Vanilagy f177be15cf Write out compressor name as Pascal-style string, bump patch 2026-07-31 00:06:07 +02:00
Vanilagy d5362e20ad Fix incorrect video depth being written in ISOBMFF for video tracks with an alpha channel (fixes #450) 2026-07-30 17:45:33 +02:00
c3df2a24e5 Add custom quality factors and quantizer bitrate mode (#448)
* Add custom quality factors and quantizer bitrate mode (closes #327)

* Fix quantizer mode fallback and per-frame quantizer edge cases

* Clean up quantizer mode tests

* Quantizer implementation

* Add quality tests

* Improve conversion codec error message, make test more lenient

* Add quantizer support blog post

---------

Co-authored-by: Vanilagy <[email protected]>
2026-07-30 17:24:59 +02:00
Vanilagy 1a99b0371d Improve encoder-side error handling, always close samples/frames even in error conditions 2026-07-29 14:45:22 +02:00
Vanilagy 90ec40166f Fix decoders not being closed in certain error scenarios, fixed unsettled promises in reading logic (fixes #446) 2026-07-29 11:42:14 +02:00
Vanilagy 4b5ef55cf1 Fix API docs some more 2026-07-24 14:53:49 +02:00
Vanilagy ae5a5838d6 Add ability to pause conversions or step them deliberately 2026-07-22 15:30:37 +02:00
f41eef0937 Add composable conversions
* Add non-owning conversions via ConversionOptions.ownsOutput

A conversion with ownsOutput: false only adds tracks to the output and
drives their media data; starting, finalizing, and metadata tags remain
the caller's responsibility. This lets multiple conversions and
directly-added user tracks compose on a single Output (see upstream
issue #436).

- ownsOutput: false allows a pre-populated output (state must still be
  'pending') and seeds track-capacity accounting from existing tracks
- execute() requires the output to be started and never finalizes it
- cancel() closes only the conversion's own sources, releasing internal
  synchronizer waiters, and leaves the output usable
- tags cannot be combined with ownsOutput: false
- isValid requires at least one contributed track instead of the
  format's minimum track counts

Prototype for API discussion; default (owning) behavior is unchanged.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AJdfnbY9AFh9i9dKgtrj6E

* Add external-audio example using a non-owning conversion

Demonstrates composing a user-owned audio track (synthesized voiceover
via OfflineAudioContext + AudioBufferSource) onto a picked video with
Conversion.init({ ownsOutput: false }), including progress reporting
and playback/download of the result.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AJdfnbY9AFh9i9dKgtrj6E

* Release synchronizer waiters when canceling during output finalization

A non-owning conversion's cancel() previously no-oped entirely when the
output (owned by someone else) was already finalizing or finalized,
leaving pump loops parked in the track synchronizer and hanging
execute() forever. Now it still marks the conversion canceled and
releases parked waiters in that state, without force-closing sources
(finalization owns flushing them at that point).

Also adds coverage: non-owning onProgress monotonicity, canceling one
of two sibling conversions, capacity seeding across sequential inits,
exact metadata exclusivity, and cancel-before-execute.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01AJdfnbY9AFh9i9dKgtrj6E

* Document non-owning conversions on the converting-media-files guide page

Adds the doc section requested in #436: what ownsOutput: false does, the
required choreography (add tracks -> output.start() before execute() ->
run the conversion concurrently with your own sources -> finalize), the
cancellation split (conversion.cancel() leaves the output alive; cancel
both for a full abort and tear the output down on error paths), isValid
semantics in this mode, and the tags restriction with the
setMetadataTags() alternative. Also cross-links the fresh-output rule to
the new section. VitePress build passes with dead-link checking on.

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* Clean up conversion logic, add Output.tracks and .hasEnoughTracks(), move new conversion tests around, remove external audio example

* non-owning -> composable, and update docs

* Update

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vanilagy <[email protected]>
2026-07-22 08:42:19 +00:00
Vanilagy 794b84884f Make sure that samples are always closed in the Conversion API, even on error cases 2026-07-18 22:54:24 +02:00
Vanilagy 3ec4061e03 Clean up 2026-07-18 15:49:57 +02:00