]>
code.delx.au - transcoding/blob - encode.py
1bc6c3a3ebf4c6f1b525c2bc4a8edc7af796c249
11 class FatalException(Exception):
14 class Command(object):
15 def __init__(self
, profile
, opts
):
16 self
.profile
= profile
19 def print_install_message(self
):
20 print >>sys
.stderr
, "Problem with command: %s", self
.name
22 print >>sys
.stderr
, "Try running:\n# aptitude install %s", self
.package
24 def check_command(self
, cmd
):
27 if subprocess
.Popen(["which", cmd
], stdout
=open("/dev/null", "w")).wait() != 0:
28 raise FatalException("Command '%s' is required" % cmd
)
30 def do_exec(self
, args
):
32 print "".join(map(commands
.mkarg
, args
))[1:]
34 if subprocess
.Popen(args
).wait() != 0:
35 raise FatalException("Failure executing command: %s" % args
)
38 class MP4Box(Command
):
46 self
.check_command("mencoder")
47 self
.check_command("MP4Box")
51 video
= "video.%s" % self
.codec2exts
[p
.vcodec
]
52 audio
= "audio.%s" % self
.codec2exts
[p
.acodec
]
53 input = self
.opts
.output
+ ".avi" # From Mencoder command
54 output
= self
.opts
.output
+ ".mp4"
55 mencoder
= ["mencoder", input, "-ovc", "copy", "-oac", "copy", "-of"]
56 self
.do_exec(["rm", "-f", output
])
57 self
.do_exec(mencoder
+ ["rawvideo", "-o", video
])
58 self
.do_exec(mencoder
+ ["rawaudio", "-o", audio
])
59 self
.do_exec(["MP4Box", "-add", video
, "-add", audio
, output
])
60 self
.do_exec(["rm", "-f", video
, audio
, input])
63 class Mencoder(Command
):
66 "xvid": "-xvidencopts",
67 "x264": "-x264encopts",
69 "mp3lame": "-lameopts",
72 def insert_options(self
, cmd
):
73 def try_opt(opt
, var
):
77 if self
.opts
.deinterlace
:
78 cmd
+= ["-vf-add", "pp=ci"]
79 try_opt("-ss", self
.opts
.startpos
)
80 try_opt("-endpos", self
.opts
.endpos
)
81 try_opt("-dvd-device", self
.opts
.dvd
)
82 try_opt("-chapter", self
.opts
.chapter
)
83 try_opt("-aid", self
.opts
.audioid
)
84 try_opt("-sid", self
.opts
.subtitleid
)
85 try_opt("-vf-add", self
.opts
.vfilters
)
86 try_opt("-af", self
.opts
.afilters
)
88 def subst_values(self
, cmd
, vpass
):
90 "vbitrate": self
.opts
.vbitrate
,
91 "abitrate": self
.opts
.abitrate
,
92 "input": self
.opts
.input,
93 "output": self
.opts
.output
+ ".avi",
97 return [x
% subst
for x
in cmd
]
102 cmd
+= ["mencoder", "%(input)s", "-o", "/dev/null"]
103 self
.insert_options(cmd
)
104 cmd
+= ["-ovc", p
.vcodec
, self
.codec2opts
[p
.vcodec
], p
.vopts
]
105 cmd
+= ["-oac", "copy"]
106 cmd
+= self
.profile
.extra
+ self
.profile
.extra1
107 cmd
= self
.subst_values(cmd
, vpass
=1)
113 cmd
+= ["mencoder", "%(input)s", "-o", "%(output)s"]
114 self
.insert_options(cmd
)
115 cmd
+= ["-ovc", p
.vcodec
, self
.codec2opts
[p
.vcodec
], p
.vopts
]
116 cmd
+= ["-oac", p
.acodec
, self
.codec2opts
[p
.acodec
], p
.aopts
]
117 if self
.opts
.episode_name
:
118 cmd
+= ["-info", "name='%s'" % self
.opts
.episode_name
]
119 cmd
+= self
.profile
.extra
+ self
.profile
.extra2
120 cmd
= self
.subst_values(cmd
, vpass
=2)
124 self
.check_command("mencoder")
127 self
.do_exec(self
.pass1())
128 self
.do_exec(self
.pass2())
132 class Profile(object):
133 def __init__(self
, commands
, **kwargs
):
134 self
.default_opts
= {
141 self
.commands
= commands
142 self
.__dict
__.update(kwargs
)
144 def __contains__(self
, keyname
):
145 return hasattr(self
, keyname
)
151 commands
=[Mencoder
, MP4Box
],
153 vopts
="pass=%(vpass)d:bitrate=%(vbitrate)d:me=umh:partitions=all:trellis=1:subq=7:bframes=1:direct_pred=auto",
155 aopts
="br=%(abitrate)d:mpeg=4:object=2",
162 vopts
="pass=%(vpass)d:bitrate=%(vbitrate)d:vhq=4:autoaspect",
164 aopts
="abr:br=%(abitrate)d",
165 extra2
=["-ffourcc", "DX50"],
170 commands
=[Mencoder
, MP4Box
],
172 vopts
="pass=%(vpass)d:bitrate=%(vbitrate)d:vhq=4:autoaspect:max_bframes=0",
174 aopts
="br=%(abitrate)d:mpeg=4:object=2",
175 extra
=["-vf-add", "scale=480:-10"],
180 commands
=[Mencoder
, MP4Box
],
182 vopts
="pass=%(vpass)d:bitrate=%(vbitrate)d:vbv_maxrate=1500:vbv_bufsize=2000:nocabac:me=umh:partitions=all:trellis=1:subq=7:bframes=0:direct_pred=auto:level_idc=30:turbo",
184 aopts
="br=%(abitrate)d:mpeg=4:object=2",
185 extra
=["-vf-add", "scale=480:-10"],
186 extra2
=["-channels", "2", "-srate", "48000"],
191 commands
=[Mencoder
, MP4Box
],
197 vopts
="pass=%(vpass)d:bitrate=%(vbitrate)d:nocabac:me=umh:partitions=all:trellis=1:subq=7:bframes=0:direct_pred=auto",
199 aopts
="br=%(abitrate)d:mpeg=4:object=2",
200 extra
=["-vf-add", "scale=320:-10"],
208 for profile_name
in profiles
.keys():
209 if sys
.argv
[0].find(profile_name
) >= 0:
212 profile_name
= "xvid"
214 parser
= optparse
.OptionParser(usage
="%prog [options] input [output]")
215 parser
.add_option("--dvd", action
="store", dest
="dvd")
216 parser
.add_option("--deinterlace", action
="store_true", dest
="deinterlace")
217 parser
.add_option("--vfilters", action
="store", dest
="vfilters")
218 parser
.add_option("--afilters", action
="store", dest
="afilters")
219 parser
.add_option("--vbitrate", action
="store", dest
="vbitrate", type="int")
220 parser
.add_option("--abitrate", action
="store", dest
="abitrate", type="int")
221 parser
.add_option("--chapter", action
="store", dest
="chapter")
222 parser
.add_option("--startpos", action
="store", dest
="startpos")
223 parser
.add_option("--endpos", action
="store", dest
="endpos")
224 parser
.add_option("--audioid", action
="store", dest
="audioid")
225 parser
.add_option("--subtitleid", action
="store", dest
="subtitleid")
226 parser
.add_option("--profile", action
="store", dest
="profile_name", default
=profile_name
)
227 parser
.add_option("--episode-name", action
="store", dest
="episode_name")
228 parser
.add_option("--dump", action
="store_true", dest
="dump")
230 opts
, args
= parser
.parse_args(sys
.argv
[1:])
233 output
= os
.path
.splitext(os
.path
.basename(input))[0]
242 if "://" not in input:
243 opts
.input = os
.path
.abspath(input)
246 opts
.dvd
= os
.path
.abspath(opts
.dvd
)
249 opts
.output
= os
.path
.abspath(output
)
258 profile
= profiles
[opts
.profile_name
]
260 print >>sys
.stderr
, "Profile '%s' not found!" % opts
.profile_name
263 # Pull in default option values from the profile
264 for key
, value
in profile
.default_opts
.iteritems():
265 if getattr(opts
, key
) is None:
266 setattr(opts
, key
, value
)
268 # Run in a temp dir so that multiple instances can be run simultaneously
269 tempdir
= tempfile
.mkdtemp()
275 for CommandClass
in profile
.commands
:
276 command
= CommandClass(profile
, opts
)
277 commands
.append(command
)
279 for command
in commands
:
282 except FatalException
, e
:
283 print >>sys
.stderr
, "Error:", e
.message
288 shutil
.rmtree(tempdir
)
290 if __name__
== "__main__":