Skip to content

Instantly share code, notes, and snippets.

@dasl-
Created November 9, 2021 05:23
Show Gist options
  • Save dasl-/db3ce584ba90802ba390ac0f07611dea to your computer and use it in GitHub Desktop.
Save dasl-/db3ce584ba90802ba390ac0f07611dea to your computer and use it in GitHub Desktop.
diff --git a/docs/configuring_omxplayer.adoc b/docs/configuring_omxplayer.adoc
index 5dda1aa..942002d 100644
--- a/docs/configuring_omxplayer.adoc
+++ b/docs/configuring_omxplayer.adoc
@@ -12,7 +12,7 @@ Here is some https://github.com/popcornmix/omxplayer/issues/256[more info about
## omxplayer configuration
-### timeout
+### timeout
From the man page:
....
--timeout n Timeout for stalled file/network operations (default 10s)
diff --git a/piwall2/broadcaster/videobroadcaster.py b/piwall2/broadcaster/videobroadcaster.py
index 5ad7495..509d433 100644
--- a/piwall2/broadcaster/videobroadcaster.py
+++ b/piwall2/broadcaster/videobroadcaster.py
@@ -82,6 +82,8 @@ class VideoBroadcaster:
def __broadcast_internal(self):
self.__logger.info(f"Starting broadcast for: {self.__video_url}")
+ self.__start_receivers()
+
"""
What's going on here? We invoke youtube-dl (ytdl) three times in the broadcast code:
1) To populate video metadata, including dimensions which allow us to know how much to crop the video
@@ -114,7 +116,6 @@ class VideoBroadcaster:
"""
download_and_convert_video_proc = self.__start_download_and_convert_video_proc()
self.__get_video_info(assert_data_not_yet_loaded = True)
- self.__start_receivers()
"""
This `sleep` makes the videos more likely to start in-sync across all the TVs, but I'm not totally
@@ -132,7 +133,7 @@ class VideoBroadcaster:
See data collected on the effectiveness of this sleep:
https://gist.github.com/dasl-/e5c05bf89c7a92d43881a2ff978dc889
"""
- time.sleep(2)
+ # time.sleep(2)
video_broadcast_proc = self.__start_video_broadcast_proc(download_and_convert_video_proc)
self.__logger.info("Waiting for download_and_convert_video and video_broadcast procs to end...")
@@ -195,6 +196,13 @@ class VideoBroadcaster:
return download_and_convert_video_proc
def __start_video_broadcast_proc(self, download_and_convert_video_proc):
+ msg = {
+ 'video_width': self.__get_video_info()['width'],
+ 'video_height': self.__get_video_info()['height'],
+ }
+ self.__control_message_helper.send_msg(ControlMessageHelper.TYPE_VIDEO_DIMENSIONS, msg)
+ self.__logger.info("Sent video_dimensions control message.")
+
# See: https://github.com/dasl-/piwall2/blob/main/docs/controlling_video_broadcast_speed.adoc
mbuffer_size = round(Receiver.VIDEO_PLAYBACK_MBUFFER_SIZE_BYTES / 2)
burst_throttling_clause = (f'HOME=/home/pi mbuffer -q -l /tmp/mbuffer.out -m {mbuffer_size}b | ' +
@@ -222,9 +230,7 @@ class VideoBroadcaster:
def __start_receivers(self):
msg = {
'log_uuid': Logger.get_uuid(),
- 'video_width': self.__get_video_info()['width'],
- 'video_height': self.__get_video_info()['height'],
- 'video_url_type': self.__get_video_url_type(),
+ 'video_url_type': self.__get_video_url_type()
}
self.__control_message_helper.send_msg(ControlMessageHelper.TYPE_PLAY_VIDEO, msg)
self.__logger.info("Sent play_video control message.")
diff --git a/piwall2/controlmessagehelper.py b/piwall2/controlmessagehelper.py
index 3be55ef..783227e 100644
--- a/piwall2/controlmessagehelper.py
+++ b/piwall2/controlmessagehelper.py
@@ -16,6 +16,7 @@ class ControlMessageHelper:
TYPE_PLAY_VIDEO = 'play_video'
TYPE_SKIP_VIDEO = 'skip_video'
TYPE_DISPLAY_MODE = 'display_mode'
+ TYPE_VIDEO_DIMENSIONS = 'video_dimensions'
CTRL_MSG_TYPE_KEY = 'msg_type'
CONTENT_KEY = 'content'
diff --git a/piwall2/displaymode.py b/piwall2/displaymode.py
index 3d73c18..02e552d 100644
--- a/piwall2/displaymode.py
+++ b/piwall2/displaymode.py
@@ -5,4 +5,5 @@ class DisplayMode:
# Repeat mode is like this: https://i.imgur.com/cpS61s8.png
DISPLAY_MODE_TILE = 'DISPLAY_MODE_TILE'
DISPLAY_MODE_REPEAT = 'DISPLAY_MODE_REPEAT'
+
DISPLAY_MODES = (DISPLAY_MODE_TILE, DISPLAY_MODE_REPEAT)
diff --git a/piwall2/receiver/receiver.py b/piwall2/receiver/receiver.py
index 49c6397..7ccc6fc 100644
--- a/piwall2/receiver/receiver.py
+++ b/piwall2/receiver/receiver.py
@@ -82,6 +82,9 @@ class Receiver:
self.__stop_video_playback_if_playing()
self.__receive_and_play_video_proc = self.__receive_and_play_video(ctrl_msg)
self.__receive_and_play_video_proc_pgid = os.getpgid(self.__receive_and_play_video_proc.pid)
+ elif msg_type == ControlMessageHelper.TYPE_VIDEO_DIMENSIONS:
+ if self.__is_video_playback_in_progress:
+ self.__set_video_crop_args(ctrl_msg)
elif msg_type == ControlMessageHelper.TYPE_SKIP_VIDEO:
if self.__is_video_playback_in_progress:
self.__stop_video_playback_if_playing()
@@ -94,10 +97,10 @@ class Receiver:
old_display_mode = self.__display_mode
old_display_mode2 = self.__display_mode2
for tv_num, tv_id in self.__tv_ids.items():
+ display_mode_to_set = display_mode_by_tv_id[tv_id]
+ if display_mode_to_set not in DisplayMode.DISPLAY_MODES:
+ display_mode_to_set = DisplayMode.DISPLAY_MODE_TILE
if tv_id in display_mode_by_tv_id:
- display_mode_to_set = display_mode_by_tv_id[tv_id]
- if display_mode_to_set not in DisplayMode.DISPLAY_MODES:
- display_mode_to_set = DisplayMode.DISPLAY_MODE_TILE
if tv_num == 1:
self.__display_mode = display_mode_to_set
else:
@@ -111,12 +114,8 @@ class Receiver:
ctrl_msg_content = ctrl_msg[ControlMessageHelper.CONTENT_KEY]
self.__orig_log_uuid = Logger.get_uuid()
Logger.set_uuid(ctrl_msg_content['log_uuid'])
- cmd, self.__crop_args, self.__crop_args2 = (
- self.__receiver_command_builder.build_receive_and_play_video_command_and_get_crop_args(
- ctrl_msg_content['log_uuid'], ctrl_msg_content['video_width'],
- ctrl_msg_content['video_height'], self.__video_player_volume_pct,
- self.__display_mode, self.__display_mode2
- )
+ cmd = self.__receiver_command_builder.build_receive_and_play_video_command(
+ ctrl_msg_content['log_uuid'], self.__video_player_volume_pct
)
self.__logger.info(f"Running receive_and_play_video command: {cmd}")
self.__is_video_playback_in_progress = True
@@ -125,6 +124,13 @@ class Receiver:
)
return proc
+ def __set_video_crop_args(self, ctrl_msg):
+ ctrl_msg_content = ctrl_msg[ControlMessageHelper.CONTENT_KEY]
+ self.__crop_args, self.__crop_args2 = self.__receiver_command_builder.get_crop_dimensions(
+ ctrl_msg_content['video_width'], ctrl_msg_content['video_height']
+ )
+ self.__omxplayer_controller.set_crop(self.__crop_args[self.__display_mode])
+
def __stop_video_playback_if_playing(self):
if not self.__is_video_playback_in_progress:
return
diff --git a/piwall2/receiver/receivercommandbuilder.py b/piwall2/receiver/receivercommandbuilder.py
index 2e00fc8..d4c3f64 100644
--- a/piwall2/receiver/receivercommandbuilder.py
+++ b/piwall2/receiver/receivercommandbuilder.py
@@ -15,14 +15,9 @@ class ReceiverCommandBuilder:
self.__config_loader = config_loader
self.__receiver_config_stanza = receiver_config_stanza
- def build_receive_and_play_video_command_and_get_crop_args(
- self, log_uuid, video_width, video_height, volume_pct, display_mode, display_mode2
- ):
+ def build_receive_and_play_video_command(self, log_uuid, volume_pct):
adev, adev2 = self.__get_video_command_adev_args()
display, display2 = self.__get_video_command_display_args()
- crop_args, crop_args2 = self.__get_video_command_crop_args(video_width, video_height)
- crop = crop_args[display_mode]
- crop2 = crop_args2[display_mode2]
# See: https://github.com/popcornmix/omxplayer/#volume-rw
volume_pct = VolumeController.normalize_vol_pct(volume_pct)
@@ -64,16 +59,16 @@ class ReceiverCommandBuilder:
f'{piwall2.receiver.receiver.Receiver.VIDEO_PLAYBACK_MBUFFER_SIZE_BYTES}b')
# See: https://github.com/dasl-/piwall2/blob/main/docs/configuring_omxplayer.adoc
- omx_cmd_template = ('omxplayer --crop {0} --adev {1} --display {2} --vol {3} --aspect-mode stretch ' +
+ omx_cmd_template = ('omxplayer --adev {0} --display {1} --vol {2} --aspect-mode stretch ' +
'--no-keys --timeout 30 --threshold 0.2 --video_fifo 10 --genlog pipe:0')
omx_cmd = omx_cmd_template.format(
- shlex.quote(crop), shlex.quote(adev), shlex.quote(display), shlex.quote(str(volume_millibels))
+ shlex.quote(adev), shlex.quote(display), shlex.quote(str(volume_millibels))
)
cmd = 'set -o pipefail && '
if self.__receiver_config_stanza['is_dual_video_output']:
omx_cmd2 = omx_cmd_template.format(
- shlex.quote(crop2), shlex.quote(adev2), shlex.quote(display2), shlex.quote(str(volume_millibels))
+ shlex.quote(adev2), shlex.quote(display2), shlex.quote(str(volume_millibels))
)
cmd += f'{mbuffer_cmd} | tee >({omx_cmd}) >({omx_cmd2}) >/dev/null'
else:
@@ -81,51 +76,7 @@ class ReceiverCommandBuilder:
receiver_cmd = (f'{DirectoryUtils().root_dir}/bin/receive_and_play_video --command {shlex.quote(cmd)} ' +
f'--log-uuid {shlex.quote(log_uuid)}')
- return (receiver_cmd, crop_args, crop_args2)
-
- def __get_video_command_adev_args(self):
- receiver_config = self.__receiver_config_stanza
- adev = None
- if receiver_config['audio'] == 'hdmi' or receiver_config['audio'] == 'hdmi0':
- adev = 'hdmi'
- elif receiver_config['audio'] == 'headphone':
- adev = 'local'
- elif receiver_config['audio'] == 'hdmi_alsa' or receiver_config['audio'] == 'hdmi0_alsa':
- adev = 'alsa:default:CARD=b1'
- else:
- raise Exception(f"Unexpected audio config value: {receiver_config['audio']}")
-
- adev2 = None
- if receiver_config['is_dual_video_output']:
- if receiver_config['audio2'] == 'hdmi1':
- adev2 = 'hdmi1'
- elif receiver_config['audio2'] == 'headphone':
- adev2 = 'local'
- elif receiver_config['audio'] == 'hdmi1_alsa':
- adev2 = 'alsa:default:CARD=b2'
- else:
- raise Exception(f"Unexpected audio2 config value: {receiver_config['audio2']}")
-
- return (adev, adev2)
-
- def __get_video_command_display_args(self):
- receiver_config = self.__receiver_config_stanza
- display = None
- if receiver_config['video'] == 'hdmi' or receiver_config['video'] == 'hdmi0':
- display = '2'
- elif receiver_config['video'] == 'composite':
- display = '3'
- else:
- raise Exception(f"Unexpected video config value: {receiver_config['video']}")
-
- display2 = None
- if receiver_config['is_dual_video_output']:
- if receiver_config['video2'] == 'hdmi1':
- display2 = '7'
- else:
- raise Exception(f"Unexpected video2 config value: {receiver_config['video2']}")
-
- return (display, display2)
+ return receiver_cmd
"""
Returns a set of crop args supporting two display modes: tile mode and repeat mode.
@@ -135,7 +86,7 @@ class ReceiverCommandBuilder:
We return four crop settings because for each mode, we calculate the crop arguments
for each of two TVs (each receiver can have at most two TVs hooked up to it).
"""
- def __get_video_command_crop_args(self, video_width, video_height):
+ def get_crop_dimensions(self, video_width, video_height):
receiver_config = self.__receiver_config_stanza
#####################################################################################
@@ -229,6 +180,50 @@ class ReceiverCommandBuilder:
}
return (crop_args, crop_args2)
+ def __get_video_command_adev_args(self):
+ receiver_config = self.__receiver_config_stanza
+ adev = None
+ if receiver_config['audio'] == 'hdmi' or receiver_config['audio'] == 'hdmi0':
+ adev = 'hdmi'
+ elif receiver_config['audio'] == 'headphone':
+ adev = 'local'
+ elif receiver_config['audio'] == 'hdmi_alsa' or receiver_config['audio'] == 'hdmi0_alsa':
+ adev = 'alsa:default:CARD=b1'
+ else:
+ raise Exception(f"Unexpected audio config value: {receiver_config['audio']}")
+
+ adev2 = None
+ if receiver_config['is_dual_video_output']:
+ if receiver_config['audio2'] == 'hdmi1':
+ adev2 = 'hdmi1'
+ elif receiver_config['audio2'] == 'headphone':
+ adev2 = 'local'
+ elif receiver_config['audio'] == 'hdmi1_alsa':
+ adev2 = 'alsa:default:CARD=b2'
+ else:
+ raise Exception(f"Unexpected audio2 config value: {receiver_config['audio2']}")
+
+ return (adev, adev2)
+
+ def __get_video_command_display_args(self):
+ receiver_config = self.__receiver_config_stanza
+ display = None
+ if receiver_config['video'] == 'hdmi' or receiver_config['video'] == 'hdmi0':
+ display = '2'
+ elif receiver_config['video'] == 'composite':
+ display = '3'
+ else:
+ raise Exception(f"Unexpected video config value: {receiver_config['video']}")
+
+ display2 = None
+ if receiver_config['is_dual_video_output']:
+ if receiver_config['video2'] == 'hdmi1':
+ display2 = '7'
+ else:
+ raise Exception(f"Unexpected video2 config value: {receiver_config['video2']}")
+
+ return (display, display2)
+
"""
The displayable width and height represents the section of the video that the wall will be
displaying. A section of these dimensions will be taken from the center of the original
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment