diff options
Diffstat (limited to 'components')
| -rw-r--r-- | components/video.py | 80 | ||||
| -rw-r--r-- | components/video.ui | 7 |
2 files changed, 77 insertions, 10 deletions
diff --git a/components/video.py b/components/video.py index 841f77b..5f55211 100644 --- a/components/video.py +++ b/components/video.py @@ -11,13 +11,15 @@ class Video: '''Video Component Frame-Fetcher''' def __init__(self, **kwargs): mandatoryArgs = [ - 'ffmpeg', # path to ffmpeg, usually core.FFMPEG_BIN + 'ffmpeg', # path to ffmpeg, usually core.FFMPEG_BIN 'videoPath', 'width', 'height', + 'scale', # percentage scale 'frameRate', # frames per second 'chunkSize', # number of bytes in one frame - 'parent' + 'parent', # mainwindow object + 'component', # component object ] for arg in mandatoryArgs: try: @@ -39,7 +41,8 @@ class Video: '-i', self.videoPath, '-f', 'image2pipe', '-pix_fmt', 'rgba', - '-filter:v', 'scale='+str(self.width)+':'+str(self.height), + '-filter:v', 'scale=%s:%s' % + scale(self.scale, self.width, self.height, str), '-vcodec', 'rawvideo', '-', ] @@ -58,7 +61,9 @@ class Video: while True: if num in self.finishedFrames: image = self.finishedFrames.pop(num) - return Image.frombytes('RGBA', (self.width, self.height), image) + return finalizeFrame( + self.component, image, self.width, self.height) + i, image = self.frameBuffer.get() self.finishedFrames[i] = image self.frameBuffer.task_done() @@ -104,6 +109,10 @@ class Component(__base__.Component): page.lineEdit_video.textChanged.connect(self.update) page.pushButton_video.clicked.connect(self.pickVideo) page.checkBox_loop.stateChanged.connect(self.update) + page.checkBox_distort.stateChanged.connect(self.update) + page.spinBox_scale.valueChanged.connect(self.update) + page.spinBox_x.valueChanged.connect(self.update) + page.spinBox_y.valueChanged.connect(self.update) self.page = page return page @@ -111,13 +120,17 @@ class Component(__base__.Component): def update(self): self.videoPath = self.page.lineEdit_video.text() self.loopVideo = self.page.checkBox_loop.isChecked() + self.distort = self.page.checkBox_distort.isChecked() + self.scale = self.page.spinBox_scale.value() + self.xPosition = self.page.spinBox_x.value() + self.yPosition = self.page.spinBox_y.value() self.parent.drawPreview() super().update() def previewRender(self, previewWorker): width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) - self.chunkSize = 4*width*height + self.updateChunksize(width, height) frame = self.getPreviewFrame(width, height) if not frame: return Image.new("RGBA", (width, height), (0, 0, 0, 0)) @@ -128,12 +141,13 @@ class Component(__base__.Component): super().preFrameRender(**kwargs) width = int(self.worker.core.settings.value('outputWidth')) height = int(self.worker.core.settings.value('outputHeight')) - self.chunkSize = 4*width*height + self.updateChunksize(width, height) self.video = Video( ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath, width=width, height=height, chunkSize=self.chunkSize, frameRate=int(self.settings.value("outputFrameRate")), - parent=self.parent, loopVideo=self.loopVideo + parent=self.parent, loopVideo=self.loopVideo, + component=self, scale=self.scale ) def frameRender(self, moduleNo, arrayNo, frameNo): @@ -143,12 +157,20 @@ class Component(__base__.Component): super().loadPreset(pr, presetName) self.page.lineEdit_video.setText(pr['video']) self.page.checkBox_loop.setChecked(pr['loop']) + self.page.checkBox_distort.setChecked(pr['distort']) + self.page.spinBox_scale.setValue(pr['scale']) + self.page.spinBox_x.setValue(pr['x']) + self.page.spinBox_y.setValue(pr['y']) def savePreset(self): return { 'preset': self.currentPreset, 'video': self.videoPath, 'loop': self.loopVideo, + 'distort': self.distort, + 'scale': self.scale, + 'x': self.xPosition, + 'y': self.yPosition, } def pickVideo(self): @@ -165,13 +187,15 @@ class Component(__base__.Component): def getPreviewFrame(self, width, height): if not self.videoPath or not os.path.exists(self.videoPath): return + command = [ self.parent.core.FFMPEG_BIN, '-thread_queue_size', '512', '-i', self.videoPath, '-f', 'image2pipe', '-pix_fmt', 'rgba', - '-filter:v', 'scale='+str(width)+':'+str(height), + '-filter:v', 'scale=%s:%s' % + scale(self.scale, width, height, str), '-vcodec', 'rawvideo', '-', '-ss', '90', '-vframes', '1', @@ -181,7 +205,43 @@ class Component(__base__.Component): stderr=subprocess.DEVNULL, bufsize=10**8 ) byteFrame = pipe.stdout.read(self.chunkSize) - image = Image.frombytes('RGBA', (width, height), byteFrame) + frame = finalizeFrame(self, byteFrame, width, height) pipe.stdout.close() pipe.kill() - return image + + return frame + + def updateChunksize(self, width, height): + if self.scale != 100 and not self.distort: + width, height = scale(self.scale, width, height, int) + self.chunkSize = 4*width*height + +def scale(scale, width, height, returntype=None): + width = (float(width) / 100.0) * float(scale) + height = (float(height) / 100.0) * float(scale) + if returntype == str: + return (str(int(width)), str(int(height))) + elif returntype == int: + return (int(width), int(height)) + else: + return (width, height) + +def finalizeFrame(self, imageData, width, height): + if self.distort: + image = Image.frombytes( + 'RGBA', + (width, height), + imageData) + else: + image = Image.frombytes( + 'RGBA', + scale(self.scale, width, height, int), + imageData) + + if self.scale != 100 \ + or self.xPosition != 0 or self.yPosition != 0: + frame = Image.new("RGBA", (width, height), (0, 0, 0, 0)) + frame.paste(image, box=(self.xPosition, self.yPosition)) + else: + frame = image + return frame diff --git a/components/video.ui b/components/video.ui index aca46b4..fa088fa 100644 --- a/components/video.ui +++ b/components/video.ui @@ -206,6 +206,13 @@ </spacer> </item> <item> + <widget class="QCheckBox" name="checkBox_distort"> + <property name="text"> + <string>Distort by scale</string> + </property> + </widget> + </item> + <item> <widget class="QLabel" name="label"> <property name="text"> <string>Scale</string> |
