Skip to content

Add audio rendering support (continued) - #65

Merged
darbyjohnston merged 5 commits into
OpenTimelineIO:mainfrom
darbyjohnston:audio
Sep 8, 2026
Merged

darbyjohnston merged 5 commits into
OpenTimelineIO:mainfrom
darbyjohnston:audio

Conversation

@darbyjohnston

Copy link
Copy Markdown
Collaborator

The original PR this work is based on: #59

Some additional notes:

  • Audio is rendered from the timeline's audio tracks and muxed into the movie, or written separately with -afile.
  • The frame rate fix: per-frame sample counts follow the frame positions, and the reader seeks only on a real discontinuity, verified sample-exact at 24, 29.97, and 59.94.
  • The minimal FFmpeg build gets ALAC rather than AAC.
  • Time warps repeat or drop frames of audio rather than stretching it, which is unchanged from Daniel's version and noted as a limitation.

Assisted-by: Claude:claude-fable-5-1 [patch] [debugging]

danielweinmann and others added 5 commits September 7, 2026 17:34
Add a complete audio pipeline parallel to the existing video pipeline:

- Decode audio from source media files using FFmpeg (libavcodec + libswresample)
- Walk OTIO timeline audio tracks: clips, gaps, transitions (crossfade), time warps, track mixing
- Extract audio from video clips that contain audio streams
- Mux audio alongside video in output containers (MP4, MOV)
- Write audio to separate files via -afile option

New CLI options: -acodec, -arate, -achannels, -afile, -no_audio

New files:
- AudioBuffer.h: interleaved float32 audio buffer type
- FFmpegAudioRead.h/cpp: audio decoder using FFmpeg + swresample
- AudioGraph.h/cpp: OTIO timeline walker for audio (mirrors ImageGraph)
- FFmpegAudioWrite.h/cpp: standalone audio file writer

Modified files:
- FFmpeg.h/cpp: AudioCodec enum (pcm_s16le, pcm_s24le, pcm_f32le, flac, aac)
- FFmpegWrite.h/cpp: audio+video muxing in combined writer
- App.h/cpp: CLI options and audio render loop integration
- TimelineAlgo.h/cpp: getAudioClips() helper
- CMakeLists.txt: new sources + libswresample linking
- BuildFFmpeg.cmake: AAC codec in minimal build

Signed-off-by: Daniel Weinmann <daniel@seasoned.cc>
(cherry picked from commit 3b9bf3c)
The render loop asked for the same number of samples every frame, the
sample rate over the frame rate rounded to an integer. At 24 fps that is
exact. At 29.97 it is 1602 where the frame is 1601.6 samples long, so
the audio ran long by the difference every frame, and the reader, which
compared its own clock against the frame time and seeked whenever they
disagreed, seeked on every frame: a flush, a resampler reset, and a
backward seek to a packet boundary whose leading samples were then
played again. On a 440 Hz tone that was 86 audible jumps in ten seconds.

The count for a frame is now the difference between its rounded start
and end positions in samples, so the counts alternate and sum to the
timeline's length. The reader keeps its position in samples, seeks only
when asked for somewhere it is not, and after a seek drops the samples
before the target so the output picks up at the sample asked for rather
than at the packet the seek landed on.

Verified against a tone at 24, 29.97 and 59.94 fps, with a clip that
starts mid-file, a gap, a transition and a second audio track: the
output matches the source sample for sample.

Signed-off-by: Darby Johnston <darbyjohnston@yahoo.com>
FFmpeg 7.1 deprecated the codec's sample format list in favor of
avcodec_get_supported_config(), which the writers now ask. The unused
getAudioClips() goes, and the README says what the audio options do.

Signed-off-by: Darby Johnston <darbyjohnston@yahoo.com>
The minimal build carries the codecs that ship without a patent license,
and AAC is not one of them. ALAC is: Apache-licensed, encoded and decoded
by FFmpeg itself, and played by QuickTime and most everything else inside
a MOV, so it is the compressed choice there. AAC stays in the codec list
for a full FFmpeg build; the options shown are the encoders the build has.

Signed-off-by: Darby Johnston <darbyjohnston@yahoo.com>
A video clip's media may carry audio, and it was mixed in alongside the
audio tracks. Now it is left alone: the timeline says what is heard the
way it says what is seen, and a timeline with no audio tracks writes a
movie with no audio stream. That also drops the probe that opened every
video clip's media on start-up to find out whether it had audio.

Signed-off-by: Darby Johnston <darbyjohnston@yahoo.com>
@darbyjohnston darbyjohnston mentioned this pull request Sep 8, 2026
7 of 8 tasks
@darbyjohnston
darbyjohnston merged commit 05ae7ce into OpenTimelineIO:main Sep 8, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants