I will be installing Archlinux ARM on the RPI4, but since that is a real pain, I'll be using Endeavour OS ARM which ultimately gets you Archlinux ARM, but a lot easier to install.
The results will also have the advantage of allowing the user to have a full Desktop Environment and still be able to run mythfrontend when desired. In this case I'll be using KDE Plasma on X11, but with compositor off.
We are going to build MythTV fixes/33
The hardware being used in this example is:
RPI4 4GB RAM
USB3 to SATA SSD Adapter
1TB SATA SSD
USB keyboard
FHD HDMI monitor
SiliconDust HDHomeRun Quatro networked ATSC 1.0 tuner (4 tuners) (HDHR)
Ethernet connected to the HDHR with Cat-5e directly.
WiFi used for an Internet connection.
We will be following the instructions on installing EndeavourOS (EOS) ARM from https://arm.endeavouros.com/. However, you basically get the EOS bootable ISO for your x86_64 laptop or PC and boot the live version so nothing changes on you laptop. Once the EOS ISO has booted, there will be a Welcome window that shows options and one is the ARM installer. Make sure you have a network connection before clicking the ARM installer because this is a network install. You should also have your USB3 SATA SSD plugged in at this point. Once this completes you can remove the USB3 SATA SSD and plug it into your RPI4.
EOS ARM will boot your RPI4 into an Calamares type installer that lets you setup your credentials and choose your desktop environment. In my case I used KDE Plasma as I like it best and it's performance is very good on a RPI4 under X11 with compositor off. Plasma also is easier for setting up other aspects of living on my home network by managing the firewall, creating menu items, and allowing the Dolphin file manager browse the local LAN.
On first boot of the RPI4 after installation of Plasma, at the login page, select X11 because it will default to Wayland which doesn't work well on KDE Plasma and the RPI4. After logging in go to Settings and search for the setting compositor, then disable it on boot.
I overclocked my RPI4 as follows:
edit /boot/config.txt
add these lines to the file:
Code: Select all
arm_freq=2000
over_voltage=6
gpu_freq=750
Code: Select all
sudo systemctl disable --now firewalld.service
https://wiki.archlinux.org/title/avahi# ... resolution
Edit /etc/nsswitch.conf and change the hosts: line to look like this:
Code: Select all
hosts: mymachines mdns_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] files myhostname dns
https://www.mythtv.org/wiki/Build_from_Source
Get the dependencies:
Code: Select all
sudo pacman -S --needed python-pip exiv2 fftw jack lame libass libavc1394 \
libbluray libiec61883 libpulse libsamplerate libva libvdpau libvpx \
libxinerama libxml2 libxrandr qt5-script taglib x264 x265 \
soundtouch git base-devel help2man libcdio libcec libmariadbclient \
libxml2 lirc perl-dbd-mysql perl-io-socket-inet6 perl-libwww \
perl-xml-simple perl-xml-xpath python-future python-lxml \
python-mysqlclient python-requests python-simplejson yasm glew \
mariadb mariadb-clients perl-dbd-mysql perl-io-socket-inet6 libzip python-pyqt5-webengine lzo
yay -S libhdhomerun
yay -S perl-net-upnp
yay -S python-timeout-decorator
yay -S python-requests-cache
Clone the MythTV repository and build from source. If you copy this whole block it should work but take ~2 hours to complete:
Code: Select all
mkdir ~/build
cd ~/build
git clone https://github.com/MythTV/mythtv.git mythtv
cd mythtv
git checkout fixes/33
cd mythtv
./configure --prefix=/usr --disable-vdpau --enable-opengl --disable-vaapi --arch=aarch64
make -j 4
sudo make install
If you want a combo FE/BE, then we have to setup the backend now. The bash script below is what I use. It sets up the Database, mythtv user, directory structure, xmltv, daily backups service, mythtv-backend service, and mythfilldatabase service. You should save it as a .sh file and make it executable. Look for user names and email addresses to get notices or comment that part out. There is also a section of function calls that you can comment out what you don't want.
Code: Select all
#! /bin/bash
# Globals
mythtv_git_directory=/tmp/build
mythtv_git_branch=fixes/33
mythtv_password=mythtv #if changed need to manually update /etc/apache2/sites-available/mythweb.conf
mythtv_storagegroup_path=/srv/mythtv/ # using /srv/mythtv in preference to /var/lib/mythtv/,
mythtv_storagegroups="banners coverart fanart recordings streaming videos bare-client db_backups livetv screenshots trailers music musicart"
# this gets git source for mythweb and mythtv/packaging
fn_get_git()
{
mkdir -p $mythtv_git_directory
cd $mythtv_git_directory
#mythtv packaging - we only need a few files
git clone -b $mythtv_git_branch https://github.com/MythTV/packaging.git
git clone -b $mythtv_git_branch https://github.com/MythTV/mythtv.git
}
fn_setup_mythtv_user()
{
sudo useradd -m --groups optical,audio,video --home /home/mythtv --shell /bin/bash mythtv
# allow default user, to run mythtv-setup
sudo usermod -aG mythtv $USER
# create basic config.xml in /etc/mythtv/ same as ubuntu (mythbuntu ppa)/debian (built from source)
sudo mkdir -p /etc/mythtv/
sudo bash -c "cat >/etc/mythtv/config.xml" <<ENDOFSCRIPTINPUT
<Configuration>
<LocalHostName>my-unique-identifier-goes-here</LocalHostName>
<Database>
<PingHost>1</PingHost>
<Host>localhost</Host>
<UserName>mythtv</UserName>
<Password>${mythtv_password}</Password>
<DatabaseName>mythconverg</DatabaseName>
<Port>3306</Port>
</Database>
<WakeOnLAN>
<Enabled>0</Enabled>
<SQLReconnectWaitTime>0</SQLReconnectWaitTime>
<SQLConnectRetry>5</SQLConnectRetry>
<Command>echo 'WOLsqlServerCommand not set'</Command>
</WakeOnLAN>
</Configuration>
ENDOFSCRIPTINPUT
sudo mkdir -p /home/mythtv/.mythtv/ # for mythtv user
sudo ln -s /etc/mythtv/config.xml /home/mythtv/.mythtv/config.xml
sudo cp $mythtv_git_directory/packaging/deb/debian/session-settings /etc/mythtv/
sudo chown -R mythtv:mythtv /home/mythtv/ /etc/mythtv
mkdir -p $HOME/.mythtv/ # for pi user
ln -s /etc/mythtv/config.xml $HOME/.mythtv/config.xml # for mythfrontend
sudo cp $mythtv_git_directory/packaging/deb/debian/41-mythtv-permissions.rules /lib/udev/rules.d/
sudo cp $mythtv_git_directory/packaging/deb/debian/30-mythtv-sysctl.conf /etc/sysctl.d/
echo -e "\nmythtv user setup"
}
fn_setup_xmltv()
{
# install repository version (gets required perl modules)
yay -S xmltv
sudo ln -s /usr/bin/vendor_perl/tv_* /usr/local/bin/
echo -e "\nxmltv has been installed and updated to latest version"
}
fn_setup_mariadb()
{
sudo pacman -S --needed mariadb
sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql
sudo systemctl enable --now mariadb.service
sudo mysql_secure_installation
#setup timezone info
mysql_tzinfo_to_sql /usr/share/zoneinfo | sudo mysql -uroot mysql
sudo systemctl restart mysql
#setup mythconverg db
sudo mysql -uroot << ENDOFSCRIPTINPUT
CREATE DATABASE IF NOT EXISTS mythconverg;
CREATE USER IF NOT EXISTS 'mythtv'@'%' IDENTIFIED BY 'mythtv';
CREATE USER IF NOT EXISTS 'mythtv'@'localhost' IDENTIFIED BY 'mythtv';
SET PASSWORD FOR 'mythtv'@'%' = PASSWORD('$mythtv_password');
SET PASSWORD FOR 'mythtv'@'localhost' = PASSWORD('$mythtv_password');
CONNECT mythconverg;
GRANT ALL PRIVILEGES ON *.* TO 'mythtv'@'%' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'mythtv'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT
ENDOFSCRIPTINPUT
echo -e "\nmythconverg database created for user mythtv - password $mythtv_password"
}
fn_mythconverg_daily_backup()
{
# setup mythconverg daily backup, instead of weekly (personal preference)
sudo bash -c "cat >/etc/systemd/system/mythtv-database-backup.service" <<ENDOFSCRIPTINPUT
# This service unit is for backing up the mythtv database called mythconverg
#
[Unit]
Description=Backup MythTV Database 'mythconverg'
Requires=mysql.service
After=mysql.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/mythtv-database-backup.sh
ENDOFSCRIPTINPUT
sudo bash -c "cat >/etc/systemd/system/mythtv-database-backup.timer" <<ENDOFSCRIPTINPUT
# This timer unit is for mythtv-database-backup
#
[Unit]
Description=start mythtv-database-backup
[Timer]
Unit=mythtv-database-backup.service
OnCalendar=*-*-* 05:30:00
Persistent=true
[Install]
WantedBy=timers.target
ENDOFSCRIPTINPUT
sudo cp /tmp/build/mythtv/mythtv/contrib/maintenance/optimize_mythdb.pl /usr/local/bin/
sudo chmod a+x /usr/local/bin/optimize_mythdb.pl
sudo bash -c "cat >/usr/local/bin/mythtv-database-backup.sh" <<ENDOFSCRIPTINPUT
#!/bin/sh
# /etc/cron.weekly/mythtv-database script - check and backup mythconverg tables
# Copyright 2005/12/02 2006/10/08 Paul Andreassen
# 2010 Mario Limonciello
set -e -u
DBNAME="mythconverg"
USER=jim
EMAILADDRESS="your-email-here@gmail.com"
/usr/bin/mysqlcheck -s \$DBNAME
BKUP_LOG=/tmp/backup-mythconverg.log
export MYTHCONFDIR=/home/\$USER/.mythtv/
/usr/local/bin/optimize_mythdb.pl | grep -v "^Analyzed:" 2>&1 >> \$BKUP_LOG
sudo --preserve-env --user=\$USER /usr/share/mythtv/mythconverg_backup.pl --rotate=5 --verbose 2>&1 >> \$BKUP_LOG
if [ \$? -eq 0 ]; then
MSG="den-pc \$DBNAME Checked and Backed Up, RC=\$?"
else
MSG="den-pc \$DBNAME Back Up Failed, RC=\$?"
fi
cd /srv/mythtv/db_backups
ls -l --directory --block-size=K * | tail -10 >> \$BKUP_LOG
#mail -s "\$MSG" \$EMAILADDRESS < \$BKUP_LOG
ENDOFSCRIPTINPUT
sudo chmod 755 /usr/local/bin/mythtv-database-backup.sh
sudo systemctl enable mythtv-database-backup.timer
echo -e "daily backup of mythconverg database has been setup"
}
fn_setup_mythfilldatabase()
{
sudo bash -c "cat >/etc/systemd/system/mythfilldatabase.timer" <<ENDOFSCRIPTINPUT
[Unit]
Description=MythTV mythfilldatabase timer.
[Timer]
OnCalendar=05:10:00
Persistent=true
[Install]
WantedBy=timers.target
ENDOFSCRIPTINPUT
sudo bash -c "cat >/etc/systemd/system/mythfilldatabase.service" <<ENDOFSCRIPTINPUT
[Unit]
Description=MythTV mythfilldatabase service.
Wants=mythtv-backend.service
After=mythtv-backend.service
[Service]
User=mythtv
Group=mythtv
Type=simple
ExecStart=/usr/bin/mythfilldatabase
[Install]
WantedBy=multi-user.target
ENDOFSCRIPTINPUT
sudo systemctl enable mythfilldatabase.timer
}
fn_setup_directories()
{
sudo mkdir -p $mythtv_storagegroup_path
cd $mythtv_storagegroup_path
sudo mkdir -p $mythtv_storagegroups
sudo chown -R mythtv:mythtv $mythtv_storagegroup_path
sudo chmod -R 2775 $mythtv_storagegroup_path
echo -e "\nDirectories setup.\n"
}
fn_setup_mythtv_backend_service()
{
#todo check if already exists and skip if it does with message, user may have modified it
# user should have created ovdrride file instead of modifying directly
# for now use -n (noclobber)
sudo cp -n $mythtv_git_directory/packaging/deb/debian/mythtv-backend.service /lib/systemd/system/
sudo systemctl enable mythtv-backend
sudo systemctl daemon-reload
echo -e "\nmythtv-backend.service has been setup and enabled \n"
}
fn_tidy_up()
{
# remove local packaging repositories
rm -fr $mythtv_git_directory/packaging
rm -fr $mythtv_git_directory/mythtv
}
#main
# make sure we are not root
RUNNINGAS=`whoami`
if [ $RUNNINGAS = "root" ] ; then
echo "Please run as ordinary user, not with sudo"
exit 1
fi
#check mythbackend has been installed, if not abort with message
MYTHBACKEND=`which mythbackend`
if [ -z "$MYTHBACKEND" ]; then
echo -e "mythbackend not found"
exit 1
fi
# to disable any fn_ call just put # in front
# change the order at own risk - not tested!
fn_get_git
fn_setup_mythtv_user
fn_setup_mariadb
fn_mythconverg_daily_backup
fn_setup_mythtv_backend_service
fn_setup_mythfilldatabase
fn_setup_xmltv
fn_setup_directories
fn_tidy_up
echo -e "\n**************************************************"
echo -e "\nIf running headless on Pi4, no monitor connected on hdmi port"
echo -e " put 'hdmi_ignore_cec=1' in '/boot/config.txt' and reboot"
echo -e "\nStorage Group directories have been created in '$mythtv_storagegroup_path'"
echo -e "Directories '$mythtv_storagegroups'"
echo -e "Use mythtv-setup Storage Directories to setup those required"
echo -e "\nFor mythtv prior to fixes/31, use systemctl commands to stop or start mythtv-backend"
echo -e " To stop 'sudo systemctl stop mythtv-backend'"
echo -e " To start 'sudo systemctl start mythtv-backend'"
echo -e " Sometimes mythtv-backend maybe 'failed' by systemd, to re-enable use"
echo -e " 'sudo systemctl daemon-reload' followed by"
echo -e " 'sudo systemctl start mythtv-backend'\n"
echo -e "\nxmltv installed and updated to latest version"
echo -e "When using xmltv e.g. tv_grab_zz_sdjson"
echo -e "mythfilldatabase arguments should use '--no-allatonce'"
echo -e "\nmythconverg database password '$mythtv_password'"
echo -e "\nReferences:"
echo -e " https://www.mythtv.org/wiki/Database_Setup"
echo -e " https://www.mythtv.org/wiki/Build_from_Source"
echo -e " https://www.mythtv.org/wiki/Systemd_mythbackend_Configuration"
echo -e " https://www.mythtv.org/wiki/Setup_Storage_Directories"
echo -e " https://www.mythtv.org/wiki/Mythfilldatabase"
echo -e "\nFinished setting up for mythtv-backend - Please reboot\n"
exit 0
This must be run as user 'mythtv'
Code: Select all
sudo su mythtv
cd
tv_grab_zz_sdjson_sqlite --manage-lineups --config-file $HOME/.mythtv/SD.xmltv
Then select the "Initialize/update the local database"
Take the defaults on the next several questions until it exits.
Code: Select all
tv_grab_zz_sdjson_sqlite --configure --config-file $HOME/.mythtv/SD.xmltv
Select the Lineup. If you only have one it will be listed and you can reply yes.
Take the defaults until the command exits.
Code: Select all
tv_grab_zz_sdjson_sqlite --days 0 --config-file $HOME/.mythtv/SD.xmltv
tv_grab_zz_sdjson_sqlite --manage-lineups --config-file $HOME/.mythtv/SD.xmltv
Confirm your lineup.
Choose which channels are selected. Walk thru the channels and select yes or no.
When you're done with the list of channels, just exit.
Exit back to your normal user with 'exit' or ctrl-d
Now setup the backend with:
Code: Select all
mythtv-setup
Under Job Queue (Backend-Specific) I uncheck 'Allow Transcoding Jobs' and 'Allow Commerical Detection Jobs'. The RPI4 is not good at transcoding and Commerical detection also affects performance. Your mileage may vary.
You should uncheck the automatic program guide update in the last General option as we will be using a systemd timer/service for that.
You can make other changes if you want.
Under 2. Capture cards, select New Capture Card 4 times since we have a 4 tuner HDHomerun. The first select of New Capture Card takes some time comparied to the next 3, so wait.
At each New Capture Card entry select HDHomeRun Networked Tuner then press the right arrow and check the tuner you want to use and then right arrow on Recording Options and uncheck Use HDHomeRun for active EIT scan since we are using SchedulesDirect for EPG.
Repeat for the other tuner entries.
Under 4. Video Sources, select New Video Source. It will take a few seconds.Then select the new entry for New Video Source and then select Video Source Name and enter 'SD' which is what we used in our XMLTV setup. Note upper-case 'SD'
For Listings Grabber select Multinational (Schedules Direct JSON Web Service with SQLite D...
Then ESC and save and exit.
Under 5. Input connections select 'MPEG2TS' under Input Name and select 'SD' under Video Source.
Then only on the first Input Connections go to Scan for Channels and go to the bottom and select Scan.
Insert All
ESC and save. Then set the other Input conections up the same, but don't scan for them.
The rest of the default settings of Input connections should work and also allow multi-channel recording for subchannels like 5.1 and 5.2 on the same tuner.
Use 6. Channel Editor if you have some channels you don't want displayed.
Under 7. Storage Group you should fill out at least Default but can do more to suit your needs. Walk the folders for Default to /srv/mythtv/recordings. All of our storage directories in this case are under /srv/mythtv/.
reboot
However, for mythtv-backend to start up properly after booting the RPI4, you are going to have to delay the startup of mythtv-backend until the HDHomerun tuners are discoverable.
Add an override to the mythtv-backend.service with:
Code: Select all
sudo --login systemctl edit mythtv-backend.service
Code: Select all
[Service]
ExecStartPre=-/usr/local/bin/hdhomerun_check.py
can watch recordings etc.) If you want to prevent the backend from starting, remove the dash.
You'll need to put the hdhomerun_check.py in /usr/local/bin and make it executable, owner/group root.
hdhomerun_check.py
Code: Select all
#!/usr/bin/python3
# -*- coding: utf-8 -*-
""" See if the HD Homerun box(s) are accessible and running
Requires Python 3.6 or later.
For backends started by systemd, use:
sudo --preserve-env systemctl edit --force mythtv-backend.service
and enter or add as needed by your service:
[Service]
ExecStartPre=-/usr/local/bin/hdhomerun_check.py
Can be called with optional IP address(s) for users that
have multiple HDHRs that have STATIC addresses.
Use --help to see all options.
If run from the command line, then output will be to the screen.
Otherwise, a log file in /tmp named hdhr_discovery.log is made.
Changable with the --logfile switch.
Exit codes:
0 = success (for *ALL* HDHRs if multiple IPs were specified)
1 = no output from the hdhomerun_config discover command
2 = IPv4 and IPv6 addresses found, disable IPv6 on NIC
3 = logfile isn't writable, delete it and try again
4 = keyboard interrupt
5 x the number of HDHRs = HDHR is most likely not up
"""
__version__ = '1.28'
import argparse
import signal
import subprocess
import sys
from datetime import datetime
from os.path import basename
from os import _exit
from time import sleep
# pylint: disable=too-many-arguments,unused-argument
def keyboard_interrupt_handler(sigint, frame):
''' Handle all KeyboardInterrupts here. And, just leave. '''
_exit(4)
# pylint: enable=unused-argument
def get_program_arguments():
''' Process the command line. '''
parser = argparse.ArgumentParser(description='HDHR Access Test',
epilog='* Default values are in ()s')
parser.add_argument('HOSTS', type=str, default=None, nargs='*',
help='optional hostname(s)/IP(s) (%(default)s)')
parser.add_argument('--attempts', default=20, type=int, metavar='<num>',
help='number of tries to find HDHRs (%(default)i)')
parser.add_argument('--debug', action='store_true',
help='output additional information (%(default)s)')
parser.add_argument('--logfile', default='/tmp/hdhomerun_check.log',
type=str, metavar='<lf>',
help='optional path + name of log file (%(default)s)')
parser.add_argument('--sleep', default=1.5, type=float, metavar='<sec>',
help='seconds betweem attempts (%(default)s)')
parser.add_argument('--version', action='version',
version='%(prog)s ' + __version__)
return parser.parse_args()
def get_elapsed_time(start):
''' Calculate the time spent waiting for the HDHR to come up. '''
delta = datetime.utcnow() - start
rounded_delta = f'{delta.seconds + (delta.microseconds / 1000000):.3f}'
return rounded_delta
def log_or_print(loglevel, message, output):
''' Add timestamp, log level then print to the selected location. '''
print(datetime.now().strftime("%F %T.%f")[:-3], f'{loglevel:8}', message,
file=output)
def last_message(loglevel, result, host, start, attempt, output):
''' Common success or failure message text. '''
log_or_print(loglevel, f'{result} {"at " + host + " " if host else ""}'
f'in {get_elapsed_time(start)} seconds '
f'and {attempt} attempt{"s"[attempt == 1:]}\n', output)
def check_one_device(host, args, output):
''' Try to discover the HDHR(s). '''
attempt = 0
command = ['hdhomerun_config', 'discover']
start = datetime.utcnow()
if host:
command.append(host)
for attempt in range(1, args.attempts+1):
try:
discovery_response = subprocess.check_output(
command, text=True, stderr=subprocess.STDOUT).split()
except subprocess.CalledProcessError:
log_or_print('WARNING', f'{command[0]}: got no response, attempt: '
f'{attempt:2}', output)
sleep(args.sleep)
continue
if not discovery_response:
log_or_print('ERROR', f'No output from {command[0]}, aborting!',
output)
sys.exit(1)
if args.debug:
log_or_print('DEBUG', f'Got: {" ".join(discovery_response)}',
output)
if discovery_response.count('hdhomerun') > 1:
log_or_print('ERROR', f'{command[0]}: more than 1 IP, aborting!',
output)
sys.exit(2)
if discovery_response[0] != 'hdhomerun':
# Consider making this an ERROR and exiting not sleeping...
log_or_print('WARNING', f'{command[0]} got an unexpected response:'
f' {" ".join(discovery_response)}',
output)
sleep(args.sleep)
else:
last_message('INFO', f'Found HDHR {discovery_response[2]}', host,
start, attempt, output)
return 0
last_message('ERROR', 'No HDHR found', host, start, attempt, output)
return 5
def main(args, output=None):
''' Control checking of one or more devices. '''
log_or_print('INFO', f'Starting {basename(__file__)} v{__version__}, '
f'attempts={args.attempts}, sleep={args.sleep:.2f}', output)
if args.HOSTS:
return_value = 0
for host in args.HOSTS:
return_value += check_one_device(host, args, output)
else:
return_value = check_one_device(None, args, output)
return return_value
if __name__ == '__main__':
signal.signal(signal.SIGINT, keyboard_interrupt_handler)
ARGS = get_program_arguments()
if sys.stdin and sys.stdin.isatty():
RETURN_VALUE = main(ARGS)
else:
try:
with open(ARGS.logfile, encoding='ascii', mode='a') as file_obj:
RETURN_VALUE = main(ARGS, output=file_obj)
except PermissionError:
print(f'Can\'t write to {ARGS.logfile}, aborting!')
sys.exit(3)
sys.exit(RETURN_VALUE)
# vim: set expandtab tabstop=4 shiftwidth=4 smartindent colorcolumn=80:
In KDE/Plasma you just right-click the Application launcher (Start button - left most button in panel) and Edit Application. You can follow the KDE instructions at this site if you don't know how to do this: https://docs.kde.org/trunk5/en/kmenuedi ... start.html
setup and Audio and Video as below:
In Setup -> Audio -> Audio Output Device select "ALSA:hdmi:CARD=vc4hdmi0,DEV=0"
Setup Digital Audio and speakers base on your audio system.
In Setup -> Video -> Playback change what you want but the critical ones are:
Advanced Playback Settings -> Audio Read Ahead (ms) to your needs. Start by using 400.
Change the Current Video Playback Profile to OpenGL Normal and drill down to change Max CPUs to 4 and Deinterlacer Quality (single rate) to Low quality. Do the same for Deinterlacer quality (double rate).
The mythfilldatabase.service is set to run early in the morning. You can adjust that like any normal systemd timer. Since you don't want to wait to get an EPG, the first time you can get an update with:
Code: Select all
sudo systemctl start mythfilldatabase.service