From ac4afdf08005b5cc8bb008295b32b13e6fbae6d0 Mon Sep 17 00:00:00 2001 From: langolierz Date: Sun, 18 Feb 2018 02:45:23 +0000 Subject: [PATCH 1/3] tidy up video player logic so that switch button is stronger and loop should stop when error state is reached --- actions.py | 2 +- data_centre/json_objects/display_data.json | 2 +- .../json_objects/keypad_action_mapping.json | 2 +- .../json_objects/next_slot_number.json | 2 +- data_centre/json_objects/settings.json | 2 +- video_centre/video_driver.py | 61 +++++++++++++------ video_centre/video_player.py | 21 ++++++- 7 files changed, 65 insertions(+), 27 deletions(-) diff --git a/actions.py b/actions.py index abdb778..20a4caa 100644 --- a/actions.py +++ b/actions.py @@ -79,7 +79,7 @@ class Actions(object): self.load_this_slot_into_next_player(9) def trigger_next_player(self): - self.video_driver.manual_next = True + self.video_driver.switch_players_and_play_video() def cycle_display_mode(self): self.display.top_menu_index = 0 diff --git a/data_centre/json_objects/display_data.json b/data_centre/json_objects/display_data.json index d6498d9..8ce208e 100644 --- a/data_centre/json_objects/display_data.json +++ b/data_centre/json_objects/display_data.json @@ -1 +1 @@ -[{"start": 607.690078, "end": 610.079466, "length": 1132.04, "name": "mushroom-dreams.mp4", "location": "/media/pi/TIM/videos_to_play/mushroom-dreams.mp4"}, {"start": -1, "end": -1, "length": 3.008, "name": "samplerloop3s3.mp4", "location": "/media/pi/TIM/samplerloop3s3.mp4"}, {"start": -1, "end": -1, "length": 804.245, "name": "long_spinning.mp4", "location": "/media/pi/TIM/videos_to_play/long_spinning.mp4"}, {"start": 66.892487, "end": 68.500718, "length": 87.04, "name": "colour_pixel_02.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_02.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}, {"end": -1, "start": -1, "length": 52.757, "name": "colour_pixel_03.mp4", "location": "/media/pi/TIM/videos_to_play/colour_pixel_03.mp4"}] \ No newline at end of file +[{"location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4", "length": 49.28, "start": -1, "name": "colour_pixel_01.mp4", "end": -1}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}] \ No newline at end of file diff --git a/data_centre/json_objects/keypad_action_mapping.json b/data_centre/json_objects/keypad_action_mapping.json index a33d0e7..9517b07 100644 --- a/data_centre/json_objects/keypad_action_mapping.json +++ b/data_centre/json_objects/keypad_action_mapping.json @@ -37,7 +37,7 @@ "DEFAULT": ["load_slot_1_into_next_player"] }, "l": { - "DEFAULT": ["load_slot_2_into_next_player"] + "DEFAULT": ["load_slot_2_into_next_player","clear_all_slots"] }, "m": { "DEFAULT": ["load_slot_3_into_next_player"] diff --git a/data_centre/json_objects/next_slot_number.json b/data_centre/json_objects/next_slot_number.json index bf0d87a..c227083 100644 --- a/data_centre/json_objects/next_slot_number.json +++ b/data_centre/json_objects/next_slot_number.json @@ -1 +1 @@ -4 \ No newline at end of file +0 \ No newline at end of file diff --git a/data_centre/json_objects/settings.json b/data_centre/json_objects/settings.json index b9cc75d..724808f 100644 --- a/data_centre/json_objects/settings.json +++ b/data_centre/json_objects/settings.json @@ -1 +1 @@ -[{"name": "SCREEN_SIZE", "options": ["dev_mode", "XGA", "composite"]}, {"name": "quit_the_program", "options": ["run_action"]}, {"name": "switch_display_to_hdmi", "options": ["run_action"]}, {"name": "switch_display_to_lcd", "options": ["run_action"]}] \ No newline at end of file +[{"options": ["dev_mode", "XGA", "composite"], "name": "SCREEN_SIZE"}, {"options": ["run_action"], "name": "quit_the_program"}, {"options": ["run_action"], "name": "switch_display_to_hdmi"}, {"options": ["run_action"], "name": "switch_display_to_lcd"}] \ No newline at end of file diff --git a/video_centre/video_driver.py b/video_centre/video_driver.py index 56757e5..88843e2 100644 --- a/video_centre/video_driver.py +++ b/video_centre/video_driver.py @@ -8,12 +8,14 @@ class VideoDriver(object): self.data = data self.delay = 50 self.has_omx = self.data.has_omx + self.in_first_load_cycle = False + self.in_current_playing_cycle = False + self.in_next_load_cycle = False print(self.has_omx) if self.has_omx: self.last_player = video_player(self.root, self.message_handler, self.data, 'a.a') self.current_player = video_player(self.root,self.message_handler, self.data, 'b.b') self.next_player = video_player(self.root, self.message_handler, self.data, 'c.c') - self.manual_next = False self.print_status() self.root.after(self.delay, self.begin_playing) else: @@ -28,15 +30,26 @@ class VideoDriver(object): def begin_playing(self): # TODO: the first clip will be a demo - self.current_player.load() - self.wait_for_first_load() + if self.current_player.try_load(): + self.in_first_load_cycle = True + self.wait_for_first_load() + else: + print('load failed') def wait_for_first_load(self): - - if self.current_player.is_loaded(): - self.play_video() - else: - self.root.after(self.delay, self.wait_for_first_load) + if self.in_first_load_cycle: + if self.current_player.is_loaded(): + self.in_first_load_cycle = False + self.play_video() + else: + self.root.after(self.delay, self.wait_for_first_load) + + def switch_players_and_play_video(self): + self.in_first_load_cycle = False + self.in_current_playing_cycle = False + self.in_next_load_cycle = True + + self.switch_if_next_is_loaded() def switch_players(self): temp_player = self.last_player @@ -47,22 +60,30 @@ class VideoDriver(object): def play_video(self): self.current_player.play() - self.next_player.load() + self.next_player.try_load() + self.in_current_playing_cycle = True self.wait_for_next_cycle() def wait_for_next_cycle(self): - if self.current_player.is_finished() or self.manual_next: - self.manual_next = False - self.wait_for_next_load() - else: - self.root.after(self.delay, self.wait_for_next_cycle) + if self.in_current_playing_cycle: + if self.current_player.is_finished(): + self.in_current_playing_cycle = False + self.in_next_load_cycle = True + self.switch_if_next_is_loaded() + else: + self.root.after(self.delay, self.wait_for_next_cycle) - def wait_for_next_load(self): - if self.next_player.is_loaded(): - self.switch_players() - self.play_video() - else: - self.root.after(self.delay, self.wait_for_next_load) + def switch_if_next_is_loaded(self): + if self.in_next_load_cycle: + if self.next_player.is_loaded(): + self.in_next_load_cycle = False + self.switch_players() + self.play_video() + else: + if self.next_player.status != 'ERROR': + self.root.after(self.delay, self.switch_if_next_is_loaded) + else: + self.in_next_load_cycle = False def get_info_for_player_display(self): if self.has_omx: diff --git a/video_centre/video_player.py b/video_centre/video_player.py index ff69f97..9676e85 100644 --- a/video_centre/video_player.py +++ b/video_centre/video_player.py @@ -19,6 +19,21 @@ class video_player: self.end = -1.0 self.crop_length = 0.0 self.location = '' + self.load_attempts = 0 + + def try_load(self): + load_attempts = 0 + while(load_attempts < 4): + load_attempts = load_attempts + 1 + if self.load(): + print('load success') + return True + else: + print('load failed') + self.message_handler.set_message('ERROR', 'failed to load') + self.status = 'ERROR' + return False + def load(self): try: @@ -38,9 +53,11 @@ class video_player: if self.start > 0.5: self.set_position(self.start - 0.5) self.pause_at_start() + self.load_attempts = 0 + return True except: - self.message_handler.set_message('ERROR', 'first load error') - self.root.after(100, self.load) + self.message_handler.set_message('ERROR', 'load attempt fail') + return False def pause_at_start(self): position = self.get_position() From e9eb6c1c9e0d446445216a8c75e12b77fb2ac0ba Mon Sep 17 00:00:00 2001 From: langolierz Date: Sun, 18 Feb 2018 03:59:41 +0000 Subject: [PATCH 2/3] seperated the relative controls from the display mode so more functions can be loaded into them --- actions.py | 5 ++++- data_centre/json_objects/display_data.json | 2 +- .../json_objects/keypad_action_mapping.json | 18 +++++++++--------- display_centre/display.py | 6 +++++- user_input/numpad_input.py | 4 ++-- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/actions.py b/actions.py index 20a4caa..656f13c 100644 --- a/actions.py +++ b/actions.py @@ -7,7 +7,7 @@ class Actions(object): self.data = data self.video_driver = video_driver self.display = display - + def move_browser_selection_down(self): self.display.navigate_menu('down', len(self.data.return_browser_list())) @@ -86,10 +86,13 @@ class Actions(object): self.display.selected_list_index = self.display.top_menu_index if self.display.display_mode == "BROWSER": self.display.display_mode = "SETTINGS" + self.display.control_mode = 'NAV_SETTINGS' elif self.display.display_mode == "SAMPLER": self.display.display_mode = "BROWSER" + self.display.control_mode = 'NAV_BROWSER' elif self.display.display_mode == "SETTINGS": self.display.display_mode = "SAMPLER" + self.display.control_mode = 'PLAYER' def toggle_pause_on_player(self): self.video_driver.current_player.toggle_pause() diff --git a/data_centre/json_objects/display_data.json b/data_centre/json_objects/display_data.json index 8ce208e..718bf4a 100644 --- a/data_centre/json_objects/display_data.json +++ b/data_centre/json_objects/display_data.json @@ -1 +1 @@ -[{"location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4", "length": 49.28, "start": -1, "name": "colour_pixel_01.mp4", "end": -1}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}, {"length": -1, "start": -1, "name": "", "end": -1, "location": ""}] \ No newline at end of file +[{"name": "colour_pixel_01.mp4", "length": 49.28, "end": -1, "start": -1, "location": "/media/pi/TIM1/videos_to_play/colour_pixel_01.mp4"}, {"name": "colour_pixel_02.mp4", "start": -1, "location": "/media/pi/TIM1/videos_to_play/colour_pixel_02.mp4", "length": 87.04, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}, {"name": "", "length": -1, "location": "", "start": -1, "end": -1}] \ No newline at end of file diff --git a/data_centre/json_objects/keypad_action_mapping.json b/data_centre/json_objects/keypad_action_mapping.json index 9517b07..24b6f87 100644 --- a/data_centre/json_objects/keypad_action_mapping.json +++ b/data_centre/json_objects/keypad_action_mapping.json @@ -1,18 +1,18 @@ { "a": { - "BROWSER": ["move_browser_selection_up"], - "SAMPLER": ["seek_back_on_player"], - "SETTINGS": ["move_settings_selection_up"] + "NAV_BROWSER": ["move_browser_selection_up"], + "PLAYER": ["seek_back_on_player"], + "NAV_SETTINGS": ["move_settings_selection_up"] }, "b": { - "BROWSER": ["move_browser_selection_down"], - "SAMPLER": ["seek_forward_on_player"], - "SETTINGS": ["move_settings_selection_down"] + "NAV_BROWSER": ["move_browser_selection_down"], + "PLAYER": ["seek_forward_on_player"], + "NAV_SETTINGS": ["move_settings_selection_down"] }, "c": { - "BROWSER": ["enter_on_browser_selection"], - "SAMPLER": ["toggle_pause_on_player"], - "SETTINGS": ["enter_on_settings_selection"] + "NAV_BROWSER": ["enter_on_browser_selection"], + "PLAYER": ["toggle_pause_on_player"], + "NAV_SETTINGS": ["enter_on_settings_selection"] }, "d": { "DEFAULT": ["trigger_next_player"] diff --git a/display_centre/display.py b/display_centre/display.py index ec8f74c..62c0d9c 100644 --- a/display_centre/display.py +++ b/display_centre/display.py @@ -17,6 +17,7 @@ class Display(object): self.data = data self.display_mode = "SAMPLER" + self.control_mode = 'PLAYER' self.top_menu_index = 0 self.selected_list_index = self.top_menu_index self.browser_list = self.data.rewrite_browser_list() @@ -124,7 +125,7 @@ class Display(object): def _load_message(self): if self.message_handler.current_message[1]: - self.display_text.insert(END, '{:5}: {:38}'.format( + self.display_text.insert(END, '{:5} {:38}'.format( self.message_handler.current_message[0], self.message_handler.current_message[1][0:38])) self.display_text.tag_add('{}_MESSAGE'.format( self.message_handler.current_message[0]), 16.0,16.0 + self.SELECTOR_WIDTH) @@ -135,6 +136,9 @@ class Display(object): elif self.message_handler.function_on: self.display_text.insert(END, '{:^45}'.format('< FUNCTION KEY ON >')) self.display_text.tag_add('FUNCTION', 16.0,16.0 + self.SELECTOR_WIDTH) + else: + self.display_text.insert(END, '{:8} {:<10}'.format('CONTROL:', self.control_mode)) + self.display_text.tag_add('TITLE', 16.0,16.0 + self.SELECTOR_WIDTH) def _highlight_this_row(self, row): self.display_text.tag_add("SELECT", self.ROW_OFFSET + row, diff --git a/user_input/numpad_input.py b/user_input/numpad_input.py index 5ecf11d..c74ca57 100644 --- a/user_input/numpad_input.py +++ b/user_input/numpad_input.py @@ -31,8 +31,8 @@ class NumpadInput(object): def run_action_for_mapped_key(self, key): this_mapping = self.key_mappings[key] - if self.display.display_mode in this_mapping: - mode = self.display.display_mode + if self.display.control_mode in this_mapping: + mode = self.display.control_mode elif 'DEFAULT' in this_mapping: mode = 'DEFAULT' From 3729332a3ae8f1f6de0fe2a2b60039073a0f6b08 Mon Sep 17 00:00:00 2001 From: Tim Caldwell Date: Sun, 18 Feb 2018 20:28:48 +1300 Subject: [PATCH 3/3] add first vector draft to readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4411fb3..8762d43 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # r_e_c_u_r an open diy py/pi based video sampler + ![vectorfront][vectorfront] + __r_e_c_u_r__ is an embedded python application on _raspberry pi3_ that uses `input` from the _keypad_ to control omxplayer's `video out` while `displaying` a simple text user interface on the _rpi lcd screen_   ## features @@ -34,6 +36,7 @@ i started a [board] of features i would like to explore langolierz@gmail.com +[vectorfront]: ./documentation/vectorfront.png [board]: https://trello.com/b/mmJJFyrp/feature-ideas [operating]: documentation/operate_docs.md [building]: documentation/build_docs.md