aboutsummaryrefslogtreecommitdiff
path: root/src/components/video.py
diff options
context:
space:
mode:
authortassaron2026-01-11 14:29:58 -0500
committertassaron2026-01-11 14:29:58 -0500
commit669756b391d26661cf2e2a97a304e73343ef6655 (patch)
tree9cf2d4858c209bdab9f44d5c7f95c2a30b37f7a6 /src/components/video.py
parent9d45f7f1a986aaa5d3c084c7ae747442b94a61b1 (diff)
update to Qt 6 and Pillow 12
and yeah, I accidentally ran black on the codebase. I don't want to spend more free time fixing that. All of these changes are simple renames or removals, nothing too major.
Diffstat (limited to 'src/components/video.py')
-rw-r--r--src/components/video.py178
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: