Implemented video playback for questions

This commit is contained in:
Sebastian Lohff 2014-12-17 01:36:14 +01:00
parent d7a2d8c56a
commit 09466d83a8
4 changed files with 76 additions and 8 deletions

View File

@ -40,6 +40,7 @@ five questions. A question can have the following keys:
- Answer (to remind you of the answer, not used in the program) - Answer (to remind you of the answer, not used in the program)
- Type (type of question) - Type (type of question)
- Double-Jeopardy (if the question is a Double-Jeopardy, default false) - Double-Jeopardy (if the question is a Double-Jeopardy, default false)
- Audio (for videos, if the video should have audio or not, default false)
Four *Types* of question are supported: Four *Types* of question are supported:
@ -48,6 +49,7 @@ Four *Types* of question are supported:
four spaces four spaces
- Image: The Question key is a path to an image, which is displayed on screen - Image: The Question key is a path to an image, which is displayed on screen
- Music: The Question key is a path to a music file, which is played - Music: The Question key is a path to a music file, which is played
- Video: The Question key is a path to a video file, which is played
Gamestate Gamestate

View File

@ -10,8 +10,8 @@ class QuestionException(Exception):
class Questions(object): class Questions(object):
""" Object holding all the questions """ """ Object holding all the questions """
QUESTION_TYPES = ["Text", "Image", "Music", "Code"] QUESTION_TYPES = ["Text", "Image", "Music", "Code", "Video"]
QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy"] QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy", "Audio"]
def __init__(self, qfile): def __init__(self, qfile):
self.qfile = qfile self.qfile = qfile
@ -72,18 +72,24 @@ class Questions(object):
if key not in self.QUESTION_KEYS: if key not in self.QUESTION_KEYS:
raise QuestionException("Qestion %d from section %d (%s) has invalid keyword '%s'" % (j, i, sec["Section"], key)) raise QuestionException("Qestion %d from section %d (%s) has invalid keyword '%s'" % (j, i, sec["Section"], key))
# check Double-Jeopardy is a bool and is set to false it non-existant # check Double-Jeopardy is a bool and is set to false if non-existant
if "Double-Jeopardy" not in q.keys(): if "Double-Jeopardy" not in q.keys():
q["Double-Jeopardy"] = False q["Double-Jeopardy"] = False
elif type(q["Double-Jeopardy"]) != bool: elif type(q["Double-Jeopardy"]) != bool:
raise QuestionException("The Double-Jeopardy key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"])) raise QuestionException("The Double-Jeopardy key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"]))
# check Audio is a bool and is set to false if non-existant
if "Audio" not in q.keys():
q["Audio"] = False
elif type(q["Audio"]) != bool:
raise QuestionException("The Audio key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"]))
# check for broken question types # check for broken question types
if q["Type"] not in self.QUESTION_TYPES: if q["Type"] not in self.QUESTION_TYPES:
raise QuestionException("Question %d from Section %d (%s) has an invalid type '%s' (valid types are %s)" % (j, i, sec["Section"], q["Type"], ", ".join(self.QUESTION_TYPES))) raise QuestionException("Question %d from Section %d (%s) has an invalid type '%s' (valid types are %s)" % (j, i, sec["Section"], q["Type"], ", ".join(self.QUESTION_TYPES)))
# check if file for music/image questions exist # check if file for music/image questions exist
if q["Type"] in ("Music", "Image"): if q["Type"] in ("Music", "Image", "Video"):
if not os.path.isfile(q["Question"]): if not os.path.isfile(q["Question"]):
raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"])) raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"]))

42
video.py Normal file
View File

@ -0,0 +1,42 @@
from __future__ import print_function
from PySide import phonon
class VideoPlayer(object):
def __init__(self, video, audio=False):
self._videoFile = video
self._audio = audio
self._widget = None
self._media_obj = phonon.Phonon.MediaObject()
self._media_src = phonon.Phonon.MediaSource(self._videoFile)
self._audio_out = None
# setup media object
self._media_obj.setCurrentSource(self._media_src)
# make media object loop
self._media_obj.finished.connect(lambda: self._media_obj.play())
if self._audio:
self._audio_out = phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory)
phonon.Phonon.createPath(self._media_obj, self._audio_out)
def get_widget(self):
if self._widget == None:
self._widget = phonon.Phonon.VideoWidget()
self._widget.setScaleMode(phonon.Phonon.VideoWidget.ScaleAndCrop)
phonon.Phonon.createPath(self._media_obj, self._widget)
return self._widget
def play(self):
self._media_obj.play()
def pause(self):
self._media_obj.pause()
def stop(self):
self._media_obj.stop()

View File

