Commit 90227f52 authored by Antoine Lima's avatar Antoine Lima

PiCam replay

parent 35fca230
[codestyle]
indentation = True
[main]
version = 0.1.0
[encoding]
text_encoding = utf-8
[main]
version = 0.1.0
[vcs]
use_version_control = False
version_control_system =
[main]
version = 0.1.0
[workspace]
restore_data_on_startup = True
save_data_on_exit = True
save_history = True
save_non_project_files = False
[main]
version = 0.1.0
recent_files = ['/home/antoine/prog/PR/source-rasp/main.py', '/home/antoine/prog/PR/source-rasp/modules/game.py', '/home/antoine/prog/PR/content/settings.json', '/home/antoine/prog/PR/source-rasp/replay.py', '/home/antoine/prog/PR/source-rasp/com.py']
......@@ -7,33 +7,32 @@ Created on Wed Apr 18 18:34:40 2018
"""
import logging
import autopy
import serial
from os.path import dirname, abspath, join, isfile as exists
from autopy.key import tap as PressKey, Code as KeyCode
from os.path import isfile as exists
from autopy.key import tap as PressKey, Code as KeyCode
from threading import Thread
from player import Side
class InputThread(Thread):
keyButtonBindings = [KeyCode.ESCAPE, KeyCode.UP_ARROW, KeyCode.LEFT_ARROW, KeyCode.RIGHT_ARROW, KeyCode.DOWN_ARROW, KeyCode.RETURN]
def __init__(self, dispatcher, side):
Thread.__init__(self)
self.side = side
self.dispatcher = dispatcher
self.continueRunning = True
self.path = '/dev/ttyUSB0' if self.side==Side.Left else '/dev/ttyUSB1'
if exists(self.path):
self.arduino = serial.Serial(self.path, 9600, timeout=1)
else:
raise RuntimeError('No arduino connected on the {} side'.format(self.side.name.lower()))
def run(self):
while self.arduino.isOpen():
msg = self.arduino.readline()[:-1]
if msg:
parsedMessage = self.parseMsg(msg)
if 'butn' in parsedMessage:
......@@ -46,14 +45,14 @@ class InputThread(Thread):
def stop(self):
self.continueRunning = False
self.arduino.close()
def sendKeyStroke(self, msg):
if 'butn' in msg:
button = int(msg['butn'])
print({button: ['ESCAPE', 'UP_ARROW', 'LEFT_ARROW', 'RIGHT_ARROW', 'DOWN_ARROW', 'RETURN'][button]})
key = InputThread.keyButtonBindings[button]
PressKey(key, [])
def parseMsg(self, msg):
parts = msg.split(':')
return {parts[0]: parts[1], 'source': self.side}
......@@ -18,6 +18,7 @@ from PyQt5.QtMultimediaWidgets import QVideoWidget
from player import Side, PlayerGuest
from replay import Replay
from module import Module
from settings import Settings
import modules
from ui.game_ui import Ui_Form as GameWidget
......@@ -25,25 +26,25 @@ class GameOverChecker():
def __init__(self, conditionType, limit):
self.conditionType = conditionType
self.limit = limit
def check(self, time, scores):
'''
Checks if a game is over and return the winner if that's the case
Returns the winning side or Side.Undef otherwise
Takes the game time is seconds and a list containing the two scores
'''
# Gets the index of the highest scoring player
# Gets the index of the highest scoring player
bestPlayer = max(scores, key=scores.get)
if self.conditionType=='score' and scores[bestPlayer]>=self.limit:
return bestPlayer
elif self.conditionType=='time' and time>self.limit:
return bestPlayer
else:
return Side.Undef
class GameModule(Module):
def __init__(self, parent=None):
super().__init__(parent, GameWidget())
......@@ -55,19 +56,20 @@ class GameModule(Module):
# Button connections
self.ui.btnScore1.clicked.connect(lambda: self.goal(Side.Left))
self.ui.btnScore2.clicked.connect(lambda: self.goal(Side.Right))
self.replayer = Replay()
self.replayer = Replay(Side.Left)
def load(self):
logging.debug('Loading GameModule')
self.gameStartTime = QTime.currentTime()
self.timerUpdateChrono.start(1000)
self.ui.lcdChrono.display(QTime(0,0).toString("hh:mm:ss"))
self.showingReplay = False
self.replayer.start_recording()
self.gameoverChecker = GameOverChecker('score', 10)
if all([len(val)==0 for val in self.players.values()]):
self.players[Side.Left ].append(PlayerGuest)
self.players[Side.Right].append(PlayerGuest)
......@@ -79,17 +81,18 @@ class GameModule(Module):
logging.debug('Unloading GameModule')
del self.gameStartTime
self.timerUpdateChrono.stop()
self.replayer.stop_recording()
def other(self, **kwargs):
logging.debug('Other GameModule')
for key, val in kwargs.items():
if key=='goal' and 'source' in kwargs:
self.goal(kwargs['source'])
elif key=='players':
self.players = val
def resizeEvent(self, event):
# 40% of the window width to have (5% margin)-(40% circle)-(10% middle)-(40% circle)-(5% margin)
btnDiameter = self.mainwin.width()*0.4
......@@ -98,7 +101,7 @@ class GameModule(Module):
self.ui.btnScore2.setMinimumSize(btnDiameter, btnDiameter)
self.ui.btnScore1.setMask(region)
self.ui.btnScore2.setMask(region)
QtWidgets.QWidget.resizeEvent(self, event)
def keyPressEvent(self, e):
......@@ -112,54 +115,54 @@ class GameModule(Module):
def updateChrono(self):
# Updated each second
self.ui.lcdChrono.display(QTime(0,0).addSecs(self.getGameTime()).toString("hh:mm:ss"))
# Don't check scores while showing a replay to avoid closing the engame screen too soon
# Don't check scores while showing a replay to avoid closing the engame screen too soon
if not self.showingReplay:
self.checkEndGame()
def getGameTime(self):
return self.gameStartTime.secsTo(QTime.currentTime())
def updateScores(self):
self.ui.btnScore1.setText(str(self.scores[Side.Left]))
self.ui.btnScore2.setText(str(self.scores[Side.Right]))
self.checkEndGame()
def goal(self, side):
if side not in Side:
logging.error('Wrong goal side: {}'.format(side))
else:
self.scores[side] += 1
# Show replay
# May require `sudo apt-get install qtmultimedia5-examples` in order to install the right libraries
replayFile = self.mainwin.getContent('Replay {}.mp4'.format(side.name))
if os.path.exists(replayFile):
if True: # Debug Mode
self.updateScores()
else:
self.showingReplay = True
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.player.stateChanged.connect(self.endOfReplay)
self.player.setMuted(True)
self.player.setVideoOutput(self.ui.videoWidget)
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile)))
self.player.play()
self.ui.videoWidget.setFullScreen(True)
replayFile = self.replayer.stop_recording()
if not (Settings['replay.show'] and os.path.exists(replayFile)):
self.updateScores()
else:
self.showingReplay = True
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.player.stateChanged.connect(self.endOfReplay)
self.player.setMuted(True)
self.player.setVideoOutput(self.ui.videoWidget)
self.player.setMedia(QMediaContent(QUrl.fromLocalFile(replayFile)))
self.player.play()
self.ui.videoWidget.setFullScreen(True)
def endOfReplay(self, status):
if status!=QMediaPlayer.PlayingState:
self.ui.videoWidget.setFullScreen(False);
self.showingReplay = False
self.updateScores()
def handleCancel(self):
self.switchModule(modules.MenuModule)
def checkEndGame(self):
winSide = self.gameoverChecker.check(self.getGameTime(), self.scores)
if winSide!=Side.Undef:
self.send(modules.EndGameModule, players=self.players, winSide=winSide, scores=self.scores, time=self.getGameTime())
self.switchModule(modules.EndGameModule)
......@@ -7,6 +7,10 @@ Created on Wed Apr 18 18:34:40 2018
"""
import os
from threading import Event
from multiprocessing import Process, Lock
from main import MainWin
from settings import Settings
onRasp = os.uname()[1] == 'raspberrypi'
......@@ -15,8 +19,17 @@ if onRasp:
import picamera
class LockableValue():
def __init__(self, value):
self.value = value
self.mutex = Lock()
class Replay():
def __init__(self):
def __init__(self, side):
self.recording = LockableValue(False)
self.replayPath = MainWin.getContent('Replay {}.mp4'.format(side.name))
self.stopped = Event()
if onRasp:
self.cam = picamera.PiCamera()
self.cam.resolution = Settings['picam.resolution']
......@@ -24,23 +37,36 @@ class Replay():
self.cam.hflip = Settings['picam.hflip']
self.cam.vflip = Settings['picam.vflip']
self.format = Settings['picam.format']
self.continue_recording = False
self.stream = picamera.PiCameraCircularIO(self.cam, seconds=Settings['replay.duration'])
def start_recording(self):
if not onRasp:
self.stopped.set()
else:
self.recording.value = True
self.stopped.clear()
self.capture_process = Process(target=self.__capture)
self.capture_process.start()
def stop_recording(self):
self.recording.val = True
self.stopped.wait(timeout=2.0)
return self.replayPath
def capture(self, fileToSave):
if onRasp:
self.cam.start_recording(self.stream, self.format)
self.continue_recording = True
try:
while self.continue_recording:
recording = self.recording.val
while recording:
self.cam.wait_recording(1)
recording = self.recording.val
finally:
self.cam.stop_recording()
self.stream.copy_to(fileToSave)
self.stopped.set()
self.stream.copy_to(self.replayPath)
self.cam.close()
self.stream.close()
def stop():
self.continue_recording = False
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment