diff --git a/.gitmodules b/.gitmodules index a7669a3..508ef42 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "packages/example-content"] path = packages/example-content url = https://github.com/KTE/dex-example-content +[submodule "packages/pi_video_looper"] + path = packages/pi_video_looper + url = https://github.com/adafruit/pi_video_looper diff --git a/README.md b/README.md index 8d41648..ba46fee 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,29 @@ packages: * [example content](./packages/example-content/README.md) * [branding](./packages/branding/README.md) +## getting started + +Build a dex player by flashing the image to an SD card, +using the official [Raspberry Pi Imager](https://www.raspberrypi.org/software/). + +Then boot the Raspberry Pi with the SD card. +It it worked, it will show a 2-second demo video loop. + +### advanced + +For customizing the player/operating system, +ssh access needs to be enabled. + +This can be done using the "customization" feature of the Raspberry Pi Imager, +choosing "Enable SSH" in the "Advanced Options". It is recommended to use key-based authentication. +The user name in the image is `dex` should not be changed, the default password is also `dex` and should be changed if SSH login is enabled and password authentication is used. + +Then, after booting the Raspberry Pi, ssh into it: + +```sh +ssh dex@dexpi # or another hostname if you changed it in the customization +``` + ## development ### creating patches @@ -24,10 +47,19 @@ Good tutorials on using `quilt`: quilt new "99-name-of-my-patch" quilt add ./packages/some-upstream-code/some-file # edit ./packages/some-upstream-code/some-file -quilt refresh # pathfile is added to ./patches and name added to ./patches/series +quilt refresh # patchfile is added to ./patches and patch name is added to ./patches/series quilt rename "99-better-name-of-my-patch" ``` +editing existing patches: + +```sh +PATCH_NAME="project/99-name-of-my-patch" +quilt add -P "$PATCH_NAME" ./packages/some-upstream-code/some-file +# edit ./packages/some-upstream-code/some-file +quilt refresh "$PATCH_NAME" # patchfile is updated in ./patches +``` + ## housekeeping ### update pi-gen repo diff --git a/packages/dex-os/README.md b/packages/dex-os/README.md index 58ac5f3..620762f 100644 --- a/packages/dex-os/README.md +++ b/packages/dex-os/README.md @@ -13,7 +13,7 @@ Install ## build -Builds a custom Raspbian image, based on `2024-03-12-raspios-bullseye-arm64-lite.img`. +Builds a custom Raspbian/Raspberry Pi OS image, based on Debian `buster`. 1. set up customized pi-gen @@ -26,6 +26,7 @@ Builds a custom Raspbian image, based on `2024-03-12-raspios-bullseye-arm64-lite ```sh time ./build.sh ``` + ## development for incremental build, first run: @@ -40,6 +41,55 @@ and then time PRESERVE_CONTAINER=1 CONTINUE=1 ./build.sh ``` +debug the container: + +```sh +./dev-debug-container.sh +# gives root shell in the build container +cd pi-gen/work/… +# for example, delete our stage for faster rebuild +rm -rf stage-dex +``` + +starting from scratch: + +```sh +./dev-reset.sh +``` + +## notes + +### data partition + +The image has a third partition, formatted as FAT, for storing media and configuration files. +Its mounted under `/dexdata` on the Raspberry Pi. +It can be managed by mounting the SD card on a computer (macOS, Windows, Linux) and copying files to it. + +Creating and handling this partition differs from the default Raspberry Pi OS behavior: +* Raspbian/Raspberry Pi OS uses a single partition `rootfs` partition for the operating system and user data. + * On first boot, the `rootfs` *partition* is expanded to fill the SD card. + * This is done by settings the `init` (in `/boot/cmdline.txt`) to `init=/usr/lib/raspi-config/init_resize.sh` + * After this script ran, it removes the `init` line from `/boot/cmdline.txt` so the system will boot regularly from then on. + * Script source: + * On the second boot, the `rootfs` *filesystem* is resized to fill the now expanded partition. + * This is done by the `resize2fs_once` script in `/etc/init.d` + * This script will also remove itself after its done, so it only runs once. + * There is not reboot necessary after this step (it runs early enough in the boot process). + * Note: those steps are necessary because modifying the `rootfs` partition, where the operating system is running from, is not possible while it is mounted. + +* dexOS handles it differently: + * The `rootfs` partition is not expanded on first boot (the special `init` is already removed `/boot/cmdline.txt`). + * The `resize2fs_once` script therefore runs on first boot, and is customized to handle the data partition only + * It resizes the `dexdata` *partition* to fill the whole SD card. + * It *recreates* the `dexdata` *filesystem* to fill the partition. + * This is necessary because the `resize2fs` command not resize FAT partitions, and `fatresize` did not work reliably. + * The data in this partition is kept by backing it up to the `rootfs`, which means it must be rather small initially so there is enough space (currently 10MB). + * NOTE: right now this is a compromise. After flashing the image, it could immediately be mounted on the same computer, so the media can be copied directly to the SD card. + However, 10MB is only enough for the very small example video. + * Only after booting the SD card with an Raspberry Pi, the data partition will be expanded to the full size of the SD card. + * That means the data partition could also be ignored in the build step and only be created on first boot, but it already works. + * On the other hand, a script could be used to resize the partition on the same computer that was used to flash the images, but then its not as easy to use a just using the official Raspberry Pi Imager. + ## alternatives * diff --git a/packages/dex-os/build.sh b/packages/dex-os/build.sh index f493f81..0b7d382 100755 --- a/packages/dex-os/build.sh +++ b/packages/dex-os/build.sh @@ -80,7 +80,7 @@ fi # add our config and stage to pi-gen cp ./pi-gen-config.env "${PI_GEN_DIR}/config" rm -rf "$PI_GEN_DIR/stage-dex" -cp -r ./pi-gen/stage-dex "$PI_GEN_DIR" +rsync --archive --cvs-exclude --copy-links ./pi-gen/stage-dex "$PI_GEN_DIR" echo "STAGE_LIST=\"$STAGE_LIST\"" >> "${PI_GEN_DIR}/config" echo "USE_QCOW2=\"$USE_QCOW2\"" >> "${PI_GEN_DIR}/config" @@ -88,10 +88,6 @@ echo "USE_QCOW2=\"$USE_QCOW2\"" >> "${PI_GEN_DIR}/config" cd "$PI_GEN_DIR" cat ./config -# get git hash from monorepo -GIT_HASH="$(git rev-parse HEAD)" -export GIT_HASH - ./build-docker.sh mv ./deploy/* "${DIST_DIR}/" @@ -100,5 +96,7 @@ if [ "${CONTINUE:-0}" != "1" ]; then clear fi -echo "🎉 output in ${DIST_DIR}:" +echo; echo; echo "🎉 output in ${DIST_DIR}:" ls -lah "${DIST_DIR}" + +echo "[build] OK" diff --git a/packages/dex-os/dev-debug-container.sh b/packages/dex-os/dev-debug-container.sh new file mode 100755 index 0000000..bf6780f --- /dev/null +++ b/packages/dex-os/dev-debug-container.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -euo pipefail +WD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$WD" + +docker start pigen_work || true +docker exec -it pigen_work /bin/bash diff --git a/packages/dex-os/dev-reset.sh b/packages/dex-os/dev-reset.sh new file mode 100755 index 0000000..f7acbf0 --- /dev/null +++ b/packages/dex-os/dev-reset.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -euo pipefail +WD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$WD" + +docker stop dex-os-apt-cacher-ng || true +docker rm dex-os-apt-cacher-ng || true + +docker stop pigen_work || true +docker rm pigen_work || true + +echo "[dev-reset] OK" diff --git a/packages/dex-os/dist.sh b/packages/dex-os/dist.sh new file mode 100755 index 0000000..aed2e38 --- /dev/null +++ b/packages/dex-os/dist.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -euo pipefail +WD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$WD" + +./dev-reset.sh +./prepare.sh +./build.sh + +echo "[dist] OK" diff --git a/packages/dex-os/pi-gen/stage-dex/00-data-partition/00-packages b/packages/dex-os/pi-gen/stage-dex/00-data-partition/00-packages new file mode 100644 index 0000000..07e5abd --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/00-data-partition/00-packages @@ -0,0 +1,3 @@ +parted +dosfstools +mtools diff --git a/packages/dex-os/pi-gen/stage-dex/00-data-partition/01-run.sh b/packages/dex-os/pi-gen/stage-dex/00-data-partition/01-run.sh new file mode 100755 index 0000000..6496a54 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/00-data-partition/01-run.sh @@ -0,0 +1,7 @@ +# TODO: convert those to proper patches? Makes the repo less readable, but catches unexpected changes from upstream + +# disable the default init_resize.sh script (we dont need to resize the root partition) +sed -i 's| init=/usr/lib/raspi-config/init_resize.sh||' "${ROOTFS_DIR}/boot/cmdline.txt" + +# install our resize2fs_once script, which resizes the data partition on first boot +install -m 755 files/resize2fs_once "${ROOTFS_DIR}/etc/init.d/" diff --git a/packages/dex-os/pi-gen/stage-dex/00-data-partition/files/resize2fs_once b/packages/dex-os/pi-gen/stage-dex/00-data-partition/files/resize2fs_once new file mode 100644 index 0000000..a4971d9 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/00-data-partition/files/resize2fs_once @@ -0,0 +1,51 @@ +#!/bin/sh +### BEGIN INIT INFO +# Provides: resize2fs_once +# Required-Start: +# Required-Stop: +# Default-Start: 3 +# Default-Stop: +# Short-Description: Resize /dexdata partition to fill the SD card +# Description: +### END INIT INFO +. /lib/lsb/init-functions +case "$1" in + start) + log_daemon_msg "Starting resize2fs_once" + set -exu + + DATA_MOUNT="/dexdata/" + + # find device and partition + mount "$DATA_MOUNT" || mount "$DATA_MOUNT" -o remount + DATA_PART="$(findmnt "$DATA_MOUNT" -n -o SOURCE -r)" + DATA_PART_DEV="$(echo "$DATA_PART" | sed 's/p.*//')" + + # backup files + TMP_DIR="$(mktemp -d)${DATA_MOUNT}/" + rsync -avPh "$DATA_MOUNT" "$TMP_DIR" + + # resize partition and recreate filesystem + umount "$DATA_MOUNT" + parted "$DATA_PART_DEV" --align optimal --script 'resizepart 3 100%' + mkfs.vfat -F 32 -n "DEXDATA" "$DATA_PART" + dosfsck -w -l -a -v -f -y "$DATA_PART" + + # restore files + mount "$DATA_MOUNT" + rsync -avPh "$TMP_DIR" "$DATA_MOUNT" + + # remove run-once script + update-rc.d resize2fs_once remove + rm /etc/init.d/resize2fs_once + + log_daemon_msg "resize2fs_once finished" + + log_end_msg $? + + ;; + *) + echo "Usage: $0 start" >&2 + exit 3 + ;; +esac diff --git a/packages/dex-os/pi-gen/stage-dex/00-videolooper/01-run.sh b/packages/dex-os/pi-gen/stage-dex/00-videolooper/01-run.sh deleted file mode 100755 index eec002b..0000000 --- a/packages/dex-os/pi-gen/stage-dex/00-videolooper/01-run.sh +++ /dev/null @@ -1,22 +0,0 @@ -on_chroot << EOF - -rm -rf "/home/${FIRST_USER_NAME}/pi_video_looper" -git clone "https://github.com/adafruit/pi_video_looper" "/home/${FIRST_USER_NAME}/pi_video_looper" -ls -la "/home/${FIRST_USER_NAME}/pi_video_looper" - - -set -x - -whoami - -ls -la "/home/${FIRST_USER_NAME}" - -cd "/home/${FIRST_USER_NAME}/pi_video_looper" - -# remove 'omxplayer' from the list of packages to install (we only want hello_video) -sed -i 's/omxplayer//g' ./install.sh - -./install.sh - -EOF - diff --git a/packages/dex-os/pi-gen/stage-dex/00-videolooper/00-packages b/packages/dex-os/pi-gen/stage-dex/01-videolooper/00-packages similarity index 100% rename from packages/dex-os/pi-gen/stage-dex/00-videolooper/00-packages rename to packages/dex-os/pi-gen/stage-dex/01-videolooper/00-packages diff --git a/packages/dex-os/pi-gen/stage-dex/01-videolooper/01-run.sh b/packages/dex-os/pi-gen/stage-dex/01-videolooper/01-run.sh new file mode 100755 index 0000000..79aa95d --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/01-videolooper/01-run.sh @@ -0,0 +1,20 @@ +# shellcheck shell=sh + +# install adafruit pi_video_looper using their install script, omitting omxplayer + +rm -rf "/home/${FIRST_USER_NAME}/pi_video_looper" +cp -r files/pi_video_looper "${ROOTFS_DIR}/home/${FIRST_USER_NAME}/" + +on_chroot << EOF + +cd "/home/${FIRST_USER_NAME}/pi_video_looper" + +# remove 'omxplayer' from the list of packages to install (we only want hello_video) +sed -i 's/omxplayer//g' ./install.sh + +./install.sh + +EOF + +# add our custom video_looper.ini configuration file +install -m 644 files/video_looper.ini "${ROOTFS_DIR}/boot/video_looper.ini" diff --git a/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/pi_video_looper b/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/pi_video_looper new file mode 120000 index 0000000..9efa6e0 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/pi_video_looper @@ -0,0 +1 @@ +../../../../../pi_video_looper \ No newline at end of file diff --git a/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/video_looper.ini b/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/video_looper.ini new file mode 100644 index 0000000..d558531 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/01-videolooper/files/video_looper.ini @@ -0,0 +1,316 @@ +# video_looper.ini +# Main configuration file for video_looper. + +# source (look here for more customization options): https://github.com/adafruit/pi_video_looper/blob/141ad15fc1d5d80bfe0bc29b4b3af513cc24a7a6/assets/video_looper.ini + +################################################################################ + +# DEX configuration overview: +# * background: +# * local storage /mnt/media is a separate partition on the SD card +# * USB drives are mounted read-only on /mnt/usbdrive (video_looper default) +# * rest of the SD card is read-only +# * use hello_video player for gapless video playback (only .h264 files are supported) +# * use copymode file reader to copy files from USB drive to local storage +# * image player is also enabled by default, so images files can be used as well +# * summary of changed options: +#[video_looper] +#video_player = hello_video +#file_reader = usb_drive_copymode +#[directory] +#path = /dexdata + +################################################################################ + +# The video_looper works right out of the box by playing any video files that +# are in the root directory of an attached USB drive. +# In this file you can change a lot of the video_looper's behavior, like what +# video player is used or where it looks for media files. +# Lines that begin with # are comments that will be ignored. +# Uncomment (=activate) a line by removing its preceding # character. +# Use ./reload.sh to restart the video_looper with any changed settings. + +# Video_looper configuration block follows. +[video_looper] + +# Set which video player will be used to play media files. Can be either omxplayer, +# hello_video or image_player. omxplayer can play common formats like avi, mov, mp4, etc. and +# with full audio and video, but it has a small ~100ms delay between videos. +# If there is only one video omxplayer can also loop seamlessly. +# hello_video is a simpler player that doesn't do audio and only plays raw H264 +# streams, but loops videos seamlessly if one video is played more than once. +# The image_player only displays images and for the duration configured in this file under the "image_player" section. +# The default is omxplayer. +#video_player = omxplayer +video_player = hello_video +#video_player = image_player + +# File Reader Location +# Where to find media files. Can be usb_drive, directory or usb_drive_copymode. +# When using usb_drive any USB stick inserted in to the Pi will be automatically +# mounted and searched for media files (only in the root directory). +# Alternatively the directory option will search only a specified directory on the SD +# card for media files. +# You can change the directory to be used in the [directory] section below. +# The default is usb_drive. +#file_reader = usb_drive +#file_reader = directory +file_reader = usb_drive_copymode + +# Note on usb_drive_copymode: +# If you enable this mode, media files are copied from the USB stick to the path +# specified in the [directory] section below. +# see additional settings for copy-mode in the [copymode] section + +# On Screen Display (OSD) +# Control whether informative messages about the current player state are +# displayed, like the number of media files loaded or if it's waiting to load them. +# Default is true to display these messages, but can be set to false to disable +# them entirely. +osd = true +#osd = false + +# for how many seconds should the OSD and countdown be shown after files are found +countdown_time = 5 + +# Below you can set a wait time (in seconds) that is waited between each video. +# wait time is not honored for the first video that plays after starting a new playlist (e.g. after plugging in usb drive) +# when using a self looping player like hello_video wait_time is not waited between each repeat of one video but between different videos +# with omxplayer wait_time will also happen between every repeat of a video +wait_time = 0 + +# This option enables the display of the current date/time while waiting between the videos +# Please note that the RPi is not good at keeping the time so you need to setup NTP time sync or install a RTC module +datetime_display= false +#datetime_display = true + +# This controls the format the date/time is displayed: (see https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) +# The below datetime_display can be on two lines if required. The top line is much bigger than the bottom line and suits the time better. The bottom line is more suited to the date. 'Thursday 13th February 2023' for example. +# If the bottom line not required just leave bottom_datetime_display_format empty. +# If the suffix is required after the day then %d{SUFFIX} should be put in the *_datetime_display_format. +# Some different examples of time and date are shown below with an example. (Only one pair of *_datetime_display_format should be without #) + +# 24Hour:Minutes:Seconds on the top line, Day of week, day of month followed by the suffix (st, nd, rd etc), Month, Year ion the bottom line. +top_datetime_display_format = %H:%M:%S +bottom_datetime_display_format = %A %d{SUFFIX} %B %Y + +# 24Hour:Minutes:Seconds on the top line, Year on the bottom line. +#top_datetime_display_format = %H:%M:%S +#bottom_datetime_display_format = %Y + +# 24Hour:Minutes:Seconds on the top line, no bottom line. +#top_datetime_display_format = %H:%M:%S +#bottom_datetime_display_format = + +# To play files in random order set this to true +is_random = false +#is_random = true + +# resume last playlist item after restart +resume_playlist = false +#resume_playlist = true + +# stop playback after each file +one_shot_playback = false +#one_shot_playback = true + +# Set the background to a custom image +# This image is displayed between movies or images +# an image will be scaled to the display resolution and centered. Use i.e. +# bgimage = /home/pi/loader.png +bgimage = + +# Change the color of the background that is displayed behind videos (only works +# with omxplayer and the image_player). Provide 3 numeric values from 0 to 255 separated by a commma +# for the red, green, and blue color value. Default is 0, 0, 0 which is black. +bgcolor = 0, 0, 0 + +# Change the color of the foreground text that is displayed with the on screen +# display messages. Provide 3 numeric values in the same format as bgcolor +# above. Default is 255, 255, 255 or white. +fgcolor = 255, 255, 255 + +# Output program state to standard output if true. +# Useful for debugging to see whats going on behind the scenes +console_output = false +#console_output = true + +[control] +# In this section all settings to interact with the looper are defined + +# Control the program via keyboard +# See the readme for the complete list of keyboard commands. +keyboard_control = true +#keyboard_control = false + +# This setting defines which Raspberry Pi GPIO pin (BOARD numbering!) will jump to which file in the playlist (first file has index 0) +# See: https://www.raspberrypi.com/documentation/computers/raspberry-pi.html for info about the pin numbers +# the pins are pulled high so you need to connect your switch to the selected pin and Ground (e.g. pin 9) - there is some debouncing done in software +# The accepted settings are like this: "pinnumber" : videoindex or "pinnumber" : "filename" or "pinnumber" : "-1" or "pinnumber" : "+1" +# its also possible to send "keyboard commands" like shutdown or pause (see readme for available keyboard commands) +# the format follows the pygame key list (https://www.pygame.org/docs/ref/key.html) see example below. "keyboard_control" needs to be enabled for this to work +# to enable GPIO set a gpio_pin_map like in the example below or just enable all the example mappings. +gpio_pin_map = +#gpio_pin_map = "11" : 1, "13": 4, "16": "+2", "18": "-1", "15": "video.mp4", "19": "K_SPACE", "21": "K_p" +# Example: +# Pin 11 starts the 2nd video in the playlist, +# pin 13 starts the 5th video, +# pin 16 jumps 2 videos ahead, +# pin 18 jumps one video back, +# pin 15 plays a file with name "video.mp4" (if it exists), +# pin 19 sends the "spacebar" to the looper, pausing the current video +# pin 21 sends the "p" key and thus triggers the shutdown of the Raspberry Pi + +# USB drive file reader configuration follows. +[usb_drive] + +# The path to mount new USB drives. A number will be appended to the path for +# each mounted drive (i.e. /mnt/usbdrive0, /mnt/usbdrive1, etc.). +mount_path = /mnt/usbdrive + +# Whether to mount the USB drives as readonly (true) or writable (false). It is +# recommended to mount USB drives readonly for reliability. +readonly = true + + +# Directory file reader configuration follows. +[directory] +# The path to search for movies when using the directory file reader. +# (see the file_reader section above to enable it) +path = /dexdata + + +# Copy-mode file reader configuration follows. +[copymode] +# this setting controls what happens when a USB drive is plugged in while in copymode +# (see the file_reader section above to enable it) +# the default setting "replace" deletes any files in the video directory and then copies the files from the USB drive +# You can decide if new files on the drive should replace existing files or get added. "Replace" means that any existing videofiles on the RPi get deleted, and only the new files remain. +# This setting can be overruled by placing a file named "replace" or "add" on the drive. +# The default mode is "replace". +# NOTE: files with the same name are always overwritten +mode = replace +#mode = add + +# with this setting you can control if a file named "loader.png" should be copied from the drive to be used eg as a background +# the file is copied to /home/pi/loader.png +copyloader = false +#copyloader = true + +# this setting defines a "password" that has to exist as a file (with the password as a filename) (extension does not matter) +# on the USB drive for the videolooper to accept videos from the USB drive +# default is videopi - you should consider changing it - +# if it is empty no check will be performed +# for maximum compatibility use only ascii characters +password = videopi + + +[playlist] +# This setting allows for a fixed playlist. See the example.m3u file in assets for the syntax. +# Path to the playlist file. +# If you enter a relative path (not starting with /) it is considered relative to the selected file_reader path (directory or USB drive). +# Leave empty to not use a playlist and play all the files in the file_reader path (directory or USB drive). +path = +#path = playlist.m3u + + + + + +# ALSA configuration follows. +# This only applies when using omxplayer with sound = alsa. +[alsa] + +# ALSA hardware device to use for sound output. This consists of the card +# number and subdevice number separated by a comma, e.g. '1,0'. Run +# 'aplay -l' to list available devices. If empty, the default output device is +# used. +hw_device = +#hw_device = 1,0 + +# Volume of the hardware device can be set using a text file provided with the +# video files. If the file does not exist, the hardware volume will remain +# unchanged. This setting specifies the name of the text file. +# The file should contain a single line with an amixer-compatible volume value, +# such as '50%' or '-10db'. +hw_vol_file = +#hw_vol_file = alsa_volume + +# Name of the ALSA control to use for adjusting volume. Typically this will be +# 'PCM'. Run 'amixer -c N scontrols' (where N is the card number of your output +# device) to list available controls. +hw_vol_control = PCM + + +# omxplayer configuration follows. +[omxplayer] + +# List of supported file extensions. Must be comma separated and should not +# include the dot at the start of the extension. +extensions = avi, mov, mkv, mp4, m4v + +# Sound output for omxplayer, either hdmi, local, both or alsa. When set to +# hdmi the video sound will be played on the HDMI output, and when set to local +# the sound will be played on the analog audio output. A value of both will +# play sound on both HDMI and the analog output. A value of alsa will play +# sound through ALSA, using the device specified in the [alsa] section above. +# The both value is the default. +sound = both +#sound = hdmi +#sound = local +#sound = alsa + +# Specify a sound volume output for the video player. +# The volume will be read from a file near the +# video files. If the file does not exist, a default volume of 0db will be used. +# To use this feature create a file in the same directory as the videos and name +# it the value defined below (like 'sound_volume' by default), then inside the +# file add a single line with the volume value in text to pass to omxplayer (using +# its --vol option which takes a value in millibels). +# NOTE: This may introduce audible quantization error. Using hw_vol_file will +# generally give better sound quality. +sound_vol_file = sound_volume + +# Fixed playlists may embed titles, which can be shown. See playlist section above. +# If no fixed playlist is given, titles are simply filenames without extensions. +show_titles = false +#show_titles = true + +# Title duration in seconds. -1 means endless. +title_duration = 10 + +# Any extra command line arguments to pass to omxplayer. It is not recommended +# that you change this unless you have a specific need to do so! The audio and +# video FIFO buffers are kept low to reduce clipping ends of movie at loop. +# Run 'omxplayer -h' to have the full list of parameters or see +# https://github.com/popcornmix/omxplayer#synopsis for all available options +# on Raspberry Pi 4 and 5 you can choose the HDMI output with --display 7 or --display 2 +# without specifing --display both hdmi ports have the same output +extra_args = --no-osd --audio_fifo 0.01 --video_fifo 0.01 --align center --font-size 55 + + +# hello_video player configuration follows. +[hello_video] + +# List of supported file extensions. Must be comma separated and should not +# include the dot at the start of the extension. +extensions = h264 + + +# image player configuration follows +[image_player] + +# List of supported file extensions. Must be comma separated and should not +# include the dot at the start of the extension. +extensions = jpg, jpeg, gif, png + +# Seconds an image is displayed +duration = 5 + +# Controls if images should be scaled to fit (shrink or enlarge) the display resolution. Default: true +scale = true +#scale = false + +# Controls if images should be displayed centered. Default: true +center = true +#center = false diff --git a/packages/dex-os/pi-gen/stage-dex/02-example-content/01-run.sh b/packages/dex-os/pi-gen/stage-dex/02-example-content/01-run.sh new file mode 100755 index 0000000..ff2f6b4 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/02-example-content/01-run.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +EXAMPLE_FILE="files/dex-test-card-2s-1080p.h264" + +mkdir -p "${ROOTFS_DIR}/dexdata/" +install "$EXAMPLE_FILE" "${ROOTFS_DIR}/dexdata/" diff --git a/packages/dex-os/pi-gen/stage-dex/02-example-content/files/dex-test-card-2s-1080p.h264 b/packages/dex-os/pi-gen/stage-dex/02-example-content/files/dex-test-card-2s-1080p.h264 new file mode 120000 index 0000000..7fb18e1 --- /dev/null +++ b/packages/dex-os/pi-gen/stage-dex/02-example-content/files/dex-test-card-2s-1080p.h264 @@ -0,0 +1 @@ +../../../../../example-content/export/dex-test-card-2s-1080p-h264.mp4.h264 \ No newline at end of file diff --git a/packages/dex-os/prepare.sh b/packages/dex-os/prepare.sh index 952fb44..0014c1e 100755 --- a/packages/dex-os/prepare.sh +++ b/packages/dex-os/prepare.sh @@ -3,7 +3,9 @@ set -euo pipefail cd "$(git rev-parse --show-toplevel)" -git submodule update --recursive --init --force packages/pi-gen +git submodule update --recursive --init --force --depth=1 packages/pi-gen packages/pi_video_looper packages/example-content + quilt pop -af || true quilt push -av +echo "[prepare] OK" diff --git a/packages/example-content b/packages/example-content index c6268e5..fd685bb 160000 --- a/packages/example-content +++ b/packages/example-content @@ -1 +1 @@ -Subproject commit c6268e5b5b95217f3eebb37ae7bbde458f74b92c +Subproject commit fd685bbee1b3fe83281a32ce7f68ca3b46a7ea41 diff --git a/packages/pi_video_looper b/packages/pi_video_looper new file mode 160000 index 0000000..141ad15 --- /dev/null +++ b/packages/pi_video_looper @@ -0,0 +1 @@ +Subproject commit 141ad15fc1d5d80bfe0bc29b4b3af513cc24a7a6 diff --git a/patches/pi-gen/00-add-data-partition b/patches/pi-gen/00-add-data-partition index 08e9d77..a3775e3 100644 --- a/patches/pi-gen/00-add-data-partition +++ b/patches/pi-gen/00-add-data-partition @@ -1,7 +1,13 @@ -Index: dex-os/packages/pi-gen/export-image/prerun.sh +Adds a third "data" partition to the image, mounted at /dexdata. + +* create partion in export-image/prerun.sh + +* add mount point to /etc/fstab + +Index: dex/packages/pi-gen/export-image/prerun.sh =================================================================== ---- dex-os.orig/packages/pi-gen/export-image/prerun.sh -+++ dex-os/packages/pi-gen/export-image/prerun.sh +--- dex.orig/packages/pi-gen/export-image/prerun.sh ++++ dex/packages/pi-gen/export-image/prerun.sh @@ -12,6 +12,7 @@ if [ "${NO_PRERUN_QCOW2}" = "0" ]; then BOOT_SIZE="$((256 * 1024 * 1024))" @@ -63,7 +69,7 @@ Index: dex-os/packages/pi-gen/export-image/prerun.sh ROOT_FEATURES="^huge_file" for FEATURE in metadata_csum 64bit; do -@@ -77,11 +98,15 @@ if [ "${NO_PRERUN_QCOW2}" = "0" ]; then +@@ -77,11 +98,17 @@ if [ "${NO_PRERUN_QCOW2}" = "0" ]; then done mkdosfs -n boot -F 32 -v "$BOOT_DEV" > /dev/null mkfs.ext4 -L rootfs -O "$ROOT_FEATURES" "$ROOT_DEV" > /dev/null @@ -77,5 +83,31 @@ Index: dex-os/packages/pi-gen/export-image/prerun.sh rsync -aHAXx --exclude /var/cache/apt/archives --exclude /boot "${EXPORT_ROOTFS_DIR}/" "${ROOTFS_DIR}/" rsync -rtx "${EXPORT_ROOTFS_DIR}/boot/" "${ROOTFS_DIR}/boot/" ++ rsync -rtx "${EXPORT_ROOTFS_DIR}/dexdata/" "${ROOTFS_DIR}/dexdata/" ++ # FIXME: remove this once the example-content task works + echo "Hello, World!" > "${ROOTFS_DIR}/dexdata/hello.txt" fi +Index: dex/packages/pi-gen/stage1/01-sys-tweaks/files/fstab +=================================================================== +--- dex.orig/packages/pi-gen/stage1/01-sys-tweaks/files/fstab ++++ dex/packages/pi-gen/stage1/01-sys-tweaks/files/fstab +@@ -1,3 +1,4 @@ + proc /proc proc defaults 0 0 + BOOTDEV /boot vfat defaults 0 2 + ROOTDEV / ext4 defaults,noatime 0 1 ++DATADEV /dexdata vfat defaults 0 3 +Index: dex/packages/pi-gen/export-image/03-set-partuuid/00-run.sh +=================================================================== +--- dex.orig/packages/pi-gen/export-image/03-set-partuuid/00-run.sh ++++ dex/packages/pi-gen/export-image/03-set-partuuid/00-run.sh +@@ -8,9 +8,11 @@ if [ "${NO_PRERUN_QCOW2}" = "0" ]; then + + BOOT_PARTUUID="${IMGID}-01" + ROOT_PARTUUID="${IMGID}-02" ++ DATA_PARTUUID="${IMGID}-03" + + sed -i "s/BOOTDEV/PARTUUID=${BOOT_PARTUUID}/" "${ROOTFS_DIR}/etc/fstab" + sed -i "s/ROOTDEV/PARTUUID=${ROOT_PARTUUID}/" "${ROOTFS_DIR}/etc/fstab" ++ sed -i "s/DATADEV/PARTUUID=${DATA_PARTUUID}/" "${ROOTFS_DIR}/etc/fstab" + + sed -i "s/ROOTDEV/PARTUUID=${ROOT_PARTUUID}/" "${ROOTFS_DIR}/boot/cmdline.txt" diff --git a/patches/series b/patches/series index 7436d1d..88d751d 100644 --- a/patches/series +++ b/patches/series @@ -1,4 +1,3 @@ pi-gen/00-add-data-partition pi-gen/01-use-docker-build-script-from-arm64-branch-for-buster pi-gen/02-dont-export-default-pi-gen-stages -pi-gen-docker-build-with-tmpfs