release candidate
This commit is contained in:
@ -8,7 +8,8 @@ There is a hardware requirement of USB RCA Capture device, and this device must
|
|||||||
|
|
||||||
There is an option to install a basic GUI and then display the feed in a browser kiosk
|
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 platform requires too much processing power to be installed on even half-decent systems. An 8-core Ryzen 5 Mini-PC is incapable of running the entire stack. I have separated the implementation of this to a client and server model. I set up a new VM on my home server that can use nearly all the CPU cores when needed, and set that with a static IP. I created two new roles that call this role with a few different variables, and then the cosmos-server pipeline can be ran with a special server selected to build the default cosmos VHS capture stack. This can probably run on an Intel i9 Mini PC or a similarly beefy Ryzen. It turns out that just the A/V to RSTP job takes a non-trivial amount of compute. Trying to do that and the video encoding at the same time generally takes more than a small CPU can offer. Now there is a VCR server VM that does the capturing of both the preview stream and the capture stream. This also saves it to the network in a spot that the website can automatically see. The client just streams to the server and displays the feed that is running from the server.
|
||||||
|
|
||||||
|
|
||||||
This process uses stages of different software to accomplish the goal of making capturing a VHS tape as automatic as possible
|
This process uses stages of different software to accomplish the goal of making capturing a VHS tape as automatic as possible
|
||||||
|
|
||||||
|
|||||||
27
defaults/kiosk.yaml
Normal file
27
defaults/kiosk.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# kiosk vars
|
||||||
|
kiosk_service_templates:
|
||||||
|
- chrome_website: "http://{{ stream_control_host }}:8081"
|
||||||
|
service_name: user_stream_control
|
||||||
|
service_description: "VCR Capture User Stream Control"
|
||||||
|
extra_service_configs: ""
|
||||||
|
user_data_dir: "/opt/chrome/one"
|
||||||
|
extra_chrome_configs: |
|
||||||
|
--window-size="560,1080" \
|
||||||
|
--user-data-dir=/opt/chrome/one \
|
||||||
|
--device-scale-factor="200" \
|
||||||
|
- chrome_website: "http://{{ stream_preview_host }}:8888/stream"
|
||||||
|
service_name: stream_preview
|
||||||
|
service_description: "VCR Capture Preview Stream"
|
||||||
|
extra_service_configs: ""
|
||||||
|
user_data_dir: "/opt/chrome/two"
|
||||||
|
extra_chrome_configs: |
|
||||||
|
--window-size="1350,1080" \
|
||||||
|
--user-data-dir=/opt/chrome/two \
|
||||||
|
--window-position="570,0" \
|
||||||
|
--device-scale-factor="200" \
|
||||||
|
|
||||||
|
|
||||||
|
...
|
||||||
@ -1,69 +1,9 @@
|
|||||||
---
|
---
|
||||||
|
# package list
|
||||||
working_storage: "/media/sd_card"
|
|
||||||
|
|
||||||
owncast_capture_folder: "{{ working_storage }}/owncast"
|
|
||||||
|
|
||||||
recording_capture_folder: "{{ working_storage }}/recordings"
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
lsusb_device_ID: "534d:0021"
|
|
||||||
|
|
||||||
capture_device_ID_string: "MS210"
|
|
||||||
|
|
||||||
service_control_name: "stream_service.service"
|
|
||||||
|
|
||||||
service_name: "VCR Streamer"
|
|
||||||
|
|
||||||
container_name: "service_control"
|
|
||||||
|
|
||||||
mediamtx_local_version: "deadbeef_test"
|
|
||||||
|
|
||||||
storage_unmounted: true
|
|
||||||
|
|
||||||
mount_storge: true
|
|
||||||
|
|
||||||
format_storage: false
|
|
||||||
|
|
||||||
sd_unmounted: true
|
|
||||||
|
|
||||||
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:
|
streamer_packages:
|
||||||
- gdisk
|
- gdisk
|
||||||
- ffmpeg
|
- ffmpeg
|
||||||
- alsa-utils
|
- alsa-utils
|
||||||
# - alsa-oss
|
|
||||||
- alsa-firmware-loaders
|
- alsa-firmware-loaders
|
||||||
- apulse
|
- apulse
|
||||||
- libasound2-plugins
|
- libasound2-plugins
|
||||||
@ -72,7 +12,25 @@ streamer_packages:
|
|||||||
- python3-venv
|
- python3-venv
|
||||||
- python3-setuptools
|
- python3-setuptools
|
||||||
|
|
||||||
# media_mtx variables
|
# jenkinsfile vars
|
||||||
|
refresh_special: false
|
||||||
|
GUI_deploy: false
|
||||||
|
extra_storage: false
|
||||||
|
kiosk_refresh: false
|
||||||
|
remote_deploy: false
|
||||||
|
server_deploy: false
|
||||||
|
luna_offload: false
|
||||||
|
|
||||||
|
# jellfin vars
|
||||||
|
jellyfin_working_folder: "/opt/cosmos/jellyfin"
|
||||||
|
jellyfin_port: "8096"
|
||||||
|
jellyfin_deploy: false
|
||||||
|
|
||||||
|
# mediamtx vars
|
||||||
|
mediamtx_working_folder: "/opt/cosmos/mediamtx"
|
||||||
|
mediamtx_architecture: "amd64"
|
||||||
|
mediamtx_local_version: "deadbeef_test"
|
||||||
|
# config.yaml variables
|
||||||
mediamtx_configs:
|
mediamtx_configs:
|
||||||
- search_string: 'record:'
|
- search_string: 'record:'
|
||||||
line: ' record: no'
|
line: ' record: no'
|
||||||
@ -84,5 +42,74 @@ mediamtx_configs:
|
|||||||
line: ' recordDeleteAfter: 0s'
|
line: ' recordDeleteAfter: 0s'
|
||||||
- search_string: 'recordMaxPartSize'
|
- search_string: 'recordMaxPartSize'
|
||||||
line: ' recordMaxPartSize: 500M'
|
line: ' recordMaxPartSize: 500M'
|
||||||
|
# luna offload vars
|
||||||
|
mediamtx_remote_ffmpeg: ""
|
||||||
|
mediamtx_local_ffmpeg: ""
|
||||||
|
|
||||||
|
# kiosk vars
|
||||||
|
stream_preview_host: "localhost"
|
||||||
|
stream_control_host: "localhost"
|
||||||
|
|
||||||
|
#kiosk_service_templates:
|
||||||
|
# - chrome_website: "http://localhost:8081"
|
||||||
|
# service_name: user_stream_control
|
||||||
|
# service_description: "VCR Capture User Stream Control"
|
||||||
|
# extra_service_configs: ""
|
||||||
|
# user_data_dir: "/opt/chrome/one"
|
||||||
|
# extra_chrome_configs: |
|
||||||
|
# --window-size="560,1080" \
|
||||||
|
# --user-data-dir=/opt/chrome/one \
|
||||||
|
# --device-scale-factor="200" \
|
||||||
|
# - chrome_website: "http://{{ stream_preview_host }}:8888/stream"
|
||||||
|
# service_name: stream_preview
|
||||||
|
# service_description: "VCR Capture Preview Stream"
|
||||||
|
# extra_service_configs: ""
|
||||||
|
# user_data_dir: "/opt/chrome/two"
|
||||||
|
# extra_chrome_configs: |
|
||||||
|
# --window-size="1350,1080" \
|
||||||
|
# --user-data-dir=/opt/chrome/two \
|
||||||
|
# --window-position="570,0" \
|
||||||
|
# --device-scale-factor="200" \
|
||||||
|
|
||||||
|
# rtsp site vars
|
||||||
|
rtsp_site_working_folder: "/opt/cosmos/rtsp_site"
|
||||||
|
|
||||||
|
# service control vars
|
||||||
|
service_control_folder: "/opt/cosmos/streamer/service_control"
|
||||||
|
service_control_name: "stream_service.service"
|
||||||
|
service_name: "VCR Streamer"
|
||||||
|
container_name: "service_control"
|
||||||
|
|
||||||
|
# streamer service vars
|
||||||
|
streaming_working_folder: "/opt/cosmos/streamer"
|
||||||
|
video_device: "/dev/video0"
|
||||||
|
v4l2_id_string:
|
||||||
|
- "AV TO USB2.0"
|
||||||
|
- "USB Video"
|
||||||
|
audio_device: "hw:0,0"
|
||||||
|
lsusb_device_ID: "534d:0021"
|
||||||
|
capture_device_ID_string: "MS210"
|
||||||
|
|
||||||
|
# preview service vars
|
||||||
|
stream_preview_folder: "/opt/cosmos/preview"
|
||||||
|
|
||||||
|
# working folder vars
|
||||||
|
working_storage: "/media/sd_card"
|
||||||
|
recording_capture_folder: "{{ working_storage }}/recordings"
|
||||||
|
storage_unmounted: true
|
||||||
|
mount_storge: true
|
||||||
|
format_storage: false
|
||||||
|
sd_unmounted: true
|
||||||
|
|
||||||
|
# other vars
|
||||||
|
arm_arch: false
|
||||||
|
kiosk_models:
|
||||||
|
- "Surface Pro 2"
|
||||||
|
- "11G5S0C900"
|
||||||
|
arm_gui_list:
|
||||||
|
- "RK3588"
|
||||||
|
local_username: "cosmos"
|
||||||
|
armcpu_check: false
|
||||||
|
MediaMTX_only: false
|
||||||
|
arm_device_found: false
|
||||||
...
|
...
|
||||||
BIN
files/jellyfin-old.tar.gz
Normal file
BIN
files/jellyfin-old.tar.gz
Normal file
Binary file not shown.
Binary file not shown.
7
scratch
Normal file
7
scratch
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
ffmpeg \
|
||||||
|
-f alsa -i {{ audio_device }} -thread_queue_size 64 \
|
||||||
|
-f v4l2 -framerate 24 -video_size 640x480 -input_format yuyv422 -i {{ video_device }} \
|
||||||
|
-c:v libx264 -preset fast -crf 23 -c:a aac -b:a 192k -tune zerolatency \
|
||||||
|
-f mp4 {{ recording_capture_folder }}/$DATE.mp4
|
||||||
|
|
||||||
22
tasks/arm_gui_check.yaml
Normal file
22
tasks/arm_gui_check.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
# need to put this little guy in a file to do a loop
|
||||||
|
|
||||||
|
- name: Video Capture - run product command
|
||||||
|
shell: "lspci | grep '{{ arm_gui_list_item }}' | head -n 1 | awk {'print $8'}"
|
||||||
|
register: prod_name_output
|
||||||
|
|
||||||
|
- name: Video Capture - check for output
|
||||||
|
ignore_errors: yes
|
||||||
|
debug:
|
||||||
|
msg: "System Info: {{prod_name_output.stdout_lines[0] }}"
|
||||||
|
|
||||||
|
- name: Video Capture - Check for GUI-approved platform
|
||||||
|
ignore_errors: yes
|
||||||
|
set_fact:
|
||||||
|
GUI_deploy: "{{ prod_name_output.stdout_lines[0] in kiosk_models }}"
|
||||||
|
arm_device_found: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
...
|
||||||
@ -4,6 +4,12 @@
|
|||||||
# Install Jellyfin
|
# Install Jellyfin
|
||||||
###############################################
|
###############################################
|
||||||
|
|
||||||
|
- name: jellyfin - stop and delete container if running
|
||||||
|
ignore_errors: true
|
||||||
|
shell: |
|
||||||
|
docker stop jellyfin
|
||||||
|
docker rm jellyfin
|
||||||
|
|
||||||
- name: jellyfin - create folder
|
- name: jellyfin - create folder
|
||||||
file:
|
file:
|
||||||
path: "{{ jellyfin_working_folder }}"
|
path: "{{ jellyfin_working_folder }}"
|
||||||
@ -12,6 +18,7 @@
|
|||||||
|
|
||||||
# Extract jellyfin configs
|
# Extract jellyfin configs
|
||||||
- name: jellyfin - Extract jellyfin.tar.gz
|
- name: jellyfin - Extract jellyfin.tar.gz
|
||||||
|
when: not refresh_special | bool
|
||||||
unarchive:
|
unarchive:
|
||||||
src: jellyfin.tar.gz
|
src: jellyfin.tar.gz
|
||||||
dest: "/opt/cosmos"
|
dest: "/opt/cosmos"
|
||||||
@ -28,10 +35,11 @@
|
|||||||
- name: "jellyfin - Start container at {{ jellyfin_port }}"
|
- name: "jellyfin - Start container at {{ jellyfin_port }}"
|
||||||
shell: "docker-compose -f {{ jellyfin_working_folder }}/docker-compose.yaml up -d"
|
shell: "docker-compose -f {{ jellyfin_working_folder }}/docker-compose.yaml up -d"
|
||||||
register: jellyfin_output
|
register: jellyfin_output
|
||||||
- debug:
|
|
||||||
msg:
|
#- debug:
|
||||||
- "Docker compose output:"
|
# msg:
|
||||||
- "{{ jellyfin_output.stdout_lines }}"
|
# - "Docker compose output:"
|
||||||
- "{{ jellyfin_output.stderr_lines }}"
|
# - "{{ jellyfin_output.stdout_lines }}"
|
||||||
|
# - "{{ jellyfin_output.stderr_lines }}"
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -1,43 +0,0 @@
|
|||||||
---
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
...
|
|
||||||
102
tasks/main.yaml
102
tasks/main.yaml
@ -1,4 +1,49 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
|
- name: Video Capture - Luna Offload Vars
|
||||||
|
when: luna_offload | bool
|
||||||
|
set_fact:
|
||||||
|
mediamtx_remote_ffmpeg: "-f rtsp rtsp://172.20.20.60:8554/stream"
|
||||||
|
stream_preview_host: "172.20.20.60"
|
||||||
|
|
||||||
|
- name: Video Capture - server only Vars
|
||||||
|
when: server_deploy | bool
|
||||||
|
set_fact:
|
||||||
|
stream_preview_host: "172.20.20.60"
|
||||||
|
stream_control_host: "172.20.20.60"
|
||||||
|
|
||||||
|
- name: Video Capture - Local stream vars
|
||||||
|
when: remote_deploy | bool
|
||||||
|
set_fact:
|
||||||
|
mediamtx_local_ffmpeg: "-f rtsp rtsp://172.20.20.60:8554/stream"
|
||||||
|
|
||||||
|
- name: Video Capture - Remote stream vars
|
||||||
|
when: not remote_deploy | bool
|
||||||
|
set_fact:
|
||||||
|
mediamtx_local_ffmpeg: "-f rtsp rtsp://localhost:8554/stream"
|
||||||
|
|
||||||
|
- name: Video Capture - MediaMTX Only
|
||||||
|
when: MediaMTX_only | bool
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: include mediamtx task
|
||||||
|
include_tasks: mediamtx.yaml
|
||||||
|
- meta: end_play
|
||||||
|
|
||||||
|
- name: Video Capture - Kiosk Only
|
||||||
|
when: kiosk_refresh | bool
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: display initial kiosk_service_templates
|
||||||
|
debug:
|
||||||
|
msg: "{{ kiosk_service_templates }}"
|
||||||
|
|
||||||
|
- name: Run the chrome kiosk role when it's GUI time
|
||||||
|
include_role:
|
||||||
|
name: chrome_kiosk
|
||||||
|
when: GUI_deploy | bool
|
||||||
|
- meta: end_play
|
||||||
|
|
||||||
|
|
||||||
- name: Video Capture - Check arch if needed
|
- name: Video Capture - Check arch if needed
|
||||||
when: refresh_special | bool
|
when: refresh_special | bool
|
||||||
@ -12,6 +57,41 @@
|
|||||||
set_fact:
|
set_fact:
|
||||||
cpu_architecture: "{{ cpu_architecture_output.stdout_lines[0] }}"
|
cpu_architecture: "{{ cpu_architecture_output.stdout_lines[0] }}"
|
||||||
|
|
||||||
|
# override GUI_deploy if unauthorized
|
||||||
|
# if non-1080p resolutions are needed
|
||||||
|
# chrome configs can be set here on a
|
||||||
|
# case-by-case basis
|
||||||
|
- name: Video Capture - get Product Name for x86
|
||||||
|
when: GUI_deploy | bool and not armcpu_check | bool
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Video Capture - run product command
|
||||||
|
shell: "dmidecode | grep -A3 'System Info' | grep Product | cut -d: -f2 | cut -b2-"
|
||||||
|
register: prod_name_output
|
||||||
|
|
||||||
|
- name: Video Capture - show output
|
||||||
|
debug:
|
||||||
|
msg: "System Info: {{prod_name_output.stdout_lines[0] }}"
|
||||||
|
|
||||||
|
- name: Video Capture - Check for GUI-approved platform
|
||||||
|
ignore_errors: yes
|
||||||
|
set_fact:
|
||||||
|
GUI_deploy: "{{ prod_name_output.stdout_lines[0] in kiosk_models }}"
|
||||||
|
|
||||||
|
- name: Video Capture - get Product Name for arm
|
||||||
|
when: GUI_deploy | bool and armcpu_check | bool and not arm_device_found | bool
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Video capture - arm check loop
|
||||||
|
loop: "{{ arm_gui_list }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: arm_gui_list_item
|
||||||
|
include_tasks: arm_gui_check.yaml
|
||||||
|
|
||||||
|
- name: Video Capture - Will we GUI?
|
||||||
|
debug:
|
||||||
|
msg: "GUI Deploy: {{ GUI_deploy }}"
|
||||||
|
|
||||||
- name: Video Capture - Run Once Block
|
- name: Video Capture - Run Once Block
|
||||||
when: not refresh_special | bool
|
when: not refresh_special | bool
|
||||||
block:
|
block:
|
||||||
@ -26,20 +106,28 @@
|
|||||||
loop_var: streamer_packages_items
|
loop_var: streamer_packages_items
|
||||||
|
|
||||||
- name: Video Capture - Working Folder Handler
|
- name: Video Capture - Working Folder Handler
|
||||||
|
when: not remote_deploy | bool
|
||||||
include_tasks: working_folder.yaml
|
include_tasks: working_folder.yaml
|
||||||
|
|
||||||
- name: Video Capture - Configure MediaMTX
|
- name: Video Capture - Configure MediaMTX
|
||||||
|
when: not remote_deploy | bool
|
||||||
include_tasks: mediamtx.yaml
|
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
|
|
||||||
|
|
||||||
- name: Video Capture - Configure service control
|
- name: Video Capture - Configure service control
|
||||||
|
when: not remote_deploy | bool
|
||||||
include_tasks: service_control.yaml
|
include_tasks: service_control.yaml
|
||||||
|
|
||||||
|
- name: Video Capture - Configure Streaming
|
||||||
|
when: not server_deploy | bool
|
||||||
|
include_tasks: streamer.yaml
|
||||||
|
|
||||||
|
- name: Video Capture - Configure Jellyfin
|
||||||
|
when: '"amd64" in cpu_architecture and jellyfin_deploy | bool and not remote_deploy | bool'
|
||||||
|
include_tasks: jellyfin.yaml
|
||||||
|
|
||||||
|
- name: Run the chrome kiosk role when it's GUI time
|
||||||
|
include_role:
|
||||||
|
name: chrome_kiosk
|
||||||
|
when: GUI_deploy | bool and not server_deploy | bool
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -18,7 +18,7 @@
|
|||||||
group: root
|
group: root
|
||||||
|
|
||||||
- name: MediaMTX - check for arm
|
- name: MediaMTX - check for arm
|
||||||
when: '"arm" in cpu_architecture'
|
when: armcpu_check | bool
|
||||||
set_fact:
|
set_fact:
|
||||||
mediamtx_architecture: "arm64"
|
mediamtx_architecture: "arm64"
|
||||||
|
|
||||||
|
|||||||
31
tasks/preview.yaml
Normal file
31
tasks/preview.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
# this is not just for preview but for capture too
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - create folder
|
||||||
|
file:
|
||||||
|
path: "{{ stream_preview_folder }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - copy service script
|
||||||
|
template:
|
||||||
|
src: preview_service.sh
|
||||||
|
dest: "{{ stream_preview_folder }}/preview_service.sh"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - create service file
|
||||||
|
template:
|
||||||
|
src: preview_service.service
|
||||||
|
dest: /etc/systemd/system/preview_service.service
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - daemon reload
|
||||||
|
systemd:
|
||||||
|
name: preview_service.service
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
|
||||||
|
...
|
||||||
@ -151,4 +151,28 @@
|
|||||||
msg="{{ docker_output.stdout_lines }}"
|
msg="{{ docker_output.stdout_lines }}"
|
||||||
msg="{{ docker_output.stderr_lines }}"
|
msg="{{ docker_output.stderr_lines }}"
|
||||||
|
|
||||||
|
# create streaming service
|
||||||
|
# this used to live with the streamer but i moved it here because most of the time this will be split up
|
||||||
|
# the names don't make as much sense anymore either...
|
||||||
|
# oh well...
|
||||||
|
|
||||||
|
- name: video_capture - fil - ffmpeg service
|
||||||
|
#when: false
|
||||||
|
block:
|
||||||
|
- name: video_capture - streamer - copy service script
|
||||||
|
template:
|
||||||
|
src: stream_service.sh
|
||||||
|
dest: "{{ streaming_working_folder }}/stream_service.sh"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: video_capture - streamer - create service file
|
||||||
|
template:
|
||||||
|
src: stream_service.service
|
||||||
|
dest: /etc/systemd/system/stream_service.service
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: video_capture - streamer - daemon reload
|
||||||
|
systemd:
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
@ -10,6 +10,21 @@
|
|||||||
mode: '0755'
|
mode: '0755'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
|
register: folder_output
|
||||||
|
- debug:
|
||||||
|
msg: "{{ folder_output }}"
|
||||||
|
|
||||||
|
# Create capture Folder
|
||||||
|
- name: "video_capture - streamer - create {{ recording_capture_folder }} folder"
|
||||||
|
file:
|
||||||
|
path: "{{ recording_capture_folder }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0755'
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
register: folder_output_2
|
||||||
|
- debug:
|
||||||
|
msg: "{{ folder_output_2 }}"
|
||||||
|
|
||||||
# this service shouldn't stay running
|
# this service shouldn't stay running
|
||||||
- name: video_capture - streamer - stop stream_service if running
|
- name: video_capture - streamer - stop stream_service if running
|
||||||
@ -35,37 +50,59 @@
|
|||||||
|
|
||||||
# same with video, the lsusb ID is 534d:0021
|
# same with video, the lsusb ID is 534d:0021
|
||||||
# v4l2-ctl shows it as "AV TO USB2.0"
|
# v4l2-ctl shows it as "AV TO USB2.0"
|
||||||
|
# this checks a list and saves the only correct output
|
||||||
|
|
||||||
|
- name: video_capture - check for each video device
|
||||||
|
shell: "v4l2-ctl --list-devices 2> /dev/null | grep -A3 '{{ v4l2_strings }}' | grep video | head -n 1 | awk '{print $1}' || true"
|
||||||
|
register: v4l2_id_string_check
|
||||||
|
loop: "{{ v4l2_id_string }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: v4l2_strings
|
||||||
|
|
||||||
- name: video_capture - get video device
|
- name: video_capture - get video device
|
||||||
shell: "v4l2-ctl --list-devices 2> /dev/null | grep -A3 '{{ v4l2_id_string }}' | grep video | head -n 1 | awk '{print $1}'"
|
when: video_check_output.stdout | length > 0
|
||||||
register: video_ID_0
|
set_fact:
|
||||||
|
video_device: "{{ video_check_output.stdout_lines[0] }}"
|
||||||
- name: video_capture - set video_device
|
no_log: true
|
||||||
set_fact:
|
loop: "{{ v4l2_id_string_check.results }}"
|
||||||
video_device: "{{ video_ID_0.stdout_lines[0] }}"
|
loop_control:
|
||||||
|
loop_var: video_check_output
|
||||||
|
|
||||||
- name: video_capture - show results
|
- name: video_capture - show results
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
- "Audio Device: {{ audio_device }}"
|
- "Audio Device: {{ audio_device }}"
|
||||||
- "Video Device: {{ video_device }}"
|
- "Video Device: {{ video_device }}"
|
||||||
|
|
||||||
- name: video_capture - streamer - copy service script
|
# adding the preview service here
|
||||||
template:
|
- name: video_capture - streamer - preview - ffmpeg service
|
||||||
src: stream_service.sh
|
#when: false
|
||||||
dest: "{{ streaming_working_folder }}/stream_service.sh"
|
block:
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
- name: video_capture - streamer - create service file
|
- name: video_capture - streamer - preview - create folder
|
||||||
template:
|
file:
|
||||||
src: stream_service.service
|
path: "{{ stream_preview_folder }}"
|
||||||
dest: /etc/systemd/system/stream_service.service
|
state: directory
|
||||||
mode: 0644
|
mode: '0755'
|
||||||
|
|
||||||
- name: video_capture - streamer - daemon reload
|
- name: video_capture - streamer - preview - copy service script
|
||||||
systemd:
|
template:
|
||||||
daemon_reload: yes
|
src: preview_service.sh
|
||||||
|
dest: "{{ stream_preview_folder }}/preview_service.sh"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - create service file
|
||||||
|
template:
|
||||||
|
src: preview_service.service
|
||||||
|
dest: /etc/systemd/system/preview_service.service
|
||||||
|
mode: 0644
|
||||||
|
|
||||||
|
- name: video_capture - streamer - preview - daemon reload
|
||||||
|
systemd:
|
||||||
|
name: preview_service.service
|
||||||
|
state: started
|
||||||
|
enabled: yes
|
||||||
|
daemon_reload: yes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
...
|
...
|
||||||
@ -6,7 +6,7 @@
|
|||||||
file:
|
file:
|
||||||
path: "{{ working_storage }}"
|
path: "{{ working_storage }}"
|
||||||
state: directory
|
state: directory
|
||||||
mode: '0755'
|
mode: '0777'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
|
|
||||||
@ -20,14 +20,14 @@
|
|||||||
storage_unmounted: false
|
storage_unmounted: false
|
||||||
|
|
||||||
- name: Storage Handler Block
|
- name: Storage Handler Block
|
||||||
when: storage_unmounted and mount_storge | bool
|
when: storage_unmounted and mount_storge and extra_storage | bool
|
||||||
block:
|
block:
|
||||||
|
|
||||||
# find the device, architecture dependent
|
# find the device, architecture dependent
|
||||||
# the arm64 is intended for the friendlyelec devices
|
# the arm64 is intended for the friendlyelec devices
|
||||||
# which only have one sd slot, but still be careful
|
# which only have one sd slot, but still be careful
|
||||||
- name: Storage Handler - Get Storage Device arm64
|
- name: Storage Handler - Get Storage Device arm64
|
||||||
when: '"arm64" in cpu_architecture'
|
when: armcpu_check | bool
|
||||||
block:
|
block:
|
||||||
|
|
||||||
- name: Storage Handler - get boot device
|
- name: Storage Handler - get boot device
|
||||||
@ -39,7 +39,7 @@
|
|||||||
# this will choose the first storage device that it finds that isn't the boot device
|
# 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
|
# be careful and don't run this on an inappropriate host
|
||||||
- name: Storage Handler - Get Storage Device amd64
|
- name: Storage Handler - Get Storage Device amd64
|
||||||
when: '"amd64" in cpu_architecture'
|
when: not armcpu_check | bool
|
||||||
block:
|
block:
|
||||||
|
|
||||||
- name: Storage Handler - get boot UUID
|
- name: Storage Handler - get boot UUID
|
||||||
@ -188,7 +188,7 @@
|
|||||||
path: "/etc/samba/smb.conf"
|
path: "/etc/samba/smb.conf"
|
||||||
search_string: "/etc/samba/smb.conf.d/vcr_rip.conf"
|
search_string: "/etc/samba/smb.conf.d/vcr_rip.conf"
|
||||||
line: "include = /etc/samba/smb.conf.d/vcr_rip.conf"
|
line: "include = /etc/samba/smb.conf.d/vcr_rip.conf"
|
||||||
insertbefore: '[global]'
|
insertafter: '### smb.conf.d configs here'
|
||||||
|
|
||||||
- name: Working Folder - restart smbd
|
- name: Working Folder - restart smbd
|
||||||
service:
|
service:
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# docker-compose.yaml
|
# docker-compose.yaml
|
||||||
version: '3'
|
|
||||||
services:
|
services:
|
||||||
local-index:
|
local-index:
|
||||||
image: apache-index
|
image: apache-index
|
||||||
|
|||||||
14
templates/docker-compose-preview.yaml
Normal file
14
templates/docker-compose-preview.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- "8888:80"
|
||||||
|
volumes:
|
||||||
|
- {{ stream_preview_folder }}/nginx.conf:/etc/nginx/nginx.conf
|
||||||
|
- {{ stream_preview_folder }}/html:/usr/share/nginx/html
|
||||||
|
network_mode: bridge
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
...
|
||||||
15
templates/preview_service.service
Normal file
15
templates/preview_service.service
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=VCR Stream Preview
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
KillSignal=SIGINT
|
||||||
|
WorkingDirectory={{ stream_preview_folder }}
|
||||||
|
ExecStart={{ stream_preview_folder }}/preview_service.sh
|
||||||
|
User=root
|
||||||
|
Group=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
9
templates/preview_service.sh
Normal file
9
templates/preview_service.sh
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ffmpeg \
|
||||||
|
-f alsa -i {{ audio_device }} -thread_queue_size 64 \
|
||||||
|
-f v4l2 -framerate 24 -video_size 640x480 -input_format yuyv422 -i {{ video_device }} \
|
||||||
|
-c:v libx264 -preset fast -crf 23 -c:a aac -b:a 192k -tune zerolatency \
|
||||||
|
{{ mediamtx_local_ffmpeg }} \
|
||||||
|
{{ mediamtx_remote_ffmpeg }} \
|
||||||
|
|
||||||
@ -3,9 +3,7 @@
|
|||||||
DATE=$(date +'%Y%m%d-%H%M%S')
|
DATE=$(date +'%Y%m%d-%H%M%S')
|
||||||
|
|
||||||
ffmpeg \
|
ffmpeg \
|
||||||
-f alsa -i {{ audio_device }} -thread_queue_size 64 \
|
-i rtsp://localhost:8554/stream \
|
||||||
-f v4l2 -framerate 30 -video_size 640x480 -input_format yuyv422 -i {{ video_device }} \
|
|
||||||
-c:v libx264 -preset fast -crf 23 -c:a aac -b:a 192k -tune zerolatency \
|
-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 \
|
||||||
-f mp4 {{ recording_capture_folder }}/$DATE.mp4
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user