created seperate class for of_capture so they do not compete for access to camera etc

This commit is contained in:
langolierz
2018-10-02 18:05:11 +00:00
parent 6735716482
commit e3d0757a2c
7 changed files with 262 additions and 45 deletions

View File

@@ -9,18 +9,27 @@ from pythonosc import osc_server
from pythonosc import dispatcher from pythonosc import dispatcher
import threading import threading
import argparse import argparse
from video_centre.capture import Capture
from video_centre.of_capture import OfCapture
class Actions(object): class Actions(object):
def __init__(self, tk, message_handler, data, video_driver, capture, shaders, display): def __init__(self, tk, message_handler, data, video_driver, shaders, display, osc_client):
self.tk = tk self.tk = tk
self.message_handler = message_handler self.message_handler = message_handler
self.data = data self.data = data
self.video_driver = video_driver self.video_driver = video_driver
self.capture = capture
self.shaders = shaders self.shaders = shaders
self.display = display self.display = display
self.osc_client = osc_client
self.create_capture_object('value')
self.server = self.setup_osc_server() self.server = self.setup_osc_server()
def create_capture_object(self, value):
if self.data.settings['other']['USE_OF_CAPTURE']['value'] == 'yes':
self.capture = OfCapture(self.tk, self.osc_client, self.message_handler, self.data)
else:
self.capture = Capture(self.tk, self.message_handler, self.data)
self.display.capture = self.capture
def move_browser_selection_down(self): def move_browser_selection_down(self):
self.display.browser_menu.navigate_menu_down() self.display.browser_menu.navigate_menu_down()
@@ -192,6 +201,13 @@ class Actions(object):
if is_successful and self.video_driver.current_player.status != 'PAUSED': if is_successful and self.video_driver.current_player.status != 'PAUSED':
self.video_driver.current_player.toggle_pause() self.video_driver.current_player.toggle_pause()
## these are temp for testing !
def start_of_capture_preview(self):
self.osc_client.send_message("/capture/start", True)
def stop_of_capture_preview(self):
self.osc_client.send_message("/capture/stop", True)
def toggle_capture_recording(self): def toggle_capture_recording(self):
is_recording = self.capture.is_recording is_recording = self.capture.is_recording
if is_recording: if is_recording:

View File

@@ -9,10 +9,10 @@ class Display(object):
ROW_OFFSET = 6.0 ROW_OFFSET = 6.0
TITLE = '================== r_e_c_u_r ==================' TITLE = '================== r_e_c_u_r =================='
def __init__(self, tk, video_driver, capture, shaders, message_handler, data): def __init__(self, tk, video_driver, shaders, message_handler, data):
self.tk = tk self.tk = tk
self.video_driver = video_driver self.video_driver = video_driver
self.capture = capture self.capture = None
self.shaders = shaders self.shaders = shaders
self.message_handler = message_handler self.message_handler = message_handler
self.data = data self.data = data
@@ -198,9 +198,17 @@ class Display(object):
def _get_status_for_player(self): def _get_status_for_player(self):
now_slot, now_status, now_alpha, next_slot, next_status, next_alpha = self.video_driver.get_player_info_for_status() now_slot, now_status, now_alpha, next_slot, next_status, next_alpha = self.video_driver.get_player_info_for_status()
capture_status = self._generate_capture_status() if self.capture is not None:
capture_status = self._generate_capture_status()
preview_alpha = self.capture.get_preview_alpha()
else:
capture_status = ''
preview_alpha = 0
preview_alpha = self.capture.get_preview_alpha()
if preview_alpha == None:
preview_alpha = 0
#print('capture alpha is {}'.format(preview_alpha))
self._set_colour_from_alpha(now_alpha, preview_alpha, next_alpha) self._set_colour_from_alpha(now_alpha, preview_alpha, next_alpha)
@@ -260,7 +268,10 @@ class Display(object):
def _set_colour_from_alpha(self, now_alpha, preview_alpha, next_alpha): def _set_colour_from_alpha(self, now_alpha, preview_alpha, next_alpha):
upper_bound = 150 upper_bound = 150
is_recording = self.capture.is_recording == True if self.capture is not None:
is_recording = self.capture.is_recording == True
else:
is_recording = False
### scale values ### scale values
scaled_now = int(( now_alpha / 255 ) * (255 - upper_bound) + upper_bound) scaled_now = int(( now_alpha / 255 ) * (255 - upper_bound) + upper_bound)
scaled_preview = int(( preview_alpha / 255 ) * (255 - upper_bound) + upper_bound) scaled_preview = int(( preview_alpha / 255 ) * (255 - upper_bound) + upper_bound)

