Worker process adapted to new state machine

This commit is contained in:
Balthasar Reuter
2018-07-16 23:19:41 +02:00
parent 5b3934016e
commit bd358030cd
8 changed files with 69 additions and 35 deletions

View File

@@ -65,7 +65,7 @@ class PictureList:
# Print initial infos # Print initial infos
logging.info('Number of last existing file: %d', self.counter) logging.info('Number of last existing file: %d', self.counter)
logging.info('Saving assembled pictures as "%s%s.%s"', self.basename, logging.info('Saving pictures as "%s%s.%s"', self.basename,
self.count_width * 'X', 'jpg') self.count_width * 'X', 'jpg')
def getFilename(self, count): def getFilename(self, count):

View File

@@ -56,8 +56,10 @@ class Context:
elif isinstance(event, TeardownEvent): elif isinstance(event, TeardownEvent):
self.state = TeardownState(event.target) self.state = TeardownState(event.target)
if event.target == TeardownEvent.EXIT: if event.target == TeardownEvent.EXIT:
self._comm.bcast(None)
return 0 return 0
elif event.target == TeardownEvent.RESTART: elif event.target == TeardownEvent.RESTART:
self._comm.bcast(None)
return 123 return 123
else: else:
self.state.handleEvent(event, self) self.state.handleEvent(event, self)

View File

@@ -19,12 +19,11 @@
import logging import logging
import os.path import os.path
import sys
from time import localtime, strftime from time import localtime, strftime
from .PictureList import PictureList from .PictureList import PictureList
from .StateMachine import TeardownEvent, TeardownState from . import StateMachine
from .Threading import Workers from .Threading import Workers
@@ -34,32 +33,25 @@ class WorkerTask:
assert not kwargs assert not kwargs
def get(self, picture): def do(self, picture):
raise NotImplementedError() raise NotImplementedError()
class PictureSaver(WorkerTask): class PictureSaver(WorkerTask):
def __init__(self, config): def __init__(self, basename):
super().__init__() super().__init__()
path = os.path.join(config.get('Picture', 'basedir'),
config.get('Picture', 'basename'))
basename = strftime(path, localtime())
self._pic_list = PictureList(basename) self._pic_list = PictureList(basename)
@staticmethod def do(self, picture):
def do(picture, filename):
filename = self._pic_list.getNext()
logging.info('Saving picture as %s', filename) logging.info('Saving picture as %s', filename)
picture.save(filename, 'JPEG') picture.save(filename, 'JPEG')
def get(self, picture):
return (self.do, (picture, self._pic_list.getNext()))
class Worker: class Worker:
@@ -67,19 +59,58 @@ class Worker:
self._comm = comm self._comm = comm
self.initPostprocessTasks(config)
self.initPictureTasks(config)
def initPostprocessTasks(self, config):
self._postprocess_tasks = []
# PictureSaver for assembled pictures
path = os.path.join(config.get('Picture', 'basedir'),
config.get('Picture', 'basename'))
basename = strftime(path, localtime())
self._postprocess_tasks.append(PictureSaver(basename))
def initPictureTasks(self, config):
self._picture_tasks = []
# PictureSaver for single shots
path = os.path.join(config.get('Picture', 'basedir'),
config.get('Picture', 'basename') + '_shot_')
basename = strftime(path, localtime())
self._picture_tasks.append(PictureSaver(basename))
def run(self): def run(self):
for state in self._comm.iter(Workers.WORKER): for state in self._comm.iter(Workers.WORKER):
self.handleState(state) self.handleState(state)
return True
def handleState(self, state): def handleState(self, state):
if isinstance(state, TeardownState): if isinstance(state, StateMachine.TeardownState):
self.teardown(state) self.teardown(state)
elif isinstance(state, StateMachine.ReviewState):
self.doPostprocessTasks(state.picture)
elif isinstance(state, StateMachine.CameraEvent):
if state.name == 'capture':
self.doPictureTasks(state.picture)
else:
raise ValueError('Unknown CameraEvent "{}"'.format(state))
def teardown(self, state): def teardown(self, state):
if state.target == TeardownEvent.EXIT: pass
sys.exit(0)
elif state.target == TeardownEvent.RESTART: def doPostprocessTasks(self, picture):
sys.exit(123)
for task in self._postprocess_tasks:
task.do(picture)
def doPictureTasks(self, picture):
for task in self._picture_tasks:
task.do(picture)

View File

