FFmpeg & GStreamer¶
Once the grabber is detected as /dev/video0, you can do almost anything
with it from the command line using FFmpeg or GStreamer. No GUI, no
configuration — straight command pipes.
Installation¶
sudo pacman -S ffmpeg gst-plugins-good gst-plugins-bad gst-plugins-ugly \
gst-libav v4l-utils x264 x265
sudo apt install ffmpeg gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
gstreamer1.0-libav v4l-utils x264 x265
sudo dnf install ffmpeg gstreamer1-plugins-good \
gstreamer1-plugins-bad-free gstreamer1-plugins-ugly \
gstreamer1-libav v4l-utils x264 x265
FFmpeg: the four things everyone wants¶
1. Live preview (no recording)¶
ffplay -f v4l2 -input_format mjpeg -framerate 60 -video_size 1920x1080 \
/dev/video0
A window pops up. ESC to quit.
2. Record to MP4¶
ffmpeg -hide_banner \
-f v4l2 -input_format mjpeg -framerate 60 -video_size 1920x1080 \
-i /dev/video0 \
-f alsa -ac 2 -i hw:1,0 \
-c:v libx264 -preset veryfast -crf 18 \
-c:a aac -b:a 192k \
-t 00:00:30 \
recording.mp4
-t 00:00:30 records 30 seconds. Drop it for infinite recording (CTRL-C
to stop).
hw:1,0 is the Pengo audio card — see Audio capture → for how
to find the right number.
3. Stream to RTMP (YouTube / Twitch / custom server)¶
ffmpeg -hide_banner \
-f v4l2 -input_format mjpeg -framerate 60 -video_size 1920x1080 \
-i /dev/video0 \
-f alsa -ac 2 -i hw:1,0 \
-c:v libx264 -preset veryfast -b:v 6000k -maxrate 6000k -bufsize 12000k \
-g 60 -keyint_min 60 -sc_threshold 0 \
-c:a aac -b:a 160k -ar 44100 \
-f flv rtmp://a.rtmp.youtube.com/live2/YOUR-STREAM-KEY
Replace the RTMP URL with your destination. -g 60 means a keyframe every
2 s at 30 fps (or every 1 s at 60 fps), which most platforms prefer.
4. Re-encode to a more compatible MP4 (e.g. for editing in DaVinci)¶
ffmpeg -hide_banner \
-f v4l2 -input_format mjpeg -framerate 60 -video_size 1920x1080 \
-i /dev/video0 \
-c:v libx264 -preset slow -crf 16 -pix_fmt yuv420p \
-c:a copy \
editing_master.mp4
-pix_fmt yuv420p is the most-compatible pixel format for editing tools and
players.
FFmpeg: useful options reference¶
| Flag | Meaning |
|---|---|
-f v4l2 |
Use the V4L2 input backend (Linux video devices). |
-input_format mjpeg |
Tell the device to output MJPG (compressed) instead of YUYV (raw). MJPG = stable 60 fps. |
-framerate 60 |
Ask for 60 fps from the device. |
-video_size 1920x1080 |
1080p. The grabber only supports this one USB resolution. |
-thread_queue_size 512 |
Buffer more frames in the input queue — helps when the disk or network is slow. |
-fflags nobuffer |
Reduce latency for live previews. |
-preset ultrafast → -preset veryslow |
x264 speed/quality tradeoff. ultrafast is ~real-time, slow gives best quality for the same bitrate. |
Live low-latency preview¶
ffplay -fflags nobuffer -flags low_delay -f v4l2 -input_format mjpeg \
-framerate 60 -video_size 1920x1080 /dev/video0
GStreamer¶
GStreamer is the underlying pipeline that GNOME, KDE, PipeWire, OBS-on-Linux and a lot of embedded media apps use. If you want to build composite pipelines (overlay text, mix with another source, route through custom filters), GStreamer is the way.
Live preview¶
gst-launch-1.0 -v v4l2src device=/dev/video0 ! \
image/jpeg,width=1920,height=1080,framerate=60/1 ! \
jpegdec ! videoconvert ! autovideosink
Record to MP4¶
gst-launch-1.0 -e \
v4l2src device=/dev/video0 num-buffers=900 ! \
image/jpeg,width=1920,height=1080,framerate=60/1 ! jpegdec ! \
videoconvert ! x264enc tune=zerolatency bitrate=6000 ! \
mux.video \
pulsesrc device=alsa_input.usb-Pengo_Pengo_HDMI_Grabber-02.analog-stereo ! \
audioconvert ! aacenc ! mux.audio \
mp4mux name=mux ! filesink location=recording.mp4
Composite: Pengo over a still image (e.g. lower-third for a stream)¶
gst-launch-1.0 -e \
v4l2src device=/dev/video0 ! image/jpeg,width=1920,height=1080,framerate=60/1 \
! jpegdec ! videoconvert \
filesrc location=overlay.png ! pngdec ! imagefreeze ! videoconvert \
compositor name=comp sink_0::zorder=0 sink_1::zorder=1 \
! videoconvert ! x264enc tune=zerolatency bitrate=6000 \
! mp4mux ! filesink location=overlay.mp4
ffmpeg vs GStreamer — which to pick?¶
| FFmpeg | GStreamer | |
|---|---|---|
| Best for | Recording, transcoding, RTMP streaming | Custom composite pipelines, integration with desktop frameworks |
| CLI simplicity | Shortest commands, one-liners | Pipeline graphs (more verbose but more powerful) |
| Used by | Standalone scripts, OBS, most streaming tools | PipeWire, OBS-on-Linux internals, GNOME/KDE media, custom apps |
| Learning curve | Shallow | Medium |
For 95 % of uses, FFmpeg is enough. Reach for GStreamer when you need to build a non-trivial pipeline (PiP, alpha blends, motion detection, custom filters).
Common gotchas¶
Frame drops
If you see dropped frames in ffmpeg's output (drop= field), try:
- Switch from -input_format yuyv422 → -input_format mjpeg
- Bump -thread_queue_size to 1024 or higher
- Confirm your USB port is actually USB 3.0
- Stop competing USB 3.0 devices (external SSDs, etc.) that may share
the same bus
Audio is out of sync
Add -async 1 to the FFmpeg command, or use
-use_wallclock_as_timestamps 1 if you need frame-perfect A/V sync
against wall-clock time.
Black frame
Almost always HDCP-protected content, or a 1080i source, or no actual HDMI signal at all. Verify with a TV plugged into the loop-out — if the TV shows the source correctly but the USB stream is black, it's a grabber issue. If the TV is also black, it's the source.
Next: OBS Studio →, or Audio capture →.