A DIY HTPC/PVR based on Linux + VDR, for DVB-T2

The 1st commandment says: if you're going to use a central antenna downlink/headend in your building, by all means get an antenna input isolator.

This HOWTO is a work in progress - following my HTPC project, which is also destined to be forever a work in progress. I hope to update this text based on later developments.

The historical time frame of this scribble is H2/2019 - H1/2020.

Contents

Introduction

Being a Linux nerd with a family, I've had a twin-tuner PVR at home for a couple years - since the DVB-T arrived around 2012. (More precisely, since the "analog darkness" finally axed us notorious late adopters.) That PVR is/was a factory product with closed-source firmware and no updates. And, during the years my kids had become more adept at controlling it than I had ever been. During the DVB-T era it took a single replacement of all the wet elyts to keep it in good health - but it also had some downsides and bugs in the firmware that never got fixed.

Now with the arrival of DVB-T2, I was wondering if

  1. a factory product was good enough for the freetard part of my soul
  2. any of the factory products satisfies my technical requirements better than a DIY HTPC

With my DIY history, it has always been clear to me that the time and effort that I spend on the "project" can only ever be more expensive than any kind of off-the-shelf factory product.
And, that if I venture to build my own HTPC, it would be forever a prototype, with baby maladies. That the collection of x86 software that I put together possibly won't ever be as slick as a decent Enigma 2 derivative in an off-the-shelf PVR.
And, after the arrival of
this VU+ solo with twin T2 tuners, which I noticed a little too late, it was clear that a stack of PC HW would cost on par, or possibly more.

The question really was: do I care? ;-)

Hardware

Motherboard

I'm not a fan of ARM-based hardware. I'm an x86 conservative.
For decades, x86 has meant something power hungry - if you needed decent processing power, it wasn't going to be something that fits in a quiet living room. And, you do need some horsepower for smooth, high-res video playback in any advanced video codec. You need a beefy CPU - or, you need dedicated HW offload capability, which can turn out to be just as power hungry.

In the x86 world, at the time of this writing, there's a recent(ish) Intel CPU+IGP SoC that probably just fits the bill: the Gemini Lake ATOM. It has the second generation of Intel IGP's to support HW accelerated H.265/HEVC, and although some say that it's just a bit of cosmetic makeup over the Apollo Lake generation, in reality it does have some published improvements (decoding of 10-bit color depth, which does not mean 10-bit HDMI output unfortunately (for some)) and likely contains some further "fixes" over the 1st-gen H.265 support. A good portion of the video offload functionality actually seems to consist in firmware, and minor fixes do happen to the firmware, available as blobs.

Around the time of this writing (late 2019 / early 2020), the Intel shortage makes purchasing the "base platform" a bit of a challenge. The ecosystem of ITX motherboards does not exactly flourish = apart from empty shelves in the e-shops (especially during 2019), the selection of models with different feature sets (port counts) is rather narrow.
Note that the NUC is not my form factor of preference, for several reasons: essentially too small = too constrained in "features" (peripheral extensibility) and with troublesome heatsinking, especially if a full-fledged iSomething CPU is involved.

My favourite vendor Gigabyte have announced their own Gemini Lake boards as early as 2018, but apparently they've never hit the shelves in my part of the world (maybe except for some early batch). Interestingly, their competitor AsRock keep supplying our market, as long as Intel can provide their chips. I can see individual pieces of AsRock Gemini Lake boards appearing in the local e-shops. Maybe the DIY ITX PC market is not that significant after all = the bare motherboards do not sell nearly as swiftly as notebooks, NUC's and other "ready to use" products...

I ended up settling on the AsRock J4105-ITX. By the time I voted with my money, I knew that I'd have to learn how to install Linux on a UEFI-only motherboard, and I was fine with that, took it as a challenge, a useful piece of education for my job anyway.

Mind the paragraphs in integration pitfalls on USB headers.

Disk drives

And I knew in advance that the J4105-ITX had no M.2/mSATA SSD slot - so I decided to spoil myself and got a cheap SSD for the read-mostly system drive, and some spinning rust for the recordings (bulk video storage).

Tuners

I had past experience with DVB-T tuners based on the Realtek RTL2832U.
Obviously those tuners cannot be used to receive DVB-T2 - because the T2 uses a different modulation in the radio channel.
(Note: there are dongles using the RTL2832P, with an external modulator chip, that do receive DVB-T2 just fine. The name "Astrometa" seems to correlate with that design.)

After looking around for a bit, I purchased two pieces of a tuner dongle locally known as Evolveo Sigma T2, otherwise a re-labeled Mygica T230C v2 (AKA T230C2, as nicknamed by the Linux people). This particular revision of the T230C dongle earned support in the vanilla Linux kernel as of version 5.4, added to the driver called dvb-usb-dvbsky.ko. (Earlier work for this dongle, done in dvb-usb-cxusb.ko, got partly refactored and moved.)

Other people have reported success with a DVBSky T330 - reportedly in the vanilla since about v5.2 if memory serves.

