Painfully won, maybe this ffmpeg
incantation can help you, dear reader.
I’m working on a project at the moment that involves applying a variety of digital effects to a webcam video stream. In my preparatory research for the video effect tooling, I discovered that there’s actually a fascinatingly large number of audio/video filters for ffmpeg
.
This solution appeals to me for a few reasons:
This solution also frightens me because ffmpeg is arcane and obscure (relative to most tools I like to use.)
So, I thought I’d write up what I did and how I learned it! Primarily so that I can use it in the future for my own reference.
The google results for “stream ffmpeg webcam video stream” are mostly unsolved requests for help on stack-overflow 🙃
However, there are some useful tidbits here and there.
First, we need to know what our device is called, according to ffmpeg. On Linux, this can be done with v4l2-ctl --list-devices
(I had to install the v4l-utils
package on Fedora.)
On my system, the default webcam is /dev/video0. So let’s test to see if we can simply record from the webcam to a file:
ffmpeg -f v4l2 -i /dev/video0 output.mp4
I’d call that a success!
The simplest thing here is to use one process to create a video stream, and another to open it. This way our capturing ffmpeg incantation isn’t too long.
To stream:
ffmpeg -f v4l2 -i /dev/video0 \
-framerate 25 \
-video_size 1280x720 \
-f mpegts udp://localhost:1234
We can open up the stream with a simple ffplay -fflags nobuffer udp://localhost:1234
. (-fflags nobuffer
removes a ~10 second buffer that ffplay adds for some reason.)
now we can review the ffmpeg documentation, specifically the video filters.
Let’s try this out.
ffmpeg -f v4l2 -i /dev/video0 \
-framerate 25 \
-video_size 1280x720 \
-vf edgedetect \
-f mpegts udp://localhost:1234
Run ffplay -fflags nobuffer udp://localhost:1234
again, and let’s see what the result is…
Success! We’ve got edge detection working:
ffmpeg -filters
gives us a list of all the filters that exist in our installed copy of the utility - any that are marked V->V
are video-to-video, and we can experiment to see what cool stuff we can find. waveform
and elbg
are both interesting - this is gonna be the fun part.
I want to speed up trying out new filters. It’d be very nice if I could simply type out a filter name, maybe some parameters, and hit CR
to see the results immediately. This is all to preface the following very bad, no-good, totally incorrect, inflexible, “works-on-my-machine”, highly effective script (provided in large part by chatGPT.)
#!/bin/bash
# handle termination signals and kill both processes
terminate_processes() {
echo "Terminating processes..."
kill -TERM "$pid1" "$pid2" 2>/dev/null
wait "$pid1" 2>/dev/null
wait "$pid2" 2>/dev/null
exit 0
}
# Trap termination signals
trap terminate_processes SIGINT SIGTERM
# Run the ffmpeg command to capture and stream the webcam in a terminal window and store its process ID
alacritty --command ffmpeg -f v4l2 -i /dev/video0 \
-framerate 25 \
-video_size 1280x720 \
-vf "$1"\
-f mpegts udp://localhost:1234 &
pid1=$!
# Run the ffplay command in a terminal window and store its process ID
alacritty --command ffplay -fflags nobuffer udp://localhost:1234 &
pid2=$!
# Wait for either of the commands to finish
wait -n "$pid1" "$pid2"
# If one process is terminated, kill the other one
terminate_processes
It works perfectly for me :)