diff options
Diffstat (limited to 'src/components/video.py')
| -rw-r--r-- | src/components/video.py | 178 |
1 files changed, 103 insertions, 75 deletions
diff --git a/src/components/video.py b/src/components/video.py index 60ca800..65a05af 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -1,5 +1,5 @@ from PIL import Image -from PyQt5 import QtGui, QtCore, QtWidgets +from PyQt6 import QtGui, QtCore, QtWidgets import os import math import subprocess @@ -11,15 +11,15 @@ from ..toolkit.ffmpeg import openPipe, closePipe, testAudioStream, FfmpegVideo from ..toolkit import checkOutput -log = logging.getLogger('AVP.Components.Video') +log = logging.getLogger("AVP.Components.Video") class Component(Component): - name = 'Video' - version = '1.0.0' + name = "Video" + version = "1.0.0" def widget(self, *args): - self.videoPath = '' + self.videoPath = "" self.badAudio = False self.x = 0 self.y = 0 @@ -27,23 +27,28 @@ class Component(Component): super().widget(*args) self._image = BlankFrame(self.width, self.height) self.page.pushButton_video.clicked.connect(self.pickVideo) - self.trackWidgets({ - 'videoPath': self.page.lineEdit_video, - 'loopVideo': self.page.checkBox_loop, - 'useAudio': self.page.checkBox_useAudio, - 'distort': self.page.checkBox_distort, - 'scale': self.page.spinBox_scale, - 'volume': self.page.spinBox_volume, - 'xPosition': self.page.spinBox_x, - 'yPosition': self.page.spinBox_y, - }, presetNames={ - 'videoPath': 'video', - 'loopVideo': 'loop', - 'xPosition': 'x', - 'yPosition': 'y', - }, relativeWidgets=[ - 'xPosition', 'yPosition', - ]) + self.trackWidgets( + { + "videoPath": self.page.lineEdit_video, + "loopVideo": self.page.checkBox_loop, + "useAudio": self.page.checkBox_useAudio, + "distort": self.page.checkBox_distort, + "scale": self.page.spinBox_scale, + "volume": self.page.spinBox_volume, + "xPosition": self.page.spinBox_x, + "yPosition": self.page.spinBox_y, + }, + presetNames={ + "videoPath": "video", + "loopVideo": "loop", + "xPosition": "x", + "yPosition": "y", + }, + relativeWidgets=[ + "xPosition", + "yPosition", + ], + ) def update(self): if self.page.checkBox_useAudio.isChecked(): @@ -64,7 +69,7 @@ class Component(Component): def properties(self): props = [] outputFile = None - if hasattr(self.parent, 'lineEdit_outputFile'): + if hasattr(self.parent, "lineEdit_outputFile"): # check only happens in GUI mode outputFile = self.parent.lineEdit_outputFile.text() @@ -72,34 +77,42 @@ class Component(Component): self.lockError("There is no video selected.") elif not os.path.exists(self.videoPath): self.lockError("The video selected does not exist!") - elif outputFile and os.path.realpath(self.videoPath) == os.path.realpath(outputFile): + elif outputFile and os.path.realpath(self.videoPath) == os.path.realpath( + outputFile + ): self.lockError("Input and output paths match.") if self.useAudio: - props.append('audio') - if not testAudioStream(self.videoPath) \ - and self.error() is None: - self.lockError( - "Could not identify an audio stream in this video.") + props.append("audio") + if not testAudioStream(self.videoPath) and self.error() is None: + self.lockError("Could not identify an audio stream in this video.") return props def audio(self): params = {} if self.volume != 1.0: - params['volume'] = '=%s:replaygain_noclip=0' % str(self.volume) + params["volume"] = "=%s:replaygain_noclip=0" % str(self.volume) return (self.videoPath, params) def preFrameRender(self, **kwargs): super().preFrameRender(**kwargs) self.updateChunksize() - self.video = FfmpegVideo( - inputPath=self.videoPath, filter_=self.makeFfmpegFilter(), - width=self.width, height=self.height, chunkSize=self.chunkSize, - frameRate=int(self.settings.value("outputFrameRate")), - parent=self.parent, loopVideo=self.loopVideo, - component=self - ) if os.path.exists(self.videoPath) else None + self.video = ( + FfmpegVideo( + inputPath=self.videoPath, + filter_=self.makeFfmpegFilter(), + width=self.width, + height=self.height, + chunkSize=self.chunkSize, + frameRate=int(self.settings.value("outputFrameRate")), + parent=self.parent, + loopVideo=self.loopVideo, + component=self, + ) + if os.path.exists(self.videoPath) + else None + ) def frameRender(self, frameNo): if FfmpegVideo.threadError is not None: @@ -112,8 +125,10 @@ class Component(Component): def pickVideo(self): imgDir = self.settings.value("componentDir", os.path.expanduser("~")) filename, _ = QtWidgets.QFileDialog.getOpenFileName( - self.page, "Choose Video", - imgDir, "Video Files (%s)" % " ".join(self.core.videoFormats) + self.page, + "Choose Video", + imgDir, + "Video Files (%s)" % " ".join(self.core.videoFormats), ) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) @@ -127,33 +142,50 @@ class Component(Component): command = [ self.core.FFMPEG_BIN, - '-thread_queue_size', '512', - '-i', self.videoPath, - '-f', 'image2pipe', - '-pix_fmt', 'rgba', + "-thread_queue_size", + "512", + "-i", + self.videoPath, + "-f", + "image2pipe", + "-pix_fmt", + "rgba", ] command.extend(self.makeFfmpegFilter()) - command.extend([ - '-codec:v', 'rawvideo', '-', - '-ss', '90', - '-frames:v', '1', - ]) + command.extend( + [ + "-codec:v", + "rawvideo", + "-", + "-ss", + "90", + "-frames:v", + "1", + ] + ) if self.core.logEnabled: logFilename = os.path.join( - self.core.logDir, 'preview_%s.log' % str(self.compPos)) - log.debug('Creating ffmpeg process (log at %s)' % logFilename) - with open(logFilename, 'w') as logf: - logf.write(" ".join(command) + '\n\n') - with open(logFilename, 'a') as logf: + self.core.logDir, "preview_%s.log" % str(self.compPos) + ) + log.debug("Creating ffmpeg process (log at %s)" % logFilename) + with open(logFilename, "w") as logf: + logf.write(" ".join(command) + "\n\n") + with open(logFilename, "a") as logf: pipe = openPipe( - command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, - stderr=logf, bufsize=10**8 + command, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=logf, + bufsize=10**8, ) else: pipe = openPipe( - command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, - stderr=subprocess.DEVNULL, bufsize=10**8 + command, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + bufsize=10**8, ) byteFrame = pipe.stdout.read(self.chunkSize) @@ -164,9 +196,8 @@ class Component(Component): def makeFfmpegFilter(self): return [ - '-filter_complex', - '[0:v] scale=%s:%s' % scale( - self.scale, self.width, self.height, str), + "-filter_complex", + "[0:v] scale=%s:%s" % scale(self.scale, self.width, self.height, str), ] def updateChunksize(self): @@ -177,10 +208,10 @@ class Component(Component): self.chunkSize = 4 * width * height def command(self, arg): - if '=' in arg: - key, arg = arg.split('=', 1) - if key == 'path' and os.path.exists(arg): - if '*%s' % os.path.splitext(arg)[1] in self.core.videoFormats: + if "=" in arg: + key, arg = arg.split("=", 1) + if key == "path" and os.path.exists(arg): + if "*%s" % os.path.splitext(arg)[1] in self.core.videoFormats: self.page.lineEdit_video.setText(arg) self.page.spinBox_scale.setValue(100) self.page.checkBox_loop.setChecked(True) @@ -188,7 +219,7 @@ class Component(Component): else: print("Not a supported video format") quit(1) - elif arg == 'audio': + elif arg == "audio": if not self.page.lineEdit_video.text(): print("'audio' option must follow a video selection") quit(1) @@ -197,28 +228,25 @@ class Component(Component): super().command(arg) def commandHelp(self): - print('Load a video:\n path=/filepath/to/video.mp4') - print('Using audio:\n path=/filepath/to/video.mp4 audio') + print("Load a video:\n path=/filepath/to/video.mp4") + print("Using audio:\n path=/filepath/to/video.mp4 audio") def finalizeFrame(self, imageData): try: if self.distort: - image = Image.frombytes( - 'RGBA', - (self.width, self.height), - imageData) + image = Image.frombytes("RGBA", (self.width, self.height), imageData) else: image = Image.frombytes( - 'RGBA', + "RGBA", scale(self.scale, self.width, self.height, int), - imageData) + imageData, + ) self._image = image except ValueError: # use last good frame image = self._image - if self.scale != 100 \ - or self.xPosition != 0 or self.yPosition != 0: + if self.scale != 100 or self.xPosition != 0 or self.yPosition != 0: frame = BlankFrame(self.width, self.height) frame.paste(image, box=(self.xPosition, self.yPosition)) else: |
