Let’s take a look at how to set up a USB TV Tuner with Linux using w_scan2
, dvbv5-zap
, and ffmpeg
.
Prerequisites
Hardware
You probably already have some hardware in mind but for reference, I am using a Hauppauge tuner originally designed for Xbox but it works just as well with Linux. My corresponding lsusb
line is ID 2040:b123 Hauppauge
. I’m using this with a Raspberry Pi 4, 4GB but nothing here is particular to the Pi so it shouldn’t make any difference. I have installed 32-bit Arch Linux on it as shown in an earlier post.
Permissions
Most likely, your video device is already moved to a video
group for security. But your user may or may not be part of that group already. To add yourself to the group that can access your video device, check
I use
sudo
rather thansu
in this tutorial, but which one is appropriate depends on your installation
# Check that the devices are there
test -d /dev/dvb/adapter0 || echo "DVB devices are missing."
# Read this to see what the group is for your adapter. Usually it's "video"
ls -lh /dev/dvb/adapter0/*
# Add yourself to "video" or whichever group the adapter is in
sudo usermod -aG video $USER
At this point you should logout/login or restart in order for group settings to take effect
Software
You need w_scan2
to search for channels in your area. There are other scanning utilities, like dvbv5-scan
but they require you already have an initial scan file, which is difficult to find or create without using w_scan2
, and w_scan2
can already do the rest of the scan for you too. So you might as well use onlyw_scan2
# Build requirements
sudo pacman -S --needed base-devel git
git clone https://github.com/stefantalpalaru/w_scan2.git
cd w_scan2
./autogen.sh
./configure
make -j `nproc`
Scan for Channels
Actually scanning for channels is not that hard once you have the right package. Feel free to poke around with the array of options w_scan2
offers but I found most of them have reasonably defaults for over the air TV. YMMV, especially if you are trying to use cable or satellite. I doubt whether these cards will be of any use in those cases because they are usually encrypted. At any rate, your command will probably look something like the following:
# Still in the w_scan2 repository, run the scan
./w_scan2 -c US -M | sed 's/VSB-8/8VSB/g' | tee > ~/channels.conf
Side note on modulation errors
This is where things derailed for me. I kept getting errors that looked like this:
ERROR parameter MODULATION invalid: VSB_8 while parsing line 1 of /home/sean/.mplayer/channels.conf
In my case I had to replace instances of VSB-8
with 8VSB
, which I only found by combing through the dvbv5-zap
source code looking for what caused the error I saw. It seems the modulations are hard-coded and disagree on what exactly the names should be. It was hard to find but easy to fix, which you can see I did with sed
. If you are getting a similar error you might need to see if you are affected by a similar problem.
Recording
The old way
mencoder
can copy the recording for you, but I doubt whether you will like the result. The issue is that mencoder
is trying to do too much by packing and unpacking the data, which:
- Wastes CPU and could cause you to skip some frames unnecessarily
- Propagates reception errors
- Causes problems with A/V sync
There may be a combination of -mc _
, -noskip
and others that can resolve the AV sync issues, but even though it shows up a lot in tutorials, it’s probably not necessary for digital tuners these days. It’s already an MPEG stream so you can just copy it literally straight to disk and sidestep this whole problem.
# Don't bother copy-pasting this one
mencoder dvb://CHANNELNAME -of mpeg -ovc copy -oac copy -idx -mc 0 -o OUTPUTNAME.mpg
The new way
dvbv5-zap
supports concatenating the tuner output to a file, which is probably the simplest and most sane thing to do.
In it’s simplest form, it would look something like this:
dvbv5-zap \
-I zap \
-c "~/channels.conf" \
-C US \
-r \
-o "SERIES_NAME/`date -Isec`.mpg" \
-t 3595 \
CHANNEL_NAME
Option | Purpose |
---|---|
-I zap -c ~/channels.conf |
reads your channel list in zap format |
-C US |
uses US frequencies (this may make no difference since you scanned already) |
-r -o yadayada.mpg |
records the tuner output to yadayada.mpg |
date -Isec |
just creates a timestamp to keep from clobbering old recordings |
-t 3595 |
records for five seconds less than two hours, to avoid overlapping with another recording |
SERIES_NAME |
is whatever you want it to be (but the folder must already exist before recording) |
CHANNEL_NAME |
is the name mentioned in the far left column of your channels list |
Encoding later
Now that your video has already been received, you can take your time encoding it rather than trying to do it on the spot without hiccups.
This is quite easy to do and I recommend doing it with ffmpeg
and open codecs, specifically VP9, Opus, and MKV/WEBM. As a non-free alternative you may choose h264
and aac
in mp4
.
If you use
schedtool
later on, then this process would be good to place on Batch or Idle priority usingschedtool -D -n 19 -e ffmpeg ...
# set $source and $target to the input and output filenames first
ffmpeg -y -i "$source" -c:v libvpx-vp9 -pass 1 -b:v 300K -crf 34 -speed 4 \
-c:a libopus -b:a 64k -ac 6 -mapping_family 1 -f webm /dev/null
ffmpeg -i "$source" -c:v libvpx-vp9 -pass 2 -b:v 300K -crf 34 -speed 1 \
-auto-alt-ref 1 -lag-in-frames 25 \
-c:a libopus -b:a 64k -ac 6 -mapping_family 1 -f webm "$target"
Option | Purpose |
---|---|
-y |
Overwrite output if necessary |
-i "$source" |
Input file |
-c:v libvpx-vp9 |
VP9 video codec |
-pass 1 |
First of a two pass encoding (for better quality) |
-b:v 750K -crf 34 |
Target about 750Kbit/s - change this to your own liking. |
-auto-alt-ref 1 -lag-in-frames 25 |
Enable more advanced encoding |
-c:a libopus |
Use Opus for audio |
-b:a 64k |
Target 64k bitrate for opus |
-ac 6 -mapping_family 1 |
Use six channels for audio, which is mostly to fix oddball channel setups |
-f webm |
Store it in a webm (Matroska) container |
The bitrates shown are appropriate for medium-quality SD but you can find bitrate recommendations from Google as well
Extras
Clock
It’s a good plan to keep your clock synced if you want to schedule recording, so I recommend installing ntpd
to periodically sync your system clock, which is pretty easy to do
sudo pacman -S openntpd
sudo systemctl enable openntpd
sudo systemctl start openntpd
Priority
Newer Linux kernels support soft realtime scheduling, which you can use with schedtool
.
sudo pacman -S schedtool
# You must run schedtool as root to use the realtime scheduler,
# but then you should move back to your own user as soon as possible
sudo schedtool -R -p 10 -e \
sudo -u YOUR_ORIGINAL_USER_HERE \
whichever recording command you choose
Putting it together
Setting up your installation will require your full attention but the recording part can be pretty easily automated with a script like the following.
set -e
script_home="`dirname $0`"
video_user=$1
output_folder="$2"
channel="$3"
timeout="$4"
if test `whoami` -ne "root"; then
echo "This script needs to run as root to use realtime scheduling."
exit 1
fi
if ! test -f "$script_home/channel.list"; then
echo "Channel list not found at $script_home/channel.list"
exit 1
fi
sudo -u $video_user mkdir -p "$output_folder"
schedtool -R -p 10 -e \
sudo -u $video_user \
dvbv5-zap \
-I zap \
-C US \
-c "$script_home/channel.list" \
-r \
-t $timeout \
-o "$output_folder/`date -Isec`.mpg" \
"$channel"