aboutsummaryrefslogtreecommitdiff
path: root/src/core.py
diff options
context:
space:
mode:
authorBrianna2017-07-15 19:40:08 -0400
committerGitHub2017-07-15 19:40:08 -0400
commitf420ad69f5f6f3c830fea890a760ce0ce61ba571 (patch)
tree2a7f9df3eebbae8da4317516f84dfe7490b5d36a /src/core.py
parent94d4acc1f4f4abe4029e8f9c050932b67cae8cec (diff)
parentbcb8f27c2e4434d2296dcd66bf279b76ee0d0a4f (diff)
Merge audio-mixing branch
some basic audio features + more user feedback + merging static components
Diffstat (limited to 'src/core.py')
-rw-r--r--src/core.py135
1 files changed, 132 insertions, 3 deletions
diff --git a/src/core.py b/src/core.py
index 9792e88..4c12209 100644
--- a/src/core.py
+++ b/src/core.py
@@ -11,6 +11,8 @@ from importlib import import_module
from PyQt5.QtCore import QStandardPaths
import toolkit
+from frame import Frame
+import video_thread
class Core:
@@ -20,6 +22,7 @@ class Core:
opens projects and presets, and stores settings/paths to data.
'''
def __init__(self):
+ Frame.core = self
self.dataDir = QStandardPaths.writableLocation(
QStandardPaths.AppConfigLocation
)
@@ -412,6 +415,7 @@ class Core:
f.write('[Components]\n')
for comp in self.selectedComponents:
saveValueStore = comp.savePreset()
+ saveValueStore['preset'] = comp.currentPreset
f.write('%s\n' % str(comp))
f.write('%s\n' % str(comp.version()))
f.write('%s\n' % toolkit.presetToString(saveValueStore))
@@ -460,6 +464,115 @@ class Core:
except sp.CalledProcessError:
return "avconv"
+ def createFfmpegCommand(self, inputFile, outputFile, duration):
+ '''
+ Constructs the major ffmpeg command used to export the video
+ '''
+ duration = str(duration)
+
+ # Test if user has libfdk_aac
+ encoders = toolkit.checkOutput(
+ "%s -encoders -hide_banner" % self.FFMPEG_BIN, shell=True
+ )
+ encoders = encoders.decode("utf-8")
+
+ acodec = self.settings.value('outputAudioCodec')
+
+ options = self.encoder_options
+ containerName = self.settings.value('outputContainer')
+ vcodec = self.settings.value('outputVideoCodec')
+ vbitrate = str(self.settings.value('outputVideoBitrate'))+'k'
+ acodec = self.settings.value('outputAudioCodec')
+ abitrate = str(self.settings.value('outputAudioBitrate'))+'k'
+
+ for cont in options['containers']:
+ if cont['name'] == containerName:
+ container = cont['container']
+ break
+
+ vencoders = options['video-codecs'][vcodec]
+ aencoders = options['audio-codecs'][acodec]
+
+ for encoder in vencoders:
+ if encoder in encoders:
+ vencoder = encoder
+ break
+
+ for encoder in aencoders:
+ if encoder in encoders:
+ aencoder = encoder
+ break
+
+ ffmpegCommand = [
+ self.FFMPEG_BIN,
+ '-thread_queue_size', '512',
+ '-y', # overwrite the output file if it already exists.
+
+ # INPUT VIDEO
+ '-f', 'rawvideo',
+ '-vcodec', 'rawvideo',
+ '-s', '%sx%s' % (
+ self.settings.value('outputWidth'),
+ self.settings.value('outputHeight'),
+ ),
+ '-pix_fmt', 'rgba',
+ '-r', self.settings.value('outputFrameRate'),
+ '-t', duration,
+ '-i', '-', # the video input comes from a pipe
+ '-an', # the video input has no sound
+
+ # INPUT SOUND
+ '-t', duration,
+ '-i', inputFile
+ ]
+
+ extraAudio = [
+ comp.audio() for comp in self.selectedComponents
+ if 'audio' in comp.properties()
+ ]
+ if extraAudio:
+ unwantedVideoStreams = []
+ for streamNo, params in enumerate(extraAudio):
+ extraInputFile, params = params
+ ffmpegCommand.extend([
+ '-t', duration,
+ '-i', extraInputFile
+ ])
+ if 'map' in params and params['map'] == '-v':
+ # a video stream to remove
+ unwantedVideoStreams.append(streamNo + 1)
+
+ if unwantedVideoStreams:
+ ffmpegCommand.extend(['-map', '0'])
+ for streamNo in unwantedVideoStreams:
+ ffmpegCommand.extend([
+ '-map', '-%s:v' % str(streamNo)
+ ])
+ ffmpegCommand.extend([
+ '-filter_complex',
+ 'amix=inputs=%s:duration=first:dropout_transition=3' % str(
+ len(extraAudio) + 1
+ ),
+ ])
+
+ ffmpegCommand.extend([
+ # OUTPUT
+ '-vcodec', vencoder,
+ '-acodec', aencoder,
+ '-b:v', vbitrate,
+ '-b:a', abitrate,
+ '-pix_fmt', self.settings.value('outputVideoFormat'),
+ '-preset', self.settings.value('outputPreset'),
+ '-f', container
+ ])
+
+ if acodec == 'aac':
+ ffmpegCommand.append('-strict')
+ ffmpegCommand.append('-2')
+
+ ffmpegCommand.append(outputFile)
+ return ffmpegCommand
+
def readAudioFile(self, filename, parent):
command = [self.FFMPEG_BIN, '-i', filename]
@@ -485,7 +598,8 @@ class Core:
'-ac', '1', # mono (set to '2' for stereo)
'-']
in_pipe = toolkit.openPipe(
- command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8)
+ command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8
+ )
completeAudioArray = numpy.empty(0, dtype="int16")
@@ -495,7 +609,7 @@ class Core:
if self.canceled:
break
# read 2 seconds of audio
- progress = progress + 4
+ progress += 4
raw_audio = in_pipe.stdout.read(88200*4)
if len(raw_audio) == 0:
break
@@ -522,7 +636,22 @@ class Core:
completeAudioArrayCopy[:len(completeAudioArray)] = completeAudioArray
completeAudioArray = completeAudioArrayCopy
- return completeAudioArray
+ return (completeAudioArray, duration)
+
+ def newVideoWorker(self, loader, audioFile, outputPath):
+ self.videoThread = QtCore.QThread(loader)
+ videoWorker = video_thread.Worker(
+ loader, audioFile, outputPath, self.selectedComponents
+ )
+ videoWorker.moveToThread(self.videoThread)
+ videoWorker.videoCreated.connect(self.videoCreated)
+
+ self.videoThread.start()
+ return videoWorker
+
+ def videoCreated(self):
+ self.videoThread.quit()
+ self.videoThread.wait()
def cancel(self):
self.canceled = True