Skip to content

Add AudioConverter to the Blocks API - #1667

Merged
NicolasHug merged 13 commits into
mainfrom
audio-blocks-converter
Aug 24, 2026
Merged

Add AudioConverter to the Blocks API#1667
NicolasHug merged 13 commits into
mainfrom
audio-blocks-converter

Conversation

@NicolasHug

@NicolasHug NicolasHug commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Add AudioConverter which is a stream processor (unlike the ColorConverter, which is stateless and can work on a per-frame basis). AudioConverter can convert sample rate and number of channels. It has the same API as the PacketDecoder (drain and reset).

@pytorch-bot

pytorch-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/meta-pytorch/torchcodec/1667

Note: Links to docs will display an error until the docs builds have been completed.

⏳ No Failures, 17 Pending

As of commit 1de931d with merge base 78ed5ad (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 21, 2026
@NicolasHug
NicolasHug force-pushed the audio-blocks-converter branch 2 times, most recently from c39e054 to e52daf7 Compare August 21, 2026 15:58
@NicolasHug
NicolasHug force-pushed the audio-blocks-converter branch 2 times, most recently from d707771 to f1a0ec5 Compare August 21, 2026 15:58
@NicolasHug
NicolasHug force-pushed the audio-blocks-converter branch from f1a0ec5 to 1e3410f Compare August 21, 2026 16:45
Base automatically changed from audio-blocks-decoder to main August 21, 2026 16:45
@NicolasHug
NicolasHug force-pushed the audio-blocks-converter branch 2 times, most recently from 9b9e7d1 to 33fa222 Compare August 21, 2026 16:45
Pulls two helpers out of code that already exists:

- get_swr_output_num_samples_bound(), the av_rescale_rnd() bound that
  convert_audio_av_frame_samples() computes inline.
- swr_convert_to_tensor(), which runs swr_convert() straight into a fresh
  float32 [num_channels, N] tensor and narrows it to what was actually
  produced. That's the body of maybe_flush_audio_buffers(), which now calls
  it and drops from 25 lines to 6.

The reason to land this separately is the signature: swr_convert() takes
`const uint8_t **in` up to FFmpeg 6 and `const uint8_t * const *in` from 7 on,
and only the former converts to both. Taking `const uint8_t* const*` compiles
on 7 and 8 and fails on 4/5/6 with "would lose const qualifier", which is easy
to miss when developing against FFmpeg 7. Verified with
BUILD_AGAINST_ALL_FFMPEG_FROM_S3=1: all of core4 through core9 build.
Completes the audio pipeline: AudioDemuxer -> PacketDecoder -> AudioConverter,
turning RawAudioSamples into normalized float32 AudioSamples, optionally
resampled and remixed to another channel count.

Unlike ColorConverter this block is a stream processor rather than a function
of its input, because resampling is an interpolation filter: swresample holds
the tail of each frame back until the next arrives. So convert() can return
fewer samples than it was given, drain() is needed for the last ones, frames
must be fed in order, and reset() is needed after a seek. None of that is true
when sample_rate is left unset - format conversion and channel remixing are
frame-local - but drain()/reset() are in the documented loop from the start so
that adding sample_rate later can't silently truncate anyone's audio.

We deliberately don't implement SingleStreamDecoder's pre-roll or its
resampling alignment grid. The grid works by *dropping* up to
isr/gcd(isr,osr)-1 input samples, which is only safe behind a pre-roll; without
one it would eat the caller's own samples (up to ~1s for 44100 -> 16001).
Consequence: samples decoded after a seek don't line up bit-for-bit with a
whole-file decode. Decoding from the start does, which the tests pin.

create_swr_context() grows an overload taking channel counts rather than an
AVFrame, and the swr_convert() output-size bound moves into a shared helper.
This reverts commit c39e054.
- get_swr_output_num_samples_bound is now declared and defined by the parent
  commit, so remove this branch's copy.
- swr_convert_to_tensor keeps the parent's `const uint8_t**` parameter, which
  is what compiles against FFmpeg 4-6 as well as 7+.
- PacketDecoder became AudioPacketDecoder in #1666; update the converter tests.
@NicolasHug
NicolasHug force-pushed the audio-blocks-converter branch from fb5db8b to 4fa95eb Compare August 24, 2026 09:10
@NicolasHug
NicolasHug merged commit be6d503 into main Aug 24, 2026
72 checks passed
@NicolasHug
NicolasHug deleted the audio-blocks-converter branch August 24, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant