Merge pull request #13 from tassaron2/master

Added the ability to use an mp4 as the background image
This commit is contained in:
martin 2017-05-22 10:47:55 +02:00 committed by GitHub
commit e507cf0b6c
5 changed files with 103 additions and 28 deletions

55
core.py
View File

@ -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,15 +31,25 @@ 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 == "":
return []
else:
_, 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") im = Image.new("RGB", (1280, 720), "black")
else: else:
im = Image.open(backgroundImage) 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):
@ -83,7 +98,6 @@ 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)])

View File

@ -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()

View File

@ -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>

View File

@ -43,8 +43,17 @@ class Worker(QtCore.QObject):
except Empty: except Empty:
continue continue
im = self.core.drawBaseImage( bgImage = self.core.parseBaseImage(\
nextPreviewInformation["backgroundImage"], nextPreviewInformation["backgroundImage"],
preview=True
)
if bgImage == []:
bgImage = ''
else:
bgImage = bgImage[0]
im = self.core.drawBaseImage(
bgImage,
nextPreviewInformation["titleText"], nextPreviewInformation["titleText"],
nextPreviewInformation["titleFont"], nextPreviewInformation["titleFont"],
nextPreviewInformation["fontSize"], nextPreviewInformation["fontSize"],

View File

@ -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,9 +22,9 @@ 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,
@ -31,8 +32,19 @@ class Worker(QtCore.QObject):
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)
if imBackground != None:
im = self.core.drawBars(lastSpectrum, imBackground) 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()