Added gpu support, error handling, and better output

This commit is contained in:
2020-12-22 16:02:46 -05:00
parent 648306682f
commit a656377feb

View File

@@ -1,51 +1,137 @@
import os
import sys
import traceback
import subprocess
def clearScreen():
os.system('cls' if os.name == 'nt' else 'clear')
def convertFilesInImport():
for filename in os.listdir('input'):
print(f"{getInputPath()}{filename}")
frame_rate_string = getFrameRate(f"{getInputPath()}{filename}")
width = int(getWidth(f"{getInputPath()}{filename}"))
height = int(getHeight(f"{getInputPath()}{filename}"))
frame_rate = eval(frame_rate_string)
print(f"Frame rate is: {frame_rate}")
print(f"Width is: {width}")
print(f"Height is: {height}")
if width > height:
bitrate = getRecommendedBitrateSetting(width,frame_rate)
else:
bitrate = getRecommendedBitrateSetting(height,frame_rate)
print(f"Recommended bitrate: {bitrate}")
current_bitrate = int(getBitrate(f"{getInputPath()}{filename}"))
if current_bitrate < bitrate:
print(f"Current bitrate of {current_bitrate} is less than recommended. Using {current_bitrate}")
print("Converting now...")
#os.path.splitext(filename)[0] gets ride of file extension
#yadiff is for deinterlace
ffmpegcmd = getFfmpegPath() + " -i " + getInputPath() + filename + " -vf yadif -b " + getBitrateSetting() + " -minrate " + getBitrateSetting() + " -maxrate " + getBitrateSetting() + " -bufsize " + getBitrateSetting() + " -vcodec libx264" + getAudioSetting() + " -y " + getOutputPath() + os.path.splitext(filename)[0] + ".mp4"
os.system(ffmpegcmd)
#Windows and Linux have different nulls. Windows null and Linux /dev/null
FNULL = open(os.devnull, 'w')
ffmpegcmd_nvidia = getFfmpegExe() + " -i " + getInputPath() + filename + " -vf yadif -b " + str(bitrate) + " -minrate " + str(bitrate) + " -maxrate " + str(bitrate) + " -bufsize " + str(bitrate) + " -vcodec h264_nvenc " + getAudioSetting() + " -y " + getOutputPath() + os.path.splitext(filename)[0] + ".mp4"
# shell=True is not safe but needs used because I do not comma separate the commmand like:
# ["ffmpeg.exe", "-i", "etc"]
process = subprocess.Popen(ffmpegcmd_nvidia, stdout=FNULL, stderr=FNULL, shell=True)
process.communicate()[0]
if process.returncode != 0:
print("Using Nvidia gpu failed... Trying Intel.")
ffmpegcmd_intel = ffmpegcmd_nvidia.replace("h264_nvenc", "h264_qsv")
else:
continue
process = subprocess.Popen(ffmpegcmd_intel, stdout=FNULL, stderr=FNULL, shell=True)
process.communicate()[0]
if process.returncode != 0:
print("Using Intel gpu failed... Trying CPU.")
ffmpegcmd = ffmpegcmd_nvidia.replace("h264_qsv", "h264")
else:
continue
process = subprocess.Popen(ffmpegcmd, stdout=FNULL, stderr=FNULL, shell=True)
process.communicate()[0]
if process.returncode != 0:
raise Exception('There was an error running ffmpeg.')
def getFrameRate(file):
ffprobe_args = "-v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate"
ffprobe_exe = getFfprobeExe()
ffprobe_command = f"{ffprobe_exe} {ffprobe_args} {file}"
# popen then .read() allows setting stdout to a variable
return os.popen(ffprobe_command).read()
def getWidth(file):
ffprobe_args = "-v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=width"
ffprobe_exe = getFfprobeExe()
ffprobe_command = f"{ffprobe_exe} {ffprobe_args} {file}"
# popen then .read() allows setting stdout to a variable
return os.popen(ffprobe_command).read()
def getHeight(file):
ffprobe_args = "-v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=height"
ffprobe_exe = getFfprobeExe()
ffprobe_command = f"{ffprobe_exe} {ffprobe_args} {file}"
# popen then .read() allows setting stdout to a variable
return os.popen(ffprobe_command).read()
def getBitrate(file):
ffprobe_args = "-v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=bit_rate"
ffprobe_exe = getFfprobeExe()
ffprobe_command = f"{ffprobe_exe} {ffprobe_args} {file}"
# popen then .read() allows setting stdout to a variable
return os.popen(ffprobe_command).read()
def getFfmpegPath():
if(os.name == "nt"):
return "ffmpeg\\windows\\ffmpeg.exe"
if(sys.platform == "win32"):
return "ffmpeg\\windows"
elif(sys.platform == "darwin"):
return "ffmpeg/osx/ffmpeg"
return "ffmpeg/osx"
else:
# Linux sys.platform returns 'linux'
returnErrorAndExit("Your os is not supported. Try using Windows or OSX")
def getFfmpegExe():
path = getFfmpegPath()
if(sys.platform == "win32"):
return f"{path}\\ffmpeg.exe"
else:
return f"{path}/ffmpeg"
def getFfprobeExe():
path = getFfmpegPath()
if(sys.platform == "win32"):
return f"{path}\\ffprobe.exe"
else:
return f"{path}/ffprobe"
def getOutputPath():
if(os.name == "nt"):
if(sys.platform == "win32"):
return "output\\"
else:
return "output/"
def getInputPath():
if(os.name == "nt"):
if(sys.platform == "win32"):
return "input\\"
else:
return "input/"
def askForResolution():
inputresolution = "0"
while(inputresolution != "1" and inputresolution != "2" and inputresolution != "3" and inputresolution != "4" and inputresolution != "5" and inputresolution != "6" and inputresolution != "7" and inputresolution != "8"):
clearScreen()
print("Tell me about your source video.")
print("1. 4k at a slow frame rate (24, 25, 30)")
print("2. 1080p at a slow frame rate (24, 25, 30)")
print("3. 720p at a slow frame rate (24, 25, 30)")
print("4. 480p at a slow frame rate (24, 25, 30)")
print("5. 4k at a fast frame rate (48, 50, 60)")
print("6. 1080p at a fast frame rate (48, 50, 60)")
print("7. 720p at a fast frame rate (48, 50, 60)")
print("8. 480p at a fast frame rate (48, 50, 60)")
inputresolution = input("Please enter a number from above: ")
return inputresolution
# def askForResolution():
# inputresolution = "0"
# while(inputresolution != "1" and inputresolution != "2" and inputresolution != "3" and inputresolution != "4" and inputresolution != "5" and inputresolution != "6" and inputresolution != "7" and inputresolution != "8"):
# clearScreen()
# print("Tell me about your source video.")
# print("1. 4k at a slow frame rate (24, 25, 30)")
# print("2. 1080p at a slow frame rate (24, 25, 30)")
# print("3. 720p at a slow frame rate (24, 25, 30)")
# print("4. 480p at a slow frame rate (24, 25, 30)")
# print("5. 4k at a fast frame rate (48, 50, 60)")
# print("6. 1080p at a fast frame rate (48, 50, 60)")
# print("7. 720p at a fast frame rate (48, 50, 60)")
# print("8. 480p at a fast frame rate (48, 50, 60)")
# inputresolution = input("Please enter a number from above: ")
# return inputresolution
def askForAudioOutput():
audioOutput = "0"
@@ -59,32 +145,42 @@ def askForAudioOutput():
audioOutput = input("Please enter a number from above: ")
return audioOutput
def getBitrateSetting():
def getRecommendedBitrateSetting(longest_side,frame_rate):
# Bitrates recommended from YouTube: https://support.google.com/youtube/answer/1722171?hl=en
# 4k 24, 25,30 fps
if(resolution == "1"):
return "40000k"
# 1080p 24, 25,30 fps
elif(resolution == "2"):
return "8000k"
# 720p 24, 25,30 fps
elif(resolution == "3"):
return "5000k"
# 480p 24, 25,30 fps
elif(resolution == "4"):
return "2500k"
# 4k 48, 50, 60 fps
elif(resolution == "5"):
return "55000k"
# 1080p 48, 50, 60 fps
elif(resolution == "6"):
return "12000k"
# 720p 48, 50, 60 fps
elif(resolution == "7"):
return "7500k"
# 480p 48, 50, 60 fps
elif(resolution == "8"):
return "4000k"
if frame_rate <= 30:
if longest_side > 1920:
# 4k size
# 40,000k bitrate
return 40000000
elif longest_side > 1280:
# 1080p size
# 8000k bitrate
return 8000000
elif longest_side > 852:
# 720p size
# 5000k bitrate
return 5000000
else:
# 480p size
# 2500k bitrate
return 2500000
else:
if longest_side > 1920:
# 4k size
# 55,000k bitrate
return 55000000
elif longest_side > 1280:
# 1080p size
# 12,000k bitrate
return 12000000
elif longest_side > 852:
# 720p size
# 7500k bitrate
return 7500000
else:
# 480p size
# 4000k bitrate
return 4000000
def getAudioSetting():
if(audio == "1"):
@@ -99,9 +195,15 @@ def getAudioSetting():
def returnErrorAndExit(message):
input(message)
sys.exit()
sys.exit(1)
#Run Program
resolution = askForResolution()
try:
# resolution = askForResolution()
audio = askForAudioOutput()
convertFilesInImport()
input("Done. Press enter to exit.")
except Exception:
print(traceback.print_exc())
input("Press enter to exit.")
sys.exit(1)