research/muxing-a-soundtrack-with-ffmpeg-map
Muxing a Soundtrack onto a Silent Video with ffmpeg: When You Need -map
Engineering Note · November 4, 2026 · 5 minute read · ffmpeg · Video · Debugging
If your video has no audio stream, ffmpeg -i video.mp4 -i sound.wav -c:v copy -c:a aac out.mp4 works without any -map. If the video already has an audio track, even a silent one, the same command keeps the silent track and drops your sound. The output looks fine to a quick check, because it does have an audio stream. It just has no sound in it.
Everything below was run with ffmpeg 6.1.1 (Ubuntu build) and ffprobe from the same package, on Linux. We made the test files with ffmpeg’s own generators, so no outside media was involved. Each measurement is real output from that run.
How did we set up the test?
We made a 3-second, 320 by 180 video that has no audio, a 3-second stereo sine tone, and a longer 5-second tone for later.
ffmpeg -f lavfi -i "color=c=0x1b2a41:s=320x180:r=30:d=3" -c:v libx264 -pix_fmt yuv420p silent.mp4
ffmpeg -f lavfi -i "sine=frequency=440:duration=3" -ac 2 -ar 44100 track.wav
Listing the streams with ffprobe confirms what each file holds:
ffprobe -v error -show_entries stream=index,codec_type,codec_name -of csv=p=0 silent.mp4
silent.mp4: 0,h264,video
track.wav: 0,pcm_s16le,audio
Does it work without -map?
ffmpeg -i silent.mp4 -i track.wav -c:v copy -c:a aac a.mp4
The output has two streams, h264 video and aac audio. We measured the audio with the volumedetect filter:
ffmpeg -nostats -i a.mp4 -map 0:a:0 -af volumedetect -f null -
mean_volume: -24.1 dB
A reading of -24.1 dB is far above silence, so the tone is there. When the video has no audio, ffmpeg’s automatic choice does what you want.
What if the video already has an audio track?
Many render tools write a silent audio track so players do not complain. We made the same video with one, using the anullsrc generator (a source of digital silence):
ffmpeg -i silent.mp4 -f lavfi -i anullsrc=r=44100:cl=stereo -shortest -c:v copy -c:a aac silent_with_audio.mp4
Then we ran the same mux command as before:
ffmpeg -i silent_with_audio.mp4 -i track.wav -c:v copy -c:a aac c.mp4
ffprobe shows the same shape as the working file, 0,h264,video 1,aac,audio. The volume does not:
mean_volume: -91.0 dB
That is silence. ffmpeg’s own log says why. Its stream mapping section lists input stream 0:1, the silent audio of the first file, as the audio source. Our track.wav is not listed at all:
Stream mapping:
Stream #0:0 -> #0:0 (copy)
Stream #0:1 -> #0:1 (aac (native) -> aac (native))
By default ffmpeg chooses one video stream and one audio stream, and when several inputs could supply audio, the first input that has an audio stream wins. We did not read ffmpeg’s source to confirm the full selection rule, but this run shows the effect: a silent track in the first file takes the slot.
This is the failure that is easy to miss. The file plays, the player shows a volume control, and file inspection shows an audio stream. Only listening, or measuring, shows there is nothing in it.
How does -map fix it?
-map names the streams you want. The pattern INPUT:TYPE selects by input number (starting at 0) and type (v for video, a for audio).
ffmpeg -i silent_with_audio.mp4 -i track.wav \
-map 0:v -map 1:a -c:v copy -c:a aac -shortest e.mp4
Result: streams 0,video 1,audio, and mean_volume: -24.1 dB. The tone is back, and the silent track from the first file is not in the output.
The same two -map options also work on the simple case, so the safest habit is to always write them. Then the command does the same thing whether or not the video has hidden audio.
What about different lengths?
We muxed the 3-second video with the 5-second tone, with and without -shortest:
d_noshortest duration: 5.000000
d_shortest duration: 3.000000
Without -shortest, the output runs for 5 seconds, which means two extra seconds of audio over a video that has ended. With it, the file stops when the shortest stream ends. If you would rather fade the sound out at the cut, apply an afade filter before the mux. We did not test one here.
A checklist for any mux command
- Say which streams you want with
-map. Do not rely on defaults. - Copy what you do not need to change (
-c:v copy) and encode only the audio. - Decide the length: add
-shortestif the video should win. - After the run, check the streams with ffprobe, then measure with
volumedetect. A mean volume near -91 dB means silence. - Look at ffmpeg’s
Stream mappinglines when something is off. They list exactly which inputs were used.
Limitations
- We tested one ffmpeg build, 6.1.1 on Linux. Stream selection has been stable for years, but we did not test other versions.
- The sound was a generated sine tone, not music, and we measured loudness with
volumedetectrather than listening. - We stored the audio as AAC inside MP4 only. Other container and codec pairs have their own rules, and
-c:v copyfails if the video codec is not allowed in the container. - Audio and video drift, sync offsets and sample-rate conversion were out of scope.
- Our silent-track example was made with
anullsrc. A silent track written by another tool may be laid out differently, though the default selection logic would treat it the same way.
Related reading
- Testing a Form Flow That Depends on Bot Checks and AI
- Comparing Version Strings Without a Library
- Measuring Self-Hosted Font Payload
Frequently asked questions
Why does my ffmpeg output have no sound after I add an audio file?
ffmpeg picks one stream of each type by default, and for audio it prefers the first input that has any. If your video already contains an audio track, even a silent one, that track wins and your new file is ignored. In our test the output had an audio stream with a mean volume of -91 dB, which is silence.
What does ffmpeg -map do?
It tells ffmpeg exactly which input streams go into the output, replacing the automatic choice. The form 0:v means the video streams of the first input, and 1:a means the audio streams of the second input. With -map 0:v -map 1:a, the picture comes from the video file and the sound from the audio file.
How do I check that an output file really has audible sound?
Having an audio stream is not enough. List the streams with ffprobe, then run the file through ffmpeg's volumedetect filter and read the mean_volume line. In our test the correct file measured -24.1 dB for a sine tone, and the broken one measured -91.0 dB, which means digital silence.
Why is my output longer than the video?
When the audio is longer than the video, ffmpeg keeps writing until the longest stream ends. In our test a 5-second sound with a 3-second video gave a 5.0-second file. Adding -shortest stopped it at 3.0 seconds, the length of the video.
Can I add audio without re-encoding the video?
Yes. Use -c:v copy to pass the video stream through untouched, and encode only the audio, for example with -c:a aac. This is fast and avoids a second round of compression on the picture. It only works when the video's codec is allowed in the output container, which h264 in an mp4 file is.