Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a waveform using ffmpeg

Tags:

php

ffmpeg

I am trying to generate a waveform image using ffmpeg.

I have successfully made a waveform image, however it doesn't look very nice...

I have been looking around to try and style the image to make it look nicer, however I have been unable to find any information on this or any tutorials on this.

I am using PHP and shell_exec to create the waveform.

I am aware that there are php library that can do this but due to file format this is a lengthy process.

The code I am using is as follows:

$command = 'convertvid\bin\ffmpeg -i Temp\\'.$file.' -y -lavfi showwavespic=split_channels=0:s='.$width.'x50 Temp\\'.$PNGFileName;
shell_exec($command);

Basically I would like to add a line through the middle as there are blank spots at the moment and would like to be able to set the background and wave colour.

like image 912
krisph Avatar asked Aug 27 '15 16:08

krisph


1 Answers

Default waveform

Default waveform

ffmpeg -i input.wav -filter_complex showwavespic -frames:v 1 output.png

Notes

  • Notice the segment of silent audio in the middle (see "Fancy waveform" below if you want to see how to add a line).

  • The background is transparent.

  • Default colors are red (left channel) and green (right channel) for a stereo input. The color is mixed where the channels overlap.

  • You can change the channel colors with the colors option, such as "showwavespic=colors=blue|yellow". See a list of valid color names or use hexadecimal notation, such as #ffcc99.

  • See the showwavespic filter documentation for additional options.

  • If you want a video instead of an image use the showwaves filter.

Fancy waveform

Fancy waveform

ffmpeg -i input.mp4 -filter_complex \
"[0:a]aformat=channel_layouts=mono, \
 compand=gain=-6, \
 showwavespic=s=600x120:colors=#9cf42f[fg]; \
 color=s=600x120:color=#44582c, \
 drawgrid=width=iw/10:height=ih/5:color=#[email protected][bg]; \
 [bg][fg]overlay=format=auto,drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=1:color=#9cf42f" \
-frames:v 1 output.png

Explanation of options

  1. aformat downsamples the audio to mono. Otherwise, by default, a stereo input would result in a waveform with a different color for each channel (see Default waveform example above).

  2. compand modifies the dynamic range of the audio to make the waveform look less flat. It makes a less accurate representation of the actual audio, but can be more visually appealing for some inputs.

  3. showwavespic makes the actual waveform.

  4. color source filter is used to make a colored background that is the same size as the waveform.

  5. drawgrid adds a grid over the background. The grid does not represent anything, but is just for looks. The grid color is the same as the waveform color (#9cf42f), but opacity is set to 10% (@0.1).

  6. overlay will place [bg] (what I named the filtergraph for the background) behind [fg] (the waveform).

  7. Finally, drawbox will make the horizontal line so any silent areas are not blank.

Gradient example

Gradient example

Using gradients filter:

ffmpeg -i input.mp3 -filter_complex "gradients=s=1920x1080:c0=000000:c1=434343:x0=0:x1=0:y0=0:y1=1080,drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=1:color=#0000ff[bg];[0:a]aformat=channel_layouts=mono,showwavespic=s=1920x1080:colors=#0068ff[fg];[bg][fg]overlay=format=auto" -vframes:v 1 output.png

Color background

waveform with simple color background

ffmpeg -i input.opus -filter_complex "color=c=blue[color];aformat=channel_layouts=mono,showwavespic=s=1280x720:colors=white[wave];[color][wave]scale2ref[bg][fg];[bg][fg]overlay=format=auto" -frames:v 1 output.png

The scale2ref filter automatically makes the background the same size as the waveform.

Image background

Of course you can use an image or video instead for the background:

Image background example

ffmpeg -i audio.flac -i background.jpg -filter_complex \
"[1:v]scale=600:-1,crop=iw:120[bg]; \
 [0:a]showwavespic=s=600x120:colors=cyan|aqua[fg]; \
 [bg][fg]overlay=format=auto" \
-q:v 3 showwavespic_bg.jpg

Getting waveform stats and data

Use the astats filter. Many stats are available: RMS, peak, min, max, difference, etc.

RMS level per audio frame

Example to get standard RMS level measured in dBFS per audio frame:

ffprobe -v error -f lavfi -i "amovie=input.wav,astats=metadata=1:reset=1" -show_entries frame_tags=lavfi.astats.Overall.RMS_level -of csv=p=0 > rms.log

Peak level per second

Add the asetnsamples filter.

ffprobe -v error -f lavfi -i "amovie=input.wav,asetnsamples=44100,astats=metadata=1:reset=1" -show_entries frame_tags=lavfi.astats.Overall.Peak_level -of csv=p=0

Same as above but with timestamps

ffprobe -v error -f lavfi -i "amovie=input.wav,asetnsamples=44100,astats=metadata=1:reset=1" -show_entries frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.Peak_level -of csv=p=0

Output to file

Just append > output.log to the end of your command:

ffprobe -v error -f lavfi -i "amovie=input.wav,asetnsamples=44100,astats=metadata=1:reset=1" -show_entries frame_tags=lavfi.astats.Overall.RMS_level -of csv=p=0 > output.log

JSON

ffprobe -v error -f lavfi -i "amovie=input.wav,asetnsamples=44100,astats=metadata=1:reset=1" -show_entries frame_tags=lavfi.astats.Overall.RMS_level -of json > output.json
like image 89
llogan Avatar answered Nov 09 '22 02:11

llogan