Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RasPiOS “Bullseye” support via cvlc #135

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
8cd5039
clearer instructions for alsa output
christiansievers Dec 2, 2020
5fd00b9
WIP for cvlc & Raspbian Bullseye
PaintYourDragon Dec 13, 2021
0ffb135
cvlcplayer.py changes
PaintYourDragon Dec 13, 2021
814709c
Split update/upgrade and package install for better indication
PaintYourDragon Dec 13, 2021
24784be
Add reboot to installer
PaintYourDragon Dec 13, 2021
2d75861
Fix missing quote
PaintYourDragon Dec 13, 2021
35aa301
install.sh: use bash instead of sh (for handling input)
PaintYourDragon Dec 13, 2021
6517c6c
install.sh with os split
tofuSCHNITZEL Dec 22, 2021
54b7327
os split the ini file
tofuSCHNITZEL Dec 22, 2021
f860ca6
upstream changes to players
tofuSCHNITZEL Dec 22, 2021
d3a058e
catching up
tofuSCHNITZEL Dec 22, 2021
74749eb
readme update
tofuSCHNITZEL Dec 22, 2021
7705603
WIP: basic playback functionality
tofuSCHNITZEL Dec 23, 2021
2a5ebab
Update install.sh
tofuSCHNITZEL Dec 29, 2021
3c003f9
added back some settings - UNTESTED!
tofuSCHNITZEL Dec 29, 2021
0d67e49
_sound_args missing fix
tofuSCHNITZEL Jan 10, 2022
bbda3bf
alsa audio fixed
tofuSCHNITZEL Jan 10, 2022
35d8ba5
Merge branch 'adafruit:master' into master
christiansievers Jan 12, 2022
b540e1e
documentation, clarifications
christiansievers Jan 12, 2022
c6a936b
documentation
christiansievers Jan 12, 2022
4eb91ed
Revert "Update README.md"
christiansievers Jan 13, 2022
93e2a63
Merge branch 'master' of https://github.com/christiansievers/pi_video…
christiansievers Jan 13, 2022
2d0a7ce
video title display for cvlc
tofuSCHNITZEL Jan 14, 2022
a20595a
clearer documentation
christiansievers Jan 14, 2022
0fd56c4
merge master
tofuSCHNITZEL Jan 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ docs/_build/
# PyBuilder
target/
.idea/
.DS_Store
126 changes: 126 additions & 0 deletions Adafruit_Video_Looper/cvlcplayer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Copyright 2015 Adafruit Industries.
# Author: Tony DiCola
# License: GNU GPLv2, see LICENSE.txt
import os
import shutil
import subprocess
import tempfile
import time

from .alsa_config import parse_hw_device

class CVLCPlayer:

def __init__(self, config):
"""Create an instance of a video player that runs cvlc in the
background.
"""
self._process = None
self._temp_directory = None
self._sound_args = None
self._load_config(config)

def __del__(self):
if self._temp_directory:
shutil.rmtree(self._temp_directory)

def _get_temp_directory(self):
if not self._temp_directory:
self._temp_directory = tempfile.mkdtemp()
os.chmod(self._temp_directory, 777)
return self._temp_directory

def _load_config(self, config):
self._extensions = config.get('cvlc', 'extensions') \
.translate(str.maketrans('', '', ' \t\r\n.')) \
.split(',')
self._extra_args = config.get('cvlc', 'extra_args').split()
self._sound = config.get('cvlc', 'sound').lower()
assert self._sound in ('hdmi', 'alsa'), 'Unknown cvlc sound configuration value: {0} Expected both or alsa.'.format(self._sound)
self._alsa_hw_device = parse_hw_device(config.get('alsa', 'hw_device'))
if self._alsa_hw_device != None and self._sound == 'alsa':
self._sound_args = ['--aout=alsa', '--alsa-audio-device=hw:{},{}'.format(self._alsa_hw_device[0], self._alsa_hw_device[1])]

self._show_titles = config.getboolean('cvlc', 'show_titles')
if self._show_titles:
title_duration = config.getint('cvlc', 'title_duration')
if title_duration >= 0:
m, s = divmod(title_duration, 60)
h, m = divmod(m, 60)
self._subtitle_header = '00:00:00,00 --> {:d}:{:02d}:{:02d},00\n'.format(h, m, s)
else:
self._subtitle_header = '00:00:00,00 --> 99:59:59,00\n'

def supported_extensions(self):
"""Return list of supported file extensions."""
return self._extensions

