From 09466d83a83e108dc02fda8339fb0783798f420f Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Wed, 17 Dec 2014 01:36:14 +0100 Subject: [PATCH] Implemented video playback for questions --- Readme.md | 2 ++ question.py | 14 ++++++++++---- video.py | 42 ++++++++++++++++++++++++++++++++++++++++++ windows.py | 26 ++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 8 deletions(-) create mode 100644 video.py diff --git a/Readme.md b/Readme.md index f22c543..875ee74 100644 --- a/Readme.md +++ b/Readme.md @@ -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) - Type (type of question) - 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: @@ -48,6 +49,7 @@ Four *Types* of question are supported: four spaces - 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 + - Video: The Question key is a path to a video file, which is played Gamestate diff --git a/question.py b/question.py index 018c465..4bf6549 100644 --- a/question.py +++ b/question.py @@ -10,8 +10,8 @@ class QuestionException(Exception): class Questions(object): """ Object holding all the questions """ - QUESTION_TYPES = ["Text", "Image", "Music", "Code"] - QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy"] + QUESTION_TYPES = ["Text", "Image", "Music", "Code", "Video"] + QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy", "Audio"] def __init__(self, qfile): self.qfile = qfile @@ -72,18 +72,24 @@ class Questions(object): if key not in self.QUESTION_KEYS: 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(): q["Double-Jeopardy"] = False 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"])) + # 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 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))) # 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"]): raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"])) diff --git a/video.py b/video.py new file mode 100644 index 0000000..5d5b83e --- /dev/null +++ b/video.py @@ -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() + diff --git a/windows.py b/windows.py index e1d1fe4..d6fb47f 100644 --- a/windows.py +++ b/windows.py @@ -4,6 +4,7 @@ import copy from gamestate import QuestionAnswers from music import MusicBox +from video import VideoPlayer from player import Player, ButtonEvent, nobodyColor class QuestionWindow(QtGui.QDialog): @@ -20,6 +21,7 @@ class QuestionWindow(QtGui.QDialog): self.dj = dj self._windowSetup = False + self._videoPlayer = None if answers is not None: self.answers = answers @@ -27,7 +29,7 @@ class QuestionWindow(QtGui.QDialog): self.answers = QuestionAnswers(self.section, self.qnumber) if not self.answers.is_answered(): - if self.question["Type"] != "Music": + if not self._question_has_audio(): MusicBox.play_music("questionSong") if self.dj: @@ -43,6 +45,8 @@ class QuestionWindow(QtGui.QDialog): tag = "%s-%s" % (self.section, self.qnumber) MusicBox.add_music(tag, self.question["Question"]) MusicBox.play_music(tag) + elif self.question["Type"] == "Video": + self._videoPlayer.play() def get_answers(self): return self.answers @@ -51,6 +55,8 @@ class QuestionWindow(QtGui.QDialog): if not self._inWindow: self.buzzersOpen.emit(False) MusicBox.stop_music() + if self._videoPlayer: + self._videoPlayer.stop() event.accept() else: event.ignore() @@ -74,6 +80,7 @@ class QuestionWindow(QtGui.QDialog): self.layout.addStretch() qlabel = None + stretch = 0 if self.question["Type"] == "Text": qlabel = self._mkQuestionLabel(self.question["Question"]) elif self.question["Type"] == "Music": @@ -92,10 +99,15 @@ class QuestionWindow(QtGui.QDialog): code = map(lambda x: x + ((maxLineLen-len(x))*" "), code) qlabel = self._mkQuestionLabel("
"+"\n".join(code)+"
", monospaced=True) + elif self.question["Type"] == "Video": + self._videoPlayer = VideoPlayer(self.question["Question"], self.question["Audio"]) + qlabel = self._videoPlayer.get_widget() + stretch = 1 else: 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.setLayout(self.layout) @@ -106,6 +118,8 @@ class QuestionWindow(QtGui.QDialog): done = False if self.question["Type"] == "Music": MusicBox.stop_music() + elif self.question["Type"] == "Video": + self._videoPlayer.pause() self._inWindow = True player = self.players[e.get_playerno()-1] @@ -124,8 +138,11 @@ class QuestionWindow(QtGui.QDialog): if not done: self.buzzersOpen.emit(True) 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)) + 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: # 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): 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): CORRECT = 1 @@ -413,7 +432,6 @@ class PlayerStartWindow(QtGui.QDialog): return ret - def closeEvent(self, event): MusicBox.stop_music() self.buzzersOpen.emit(False)