video_thread.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. from PyQt5 import QtCore, QtGui, uic
  2. from PyQt5.QtCore import pyqtSignal, pyqtSlot
  3. from PIL import Image, ImageDraw, ImageFont
  4. from PIL.ImageQt import ImageQt
  5. import core
  6. import numpy
  7. import subprocess as sp
  8. import sys
  9. class Worker(QtCore.QObject):
  10. videoCreated = pyqtSignal()
  11. progressBarUpdate = pyqtSignal(int)
  12. progressBarSetText = pyqtSignal(str)
  13. def __init__(self, parent=None):
  14. QtCore.QObject.__init__(self)
  15. parent.videoTask.connect(self.createVideo)
  16. self.core = core.Core()
  17. @pyqtSlot(str, str, QtGui.QFont, int, int, int, int, tuple, tuple, str, str)
  18. def createVideo(self, backgroundImage, titleText, titleFont, fontSize, alignment,\
  19. xOffset, yOffset, textColor, visColor, inputFile, outputFile):
  20. # print('worker thread id: {}'.format(QtCore.QThread.currentThreadId()))
  21. def getBackgroundAtIndex(i):
  22. return self.core.drawBaseImage(
  23. backgroundFrames[i] if len(backgroundFrames)>0 else '',
  24. titleText,
  25. titleFont,
  26. fontSize,
  27. alignment,
  28. xOffset,
  29. yOffset,
  30. textColor,
  31. visColor)
  32. progressBarValue = 0
  33. self.progressBarUpdate.emit(progressBarValue)
  34. self.progressBarSetText.emit('Loading background image…')
  35. backgroundFrames = self.core.parseBaseImage(backgroundImage)
  36. if len(backgroundFrames) < 2:
  37. # the base image is not a video so we can draw it now
  38. imBackground = getBackgroundAtIndex(0)
  39. else:
  40. # base images will be drawn while drawing the audio bars
  41. imBackground = None
  42. self.progressBarSetText.emit('Loading audio file…')
  43. completeAudioArray = self.core.readAudioFile(inputFile)
  44. # test if user has libfdk_aac
  45. encoders = sp.check_output(self.core.FFMPEG_BIN + " -encoders -hide_banner", shell=True)
  46. if b'libfdk_aac' in encoders:
  47. acodec = 'libfdk_aac'
  48. else:
  49. acodec = 'aac'
  50. ffmpegCommand = [ self.core.FFMPEG_BIN,
  51. '-y', # (optional) means overwrite the output file if it already exists.
  52. '-f', 'rawvideo',
  53. '-vcodec', 'rawvideo',
  54. '-s', '1280x720', # size of one frame
  55. '-pix_fmt', 'rgb24',
  56. '-r', '30', # frames per second
  57. '-i', '-', # The input comes from a pipe
  58. '-an',
  59. '-i', inputFile,
  60. '-acodec', acodec, # output audio codec
  61. '-b:a', "192k",
  62. '-vcodec', "libx264",
  63. '-pix_fmt', "yuv420p",
  64. '-preset', "medium",
  65. '-f', "mp4"]
  66. if acodec == 'aac':
  67. ffmpegCommand.append('-strict')
  68. ffmpegCommand.append('-2')
  69. ffmpegCommand.append(outputFile)
  70. out_pipe = sp.Popen(ffmpegCommand,
  71. stdin=sp.PIPE,stdout=sys.stdout, stderr=sys.stdout)
  72. smoothConstantDown = 0.08
  73. smoothConstantUp = 0.8
  74. lastSpectrum = None
  75. sampleSize = 1470
  76. numpy.seterr(divide='ignore')
  77. bgI = 0
  78. for i in range(0, len(completeAudioArray), sampleSize):
  79. # create video for output
  80. lastSpectrum = self.core.transformData(
  81. i,
  82. completeAudioArray,
  83. sampleSize,
  84. smoothConstantDown,
  85. smoothConstantUp,
  86. lastSpectrum)
  87. if imBackground != None:
  88. im = self.core.drawBars(lastSpectrum, imBackground, visColor)
  89. else:
  90. im = self.core.drawBars(lastSpectrum, getBackgroundAtIndex(bgI), visColor)
  91. if bgI < len(backgroundFrames)-1:
  92. bgI += 1
  93. # write to out_pipe
  94. try:
  95. out_pipe.stdin.write(im.tobytes())
  96. finally:
  97. True
  98. # increase progress bar value
  99. if progressBarValue + 1 <= (i / len(completeAudioArray)) * 100:
  100. progressBarValue = numpy.floor((i / len(completeAudioArray)) * 100)
  101. self.progressBarUpdate.emit(progressBarValue)
  102. self.progressBarSetText.emit('%s%%' % str(int(progressBarValue)))
  103. numpy.seterr(all='print')
  104. out_pipe.stdin.close()
  105. if out_pipe.stderr is not None:
  106. print(out_pipe.stderr.read())
  107. out_pipe.stderr.close()
  108. # out_pipe.terminate() # don't terminate ffmpeg too early
  109. out_pipe.wait()
  110. print("Video file created")
  111. self.core.deleteTempDir()
  112. self.progressBarUpdate.emit(100)
  113. self.progressBarSetText.emit('100%')
  114. self.videoCreated.emit()