Added gpu support, error handling, and better output
This commit is contained in:
204
ffmpeg-files.py
204
ffmpeg-files.py
@@ -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()
|
||||
audio = askForAudioOutput()
|
||||
convertFilesInImport()
|
||||
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)
|
||||
Reference in New Issue
Block a user