FFmpeg can draw a waveform or a spectrogram (a picture that shows the strength of each frequency as colour) from an audio file, as an image or as a video, with no other tool. Use it when you upload a podcast episode to YouTube, post a music clip on social media or need a waveform thumbnail. There are three kinds of filter; pick one by what you want.

You want Filter Output
A static waveform of the whole file showwavespic one PNG
A waveform that moves with playback showwaves video
Frequency content, still / moving showspectrumpic / showspectrum PNG / video
Frequency bars (equaliser look) showfreqs video

Static waveform (showwavespic)

ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1920x480" -frames:v 1 waveform.png

The whole track is drawn in one image. -frames:v 1 means “output one frame”. showwavespic outputs only one frame anyway, so you get the same image without it. The background is transparent (RGBA, a pixel format that stores transparency).

Colour and size

ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1920x480:colors=#00d4aa" -frames:v 1 waveform.png

colors takes a hex colour code or a colour name (white, red, …). To draw the two channels of a stereo file one above the other in different colours, add split_channels=1 and list the colours separated by |.

ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1920x480:split_channels=1:colors=#00d4aa|#ff6b6b" -frames:v 1 waveform.png

Adding a background colour

When a transparent background is a problem (for a social-media image, for example), make a background with the color source, which generates a plain colour picture, and put the waveform on it with overlay.

ffmpeg -i input.mp3 -filter_complex "color=c=#0f1117:s=1920x480[bg];[0:a]showwavespic=s=1920x480:colors=#00d4aa[fg];[bg][fg]overlay=format=auto" -frames:v 1 waveform.png

Appearance options

Option Values Effect
scale lin (default) / log / sqrt / cbrt Amplitude scale. Quiet sound such as speech is easier to see with sqrt or log
draw scale (default) / full How the colour is applied. scale paints areas where channels overlap more strongly; full paints everything in the given colour. The shape of the waveform does not change
filter average (default) / peak When several samples fall on one pixel, use their average or their peak
ffmpeg -i input.mp3 -filter_complex "showwavespic=s=1920x480:draw=full" -frames:v 1 waveform.png

Animated waveform video (showwaves)

ffmpeg -i input.mp3 -filter_complex "[0:a]showwaves=s=1280x720:mode=cline:rate=30:colors=#00d4aa,format=yuv420p[v]" -map "[v]" -map 0:a -c:v libx264 -c:a aac -shortest output.mp4
  • s=1280x720 — output resolution
  • mode=cline — filled in, the same above and below the centre line. The other modes are point, line and p2p (points joined by lines)
  • rate=30 — video frame rate (default 25)
  • format=yuv420p — showwaves outputs RGBA; converting to yuv420p lets the H.264 video play in most players
  • -shortest — end the video when the audio ends

You need -filter_complex instead of -vf because this filter takes audio in and puts video out.

With a background colour

showwaves also has a transparent background, so add a background the same way as for the still image. Give the color background the same frame rate with r=30.

ffmpeg -i input.mp3 -filter_complex "color=c=#0f1117:s=1280x720:r=30[bg];[0:a]showwaves=s=1280x720:mode=cline:rate=30:colors=#00d4aa[w];[bg][w]overlay=format=auto[v]" -map "[v]" -map 0:a -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest output.mp4

Waveform over cover art (podcast layout)

-loop 1 repeats a still image to make a video, and a thin waveform strip goes along the bottom. This layout is often used for publishing podcasts and music.

ffmpeg -loop 1 -i cover.png -i input.mp3 -filter_complex "[0:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2[bg];[1:a]showwaves=s=1280x200:mode=cline:rate=30:colors=#00d4aa[w];[bg][w]overlay=0:520:format=auto[v]" -map "[v]" -map 1:a -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest output.mp4

scale=...:force_original_aspect_ratio=decrease,pad=... is the usual way to fit an image inside 1280×720 without stretching it and fill the margins with black. overlay=0:520 puts the 200-pixel-tall waveform at the bottom of the frame (y = 520–720).

