pgfw/pgfw/VideoRecorder.py

114 lines
4.5 KiB
Python

from os import makedirs
from os.path import exists, join
from tempfile import TemporaryFile
from time import strftime
from pygame.image import tostring, frombuffer, save
from pygame.time import get_ticks
from .GameChild import GameChild
class VideoRecorder(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.set_requested()
if self.requested:
self.display_surface = self.get_display_surface()
self.delegate = self.get_delegate()
self.load_configuration()
self.reset()
self.subscribe(self.respond)
def set_requested(self):
self.requested = self.get_configuration("video-recordings")["enable"] \
or self.check_command_line("-enable-video")
def load_configuration(self):
config = self.get_configuration("video-recordings")
self.root = config["path"]
self.directory_name_format = config["directory-name-format"]
self.file_extension = config["file-extension"]
self.frame_format = config["frame-format"]
self.framerate = config["framerate"]
def reset(self):
self.recording = False
self.frame_length = None
self.frames = None
self.last_frame = 0
def respond(self, event):
compare = self.delegate.compare
if compare(event, "record-video"):
self.toggle_record()
elif compare(event, "reset-game"):
self.reset()
def is_audio_recording_enabled(self):
return self.get_configuration("video-recordings", "record-audio") or\
self.check_command_line("-enable-sound-recording")
def toggle_record(self):
recording = not self.recording
if recording:
self.frame_length = len(self.get_string())
temp_dir = self.get_configuration("video-recordings", "temp-directory")
if temp_dir == "":
temp_dir = None
self.frames = TemporaryFile(dir=temp_dir)
print("writing video frames to {}".format(self.frames.name))
if self.is_audio_recording_enabled():
import pyaudio
import wave
self.audio_frames = []
self.audio_recorder = pyaudio.PyAudio()
def audio_callback(in_data, frame_count, time_info, status):
self.audio_frames.append(in_data)
return (in_data, pyaudio.paContinue)
for ii in range(self.audio_recorder.get_device_count()):
print("device {}: {}".format(ii, self.audio_recorder.get_device_info_by_index(ii)))
self.audio_stream = self.audio_recorder.open(format=pyaudio.paInt32, channels=2, rate=44100,
frames_per_buffer=1024,
input=True, stream_callback=audio_callback)
print("writing audio data to {}".format(self.audio_stream))
else:
self.write_frames()
self.recording = recording
def get_string(self):
return tostring(self.display_surface, self.frame_format)
def write_frames(self):
root = join(self.root, strftime(self.directory_name_format))
if not exists(root):
makedirs(root)
if self.is_audio_recording_enabled():
import pyaudio
import wave
self.audio_stream.stop_stream()
self.audio_stream.close()
self.audio_recorder.terminate()
wf = wave.open(join(root, "audio.wav"), "wb")
wf.setnchannels(2)
wf.setsampwidth(self.audio_recorder.get_sample_size(pyaudio.paInt32))
wf.setframerate(44100)
wf.writeframes(b"".join(self.audio_frames))
wf.close()
print("saved audio in {}".format(root))
size = self.display_surface.get_size()
frames = self.frames
frames.seek(0)
for ii, frame in enumerate(
iter(lambda: frames.read(self.frame_length), b'')):
path = join(root, "{:0{digits}}.png".format(
ii, digits=self.get_configuration("video-recordings", "filename-digits")))
save(frombuffer(frame, size, self.frame_format), path)
print("saved video frames in {}".format(root))
def update(self):
ticks = get_ticks()
if self.recording and ticks - self.last_frame >= self.framerate:
self.frames.write(self.get_string())
self.last_frame = ticks