Merge pull request #13 from tassaron2/master
Added the ability to use an mp4 as the background image
This commit is contained in:
commit
e507cf0b6c
61
core.py
61
core.py
|
@ -6,6 +6,9 @@ import subprocess as sp
|
||||||
import numpy
|
import numpy
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
from PIL.ImageQt import ImageQt
|
from PIL.ImageQt import ImageQt
|
||||||
|
import tempfile
|
||||||
|
from shutil import rmtree
|
||||||
|
import atexit
|
||||||
|
|
||||||
class Core():
|
class Core():
|
||||||
|
|
||||||
|
@ -14,6 +17,8 @@ class Core():
|
||||||
self._image = None
|
self._image = None
|
||||||
|
|
||||||
self.FFMPEG_BIN = self.findFfmpeg()
|
self.FFMPEG_BIN = self.findFfmpeg()
|
||||||
|
self.tempDir = None
|
||||||
|
atexit.register(self.deleteTempDir)
|
||||||
|
|
||||||
def findFfmpeg(self):
|
def findFfmpeg(self):
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
|
@ -26,22 +31,32 @@ class Core():
|
||||||
except:
|
except:
|
||||||
return "avconv"
|
return "avconv"
|
||||||
|
|
||||||
def drawBaseImage(self, backgroundImage, titleText, titleFont, fontSize, alignment, xOffset, yOffset):
|
def parseBaseImage(self, backgroundImage, preview=False):
|
||||||
|
''' determines if the base image is a single frame or list of frames '''
|
||||||
if self._image == None or not self.lastBackgroundImage == backgroundImage:
|
|
||||||
self.lastBackgroundImage = backgroundImage
|
|
||||||
|
|
||||||
if backgroundImage == "":
|
if backgroundImage == "":
|
||||||
im = Image.new("RGB", (1280, 720), "black")
|
return []
|
||||||
else:
|
else:
|
||||||
im = Image.open(backgroundImage)
|
_, bgExt = os.path.splitext(backgroundImage)
|
||||||
|
if not bgExt == '.mp4':
|
||||||
|
return [backgroundImage]
|
||||||
|
else:
|
||||||
|
return self.getVideoFrames(backgroundImage, preview)
|
||||||
|
|
||||||
|
def drawBaseImage(self, backgroundFile, titleText, titleFont, fontSize, alignment, xOffset, yOffset):
|
||||||
|
if backgroundFile == '':
|
||||||
|
im = Image.new("RGB", (1280, 720), "black")
|
||||||
|
else:
|
||||||
|
im = Image.open(backgroundFile)
|
||||||
|
|
||||||
|
if self._image == None or not self.lastBackgroundImage == backgroundFile:
|
||||||
|
self.lastBackgroundImage = backgroundFile
|
||||||
|
|
||||||
# resize if necessary
|
# resize if necessary
|
||||||
if not im.size == (1280, 720):
|
if not im.size == (1280, 720):
|
||||||
im = im.resize((1280, 720), Image.ANTIALIAS)
|
im = im.resize((1280, 720), Image.ANTIALIAS)
|
||||||
|
|
||||||
self._image = ImageQt(im)
|
self._image = ImageQt(im)
|
||||||
|
|
||||||
self._image1 = QtGui.QImage(self._image)
|
self._image1 = QtGui.QImage(self._image)
|
||||||
painter = QPainter(self._image1)
|
painter = QPainter(self._image1)
|
||||||
font = titleFont
|
font = titleFont
|
||||||
|
@ -81,9 +96,8 @@ class Core():
|
||||||
|
|
||||||
|
|
||||||
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
|
imBottom = imTop.transpose(Image.FLIP_TOP_BOTTOM)
|
||||||
|
|
||||||
im = Image.new("RGB", (1280, 720), "black")
|
im = Image.new("RGB", (1280, 720), "black")
|
||||||
|
|
||||||
im.paste(image, (0, 0))
|
im.paste(image, (0, 0))
|
||||||
im.paste(imTop, (0, 0), mask=imTop)
|
im.paste(imTop, (0, 0), mask=imTop)
|
||||||
im.paste(imBottom, (0, 360), mask=imBottom)
|
im.paste(imBottom, (0, 360), mask=imBottom)
|
||||||
|
@ -150,3 +164,30 @@ class Core():
|
||||||
x = frequencies[0:int(paddedSampleSize/2) - 1]
|
x = frequencies[0:int(paddedSampleSize/2) - 1]
|
||||||
|
|
||||||
return lastSpectrum
|
return lastSpectrum
|
||||||
|
|
||||||
|
def deleteTempDir(self):
|
||||||
|
if self.tempDir and os.path.exists(self.tempDir):
|
||||||
|
rmtree(self.tempDir)
|
||||||
|
|
||||||
|
|
||||||
|
def getVideoFrames(self, videoPath, firstOnly=False):
|
||||||
|
self.tempDir = os.path.join(tempfile.gettempdir(), 'audio-visualizer-python-data')
|
||||||
|
# recreate the temporary directory so it is empty
|
||||||
|
self.deleteTempDir()
|
||||||
|
os.mkdir(self.tempDir)
|
||||||
|
if firstOnly:
|
||||||
|
filename = 'preview%s.jpg' % os.path.basename(videoPath).split('.', 1)[0]
|
||||||
|
options = '-ss 10 -vframes 1'
|
||||||
|
else:
|
||||||
|
filename = '$frame%05d.jpg'
|
||||||
|
options = ''
|
||||||
|
sp.call( \
|
||||||
|
'%s -i "%s" -y %s "%s"' % ( \
|
||||||
|
self.FFMPEG_BIN,
|
||||||
|
videoPath,
|
||||||
|
options,
|
||||||
|
os.path.join(self.tempDir, filename)
|
||||||
|
),
|
||||||
|
shell=True
|
||||||
|
)
|
||||||
|
return sorted([os.path.join(self.tempDir, f) for f in os.listdir(self.tempDir)])
|
||||||
|
|
6
main.py
6
main.py
|
@ -131,7 +131,7 @@ class Main(QtCore.QObject):
|
||||||
backgroundDir = self.settings.value("backgroundDir", expanduser("~"))
|
backgroundDir = self.settings.value("backgroundDir", expanduser("~"))
|
||||||
|
|
||||||
fileName = QtGui.QFileDialog.getOpenFileName(self.window,
|
fileName = QtGui.QFileDialog.getOpenFileName(self.window,
|
||||||
"Open Background Image", backgroundDir, "Image Files (*.jpg *.png)");
|
"Open Background Image", backgroundDir, "Image Files (*.jpg *.png);; Video Files (*.mp4)");
|
||||||
|
|
||||||
if not fileName == "":
|
if not fileName == "":
|
||||||
self.settings.setValue("backgroundDir", os.path.dirname(fileName))
|
self.settings.setValue("backgroundDir", os.path.dirname(fileName))
|
||||||
|
@ -147,6 +147,7 @@ class Main(QtCore.QObject):
|
||||||
self.videoWorker.moveToThread(self.videoThread)
|
self.videoWorker.moveToThread(self.videoThread)
|
||||||
self.videoWorker.videoCreated.connect(self.videoCreated)
|
self.videoWorker.videoCreated.connect(self.videoCreated)
|
||||||
self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
|
self.videoWorker.progressBarUpdate.connect(self.progressBarUpdated)
|
||||||
|
self.videoWorker.progressBarSetText.connect(self.progressBarSetText)
|
||||||
|
|
||||||
self.videoThread.start()
|
self.videoThread.start()
|
||||||
self.videoTask.emit(self.window.label_background.text(),
|
self.videoTask.emit(self.window.label_background.text(),
|
||||||
|
@ -163,6 +164,9 @@ class Main(QtCore.QObject):
|
||||||
def progressBarUpdated(self, value):
|
def progressBarUpdated(self, value):
|
||||||
self.window.progressBar_create.setValue(value)
|
self.window.progressBar_create.setValue(value)
|
||||||
|
|
||||||
|
def progressBarSetText(self, value):
|
||||||
|
self.window.progressBar_create.setFormat(value)
|
||||||
|
|
||||||
def videoCreated(self):
|
def videoCreated(self):
|
||||||
self.videoThread.quit()
|
self.videoThread.quit()
|
||||||
self.videoThread.wait()
|
self.videoThread.wait()
|
||||||
|
|
5
main.ui
5
main.ui
|
@ -386,7 +386,10 @@
|
||||||
<number>24</number>
|
<number>24</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="textVisible">
|
<property name="textVisible">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<enum>Qt::AlignCenter</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -43,8 +43,17 @@ class Worker(QtCore.QObject):
|
||||||
except Empty:
|
except Empty:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
bgImage = self.core.parseBaseImage(\
|
||||||
|
nextPreviewInformation["backgroundImage"],
|
||||||
|
preview=True
|
||||||
|
)
|
||||||
|
if bgImage == []:
|
||||||
|
bgImage = ''
|
||||||
|
else:
|
||||||
|
bgImage = bgImage[0]
|
||||||
|
|
||||||
im = self.core.drawBaseImage(
|
im = self.core.drawBaseImage(
|
||||||
nextPreviewInformation["backgroundImage"],
|
bgImage,
|
||||||
nextPreviewInformation["titleText"],
|
nextPreviewInformation["titleText"],
|
||||||
nextPreviewInformation["titleFont"],
|
nextPreviewInformation["titleFont"],
|
||||||
nextPreviewInformation["fontSize"],
|
nextPreviewInformation["fontSize"],
|
||||||
|
|
|
@ -11,6 +11,7 @@ class Worker(QtCore.QObject):
|
||||||
|
|
||||||
videoCreated = pyqtSignal()
|
videoCreated = pyqtSignal()
|
||||||
progressBarUpdate = pyqtSignal(int)
|
progressBarUpdate = pyqtSignal(int)
|
||||||
|
progressBarSetText = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
|
@ -21,18 +22,29 @@ class Worker(QtCore.QObject):
|
||||||
@pyqtSlot(str, str, QtGui.QFont, int, int, int, int, str, str)
|
@pyqtSlot(str, str, QtGui.QFont, int, int, int, int, str, str)
|
||||||
def createVideo(self, backgroundImage, titleText, titleFont, fontSize, alignment, xOffset, yOffset, inputFile, outputFile):
|
def createVideo(self, backgroundImage, titleText, titleFont, fontSize, alignment, xOffset, yOffset, inputFile, outputFile):
|
||||||
# print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
|
# print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
|
||||||
|
def getBackgroundAtIndex(i):
|
||||||
imBackground = self.core.drawBaseImage(
|
return self.core.drawBaseImage(
|
||||||
backgroundImage,
|
backgroundFrames[i],
|
||||||
titleText,
|
titleText,
|
||||||
titleFont,
|
titleFont,
|
||||||
fontSize,
|
fontSize,
|
||||||
alignment,
|
alignment,
|
||||||
xOffset,
|
xOffset,
|
||||||
yOffset)
|
yOffset)
|
||||||
|
|
||||||
self.progressBarUpdate.emit(0)
|
progressBarValue = 0
|
||||||
|
self.progressBarUpdate.emit(progressBarValue)
|
||||||
|
self.progressBarSetText.emit('Loading background image…')
|
||||||
|
|
||||||
|
backgroundFrames = self.core.parseBaseImage(backgroundImage)
|
||||||
|
if len(backgroundFrames) < 2:
|
||||||
|
# the base image is not a video so we can draw it now
|
||||||
|
imBackground = getBackgroundAtIndex(0)
|
||||||
|
else:
|
||||||
|
# base images will be drawn while drawing the audio bars
|
||||||
|
imBackground = None
|
||||||
|
|
||||||
|
self.progressBarSetText.emit('Loading audio file…')
|
||||||
completeAudioArray = self.core.readAudioFile(inputFile)
|
completeAudioArray = self.core.readAudioFile(inputFile)
|
||||||
|
|
||||||
# test if user has libfdk_aac
|
# test if user has libfdk_aac
|
||||||
|
@ -71,11 +83,10 @@ class Worker(QtCore.QObject):
|
||||||
smoothConstantDown = 0.08
|
smoothConstantDown = 0.08
|
||||||
smoothConstantUp = 0.8
|
smoothConstantUp = 0.8
|
||||||
lastSpectrum = None
|
lastSpectrum = None
|
||||||
progressBarValue = 0
|
|
||||||
sampleSize = 1470
|
sampleSize = 1470
|
||||||
|
|
||||||
numpy.seterr(divide='ignore')
|
numpy.seterr(divide='ignore')
|
||||||
|
bgI = 0
|
||||||
for i in range(0, len(completeAudioArray), sampleSize):
|
for i in range(0, len(completeAudioArray), sampleSize):
|
||||||
# create video for output
|
# create video for output
|
||||||
lastSpectrum = self.core.transformData(
|
lastSpectrum = self.core.transformData(
|
||||||
|
@ -85,7 +96,12 @@ class Worker(QtCore.QObject):
|
||||||
smoothConstantDown,
|
smoothConstantDown,
|
||||||
smoothConstantUp,
|
smoothConstantUp,
|
||||||
lastSpectrum)
|
lastSpectrum)
|
||||||
im = self.core.drawBars(lastSpectrum, imBackground)
|
if imBackground != None:
|
||||||
|
im = self.core.drawBars(lastSpectrum, imBackground)
|
||||||
|
else:
|
||||||
|
im = self.core.drawBars(lastSpectrum, getBackgroundAtIndex(bgI))
|
||||||
|
if bgI < len(backgroundFrames)-1:
|
||||||
|
bgI += 1
|
||||||
|
|
||||||
# write to out_pipe
|
# write to out_pipe
|
||||||
try:
|
try:
|
||||||
|
@ -97,6 +113,7 @@ class Worker(QtCore.QObject):
|
||||||
if progressBarValue + 1 <= (i / len(completeAudioArray)) * 100:
|
if progressBarValue + 1 <= (i / len(completeAudioArray)) * 100:
|
||||||
progressBarValue = numpy.floor((i / len(completeAudioArray)) * 100)
|
progressBarValue = numpy.floor((i / len(completeAudioArray)) * 100)
|
||||||
self.progressBarUpdate.emit(progressBarValue)
|
self.progressBarUpdate.emit(progressBarValue)
|
||||||
|
self.progressBarSetText.emit('%s%%' % str(int(progressBarValue)))
|
||||||
|
|
||||||
numpy.seterr(all='print')
|
numpy.seterr(all='print')
|
||||||
|
|
||||||
|
@ -108,4 +125,5 @@ class Worker(QtCore.QObject):
|
||||||
out_pipe.wait()
|
out_pipe.wait()
|
||||||
print("Video file created")
|
print("Video file created")
|
||||||
self.progressBarUpdate.emit(100)
|
self.progressBarUpdate.emit(100)
|
||||||
|
self.progressBarSetText.emit('100%')
|
||||||
self.videoCreated.emit()
|
self.videoCreated.emit()
|
||||||
|
|
Reference in New Issue