update readme

This commit is contained in:
2025-09-20 14:28:45 -07:00
parent a08d8c9153
commit 3432e8ac9f
15 changed files with 457 additions and 257 deletions

View File

@ -1,21 +1,47 @@
This is an ansible role intended to be ran as a supplement to my server-base playbook upon request
This is an ansible role intended to be ran as the final step in the corresponding playbook to do what it says on the tin
Some considerations of this are the expectations of docker and samba already being installed and configured
If this is not ran as a part of the cosmos playbook, then some considerations here are the expectations of docker and samba already being installed and configured
This ansible task automatically builds out a matt-cloud debian system to be a VCR Ripping device
This ansible task automatically builds out a matt-cloud debian puck to be a VCR Ripping device
There is a hardware requirement of USB RCA Capture device, and this device must be configured in defauts/main.yaml
There is a hardware requirement of USB RCA Capture device, and this device must have its settings configured in defauts/main.yaml
There is an option to install a basic GUI and then display the feed in a browser kiosk
This platform requires too much processing power to be installed on weak systems. The RK3528A 4-core SBC loads up to 6 when this runs on it. Perhaps a future version of this will have a detector so that when it's installed on a wimpy ARM SBC it will do nothing except save the file; no MediaMTX or Jellyfin. Not important right now.
This process uses stages of different software to accomplish the goal of making capturing a VHS tape as automatic as possible
Most of the layers include:
- ffmpeg service to combine the video and audio of the USB capture device into a rtmp stream
- mediamtx to automatically save rtmp streams to a mp4 file
- a docker apache php container for the control site
- a python API service to control the ffmpeg streaming service
- a small helper script to monitor the elapsed time and stop streaming after the selected time
- a playbook to mount and format a sd card when using ARM based puck systems
The various pertinent services live at these ports:
- Control Panel at port 8081
- Local Read-Only File Index at 8080
- Preview livestream at 8888
- Jellyfin at 8096
Overview of layers:
- ffmpeg service to combine the video and audio of the USB capture device into a RTMP stream and mp4 file
- The RTMP stream is so the capture can be live-previewed
- This feed is pointed at the MediaMTX service
- Mediamtx to monitor current capture
- This service will only be used for its ability to view a RTMP stream live in a web browser
- Docker container with apache+php for the control site
- This runs the PHP site that controls the ffmpeg capture service
- Python API service to control the ffmpeg streaming service
- This Python API is used by the PHP site for controlling the service
- It also has the duration variable storage control API here
- This is stored locally in a JSON file
- Small helper script to monitor the elapsed time and stop streaming after the selected time
- This script kills the capture service after the duration has been reached
- It does this by reading the JSON file managed by the Python API
- Playbook to mount and format additional storage when present
- When a secondary storage is detected it will be mapped at the media storage path
- If there is a blank storage attached, it will be formatted so BE CAREFUL
- If there is no secondary storage, the videos will be stored on the root path
- Playbook to install the GUI when certain hardware is detected
- Right now it will just be a 2nd Gen MS Surface I have
- It will be identified by the "System Info" dmidecode data
- There is a variable in the defaults file for a list of these strings
Some additional notes on the storage handling task working_folder.yaml. This will mount additional local storage if present. It expects there to be a single additional storage device and will work with an SD Card or an NVMe. It will map if a valid GPT ext4 volume is present, and it will create a new ext4 volume if there are no volumes present on this storage. It should just fail in edge cases which is fine. It would be a bad idea to run this playbook on an inappropriate endpoint.

View File

@ -10,10 +10,16 @@ streaming_working_folder: "/opt/cosmos/streamer"
mediamtx_working_folder: "/opt/cosmos/mediamtx"
jellyfin_working_folder: "/opt/cosmos/jellyfin"
jellyfin_port: "8096"
service_control_folder: "/opt/cosmos/streamer/service_control"
video_device: "/dev/video0"
v4l2_id_string: "AV TO USB2.0"
audio_device: "hw:0,0"
mediamtx_architecture: "amd64"
@ -30,9 +36,11 @@ container_name: "service_control"
mediamtx_local_version: "deadbeef_test"
mount_sd: true
storage_unmounted: true
format_sd: false
mount_storge: true
format_storage: false
sd_unmounted: true
@ -40,22 +48,34 @@ arm_arch: false
refresh_special: true
kiosk_models:
- "Surface Pro 2"
install_kodi: false
local_username: "cosmos"
chrome_website: "http://localhost:8888/stream"
fixed_size: "--start-fullscreen"
streamer_packages:
- gdisk
- ffmpeg
- alsa-utils
- alsa-oss
# - alsa-oss
- alsa-firmware-loaders
- apulse
- libasound2-plugins
- v4l-utils
- usbutils
- python3-venv
- python3-setuptools
# media_mtx variables
mediamtx_configs:
- search_string: 'record:'
line: ' record: yes'
line: ' record: no'
- search_string: 'recordPath'
line: ' recordPath: {{ recording_capture_folder }}/%path/%Y-%m-%d_%H-%M/%H-%M-%S-%f'
- search_string: 'recordSegmentDuration'