I actually purchased one piece of the tuner dongle in early summer of 2019, tested with software available at the time (Crazycat's driver, VLC and ffplay), and after J.P. van Woerkom came up with his paches to dvbsky.c, I concluded that it had a chance... and during the autumn, I purchased another piece of the tuner dongle, and all the rest of the HTPC hardware.

I gave quite some thought to "mechanical integration" of the tuners.
The tuners come in the form of dongles in a plastic case - not very appropriate for "embedding" / mounting inside a chassis, and even in open air, they seem to run a little hot (especially when active).
I ended up disassembling the plastic shells - it's easy to do even with just your fingernails, the shells are made of two halves and not glued nor welded together, they come apart easily enough.
After de-soldering the IR sensors and documenting their pinout (I ultimately re-used them on a long leash as external sensors), I sandwiched the bare dongle PCB's between two pieces of flat aluminum. I padded and thermocoupled the PCB's between the aluminum bars by two hefty pads of 4mm-thick "thermocoupling chewing-gum" (some white variety, that looked electrically isolating). The aluminum parts now function as heat spreaders, caressed by the lazy draft of air in the chassis, propelled by a slowed-down fan.

The dongles get their input signal from a conveniently shaped 1:4 passive splitter, mounted into the rear wall of the chassis. I chose a splitter that has 2 outputs facing inward (for the tuner dongles) and three connectors outside the chassis: input in the middle and two outputs on the sides. This is deliberate. I could use a 1:2 splitter, but then I'd need to use an external splitter to provide signal to another receiver that I'm keeping around just in case... I.e. the extra output ports of the splitter provide "RF signal pass through" - albeit passive (1:4 = cca -8 db).
I use F-connectors wherever I can, rather than IEC. In this case, as the tuner dongles have an IEC female for antenna input, I had to use two conversion plugs (F male to IEC male) between the 1:4 F-splitter and the tuner dongles. Not much of a problem, the case is deep enough.

To connect the tuners to the motherboard, I used some off-the-shelf "USB header break-out cables". I just needed to trim some excessive plastic off the USB-A female connectors, so that I could get the USB ports closer together. And I re-wired the red conductors to take +5V straight from the PSU, rather than +5VSB from the motherboard. It appears that the dongles' IR sensors cannot be used to wake up the computer, so it makes sense to save some stand-by consumption (the dongles would otherwise remain warm even when idle, on stand-by power).
I re-wired the USB power for the dongles non-destructively by releasing their pins from the header plug's plastic body, and by making an extension cable (single red conductor) with a 2-pin straight header soldered to the end, as a mating counterpart to the modified USB breakout cable.
Thus, I can leave the motherboard powered by +5VSB during ACPI S5 (soft power off) including the wireless keyboard receiver for the RII X1 mini-keyboard, which can be used to start the box (verified).

Remote control

Infrared remotes have the disadvantage that they need direct line of sight between the handset and the sensor on the PVR - even worse, you often need to point the handset (observing the IR LED's transmission diagram). Also, while some DIY LIRC interface on a serial port could theoretically be used to start the HTPC, the IR sensor in a typical USB tuner dongle does not have that capability.
That's why I'd been watching wireless keyboards and mice, as an alternative way to control the HTPC. Specifically, the variant with a proprietary link in the 2.4 GHz band (as opposed to standard Bluetooth, also in the 2.4 GHz band) - because the proprietary link is said to last longer on batteries (compared to Bluetooth, which may be an information out of date nowadays) and because the proprietary radio looks like a generic USB keyboard (+mouse, composite device) = can be used to wake up the HTPC from ACPI S5, as long as the USB port is powered from +5VSB. Proven to work on the J4105-ITX.

It has always been my general idea, to use the HTPC primarily as a PVR/SetTopBox, but to be able to "toggle into PC mode" if desired - to have a minimal desktop with general purpose apps (browser, terminal etc.) Plenty more info on the details in the chapter on software. This dichotomy (TV appliance vs. PC) has several aspects, among others it reflects in the "choice of optimal remote control":

I ended up ordering the RII Mini X1 from Deal Extreme (not sold locally where I live). That wireless keyboard + touchpad combo is about as big as a typical IR remote. Note: I chose the X1 over the K1, as the X1 is closer to a proper PC keyboard, e.g. it has a normal Escape key. That said, Riitek makes a whole family of mini keyboards, some of which are closer to a standard TV remote.

And I discovered, that I can also use several IR remotes that I have in the household, via the integrated IR sensor in the Evolveo/Mygica. (I actually desoldered the sensors and put them on a longer cable outside the chassis.)

Both these remote controls can be used in parallel. They're both on the table, grab whichever feels handy at the moment.

Only the wireless RII can be used to start the HTPC.
The IR sensor in the TV dongle apparently cannot do that.
Perhaps a DIY LIRC receiver on the COM port could do that.
I may try to build one, if I get dissatisfied with the receiver that comes integrated in the TV dongles.

Chassis

As far as Mini-ITX chassises for HTPC use are concerned, I am disappointed. The chassises available are too large, or inconveniently shaped, or ugly, or expensive, or all of that combined - and I generally find the arrangement of their inner space inconvenient for my HTPC needs.
They don't have much in the way of cable management and little thought is given to heat dissipation, in spite of the fact that those ITX boxes are typically built for 60W-class CPU's.
I was looking for something the size of a standard "stackable home Hi-Fi component".

I remember the age when the VCR was a dream machine for anybody's living room - and nowadays I was wondering if I could use an old VCR chassis (mechanical case) as a DIY HTPC chassis. A quick Google search has shown prior art in exactly that direction. In the end I even managed to find a stray old VCR of the same model that was used in one of the YouTube movies :-)

As expected, the chassis took quite a bit of patient customization to have it accept a Mini-ITX motherboard and the other components. The plastic chassis body is made mostly of pressure-cast solid Polystyrene, and therefore quite fragile - one has to be careful with the hacksaw. Fortunately the chassis has a "belly plate" consisting of a soft steel sheet. After some patient measurements, it was not much of a problem to drill some holes in the ATX footprint for M3 spacers to support the motherboard - etc.

My CPU has <10W TDP (more like 5W) and my goal was to provide the box with a faint but forced draft of fresh air, along and across all the (minuscule) heat sources inside - including the surprisingly nice heatsink on the Gemini Lake "Celeron" J4105 SoC. As I decided not to use a computer PSU with a fan integrated, I added a silent low-RPM 60mm fan of my own in the corner of the chassis near the mains PSU, and drilled some holes into the opposite sideways wall (soft steel sheet) for air intake.

I have also kept the original power button in operation. Instead of the original PCB behind the buttons, I used a piece of PCB breadboard to mount a single micro-switch in the right position, working as an ATX power button. It appears to work fine.

Power supply

During the last years, I've tried several times trawling the web for an ITX-class PSU to match a modern ATOM-based setup. Roughly speaking, I've found the following choices:

I ended up buying a single-output "enclosed" 50W 12V PSU by MeanWell, passive but richly vented - the LRS-50-12. Externally, its output gets stepped down by three cheap sync-rectified buck converter boards, and a handful of discrete components - I have breadboarded a "triple ATX buck" on my own, on a universal PCB, to match my taste in heat dissipation and power rail dimensioning. The triple buck is not "enclosed", but it need not be, as it does not pose a risk of shock upon an accidental touch.
I've used the following buck converter boards:


Thermally the three buck converters are all very fine.

triple buck - click for a PDF
Click the picture to download a PDF. You can also download the Kicad schematic file.

Hardware integration pitfalls

I.e., stuff that I did not expect, that caught me off guard.

USB headers on the J4105-ITX

I planned right from the start to hide the USB tuner dongles inside the chassis. For that, I needed 2 ports of USB 2.0 on internal headers. Another header would be convenient to host the USB radio of the wireless RII mini.

And indeed, the J4105-ITX features a total of 3 lanes of USB 2.0 on internal 2.54mm headers.
There's one dual-port header and another single-port header. (One last lane is probably routed to the MiniPCI-e slot.)
Plus, there's a USB 3.0 dual-port header - nice to have for the chassis front ports. And, you bet that I bought some extra USB 3.0 breakout cable (found some from DeLock) and hacked that into the front panel of the vintage VCR chassis.

So I connected all the breakout cabling, connected the dongles, and the wireless keyboard radio, and... to my surprise, the dongles connected to the dual header (USB_0_1) did not work. I went on to try some USB flash thumb drives... same story. Keyboards and mice did work though. What ho, are these USB 1.1 or what? In a Gemini Lake SoC? The SoC datasheet says USB 2.0, the board manual says 2.0... Yet, after plugging a USB 2.0 high-speed device, sometimes I got nothing, sometimes I got an error message from the USB XHCI / physical layer. After fumbling with the cables for a couple minutes, suddenly the cursed USB 2.0 header started to work just fine. As if there has never been a problem.
What?
At that point, it dawned on me, that the high-speed devices had started to work since the moment I pulled the blue USB 3.0 breakout cable out of its respective header.

Which gave me a straight-forward suspicion, that the USB 2.0 lanes within the USB 3.0 header (labeled USB3_0_1) had their pinout wired parallel with the nearby USB 2.0 header. Which has proved to be true, and ultimately I've found a note in that sense in the motherboard manual. So after all, this is an RTFM.

I ended up disconnecting the USB 2.0 lanes in the USB 3.0 breakout cable - so that I could have the blue front panel ports available at least for USB 3.0 devices. It does work that way. And the USB 2.0 lanes are available to the two USB tuner dongles hidden inside the chassis.

Motherboard heatsink thermocoupling

The passive CPU heatsink runs surprisingly cool. Except, I have noticed that coretemp reports values towards 60oC under load - while the heatsink is barely lukewarm. I ended up removing the heatsink, I gently scrubbed off the grey "sarcon look-alike" chewing gum (by that time already solid! and about 0.5mm thick) and applied a small bead of the the Ceramique paste on the SoC chip. Before slapping the heatsink back, I also noticed that the heatsink itself was painted (or eloxed?) even on the underside, where it should absorb heat from the CPU. So I shaved that paint or elox away, in the area of contact, trying to keep the surface as flat as possible.

This has lowered the coretemp readings by about 10-15 oC.

If you try that, please be super-careful when manipulating with the nylon heatsink holder bolts. The "harpoon ends" need to be pressed together to pass through the PCB holes backwards, while at the same time some dense bus traces on the PCB seem to be routed very close to the mounting holes (no safe distance, apparently). While messing with the harpoon-ended nylon bolts, you risk ruining those bus conductors.

Antenna input isolator

After years of ignorance, I have learned to appreciate the subtle beauty of an external galvanic isolator (capacitive coupler) at the antenna input of your TV receiver (PVR, HTPC).

Please note that using those USB tuner dongles on an HTPC with "class I" protective grounding is very different from using that same dongle model on a notebook, possibly running on battery, or having an earth-isolated external "black brick" adaptor (secondary common/return contact possibly floating independent of Protective Earth in the wall socket).

I've known for years that large networks of small-signal devices sharing a common signal ground potential are prone to EMI and unequal earth potentials across the network. Until one minor "overvoltage event" along those lines ended up harming the HDMI output on my motherboard. I can use the DVI output (same framing, the difference in connector is pretty much mechanical) but the damaged HDMI port is a shame. My shame.

There are several possible scenarios of how it can happen, that you get a spike of relatively high voltage difference between different PE points in a building.
In 3-wire systems with a "neutral" conductor separate from the PE, this should only ever happen upon an accidental short circuit of live to the PE. In legacy 2-wire systems, where the mains "neutral" conductor shares function of the Protective Earth, you can get kit zapped merely by plugging in an SMPS notebook adaptor into the wall, while your HTPC near by is plugged into the building's (earthed) central TV signal headend.

In my case, the TV antenna input was the link to the broader "protective earth" system in the building, and as my local PE potential glitched too high (upon me connecting a notebook adaptor to the same "mains circuit"), Mr. Kirchhof arranged that some fault current has flown through the antenna ground, and the HDMI cable's ground.
And, while all my home electronics boxes are Class II devices (possibly for this one reason), the HTPC is a Class I device (signal and chassis common ground earthed to the PE). At that moment in time, the antenna was plugged into a TV set, which was connected by an HDMI cable to the PVR being constructed. Thus emerges the path from the local PE "island" through the HTPC and the TV set into the antenna's wall socket. Apparently, the HDMI driver (level shifter) was the softest spot in the signal chain.

An "antenna cable isolator" is a box with two coax connectors and two capacitors, that couple the live center pin and the shield (GND) between both sides of the isolator.
If you insert an antenna isolator just before your TV receiver (or PVR), you slash that extra link between protective earth potentials at different mains branches in your building, you confine any "earth overvoltage" mischief of your own inside your own local "island of PE reference".

I.e., an antenna input isolator would've saved the HDMI output of my motherboard.

I now understand, why all the consumer electronics gear for the living room is "safety class II" = floating ground and plastic boxes. Apart from price, the plastic boxes isolate the consumer from grounding issues. While the signal interfaces are typically not earth-isolated, by connecting a couple of such boxes together you merely create an island of common reference ground, insulated from the rest of the world - or at the very worst, earthed at a single point to the building's common antenna downlink (headend amp).
I also understand a part of the motivation why some "black brick" notebook power adaptors do not have their secondary GND connected to the primary PE.
This approach used to be less of a problem in the days when everything was powered by 50Hz iron-core transformers. Those have very little capacitive coupling between the windings. In contrast, modern-day electronics, powered by SMPS modules, have inherent significant RF coupling from the primary to the secondary side, which is blocked by Y-caps, which results in capacitive leakage of 50 Hz into the earths of the powered equipment...

Software

OS = Linux

The good thing about Linux is freedom of choice. You are free to elect whether to stay ultra-conservative with Debian stable, or try the effortless and cautious bleeding edge in the form of the quarterly Ubuntu edition (also as a basis for your own compilation of fresh versions of selected apps "from source"), or go with RedHat/Fedora if you're orthodox, or try some rolling release distro, or just follow your personal inclination.

In my case, I first "tested the water" in the spring of 2019 in the then latest Ubuntu Cosmic, and after seeing a chance of success, I later installed Debian 10 (cca 10.2 at the time = fall of 2019) now on production hardware and repeated the compilation of key video stuff from source (see below).

When playing with VDR and front-end plugins (see below), you are free to choose your window manager for the front end, or you can work without an X-desktop = your VDR front-end can run as an exclusive app on a kernel framebuffer, that including vaapi acceleration (not sure about cuvid).
The choice of window manager (or no window manager) will result in minor nuances in behavior of VDR in response to user interface input, window manager events etc.

In my case, I knew I wanted some light desktop with multiple workspaces. I.e., perhaps not as spartan as Matchbox (the tiling fullscreen thing). Unsurprisingly, I ended up using XFCE - my overall favourite lightweight WM.

TV UI = VDR

Among the "TV apps", the typical order/ranking is Kodi, MythTV and then maybe, somewhere far behind, follows VDR.

Once again the freedom of choice is priceless. Kodi and MythTV sure have their following and address a wide range of needs and problems. Except... to me, for the moment, or when I first tried, they did not address my primary concern very well: DVB-T2 reception. In both of those apps, T/T2 reception is a bit of an "appendix", depending on an external headend app, T2 was buggy etc. Also, Kodi and MythTV seem a tad bloated for what I need them for.

VDR is comparably lighter weight, perhaps not as vibrant with frenetic development, but stable enough at 2.4.1 and getting further updates - and, being proven for many years with DVB-T, it has just about become practically useful for DVB-T2. It might use some minor improvements in the way of ergonomy of its UI, but that's comparing to a PVR UI I've been using for the last 8 years (which has kind of gotten under my skin). Also, VDR seems to have a friendly local community of hackers in Germany, which is "just next door" to me on the globe and in the E.U.

The VDR core is essentially a back-end service. To actually watch TV locally, you need a "front-end plugin". On Intel hardware, you have a choice of two plugins: the vdr-plugin-vaapidevice and vdr-plugin-softhdvaapi (a part of the softhdcuvid project). The current codebase of both these plugins has common origins in the venerable vdr-plugin-softhddevice (which itself has been unmaintained for several years, and of which these new plugins are forks).
Alternatively, instead of native plugins, you can also use Kodi (with some Kodi plugin) to connect to a VDR service and watch TV that way.

Support for A/V codecs

In Linux, many pieces of software use the FFMPEG package for video decoding (or encoding).
The FFMPEG package contains a few stand-alone executables for simple command-line work and troubleshooting, but perhaps most importantly, it provides the "codec back-end" = a library called libavcodec (really a set of libraries whose names start with libav*).

FFMPEG or more precisely the libav* libraries contain a number of software-based codecs, optimized to squeeze the maximum out of the instruction set of the CPU.
But, there's also a possibility to offload some decoding of specific supported codecs into GPU hardware. Namely, there's the VA-API (= a generic interface standard) and for Intel IGP's there's a VA-API implementation called libva (from Intel). And it's exactly the libva that introduces HW offload of H.265 HEVC into Gemini Lake IGP hardware.

For the video offload to work on Gemini Lake IGP hardware, you need to download all the firmware blobs that the kernel asks for when loading the in-kernel driver.

Video file players

Try VLC, and only if that doesn't suit your needs, look for something else...

VLC has a rich set of codecs in its own codebase, but can also use FFMPEG and maybe vaapi. For that, you may need to compile VLC from source... good luck with all the dependencies.

Normal mortals just use the VLC from distro repo.

LIRC = the software side of IR remote control

Allright, it's for the IR remote control, but exactly what is this good for? Doesn't Linux have all that's needed "in the basic package" ?

Let me go back into history a little.

Originally when Lirc was released, around the turn of the centuries, Linux had no in-kernel support for IR, there were no USB TV dongles with IR built in (as there was hardly any USB), there were a couple specific TV receiver cards for the PC (in the PCI form factor) which might have a proprietary IR sensor included, and perhaps there were also some stand-alone IR receivers... but there was no unifying support for IR remote controllers in Linux.

So in the old days, you could get IR remote control in Linux by using some existing IR handset and build a simple DIY IR interface for the serial port. All it takes is a three-legged IR receiver (essentially a photo-transistor + amp in one), a DB9 connector and a few additional components. Each pulse received from the "IR remote" triggers an IRQ from the UART, the frame decoding (bit banging) is done in software on the host PC.
Back then it made perfect sense to have a daemon that receives the IR frames and provides clean output on a local interface in the Linux OS, for other applications to use.
Both the DIY IR receiver and the named pipe in the local system still exist and can be made to work.

In the more modern days, the most popular TV tuners for the PC have taken the form of USB dongles, there are several chipsets for these gadgets, and often the dongle also has an IR sensor built in. And, if you're lucky enough to have your dongle supported in the Linux kernel, you will likely also get support for the IR receiver in the dongle.
IR receiver drivers are now a subclass of the generic "input layer" = they get a place in the device tree next to HID devices such as mice and keyboards.
The kernel's "input" devices are also auto-imported into Xwindows (xinput layer). Thus, theoretically you don't need Lirc anymore. And it's true that some button-pushes from the remote will make it all the way to the Xwindows "keyboard buffer".

But there are several catches here:
Firstly, in order to control VDR by your IR remote via the xinput layer, you need to map the IR buttons to some existing/meaningful XKeySym keystrokes, which pretty much correspond to a standard PC keyboard layout = you're a little limited.
Secondly, the XKeySym keystrokes appear anywhere where your focus happens to be, completely ignorant of whether this is appropriate or not.
Thirdly, when VDR loses focus, it stops receiving input (keystrokes) from the xinput layer = "the remote controler handset stops functioning".

The LIRC socket in the system is useful exactly for that purpose and reason: it is an "out of band" control channel that ignores Window Manager focus. If you control your VDR with an IR remote via LIRC, it doesn't matter if VDR's visual window happens to have focus or not. It will respond to LIRC all the time.
So if you choose to go with LIRC, you will probably want to prevent Xwindows (xinput) from registering events from the IR input devices. This can be done in xorg.conf, see the chapter on SW configuration for details.

LIRC can also perform things in the OS for you, that are independent from VDR. I.e. you can run miscellaneous scripted actions based on IR keypresses. You can also use LIRC to transmit or re-transmit things via IR (if you have the hardware = transmitter). See the upstream LIRC documentation for details.

Things that need to be compiled from source code

Hopefully in a year or two, all the necessary components will be available in distroes, and compilation from source will be deservedly pointless.

Unless you'll be deploying your OS image to a number of thin production boxes, in which case "a dedicated build machine" makes perfect sense, i.e. if you're building just one HTPC machine for yourself, perhaps it is easiest to do all the building on the target machine.

You should probably start by compiling the kernel. This is because several of the DVB-related and video-related user space tools may want to talk to the kernel via several API's and at compile time they'd better know what API version they should compile against. My preferred way, in terms of least effort, is to install and boot the kernel just compiled, and then proceed to compile the user space software.

While you're booting the new kernel, the i915 IGP driver will likely ask for some firmware blobs. You need to download those and copy them to /lib/firmware. (You may also appreciate a snippet of superficial explanation from Intel, what the firmware is good for.)

Next, you need to compile and install several video/media-related software packages in the user space. Just try to stick to the well known "holy trinity":

./configure
make
make install

And, you may want to use --prefix=/usr as a general rule (unless you know better of course).
Some of the packages are available in a form where they lack a ./configure script, but need one. And the pleasure is yours, to have one generated.

I recommend that you build the packages in approximately the following order:

libva

./configure --prefix=/usr --enable-x11 --enable-wayland

libva-utils (most importantly the vainfo)

intel-vaapi-driver

ffmpeg (ffplay needs libsdl2-dev, configure with --enable-shared)

vdr --doesn't have a ./configure at all, set prefix in the main Makefile.
Plugins get a special treatment. When you download a plugin source code, unpack or clone that into a subdirectory under $VDR_src_dir/PLUGINS/src/ and give your plugin subdirectory a name that looks like vdr-plugin-myplugin , i.e. $VDR_src_dir/PLUGINS/src/vdr-plugin-myplugin/ .
If you stick to that naming convention, the plugins will get compiled by the VDR's main Makefile simply upon "make" (which implies "make all"). Note: in contrast to "make all", which applies to plugins automatically, "make clean" does not clean up in the plugins subdirectory. For that, you need "make clean-plugins".

vdr plugin vaapidevice - optional, alternative to vdr-plugin-softhdcuvid=softhdvaapi.
Extra libraries:

libxcb-util0-dev
libxcb-icccm4-dev
libxcb-dpms0-dev
libxcb-screensaver0-dev
libxcb-ewmh-dev

vdr plugin softhdcuvid - optional, alternative to vdr-plugin-vaapidevice
For video decode offload on an Intel IGP, you need its facet called softhdvaapi. In order to switch to this facet, make the following choices in the plugin's own Makefile:

VAAPI=1
#CUVID=1
#LIBPLACEBO=1

Note that there's conflicting information on wheter libplacebo (and glew?) is necessary. The source code's README says that it is required, although a work in progress. In the Makefile you can leave libplacebo out and no harm occurs. Libplacebo is useful for scaling, and reportedly runs the crunching on the GPU. I haven't enabled libplacebo at compile time and softhdvaapi works nonetheless.

vdr plugin femon - optional. Adds a nice "signal quality bar". Note that the vaapidevice plugin has its own "debug information bar", which looks a little different and provides some more detail.

vdr plugin wirbelscan - for scanning the band for transponders / tuning the programs.
Really a pluginized and slightly updated clone of the original cmdline tool w_scan or w_scan2.
Is already a little dated. The command-line t2scan may provide a better service.

Software configuration

Please note that the precise config is forever a work in progress :-)

HDD mount points

I'm using a combination of a cheap 120GB SSD (for the system boot drive) and some 1TB spinning rust, possibly shingled, for video storage and other volatile data.

I generally try to operate SSD's in "read-mostly" mode, if not read-only (which would provide maximum lifetime, at the cost of loss of comfort).
In that vein, I have moved (symlinked) /var/log and /home to the magnetic drive. I'm sure /var/log needs no explanation. As for /home, some software churns its config and cache quite intensively in that directory - such as, web browsers, and some window managers (though possibly not XFCE - there are other usual suspects).
And of course the video storage space of VDR also belongs on that drive.

I was wondering what name to give to the mountpoint for the magnetic disk. "Rust" is already taken in the Linux world... so i chose /hulk , as the magnetic disk is green and bulky (relatively speaking, for the 2.5" form factor).
I.e., I now have the following subdirectories on the magnetic drive:

/hulk/vdr
/hulk/log
/hulk/home

The boot process

It takes the system maybe 25 seconds to boot - but I didn't bother much to minimize the time. Specifically, I could probably disable the boot menu timeout in grub (a couple seconds wasted) and also the BIOS can be set for a superfast POST - at which point the motherboard does not wait for the Delete key, and if you want to enter the BIOS SETUP, you need to use some special UEFI-aware utilities to tell the motherboard to boot into the SETUP once after the next reboot...

The boot of kernel and systemd services and X happens within maybe 8 seconds total. Once the X desktop appears, VDR takes about 4 seconds to start and tune into a channel (= before picture appears). But before all that, the regular POST takes about 7 seconds and the GRUB timeout is 5 seconds.

/etc/modules

In /etc/modules I have just nct6775 to have access to hardware health monitoring on the AsRock J4105-ITX. (Pretty much just the voltages. The CPU temperature is best observed using the coretemp sensor - if you're interested at all).

Kernel command line parameters

As for kernel command-line parameters, I have the following in my /etc/default/grub :

GRUB_CMDLINE_LINUX="net.ifnames=0 mitigations=off video=HDMI-A-2:1920x1080@50D"

(&& update-grub, as you probably know.)
Unless you're paranoid, in a living-room HTPC you probably don't need any countermeasures against Meltdown/Spectre and friends. The absence of "security hole mitigations" will save some CPU horsepower = CPU time = juice, may even make your machine feel marginally smoother.
The video mode argument applies to text console = kernel boot and the text-mode virtual consoles. Xwindows have their own idea of the video mode, and you can rectify that using a modeline in xorg.conf - see below.
And, you will likely use HDMI-A-1 = the first HDMI output. I'm using #2 which happens to have an DVI physical connector. To learn the names of your video ports, try adding
drm.debug=0xe to your kernel command line temporarily.
HDMI and DVI are electrically nowadays pretty much the same, including HDMI audio. Historically DVI is older, was initially slower and did not contain audio. Both use TMDS framing and signal levels and are nowadays generated by the same framer and level shifters - on the J4105-ITX they're literally just two output ports of the same IGP. The presence of HDMI audio in the data stream does not bother older monitors that simply do not decode that part of the frame.

Modelines in xorg.conf

Speaking of graphical resolutions, here goes the relevant portion of my xorg.conf - or rather, the contents of /etc/X11/xorg.conf.d/20-intel.conf :

Section "Monitor"
  Identifier    "HDMI2"
  #Modeline      "1920x1080_50" 141.50  1920 2032 2232 2544  1080 1083 1088 1114 -hsync +vsync
  ModeLine      "1920x1080_50" 148.500 1920 2448 2492 2640  1080 1084 1089 1125 +hsync +vsync
  Modeline      "1920x1080_60" 173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
  Modeline      "1920x1080_24" 63.00  1920 1976 2160 2400  1080 1083 1088 1098 -hsync +vsync
  Option        "PreferredMode" "1920x1080_50"
#  Option        "RightOf" "eDP1"
  Option        "DPMS" "false"
EndSection

Section "Screen"
  Identifier    "Screen0"
  Device        "Device0"
  Monitor       "HDMI2"
  DefaultDepth   24
  SubSection   "Display"
    Depth       24
    #Modes      "1920x1080_50" "1920x1080_60" "1920x1080_24"
  EndSubSection
EndSection

Section "Device"
  Identifier    "Device0"
  Driver        "intel"
  BusID         "0:2:0"
  #Option        "Monitor-eDP-1" "eDP1"
  Option        "Monitor-HDMI-2" "HDMI2"
  Option        "TearFree" "true"
EndSection

The relevant debugging aids here are a listing of /var/log/Xorg.0.log and the command-line util xrandr.

Window manager tweaks

When trying to make VDR work with XFCE, I had to face a few small nuissances.

Firstly, the panels, created by a program called xfce4-panel never really vanish from view. They can be minimized down to 1 pixel, but there's no way to make them vanish completely (unless you want to find the right place in the source code and recompile the panel app from source).
It seems equally impossible to find where the panel gets started from. Ultimately the most viable way of neutering the panel is by renaming or deleting the xfce4-panel binary :-(
Fortunately, this does not prevent you from using xfce. All the needed menus remain available upon the right mouse-click on the desktop (like a context menu) and you can also create desktop launchers for your favourite applications.

Secondly, for some reason, the visual window created by softhdvaapi kept losing focus. This can be largely mitigated using the following configuration option:
Window Manager Tweaks -> Focus -> Activate focus stealing prevention
but even then, somehow, the window only accepts keyboard input if its decorated. In the full screen mode, apparently it does not ever obtain the focus...

As a result, for the time being, I rely on IR remote to control VDR. The IR remote is actually handier than a miniature PC keyboard, in terms of using it in the dark and without looking.
And if you place the sensor high enough, it's even not that much pain to use in terms of pointing at the sensor, compared to the radio-based keyboard.

VDR - tuning DVB-T2

VDR keeps a list of its channels in a file calls /var/lib/vdr/channels.conf.
There are two ways to obtain this file: either you've managed to make vdr-plugin-wirbelscan to work (takes a seed file, created by dvbv5_scan if memory serves, in v3 format, which has some bugs), or the IMO easier way:
use the stand-alone command-line tool called t2scan to produce a channels.conf for you.

t2scan > channels.conf
or to add some further optional parameters, e.g.:
t2scan -Y CZ -o vdr20 -l 33 -r >/var/lib/vdr/channels.conf 2>channels.err.txt

Feel free to combine the latter with a tail -f channels.err.txt in another console (because there's no way to pipe stderr into tee or something).

Some say that the -Y argument can only limit t2scan in its actions, thus possibly preventing it from seeing some transponders if your national "profile" in t2scan's database contains outdated information, or if you want to receive transponders from more than one country.
Apparently the t2scan's VDR 2.x series output format is a t2scan's compile-time default.
In the list of channels, quote channel numbers as per the standard CCIR raster. If you do not provide a list of channels, t2scan scans "the whole range" - see man t2scan, the -L command for details on what "the whole range" is.
The -r should print signal strength and quality figures at stderr while scanning.

Note that t2scan is a fork/successor to w_scan and w_scan2 which have several downsides. And, while t2scan seems like "just the right tool" for DVB-T2, the older w_scan and w_scan2 may be required for DVB-S.

The file channels.conf allows you to sort and edit the channels on your own, in a text editor of your choice. Note that VDR must be stopped (killed) while you're messing with the file.
Alternatively, VDR does have a sorting option in the channels list - use the blue button to "mark" a channel, and the up/down arrows to select the desired location. Confirm by OK.

Valid debugging tools = other ways to talk to the tuner dongles:
maybe dvbv5_zap (from the dvb-tools package) and especially the vdr-plugin-femon. If you have Femon, in the main menu you will find a row called "6. Signal Information". This shows a thin row with basic information - but try pressing OK a couple times. And BACK to close this debugg display. (There's also a stand-alone command-line utility called femon, which doesn't seem to function in my system.)

On a slightly tangential note, in the context of "tuning your TV channels": if you happen to own an old dongle with the RTL2832U, you can try using it as an overview band-scanner (spectrum analyzer). There are two software tools that can do the job:

VDR - program startup

I launch VDR using a simple script:

#!/bin/sh
VDR_BIN='/usr/bin/vdr'
VDR_PLUGINS_DIR='-L /usr/lib/vdr'

#$VDR_BIN $VDR_PLUGINS_DIR --lirc=/var/run/lirc/lircd --plugin="vaapidevice -a pulse" --plugin=femon --plugin=wirbelscan
$VDR_BIN $VDR_PLUGINS_DIR --lirc=/var/run/lirc/lircd --plugin="softhdvaapi -a pulse -f" --plugin=femon --plugin=wirbelscan

The argument  -a pulse  tells the plugin to send audio to the PulseAudio interface in X. Which appears to be the only way to send audio down the HDMI Audio output (apparently the hardware port gets claimed by the Xwindows audio infrastructure).

To have VDR autostart on X startup, I have used the standard XFCE control panel "Session and Startup":
Applications -> Settings -> Session and Startup -> Application Autostart
Once in that tab, click "+Add" and enter /usr/bin/vdr.sh as the executable thing to start (which is where I have placed my script).
Another possibility would be to place the script in /etc/X11/Xsesssion or ~tv/.xsession or some such.
I also have XFCE desktop launchers to start and to kill the VDR binary.
TBD: implement a "shutdown script" (stuff that gets called when you press the power button on the remote).
TBD: use svdrpsend to detach/attach the front-end plugin to the VDR service automatically when switching to another workspace (my XFCE desktop has 4 workspaces).

A valid debugging aid for the HW decode offload environment is possibly the vainfo command-line utility.
The vdr-plugin-vaapidevice (currently suffering from pixelsalat on MPEG 576i) also has a useful built-in on-screen debug display of video stream parameters: frame rate, resolution, compression codec.
The various VDR plugins each have their own cmdline parameters, which need to be entered in quotes - see the examples above and see the Github README's of the individual plugin source repositories. Some plugins may also have a config file. For instance, you can try different deinterlacing algorithms using command line args.

VDR - remote control

VDR needs a file that defines the mapping from several input sources, such as the PC/Xwindows keyboard, or the LIRC socket, to VDR's own "control events".
That file is called /var/lib/vdr/remote.conf, and in my system it looks like this:

XKeySym.Up         Up
XKeySym.Down       Down
XKeySym.Menu       m
XKeySym.Ok         Return
XKeySym.Back       BackSpace
XKeySym.Back       Escape
XKeySym.Left       Left
XKeySym.Right      Right
XKeySym.Red        F1
XKeySym.Green      F2
XKeySym.Yellow     F3
XKeySym.Blue       F4
XKeySym.0          0
XKeySym.1          1
XKeySym.2          2
XKeySym.3          3
XKeySym.4          4
XKeySym.5          5
XKeySym.6          6
XKeySym.7          7
XKeySym.8          8
XKeySym.9          9
XKeySym.Info       i
XKeySym.Channel+   k
XKeySym.Channel-   j
XKeySym.Channels   c
XKeySym.Audio      a
XKeySym.Subtitles  s
XKeySym.User1      F5
XKeySym.User2      F6
XKeySym.User3      F7
XKeySym.User4      F8
XKeySym.User5      F9
XKeySym.User6      F10
XKeySym.Volume-    F11
XKeySym.Volume+    F12
XKeySym.Power      q
LIRC.Power     KEY_POWER
LIRC.Up        KEY_UP
LIRC.Down      KEY_DOWN
LIRC.Left      KEY_LEFT
LIRC.Right     KEY_RIGHT
LIRC.Ok        KEY_OK
LIRC.Back      KEY_BACK
LIRC.Menu      KEY_MENU
LIRC.Info      KEY_INFO
LIRC.Schedule  KEY_EPG
LIRC.Recordings KEY_LIST
LIRC.Timers    KEY_TIME
LIRC.Red       KEY_RED
LIRC.Green     KEY_GREEN
LIRC.Yellow    KEY_YELLOW
LIRC.Blue      KEY_BLUE
LIRC.Volume+   KEY_VOLUMEUP
LIRC.Volume-   KEY_VOLUMEDOWN
LIRC.Mute      KEY_MUTE
LIRC.Channel+  KEY_CHANNELUP
LIRC.Channel-  KEY_CHANNELDOWN
LIRC.Channels  KEY_TV
LIRC.0         KEY_0
LIRC.1         KEY_1
LIRC.2         KEY_2
LIRC.3         KEY_3
LIRC.4         KEY_4
LIRC.5         KEY_5
LIRC.6         KEY_6
LIRC.7         KEY_7
LIRC.8         KEY_8
LIRC.9         KEY_9
LIRC.Play      KEY_PLAY
LIRC.Record    KEY_RECORD
LIRC.Pause     KEY_PAUSE
LIRC.Stop      KEY_STOP
LIRC.FastFwd   KEY_FASTFORWARD
LIRC.FastRew   KEY_FASTREVERSE
LIRC.Next      KEY_NEXT
LIRC.Prev      KEY_PREVIOUS

In my system, initially I started "testing the water" with VDR using the PC keyboard. Only later I added IR remote control (because it takes more tuning).

Notice the somewhat funny format of the file, which apparently is something like:
EVENT_SOURCE_DEVICE.TARGET_VDR_EVENT SOURCE_DEVICE_EVENT
I.e., kind of "backwards".

IR input interface of the kernel

As far as you are concerned, the HW-specific driver for the IR sensor that's a part of your USB TV dongle, should come as part of the "linux-media" driver for your dongle. That's the way it works with the Mygica dongles, and earlier with some of the various RTL2832 dongles.

The key tool here is a utility called ir-keytable , coming from a Debian package of the same name.

Invoked as
ir-keytable -t
it will dump the raw codes coming from the IR sensor, and their interpretations too, if the individual codes are already known (have already been mapped).

For production use, the utility is using "keytable files" / keymaps.
There's a library of predefined keymaps for known remote control units, which can be found in /lib/udev/rc_keymaps/.
You should probably copy your desired keymap file into /etc/rc_keymaps/ . Or, create a new one in that directory.
Note that their format has changed between cca Debian 8 and Debian 10, so that e.g.
this description, while otherwise excellent, is no longer precise about the keytable file format. The format that is current at the time of this writing, has a .toml suffix.
The contents of my keymap file, called /etc/rc_keymaps/vestel_t816.toml , look like this:

[[protocols]]
name = "vestel_t816"
protocol = "rc5"
[protocols.scancodes]
0x080C = "KEY_POWER"
0x0812 = "KEY_UP"
0x0813 = "KEY_DOWN"
0x0815 = "KEY_LEFT"
0x0816 = "KEY_RIGHT"
0x0814 = "KEY_OK"
0x080a = "KEY_BACK"
0x0835 = "KEY_MENU"
0x0822 = "KEY_EPG"
0x083f = "KEY_INFO"
0x0837 = "KEY_RED"
0x0836 = "KEY_GREEN"
0x0832 = "KEY_YELLOW"
0x0834 = "KEY_BLUE"
0x0811 = "KEY_VOLUMEDOWN"
0x0810 = "KEY_VOLUMEUP"
0x080d = "KEY_MUTE"
0x0821 = "KEY_CHANNELDOWN"
0x0820 = "KEY_CHANNELUP"
0x081e = "KEY_TV"
0x0800 = "KEY_0"
0x0801 = "KEY_1"
0x0802 = "KEY_2"
0x0803 = "KEY_3"
0x0804 = "KEY_4"
0x0805 = "KEY_5"
0x0806 = "KEY_6"
0x0807 = "KEY_7"
0x0808 = "KEY_8"
0x0809 = "KEY_9"
0x0827 = "KEY_LIST"
0x082d = "KEY_TIME"
0x082e = "KEY_PLAY"
0x082a = "KEY_RECORD"
0x0830 = "KEY_PAUSE"
0x082f = "KEY_STOP"
0x082c = "KEY_FASTFORWARD"
0x082b = "KEY_FASTREVERSE"
0x0829 = "KEY_NEXT"
0x080e = "KEY_PREVIOUS"
0x0817 = "KEY_PROG1"
0x0818 = "KEY_PROG2"
0x0819 = "KEY_PROG3"
0x081a = "KEY_PROG4"

Note that this is a particular model of a remote control, and not a very new one... In fact, the original remote has long been dead, and I'm using a customized universal/programmable remote for the Vestel PVR just being phased out, after some 8 years of service (yes all the elyts are already replaced). I mean to say that you'll probably need to create your own keymap.

The format of the file should be pretty clear.
On the left, you put the code that gets printed by keytable -t while your pressing buttons on your remote control handset.
The string on the right corresponds to the strings listed in /etc/lirc/lircd.conf.d/devinput.lircd.conf .

To load my polished keymap (or keymaps) automatically at boot, I have the following in /etc/rc.local:

#!/bin/sh

# rectify the infrared keytable
/usr/bin/ir-keytable -c
/usr/bin/ir-keytable -p RC5 -w /etc/rc_keymaps/vestel_t816.toml

This file is nowadays executed by a systemd service called rc-local.
If the rc.local does not get executed, try e.g. systemctl status rc-local .

There are several IR RC protocols in use by different makers of consumer electronics for the living room. The sensor in a Mygica T230C2 appears to only support the rc5 protocol. Which however works with all the ~4 IR RC units that I have around.

So the first thing you should try is keytable -t.
And press some buttons. That should yield some raw IR codes.
Based on those, you write a .toml file.
You apply that file using ir-keytable -w my_keymap.toml .
Once you add a mapping for a particular IR keycode, you should start seeing the LIRC-level code falling out of the socket (using irw).

Configuring LIRC

To use lircd on top of the kernel's "IR-flavoured input" devices, you pretty much just need to stick to the default config of the lirc package in debian:
/etc/lirc/lircd.conf.d/devinput.lircd.conf can stay at the distro default. Apparently this file maps the "devinput" events into LIRC events.
/usr/share/lirc/configs/devinput.conf also stays the same (only mentioned here for the sake of completeness
/etc/lirc/lircd.conf also remains at the distro default /etc/lirc/hardware.conf is defunct and old. If you have one, perhaps just remove it...

Really what's interesting here, is the debugging util called irw . It will dump any button presses falling out of the /var/run/lirc/lircd socket.

For details, consult the current lirc documentation.

Disable IR xinput in xorg.conf

As mentioned before, it's probably a good idea to ask X to keep hands off the IR RC input device.
In my system, I have a file called /etc/X11/xorg.conf.d/41-DVB-T2-lirc-inputs.conf with the following contents:

# inspired by
#  /usr/share/X11/xorg.conf.d/40-libinput.conf
#  https://askubuntu.com/questions/17603/how-to-get-xorg-to-ignore-certain-input-devices
#
# This file prevents X from using input from IR receivers
# that are present on USB DVB-T/T2 dongles.
# See the output of 'xinput --list' for some MatchProduct strings.
#
# Once your IR remote is mapped using ir-keytable,
# in the default config, X-windows start picking up the IR remote buttons
# as keyboard keystrokes. You can use that to pass them to your apps,
# but then this input (IR remote control) is subject to Window focus.
# If you prefer your app to listen to the Lirc socket, and thus evade
# any mischief from the shifting Window focus, you probably want to
# prevent X from receiving the IR Remote buttons as keyboard events.
# Alternatively, you can also just skip keyboard events e.g. in VDR's
# remote.conf (if VDR is the app you're aiming for) and leave the
# IR remote piped into xinput (i.e. delete this config file).

Section "InputClass"
        Identifier "DVB-T USB Dngles with IR - supress them from xinput"
        MatchProduct "DVB-T"
        MatchDevicePath "/dev/input/event*"
        #Driver "libinput"
        Option "Ignore" "true"
EndSection