waveform component is working, preview is glitchy
This commit is contained in:
parent
c1457b6dad
commit
1297af61c9
|
@ -18,6 +18,9 @@ class Component(Component):
|
||||||
def names(*args):
|
def names(*args):
|
||||||
return ['Original Audio Visualization']
|
return ['Original Audio Visualization']
|
||||||
|
|
||||||
|
def properties(self):
|
||||||
|
return ['pcm']
|
||||||
|
|
||||||
def widget(self, *args):
|
def widget(self, *args):
|
||||||
self.visColor = (255, 255, 255)
|
self.visColor = (255, 255, 255)
|
||||||
self.scale = 20
|
self.scale = 20
|
||||||
|
|
|
@ -4,10 +4,10 @@ import os
|
||||||
import math
|
import math
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from component import Component, ComponentError
|
from component import Component
|
||||||
from toolkit.frame import BlankFrame
|
from toolkit.frame import BlankFrame, scale
|
||||||
from toolkit.ffmpeg import testAudioStream, FfmpegVideo
|
from toolkit.ffmpeg import openPipe, closePipe, testAudioStream, FfmpegVideo
|
||||||
from toolkit import openPipe, closePipe, checkOutput, scale
|
from toolkit import checkOutput
|
||||||
|
|
||||||
|
|
||||||
class Component(Component):
|
class Component(Component):
|
||||||
|
@ -132,7 +132,7 @@ class Component(Component):
|
||||||
]
|
]
|
||||||
command.extend(self.makeFfmpegFilter())
|
command.extend(self.makeFfmpegFilter())
|
||||||
command.extend([
|
command.extend([
|
||||||
'-vcodec', 'rawvideo', '-',
|
'-codec:v', 'rawvideo', '-',
|
||||||
'-ss', '90',
|
'-ss', '90',
|
||||||
'-frames:v', '1',
|
'-frames:v', '1',
|
||||||
])
|
])
|
||||||
|
|
|
@ -5,10 +5,10 @@ import os
|
||||||
import math
|
import math
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from component import Component, ComponentError
|
from component import Component
|
||||||
from toolkit.frame import BlankFrame
|
from toolkit.frame import BlankFrame, scale
|
||||||
from toolkit import openPipe, checkOutput, rgbFromString
|
from toolkit import checkOutput, rgbFromString, pickColor
|
||||||
from toolkit.ffmpeg import FfmpegVideo
|
from toolkit.ffmpeg import openPipe, closePipe, getAudioDuration, FfmpegVideo
|
||||||
|
|
||||||
|
|
||||||
class Component(Component):
|
class Component(Component):
|
||||||
|
@ -21,17 +21,27 @@ class Component(Component):
|
||||||
|
|
||||||
self.page.lineEdit_color.setText('%s,%s,%s' % self.color)
|
self.page.lineEdit_color.setText('%s,%s,%s' % self.color)
|
||||||
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
|
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
|
||||||
% QColor(*self.color1).name()
|
% QColor(*self.color).name()
|
||||||
self.page.lineEdit_color.setStylesheet(btnStyle)
|
self.page.pushButton_color.setStyleSheet(btnStyle)
|
||||||
self.page.pushButton_color.clicked.connect(lambda: self.pickColor())
|
self.page.pushButton_color.clicked.connect(lambda: self.pickColor())
|
||||||
|
self.page.spinBox_scale.valueChanged.connect(self.updateChunksize)
|
||||||
|
|
||||||
|
if hasattr(self.parent, 'window'):
|
||||||
|
self.parent.window.lineEdit_audioFile.textChanged.connect(
|
||||||
|
self.update
|
||||||
|
)
|
||||||
|
|
||||||
self.trackWidgets(
|
self.trackWidgets(
|
||||||
{
|
{
|
||||||
'mode': self.page.comboBox_mode,
|
'mode': self.page.comboBox_mode,
|
||||||
|
'amplitude': self.page.comboBox_amplitude,
|
||||||
'x': self.page.spinBox_x,
|
'x': self.page.spinBox_x,
|
||||||
'y': self.page.spinBox_y,
|
'y': self.page.spinBox_y,
|
||||||
'mirror': self.page.checkBox_mirror,
|
'mirror': self.page.checkBox_mirror,
|
||||||
'scale': self.page.spinBox_scale,
|
'scale': self.page.spinBox_scale,
|
||||||
|
'opacity': self.page.spinBox_opacity,
|
||||||
|
'compress': self.page.checkBox_compress,
|
||||||
|
'mono': self.page.checkBox_mono,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,6 +52,26 @@ class Component(Component):
|
||||||
self.page.pushButton_color.setStyleSheet(btnStyle)
|
self.page.pushButton_color.setStyleSheet(btnStyle)
|
||||||
super().update()
|
super().update()
|
||||||
|
|
||||||
|
def loadPreset(self, pr, *args):
|
||||||
|
super().loadPreset(pr, *args)
|
||||||
|
|
||||||
|
self.page.lineEdit_color.setText('%s,%s,%s' % pr['color'])
|
||||||
|
btnStyle = "QPushButton { background-color : %s; outline: none; }" \
|
||||||
|
% QColor(*pr['color']).name()
|
||||||
|
self.page.pushButton_color.setStyleSheet(btnStyle)
|
||||||
|
|
||||||
|
def savePreset(self):
|
||||||
|
saveValueStore = super().savePreset()
|
||||||
|
saveValueStore['color'] = self.color
|
||||||
|
return saveValueStore
|
||||||
|
|
||||||
|
def pickColor(self):
|
||||||
|
RGBstring, btnStyle = pickColor()
|
||||||
|
if not RGBstring:
|
||||||
|
return
|
||||||
|
self.page.lineEdit_color.setText(RGBstring)
|
||||||
|
self.page.pushButton_color.setStyleSheet(btnStyle)
|
||||||
|
|
||||||
def previewRender(self):
|
def previewRender(self):
|
||||||
self.updateChunksize()
|
self.updateChunksize()
|
||||||
frame = self.getPreviewFrame(self.width, self.height)
|
frame = self.getPreviewFrame(self.width, self.height)
|
||||||
|
@ -53,10 +83,11 @@ class Component(Component):
|
||||||
def preFrameRender(self, **kwargs):
|
def preFrameRender(self, **kwargs):
|
||||||
super().preFrameRender(**kwargs)
|
super().preFrameRender(**kwargs)
|
||||||
self.updateChunksize()
|
self.updateChunksize()
|
||||||
|
w, h = scale(self.scale, self.width, self.height, str)
|
||||||
self.video = FfmpegVideo(
|
self.video = FfmpegVideo(
|
||||||
inputPath=self.audioFile,
|
inputPath=self.audioFile,
|
||||||
filter_=makeFfmpegFilter(),
|
filter_=self.makeFfmpegFilter(),
|
||||||
width=self.width, height=self.height,
|
width=w, height=h,
|
||||||
chunkSize=self.chunkSize,
|
chunkSize=self.chunkSize,
|
||||||
frameRate=int(self.settings.value("outputFrameRate")),
|
frameRate=int(self.settings.value("outputFrameRate")),
|
||||||
parent=self.parent, component=self,
|
parent=self.parent, component=self,
|
||||||
|
@ -65,7 +96,7 @@ class Component(Component):
|
||||||
def frameRender(self, frameNo):
|
def frameRender(self, frameNo):
|
||||||
if FfmpegVideo.threadError is not None:
|
if FfmpegVideo.threadError is not None:
|
||||||
raise FfmpegVideo.threadError
|
raise FfmpegVideo.threadError
|
||||||
return finalizeFrame(self.video.frame(frameNo))
|
return self.finalizeFrame(self.video.frame(frameNo))
|
||||||
|
|
||||||
def postFrameRender(self):
|
def postFrameRender(self):
|
||||||
closePipe(self.video.pipe)
|
closePipe(self.video.pipe)
|
||||||
|
@ -74,18 +105,25 @@ class Component(Component):
|
||||||
inputFile = self.parent.window.lineEdit_audioFile.text()
|
inputFile = self.parent.window.lineEdit_audioFile.text()
|
||||||
if not inputFile or not os.path.exists(inputFile):
|
if not inputFile or not os.path.exists(inputFile):
|
||||||
return
|
return
|
||||||
|
duration = getAudioDuration(inputFile)
|
||||||
|
if not duration:
|
||||||
|
return
|
||||||
|
startPt = duration / 3
|
||||||
|
|
||||||
command = [
|
command = [
|
||||||
self.core.FFMPEG_BIN,
|
self.core.FFMPEG_BIN,
|
||||||
'-thread_queue_size', '512',
|
'-thread_queue_size', '512',
|
||||||
|
'-r', self.settings.value("outputFrameRate"),
|
||||||
|
'-ss', "{0:.3f}".format(startPt),
|
||||||
'-i', inputFile,
|
'-i', inputFile,
|
||||||
'-f', 'image2pipe',
|
'-f', 'image2pipe',
|
||||||
'-pix_fmt', 'rgba',
|
'-pix_fmt', 'rgba',
|
||||||
]
|
]
|
||||||
command.extend(self.makeFfmpegFilter())
|
command.extend(self.makeFfmpegFilter(preview=True, startPt=startPt))
|
||||||
command.extend([
|
command.extend([
|
||||||
'-vcodec', 'rawvideo', '-',
|
'-an',
|
||||||
'-ss', '90',
|
'-s:v', '%sx%s' % scale(self.scale, self.width, self.height, str),
|
||||||
|
'-codec:v', 'rawvideo', '-',
|
||||||
'-frames:v', '1',
|
'-frames:v', '1',
|
||||||
])
|
])
|
||||||
pipe = openPipe(
|
pipe = openPipe(
|
||||||
|
@ -95,44 +133,56 @@ class Component(Component):
|
||||||
byteFrame = pipe.stdout.read(self.chunkSize)
|
byteFrame = pipe.stdout.read(self.chunkSize)
|
||||||
closePipe(pipe)
|
closePipe(pipe)
|
||||||
|
|
||||||
frame = finalizeFrame(self, byteFrame, width, height)
|
frame = self.finalizeFrame(byteFrame)
|
||||||
return frame
|
return frame
|
||||||
|
|
||||||
def makeFfmpegFilter(self):
|
def makeFfmpegFilter(self, preview=False, startPt=0):
|
||||||
w, h = scale(self.scale, self.width, self.height, str)
|
w, h = scale(self.scale, self.width, self.height, str)
|
||||||
|
if self.amplitude == 0:
|
||||||
|
amplitude = 'lin'
|
||||||
|
elif self.amplitude == 1:
|
||||||
|
amplitude = 'log'
|
||||||
|
elif self.amplitude == 2:
|
||||||
|
amplitude = 'sqrt'
|
||||||
|
elif self.amplitude == 3:
|
||||||
|
amplitude = 'cbrt'
|
||||||
|
hexcolor = QColor(*self.color).name()
|
||||||
|
opacity = "{0:.1f}".format(self.opacity / 100)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'-filter_complex',
|
'-filter_complex',
|
||||||
'[0:a] showwaves=s=%sx%s:mode=%s,format=rgba [v]' % (
|
'[0:a] %s%s'
|
||||||
w, h, self.mode,
|
'showwaves=r=30:s=%sx%s:mode=%s:colors=%s@%s:scale=%s%s%s [v1]; '
|
||||||
|
'[v1] scale=%s:%s%s [v]' % (
|
||||||
|
'compand=gain=2,' if self.compress else '',
|
||||||
|
'aformat=channel_layouts=mono,' if self.mono else '',
|
||||||
|
self.settings.value("outputWidth"),
|
||||||
|
self.settings.value("outputHeight"),
|
||||||
|
str(self.page.comboBox_mode.currentText()).lower(),
|
||||||
|
hexcolor, opacity, amplitude,
|
||||||
|
', drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=4:color=%s@%s' % (
|
||||||
|
hexcolor, opacity
|
||||||
|
) if self.mode < 2 else '',
|
||||||
|
', hflip' if self.mirror else'',
|
||||||
|
w, h,
|
||||||
|
', trim=duration=%s' % "{0:.3f}".format(startPt + 1) if preview else '',
|
||||||
),
|
),
|
||||||
'-map', '[v]',
|
'-map', '[v]',
|
||||||
'-map', '0:a',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
def updateChunksize(self):
|
def updateChunksize(self):
|
||||||
if self.scale != 100:
|
|
||||||
width, height = scale(self.scale, self.width, self.height, int)
|
width, height = scale(self.scale, self.width, self.height, int)
|
||||||
else:
|
|
||||||
width, height = self.width, self.height
|
|
||||||
self.chunkSize = 4 * width * height
|
self.chunkSize = 4 * width * height
|
||||||
|
|
||||||
|
def finalizeFrame(self, imageData):
|
||||||
def scale(scale, width, height, returntype=None):
|
image = Image.frombytes(
|
||||||
width = (float(width) / 100.0) * float(scale)
|
'RGBA',
|
||||||
height = (float(height) / 100.0) * float(scale)
|
scale(self.scale, self.width, self.height, int),
|
||||||
if returntype == str:
|
imageData
|
||||||
return (str(math.ceil(width)), str(math.ceil(height)))
|
)
|
||||||
elif returntype == int:
|
|
||||||
return (math.ceil(width), math.ceil(height))
|
|
||||||
else:
|
|
||||||
return (width, height)
|
|
||||||
|
|
||||||
|
|
||||||
def finalizeFrame(self, imageData, width, height):
|
|
||||||
# frombytes goes here
|
|
||||||
if self.scale != 100 \
|
if self.scale != 100 \
|
||||||
or self.x != 0 or self.y != 0:
|
or self.x != 0 or self.y != 0:
|
||||||
frame = BlankFrame(width, height)
|
frame = BlankFrame(self.width, self.height)
|
||||||
frame.paste(image, box=(self.x, self.y))
|
frame.paste(image, box=(self.x, self.y))
|
||||||
else:
|
else:
|
||||||
frame = image
|
frame = image
|
||||||
|
|
|
@ -226,9 +226,31 @@
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="checkBox_mirror">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Mirror</string>
|
<string>Opacity</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="spinBox_opacity">
|
||||||
|
<property name="buttonSymbols">
|
||||||
|
<enum>QAbstractSpinBox::UpDownArrows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>400</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>100</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -263,6 +285,75 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_compress">
|
||||||
|
<property name="text">
|
||||||
|
<string>Compress</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_mono">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mono</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="checkBox_mirror">
|
||||||
|
<property name="text">
|
||||||
|
<string>Mirror</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Amplitude</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox_amplitude">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Linear</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Logarithmic</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Square root</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cubic root</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
|
|
@ -6,22 +6,9 @@ import string
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import signal
|
|
||||||
import math
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
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(math.ceil(width)), str(math.ceil(height)))
|
|
||||||
elif returntype == int:
|
|
||||||
return (math.ceil(width), math.ceil(height))
|
|
||||||
else:
|
|
||||||
return (width, height)
|
|
||||||
|
|
||||||
|
|
||||||
def badName(name):
|
def badName(name):
|
||||||
'''Returns whether a name contains non-alphanumeric chars'''
|
'''Returns whether a name contains non-alphanumeric chars'''
|
||||||
return any([letter in string.punctuation for letter in name])
|
return any([letter in string.punctuation for letter in name])
|
||||||
|
@ -69,14 +56,6 @@ def checkOutput(commandList, **kwargs):
|
||||||
return subprocess.check_output(commandList, **kwargs)
|
return subprocess.check_output(commandList, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@pipeWrapper
|
|
||||||
def openPipe(commandList, **kwargs):
|
|
||||||
return subprocess.Popen(commandList, **kwargs)
|
|
||||||
|
|
||||||
def closePipe(pipe):
|
|
||||||
pipe.stdout.close()
|
|
||||||
pipe.send_signal(signal.SIGINT)
|
|
||||||
|
|
||||||
def disableWhenEncoding(func):
|
def disableWhenEncoding(func):
|
||||||
def decorator(self, *args, **kwargs):
|
def decorator(self, *args, **kwargs):
|
||||||
if self.encoding:
|
if self.encoding:
|
||||||
|
|
|
@ -6,10 +6,12 @@ import sys
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
import signal
|
||||||
from queue import PriorityQueue
|
from queue import PriorityQueue
|
||||||
|
|
||||||
import core
|
import core
|
||||||
from toolkit.common import checkOutput, openPipe
|
from toolkit.common import checkOutput, pipeWrapper
|
||||||
|
from component import ComponentError
|
||||||
|
|
||||||
|
|
||||||
class FfmpegVideo:
|
class FfmpegVideo:
|
||||||
|
@ -60,7 +62,8 @@ class FfmpegVideo:
|
||||||
kwargs['filter_']
|
kwargs['filter_']
|
||||||
)
|
)
|
||||||
self.command.extend([
|
self.command.extend([
|
||||||
'-vcodec', 'rawvideo', '-',
|
'-s:v', '%sx%s' % (self.width, self.height),
|
||||||
|
'-codec:v', 'rawvideo', '-',
|
||||||
])
|
])
|
||||||
|
|
||||||
self.frameBuffer = PriorityQueue()
|
self.frameBuffer = PriorityQueue()
|
||||||
|
@ -85,9 +88,11 @@ class FfmpegVideo:
|
||||||
self.frameBuffer.task_done()
|
self.frameBuffer.task_done()
|
||||||
|
|
||||||
def fillBuffer(self):
|
def fillBuffer(self):
|
||||||
|
import sys
|
||||||
|
print(self.command)
|
||||||
self.pipe = openPipe(
|
self.pipe = openPipe(
|
||||||
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
|
self.command, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.DEVNULL, bufsize=10**8
|
stderr=sys.__stdout__, bufsize=10**8
|
||||||
)
|
)
|
||||||
while True:
|
while True:
|
||||||
if self.parent.canceled:
|
if self.parent.canceled:
|
||||||
|
@ -100,7 +105,7 @@ class FfmpegVideo:
|
||||||
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
|
self.frameBuffer.put((self.frameNo-1, self.lastFrame))
|
||||||
continue
|
continue
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
Video.threadError = ComponentError(self.component, 'video')
|
FfmpegVideo.threadError = ComponentError(self.component, 'video')
|
||||||
break
|
break
|
||||||
|
|
||||||
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
|
self.currentFrame = self.pipe.stdout.read(self.chunkSize)
|
||||||
|
@ -109,6 +114,16 @@ class FfmpegVideo:
|
||||||
self.lastFrame = self.currentFrame
|
self.lastFrame = self.currentFrame
|
||||||
|
|
||||||
|
|
||||||
|
@pipeWrapper
|
||||||
|
def openPipe(commandList, **kwargs):
|
||||||
|
return subprocess.Popen(commandList, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def closePipe(pipe):
|
||||||
|
pipe.stdout.close()
|
||||||
|
pipe.send_signal(signal.SIGINT)
|
||||||
|
|
||||||
|
|
||||||
def findFfmpeg():
|
def findFfmpeg():
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
# The application is frozen
|
# The application is frozen
|
||||||
|
@ -347,7 +362,12 @@ def getAudioDuration(filename):
|
||||||
except subprocess.CalledProcessError as ex:
|
except subprocess.CalledProcessError as ex:
|
||||||
fileInfo = ex.output
|
fileInfo = ex.output
|
||||||
|
|
||||||
|
try:
|
||||||
info = fileInfo.decode("utf-8").split('\n')
|
info = fileInfo.decode("utf-8").split('\n')
|
||||||
|
except UnicodeDecodeError as e:
|
||||||
|
print('Unicode error:', str(e))
|
||||||
|
return False
|
||||||
|
|
||||||
for line in info:
|
for line in info:
|
||||||
if 'Duration' in line:
|
if 'Duration' in line:
|
||||||
d = line.split(',')[0]
|
d = line.split(',')[0]
|
||||||
|
|
|
@ -6,6 +6,7 @@ from PIL import Image
|
||||||
from PIL.ImageQt import ImageQt
|
from PIL.ImageQt import ImageQt
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import math
|
||||||
|
|
||||||
import core
|
import core
|
||||||
|
|
||||||
|
@ -41,6 +42,17 @@ class PaintColor(QtGui.QColor):
|
||||||
super().__init__(b, g, r, a)
|
super().__init__(b, g, r, a)
|
||||||
|
|
||||||
|
|
||||||
|
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(math.ceil(width)), str(math.ceil(height)))
|
||||||
|
elif returntype == int:
|
||||||
|
return (math.ceil(width), math.ceil(height))
|
||||||
|
else:
|
||||||
|
return (width, height)
|
||||||
|
|
||||||
|
|
||||||
def defaultSize(framefunc):
|
def defaultSize(framefunc):
|
||||||
'''Makes width/height arguments optional'''
|
'''Makes width/height arguments optional'''
|
||||||
def decorator(*args):
|
def decorator(*args):
|
||||||
|
|
|
@ -19,9 +19,11 @@ import time
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
from component import ComponentError
|
from component import ComponentError
|
||||||
from toolkit import openPipe
|
|
||||||
from toolkit.ffmpeg import readAudioFile, createFfmpegCommand
|
|
||||||
from toolkit.frame import Checkerboard
|
from toolkit.frame import Checkerboard
|
||||||
|
from toolkit.ffmpeg import (
|
||||||
|
openPipe, readAudioFile,
|
||||||
|
getAudioDuration, createFfmpegCommand
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Worker(QtCore.QObject):
|
class Worker(QtCore.QObject):
|
||||||
|
@ -132,7 +134,10 @@ class Worker(QtCore.QObject):
|
||||||
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
|
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
|
||||||
# READ AUDIO, INITIALIZE COMPONENTS, OPEN A PIPE TO FFMPEG
|
# READ AUDIO, INITIALIZE COMPONENTS, OPEN A PIPE TO FFMPEG
|
||||||
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
|
# =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~
|
||||||
|
if any([
|
||||||
|
True if 'pcm' in comp.properties() else False
|
||||||
|
for comp in self.components
|
||||||
|
]):
|
||||||
self.progressBarSetText.emit("Loading audio file...")
|
self.progressBarSetText.emit("Loading audio file...")
|
||||||
audioFileTraits = readAudioFile(
|
audioFileTraits = readAudioFile(
|
||||||
self.inputFile, self
|
self.inputFile, self
|
||||||
|
@ -141,6 +146,12 @@ class Worker(QtCore.QObject):
|
||||||
self.cancelExport()
|
self.cancelExport()
|
||||||
return
|
return
|
||||||
self.completeAudioArray, duration = audioFileTraits
|
self.completeAudioArray, duration = audioFileTraits
|
||||||
|
else:
|
||||||
|
duration = getAudioDuration(self.inputFile)
|
||||||
|
class FakeList:
|
||||||
|
def __len__(self):
|
||||||
|
return int((duration * 44100) + 44100) - 1470
|
||||||
|
self.completeAudioArray = FakeList()
|
||||||
|
|
||||||
self.progressBarUpdate.emit(0)
|
self.progressBarUpdate.emit(0)
|
||||||
self.progressBarSetText.emit("Starting components...")
|
self.progressBarSetText.emit("Starting components...")
|
||||||
|
@ -284,7 +295,10 @@ class Worker(QtCore.QObject):
|
||||||
|
|
||||||
numpy.seterr(all='print')
|
numpy.seterr(all='print')
|
||||||
|
|
||||||
|
try:
|
||||||
self.out_pipe.stdin.close()
|
self.out_pipe.stdin.close()
|
||||||
|
except BrokenPipeError:
|
||||||
|
print('Broken pipe to ffmpeg!')
|
||||||
if self.out_pipe.stderr is not None:
|
if self.out_pipe.stderr is not None:
|
||||||
print(self.out_pipe.stderr.read())
|
print(self.out_pipe.stderr.read())
|
||||||
self.out_pipe.stderr.close()
|
self.out_pipe.stderr.close()
|
||||||
|
|
Reference in New Issue