mirror of
https://github.com/cyberboy666/r_e_c_u_r.git
synced 2025-12-12 11:20:15 +01:00
tidied up the exsting code, added data objects and special helper classes
This commit is contained in:
168
data_centre.py
168
data_centre.py
@@ -1,37 +1,52 @@
|
||||
import json
|
||||
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
import os
|
||||
from random import randint
|
||||
|
||||
#TODO : standise the paths to things, use constants for file names, standise the naming convention of files
|
||||
import time
|
||||
import inspect
|
||||
|
||||
PATH_TO_BROWSER = 'C:/TestFolderStucture'
|
||||
######## sets names for the persistant data objects ########
|
||||
NEXT_BANK_JSON = 'next_bank_number.json'
|
||||
SETTINGS_JSON = 'settings.json'
|
||||
BANK_DATA_JSON = 'display_data.json'
|
||||
|
||||
PATH_TO_DATA_OBJECTS = 'C:/Users/Tim/PycharmProjects/videoLooper/'
|
||||
######## define how to get path to current dir and set up logging ########
|
||||
def get_the_current_dir_path():
|
||||
#TODO: investigate weird path formatting differences
|
||||
current_file_path = inspect.stack()[0][1]
|
||||
return os.path.split(current_file_path)[0] + '/'
|
||||
|
||||
def setup_logging():
|
||||
logger = logging.getLogger('logfile')
|
||||
current_dir = get_the_current_dir_path()
|
||||
hdlr = logging.FileHandler(current_dir + 'logfile.log')
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.INFO)
|
||||
return logger
|
||||
|
||||
logger = setup_logging()
|
||||
|
||||
######## sets paths and constants ########
|
||||
PATH_TO_BROWSER = 'C:\TestFolderStucture' #TODO replace this with pi path name when i know what makes sense
|
||||
PATH_TO_DATA_OBJECTS = get_the_current_dir_path()
|
||||
EMPTY_BANK = dict(name='',location='',length=-1,start=-1,end=-1)
|
||||
|
||||
logger = logging.getLogger('myapp')
|
||||
hdlr = logging.FileHandler('C:/Users/Tim/PycharmProjects/videoLooper/myapp.log')
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
####<<<< data methods for browser tab >>>>#####
|
||||
class data(object):
|
||||
######## a data class used mainly for managing the browser list ########
|
||||
def __init__(self):
|
||||
|
||||
self._open_folders = []
|
||||
self._browser_list = []
|
||||
|
||||
|
||||
def rewrite_browser_list(self):
|
||||
self._browser_list = generate_browser_list(PATH_TO_BROWSER, 0, self._open_folders)
|
||||
|
||||
def get_browser_data_for_display(self):
|
||||
######## map the browser_list to format for displaying in asciimatics ########
|
||||
if not self._browser_list:
|
||||
self.rewrite_browser_list()
|
||||
|
||||
@@ -48,34 +63,13 @@ class data(object):
|
||||
self._open_folders.remove(folder_name)
|
||||
|
||||
|
||||
def get_all_looper_data_for_display():
|
||||
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
loop_data = []
|
||||
for index, bank in enumerate(memory_bank):
|
||||
length = convert_int_to_string_for_display(bank["length"])
|
||||
start = convert_int_to_string_for_display(bank["start"])
|
||||
end = convert_int_to_string_for_display(bank["end"])
|
||||
loop_data.append(([str(index),bank["name"],length,start,end],index))
|
||||
|
||||
return loop_data
|
||||
|
||||
def is_file_in_memory_bank(file_name, memory_bank=[]):
|
||||
if not memory_bank:
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
for index, bank in enumerate(memory_bank):
|
||||
if(file_name == bank['name']):
|
||||
return True , index
|
||||
return False, ''
|
||||
|
||||
def generate_browser_list(current_path, current_level, open_folder_list):
|
||||
|
||||
def generate_browser_list(initial_path, current_level, open_folder_list):
|
||||
######## starts the recursive process of listing all folders and video files to display ########
|
||||
global results
|
||||
results = []
|
||||
add_folder_to_browser_list(initial_path, current_level,open_folder_list)
|
||||
|
||||
add_folder_to_browser_list(current_path, current_level,open_folder_list)
|
||||
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
|
||||
for browser_line in results:
|
||||
is_file, file_name = extract_file_type_and_name_from_browser_format(browser_line['name'])
|
||||
@@ -87,6 +81,8 @@ def generate_browser_list(current_path, current_level, open_folder_list):
|
||||
return results
|
||||
|
||||
def add_folder_to_browser_list(current_path, current_level,open_folder_list):
|
||||
######## adds the folders and mp4 files at the current level to the results list. recursively recalls at deeper level if folder is open ########
|
||||
#TODO make note of / investigate what happens with multiple folders of same name
|
||||
root, dirs, files = next(os.walk(current_path))
|
||||
|
||||
indent = ' ' * 4 * (current_level)
|
||||
@@ -105,24 +101,33 @@ def add_folder_to_browser_list(current_path, current_level,open_folder_list):
|
||||
results.append(dict(name='{}{}'.format(indent, f), bank='-'))
|
||||
|
||||
def check_folder_state(folder_name,open_folder_list):
|
||||
######## used for displaying folders as open or closed ########
|
||||
if (folder_name in open_folder_list):
|
||||
return True, '/'
|
||||
else:
|
||||
return False, '|'
|
||||
|
||||
def extract_file_type_and_name_from_browser_format(dir_name):
|
||||
#logger.info('the name we got was {}'.format(dir_name))
|
||||
######## removes whitespace and folder state from display item ########
|
||||
if(dir_name.endswith('|') or dir_name.endswith('/')):
|
||||
return False , dir_name.lstrip()[:-1]
|
||||
else:
|
||||
return True , dir_name.lstrip()
|
||||
|
||||
def get_length_for_file(location):
|
||||
#TODO: will have omx.player get length of file probs..
|
||||
pass
|
||||
def is_file_in_memory_bank(file_name, memory_bank=[]):
|
||||
######## used for displaying the mappings in browser view ########
|
||||
if not memory_bank:
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
for index, bank in enumerate(memory_bank):
|
||||
if(file_name == bank['name']):
|
||||
return True , index
|
||||
return False, ''
|
||||
|
||||
####<<<< responding to user input in browser tab >>>>#####
|
||||
|
||||
def create_new_bank_mapping_in_first_open(file_name):
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
######## used for mapping current video to next available bank ########
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
for index , bank in enumerate(memory_bank):
|
||||
if(not bank['name']):
|
||||
create_new_bank_mapping(index,file_name,memory_bank)
|
||||
@@ -130,12 +135,18 @@ def create_new_bank_mapping_in_first_open(file_name):
|
||||
return False
|
||||
|
||||
def create_new_bank_mapping(bank_number,file_name,memory_bank=[]):
|
||||
######## used for mapping current video to a specific bank ########
|
||||
has_location , location = get_path_for_file(file_name)
|
||||
length = get_length_for_file(location)
|
||||
new_bank = dict(name=file_name, location=location, length=-1, start=-1, end=-1)
|
||||
update_a_banks_data(bank_number, new_bank, memory_bank)
|
||||
|
||||
def get_length_for_file(location):
|
||||
#TODO: will have omx.player get length of file probs..
|
||||
pass
|
||||
|
||||
def get_path_for_file(file_name):
|
||||
######## returns full path for a given file name ########
|
||||
for root, dirs, files in os.walk(PATH_TO_BROWSER):
|
||||
if file_name in files:
|
||||
print root
|
||||
@@ -144,50 +155,54 @@ def get_path_for_file(file_name):
|
||||
return False, ''
|
||||
|
||||
def update_a_banks_data(bank_number, bank_info, memory_bank=[]):
|
||||
######## overwrite a given banks info with new data ########
|
||||
if not memory_bank:
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
memory_bank[bank_number] = bank_info
|
||||
update_json('DisplayData.json', memory_bank)
|
||||
update_json(BANK_DATA_JSON, memory_bank)
|
||||
|
||||
def clear_all_banks():
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
for index , bank in enumerate(memory_bank):
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
for index, bank in enumerate(memory_bank):
|
||||
memory_bank[index] = EMPTY_BANK
|
||||
update_json('DisplayData.json', memory_bank)
|
||||
update_json(BANK_DATA_JSON, memory_bank)
|
||||
|
||||
def read_json(file_name):
|
||||
####<<<< data methods for looper tab >>>>#####
|
||||
|
||||
with open(PATH_TO_DATA_OBJECTS + file_name) as data_file:
|
||||
data = json.load(data_file)
|
||||
def get_all_looper_data_for_display():
|
||||
######## read bank mappings from data object and format for displaying in asciimatics ########
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
loop_data = []
|
||||
for index, bank in enumerate(memory_bank):
|
||||
length = convert_int_to_string_for_display(bank["length"])
|
||||
start = convert_int_to_string_for_display(bank["start"])
|
||||
end = convert_int_to_string_for_display(bank["end"])
|
||||
loop_data.append(([str(index),bank["name"],length,start,end],index))
|
||||
|
||||
return data
|
||||
return loop_data
|
||||
|
||||
def update_json(file_name,data):
|
||||
|
||||
with open('{}{}'.format(PATH_TO_DATA_OBJECTS, file_name), 'w') as data_file:
|
||||
json.dump(data, data_file)
|
||||
####<<<< data methods for looper tab >>>>#####
|
||||
|
||||
def get_all_settings_data_for_display():
|
||||
settings = read_json('Settings.json')
|
||||
######## read settings from data object and format for displaying in asciimatics ########
|
||||
settings = read_json(SETTINGS_JSON)
|
||||
display_settings = []
|
||||
for index, setting in enumerate(settings):
|
||||
display_settings.append(([setting['name'],setting['value']],index))
|
||||
return display_settings
|
||||
|
||||
def get_a_banks_data(bank_number):
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
return memory_bank[bank_number]
|
||||
|
||||
def switch_settings(setting_name):
|
||||
settings = read_json('Settings.json')
|
||||
######## update the value of selected setting by cycling through valid options ########
|
||||
settings = read_json(SETTINGS_JSON)
|
||||
|
||||
for index, setting in enumerate(settings):
|
||||
if setting['name'] == setting_name:
|
||||
setting = cycle_setting_value(setting)
|
||||
|
||||
update_json('Settings.json',settings)
|
||||
update_json(SETTINGS_JSON,settings)
|
||||
|
||||
def cycle_setting_value(setting):
|
||||
######## contains the valid setting values for each applicable option ########
|
||||
if setting['name'] == 'PLAYBACK_MODE':
|
||||
if setting['value'] == 'LOOPER':
|
||||
setting['value'] = 'PLAYLIST'
|
||||
@@ -213,17 +228,18 @@ def cycle_setting_value(setting):
|
||||
|
||||
return setting
|
||||
|
||||
####<<<< data methods for video_centre >>>>#####
|
||||
|
||||
def get_next_context():
|
||||
next_bank_number = read_json('next_bank_number.json')
|
||||
memory_bank = read_json('DisplayData.json')
|
||||
######## loads the bank details, uses settings to modify them and then set next bank number ########
|
||||
next_bank_number = read_json(NEXT_BANK_JSON)
|
||||
memory_bank = read_json(BANK_DATA_JSON)
|
||||
next_bank_details = memory_bank[next_bank_number]
|
||||
start_value = next_bank_details['start']
|
||||
end_value = next_bank_details['end']
|
||||
length = next_bank_details['length']
|
||||
|
||||
use_rand_start, use_sync_length, sync_length, playback_mode = get_context_options_from_settings()
|
||||
set_next_bank_number_from_playback_mode(playback_mode,next_bank_number)
|
||||
|
||||
if use_rand_start and use_sync_length:
|
||||
start_value = randint(0, length - sync_length)
|
||||
@@ -233,10 +249,14 @@ def get_next_context():
|
||||
elif not use_rand_start and use_sync_length:
|
||||
end_value = min(length, start_value + sync_length)
|
||||
|
||||
set_next_bank_number_from_playback_mode(playback_mode, next_bank_number)
|
||||
|
||||
context = dict(location=next_bank_details['location'],start=start_value,end=end_value, bank_number=next_bank_number)
|
||||
return context
|
||||
|
||||
def get_context_options_from_settings():
|
||||
settings = read_json('Settings.json')
|
||||
######## looks up the settings data object and returns states of relevant options ########
|
||||
settings = read_json(SETTINGS_JSON)
|
||||
use_sync_length = False
|
||||
sync_length = 0
|
||||
use_rand_start = False
|
||||
@@ -255,6 +275,7 @@ def get_context_options_from_settings():
|
||||
return use_rand_start , use_sync_length , sync_length , playback_mode
|
||||
|
||||
def set_next_bank_number_from_playback_mode(playback_mode, current_bank_number):
|
||||
######## sets next bank number by using playback mode logic ########
|
||||
next_bank_number = 0
|
||||
if playback_mode == 'LOOPER':
|
||||
next_bank_number = current_bank_number
|
||||
@@ -266,6 +287,17 @@ def set_next_bank_number_from_playback_mode(playback_mode, current_bank_number):
|
||||
next_bank_number = current_bank_number
|
||||
update_json('next_bank_number.json',next_bank_number)
|
||||
|
||||
####<<<< generic methods for all tabs >>>>#####
|
||||
|
||||
def read_json(file_name):
|
||||
with open(PATH_TO_DATA_OBJECTS + file_name) as data_file:
|
||||
data = json.load(data_file)
|
||||
return data
|
||||
|
||||
def update_json(file_name,data):
|
||||
with open('{}{}'.format(PATH_TO_DATA_OBJECTS, file_name), 'w') as data_file:
|
||||
json.dump(data, data_file)
|
||||
|
||||
def convert_int_to_string_for_display(time_in_seconds):
|
||||
if time_in_seconds < 0:
|
||||
return ''
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
from Tkinter import *
|
||||
import time
|
||||
import os
|
||||
|
||||
import math
|
||||
from asciimatics.effects import RandomNoise
|
||||
from asciimatics.event import KeyboardEvent
|
||||
from asciimatics.exceptions import ResizeScreenError, NextScene
|
||||
from asciimatics.scene import Scene
|
||||
from asciimatics.screen import Screen
|
||||
from dual_screen import Screen
|
||||
from asciimatics.widgets import Frame, Layout, Divider, Button, ListBox, Widget, MultiColumnListBox, PopUpDialog, Text, \
|
||||
Label
|
||||
|
||||
@@ -20,13 +21,7 @@ VIDEO_DISPLAY_TEXT = 'NOW [{}] {} NEXT [{}] {}'
|
||||
VIDEO_DISPLAY_BANNER_LIST = ['[','-','-','-','-','-','-','-','-','-','-',']']
|
||||
VIDEO_DISPLAY_BANNER_TEXT = '{} {} {}'
|
||||
|
||||
logger = logging.getLogger('myapp')
|
||||
hdlr = logging.FileHandler('C:/Users/Tim/PycharmProjects/videoLooper/myapp.log')
|
||||
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
|
||||
hdlr.setFormatter(formatter)
|
||||
logger.addHandler(hdlr)
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
logger = data_centre.setup_logging()
|
||||
|
||||
class Display(Frame):
|
||||
def __init__(self, switch, screen,driver, on_load=None):
|
||||
@@ -37,30 +32,24 @@ class Display(Frame):
|
||||
title="r_e_c_u_r"
|
||||
)
|
||||
self._last_frame = 0
|
||||
self.popup_message = None
|
||||
self.video_driver = driver
|
||||
self.my_frame_update_count = 40
|
||||
|
||||
|
||||
|
||||
layout_top = Layout([1,1,1])
|
||||
self.add_layout(layout_top)
|
||||
|
||||
self.browser_button = Button("BROWSER", self.do_nothing())
|
||||
self.browser_button.disabled = True
|
||||
#self.browser_button.is_tab_stop = False
|
||||
if switch[0]:
|
||||
self.browser_button.custom_colour = "focus_button"
|
||||
|
||||
self.looper_button = Button("LOOPER", self.do_nothing())
|
||||
self.looper_button.disabled = True
|
||||
#self.looper_button.is_tab_stop = False
|
||||
if switch[1]:
|
||||
self.looper_button.custom_colour = "focus_button"
|
||||
|
||||
self.settings_button = Button("SETTINGS", self.do_nothing())
|
||||
self.settings_button.disabled = True
|
||||
#self.advance_button.is_tab_stop = False
|
||||
if switch[2]:
|
||||
self.settings_button.custom_colour = "focus_button"
|
||||
layout_top.add_widget(Divider(), 0)
|
||||
@@ -83,7 +72,7 @@ class Display(Frame):
|
||||
self.fix()
|
||||
|
||||
def do_nothing(self):
|
||||
return
|
||||
pass
|
||||
|
||||
def get_text_for_video_display(self):
|
||||
now_bank, now_status, next_bank, next_status, duration, video_length = self.video_driver.get_info_for_video_display()
|
||||
@@ -109,8 +98,6 @@ class Display(Frame):
|
||||
return 20
|
||||
|
||||
def get_focus_on_list(self, list):
|
||||
|
||||
#return self._layouts[self._focus]
|
||||
return list.options[list.value][0][0]
|
||||
|
||||
def process_event(self, event):
|
||||
@@ -120,6 +107,7 @@ class Display(Frame):
|
||||
|
||||
return super(Display, self).process_event(event)
|
||||
|
||||
|
||||
class Browser(Display):
|
||||
def __init__(self, screen, data, driver):
|
||||
super(Browser, self).__init__([1,0,0],screen,driver, on_load=self._reload_list)
|
||||
@@ -164,13 +152,8 @@ class Browser(Display):
|
||||
self._reload_list(self._browser_data_view.value)
|
||||
|
||||
if event.key_code in [ord('c')]:
|
||||
#self.popup_message = PopUpDialog(self._screen, 'Deleting all banks',['|'])
|
||||
|
||||
#self._scene.add_effect()
|
||||
data_centre.clear_all_banks()
|
||||
#time.sleep(1)
|
||||
|
||||
#self._scene.remove_effect(popup_message)
|
||||
self._data_object.rewrite_browser_list()
|
||||
self._reload_list(self._browser_data_view.value)
|
||||
|
||||
@@ -181,14 +164,11 @@ class Browser(Display):
|
||||
logger.info('the BROWSER frame number is {}'.format(frame_no))
|
||||
super(Browser, self)._update(frame_no)
|
||||
|
||||
|
||||
|
||||
|
||||
def _reload_list(self, new_value=None):
|
||||
|
||||
self._browser_data_view.options = self._data_object.get_browser_data_for_display()
|
||||
self._browser_data_view.value = new_value
|
||||
|
||||
|
||||
class Looper(Display):
|
||||
def __init__(self, screen, data,driver):
|
||||
super(Looper, self).__init__([0, 1, 0],screen,driver,on_load=self._reload_list,)
|
||||
@@ -206,25 +186,13 @@ class Looper(Display):
|
||||
self.fix()
|
||||
|
||||
def process_event(self, event):
|
||||
# if isinstance(event, KeyboardEvent):
|
||||
# if event.key_code in [ord('q'), ord('Q'), Screen.ctrl("c")]:
|
||||
# raise StopApplication("User quit")
|
||||
# elif event.key_code in [ord("r"), ord("R")]:
|
||||
# self._reverse = not self._reverse
|
||||
# elif event.key_code == ord("<"):
|
||||
# self._sort = max(0, self._sort - 1)
|
||||
# elif event.key_code == ord(">"):
|
||||
# self._sort = min(7, self._sort + 1)
|
||||
|
||||
#self._last_frame = 0
|
||||
|
||||
# Now pass on to lower levels for normal handling of the event.
|
||||
return super(Looper, self).process_event(event)
|
||||
|
||||
def _reload_list(self, new_value=None):
|
||||
self._bank_data_view.options = data_centre.get_all_looper_data_for_display()
|
||||
self._bank_data_view.value = new_value
|
||||
|
||||
|
||||
class Settings(Display):
|
||||
def __init__(self, screen, data,driver):
|
||||
super(Settings, self).__init__([0, 0, 1], screen,driver,on_load=self._reload_list)
|
||||
@@ -255,6 +223,7 @@ class Settings(Display):
|
||||
|
||||
return super(Settings, self).process_event(event)
|
||||
|
||||
|
||||
class ScrollingMultiColumnListBox(MultiColumnListBox):
|
||||
def __init__(self, height, columns, options, titles):
|
||||
super(ScrollingMultiColumnListBox, self).__init__(height, columns, options, titles)
|
||||
@@ -268,13 +237,6 @@ class ScrollingMultiColumnListBox(MultiColumnListBox):
|
||||
|
||||
super(ScrollingMultiColumnListBox,self).process_event(event)
|
||||
|
||||
|
||||
def inspect_browser_focus(dir_name):
|
||||
if(dir_name.endswith('|') or dir_name.endswith('/')):
|
||||
return False , dir_name.lstrip()[:-1]
|
||||
else:
|
||||
return True , dir_name.lstrip()
|
||||
|
||||
def create_video_display_banner(duration,video_length):
|
||||
banner_list = ['[','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-',']']
|
||||
max = len(banner_list) - 1
|
||||
@@ -288,25 +250,28 @@ def create_video_display_banner(duration,video_length):
|
||||
|
||||
return ''.join(banner_list)
|
||||
|
||||
|
||||
|
||||
def demo(screen):
|
||||
def demo(screen, tk):
|
||||
scenes = [Scene([Browser(screen, data,video_driver)], -1),
|
||||
Scene([Looper(screen, data,video_driver)], -1),
|
||||
Scene([Settings(screen, data,video_driver)], -1)]
|
||||
screen.play(scenes)
|
||||
screen.play(scenes,tk)
|
||||
|
||||
data = data_centre.data()
|
||||
video_driver = video_centre.video_driver()
|
||||
last_scene = None
|
||||
|
||||
tk = Tk()
|
||||
canvas = Canvas(tk, width=500, height=400, bd=0, highlightthickness=0)
|
||||
canvas.pack()
|
||||
|
||||
while True:
|
||||
try:
|
||||
Screen.wrapper(demo, catch_interrupt=True)
|
||||
Screen.wrapper(demo, catch_interrupt=True, arguments=(tk,))
|
||||
sys.exit(0)
|
||||
except ResizeScreenError as e:
|
||||
last_scene = e.scene
|
||||
except Exception as e:
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error(str(e))
|
||||
# Logs the error appropriately.
|
||||
|
||||
|
||||
|
||||
1
display_data.json
Normal file
1
display_data.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"start": -1, "length": -1, "end": -1, "location": "", "name": "extremely_minimal_video_1.mp4"}, {"start": -1, "length": -1, "end": -1, "location": "C:\\TestFolderStucture\\minimal_videos/minimal_video_1.mp4", "name": "minimal_video_1.mp4"}, {"start": -1, "length": -1, "end": -1, "location": "C:\\TestFolderStucture\\minimal_videos/minimal_video_2.mp4", "name": "minimal_video_2.mp4"}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}, {"start": -1, "length": -1, "end": -1, "location": "", "name": ""}]
|
||||
2121
dual_screen.py
Normal file
2121
dual_screen.py
Normal file
File diff suppressed because it is too large
Load Diff
1
next_bank_number.json
Normal file
1
next_bank_number.json
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
544
omxdriver.py
Normal file
544
omxdriver.py
Normal file
@@ -0,0 +1,544 @@
|
||||
import signal
|
||||
import os
|
||||
import sys
|
||||
import dbus
|
||||
import subprocess
|
||||
from time import time,strftime
|
||||
|
||||
|
||||
|
||||
"""
|
||||
12/6/2016 - rewrite to use dbus
|
||||
2/11/2016 - connection needs to wait for dbus filemane to be populated
|
||||
2/11/2016 - remove busy wait for conection
|
||||
24/11/2016 - move pause after load to after first get_position to ensure omxplayer has loaded track before pause
|
||||
24/11/2016 - report dbus exception messages in log
|
||||
30/11/2016 - pause at start waits until position is not 0 as video has not started until it becomes -ve
|
||||
2/12/2016 - make pause glitch tolerant, try again if fails
|
||||
3/12/2016 - remove threading to stop pause and unpause for showing happening in wrong order
|
||||
5/12/2016 - deal with situation where pause at end happened so late that video finished first
|
||||
5/12/2016 - need to send nice-day when stop is received and paused for end as now do not intercept one from omxplayer
|
||||
|
||||
omxdriver hides the detail of using the omxplayer command from videoplayer
|
||||
This is meant to be used with videoplayer.py
|
||||
Its easy to end up with many copies of omxplayer.bin running if this class is not used with care. use pp_videoplayer.py for a safer interface.
|
||||
|
||||
External commands
|
||||
----------------------------
|
||||
__init__ just creates the instance and initialises variables (e.g. omx=OMXDriver())
|
||||
load - processes the track up to where it is ready to display, at this time it pauses.
|
||||
show - plays the video from where 'prepare' left off by resuming from the pause.
|
||||
play - plays a track (not used by gapless)
|
||||
pause/unpause - pause on/off
|
||||
toggle_pause - toggles pause
|
||||
control - sends controls to omxplayer.bin while track is playing (use stop and pause instead of q and p)
|
||||
stop - stops a video that is playing.
|
||||
terminate - Stops a video playing. Used when aborting an application.
|
||||
kill - kill of omxplayer when it hasn't terminated at the end of a track.
|
||||
|
||||
Signals
|
||||
----------
|
||||
The following signals are produced while a track is playing
|
||||
self.start_play_signal = True when a track is ready to be shown
|
||||
self.end_play_signal= True when a track has finished due to stop or because it has come to an end
|
||||
self.end_play_reason reports the reason for the end
|
||||
Also is_running() tests whether the sub-process running omxplayer is present.
|
||||
|
||||
"""
|
||||
|
||||
class OMXDriver(object):
|
||||
|
||||
# adjust this to determine freeze after the first frame
|
||||
after_first_frame_position =-50000 # microseconds
|
||||
|
||||
_LAUNCH_CMD = '/usr/bin/omxplayer --no-keys ' # needs changing if user has installed his own version of omxplayer elsewhere
|
||||
KEY_MAP = { '-': 17, '+': 18, '=': 18} # add more keys here, see popcornmix/omxplayer github file KeyConfig.h
|
||||
|
||||
def __init__(self,widget,pp_dir):
|
||||
|
||||
|
||||
self.widget=widget
|
||||
self.pp_dir=pp_dir
|
||||
|
||||
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.duration=0
|
||||
self.video_position = 0
|
||||
|
||||
self.pause_at_end_required=False
|
||||
self.paused_at_end=False
|
||||
self.pause_at_end_time=0
|
||||
|
||||
# self.pause_before_play_required='before-first-frame' #no,before-first-frame, after-first-frame
|
||||
# self.pause_before_play_required='no'
|
||||
self.paused_at_start='False'
|
||||
|
||||
self.paused=False
|
||||
|
||||
self.terminate_reason=''
|
||||
|
||||
# dbus and subprocess
|
||||
self._process=None
|
||||
self.__iface_root=None
|
||||
self.__iface_props = None
|
||||
self.__iface_player = None
|
||||
|
||||
|
||||
def load(self, track, freeze_at_start,options,caller):
|
||||
self.pause_before_play_required=freeze_at_start
|
||||
self.caller=caller
|
||||
track= "'"+ track.replace("'","'\\''") + "'"
|
||||
# self.mon.log(self,'TIME OF DAY: '+ strftime("%Y-%m-%d %H:%M"))
|
||||
self.dbus_user = os.environ["USER"]
|
||||
|
||||
self.id=str(int(time()*10))
|
||||
|
||||
|
||||
|
||||
self.dbus_name = "org.mpris.MediaPlayer2.omxplayer"+self.id
|
||||
|
||||
self.omxplayer_cmd = OMXDriver._LAUNCH_CMD + options + " --dbus_name '"+ self.dbus_name + "' " + track
|
||||
# self.mon.log(self, 'dbus user ' + self.dbus_user)
|
||||
# self.mon.log(self, 'dbus name ' + self.dbus_name)
|
||||
|
||||
# print self.omxplayer_cmd
|
||||
print("Send command to omxplayer: "+ self.omxplayer_cmd)
|
||||
# self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/home/pi/pipresents/pp_logs/stdout.txt','a'),stderr=file('/home/pi/pipresents/pp_logs/stderr.txt','a'))
|
||||
self._process=subprocess.Popen(self.omxplayer_cmd,shell=True,stdout=file('/dev/null','a'),stderr=file('/dev/null','a'))
|
||||
self.pid=self._process.pid
|
||||
|
||||
# wait for omxplayer to start then start monitoring thread
|
||||
self.dbus_tries = 0
|
||||
self.omx_loaded = False
|
||||
self._wait_for_dbus()
|
||||
return
|
||||
|
||||
def _wait_for_dbus(self):
|
||||
connect_success=self.__dbus_connect()
|
||||
if connect_success is True:
|
||||
# print 'SUCCESS'
|
||||
print('connected to omxplayer dbus after ' + str(self.dbus_tries) + ' centisecs')
|
||||
|
||||
# get duration of the track in microsecs if fails return a very large duration
|
||||
# posibly faile because omxplayer is running but not omxplayer.bin
|
||||
duration_success,duration=self.get_duration()
|
||||
if duration_success is False:
|
||||
print('get duration failed for n attempts using '+ str(duration/60000000)+ ' minutes')
|
||||
# calculate time to pause before last frame
|
||||
self.duration = duration
|
||||
self.pause_at_end_time = duration - 350000
|
||||
# start the thread that is going to monitor output from omxplayer.
|
||||
self._monitor_status()
|
||||
else:
|
||||
self.dbus_tries+=1
|
||||
self.widget.after(100,self._wait_for_dbus)
|
||||
|
||||
|
||||
|
||||
def _monitor_status(self):
|
||||
# print '\n',self.id, '** STARTING ',self.duration
|
||||
self.start_play_signal=False
|
||||
self.end_play_signal=False
|
||||
self.end_play_reason='nothing'
|
||||
self.paused_at_end=False
|
||||
self.paused_at_start='False'
|
||||
self.delay = 50
|
||||
self.widget.after(0,self._status_loop)
|
||||
|
||||
|
||||
|
||||
"""
|
||||
freeze at start
|
||||
'no' - unpause in show - test !=0
|
||||
'before_first_frame' - don't unpause in show, test !=0
|
||||
'after_first_frame' - don't unpause in show, test > -100000
|
||||
"""
|
||||
|
||||
def _status_loop(self):
|
||||
if self.is_running() is False:
|
||||
# process is not running because quit or natural end - seems not to happen
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print ' send nice day - process not running'
|
||||
return
|
||||
else:
|
||||
success, video_position = self.get_position()
|
||||
# if video_position <= 0: print 'read position',video_position
|
||||
if success is False:
|
||||
# print 'send nice day - exception when reading video position'
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
return
|
||||
else:
|
||||
self.video_position=video_position
|
||||
# if timestamp is near the end then pause
|
||||
if self.pause_at_end_required is True and self.video_position>self.pause_at_end_time: #microseconds
|
||||
# print 'pausing at end, leeway ',self.duration - self.video_position
|
||||
pause_end_success = self.pause(' at end of track')
|
||||
if pause_end_success is True:
|
||||
# print self.id,' pause for end success', self.video_position
|
||||
self.paused_at_end=True
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='pause_at_end'
|
||||
return
|
||||
else:
|
||||
print 'pause at end failed, probably because of delay after detection, just run on'
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
# need to do the pausing for preload after first timestamp is received 0 is default value before start
|
||||
# print self.pause_before_play_required,self.paused_at_start,self.video_position,OMXDriver.after_first_frame_position
|
||||
if (self.pause_before_play_required == 'after-first-frame' and self.paused_at_start == 'False' and self.video_position >OMXDriver.after_first_frame_position)\
|
||||
or(self.pause_before_play_required != 'after-first-frame' and self.paused_at_start == 'False' and self.video_position !=0):
|
||||
pause_after_load_success=self.pause('after load')
|
||||
if pause_after_load_success is True:
|
||||
# print self.id,' pause after load success',self.video_position
|
||||
self.start_play_signal = True
|
||||
self.paused_at_start='True'
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
# print 'pause after load failed '+ + str(self.video_position)
|
||||
print( str(self.id)+ ' pause after load fail ' + str(self.video_position))
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
else:
|
||||
self.widget.after(self.delay,self._status_loop)
|
||||
|
||||
|
||||
|
||||
def show(self,freeze_at_end_required,initial_volume):
|
||||
self.initial_volume=initial_volume
|
||||
self.pause_at_end_required=freeze_at_end_required
|
||||
# unpause to start playing
|
||||
if self.pause_before_play_required =='no':
|
||||
unpause_show_success=self.unpause(' to start showing')
|
||||
# print 'unpause for show',self.paused
|
||||
if unpause_show_success is True:
|
||||
pass
|
||||
# print self.id,' unpause for show success', self.video_position
|
||||
else:
|
||||
# should never fail, just warn at the moment
|
||||
print(str(self.id)+ ' unpause for show fail ' + str(self.video_position))
|
||||
|
||||
|
||||
def control(self,char):
|
||||
|
||||
val = OMXDriver.KEY_MAP[char]
|
||||
print('>control received and sent to omxplayer ' + str(self.pid))
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(dbus.Int32(val))
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('Failed to send control - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
print('Failed to send control - process not running')
|
||||
return
|
||||
|
||||
|
||||
# USE ONLY at end and after load
|
||||
# return succces of the operation, several tries if pause did not work and no error reported.
|
||||
def pause(self,reason):
|
||||
print(self,'pause received '+reason)
|
||||
if self.paused is False:
|
||||
print('not paused so send pause '+reason)
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_pause() is False:
|
||||
# failed for good reason
|
||||
return False
|
||||
status=self.omxplayer_is_paused() # test omxplayer after sending the command
|
||||
if status == 'Paused':
|
||||
self.paused = True
|
||||
return True
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
# failed for no good reason
|
||||
print(self, '!!!!! repeat pause ' + str(tries))
|
||||
# print self.id,' !!!!! repeat pause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' pause failed for n attempts'
|
||||
print('pause failed for n attempts')
|
||||
return False
|
||||
# repeat
|
||||
|
||||
|
||||
# USE ONLY for show
|
||||
|
||||
def unpause(self,reason):
|
||||
print('MON' + 'Unpause received '+ reason)
|
||||
if self.paused is True:
|
||||
print('MON' +'Is paused so Track will be unpaused '+ reason)
|
||||
tries=1
|
||||
while True:
|
||||
if self.send_unpause() is False:
|
||||
return False
|
||||
status = self.omxplayer_is_paused() # test omxplayer
|
||||
if status == 'Playing':
|
||||
self.paused = False
|
||||
self.paused_at_start='done'
|
||||
self.set_volume(self.initial_volume)
|
||||
return True
|
||||
|
||||
if status == 'Failed':
|
||||
# failed for good reason because of exception or process not running caused by end of track
|
||||
return False
|
||||
else:
|
||||
print('warn' + '!!!!! repeat unpause ' + str(tries))
|
||||
# print self.id,' !!!! repeat unpause ',self.video_position, tries
|
||||
tries +=1
|
||||
if tries >5:
|
||||
# print self.id, ' unpause failed for n attempts'
|
||||
print('warn' + 'unpause failed for n attempts')
|
||||
return False
|
||||
|
||||
|
||||
def omxplayer_is_paused(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
result=self.__iface_props.PlaybackStatus()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to test paused - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return 'Failed'
|
||||
return result
|
||||
else:
|
||||
print('warn'+'Failed to test paused - process not running')
|
||||
# print self.id,' test paused not successful - process'
|
||||
return 'Failed'
|
||||
|
||||
|
||||
def send_pause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Pause()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to send pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
print('warn'+'Failed to send pause - process not running')
|
||||
# print self.id,' send pause not successful - process'
|
||||
return False
|
||||
|
||||
|
||||
def send_unpause(self):
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to send unpause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
print('warn'+'Failed to send unpause - process not running')
|
||||
# print self.id,' send unpause not successful - process'
|
||||
return False
|
||||
|
||||
def pause_on(self):
|
||||
print('mon'+'pause on received ')
|
||||
# print 'pause on',self.paused
|
||||
if self.paused is True:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
# self.__iface_player.Action(16)
|
||||
self.__iface_player.Pause() # - this should work but does not!!!
|
||||
self.paused=True
|
||||
# print 'paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to do pause on - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
print('warn'+'Failed to do pause on - process not running')
|
||||
return
|
||||
|
||||
|
||||
def pause_off(self):
|
||||
print('mon'+'pause off received ')
|
||||
# print 'pause off',self.paused
|
||||
if self.paused is False:
|
||||
return
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
self.paused=False
|
||||
# print 'not paused OK'
|
||||
return
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to do pause off - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
print('warn'+'Failed to do pause off - process not running')
|
||||
return
|
||||
|
||||
def go(self):
|
||||
print('log'+'go received ')
|
||||
self.unpause('for go')
|
||||
|
||||
|
||||
def mute(self):
|
||||
self.__iface_player.Mute()
|
||||
|
||||
def unmute(self):
|
||||
self.__iface_player.Unmute()
|
||||
|
||||
def set_volume(self,millibels):
|
||||
volume = pow(10, millibels / 2000.0);
|
||||
self.__iface_props.Volume(volume)
|
||||
|
||||
|
||||
def toggle_pause(self,reason):
|
||||
print('log'+'toggle pause received '+ reason)
|
||||
if not self.paused:
|
||||
self.paused = True
|
||||
else:
|
||||
self.paused=False
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_player.Action(16)
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to toggle pause - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
print('warn'+'Failed to toggle pause - process not running')
|
||||
return
|
||||
|
||||
|
||||
|
||||
def stop(self):
|
||||
print('log'+'>stop received and quit sent to omxplayer ' + str(self.pid))
|
||||
# need to send 'nice day'
|
||||
if self.paused_at_end is True:
|
||||
self.end_play_signal=True
|
||||
self.end_play_reason='nice_day'
|
||||
# print 'send nice day for close track'
|
||||
if self.is_running():
|
||||
try:
|
||||
self.__iface_root.Quit()
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed to quit - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return
|
||||
else:
|
||||
print('warn'+'Failed to quit - process not running')
|
||||
return
|
||||
|
||||
|
||||
# kill the subprocess (omxplayer and omxplayer.bin). Used for tidy up on exit.
|
||||
def terminate(self,reason):
|
||||
self.terminate_reason=reason
|
||||
self.stop()
|
||||
|
||||
def get_terminate_reason(self):
|
||||
return self.terminate_reason
|
||||
|
||||
|
||||
# test of whether _process is running
|
||||
def is_running(self):
|
||||
retcode=self._process.poll()
|
||||
# print 'is alive', retcode
|
||||
if retcode is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# kill off omxplayer when it hasn't terminated at the end of a track.
|
||||
# send SIGINT (CTRL C) so it has a chance to tidy up daemons and omxplayer.bin
|
||||
def kill(self):
|
||||
if self.is_running()is True:
|
||||
self._process.send_signal(signal.SIGINT)
|
||||
|
||||
|
||||
def get_position(self):
|
||||
# don't test process as is done just before
|
||||
try:
|
||||
micros = self.__iface_props.Position()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# print 'Failed get_position - dbus exception: {}'.format(ex.get_dbus_message())
|
||||
return False,-1
|
||||
|
||||
|
||||
def get_duration(self):
|
||||
tries=1
|
||||
while True:
|
||||
success,duration=self._try_duration()
|
||||
if success is True:
|
||||
return True,duration
|
||||
else:
|
||||
print('warn'+ 'repeat get duration ' + str(tries))
|
||||
tries +=1
|
||||
if tries >5:
|
||||
return False,sys.maxint*100
|
||||
|
||||
|
||||
def _try_duration(self):
|
||||
"""Return the total length of the playing media"""
|
||||
if self.is_running() is True:
|
||||
try:
|
||||
micros = self.__iface_props.Duration()
|
||||
return True,micros
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
print('warn'+'Failed get duration - dbus exception: {}'.format(ex.get_dbus_message()))
|
||||
return False,-1
|
||||
else:
|
||||
return False,-1
|
||||
|
||||
|
||||
|
||||
|
||||
# *********************
|
||||
# connect to dbus
|
||||
# *********************
|
||||
def __dbus_connect(self):
|
||||
if self.omx_loaded is False:
|
||||
# read the omxplayer dbus data from files generated by omxplayer
|
||||
bus_address_filename = "/tmp/omxplayerdbus.{}".format(self.dbus_user)
|
||||
bus_pid_filename = "/tmp/omxplayerdbus.{}.pid".format(self.dbus_user)
|
||||
|
||||
if not os.path.exists(bus_address_filename):
|
||||
print('log'+'waiting for bus address file ' + bus_address_filename)
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f = open(bus_address_filename, "r")
|
||||
bus_address = f.read().rstrip()
|
||||
if bus_address == '':
|
||||
print('log'+ 'waiting for bus address in file ' + bus_address_filename)
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus address found ' + bus_address)
|
||||
if not os.path.exists(bus_pid_filename):
|
||||
print('warn'+ 'bus pid file does not exist ' + bus_pid_filename)
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
f= open(bus_pid_filename, "r")
|
||||
bus_pid = f.read().rstrip()
|
||||
if bus_pid == '':
|
||||
self.omx_loaded=False
|
||||
return False
|
||||
else:
|
||||
# self.mon.log(self, 'bus pid found ' + bus_pid)
|
||||
os.environ["DBUS_SESSION_BUS_ADDRESS"] = bus_address
|
||||
os.environ["DBUS_SESSION_BUS_PID"] = bus_pid
|
||||
self.omx_loaded = True
|
||||
|
||||
if self.omx_loaded is True:
|
||||
session_bus = dbus.SessionBus()
|
||||
try:
|
||||
omx_object = session_bus.get_object(self.dbus_name, "/org/mpris/MediaPlayer2", introspect=False)
|
||||
self.__iface_root = dbus.Interface(omx_object, "org.mpris.MediaPlayer2")
|
||||
self.__iface_props = dbus.Interface(omx_object, "org.freedesktop.DBus.Properties")
|
||||
self.__iface_player = dbus.Interface(omx_object, "org.mpris.MediaPlayer2.Player")
|
||||
except dbus.exceptions.DBusException as ex:
|
||||
# self.mon.log(self,"Waiting for dbus connection to omxplayer: {}".format(ex.get_dbus_message()))
|
||||
return False
|
||||
return True
|
||||
|
||||
1
settings.json
Normal file
1
settings.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"name": "PLAYBACK_MODE", "value": "RANDOM"}, {"name": "PLAYLIST", "value": "[1,1,1,4,1,2,1,4]"}, {"name": "SYNC_LENGTHS", "value": "OFF"}, {"name": "SYNC_LENGTHS_TO", "value": "00:08"}, {"name": "RAND_START", "value": "OFF"}, {"name": "VIDEO_OUTPUT", "value": "HDMI"}]
|
||||
124
video_centre.py
124
video_centre.py
@@ -1,72 +1,81 @@
|
||||
import time
|
||||
|
||||
#from omxdriver import OMXDriver <== for deving only
|
||||
from Tkinter import Tk, Canvas
|
||||
import data_centre
|
||||
|
||||
|
||||
class video_driver(object):
|
||||
def __init__(self):
|
||||
def __init__(self, widget = None):
|
||||
|
||||
self.last_player = video_player()
|
||||
self.current_player = video_player()
|
||||
self.next_player = video_player()
|
||||
self.widget = widget
|
||||
self.delay = 50
|
||||
self.last_player = video_player(self.widget,'a')
|
||||
self.current_player = video_player(self.widget,'b')
|
||||
self.next_player = video_player(self.widget,'c')
|
||||
|
||||
self.manual_next = False
|
||||
|
||||
#self.video_driver.begin_playing()
|
||||
self.begin_playing()
|
||||
|
||||
def begin_playing(self):
|
||||
#TODO:von startup set up the intital data_structures with a preloaded intial clip in bank 0
|
||||
#TODO: the first clip will be a demo
|
||||
first_context = data_centre.get_next_context()
|
||||
#first_context = '/home/pi/pp_home/media/samplerloop3s.mp4'
|
||||
self.current_player.load_content(first_context)
|
||||
|
||||
self.wait_for_first_load()
|
||||
|
||||
def wait_for_first_load(self):
|
||||
if self.current_player.is_loaded:
|
||||
if self.current_player.is_loaded():
|
||||
self.play_video()
|
||||
else:
|
||||
#need to wait here then
|
||||
time.sleep(1)
|
||||
self.wait_for_first_load()
|
||||
#load player states
|
||||
self.widget.after(self.delay, self.wait_for_first_load)
|
||||
|
||||
def switch_players(self):
|
||||
self.temp_player = self.last_player
|
||||
self.last_player = self.current_player
|
||||
print('switch: last_player is {}'.format(self.last_player.name))
|
||||
self.current_player = self.next_player
|
||||
self.next_player.set_to_default()
|
||||
|
||||
def play_video(self):
|
||||
self.current_player.play_content()
|
||||
print('switch: current_player is {}'.format(self.current_player.name))
|
||||
self.next_player = self.temp_player
|
||||
print('switch: next_player is {}'.format(self.next_player.name))
|
||||
self.last_player.exit()
|
||||
|
||||
def play_video(self):
|
||||
print('{} is about to play'.format(self.current_player.name))
|
||||
self.current_player.play_content()
|
||||
#self.last_player.exit()
|
||||
|
||||
next_context = data_centre.get_next_context()
|
||||
#next_context = '/home/pi/pp_home/media/samplerloop3s.mp4'
|
||||
self.next_player.load_content(next_context)
|
||||
|
||||
self.wait_for_next_cycle()
|
||||
|
||||
|
||||
def wait_for_next_cycle(self):
|
||||
if(self.current_player.is_finished or self.manual_next):
|
||||
|
||||
if(self.current_player.is_finished() or self.manual_next):
|
||||
print('{} is finished'.format(self.current_player.name))
|
||||
self.manual_next = False
|
||||
if self.next_player.is_loaded:
|
||||
if self.next_player.is_loaded():
|
||||
print('{} is loaded on switchover'.format(self.next_player.name))
|
||||
self.switch_players()
|
||||
self.play_video()
|
||||
else:
|
||||
print('{} is not loaded yet!'.format(self.next_player.name))
|
||||
self.current_player.pause_content()
|
||||
self.wait_for_next_load()
|
||||
else:
|
||||
#need to delay here and then
|
||||
time.sleep(1)
|
||||
self.wait_for_next_cycle()
|
||||
self.widget.after(self.delay, self.wait_for_next_cycle)
|
||||
|
||||
def wait_for_next_load(self):
|
||||
if(self.next_player.is_loaded):
|
||||
if(self.next_player.is_loaded()):
|
||||
self.switch_players()
|
||||
self.play_video()
|
||||
else:
|
||||
#need to delay here, and then
|
||||
time.sleep(1)
|
||||
self.widget.after(self.delay, self._status_loop)
|
||||
self.wait_for_next_load()
|
||||
self.widget.after(self.delay, self.wait_for_next_load)
|
||||
|
||||
|
||||
def get_info_for_video_display(self):
|
||||
return self.current_player.bank_number, self.current_player.status, self.next_player.bank_number,\
|
||||
@@ -74,55 +83,56 @@ class video_driver(object):
|
||||
|
||||
|
||||
class video_player(object):
|
||||
def __init__(self):
|
||||
self.is_loaded = False
|
||||
self.is_finished = False
|
||||
def __init__(self, widget, name):
|
||||
self.widget = widget
|
||||
self.name = name
|
||||
self.status = 'UNASSIGNED'
|
||||
self.bank_number = '-'
|
||||
self.duration = 0
|
||||
self.video_length = 10
|
||||
|
||||
self.omx = OMXDriver(self.widget,'')
|
||||
|
||||
def is_loaded(self):
|
||||
return self.omx.start_play_signal
|
||||
|
||||
def is_finished(self):
|
||||
return self.omx.end_play_signal
|
||||
|
||||
def get_fake_duration(self):
|
||||
self.duration = self.duration + 1
|
||||
return self.duration
|
||||
|
||||
def play_content(self):
|
||||
self.status = 'PLAYING'
|
||||
time.sleep(1)
|
||||
self.duration = 1
|
||||
time.sleep(1)
|
||||
self.duration = 2
|
||||
time.sleep(1)
|
||||
self.duration = 3
|
||||
time.sleep(1)
|
||||
self.duration = 4
|
||||
time.sleep(1)
|
||||
self.duration = 5
|
||||
time.sleep(1)
|
||||
self.duration = 6
|
||||
time.sleep(1)
|
||||
self.duration = 7
|
||||
time.sleep(1)
|
||||
self.duration = 8
|
||||
time.sleep(1)
|
||||
self.duration = 9
|
||||
self.is_finished = True
|
||||
pass
|
||||
print('{} is playing now'.format(self.name))
|
||||
self.omx.pause_before_play_required = 'no'
|
||||
self.omx.show(True,0)
|
||||
|
||||
def load_content(self, context):
|
||||
self.status = 'LOADING'
|
||||
time.sleep(3)
|
||||
self.status = 'LOADED'
|
||||
self.is_loaded = True
|
||||
#do the loading...
|
||||
pass
|
||||
print('{} is loading now {}'.format(self.name,context))
|
||||
self.omx.load(context,'after-first-frame','','')
|
||||
|
||||
def set_to_default(self):
|
||||
self.is_finished = False
|
||||
self.is_loaded = False
|
||||
self.omx.kill()
|
||||
self.omx = OMXDriver(self.widget,'')
|
||||
|
||||
def exit(self):
|
||||
pass
|
||||
if(self.omx.omx_loaded is not None):
|
||||
print('{} is exiting omx'.format(self.name))
|
||||
self.omx.stop()
|
||||
self.omx = OMXDriver(self.widget,'')
|
||||
|
||||
def pause_content(self):
|
||||
self.status = 'PAUSED'
|
||||
|
||||
# tk = Tk()
|
||||
#
|
||||
# canvas = Canvas(tk,width=500,height=400, bd=0, highlightthickness=0)
|
||||
# canvas.pack()
|
||||
#
|
||||
# driver = video_driver(canvas)
|
||||
#
|
||||
# while True:
|
||||
# tk.update()
|
||||
|
||||
Reference in New Issue
Block a user