250 lines
7.2 KiB
Python
Executable file
250 lines
7.2 KiB
Python
Executable file
#!/usr/bin/env python
|
|
"""
|
|
export-video
|
|
Little scrip to export video file for The Internet :D
|
|
"""
|
|
import sys
|
|
import getopt
|
|
import re
|
|
import os
|
|
import subprocess
|
|
import logging
|
|
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
|
|
|
|
|
|
def usage():
|
|
""" Print usage"""
|
|
print("export-video -i input -o output [-d --desinterlace]")
|
|
|
|
params = {
|
|
"desinterlace": False,
|
|
"file_output": "",
|
|
"file_input": "",
|
|
"vbitrate": "600k",
|
|
"abitrate": "96k",
|
|
"h264_vcommand": [
|
|
"-trellis", "0",
|
|
"-me_method", "umh",
|
|
"-subq", "8",
|
|
"-me_range", "16",
|
|
"-bf", "3",
|
|
"-rc_lookahead", "16",
|
|
"-g", "250"
|
|
],
|
|
"h264_acommand": ["-strict", "experimental"],
|
|
"webm_vcommand": [
|
|
"-rc_lookahead", "16",
|
|
"-keyint_min", "0"
|
|
"-g", "250",
|
|
"-skip_threshold", "0",
|
|
"-level", "116"
|
|
],
|
|
"webm_acommand": ["-strict", "experimental"],
|
|
"verbose": True,
|
|
"pattern": "",
|
|
"twopass": False,
|
|
"recursive": False}
|
|
|
|
VERSION = "0.1dev"
|
|
|
|
|
|
def execute(command, shell=False):
|
|
"""
|
|
Execute a system command and return its results.
|
|
Thanxx Strycote from Lutris.net
|
|
"""
|
|
try:
|
|
stdout, stderr = subprocess.Popen(command,
|
|
shell=shell,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE).communicate()
|
|
except OSError as ex:
|
|
logging.error('Could not run command %s: %s', command, ex)
|
|
return
|
|
return stdout.strip()
|
|
|
|
|
|
def find_executable(exec_name):
|
|
"""
|
|
find executable with which command
|
|
exec_name (string) : executable to find
|
|
"""
|
|
if not exec_name:
|
|
raise ValueError("find_executable: exec_name required")
|
|
return execute(['which', exec_name])
|
|
|
|
|
|
def list_file(directory, pattern, recursive):
|
|
"""
|
|
list files from a directory
|
|
directory (string) : source directory
|
|
pattern (string) : regex used to found files
|
|
recursive (boolean) : should i serach on sub-folder?
|
|
"""
|
|
logging.info('searching in directory %s', directory)
|
|
files_list = []
|
|
try:
|
|
dirs = os.listdir(directory)
|
|
except OSError:
|
|
logging.error('error : %s not a directory?', directory)
|
|
return
|
|
|
|
for i in dirs:
|
|
logging.debug(' working on file / dir %s', i)
|
|
if os.path.isdir(directory + "/" + i) and recursive:
|
|
logging.info('directory found : %s', i)
|
|
files_list.extend(list_file(
|
|
directory + "/" + i,
|
|
pattern,
|
|
recursive
|
|
))
|
|
else:
|
|
if re.search(pattern, i) is not None:
|
|
logging.info('file found : %s', i)
|
|
files_list.append(directory + "/" + i)
|
|
return files_list
|
|
|
|
|
|
def get_file_name(path):
|
|
"""
|
|
find basename without extension
|
|
path (string) : complete path + file
|
|
"""
|
|
return os.path.splitext(os.path.basename(path))[0]
|
|
|
|
|
|
def process_arg(sysarg):
|
|
"""
|
|
Process arguments
|
|
sysarg (list) : list of arguments
|
|
"""
|
|
try:
|
|
opts, args = getopt.getopt(
|
|
sysarg, "hi:o:dp:a:v:2",
|
|
[
|
|
"help",
|
|
"input=",
|
|
"output=",
|
|
"desinterlace",
|
|
"pattern=",
|
|
"abitrate=",
|
|
"vbitrate=",
|
|
"twopass"
|
|
]
|
|
)
|
|
except getopt.GetoptError:
|
|
usage()
|
|
sys.exit(2)
|
|
for opt, arg in opts:
|
|
if opt in ("-h", "--help"):
|
|
usage()
|
|
sys.exit()
|
|
if opt in ("-o", "--output"):
|
|
params["file_output"] = arg
|
|
if opt in ("-d", "--desinterlace"):
|
|
logging.info("Desinterlace activated")
|
|
params["h264_vcommand"] += ["-vf", "yadif"]
|
|
params["webm_vcommand"] += ["-vf", "yadif"]
|
|
if opt in ("-i", "--input"):
|
|
params["file_input"] = arg
|
|
if opt in ("-p", "--pattern"):
|
|
params["pattern"] = "^\\w*."+arg+"$"
|
|
if opt in ("-a", "--abitrate"):
|
|
params["abitrate"] = arg
|
|
if opt in ("-v", "--vbitrate"):
|
|
params["vbitrate"] = arg
|
|
if opt in ("-2", "--twopass"):
|
|
params["twopass"] = True
|
|
if opt in ("-r", "--recursive"):
|
|
params["recursive"] = True
|
|
|
|
|
|
def encode_h264(src, dest):
|
|
""" Encode file
|
|
src (string) : source video file
|
|
dest (string) : destination file
|
|
"""
|
|
if params["twopass"]:
|
|
logging.debug("two pass encoding started ...")
|
|
firstpass = [
|
|
EXEC_FFMPEG,
|
|
"-y",
|
|
"-i", src,
|
|
"-codec:va", "libx264",
|
|
"-b:v", params["vbitrate"],
|
|
"-pass", "1",
|
|
] + params["h264_vcommand"] + [
|
|
"-f", "rawvideo",
|
|
"/dev/null"
|
|
]
|
|
secondpass = [
|
|
EXEC_FFMPEG,
|
|
"-i", src,
|
|
"-pass", "2",
|
|
"-codec:v", "libx264",
|
|
"-b:v ", params["vbitrate"]
|
|
] + params["h264_vcommand"] + [
|
|
"-b:a", params["abitrate"]
|
|
] + params["h264_acommand"] + [
|
|
dest+".mp4"
|
|
]
|
|
logging.debug("First Pass command %s", firstpass)
|
|
execute(firstpass)
|
|
logging.debug("Second pass command %s", secondpass)
|
|
execute(secondpass)
|
|
else:
|
|
logging.debug("one pass encoding started ...")
|
|
encode = [
|
|
EXEC_FFMPEG,
|
|
"-i", src,
|
|
"-codec:v", "libx264",
|
|
"-b:v ", params["vbitrate"]
|
|
] + params["h264_vcommand"] + [
|
|
"-b:a", params["abitrate"]
|
|
] + params["h264_acommand"] + [
|
|
dest+".mp4",
|
|
]
|
|
logging.debug(encode)
|
|
execute(encode)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
EXEC_FFMPEG = find_executable("ffmpeg")
|
|
if not EXEC_FFMPEG:
|
|
print('ffmpeg not found, exiting')
|
|
sys.exit(2)
|
|
process_arg(sys.argv[1:])
|
|
if not params["file_input"]:
|
|
print("you must specify a file / directory input")
|
|
sys.exit(2)
|
|
if os.path.isdir(params["file_input"]):
|
|
if os.path.isfile(params["file_output"]):
|
|
print("Can't batch export to a single file! Bye Bye")
|
|
sys.exit(2)
|
|
logging.info('%s is a directory', params["file_input"])
|
|
video_files = list_file(
|
|
params["file_input"],
|
|
params["pattern"],
|
|
params["recursive"]
|
|
)
|
|
for f in video_files:
|
|
logging.info('batch encode | file %s', f)
|
|
encode_h264(f, os.path.join(
|
|
params["file_output"], get_file_name(f)
|
|
))
|
|
else:
|
|
if os.path.isfile(params["file_input"]):
|
|
if not params["file_output"]:
|
|
params["file_output"] = get_file_name(params["file_input"])
|
|
else:
|
|
if os.path.isdir(params["file_output"]):
|
|
params["file_input"] = os.path.join(
|
|
params["file_input"],
|
|
get_file_name(params["file_input"])
|
|
)
|
|
logging.info('%s is a file', params["file_input"])
|
|
encode_h264(params["file_input"], params["file_output"])
|
|
else:
|
|
logging.info("input file desn't exist, bye bye")
|
|
sys.exit(2)
|
|
sys.exit(0)
|