Ahosting Logo
Knowledge Base

Working with Audio Tracks in FFmpeg

Two audio trapsReplacing audio· without minus shortest, a longer music track pads the video· so the output runs on past the pictureMapping streams· a file can carry several audio tracks· and without explicit mapping FFmpeg picks one for you· which is often not the one you wantedDownmixing surroundA six-channel track played on two speakers loses the centre channel, which is where the dialogueis. Downmix deliberately.

Audio in FFmpeg is a separate set of streams with its own selection, mixing and channel handling. Most audio problems come from FFmpeg quietly picking one stream when the file had several, or from mixing two sources in a way that clips.

Replacing the audio on a video

ffmpeg -i video.mp4 -i audio.mp3 -c:v copy -map 0:v:0 -map 1:a:0 \
-shortest output.mp4

-map 0:v:0 takes video from the first input, -map 1:a:0 takes audio from the second. -c:v copy leaves the video untouched, so this runs in seconds.

-shortest ends the output when the shorter input ends. Without it, a music track longer than the video produces a file that continues with a frozen last frame, or, depending on the container, one whose duration is wrong.

Removing audio entirely

ffmpeg -i input.mp4 -c copy -an output.mp4

-an means no audio. With -c copy this is instant.

Conversely, -vn extracts audio by discarding video.

Mixing two sources

To lay music under existing dialogue:

ffmpeg -i video.mp4 -i music.mp3 -filter_complex \
"[0:a][1:a]amix=inputs=2:duration=first:dropout_transition=0[a]" \
-map 0:v -map "[a]" -c:v copy output.mp4

duration=first matches the video's audio rather than the music's.

By default amix reduces the volume of each input to avoid clipping, which usually makes the original dialogue quieter than you wanted. Set the levels yourself instead.

Setting levels properly

Lower the music before mixing rather than accepting what amix does:

-filter_complex "[1:a]volume=0.2[bg];[0:a][bg]amix=inputs=2:duration=first[a]"

Background music under speech usually wants to be somewhere between 0.1 and 0.3 of the original. That sounds drastic written down and is roughly right by ear.

Judge it on the mix rather than in isolation. Music that sounds correct alone is almost always too loud under dialogue.

Clipping, and how to avoid it

Adding two signals can exceed the maximum a sample can hold, and the excess is not rounded off gracefully. It becomes audible distortion.

The distortion survives everything downstream. There is no fix afterwards, only a re-mix from the sources.

So mix conservatively, and normalise the result rather than pushing levels up during the mix. Normalizing audio loudness explains doing that to a standard.

Channel problems

Two common faults, both fixable in one filter.

Audio in one ear only. A mono source placed in one channel of a stereo track. Duplicate it:

-af "pan=stereo|c0=c0|c1=c0"

Stereo where you want mono, to halve the size of a spoken-word file:

-ac 1

For a podcast or narration, mono is the right choice. Nobody is listening to a voice in stereo, and it costs half the bitrate.

Downmixing surround

A film with 5.1 audio played on stereo speakers often loses the dialogue, because the centre channel, where speech lives, is folded in too quietly.

-ac 2

That gives FFmpeg's standard downmix, which is usually acceptable. When dialogue is still too quiet, a custom pan filter that raises the centre channel is the fix, and it is worth doing for content people will actually watch.

Fixing sync

To shift audio relative to video:

ffmpeg -i input.mp4 -itsoffset 0.5 -i input.mp4 \
-map 0:v -map 1:a -c copy output.mp4

The same file is opened twice with the audio delayed by half a second.

Before reaching for this, check whether the source has a variable frame rate. Drift that increases over the file is that, not a fixed offset, and shifting will fix the start while making the end worse. There is more on spotting it in using ffprobe.

Choosing the right stream

A film with several language tracks converts with whichever FFmpeg considers default, which may not be the one anyone wanted.

List the streams first, then map by index:

-map 0:v:0 -map 0:a:1

That takes the second audio stream explicitly. Checking first is what stops a batch job producing a hundred files in the wrong language. For the extraction case, see extracting audio.

Fades

-af "afade=t=in:st=0:d=2,afade=t=out:st=58:d=2"

Two seconds in at the start, two seconds out beginning at 58 seconds. The fade-out start time is absolute, so it has to be calculated from the duration, which is exactly the kind of value worth reading with ffprobe rather than assuming.

Encode audio once

Every re-encode of a lossy format loses quality, and it is not recoverable.

When you are only changing the video, copy the audio with -c:a copy. When you must re-encode, AAC at 128k is transparent enough for speech and most music, and 192k is generous.

Going higher than the source bitrate never improves anything. It stores the losses more precisely.

Tracks are only usable if a player can tell them apart, which is a metadata question rather than an audio one. There is more on labelling them in How to Edit Metadata and Chapters with FFmpeg.

Inspect the audio before deciding what to do

Most audio problems are diagnosed from the stream properties rather than by listening, and reading them takes a second.

ffprobe -v error -select_streams a -show_entries stream=index,codec_name,channels,channel_layout,sample_rate,bit_rate \
  -of default=nw=1 input.mp4

The channel layout is the field that explains most playback complaints. A file with surround audio played on a device expecting two channels can lose dialogue entirely, since the centre channel is where speech usually sits.

The sample rate matters for compatibility rather than quality. An unusual rate plays correctly in some players and not others, and converting it is cheap compared with diagnosing the reports.

Keep the video untouched while changing the audio

Audio work does not require re-encoding the picture, and doing so wastes hours and loses quality.

ffmpeg -i in.mp4 -c:v copy -c:a aac -b:a 192k -ac 2 out.mp4
ffprobe -v error -select_streams v -show_entries stream=codec_name,bit_rate -of csv=p=0 out.mp4

Copying the video stream makes the operation take seconds rather than the length of a full encode.

Check the result reports the same video codec and bitrate as the source. If it does not, something in the command forced a re-encode, and the picture has been degraded for a change that only concerned the sound.

Check the result on a single speaker

Audio judged on headphones behaves differently on a phone speaker, and that is where most viewing happens.

The specific failure is a mix where the two channels partly cancel when combined, which sounds correct in stereo and loses content when the device plays a single combined channel.

ffmpeg -i out.mp4 -ac 1 -f null - 2>&1 | tail -3

Producing a single channel version and listening to it is the fastest check. Anything that disappears there will be missing for a large proportion of your audience, and it is invisible in every other test.