View File

@@ -59,10 +59,10 @@
"DEFAULT": ["load_slot_6_into_next_player","toggle_shaders"] "DEFAULT": ["load_slot_6_into_next_player","toggle_shaders"]
}, },
"q": { "q": {
"DEFAULT": ["load_slot_7_into_next_player", "increase_speed"] "DEFAULT": ["load_slot_7_into_next_player", "start_of_capture_preview"]
}, },
"r": { "r": {
"DEFAULT": ["load_slot_8_into_next_player", "decrease_speed"] "DEFAULT": ["load_slot_8_into_next_player", "stop_of_capture_preview"]
}, },
"s": { "s": {
"DEFAULT": ["load_slot_9_into_next_player","quit_the_program"] "DEFAULT": ["load_slot_9_into_next_player","quit_the_program"]

View File

@@ -131,6 +131,14 @@
], ],
"value": "dev" "value": "dev"
}, },
"USE_OF_CAPTURE": {
"action": "create_capture_object",
"options": [
"yes",
"no"
],
"value": "no"
},
"VIDEO_BACKEND": { "VIDEO_BACKEND": {
"action": "switch_video_backend", "action": "switch_video_backend",
"options": [ "options": [

View File

@@ -15,7 +15,7 @@ from user_input.numpad_input import NumpadInput
from user_input.midi_input import MidiInput from user_input.midi_input import MidiInput
from user_input.analog_input import AnalogInput from user_input.analog_input import AnalogInput
from video_centre.video_driver import VideoDriver from video_centre.video_driver import VideoDriver
from video_centre.capture import Capture #from video_centre.capture import Capture
from video_centre.shaders import Shaders from video_centre.shaders import Shaders
import data_centre import data_centre
@@ -43,14 +43,14 @@ def setup_osc_client():
osc_client = setup_osc_client() osc_client = setup_osc_client()
# setup the video driver # setup the video driver
video_driver = VideoDriver(tk, osc_client, message_handler, data) video_driver = VideoDriver(tk, osc_client, message_handler, data)
capture = Capture(tk, osc_client, message_handler, data) #capture = Capture(tk, osc_client, message_handler, data)
shaders = Shaders(tk, osc_client, message_handler, data) shaders = Shaders(tk, osc_client, message_handler, data)
# setup the display # setup the display
display = Display(tk, video_driver, capture, shaders, message_handler, data) display = Display(tk, video_driver, shaders, message_handler, data)
# setup the actions # setup the actions
actions = Actions(tk, message_handler, data, video_driver, capture, shaders, display) actions = Actions(tk, message_handler, data, video_driver, shaders, display, osc_client)
numpad_input = NumpadInput(tk, message_handler, display, actions, data) numpad_input = NumpadInput(tk, message_handler, display, actions, data)
midi_input = MidiInput(tk, message_handler, display, actions, data) midi_input = MidiInput(tk, message_handler, display, actions, data)

View File

@@ -7,9 +7,8 @@ import fractions
class Capture(object): class Capture(object):
PREVIEW_LAYER = 255 PREVIEW_LAYER = 255
def __init__(self, root, osc_client, message_handler, data): def __init__(self, root, message_handler, data):
self.root = root self.root = root
self.osc_client = osc_client
self.message_handler = message_handler self.message_handler = message_handler
self.data = data self.data = data
@@ -57,14 +56,19 @@ class Capture(object):
if self.use_capture == False: if self.use_capture == False:
self.message_handler.set_message('INFO', 'capture not enabled') self.message_handler.set_message('INFO', 'capture not enabled')
return False return False
if not self.device or self.device.closed: if self.data.settings['other']['USE_OF_CAPTURE']['value'] == 'yes':
self.create_capture_device() self.osc_client.send_message("/capture/start", True)
self.is_previewing = True self.is_previewing = True
self.device.start_preview() return True
self.set_preview_screen_size() else:
self.set_capture_settings() if not self.device or self.device.closed:
self.device.preview.layer = self.PREVIEW_LAYER self.create_capture_device()
return True self.is_previewing = True
self.device.start_preview()
self.set_preview_screen_size()
self.set_capture_settings()
self.device.preview.layer = self.PREVIEW_LAYER
return True
def set_capture_settings(self): def set_capture_settings(self):
if self.capture_type == "piCaptureSd1": if self.capture_type == "piCaptureSd1":
@@ -84,10 +88,14 @@ class Capture(object):
self.device.preview.fullscreen = True self.device.preview.fullscreen = True
def stop_preview(self): def stop_preview(self):
self.device.stop_preview() if self.data.settings['other']['USE_OF_CAPTURE']['value'] == 'yes':
self.is_previewing = False self.osc_client.send_message("/capture/stop", True)
if not self.device.recording: self.is_previewing = False
self.device.close() else:
self.device.stop_preview()
self.is_previewing = False
if not self.device.recording:
self.device.close()
def start_recording(self): def start_recording(self):
if self.use_capture == False: if self.use_capture == False:
@@ -95,7 +103,7 @@ class Capture(object):
return return
if not self.check_available_disk_space(): if not self.check_available_disk_space():
return return
if self.device.closed: if self.device is None or self.device.closed:
self.create_capture_device() self.create_capture_device()
if not os.path.exists(self.video_dir): if not os.path.exists(self.video_dir):
@@ -185,22 +193,10 @@ class Capture(object):
error_info = e.message error_info = e.message
else: else:
error_info = e error_info = e
self.message_handler.set_message('ERROR',error_info) self.message_handler.set_message('ERROR',error_info)
else: return 0
return 0 return 0
#def is_previewing(self):
# if self.device.closed or not self.device.preview:
# return False
#else:
# return True
#def is_recording(self):
# if self.device.recording:
# return True
#else:
# return False
def set_colour(self, u_value, v_value): def set_colour(self, u_value, v_value):
(u, v) = (128, 128) (u, v) = (128, 128)
if self.device.color_effects is not None: if self.device.color_effects is not None:
@@ -235,6 +231,3 @@ class Capture(object):

189
video_centre/of_capture.py Normal file
View File

@@ -0,0 +1,189 @@
import os
import subprocess
import datetime
import fractions
class OfCapture(object):
def __init__(self, root, osc_client, message_handler, data):
self.root = root
self.osc_client = osc_client
self.message_handler = message_handler
self.data = data
self.device = None
self.is_recording = False
self.is_previewing = False
self.video_dir = '/home/pi/Videos/'
self.update_capture_settings()
#self.create_capture_device()
#def create_capture_device(self):
# if self.use_capture:
# self.update_capture_settings()
# try:
# self.device = picamera.PiCamera(resolution=self.resolution, framerate=self.framerate, sensor_mode = self.sensor_mode)
# except picamera.exc.PiCameraError as e:
# self.use_capture = False
# print('camera exception is {}'.format(e))
# self.message_handler.set_message('INFO', 'no capture device attached')
def update_capture_settings(self):
##setting class variables
self.use_capture = self.data.settings['capture']['DEVICE']['value'] == 'enabled'
self.resolution = self.convert_resolution_value(self.data.settings['capture']['RESOLUTION']['value'])
self.framerate = self.convert_framerate_value(self.data.settings['capture']['FRAMERATE']['value'])
self.capture_type = self.data.settings['capture']['TYPE']['value']
if self.capture_type == "piCaptureSd1":
self.sensor_mode = 6
else:
self.sensor_mode = 0
##update current instance (device) if in use
if self.device and not self.device.closed:
self.device.image_effect = self.data.settings['capture']['IMAGE_EFFECT']['value']
self.device.shutter_speed = self.convert_shutter_value(self.data.settings['capture']['SHUTTER']['value'])
## can only update resolution and framerate if not recording
if not self.is_recording:
self.device.framerate = self.framerate
self.device.resolution = self.resolution
def start_preview(self):
if self.use_capture == False:
self.message_handler.set_message('INFO', 'capture not enabled')
return False
self.is_previewing = True
self.set_capture_settings()
self.osc_client.send_message("/capture/preview/start", True)
return True
def set_capture_settings(self):
if self.capture_type == "piCaptureSd1":
pass
#self.device.sensor_mode = 6
#self.device.awb_mode = "off"
#self.device.awb_gains = 1.0
#self.device.exposure_mode = "off"
else:
pass
#self.sensor_mode = 0
def stop_preview(self):
self.osc_client.send_message("/capture/preview/stop", True)
self.is_previewing = False
def start_recording(self):
if self.use_capture == False:
self.message_handler.set_message('INFO', 'capture not enabled')
return
if not self.check_available_disk_space():
return
if not os.path.exists(self.video_dir):
os.makedirs(self.video_dir)
self.is_recording = True
#self.device.start_recording(self.video_dir + '/raw.h264')
self.osc_client.send_message("/capture/record/start", True)
self.monitor_disk_space()
def monitor_disk_space(self):
if self.is_recording:
if self.check_available_disk_space():
self.root.after(10000, self.monitor_disk_space)
else:
self.stop_recording()
def check_available_disk_space(self):
mb_free = self.data._get_mb_free_diskspace(self.video_dir)
if mb_free < 10:
self.message_handler.set_message('INFO', 'insufficient space on disk')
return False
else:
return True
def stop_recording(self):
#self.device.stop_recording()
self.osc_client.send_message("/capture/record/stop", True)
#set status to saving
mp4box_process, recording_name = self.convert_raw_recording()
self.is_recording = 'saving'
self.root.after(0, self.wait_for_recording_to_save, mp4box_process, recording_name)
self.update_capture_settings()
# return path to the video
if not self.device.preview:
self.device.close()
def convert_raw_recording(self):
recording_path , recording_name = self.generate_recording_path()
try:
if self.sensor_mode == 6:
mp4box_process = subprocess.Popen(['MP4Box', '-fps', '60', '-add', self.video_dir + '/raw.h264', recording_path])
return mp4box_process , recording_name
else:
mp4box_process = subprocess.Popen(['MP4Box', '-add', self.video_dir + '/raw.h264', recording_path])
return mp4box_process , recording_name
except Exception as e:
print(e)
if hasattr(e, 'message'):
error_info = e.message
else:
error_info = e
self.message_handler.set_message('ERROR',error_info)
def wait_for_recording_to_save(self, process, name):
print('the poll is {}'.format(process.poll()))
if process.poll() is not None:
self.is_recording = False
os.remove(self.video_dir + '/raw.h264')
self.data.create_new_slot_mapping_in_first_open(name)
else:
self.root.after(300, self.wait_for_recording_to_save, process, name)
def generate_recording_path(self):
rec_dir = self.video_dir + '/recordings'
if not os.path.exists(rec_dir):
os.makedirs(rec_dir)
date = datetime.datetime.now().strftime("%Y-%m-%d")
i = 0
while os.path.exists('{}/rec-{}-{}.mp4'.format(rec_dir,date, i)):
i += 1
name = 'rec-{}-{}.mp4'.format(date, i)
return '{}/{}'.format(rec_dir,name), name
def get_recording_time(self):
pass
#if not self.device or not self.device.recording or self.device.frame.timestamp == None:
# return -1
#else:
# return self.device.frame.timestamp / 1000000
def get_preview_alpha(self):
return 0
def set_colour(self, u_value, v_value):
pass
def set_alpha(self, amount):
pass
@staticmethod
def convert_resolution_value(setting_value):
split_values = setting_value.split('x')
return (int(split_values[0]), int(split_values[1]))
@staticmethod
def convert_framerate_value(setting_value):
return fractions.Fraction(setting_value).limit_denominator()
def convert_shutter_value(self, setting_value):
if setting_value == 'auto':
return 0
elif setting_value == 'max':
return int(1000000 / self.framerate)
else:
return int(fractions.Fraction(setting_value) * 1000000)