BIN
files/jellyfin.tar.gz Normal file

Binary file not shown.

37
tasks/jellyfin.yaml Normal file
View File

@ -0,0 +1,37 @@
---
###############################################
# Install Jellyfin
###############################################
- name: jellyfin - create folder
file:
path: "{{ jellyfin_working_folder }}"
state: directory
mode: '0755'
# Extract jellyfin configs
- name: jellyfin - Extract jellyfin.tar.gz
unarchive:
src: jellyfin.tar.gz
dest: "/opt/cosmos"
owner: "1000"
group: "1000"
mode: 0755
- name: jellyfin - Copy config
template:
src: docker-compose-jellyfin.yaml
dest: "{{ jellyfin_working_folder }}/docker-compose.yaml"
mode: 0644
- name: "jellyfin - Start container at {{ jellyfin_port }}"
shell: "docker-compose -f {{ jellyfin_working_folder }}/docker-compose.yaml up -d"
register: jellyfin_output
- debug:
msg:
- "Docker compose output:"
- "{{ jellyfin_output.stdout_lines }}"
- "{{ jellyfin_output.stderr_lines }}"
...

43
tasks/kiosk.yaml Normal file
View File

@ -0,0 +1,43 @@
---
- name: Kiosk - get Product Name
shell: "dmidecode | grep -A3 'System Info' | grep Product | cut -d: -f2 | cut -b2-"
register: prod_name_output
- name: Kiosk - Check for approved platform
set_fact:
install_sddm: "{{ prod_name_output.stdout_lines[0] in kiosk_models }}"
- name: Kiosk - Proceed with local kiosk install
when: install_sddm | bool
block:
# install SDDM + Plasma using Kodi role
- name: Kiosk - Install SDDM + KDE
include_role:
- kodi
# Install Chrome
- name: Install chrome
block:
- name: prereqs - Chrome - Check if installed
command: dpkg -l google-chrome-stable
register: chrome_installed
ignore_errors: true
- name: prereqs - Chrome - Set chrome_present variable
set_fact:
chrome_present: "{{ chrome_installed.rc == 0 }}"
- name: prereqs - Install Chrome
include_tasks: /var/jenkins_home/ansible/roles/install_apps/tasks/chrome.yaml
when: not chrome_present | bool
# set up chrome kiosk using lldp_scan role
- name: Kiosk - Install Chrome Kiosk Service
include_role:
- lldp_scan
...

View File

@ -12,23 +12,28 @@
set_fact:
cpu_architecture: "{{ cpu_architecture_output.stdout_lines[0] }}"
- name: Video Capture - Install Packages
- name: Video Capture - Run Once Block
when: not refresh_special | bool
apt:
name:
- "{{ streamer_packages_items }}"
state: present
loop: "{{ streamer_packages }}"
loop_control:
loop_var: streamer_packages_items
block:
- name: Video Capture - SD Card Handler
when: mount_sd | bool
include_tasks: sd_handler.yaml
- name: Video Capture - Install Packages
apt:
name:
- "{{ streamer_packages_items }}"
state: present
loop: "{{ streamer_packages }}"
loop_control:
loop_var: streamer_packages_items
- name: Video Capture - Configure MediaMTX
when: not refresh_special | bool
include_tasks: mediamtx.yaml
- name: Video Capture - Working Folder Handler
include_tasks: working_folder.yaml
- name: Video Capture - Configure MediaMTX
include_tasks: mediamtx.yaml
- name: Video Capture - Configure Jellyfin
when: '"amd64" in cpu_architecture'
include_tasks: jellyfin.yaml
- name: Video Capture - Configure Streaming
include_tasks: streamer.yaml

View File