Spectrogram (showspectrumpic / showspectrum)

A spectrogram shows time along the x-axis, frequency up the y-axis and strength as colour. You can see noise bands at a glance, and whether high frequencies are there or cut off (the 16 kHz cut-off in an MP3, for example), so it is also useful for checking audio quality.

ffmpeg -i input.mp3 -filter_complex "showspectrumpic=s=1920x480" -frames:v 1 spectrum.png

By default the image has a legend with axes and scale marks. Turn it off with legend=0 when you want a clean picture. Set the colour scheme with color (the showspectrumpic default is intensity; rainbow and others are also available).

ffmpeg -i input.mp3 -filter_complex "showspectrumpic=s=1920x480:legend=0:color=intensity" -frames:v 1 spectrum.png

For video, use showspectrum. With slide=scroll, the picture moves from right to left.

ffmpeg -i input.mp3 -filter_complex "[0:a]showspectrum=s=1280x720:mode=combined:color=intensity:slide=scroll[v]" -map "[v]" -map 0:a -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest output.mp4

Frequency bars (showfreqs)

A display like a graphic equaliser, with one bar for each frequency band.

ffmpeg -i input.mp3 -filter_complex "[0:a]showfreqs=s=1280x720:mode=bar:colors=#00d4aa[v]" -map "[v]" -map 0:a -c:v libx264 -pix_fmt yuv420p -c:a aac -shortest output.mp4

showfreqs also has a rate option, and the default is 25 fps. Add rate=30 for 30 fps.

Measured: render time and file size

These are the processing time and output size of each filter on a 3-minute (180 s) stereo MP3. The source is pink noise (a kind of random noise) made with anoisesrc=color=pink:d=180:r=44100, turned into stereo with -ac 2 and saved as a 192 kb/s MP3. Noise is the worst case for waveform detail, so real music and speech give smaller files. The commands are the ones above with -preset veryfast added (-crf 23 is the default). Test machine: i9-14900KF, FFmpeg 8.1. Measured 2026-09-24.

Output Time Size
showwavespic 1920×480 PNG 0.25 s 11 KB
showspectrumpic 1920×480 PNG 0.40 s 1.4 MB
showwaves cline 1280×720 / 30 fps / 3 min 18.4 s 148.4 MB
showwaves cline 1920×1080 / 30 fps / 3 min 21.3 s 161.0 MB
showspectrum 1280×720 / 3 min 5.7 s 13.4 MB
showfreqs bar 1280×720 / 3 min 17.6 s 35.8 MB

The table shows two things.

  1. showwaves video compresses badly with H.264. Thin lines move across the whole frame in every frame, so motion prediction (saving space by storing only what changed since the previous frame) barely works. The 3-minute video came out at 148.4 MB (about 6.6 Mbps), while the spectrogram video of the same audio is 13.4 MB. At the same 1280×720, mode=point brought it down to 71.2 MB, a video of only a 200-pixel strip to 80.7 MB, and -crf 28 to 95.8 MB (mode=line: 92.0 MB). The filled cline mode gives the largest file.
  2. 720p and 1080p are close in size (148.4 MB and 161.0 MB). With 2.25 times the pixels, the file grew by less than 10%.

FAQ

The output is all black / no waveform visible

showwaves and showwavespic output a transparent (RGBA) background. Players and image viewers that cannot show transparency display it as black. Add a background with color and overlay as shown above. For quiet recordings, scale=sqrt or scale=log makes the waveform easier to see.

I want one waveform for a stereo file

By default, showwavespic draws the channels on top of each other (split_channels=0). For a single waveform, put aformat=channel_layouts=mono in front of it to mix the audio down to mono first.

The waveform video has no sound

-map 0:a is missing. Once you use any -map, FFmpeg stops choosing streams automatically. So after -map "[v]" for the video, you also need -map 0:a for the audio.

The Waveform video tool generates a showwaves-style video from an audio file in your browser.