n900-encode.py v0.2: switched to mencoder for encoding
This commit is contained in:
parent
cc94f36ab8
commit
b82de7f927
1 changed files with 102 additions and 90 deletions
182
n900-encode.py
182
n900-encode.py
|
@ -5,12 +5,16 @@
|
||||||
# Disclaimer: This program is provided without any warranty, USE AT YOUR OWN RISK!
|
# Disclaimer: This program is provided without any warranty, USE AT YOUR OWN RISK!
|
||||||
#
|
#
|
||||||
# (C) 2010 Stefan Brand <seiichiro@seiichiro0185.org>
|
# (C) 2010 Stefan Brand <seiichiro@seiichiro0185.org>
|
||||||
|
#
|
||||||
|
# Version 0.2
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
|
|
||||||
import sys, os, getopt, subprocess, re, atexit
|
import sys, os, getopt, subprocess, re, atexit
|
||||||
from signal import signal, SIGTERM, SIGINT
|
from signal import signal, SIGTERM, SIGINT
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
|
version = "0.2"
|
||||||
|
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
# Default values, feel free to adjust
|
# Default values, feel free to adjust
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
|
@ -18,11 +22,12 @@ from time import sleep
|
||||||
_basewidth = 800 # Base width for widescreen Video
|
_basewidth = 800 # Base width for widescreen Video
|
||||||
_basewidth43 = 640 # Base width for 4:3 Video
|
_basewidth43 = 640 # Base width for 4:3 Video
|
||||||
_maxheight = 480 # maximum height allowed
|
_maxheight = 480 # maximum height allowed
|
||||||
_abitrate = 96 # Audio Bitrate in kBit/s
|
_abitrate = 112 # Audio Bitrate in kBit/s
|
||||||
_vbitrate = 500 # Video Bitrate in kBit/s
|
_vbitrate = 22 # Video Bitrate, if set to value < 52 it is used as a CRF Value for Constant rate factor encoding
|
||||||
_threads = 2 # Use n Threads to encode
|
_threads = 0 # Use n Threads to encode (0 means use number of CPUs / Cores)
|
||||||
_mpbin = None # mplayer binary, if set to None it is searched in your $PATH
|
_mpbin = None # mplayer binary, if set to None it is searched in your $PATH
|
||||||
_ffbin = None # ffmpeg binary, if set to None it is searched in your $PATH
|
_mcbin = None # mencoder binary, if set to None it is searched in your $PATH
|
||||||
|
_m4bin = None # MP4Box binary, if set to None it is searched in your $PATH
|
||||||
|
|
||||||
###########################################################################################
|
###########################################################################################
|
||||||
# Main Program, no changes needed below this line
|
# Main Program, no changes needed below this line
|
||||||
|
@ -41,8 +46,8 @@ def main(argv):
|
||||||
input = None
|
input = None
|
||||||
output = "n900encode.mp4"
|
output = "n900encode.mp4"
|
||||||
mpopts = ""
|
mpopts = ""
|
||||||
abitrate = _abitrate * 1000
|
abitrate = _abitrate
|
||||||
vbitrate = _vbitrate * 1000
|
vbitrate = _vbitrate
|
||||||
threads = _threads
|
threads = _threads
|
||||||
overwrite = False
|
overwrite = False
|
||||||
for opt, arg in opts:
|
for opt, arg in opts:
|
||||||
|
@ -53,9 +58,9 @@ def main(argv):
|
||||||
elif opt in ("-m" "--mpopts"):
|
elif opt in ("-m" "--mpopts"):
|
||||||
mpopts = arg
|
mpopts = arg
|
||||||
elif opt in ("-a", "--abitrate"):
|
elif opt in ("-a", "--abitrate"):
|
||||||
abitrate = int(arg) * 1000
|
abitrate = int(arg)
|
||||||
elif opt in ("-v", "--vbitrate"):
|
elif opt in ("-v", "--vbitrate"):
|
||||||
vbitrate = int(arg) * 1000
|
vbitrate = int(arg)
|
||||||
elif opt in ("-t", "--threads"):
|
elif opt in ("-t", "--threads"):
|
||||||
threads = arg
|
threads = arg
|
||||||
elif opt in ("-f", "--force-overwrite"):
|
elif opt in ("-f", "--force-overwrite"):
|
||||||
|
@ -74,14 +79,24 @@ def main(argv):
|
||||||
print "Error: mplayer not found in PATH and no binary given, Aborting!"
|
print "Error: mplayer not found in PATH and no binary given, Aborting!"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
global ffbin
|
global mcbin
|
||||||
ffbin = None
|
mcbin = None
|
||||||
if not _ffbin == None and os.path.exists(_ffbin) and not os.path.isdir(_ffbin):
|
if not _mcbin == None and os.path.exists(_mcbin) and not os.path.isdir(_mcbin):
|
||||||
ffbin = _ffbin
|
mcbin = _mcbin
|
||||||
else:
|
else:
|
||||||
ffbin = progpath("ffmpeg")
|
mcbin = progpath("mencoder")
|
||||||
if ffbin == None:
|
if mcbin == None:
|
||||||
print "Error: ffmpeg not found in PATH and no binary given, Aborting!"
|
print "Error: mencoder not found in PATH and no binary given, Aborting!"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
global m4bin
|
||||||
|
m4bin = None
|
||||||
|
if not _m4bin == None and os.path.exists(_m4bin) and not os.path.isdir(_m4bin):
|
||||||
|
m4bin = _m4bin
|
||||||
|
else:
|
||||||
|
m4bin = progpath("MP4Box")
|
||||||
|
if m4bin == None:
|
||||||
|
print "Error: mencoder not found in PATH and no binary given, Aborting!"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Check input and output files
|
# Check input and output files
|
||||||
|
@ -98,7 +113,7 @@ def main(argv):
|
||||||
|
|
||||||
# Start Processing
|
# Start Processing
|
||||||
res = calculate(input)
|
res = calculate(input)
|
||||||
convert(input, output, res, abitrate, vbitrate, threads, mpopts)
|
convert(input, output, res, _abitrate, vbitrate, threads, mpopts)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -119,6 +134,10 @@ def calculate(input):
|
||||||
s = re.compile("^ID_VIDEO_HEIGHT=(.*)$", re.M)
|
s = re.compile("^ID_VIDEO_HEIGHT=(.*)$", re.M)
|
||||||
m = s.search(mp[0])
|
m = s.search(mp[0])
|
||||||
orig_height = m.group(1)
|
orig_height = m.group(1)
|
||||||
|
s = re.compile("^ID_VIDEO_FPS=(.*)$", re.M)
|
||||||
|
m = s.search(mp[0])
|
||||||
|
fps = m.group(1)
|
||||||
|
|
||||||
except:
|
except:
|
||||||
print "Error: unable to identify source video, exiting!"
|
print "Error: unable to identify source video, exiting!"
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
@ -132,87 +151,87 @@ def calculate(input):
|
||||||
width = _basewidth43
|
width = _basewidth43
|
||||||
height = int(round(_basewidth43 / float(orig_aspect) / 16) * 16)
|
height = int(round(_basewidth43 / float(orig_aspect) / 16) * 16)
|
||||||
|
|
||||||
return (width, height)
|
return (width, height, fps)
|
||||||
|
|
||||||
|
|
||||||
def convert(input, output, res, abitrate, vbitrate, threads, mpopts):
|
def convert(input, output, res, abitrate, vbitrate, threads, mpopts):
|
||||||
"""Convert the Video"""
|
"""Convert the Video"""
|
||||||
|
|
||||||
# Needed for cleanup function
|
# Needed for cleanup function
|
||||||
global afifo, vfifo, mda, mdv
|
global h264, aac
|
||||||
|
|
||||||
# Create FIFOs for passing audio/video from mplayer to ffmpeg
|
# define some localvariables
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
afifo = "/tmp/stream" + str(pid) + ".wav"
|
h264 = output + ".h264"
|
||||||
vfifo = "/tmp/stream" + str(pid) + ".yuv"
|
aac = output + ".aac"
|
||||||
os.mkfifo(afifo)
|
width = str(res[0])
|
||||||
os.mkfifo(vfifo)
|
height = str(res[1])
|
||||||
|
fps = str(res[2])
|
||||||
|
|
||||||
# Define mplayer command for video decoding
|
if (vbitrate < 52):
|
||||||
mpvideodec = [ mpbin,
|
vbr = "crf=" + str(vbitrate)
|
||||||
|
else:
|
||||||
|
vbr = "bitrate=" + str(vbitrate)
|
||||||
|
|
||||||
|
# Define mencoder command for video encoding
|
||||||
|
mencvideo = [ mcbin,
|
||||||
|
"-ovc", "x264",
|
||||||
|
"-x264encopts", vbr + ":bframes=0:trellis=0:nocabac:no8x8dct:level_idc=30:frameref=4:me=umh:weightp=0:vbv_bufsize=2000:vbv_maxrate=1800:threads=" + str(threads),
|
||||||
"-sws", "9",
|
"-sws", "9",
|
||||||
"-vf", "scale=" + str(res[0]) + ":" + str(res[1]) + ",unsharp=c4x4:0.3:l5x5:0.5",
|
"-vf", "scale=" + width + ":" + height + ",dsize=" + width + ":" + height + ",fixpts=fps=" + fps + ",ass,fixpts,harddup",
|
||||||
"-vo", "yuv4mpeg:file=" + vfifo,
|
"-of", "rawvideo",
|
||||||
"-ao", "null",
|
"-o", h264,
|
||||||
"-nosound",
|
"-nosound",
|
||||||
"-noframedrop",
|
"-noskip",
|
||||||
"-benchmark",
|
"-ass",
|
||||||
"-quiet",
|
|
||||||
"-nolirc",
|
|
||||||
"-msglevel", "all=-1",
|
|
||||||
input ]
|
input ]
|
||||||
|
if (mpopts != ""):
|
||||||
for mpopt in mpopts.split(" "):
|
for mpopt in mpopts.split(" "):
|
||||||
mpvideodec.append(mpopt)
|
mencvideo.append(mpopt)
|
||||||
|
|
||||||
# Define mplayer command for audio decoding
|
# Define mencoder command for audio encoding
|
||||||
mpaudiodec = [ mpbin,
|
mencaudio = [ mcbin,
|
||||||
"-ao", "pcm:file=" + afifo,
|
"-oac", "faac",
|
||||||
"-vo", "null",
|
"-faacopts", "br=" + str(abitrate) + ":mpeg=4:object=2",
|
||||||
"-vc", "null",
|
"-ovc", "copy",
|
||||||
"-noframedrop",
|
"-of", "rawaudio",
|
||||||
"-quiet",
|
"-o", aac,
|
||||||
"-nolirc",
|
"-noskip",
|
||||||
"-msglevel", "all=-1",
|
|
||||||
input ]
|
input ]
|
||||||
|
if (mpopts != ""):
|
||||||
for mpopt in mpopts.split(" "):
|
for mpopt in mpopts.split(" "):
|
||||||
mpaudiodec.append(mpopt)
|
mencaudio.append(mpopt)
|
||||||
|
|
||||||
|
|
||||||
# Define ffmpeg command for a/v encoding
|
# Define MB4Box Muxing Command
|
||||||
ffmenc = [ ffbin,
|
mp4mux = [ m4bin,
|
||||||
"-f", "yuv4mpegpipe",
|
"-fps", fps,
|
||||||
"-i", vfifo,
|
"-new", "-add", h264,
|
||||||
"-i", afifo,
|
"-add", aac,
|
||||||
"-acodec", "libfaac",
|
|
||||||
"-ac", "2",
|
|
||||||
"-ab", str(abitrate),
|
|
||||||
"-ar", "22500",
|
|
||||||
"-vcodec", "libx264",
|
|
||||||
"-threads", str(threads),
|
|
||||||
"-b", str(vbitrate),
|
|
||||||
"-flags", "+loop", "-cmp", "+chroma",
|
|
||||||
"-partitions", "+parti4x4+partp8x8+partb8x8",
|
|
||||||
"-subq", "5", "-trellis", "1", "-refs", "1",
|
|
||||||
"-coder", "0", "-me_range", "16",
|
|
||||||
"-g", "300", "-keyint_min", "25",
|
|
||||||
"-sc_threshold", "40", "-i_qfactor", "0.71",
|
|
||||||
"-bt", "640", "-bufsize", "10M", "-maxrate", "1000000",
|
|
||||||
"-rc_eq", "'blurCplx^(1-qComp)'",
|
|
||||||
"-qcomp", "0.62", "-qmin", "10", "-qmax", "51",
|
|
||||||
"-level", "30", "-f", "mp4",
|
|
||||||
output ]
|
output ]
|
||||||
|
|
||||||
# Start mplayer decoding processes in background
|
# Encode Video
|
||||||
|
print "### Starting Video Encode ###"
|
||||||
try:
|
try:
|
||||||
mdv = subprocess.Popen(mpvideodec, stdout=None, stderr=None)
|
subprocess.check_call(mencvideo)
|
||||||
mda = subprocess.Popen(mpaudiodec, stdout=None, stderr=None)
|
print "### Video Encoding Finished. ###"
|
||||||
except:
|
except subprocess.CalledProcessError:
|
||||||
print "Error: Starting decoding threads failed!"
|
print "Error: Video Encoding Failed!"
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
# Start ffmpeg encoding process in foreground
|
print "### Starting Audio Encode ###"
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(ffmenc)
|
subprocess.check_call(mencaudio)
|
||||||
|
print "### Audio Encode Finished. ###"
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
print "Error: Audio Encoding Failed!"
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
# Mux Video and Audio to MP4
|
||||||
|
print "### Starting MP4 Muxing ###"
|
||||||
|
try:
|
||||||
|
subprocess.check_call(mp4mux)
|
||||||
|
print "### MP4 Muxing Finished. Video is now ready! ###"
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
print "Error: Encoding thread failed!"
|
print "Error: Encoding thread failed!"
|
||||||
sys.exit(4)
|
sys.exit(4)
|
||||||
|
@ -229,17 +248,10 @@ def progpath(program):
|
||||||
def cleanup():
|
def cleanup():
|
||||||
"""Clean up when killed"""
|
"""Clean up when killed"""
|
||||||
|
|
||||||
# give ffmpeg time to stop
|
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
try:
|
try:
|
||||||
os.kill(mda.pid())
|
os.remove(h264)
|
||||||
os.kill(mdv.pid())
|
os.remove(aac)
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
os.remove(afifo)
|
|
||||||
os.remove(vfifo)
|
|
||||||
finally:
|
finally:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -247,7 +259,7 @@ def cleanup():
|
||||||
def usage():
|
def usage():
|
||||||
"""Print avaiable commandline arguments"""
|
"""Print avaiable commandline arguments"""
|
||||||
|
|
||||||
print "This is n900-encode.py (C) 2010 Stefan Brand <seiichiro0185 AT tol DOT ch>"
|
print "This is n900-encode.py Version" + version + "(C) 2010 Stefan Brand <seiichiro0185 AT tol DOT ch>"
|
||||||
print "Usage:"
|
print "Usage:"
|
||||||
print " n900-encode.py --input <file> [opts]\n"
|
print " n900-encode.py --input <file> [opts]\n"
|
||||||
print "Options:"
|
print "Options:"
|
||||||
|
@ -255,8 +267,8 @@ def usage():
|
||||||
print " --output <file> [-o]: Name of the converted Video"
|
print " --output <file> [-o]: Name of the converted Video"
|
||||||
print " --mpopts \"<opts>\" [-m]: Additional options for mplayer (eg -sid 1 or -aid 1) Must be enclosed in \"\""
|
print " --mpopts \"<opts>\" [-m]: Additional options for mplayer (eg -sid 1 or -aid 1) Must be enclosed in \"\""
|
||||||
print " --abitrate <br> [-a]: Audio Bitrate in KBit/s"
|
print " --abitrate <br> [-a]: Audio Bitrate in KBit/s"
|
||||||
print " --vbitrate <br> [-v]: Video Bitrate in kBit/s"
|
print " --vbitrate <br> [-v]: Video Bitrate in kBit/s, values < 0 activate h264 CRF-Encoding, given value is used as CRF Factor"
|
||||||
print " --threads <num> [-t]: Use <num> Threads to encode"
|
print " --threads <num> [-t]: Use <num> Threads to encode, giving 0 will autodetect number of CPUs"
|
||||||
print " --force-overwrite [-f]: Overwrite output-file if existing"
|
print " --force-overwrite [-f]: Overwrite output-file if existing"
|
||||||
print " --help [-h]: Print this Help"
|
print " --help [-h]: Print this Help"
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
Loading…
Reference in a new issue