@ -1,6 +1,6 @@
---
# mediamtx automatically makes video files from rtmp streams
# mediamtx is for monitoring the capture
- name: MediaMTX - stop mediamtx_service if running
systemd:
@ -40,6 +40,7 @@
mode: '0755'
remote_src: yes
# this loops over a bunch of vars and modifies the config file
- name: MediaMTX - update configs
lineinfile:
path: "{{ mediamtx_working_folder }}/mediamtx.yml"

View File

@ -1,215 +0,0 @@
---
# when ran, this will look for an SD card
# optionally format it, be careful with that, it WILL destroy things
# map it to working_storage
# can only run on arm64
# '"arm64" in cpu_architecture'
- name: Video Capture - Check for SD
shell: "df"
register: df_check_output
- name: Video Capture - Set sd_unmounted
when: working_storage in df_check_output.stdout
set_fact:
sd_unmounted: false
- name: Video Capture - Set arm_arch
when: '"arm64" in cpu_architecture'
set_fact:
arm_arch: true
format_sd: false
- name: SD Handler - Checks have passed
when: sd_unmounted and arm_arch | bool
block:
- name: SD Handler - Get SD Device
block:
- name: SD Handler - get boot device
shell: "blkid | grep '\"boot\"' | cut -d: -f 1 | cut -d/ -f 3 | cut -dp -f 1"
register: boot_device
- name: SD Handler - get sd card device
shell: "lsblk -o NAME,SIZE --nodeps | grep -v -e loop -e {{ boot_device.stdout_lines[0] }} -e NAME | cut -d ' ' -f 1"
register: sd_card_device
- name: SD Handler - format SD card
when: format_sd | bool
block:
- name: SD Handler - clear existing partition table
shell: 'sgdisk --zap-all "/dev/{{ sd_card_device.stdout_lines[0] }}"'
- name: SD Handler - create new partition table
shell: 'sgdisk --new=0:0:0 "/dev/{{ sd_card_device.stdout_lines[0] }}"'
- name: SD Handler - create new volume table
shell: 'sgdisk --typecode=1:8300 --change-name=1:"Linux filesystem" "/dev/{{ sd_card_device.stdout_lines[0] }}"'
- name: SD Handler - find new volume
shell: 'blkid | grep {{ sd_card_device.stdout_lines[0] }} | cut -d: -f1'
register: new_sd_volume
- name: SD Handler - format new volume
shell: 'mkfs.ext4 {{ new_sd_volume.stdout_lines[0] }}'
register: format_output
- name: SD Handler - show format stdout
debug:
msg: "{{ format_output.stdout_lines }}"
- name: SD Handler - find SD card volume
block:
- name: SD Handler - get sd card uuid
shell: "blkid | grep {{ sd_card_device.stdout_lines[0] }} | awk '{for (i=1; i<=NF; i++) print $i}' | grep UUID | grep -v PART | cut -d '\"' -f 2"
register: sd_card_uuid_output
- name: SD Handler - set uuid variable
set_fact:
sd_card_uuid: "{{ sd_card_uuid_output.stdout_lines[0] }}"
- debug:
msg: "UUID Found: {{ sd_card_uuid }}"
- name: SD Handler - mount sd card
block:
- name: SD Handler - check folder
file:
path: "{{ working_storage }}"
state: directory
mode: '0755'
owner: root
group: root
- name: SD Handler - Generate fstab entry
set_fact:
fstab_line_sd: "UUID={{ sd_card_uuid }} {{ working_storage }} ext4 errors=remount-ro 0 1"
- name: SD Handler - add fstab entry
lineinfile:
path: "/etc/fstab"
search_string: "{{ sd_card_uuid }}"
line: "{{ fstab_line_sd }}"
- debug:
msg: |
fstab entry:
{{ fstab_line_sd }}
- name: SD Handler - daemon reload
systemd:
daemon_reload: yes
- name: SD Handler - Mount it
shell: mount -a
- name: SD Handler - validate this
block:
- name: SD Handler - check for new mount point
shell: "df -h | grep -e Size -e {{ working_storage }}"
register: sd_test_output
- debug:
msg: "{{ sd_test_output.stdout_lines }}"
- name: SD Handler - samba and index
block:
- name: SD Handler - Share with samba
block:
- name: SD Handler - Create config file
copy:
dest: "/etc/samba/smb.conf.d/vcr_rip.conf"
content: |
[vcr_rip]
path = {{ working_storage }}
writable = yes
read only = no
only guest = yes
public = yes
guest ok = yes
guest only = yes
guest account = nobody
browsable = yes
mode: 0644
- name: SD Handler - Include in smb.conf
lineinfile:
path: "/etc/samba/smb.conf"
search_string: "/etc/samba/smb.conf.d/vcr_rip.conf"
line: "include = /etc/samba/smb.conf.d/vcr_rip.conf"
insertbefore: '[global]'
- name: SD Handler - restart smbd
service:
name: smbd
state: restarted
enabled: yes
- name: SD Handler - Apache Index
block:
###############################################
# Clone and build apache-index
###############################################
- name: SD Handler - - apache-index - Ensure the destination directory exists
file:
path: /opt/cosmos/apache-index # Replace with your desired directory on the target machine
state: directory
mode: '0755'
- name: SD Handler - - apache-index - Clone the Git repository
git:
repo: 'https://gitea.matt-cloud.com/matt/apache-index.git' # Replace with your repository URL
dest: '/opt/cosmos/apache-index' # Replace with your desired directory on the target machine
version: 'main' # Replace with the branch, tag, or commit you want to clone
force: yes
- name: SD Handler - - apache-index - Build image
docker_image:
name: apache-index # Name of the SD Handler - image
source: build
build:
path: /opt/cosmos/apache-index # Path to the directory containing your Dockerfile
state: present
tag: latest
register: build_index_output
- name: SD Handler - - apache-index - Image changed
debug: msg="{{ build_index_output.changed }}"
- name: SD Handler - - apache-index - Image failed
debug: msg="{{ build_index_output.failed }}"
- name: SD Handler - - apache-index - Image layers
debug: msg="{{ build_index_output.image.RootFS.Layers }}"
###############################################
# Install local-index 00
###############################################
- name: SD Handler - - local-index - create folder
file:
path: "{{ streaming_working_folder }}/local-index"
state: directory
mode: '0755'
- name: SD Handler - - local-index - Copy config
template:
src: docker-compose-local-index.yaml
dest: "{{ streaming_working_folder }}/local-index/docker-compose.yaml"
mode: 0644
- name: SD Handler - - local-index - Start container at 172.17.0.1:8080
shell: "docker-compose -f {{ streaming_working_folder }}/local-index/docker-compose.yaml up -d"
register: local_index_output
- debug: |
msg="{{ local_index_output.stdout_lines }}"
msg="{{ local_index_output.stderr_lines }}"
...

