This repository has been archived on 2020-08-22. You can view files and clone it, but cannot push or open issues or pull requests.
pyaudviz/core.py

153 lines
4.5 KiB
Python
Raw Normal View History

import sys, io, os
2015-03-02 16:47:52 -05:00
from PyQt4 import QtCore, QtGui, uic
from os.path import expanduser
import subprocess as sp
import numpy
from PIL import Image
import tempfile
from shutil import rmtree
import atexit
import time
2015-03-02 16:47:52 -05:00
class Core():
def __init__(self):
self.lastBackgroundImage = ""
self._image = None
self.FFMPEG_BIN = self.findFfmpeg()
self.tempDir = None
atexit.register(self.deleteTempDir)
def findFfmpeg(self):
2015-03-02 16:47:52 -05:00
if sys.platform == "win32":
return "ffmpeg.exe"
2015-03-02 16:47:52 -05:00
else:
try:
with open(os.devnull, "w") as f:
sp.check_call(['ffmpeg', '-version'], stdout=f, stderr=f)
return "ffmpeg"
except:
return "avconv"
2015-03-02 16:47:52 -05:00
def parseBaseImage(self, backgroundImage, preview=False):
''' determines if the base image is a single frame or list of frames '''
2015-03-02 16:47:52 -05:00
if backgroundImage == "":
return ['']
2015-03-02 16:47:52 -05:00
else:
_, bgExt = os.path.splitext(backgroundImage)
if not bgExt == '.mp4':
return [backgroundImage]
else:
return self.getVideoFrames(backgroundImage, preview)
def drawBaseImage(self, backgroundFile):
if backgroundFile == '':
im = Image.new("RGB", (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), "black")
else:
im = Image.open(backgroundFile)
if self._image == None or not self.lastBackgroundImage == backgroundFile:
self.lastBackgroundImage = backgroundFile
2015-03-02 16:47:52 -05:00
# resize if necessary
if not im.size == (int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))):
im = im.resize((int(self.settings.value('outputWidth')), int(self.settings.value('outputHeight'))), Image.ANTIALIAS)
2015-03-02 16:47:52 -05:00
return im
2017-06-02 04:30:51 -04:00
def readAudioFile(self, filename, parent):
command = [ self.FFMPEG_BIN,
'-i', filename]
try:
fileInfo = sp.check_output(command, stderr=sp.STDOUT, shell=False)
except sp.CalledProcessError as ex:
fileInfo = ex.output
pass
info = fileInfo.decode("utf-8").split('\n')
for line in info:
if 'Duration' in line:
d = line.split(',')[0]
d = d.split(' ')[3]
d = d.split(':')
duration = float(d[0])*3600 + float(d[1])*60 + float(d[2])
2015-03-02 16:47:52 -05:00
command = [ self.FFMPEG_BIN,
'-i', filename,
'-f', 's16le',
'-acodec', 'pcm_s16le',
'-ar', '44100', # ouput will have 44100 Hz
'-ac', '1', # mono (set to '2' for stereo)
'-']
in_pipe = sp.Popen(command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8)
2015-03-02 16:47:52 -05:00
completeAudioArray = numpy.empty(0, dtype="int16")
2017-06-02 04:30:51 -04:00
progress = 0
lastPercent = None
2015-03-02 16:47:52 -05:00
while True:
if self.canceled:
break
2015-03-02 16:47:52 -05:00
# read 2 seconds of audio
2017-06-02 04:30:51 -04:00
progress = progress + 4
2015-03-02 16:47:52 -05:00
raw_audio = in_pipe.stdout.read(88200*4)
if len(raw_audio) == 0:
break
audio_array = numpy.fromstring(raw_audio, dtype="int16")
completeAudioArray = numpy.append(completeAudioArray, audio_array)
2017-06-02 04:30:51 -04:00
percent = int(100*(progress/duration))
if percent >= 100:
percent = 100
if lastPercent != percent:
string = 'Loading audio file: '+str(percent)+'%'
parent.progressBarSetText.emit(string)
parent.progressBarUpdate.emit(percent)
lastPercent = percent
2015-03-02 16:47:52 -05:00
in_pipe.kill()
in_pipe.wait()
# add 0s the end
completeAudioArrayCopy = numpy.zeros(len(completeAudioArray) + 44100, dtype="int16")
completeAudioArrayCopy[:len(completeAudioArray)] = completeAudioArray
completeAudioArray = completeAudioArrayCopy
return completeAudioArray
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)])
def cancel(self):
self.canceled = True
def reset(self):
self.canceled = False