Compare commits

...

4 commits
1.1 ... master

Author SHA1 Message Date
seiichiro 5ed4fb4ae6 Version 1.2.1
Fixed some minor errors
Added more robust error handling
2012-08-29 11:58:56 +02:00
seiichiro 86eacfa9b5 Version 1.2
Added possibility for CRF-Encoding
Default Quality is now CRF at factor 22
Some Encoding Tweaks and default values for the Nokia N9
2012-03-23 20:25:16 +01:00
Stefan Brand 6bb819a6a0 Version 1.1.1
Fixed README formating
2012-02-23 08:43:58 +01:00
seiichiro fb4e284b9b Version 1.1
Switched to encoding with ffmpeg 0.10
Script now runs on python 2 and python 3
2012-02-23 08:37:03 +01:00
2 changed files with 101 additions and 62 deletions

3
README
View file

@ -6,8 +6,7 @@ PREQUISITES:
The following components are needed:
* mplayer
* mencoder
* MP4Box (from gpac package)
* ffmpeg (tested with version 0.10, older versions may or may not work)
* python
USAGE:

View file

@ -4,7 +4,9 @@
# n900-encode.py: Encode almost any Video to an Nokia N900-compatible format (h264,aac,mp4)
# Disclaimer: This program is provided without any warranty, USE AT YOUR OWN RISK!
#
# (C) 2010-2011 Stefan Brand <seiichiro@seiichiro0185.org>
# Version 1.2 (23.03.2012)
#
# (C) 2010-2012 Stefan Brand <seiichiro@seiichiro0185.org>
#
# This programm is licensed under the Terms of the GPL Version 3
# See COPYING for more info.
@ -19,12 +21,12 @@ from time import sleep
# Default values, feel free to adjust
###########################################################################################
_basewidth = 800 # Base width for widescreen Video
_basewidth = 854 # Base width for widescreen Video
_basewidth43 = 640 # Base width for 4:3 Video
_maxheight = 480 # maximum height allowed
_abitrate = 96 # Audio Bitrate in kBit/s
_vbitrate = 500 # Video Bitrate in kBit/s
_threads = 2 # Use n Threads to encode
_abitrate = 112 # Audio Bitrate in kBit/s
_vbitrate = 22 # Video Bitrate in kBit/s, Values < 52 are used as a CRF-Factor
_threads = "auto" # Use n Threads to encode
_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
@ -32,21 +34,32 @@ _ffbin = None # ffmpeg binary, if set to None it is searched in your $PATH
# Main Program, no changes needed below this line
###########################################################################################
# Global Variables
mda = None
mdv = None
afifo = None
vfifo = None
# Main Function
def main(argv):
"""Main Function, cli argument processing and checking"""
# CLI Argument Processing
try:
opts, args = getopt.getopt(argv, "i:o:m:v:a:t:hf", ["input=", "output=", "mpopts=", "abitrate=", "vbitrate=", "threads=", "help", "force-overwrite"])
except getopt.GetoptError, err:
print str(err)
except:
usage()
if (len(args) != 0):
print("Error: Unsupported Arguments found!")
usage()
input = None
output = "n900encode.mp4"
mpopts = ""
abitrate = _abitrate * 1000
vbitrate = _vbitrate * 1000
vbitrate = int(_vbitrate)
threads = _threads
overwrite = False
for opt, arg in opts:
@ -59,7 +72,7 @@ def main(argv):
elif opt in ("-a", "--abitrate"):
abitrate = int(arg) * 1000
elif opt in ("-v", "--vbitrate"):
vbitrate = int(arg) * 1000
vbitrate = int(arg)
elif opt in ("-t", "--threads"):
threads = arg
elif opt in ("-f", "--force-overwrite"):
@ -70,34 +83,34 @@ def main(argv):
# Check for needed Programs
global mpbin
mpbin = None
if not _mpbin == None and os.path.exists(_mpbin) and not os.path.isdir(_mpbin):
if not _mpbin == None and os.path.isfile(_mpbin):
mpbin = _mpbin
else:
mpbin = progpath("mplayer")
if mpbin == None:
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)
global ffbin
ffbin = None
if not _ffbin == None and os.path.exists(_ffbin) and not os.path.isdir(_ffbin):
if not _ffbin == None and os.path.isfile(_ffbin):
ffbin = _ffbin
else:
ffbin = progpath("ffmpeg")
if ffbin == None:
print "Error: ffmpeg not found in PATH and no binary given, Aborting!"
print( "Error: ffmpeg not found in PATH and no binary given, Aborting!")
sys.exit(1)
# Check input and output files
if not os.path.isfile(input):
print "Error: input file is not a valid File or doesn't exist"
if (input == None or not os.path.isfile(input)):
print("Error: input file is not a valid File or doesn't exist")
sys.exit(2)
if os.path.isfile(output):
if overwrite:
os.remove(output)
else:
print "Error: output file " + output + " already exists, force overwrite with -f"
print("Error: output file " + output + " already exists, force overwrite with -f")
sys.exit(1)
# Start Processing
@ -111,20 +124,24 @@ def calculate(input):
# Get characteristics using mplayer
cmd=[mpbin, "-ao", "null", "-vo", "null", "-frames", "0", "-identify", input]
mp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
try:
mp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
except:
print("Error: Couldn't execute mplayer")
sys.exit(1)
try:
s = re.compile("^ID_VIDEO_ASPECT=(.*)$", re.M)
m = s.search(mp[0])
m = s.search(bytes.decode(mp[0]))
orig_aspect = m.group(1)
s = re.compile("^ID_VIDEO_WIDTH=(.*)$", re.M)
m = s.search(mp[0])
m = s.search(bytes.decode(mp[0]))
orig_width = m.group(1)
s = re.compile("^ID_VIDEO_HEIGHT=(.*)$", re.M)
m = s.search(mp[0])
m = s.search(bytes.decode(mp[0]))
orig_height = m.group(1)
except:
print "Error: unable to identify source video, exiting!"
print("Error: unable to identify source video, exiting!")
sys.exit(2)
# Calculate output resolution
@ -149,13 +166,17 @@ def convert(input, output, res, abitrate, vbitrate, threads, mpopts):
pid = os.getpid()
afifo = "/tmp/stream" + str(pid) + ".wav"
vfifo = "/tmp/stream" + str(pid) + ".yuv"
os.mkfifo(afifo)
os.mkfifo(vfifo)
try:
os.mkfifo(afifo)
os.mkfifo(vfifo)
except:
print("Error: Couldn't create fifos!")
sys.exit(2)
# Define mplayer command for video decoding
mpvideodec = [ mpbin,
"-sws", "9",
"-vf", "scale=" + str(res[0]) + ":" + str(res[1]) + ",unsharp=c4x4:0.3:l5x5:0.5",
"-vf", "scale=" + str(res[0]) + ":" + str(res[1]) + ",dsize=" + str(res[0]) + ":" + str(res[1]) + ",unsharp=c4x4:0.3:l5x5:0.5", "-ass",
"-vo", "yuv4mpeg:file=" + vfifo,
"-ao", "null",
"-nosound",
@ -183,27 +204,34 @@ def convert(input, output, res, abitrate, vbitrate, threads, mpopts):
# Define ffmpeg command for a/v encoding
if (vbitrate > 51):
rmode = "-b:v"
vbitr = str(vbitrate*1000)
else:
rmode = "-crf"
vbitr = str(vbitrate)
ffmenc = [ ffbin,
"-f", "yuv4mpegpipe",
"-i", vfifo,
"-i", afifo,
"-acodec", "libfaac",
"-acodec", "aac",
"-strict", "experimental",
"-ac", "2",
"-ab", str(abitrate),
"-ar", "22500",
"-ar", "44100",
"-vcodec", "libx264",
"-threads", str(threads),
"-b", str(vbitrate),
"-flags", "+loop", "-cmp", "+chroma",
"-vprofile", "baseline",
"-tune", "animation",
rmode, vbitr,
"-flags", "+loop", "-cmp", "+chroma", "-coder", "0",
"-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",
"-subq", "7", "-trellis", "1", "-refs", "3",
"-me_range", "16", "-me_method", "hex",
"-bufsize", "10M", "-maxrate", "1000000",
"-x264opts", "level=3.1", "-f", "mp4",
output ]
# Start mplayer decoding processes in background
@ -211,15 +239,24 @@ def convert(input, output, res, abitrate, vbitrate, threads, mpopts):
mdv = subprocess.Popen(mpvideodec, stdout=None, stderr=None)
mda = subprocess.Popen(mpaudiodec, stdout=None, stderr=None)
except:
print "Error: Starting decoding threads failed!"
print("Error: Starting decoding threads failed!")
sys.exit(3)
print("Waiting for decoding threads to start...")
# Wait
sleep(2)
# Check if the decoding processes are running
if (mda.poll() != None or mdv.poll() != None):
print("Error: Starting decoding threads failed!")
sys.exit(3)
# Start ffmpeg encoding process in foreground
try:
subprocess.check_call(ffmenc)
except subprocess.CalledProcessError:
print "Error: Encoding thread failed!"
sys .exit(4)
print("Error: Encoding thread failed!")
sys.exit(4)
def progpath(program):
@ -238,31 +275,34 @@ def cleanup():
# Cleanup
try:
os.kill(mda.pid())
os.kill(mdv.pid())
if (mda != None):
if (mda.returncode == None):
mda.kill()
if (mdv != None):
if (mdv.returncode == None):
mdv.kill()
finally:
try:
if (afifo != None and os.path.exists(afifo)):
os.remove(afifo)
if (vfifo != None and os.path.exists(vfifo)):
os.remove(vfifo)
finally:
sys.exit(0)
def usage():
"""Print avaiable commandline arguments"""
print "This is n900-encode.py (C) 2010 Stefan Brand <seiichiro0185 AT tol DOT ch>"
print "Usage:"
print " n900-encode.py --input <file> [opts]\n"
print "Options:"
print " --input <file> [-i]: Video to Convert"
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 " --abitrate <br> [-a]: Audio Bitrate in KBit/s"
print " --vbitrate <br> [-v]: Video Bitrate in kBit/s"
print " --threads <num> [-t]: Use <num> Threads to encode"
print " --force-overwrite [-f]: Overwrite output-file if existing"
print " --help [-h]: Print this Help"
sys.exit(0)
print("This is n900-encode.py (C) 2012 Stefan Brand <seiichiro0185 AT seiichiro0185 DOT org>")
print("Usage:")
print(" n900-encode.py --input <file> [opts]\n")
print("Options:")
print(" --input <file> [-i]: Video to Convert")
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(" --abitrate <br> [-a]: Audio Bitrate in KBit/s")
print(" --vbitrate <br> [-v]: Video Bitrate in kBit/s, values less than 52 will be used as CRF-Factor")
print(" --threads <num> [-t]: Use <num> Threads to encode")
print(" --force-overwrite [-f]: Overwrite output-file if existing")
print(" --help [-h]: Print this Help")
os._exit(0)
# Start the Main Function
@ -277,5 +317,5 @@ if __name__ == "__main__":
if len(sys.argv) > 1:
main(sys.argv[1:])
else:
print "Error: You have to give an input file at least!"
print("Error: You have to give an input file at least!")
usage()