View File

@ -38,9 +38,9 @@
copy:
dest: "{{ service_control_folder }}/requirements.txt"
content: |
requests
Flask==2.1.0
pytz
requests
lxml
Werkzeug==2.0
mode: 0644
@ -61,6 +61,7 @@
dest: /etc/systemd/system/service_control.service
mode: 0644
# this is the service that stops the capture service
- name: video_capture - service timeout helper files
block:
@ -96,7 +97,7 @@
###############################################
# This part sets up serice control website
# This part sets up service control website
###############################################
- name: service control web interface

View File

@ -34,9 +34,10 @@
audio_device: "hw:{{ sound_ID_0.stdout_lines[0] }},{{ sound_ID_1.stdout_lines[0] }}"
# same with video, the lsusb ID is 534d:0021
# v4l2-ctl shows it as "AV TO USB2.0"
- name: video_capture - get video device
shell: "v4l2-ctl --list-devices -z {{ lsusb_device_ID }} | grep video | head -n 1 | awk '{print $1}'"
shell: "v4l2-ctl --list-devices 2> /dev/null | grep -A3 '{{ v4l2_id_string }}' | grep video | head -n 1 | awk '{print $1}'"
register: video_ID_0
- name: video_capture - set video_device

254
tasks/working_folder.yaml Normal file
View File

