diff options
| author | Brianna | 2017-07-15 19:40:08 -0400 |
|---|---|---|
| committer | GitHub | 2017-07-15 19:40:08 -0400 |
| commit | f420ad69f5f6f3c830fea890a760ce0ce61ba571 (patch) | |
| tree | 2a7f9df3eebbae8da4317516f84dfe7490b5d36a /src/components | |
| parent | 94d4acc1f4f4abe4029e8f9c050932b67cae8cec (diff) | |
| parent | bcb8f27c2e4434d2296dcd66bf279b76ee0d0a4f (diff) | |
Merge audio-mixing branch
some basic audio features + more user feedback + merging static components
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/color.py | 17 | ||||
| -rw-r--r-- | src/components/image.py | 29 | ||||
| -rw-r--r-- | src/components/original.py | 11 | ||||
| -rw-r--r-- | src/components/sound.py | 89 | ||||
| -rw-r--r-- | src/components/sound.ui | 122 | ||||
| -rw-r--r-- | src/components/text.py | 36 | ||||
| -rw-r--r-- | src/components/video.py | 67 | ||||
| -rw-r--r-- | src/components/video.ui | 17 |
8 files changed, 334 insertions, 54 deletions
diff --git a/src/components/color.py b/src/components/color.py index b87f3e9..ef4dd95 100644 --- a/src/components/color.py +++ b/src/components/color.py @@ -15,6 +15,7 @@ class Component(Component): def widget(self, parent): self.parent = parent + self.settings = self.parent.core.settings page = self.loadUi('color.ui') self.color1 = (0, 0, 0) @@ -42,9 +43,9 @@ class Component(Component): page.spinBox_x.valueChanged.connect(self.update) page.spinBox_y.valueChanged.connect(self.update) page.spinBox_width.setValue( - int(parent.settings.value("outputWidth"))) + int(self.settings.value("outputWidth"))) page.spinBox_height.setValue( - int(parent.settings.value("outputHeight"))) + int(self.settings.value("outputHeight"))) page.lineEdit_color1.textChanged.connect(self.update) page.lineEdit_color2.textChanged.connect(self.update) @@ -109,21 +110,19 @@ class Component(Component): self.page.pushButton_color2.setEnabled(False) self.page.fillWidget.setCurrentIndex(self.fillType) - self.parent.drawPreview() super().update() def previewRender(self, previewWorker): - width = int(previewWorker.core.settings.value('outputWidth')) - height = int(previewWorker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.drawFrame(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) + def properties(self): return ['static'] def frameRender(self, layerNo, frameNo): - width = int(self.worker.core.settings.value('outputWidth')) - height = int(self.worker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.drawFrame(width, height) def drawFrame(self, width, height): diff --git a/src/components/image.py b/src/components/image.py index 6edd893..c0d1c0d 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -13,7 +13,7 @@ class Component(Component): def widget(self, parent): self.parent = parent - self.settings = parent.settings + self.settings = self.parent.core.settings page = self.loadUi('image.ui') page.lineEdit_image.textChanged.connect(self.update) @@ -38,22 +38,29 @@ class Component(Component): self.yPosition = self.page.spinBox_y.value() self.stretched = self.page.checkBox_stretch.isChecked() self.mirror = self.page.checkBox_mirror.isChecked() - self.parent.drawPreview() + super().update() def previewRender(self, previewWorker): - self.imageFormats = previewWorker.core.imageFormats - width = int(previewWorker.core.settings.value('outputWidth')) - height = int(previewWorker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.drawFrame(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) - return ['static'] + def properties(self): + props = ['static'] + if not os.path.exists(self.imagePath): + props.append('error') + return props + + def error(self): + if not self.imagePath: + return "There is no image selected." + if not os.path.exists(self.imagePath): + return "The image selected does not exist!" def frameRender(self, layerNo, frameNo): - width = int(self.worker.core.settings.value('outputWidth')) - height = int(self.worker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.drawFrame(width, height) def drawFrame(self, width, height): @@ -110,7 +117,7 @@ class Component(Component): imgDir = self.settings.value("componentDir", os.path.expanduser("~")) filename, _ = QtWidgets.QFileDialog.getOpenFileName( self.page, "Choose Image", imgDir, - "Image Files (%s)" % " ".join(self.imageFormats)) + "Image Files (%s)" % " ".join(self.core.imageFormats)) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) diff --git a/src/components/original.py b/src/components/original.py index 638095d..f5776a4 100644 --- a/src/components/original.py +++ b/src/components/original.py @@ -21,6 +21,7 @@ class Component(Component): def widget(self, parent): self.parent = parent + self.settings = self.parent.core.settings self.visColor = (255, 255, 255) self.scale = 20 self.y = 0 @@ -50,7 +51,7 @@ class Component(Component): self.visColor = self.RGBFromString(self.page.lineEdit_visColor.text()) self.scale = self.page.spinBox_scale.value() self.y = self.page.spinBox_y.value() - self.parent.drawPreview() + super().update() def loadPreset(self, pr, presetName=None): @@ -76,8 +77,8 @@ class Component(Component): def previewRender(self, previewWorker): spectrum = numpy.fromfunction( lambda x: float(self.scale)/2500*(x-128)**2, (255,), dtype="int16") - width = int(previewWorker.core.settings.value('outputWidth')) - height = int(previewWorker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.drawBars( width, height, spectrum, self.visColor, self.layout ) @@ -88,8 +89,8 @@ class Component(Component): self.smoothConstantUp = 0.8 self.lastSpectrum = None self.spectrumArray = {} - self.width = int(self.worker.core.settings.value('outputWidth')) - self.height = int(self.worker.core.settings.value('outputHeight')) + self.width = int(self.settings.value('outputWidth')) + self.height = int(self.settings.value('outputHeight')) for i in range(0, len(self.completeAudioArray), self.sampleSize): if self.canceled: diff --git a/src/components/sound.py b/src/components/sound.py new file mode 100644 index 0000000..4a5714b --- /dev/null +++ b/src/components/sound.py @@ -0,0 +1,89 @@ +from PyQt5 import QtGui, QtCore, QtWidgets +import os + +from component import Component +from frame import BlankFrame + + +class Component(Component): + '''Sound''' + + modified = QtCore.pyqtSignal(int, dict) + + def widget(self, parent): + self.parent = parent + self.settings = parent.settings + page = self.loadUi('sound.ui') + + page.lineEdit_sound.textChanged.connect(self.update) + page.pushButton_sound.clicked.connect(self.pickSound) + + self.page = page + return page + + def update(self): + self.sound = self.page.lineEdit_sound.text() + super().update() + + def previewRender(self, previewWorker): + width = int(previewWorker.core.settings.value('outputWidth')) + height = int(previewWorker.core.settings.value('outputHeight')) + return BlankFrame(width, height) + + def preFrameRender(self, **kwargs): + pass + + def properties(self): + props = ['static', 'audio'] + if not os.path.exists(self.sound): + props.append('error') + return props + + def error(self): + if not self.sound: + return "No audio file selected." + if not os.path.exists(self.sound): + return "The audio file selected no longer exists!" + + def audio(self): + return (self.sound, {}) + + def pickSound(self): + sndDir = self.settings.value("componentDir", os.path.expanduser("~")) + filename, _ = QtWidgets.QFileDialog.getOpenFileName( + self.page, "Choose Sound", sndDir, + "Audio Files (%s)" % " ".join(self.core.audioFormats)) + if filename: + self.settings.setValue("componentDir", os.path.dirname(filename)) + self.page.lineEdit_sound.setText(filename) + self.update() + + def frameRender(self, layerNo, frameNo): + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) + return BlankFrame(width, height) + + def loadPreset(self, pr, presetName=None): + super().loadPreset(pr, presetName) + self.page.lineEdit_sound.setText(pr['sound']) + + def savePreset(self): + return { + 'sound': self.sound, + } + + def commandHelp(self): + print('Path to audio file:\n path=/filepath/to/sound.ogg') + + def command(self, arg): + if not arg.startswith('preset=') and '=' in arg: + key, arg = arg.split('=', 1) + if key == 'path': + if '*%s' % os.path.splitext(arg)[1] \ + not in self.core.audioFormats: + print("Not a supported audio format") + quit(1) + self.page.lineEdit_sound.setText(arg) + return + + super().command(arg) diff --git a/src/components/sound.ui b/src/components/sound.ui new file mode 100644 index 0000000..5fc00c1 --- /dev/null +++ b/src/components/sound.ui @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>586</width> + <height>197</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>4</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <widget class="QLabel" name="label_textColor"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>31</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Audio File</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="lineEdit_sound"> + <property name="minimumSize"> + <size> + <width>1</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="pushButton_sound"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>1</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="text"> + <string>...</string> + </property> + <property name="MaximumSize" stdset="0"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/components/text.py b/src/components/text.py index 2b1884f..19460e5 100644 --- a/src/components/text.py +++ b/src/components/text.py @@ -17,10 +17,11 @@ class Component(Component): self.titleFont = QFont() def widget(self, parent): - height = int(parent.settings.value('outputHeight')) - width = int(parent.settings.value('outputWidth')) - self.parent = parent + self.settings = self.parent.core.settings + height = int(self.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + self.textColor = (255, 255, 255) self.title = 'Text' self.alignment = 1 @@ -68,17 +69,17 @@ class Component(Component): btnStyle = "QPushButton { background-color : %s; outline: none; }" \ % QColor(*self.textColor).name() self.page.pushButton_textColor.setStyleSheet(btnStyle) - self.parent.drawPreview() + super().update() def getXY(self): '''Returns true x, y after considering alignment settings''' fm = QtGui.QFontMetrics(self.titleFont) if self.alignment == 0: # Left - x = self.xPosition + x = int(self.xPosition) if self.alignment == 1: # Middle - offset = fm.width(self.title)/2 + offset = int(fm.width(self.title)/2) x = self.xPosition - offset if self.alignment == 2: # Right @@ -115,26 +116,31 @@ class Component(Component): } def previewRender(self, previewWorker): - width = int(previewWorker.core.settings.value('outputWidth')) - height = int(previewWorker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.addText(width, height) - def preFrameRender(self, **kwargs): - super().preFrameRender(**kwargs) - return ['static'] + def properties(self): + props = ['static'] + if not self.title: + props.append('error') + return props + + def error(self): + return "No text provided." def frameRender(self, layerNo, frameNo): - width = int(self.worker.core.settings.value('outputWidth')) - height = int(self.worker.core.settings.value('outputHeight')) + width = int(self.settings.value('outputWidth')) + height = int(self.settings.value('outputHeight')) return self.addText(width, height) def addText(self, width, height): - x, y = self.getXY() - image = FramePainter(width, height) + image = FramePainter(width, height) self.titleFont.setPixelSize(self.fontSize) image.setFont(self.titleFont) image.setPen(self.textColor) + x, y = self.getXY() image.drawText(x, y, self.title) return image.finalize() diff --git a/src/components/video.py b/src/components/video.py index e6890e0..0b93293 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -8,7 +8,7 @@ from queue import PriorityQueue from component import Component, BadComponentInit from frame import BlankFrame -from toolkit import openPipe +from toolkit import openPipe, checkOutput class Video: @@ -115,6 +115,8 @@ class Component(Component): self.settings = parent.settings page = self.loadUi('video.ui') self.videoPath = '' + self.badVideo = False + self.badAudio = False self.x = 0 self.y = 0 self.loopVideo = False @@ -123,6 +125,7 @@ class Component(Component): page.pushButton_video.clicked.connect(self.pickVideo) page.checkBox_loop.stateChanged.connect(self.update) page.checkBox_distort.stateChanged.connect(self.update) + page.checkBox_useAudio.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) @@ -133,15 +136,15 @@ class Component(Component): def update(self): self.videoPath = self.page.lineEdit_video.text() self.loopVideo = self.page.checkBox_loop.isChecked() + self.useAudio = self.page.checkBox_useAudio.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): - self.videoFormats = previewWorker.core.videoFormats width = int(previewWorker.core.settings.value('outputWidth')) height = int(previewWorker.core.settings.value('outputHeight')) self.updateChunksize(width, height) @@ -151,6 +154,47 @@ class Component(Component): else: return frame + def properties(self): + props = [] + if not self.videoPath or self.badVideo \ + or not os.path.exists(self.videoPath): + return ['error'] + + if self.useAudio: + props.append('audio') + self.testAudioStream() + if self.badAudio: + return ['error'] + + return props + + def error(self): + if self.badAudio: + return "Could not identify an audio stream in this video." + if not self.videoPath: + return "There is no video selected." + if not os.path.exists(self.videoPath): + return "The video selected does not exist!" + if self.badVideo: + return "The video selected is corrupt!" + + def testAudioStream(self): + # test if an audio stream really exists + audioTestCommand = [ + self.core.FFMPEG_BIN, + '-i', self.videoPath, + '-vn', '-f', 'null', '-' + ] + try: + checkOutput(audioTestCommand, stderr=subprocess.DEVNULL) + except subprocess.CalledProcessError: + self.badAudio = True + else: + self.badAudio = False + + def audio(self): + return (self.videoPath, {'map': '-v'}) + def preFrameRender(self, **kwargs): super().preFrameRender(**kwargs) width = int(self.worker.core.settings.value('outputWidth')) @@ -158,7 +202,7 @@ class Component(Component): self.blankFrame_ = BlankFrame(width, height) self.updateChunksize(width, height) self.video = Video( - ffmpeg=self.parent.core.FFMPEG_BIN, videoPath=self.videoPath, + ffmpeg=self.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, @@ -175,6 +219,7 @@ class Component(Component): super().loadPreset(pr, presetName) self.page.lineEdit_video.setText(pr['video']) self.page.checkBox_loop.setChecked(pr['loop']) + self.page.checkBox_useAudio.setChecked(pr['useAudio']) self.page.checkBox_distort.setChecked(pr['distort']) self.page.spinBox_scale.setValue(pr['scale']) self.page.spinBox_x.setValue(pr['x']) @@ -185,6 +230,7 @@ class Component(Component): 'preset': self.currentPreset, 'video': self.videoPath, 'loop': self.loopVideo, + 'useAudio': self.useAudio, 'distort': self.distort, 'scale': self.scale, 'x': self.xPosition, @@ -195,7 +241,7 @@ class Component(Component): imgDir = self.settings.value("componentDir", os.path.expanduser("~")) filename, _ = QtWidgets.QFileDialog.getOpenFileName( self.page, "Choose Video", - imgDir, "Video Files (%s)" % " ".join(self.videoFormats) + imgDir, "Video Files (%s)" % " ".join(self.core.videoFormats) ) if filename: self.settings.setValue("componentDir", os.path.dirname(filename)) @@ -238,7 +284,7 @@ class Component(Component): if not arg.startswith('preset=') and '=' in arg: key, arg = arg.split('=', 1) if key == 'path' and os.path.exists(arg): - if os.path.splitext(arg)[1] in self.core.videoFormats: + 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) @@ -246,10 +292,17 @@ class Component(Component): else: print("Not a supported video format") quit(1) + elif arg == 'audio': + if not self.page.lineEdit_video.text(): + print("'audio' option must follow a video selection") + quit(1) + self.page.checkBox_useAudio.setChecked(True) + return 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') def scale(scale, width, height, returntype=None): @@ -281,6 +334,7 @@ def finalizeFrame(self, imageData, width, height): '### BAD VIDEO SELECTED ###\n' 'Video will not export with these settings' ) + self.badVideo = True return BlankFrame(width, height) if self.scale != 100 \ @@ -289,4 +343,5 @@ def finalizeFrame(self, imageData, width, height): frame.paste(image, box=(self.xPosition, self.yPosition)) else: frame = image + self.badVideo = False return frame diff --git a/src/components/video.ui b/src/components/video.ui index f05e8a5..97b7d6f 100644 --- a/src/components/video.ui +++ b/src/components/video.ui @@ -190,16 +190,20 @@ </widget> </item> <item> - <spacer name="horizontalSpacer_10"> + <widget class="QCheckBox" name="checkBox_useAudio"> + <property name="text"> + <string>Use Audio</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> - </property> <property name="sizeHint" stdset="0"> <size> - <width>5</width> + <width>40</width> <height>20</height> </size> </property> @@ -256,9 +260,6 @@ </property> </spacer> </item> - <item> - <widget class="QWidget" name="widget" native="true"/> - </item> </layout> </widget> <resources/> |
