Created
November 9, 2021 05:23
-
-
Save dasl-/db3ce584ba90802ba390ac0f07611dea to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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