@ -0,0 +1,254 @@
---
# this is for prepping the working folder, including mounting the storage if present and requested
# this folder needs to exist regardless of if there's storage to mount
- name: Working Folder - check folder
file:
path: "{{ working_storage }}"
state: directory
mode: '0755'
owner: root
group: root
- name: Working Folder - Check for Storage
shell: "df"
register: df_check_output
- name: Working Folder - Set storage_unmounted
when: working_storage in df_check_output.stdout
set_fact:
storage_unmounted: false
- name: Storage Handler Block
when: storage_unmounted and mount_storge | bool
block:
# find the device, architecture dependent
# the arm64 is intended for the friendlyelec devices
# which only have one sd slot, but still be careful
- name: Storage Handler - Get Storage Device arm64
when: '"arm64" in cpu_architecture'
block:
- name: Storage Handler - get boot device
shell: "blkid | grep '\"boot\"' | cut -d: -f 1 | cut -d/ -f 3 | cut -dp -f 1"
register: boot_device_arm64
- debug:
msg: "Boot device: {{ boot_device_arm64.stdout_lines[0] }}"
# this will choose the first storage device that it finds that isn't the boot device
# be careful and don't run this on an inappropriate host
- name: Storage Handler - Get Storage Device amd64
when: '"amd64" in cpu_architecture'
block:
- name: Storage Handler - get boot UUID
shell: 'cat /etc/fstab | grep " / " | grep UUID | cut -d= -f2 | cut -d " " -f 1'
register: boot_uuid
- debug:
msg: "Boot device UUID: {{ boot_uuid.stdout_lines[0] }}"
- name: Storage Handler - get boot device
shell: "blkid | grep {{ boot_uuid.stdout_lines[0] }} | cut -d: -f 1 | cut -d/ -f 3 | cut -dp -f 1 | cut -b 1-3"
register: boot_device_amd64
- debug:
msg: "Boot device: {{ boot_device_amd64.stdout_lines[0] }}"
- name: set boot_device variable
set_fact:
boot_device: "{{ boot_device_arm64.stdout_lines[0] | default(boot_device_amd64.stdout_lines[0]) }}"
- name: Storage Handler - get storage device
shell: "lsblk -o NAME,SIZE --nodeps | grep -v -e loop -e {{ boot_device }} -e NAME | cut -d ' ' -f 1"
register: storage_device_output
- name: Storage Handler - set uuid variable
set_fact:
storage_device: "{{ storage_device_output.stdout_lines[0] }}"
- debug:
msg: "Storage Device Found: {{ storage_device }}"
- name: Storage Handler - check for volumes
block:
- name: Storage Handler - Check for volumes on storage device
shell: 'lsblk | grep {{ storage_device }} | grep -v disk || true'
register: volume_check
- name: Storage Handler - Set format_storage variable
when: not storage_device in volume_check.stdout
set_fact:
format_storage: true
- name: Storage Handler - Test if format
when: format_storage
debug:
msg: "Looks like it's clobberin' time: {{ storage_device }} will be wiped and prepped"
- name: Storage Handler - Test if no format
when: not format_storage | bool
debug:
msg:
- "Looks like there's at least one volume there, the storage is safe:"
- "{{ volume_check.stdout_lines }}"
# this little block will format the storage found above
# it will be skipped unless you do something about it
- name: Storage Handler - format storage
# when: false
when: format_storage | bool
block:
- name: Storage Handler - clear existing partition table
shell: 'sgdisk --zap-all "/dev/{{ storage_device }}"'
- name: Storage Handler - create new partition table
shell: 'sgdisk --new=0:0:0 "/dev/{{ storage_device }}"'
- name: Storage Handler - create new volume table
shell: 'sgdisk --typecode=1:8300 --change-name=1:"Linux filesystem" "/dev/{{ storage_device }}"'
- name: Storage Handler - find new volume
shell: 'blkid | grep {{ storage_device }} | cut -d: -f1'
register: new_sd_volume
- name: Storage Handler - format new volume
shell: 'mkfs.ext4 {{ new_sd_volume.stdout_lines[0] }}'
register: format_output
- name: Storage Handler - show format stdout
debug:
msg: "{{ format_output.stdout_lines }}"
- name: Storage Handler - find storage volume
block:
- name: Storage Handler - get storage uuid
shell: "blkid | grep {{ storage_device }} | awk '{for (i=1; i<=NF; i++) print $i}' | grep UUID | grep -v PART | cut -d '\"' -f 2"
register: storage_uuid_output
- name: Storage Handler - set uuid variable
set_fact:
storage_uuid: "{{ storage_uuid_output.stdout_lines[0] }}"
- name: Storage Handler - Generate fstab entry
set_fact:
fstab_line_storage: "UUID={{ storage_uuid }} {{ working_storage }} ext4 errors=remount-ro 0 1"
- debug:
msg:
- "UUID Found:"
- "{{ storage_uuid }}"
- "fstab entry:"
- "{{ fstab_line_storage }}"
- name: Storage Handler - mount storage
block:
- name: Storage Handler - add fstab entry
lineinfile:
path: "/etc/fstab"
search_string: "{{ storage_uuid }}"
line: "{{ fstab_line_storage }}"
- name: Storage Handler - daemon reload
systemd:
daemon_reload: yes
- name: Storage Handler - Mount it
shell: mount -a
- name: Storage Handler - check for new mount point
shell: "df -h | grep -e Size -e {{ working_storage }}"
register: storage_output
- debug:
msg:
- "Storage handler drive mount result:"
- "{{ storage_output.stdout_lines }}"
###############################################
# this shares out the working folder with samba
# and builds an apache index site
###############################################
- name: Working Folder - samba and index
block:
- name: Working Folder - Share with samba
block:
- name: Working Folder - Create smb config file
template:
src: vcr_rip.conf
dest: "/etc/samba/smb.conf.d/vcr_rip.conf"
mode: 0644
- name: Working Folder - Include config in smb.conf
lineinfile:
path: "/etc/samba/smb.conf"
search_string: "/etc/samba/smb.conf.d/vcr_rip.conf"
line: "include = /etc/samba/smb.conf.d/vcr_rip.conf"
insertbefore: '[global]'
- name: Working Folder - restart smbd
service:
name: smbd
state: restarted
enabled: yes
- name: Working Folder - Apache Index
block:
# Clone and build apache-index
- name: Working Folder - apache-index - Ensure the destination directory exists
file:
path: /opt/cosmos/apache-index # Replace with your desired directory on the target machine
state: directory
mode: '0755'
- name: Working Folder - apache-index - Clone the Git repository
git:
repo: 'https://gitea.matt-cloud.com/matt/apache-index.git' # Replace with your repository URL
dest: '/opt/cosmos/apache-index' # Replace with your desired directory on the target machine
version: 'main' # Replace with the branch, tag, or commit you want to clone
force: yes
- name: Working Folder - apache-index - Build image
docker_image:
name: apache-index # Name of the Storage Handler - image
source: build
build:
path: /opt/cosmos/apache-index # Path to the directory containing your Dockerfile
state: present
tag: latest
register: build_index_output
- name: Storage Handler - apache-index results
debug:
msg:
- "{{ build_index_output.changed }}"
- "{{ build_index_output.failed }}"
- "{{ build_index_output.image.RootFS.Layers }}"
# start local-index
- name: Working Folder - local-index - create folder
file:
path: "{{ streaming_working_folder }}/local-index"
state: directory
mode: '0755'
- name: Working Folder - local-index - Copy config
template:
src: docker-compose-local-index.yaml
dest: "{{ streaming_working_folder }}/local-index/docker-compose.yaml"
mode: 0644
- name: Working Folder - local-index - Start container at 172.17.0.1:8080
shell: "docker-compose -f {{ streaming_working_folder }}/local-index/docker-compose.yaml up -d"
register: local_index_output
- debug:
msg:
- "local-index docker compose output"
- "{{ local_index_output.stdout_lines }}"
- "{{ local_index_output.stderr_lines }}"
...