@ -4,6 +4,7 @@ import copy
from gamestate import QuestionAnswers from gamestate import QuestionAnswers
from music import MusicBox from music import MusicBox
from video import VideoPlayer
from player import Player, ButtonEvent, nobodyColor from player import Player, ButtonEvent, nobodyColor
class QuestionWindow(QtGui.QDialog): class QuestionWindow(QtGui.QDialog):
@ -20,6 +21,7 @@ class QuestionWindow(QtGui.QDialog):
self.dj = dj self.dj = dj
self._windowSetup = False self._windowSetup = False
self._videoPlayer = None
if answers is not None: if answers is not None:
self.answers = answers self.answers = answers
@ -27,7 +29,7 @@ class QuestionWindow(QtGui.QDialog):
self.answers = QuestionAnswers(self.section, self.qnumber) self.answers = QuestionAnswers(self.section, self.qnumber)
if not self.answers.is_answered(): if not self.answers.is_answered():
if self.question["Type"] != "Music": if not self._question_has_audio():
MusicBox.play_music("questionSong") MusicBox.play_music("questionSong")
if self.dj: if self.dj:
@ -43,6 +45,8 @@ class QuestionWindow(QtGui.QDialog):
tag = "%s-%s" % (self.section, self.qnumber) tag = "%s-%s" % (self.section, self.qnumber)
MusicBox.add_music(tag, self.question["Question"]) MusicBox.add_music(tag, self.question["Question"])
MusicBox.play_music(tag) MusicBox.play_music(tag)
elif self.question["Type"] == "Video":
self._videoPlayer.play()
def get_answers(self): def get_answers(self):
return self.answers return self.answers
@ -51,6 +55,8 @@ class QuestionWindow(QtGui.QDialog):
if not self._inWindow: if not self._inWindow:
self.buzzersOpen.emit(False) self.buzzersOpen.emit(False)
MusicBox.stop_music() MusicBox.stop_music()
if self._videoPlayer:
self._videoPlayer.stop()
event.accept() event.accept()
else: else:
event.ignore() event.ignore()
@ -74,6 +80,7 @@ class QuestionWindow(QtGui.QDialog):
self.layout.addStretch() self.layout.addStretch()
qlabel = None qlabel = None
stretch = 0
if self.question["Type"] == "Text": if self.question["Type"] == "Text":
qlabel = self._mkQuestionLabel(self.question["Question"]) qlabel = self._mkQuestionLabel(self.question["Question"])
elif self.question["Type"] == "Music": elif self.question["Type"] == "Music":
@ -92,10 +99,15 @@ class QuestionWindow(QtGui.QDialog):
code = map(lambda x: x + ((maxLineLen-len(x))*" "), code) code = map(lambda x: x + ((maxLineLen-len(x))*" "), code)
qlabel = self._mkQuestionLabel("<pre>"+"\n".join(code)+"</pre>", monospaced=True) qlabel = self._mkQuestionLabel("<pre>"+"\n".join(code)+"</pre>", monospaced=True)
elif self.question["Type"] == "Video":
self._videoPlayer = VideoPlayer(self.question["Question"], self.question["Audio"])
qlabel = self._videoPlayer.get_widget()
stretch = 1
else: else:
raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"])) raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"]))
self.layout.addWidget(qlabel) self.layout.addWidget(qlabel, stretch=stretch)
self.layout.addStretch() self.layout.addStretch()
self.setLayout(self.layout) self.setLayout(self.layout)
@ -106,6 +118,8 @@ class QuestionWindow(QtGui.QDialog):
done = False done = False
if self.question["Type"] == "Music": if self.question["Type"] == "Music":
MusicBox.stop_music() MusicBox.stop_music()
elif self.question["Type"] == "Video":
self._videoPlayer.pause()
self._inWindow = True self._inWindow = True
player = self.players[e.get_playerno()-1] player = self.players[e.get_playerno()-1]
@ -124,8 +138,11 @@ class QuestionWindow(QtGui.QDialog):
if not done: if not done:
self.buzzersOpen.emit(True) self.buzzersOpen.emit(True)
if self.question["Type"] == "Music": if self.question["Type"] == "Music":
# restart music if question was not answered # resume music if question was not answered
MusicBox.play_music("%s-%s" % (self.section, self.qnumber)) MusicBox.play_music("%s-%s" % (self.section, self.qnumber))
elif self.question["Type"] == "Video":
# resume video if question was not answered
self._videoPlayer.play()
elif e.get_playerno() > len(self.players) and not self._inWindow: elif e.get_playerno() > len(self.players) and not self._inWindow:
# unknown player! to not confuse certain devices we send a buttons open event # unknown player! to not confuse certain devices we send a buttons open event
@ -158,6 +175,8 @@ class QuestionWindow(QtGui.QDialog):
def playerButtonPress(self, no): def playerButtonPress(self, no):
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no))) QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no)))
def _question_has_audio(self):
return self.question["Type"] == "Music" or (self.question["Type"] == "Video" and self.question["Audio"])
class QuestionAnswerWindow(QtGui.QDialog): class QuestionAnswerWindow(QtGui.QDialog):
CORRECT = 1 CORRECT = 1
@ -413,7 +432,6 @@ class PlayerStartWindow(QtGui.QDialog):
return ret return ret
def closeEvent(self, event): def closeEvent(self, event):
MusicBox.stop_music() MusicBox.stop_music()
self.buzzersOpen.emit(False) self.buzzersOpen.emit(False)