def play(self, movie, loop=None, vol=0):
"""Play the provided movie file, optionally looping it repeatedly."""
self.stop(3) # Up to 3 second delay to let the old player stop.
# Assemble list of arguments.
args = ['sudo', '-u','pi', 'cvlc', '-q']
if self._sound_args:
args.extend(self._sound_args) # Add sound arguments.
args.extend(self._extra_args) # Add extra arguments from config.
if vol is not 0:
args.extend(['--gain', str(vol)])
if loop is None:
loop = movie.repeats
if loop <= -1:
args.append('--loop') # Add loop parameter if necessary.
else:
args.append('--play-and-exit')

#video title display
if self._show_titles and movie.title:
srt_path = os.path.join(self._get_temp_directory(), 'video_looper.srt')
with open(srt_path, 'w') as f:
f.write(self._subtitle_header)
f.write(movie.title)
args.append('--sub-file={}'.format(srt_path))
else:
args.append('--no-osd')

args.append(movie.filename) # Add movie file path.
#DEBUG ONLY:
print(args)
# Run cvlc process and direct standard output to /dev/null.
self._process = subprocess.Popen(args,
stdout=open(os.devnull, 'wb'),
close_fds=True)

def is_playing(self):
"""Return true if the video player is running, false otherwise."""
if self._process is None:
return False
self._process.poll()
return self._process.returncode is None

def stop(self, block_timeout_sec=0):
"""Stop the video player. block_timeout_sec is how many seconds to
block waiting for the player to stop before moving on.
"""
# Stop the player if it's running.
if self._process is not None and self._process.returncode is None:
# There are a couple processes used by cvlc, so kill both
# with a pkill command.
subprocess.call(['pkill', '-9', 'vlc'])
# If a blocking timeout was specified, wait up to that amount of time
# for the process to stop.
start = time.time()
while self._process is not None and self._process.returncode is None:
if (time.time() - start) >= block_timeout_sec:
break
time.sleep(0)
# Let the process be garbage collected.
self._process = None

@staticmethod
def can_loop_count():
return False