@@ -18,7 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging import logging
import sys
from PIL import Image, ImageOps from PIL import Image, ImageOps
@@ -51,8 +50,7 @@ class Camera:
self._pic_dims = None self._pic_dims = None
self._is_preview = self._cfg.getBool('Photobooth', 'show_preview') self._is_preview = self._cfg.getBool('Photobooth', 'show_preview')
self._is_keep_pictures = self._cfg.getBool('Photobooth', self._is_keep_pictures = self._cfg.getBool('Picture', 'keep_pictures')
'keep_pictures')
def startup(self): def startup(self):
@@ -72,16 +70,14 @@ class Camera:
if self._cap is not None: if self._cap is not None:
self._cap.cleanup() self._cap.cleanup()
if state.target == StateMachine.TeardownEvent.EXIT:
sys.exit(0)
elif state.target == StateMachine.TeardownEvent.RESTART:
sys.exit(123)
def run(self): def run(self):
for state in self._comm.iter(Workers.CAMERA): for state in self._comm.iter(Workers.CAMERA):
self.handleState(state) self.handleState(state)
return True
def handleState(self, state): def handleState(self, state):
if isinstance(state, StateMachine.StartupState): if isinstance(state, StateMachine.StartupState):

View File

@@ -50,8 +50,6 @@ countdown_time = 8
display_time = 5 display_time = 5
# Timeout for postprocessing (shown after review) # Timeout for postprocessing (shown after review)
postprocess_time = 60 postprocess_time = 60
# Keep single pictures (True/False)
keep_pictures = False
[Picture] [Picture]
# Basedir of output pictures # Basedir of output pictures
@@ -70,3 +68,5 @@ size_y = 2362
min_dist_x = 20 min_dist_x = 20
# Minimum distance between thumbnails in vertical direction # Minimum distance between thumbnails in vertical direction
min_dist_y = 20 min_dist_y = 20
# Keep single pictures (True/False)
keep_pictures = False

View File

@@ -651,6 +651,10 @@ class Settings(QtWidgets.QFrame):
self.add('Picture', 'basedir', basedir) self.add('Picture', 'basedir', basedir)
self.add('Picture', 'basename', basename) self.add('Picture', 'basename', basename)
keep_pictures = QtWidgets.QCheckBox()
keep_pictures.setChecked(self._cfg.getBool('Picture', 'keep_pictures'))
self.add('Picture', 'keep_pictures', keep_pictures)
lay_num = QtWidgets.QHBoxLayout() lay_num = QtWidgets.QHBoxLayout()
lay_num.addWidget(num_x) lay_num.addWidget(num_x)
lay_num.addWidget(QtWidgets.QLabel('x')) lay_num.addWidget(QtWidgets.QLabel('x'))
@@ -688,6 +692,7 @@ class Settings(QtWidgets.QFrame):
lay_file) lay_file)
layout.addRow('Basename of files (strftime possible):', layout.addRow('Basename of files (strftime possible):',
basename) basename)
layout.addRow('Keep single shots:', keep_pictures)
widget = QtWidgets.QWidget() widget = QtWidgets.QWidget()
widget.setLayout(layout) widget.setLayout(layout)
@@ -808,6 +813,8 @@ class Settings(QtWidgets.QFrame):
self.get('Picture', 'basedir').text()) self.get('Picture', 'basedir').text())
self._cfg.set('Picture', 'basename', self._cfg.set('Picture', 'basename',
self.get('Picture', 'basename').text()) self.get('Picture', 'basename').text())
self._cfg.set('Picture', 'keep_pictures',
str(self.get('Picture', 'keep_pictures').isChecked()))
self._cfg.set('Gpio', 'enable', self._cfg.set('Gpio', 'enable',
str(self.get('Gpio', 'enable').isChecked())) str(self.get('Gpio', 'enable').isChecked()))

View File

@@ -128,11 +128,7 @@ class PyQt5Gui(GuiSkeleton):
def teardown(self, state): def teardown(self, state):
if state.target == TeardownEvent.EXIT: if state.target == TeardownEvent.WELCOME:
self._app.exit(0)
elif state.target == TeardownEvent.RESTART:
self._app.exit(123)
elif state.target == TeardownEvent.WELCOME:
self._comm.send(Workers.MASTER, GuiEvent('welcome')) self._comm.send(Workers.MASTER, GuiEvent('welcome'))
def showError(self, state): def showError(self, state):

View File

@@ -54,7 +54,8 @@ class CameraProcess(mp.Process):
while True: while True:
try: try:
cap.run() if cap.run():
break
except Exception as e: except Exception as e:
self._comm.send(Workers.MASTER, ErrorEvent(e)) self._comm.send(Workers.MASTER, ErrorEvent(e))
@@ -73,7 +74,8 @@ class WorkerProcess(mp.Process):
while True: while True:
try: try:
Worker(self.cfg, self.comm).run() if Worker(self.cfg, self.comm).run():
break
except Exception as e: except Exception as e:
self._comm.send(Workers.MASTER, ErrorEvent(e)) self._comm.send(Workers.MASTER, ErrorEvent(e))