View File

@ -0,0 +1,17 @@
---
services:
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
volumes:
- ./config:/config
- {{ recording_capture_folder }}:/data/recordings:ro
ports:
- {{ jellyfin_port }}:8096
restart: always
network_mode: bridge
...

View File

@ -4,11 +4,12 @@ After=network.target
[Service]
Type=simple
KillSignal=SIGINT
WorkingDirectory={{ streaming_working_folder }}
ExecStart={{ streaming_working_folder }}/stream_service.sh
Restart=always
User=root
Group=root
[Install]
WantedBy=multi-user.target

View File

@ -1,12 +1,11 @@
#!/bin/bash
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
-f alsa -ac 2 -i {{ audio_device }} -thread_queue_size 64 \
DATE=$(date +'%Y%m%d-%H%M%S')
ffmpeg \
-f alsa -i {{ audio_device }} -thread_queue_size 64 \
-f v4l2 -framerate 30 -video_size 640x480 -input_format yuyv422 -i {{ video_device }} \
-c:v libx264 -preset ultrafast -tune zerolatency \
-vf "format=yuv420p" -g 60 -c:a aac -b:a 128k -ar 44100 \
-f flv rtmp://0.0.0.0:1935/stream
-c:v libx264 -preset fast -crf 23 -c:a aac -b:a 192k -tune zerolatency \
-f rtsp rtsp://localhost:8554/stream \
-f mp4 {{ recording_capture_folder }}/$DATE.mp4

10
templates/vcr_rip.conf Normal file
View File

@ -0,0 +1,10 @@
[vcr_rip]
path = {{ working_storage }}
writable = yes
read only = no
only guest = yes
public = yes
guest ok = yes
guest only = yes
guest account = nobody
browsable = yes