def create_player(config, **kwargs):
"""Create new video player based on cvlc."""
return CVLCPlayer(config)
4 changes: 2 additions & 2 deletions Adafruit_Video_Looper/video_looper.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,8 @@ def _animate_countdown(self, playlist):
"""Print text with the number of loaded movies and a quick countdown
message if the on screen display is enabled.
"""
# Print message to console with number of movies in playlist.
message = 'Found {0} movie{1}.'.format(playlist.length(),
# Print message to console with number of media files in playlist.
message = 'Found {0} media file{1}.'.format(playlist.length(),
's' if playlist.length() >= 2 else '')
self._print(message)
# Do nothing else if the OSD is turned off.
Expand Down
56 changes: 34 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
# pi_video_looper
An application to turn your Raspberry Pi into a dedicated looping video playback device.
Can be used in art installations, fairs, theatre, events, infoscreens, advertisment etc...
Can be used in art installations, fairs, theatre, events, infoscreens, advertisements etc...

Easy to use out of the box but also has a lot of settings to make it fit your use case.
Works right out of the box, but also has a lot of customisation options to make it fit your use case. See the [video_looper.ini](https://github.com/adafruit/pi_video_looper/blob/master/assets/video_looper.ini) configuration file for an overview of options.

If you miss a feature just post an issue on github. (https://github.com/adafruit/pi_video_looper)
If you miss a feature just post an issue on Github. (https://github.com/adafruit/pi_video_looper)

Currently only Raspberry Pi OS Lite __(Legacy)__ is supported.
With the current Raspberry Pi OS Version 11 (bullseye) only cvlc and image_player are supported.
If you still want or need to use omxplayer or hello_video you need to install Raspberry Pi OS Lite __(Legacy)__.
You can download it from here: https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy

There are also pre-compiled versions available from: https://videolooper.de/ (but they might not contain the latest version of pi_video_looper)
There are also pre-compiled versions available from <https://videolooper.de> (but they might not always contain the latest version of pi_video_looper)

## Changelog
#### new in v1.1.0
- NEW PLAYER: cvlc
since Rasperry Pi OS 11 (bullseye) omxplayer and hello_video are no longer supported.
cvlc can be used with the legacy os as well. The install script automatically installs the appropriate dependencies for your system.

#### new in v1.0.10
- NEW PLAYER: "Image Player" (beta)
The new player can display images instead of videos (slideshow).
Display duration and other options can be controlled via "image_player" section in ini
Displays images in a slideshow instead of playing videos.
Display duration and other options can be controlled via the "image_player" section in video_looper.ini
All other settings, like background image, color, wait time, copy mode, keyboard shortcuts, etc. should work as expected
Currently tested formats: jpg, gif, png (others might work also - you need to adapt the extensions setting)

Expand All @@ -34,10 +40,10 @@ There are also pre-compiled versions available from: https://videolooper.de/ (bu

#### new in v1.0.6

- Support for OMXPlayer ALSA sound output.
Enabled by setting `omxplayer.sound` to `alsa`. A new config key `alsa.hw_device` can be used to specify a non-default output device.
- Support for omxplayer ALSA sound output.
Enabled by setting sound output for omxplayer to `alsa` in video_looper.ini. A new config key `alsa.hw_device` can be used to specify a non-default output device.
- Support for ALSA hardware volume control.
The new config keys `alsa.hw_vol_file` and `alsa.hw_vol_control` can be used to set the output device volume based on a text file provided with the videos.
The new config keys `alsa.hw_vol_file` and `alsa.hw_vol_control` can be used to set the output device volume in a text file provided with the videos.
- The `sound_vol_file` functionality can now be disabled by leaving the config value empty.

#### new in v1.0.5
Expand All @@ -47,13 +53,13 @@ There are also pre-compiled versions available from: https://videolooper.de/ (bu
Paths in the playlist can be absolute, or relative to the playlist's path.
Playlists can include a title for each item (`#EXTINF` directive); see next point.
If something goes wrong with the playlist (file not found etc.) it will fall back to just play all files in the `file_reader` directory. (enable `console_output` for more info)
- Support for video titles (OMXPlayer only).
- Support for video titles (omxplayer only).
Can display a text on top of the videos.
To be enabled by config key `omxplayer.show_titles`.
Without a playlist file, titles are simply the videos' filename (without extension).
If a M3U playlist is used, then titles come from the playlist instead.
If an M3U playlist is used, then titles come from the playlist instead.

An easy way to create M3U files is e.g. VLC. For an example m3u file see assets/example.m3u
An easy way to create M3U files is e.g. VLC. For an example M3U file see assets/example.m3u

#### new in v1.0.4
- new keyboard shortcut "k"
Expand All @@ -76,7 +82,7 @@ There are also pre-compiled versions available from: https://videolooper.de/ (bu

#### new in v1.0.2:
- in directory mode the directory is now monitored;
if the number of files changes the playlist is regenerated (usefull if the folder is filled e.g. via a network share)
if the number of files changes the playlist is regenerated (useful if the folder is filled e.g. via a network share)
- some defaults have changed
- new option for the countdown time (default is now 5 seconds)
- new option for a wait time between videos (default is 0 seconds)
Expand All @@ -87,17 +93,23 @@ There are also pre-compiled versions available from: https://videolooper.de/ (bu

#### new in v1.0.1:
- reworked for python3
- keyboard control (quiting the player)
- keyboard control (quitting the player)
- option for displaying an image instead of a blank screen between videos

#### how to install:
sudo ./install.sh
## How to install
`sudo apt-get install git`
`git clone https://github.com/adafruit/pi_video_looper`
`cd pi_video_looper`
`sudo ./install.sh`

Default player is omxplayer. Use the `no_hello_video` flag to install without the hello_video player (a lot faster to install):
`sudo ./install.sh no_hello_video`

#### features and settings
To change the settings of the video looper (e.g. random playback) edit the `/boot/video_looper.ini` file via ssh with `sudo nano /boot/video_looper.ini` or directly on the RPis SD Card via a cardreader.
## Features and settings
To change the settings of the video looper (e.g. random playback, copy mode, advanced features) edit the `/boot/video_looper.ini` file, i.e. by quitting the player with 'ESC' and logging in to the Raspberry with an attached keyboard, or remotely via ssh. Then edit the configuration file with `sudo nano /boot/video_looper.ini`. Alternatively insert the SD card into your computer and edit it with your preferred text editor.

#### copymode explained:
when a usb drive with video files is plugged in, they are copied onto the rpi. (with progress bar)
when a USB drive with video files is plugged in, they are copied onto the rpi. (with progress bar)

to protect the player from unauthorised drives a file must be present on the drive that has a filename
as defined in the password setting in the ini file (default: videopi)
Expand All @@ -113,8 +125,8 @@ Note: files with the same name always get overwritten
* with hello_video there is no gap when a video is repeated but there is a small gap between different videos
* with omxplayer there will also be a short gap between the repeats

* if you have only one video then omxplayer can also loop seamlessly (and wth audio)
* the last supported Rasperry Pi OS image version is 2021-05-07 (https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/2021-05-07-raspios-buster-armhf-lite.zip)
* if you have only one video then omxplayer will also loop seamlessly (and with audio)
* the last supported Rasperry Pi OS image version is [2021-05-07-raspios-buster-armhf-lite.zip](https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/2021-05-07-raspios-buster-armhf-lite.zip)

#### keyboard commands:
if enabled (via config file) the following keyboard commands are active:
Expand Down
Loading