summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornoah <noah@656d521f-e311-0410-88e0-e7920216d269>2007-04-18 18:40:10 +0000
committernoah <noah@656d521f-e311-0410-88e0-e7920216d269>2007-04-18 18:40:10 +0000
commit2289f21c76ad337a6a58a9e5a55ec1412f0b5c75 (patch)
tree53a7336e764c1c8a028fb035b55770358d750137
parentcde438d84b1331efd956a83d07b9d10d71c91a28 (diff)
downloadpexpect-2289f21c76ad337a6a58a9e5a55ec1412f0b5c75.tar.gz
Newish rippy.
git-svn-id: http://pexpect.svn.sourceforge.net/svnroot/pexpect/trunk@468 656d521f-e311-0410-88e0-e7920216d269
-rwxr-xr-xpexpect/examples/rippy.py315
1 files changed, 209 insertions, 106 deletions
diff --git a/pexpect/examples/rippy.py b/pexpect/examples/rippy.py
index 9c9bdb4..98a7ac8 100755
--- a/pexpect/examples/rippy.py
+++ b/pexpect/examples/rippy.py
@@ -43,16 +43,35 @@ compression before I calculate the revised bitrate. I'm also considering an
enhancement where Rippy would compress ten spread out chunks, 1-minute in
length to estimate the bitrate.
-For the latest version see http://rippy.sourceforge.net/
+Free, open source, and all that good stuff.
+Rippy Copyright (c) 2006 Noah Spurrier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
-$Id $
Noah Spurrier
+$Id$
"""
import sys, os, re, math, stat, getopt, traceback, types, time
import pexpect
__version__ = '1.2'
-__revision__ = '$Revision: 402 $'
+__revision__ = '$Revision: 11 $'
__all__ = ['main', __version__, __revision__]
GLOBAL_LOGFILE_NAME = "rippy_%d.log" % os.getpid()
@@ -67,6 +86,7 @@ prompts_key_order = (
'verbose_flag',
'dry_run_flag',
'video_source_filename',
+'video_chapter',
'video_final_filename',
'video_length',
'video_aspect_ratio',
@@ -74,9 +94,9 @@ prompts_key_order = (
'video_encode_passes',
'video_codec',
'video_fourcc_override',
-'video_target_size',
'video_bitrate',
'video_bitrate_overhead',
+'video_target_size',
'video_crop_area',
'video_deinterlace_flag',
'video_gray_flag',
@@ -84,9 +104,10 @@ prompts_key_order = (
'audio_id',
'audio_codec',
'audio_raw_filename',
+'audio_volume_boost',
'audio_sample_rate',
'audio_bitrate',
-'audio_lowpass_filter',
+#'audio_lowpass_filter',
'delete_tmp_files_flag'
)
#
@@ -99,16 +120,16 @@ prompts = {
It can be any file that mencoder supports.
You can also choose a DVD device using the dvd://1 syntax.
Title 1 is usually the main title on a DVD.""",0),
-#'video_transcoded_filename':("videodump.avi", 'Video transcoded filename?', """This is the temporary file where the video will be stored in the new format.""",2),
+'video_chapter':("1",'video chapter?',"""This is the chapter number. Usually disks such as TV series seasons will be divided into chapters. Maybe be ALL.""",0),
'video_final_filename':("video_final.avi", "video final filename?", """This is the name of the final video.""",0),
'audio_raw_filename':("audiodump.wav", "audio raw filename?", """This is the audio raw PCM filename. This is prior to compression.
-Note that mplayer automatically names this audiodump.wav, so
-currently changing this does not work.""",2),
+Note that mplayer automatically names this audiodump.wav, so don't change this.""",1000),
#'audio_compressed_filename':("audiodump.mp3","Audio compressed filename?", """This is the name of the compressed audio that will be mixed
#into the final video. Normally you don't need to change this.""",2),
-'video_length':("calc","video length in seconds?","""This sets the length of the video in seconds. Set to 'calc' to calculate the length from the
-raw audio stream. That's a hack because mplayer cannot get the length of
-the video from the source video file. Normally you don't need to change this.""",1),
+'video_length':("None","video length in seconds?","""This sets the length of the video in seconds. This is used to estimate the
+bitrate for a target video file size. Set to 'calc' to have Rippy calculate
+the length. Set to 'none' if you don't want rippy to estimate the bitrate --
+you will have to manually specify bitrate.""",1),
'video_aspect_ratio':("calc","aspect ratio?","""This sets the aspect ratio of the video. Most DVDs are 16/9 or 4/3.""",1),
'video_scale':("none","video scale?","""This scales the video to the given output size. The default is to do no scaling.
You may type in a resolution such as 320x240 or you may use presets.
@@ -119,10 +140,11 @@ You may type in a resolution such as 320x240 or you may use presets.
sntsc: 640x480 (square pixel NTSC)
spal: 768x576 (square pixel PAL)""",1),
'video_codec':("mpeg4","video codec?","""This is the video compression to use. This is passed directly to mencoder, so
-any format that it recognizes will work. DivX and XviD use mpeg4.
+any format that it recognizes should work. For XviD or DivX use mpeg4.
+Almost all MS Windows systems support wmv2 out of the box.
Some common codecs include:
mjpeg, h263, h263p, h264, mpeg4, msmpeg4, wmv1, wmv2, mpeg1video, mpeg2video, huffyuv, ffv1.
-See mencoder manual for details.""",2),
+""",2),
'audio_codec':("mp3","audio codec?","""This is the audio compression to use. This is passed directly to mencoder, so
any format that it recognizes will work.
Some common codecs include:
@@ -134,37 +156,36 @@ The following are common fourcc values:
XVID - used by Xvid (safest)
DX50 -
MP4S - Microsoft""",2),
-'video_encode_passes':("2","number of encode passes?","""This sets how many passes to use to encode the video. You can choose 1 or 2.
+'video_encode_passes':("1","number of encode passes?","""This sets how many passes to use to encode the video. You can choose 1 or 2.
Using two pases takes twice as long as one pass, but produces a better
-quality video. I found that the effect is not that noticable.""",1),
+quality video. I found that the improvement is not that impressive.""",1),
'verbose_flag':("Y","verbose output?","""This sets verbose output. If true then all commands and arguments are printed
before they are run. This is useful to see exactly how commands are run.""",1),
'dry_run_flag':("N","dry run?","""This sets 'dry run' mode. If true then commands are not run. This is useful
-if you want to see what would happen by running the script.""",1),
+if you want to see what would the script would do.""",1),
'video_bitrate':("calc","video bitrate?","""This sets the video bitrate. This overrides video_target_size.
Set to 'calc' to automatically estimate the bitrate based on the
-video final target size.""",1),
-'video_target_size':("700","video final target size in MB?","""This sets the target video size that you want to end up with.
+video final target size. If you set video_length to 'none' then
+you will have to specify this video_bitrate.""",1),
+'video_target_size':("737280000","video final target size?","""This sets the target video size that you want to end up with.
This is over-ridden by video_bitrate. In other words, if you specify
video_bitrate then video_target_size is ignored.
-Due to the unpredictable nature of compression the final video size may not
-exactly match. The following are common CDR sizes:
+Due to the unpredictable nature of VBR compression the final video size
+may not exactly match. The following are common CDR sizes:
180MB CDR (21 minutes) holds 193536000 bytes
550MB CDR (63 minutes) holds 580608000 bytes
650MB CDR (74 minutes) holds 681984000 bytes
700MB CDR (80 minutes) holds 737280000 bytes""",0),
-'video_bitrate_overhead':("1.19","bitrate overhead factor?","""I found that a 19% overhead (1.19 factor) produces
-a bitrate estimate that results in video files that are just under the
-target size. For a 700MB CDR, there will be about 4% free. Adjust this value if
-you want to leave more room for other files such as subtitle files.
+'video_bitrate_overhead':("1.0","bitrate overhead factor?","""Adjust this value if you want to leave more room for
+other files such as subtitle files.
If you specify video_bitrate then this value is ignored.""",2),
'video_crop_area':("detect","crop area?","""This sets the crop area to remove black bars from the top or sides of the video.
This helps save space. Set to 'detect' to automatically detect the crop area.
Set to 'none' to not crop the video. Normally you don't need to change this.""",1),
'video_deinterlace_flag':("N","is the video interlaced?","""This sets the deinterlace flag. If set then mencoder will be instructed
-to filter out interlace artifacts.""",1),
+to filter out interlace artifacts (using '-vf pp=md').""",1),
'video_gray_flag':("N","is the video black and white (gray)?","""This improves output for black and white video.""",1),
-'subtitle_id':("0","Subtitle ID stream?","""This selects the subtitle stream to extract from the source video.
+'subtitle_id':("None","Subtitle ID stream?","""This selects the subtitle stream to extract from the source video.
Normally, 0 is the English subtitle stream for a DVD.
Subtitles IDs with higher numbers may be other languages.""",1),
'audio_id':("128","audio ID stream?","""This selects the audio stream to extract from the source video.
@@ -179,10 +200,12 @@ the more space the audio track will take. That will leave less space for video.
The higher the bitrate the more space the audio track will take.
That will leave less space for video. Most people find music to be acceptable
at 128 kBitS. 96 kBitS is a good trade-off if you are trying to fit a video onto a CD.""",1),
-'audio_lowpass_filter':("16","audio lowpass filter (kHz)?","""This sets the low-pass filter for the audio.
-Normally this should be half of the audio sample rate.
-This improves audio compression and quality.
-Normally you don't need to change this.""",1),
+'audio_volume_boost':("none","volume dB boost?","""Many DVDs have very low audio volume. This sets an audio volume boost in Decibels.
+Values of 6 to 10 usually adjust quiet DVDs to a comfortable level.""",1),
+#'audio_lowpass_filter':("16","audio lowpass filter (kHz)?","""This sets the low-pass filter for the audio.
+#Normally this should be half of the audio sample rate.
+#This improves audio compression and quality.
+#Normally you don't need to change this.""",1),
'delete_tmp_files_flag':("N","delete temporary files when finished?","""If Y then %s, audio_raw_filename, and 'divx2pass.log' will be deleted at the end."""%GLOBAL_LOGFILE_NAME,1)
}
@@ -197,16 +220,16 @@ def convert (options):
This options dictionary could be used again to repeat the convert process
(it is also saved to rippy.conf as text).
"""
- try:
- sid = int(options['subtitle_id'])
+ if options['subtitle_id'] is not None:
print "# extract subtitles"
apply_smart (extract_subtitles, options)
- except:
+ else:
print "# do not extract subtitles."
- # Optimization alert!
+ # Optimization
# I really only need to calculate the exact video length if the user
- # selected 'calc' for video_bitrate or
+ # selected 'calc' for video_bitrate
+ # or
# selected 'detect' for video_crop_area.
if options['video_bitrate']=='calc' or options['video_crop_area']=='detect':
# As strange as it seems, the only reliable way to calculate the length
@@ -218,17 +241,18 @@ def convert (options):
apply_smart (extract_audio, options)
options['video_length'] = apply_smart (get_length, options)
print "# Length of raw audio file : %d seconds (%0.2f minutes)" % (options['video_length'], float(options['video_length'])/60.0)
-
- if options['video_bitrate']=='calc':
- options['video_bitrate'] = options['video_bitrate_overhead'] * apply_smart (calc_video_bitrate, options)
- print "# video bitrate : " + str(options['video_bitrate'])
-
- if options['video_crop_area']=='detect':
- options['video_crop_area'] = apply_smart (crop_detect, options)
- print "# crop area : " + str(options['video_crop_area'])
+ if options['video_bitrate']=='calc':
+ options['video_bitrate'] = options['video_bitrate_overhead'] * apply_smart (calc_video_bitrate, options)
+ print "# video bitrate : " + str(options['video_bitrate'])
+ if options['video_crop_area']=='detect':
+ options['video_crop_area'] = apply_smart (crop_detect, options)
+ print "# crop area : " + str(options['video_crop_area'])
+ print "# compression estimate"
+ print apply_smart (compression_estimate, options)
print "# compress video"
apply_smart (compress_video, options)
+ 'audio_volume_boost',
print "# delete temporary files:",
if options['delete_tmp_files_flag']:
@@ -237,25 +261,27 @@ def convert (options):
else:
print "no"
- video_actual_size = get_filesize (options['video_final_filename'])
- revised_bitrate = calculate_revised_bitrate (options['video_bitrate'], options['video_target_size'], video_actual_size)
-
+ # Finish by saving options to rippy.conf and
+ # calclating if final_size is less than target_size.
o = ["# options used to create video\n"]
- o.append("# revised video_bitrate : %d\n" % revised_bitrate)
+ video_actual_size = get_filesize (options['video_final_filename'])
+ if options['video_target_size'] != 'none':
+ revised_bitrate = calculate_revised_bitrate (options['video_bitrate'], options['video_target_size'], video_actual_size)
+ o.append("# revised video_bitrate : %d\n" % revised_bitrate)
for k,v in options.iteritems():
o.append (" %30s : %s\n" % (k, v))
print '# '.join(o)
fout = open("rippy.conf","wb").write(''.join(o))
-
print "# final actual video size = %d" % video_actual_size
- if video_actual_size > options['video_target_size']:
- print "# FINAL VIDEO SIZE IS GREATER THAN DESIRED TARGET"
- print "# final video size is %d bytes over target size" % (video_actual_size - options['video_target_size'])
- else:
- print "# final video size is %d bytes under target size" % (options['video_target_size'] - video_actual_size)
- print "# If you want to run the entire compression process all over again"
- print "# to get closer to the target video size then trying using a revised"
- print "# video_bitrate of %d" % revised_bitrate
+ if options['video_target_size'] != 'none':
+ if video_actual_size > options['video_target_size']:
+ print "# FINAL VIDEO SIZE IS GREATER THAN DESIRED TARGET"
+ print "# final video size is %d bytes over target size" % (video_actual_size - options['video_target_size'])
+ else:
+ print "# final video size is %d bytes under target size" % (options['video_target_size'] - video_actual_size)
+ print "# If you want to run the entire compression process all over again"
+ print "# to get closer to the target video size then trying using a revised"
+ print "# video_bitrate of %d" % revised_bitrate
return options
@@ -264,7 +290,7 @@ def convert (options):
def exit_with_usage(exit_code=1):
print globals()['__doc__']
print 'version:', globals()['__version__']
- print 'revision:', globals()['__revision__']
+ sys.stdout.flush()
os._exit(exit_code)
def check_missing_requirements ():
@@ -381,7 +407,7 @@ def get_aspect_ratio (video_source_filename):
This function is very lenient. It basically guesses 16/9 whenever
it cannot figure out the aspect ratio.
"""
- cmd = "mplayer %s -vo png -ao null -frames 1" % video_source_filename
+ cmd = "mplayer '%s' -vo png -ao null -frames 1" % video_source_filename
(command_output, exitstatus) = run(cmd)
ar = re.findall("Movie-Aspect is ([0-9]+\.?[0-9]*:[0-9]+\.?[0-9]*)", command_output)
if len(ar)==0:
@@ -406,7 +432,7 @@ def get_aid_list (video_source_filename):
"""This returns a list of audio ids in the source video file.
TODO: Also extract ID_AID_nnn_LANG to associate language. Not all DVDs include this.
"""
- cmd = "mplayer %s -vo null -ao null -frames 0 -identify" % video_source_filename
+ cmd = "mplayer '%s' -vo null -ao null -frames 0 -identify" % video_source_filename
(command_output, exitstatus) = run(cmd)
idl = re.findall("ID_AUDIO_ID=([0-9]+)", command_output)
idl.sort()
@@ -416,7 +442,7 @@ def get_sid_list (video_source_filename):
"""This returns a list of subtitle ids in the source video file.
TODO: Also extract ID_SID_nnn_LANG to associate language. Not all DVDs include this.
"""
- cmd = "mplayer %s -vo null -ao null -frames 0 -identify" % video_source_filename
+ cmd = "mplayer '%s' -vo null -ao null -frames 0 -identify" % video_source_filename
(command_output, exitstatus) = run(cmd)
idl = re.findall("ID_SUBTITLE_ID=([0-9]+)", command_output)
idl.sort()
@@ -428,7 +454,7 @@ def extract_audio (video_source_filename, audio_id=128, verbose_flag=0, dry_run_
At this time there is no way to set the output audio name.
"""
#cmd = "mplayer %(video_source_filename)s -vc null -vo null -aid %(audio_id)s -ao pcm:fast -noframedrop" % locals()
- cmd = "mplayer %(video_source_filename)s -vc dummy -vo null -aid %(audio_id)s -ao pcm:fast -noframedrop" % locals()
+ cmd = "mplayer -quiet '%(video_source_filename)s' -vc dummy -vo null -aid %(audio_id)s -ao pcm:fast -noframedrop" % locals()
if verbose_flag: print cmd
if not dry_run_flag:
run(cmd)
@@ -437,7 +463,7 @@ def extract_audio (video_source_filename, audio_id=128, verbose_flag=0, dry_run_
def extract_subtitles (video_source_filename, subtitle_id=0, verbose_flag=0, dry_run_flag=0):
"""This extracts the given subtitle_id track as VOBSUB format from the given source video.
"""
- cmd = "mencoder %(video_source_filename)s -o /dev/null -nosound -ovc copy -vobsubout subtitles -vobsuboutindex 0 -sid %(subtitle_id)s" % locals()
+ cmd = "mencoder -quiet '%(video_source_filename)s' -o /dev/null -nosound -ovc copy -vobsubout subtitles -vobsuboutindex 0 -sid %(subtitle_id)s" % locals()
if verbose_flag: print cmd
if not dry_run_flag:
run(cmd)
@@ -500,32 +526,36 @@ def calc_video_kbitrate (target_size, length_secs):
def crop_detect (video_source_filename, video_length, dry_run_flag=0):
"""This attempts to figure out the best crop for the given video file.
- Basically it runs crop detect for 5 seconds on three different places in the video.
+ Basically it runs crop detect for 10 seconds on five different places in the video.
It picks the crop area that was most often detected.
"""
- skip = int(video_length/9)
- sample_length = 5
- cmd1 = "mencoder %s -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, skip, sample_length)
- cmd2 = "mencoder %s -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 2*skip, sample_length)
- cmd3 = "mencoder %s -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 3*skip, sample_length)
+ skip = int(video_length/9) # offset to skip (-ss option in mencoder)
+ sample_length = 10
+ cmd1 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, skip, sample_length)
+ cmd2 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 2*skip, sample_length)
+ cmd3 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 4*skip, sample_length)
+ cmd4 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 6*skip, sample_length)
+ cmd5 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 8*skip, sample_length)
if dry_run_flag:
return "0:0:0:0"
(command_output1, exitstatus1) = run(cmd1)
(command_output2, exitstatus2) = run(cmd2)
(command_output3, exitstatus3) = run(cmd3)
+ (command_output4, exitstatus4) = run(cmd4)
+ (command_output5, exitstatus5) = run(cmd5)
idl = re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output1)
idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output2)
idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output3)
+ idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output4)
+ idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output5)
items_count = count_unique(idl)
return items_count[0][1]
-def compress_video (video_source_filename, video_final_filename, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_lowpass_filter=None, audio_sample_rate=None, audio_bitrate=None, verbose_flag=0, dry_run_flag=0):
- """This compresses the video and audio of the given source video filename to the transcoded filename.
- This does a two-pass compression (I'm assuming mpeg4, I should probably make this smarter for other formats).
- audio_lowpass_filter is DISABLED
-For VCD and SVCD use acodec mp2:
-mencoder movie.wmv -o movie.avi -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrate=224
- """
+
+def build_compression_command (video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None, seek_skip=None, seek_length=None, video_chapter=None):
+#Notes:For DVD, VCD, and SVCD use acodec=mp2 and vcodec=mpeg2video:
+#mencoder movie.avi -o movie.VOB -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrate=224:vcodec=mpeg2video:vbitrate=2000
+
#
# build video filter (-vf) argument
#
@@ -548,6 +578,15 @@ mencoder movie.wmv -o movie.avi -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrat
video_filter = '-vf ' + video_filter
#
+ # build chapter argument
+ #
+ if video_chapter is not None:
+ chapter = '-chapter %d-%d' %(video_chapter,video_chapter)
+ else:
+ chapter = ''
+ chapter = '-chapter 1-1'
+
+ #
# build audio_filter argument
#
audio_filter = ''
@@ -555,10 +594,15 @@ mencoder movie.wmv -o movie.avi -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrat
if audio_filter != '':
audio_filter = audio_filter + ','
audio_filter = audio_filter + 'lavcresample=%s' % audio_sample_rate
+ if audio_volume_boost is not None:
+ if audio_filter != '':
+ audio_filter = audio_filter + ','
+ audio_filter = audio_filter + 'volume=%0.1f:1'%audio_volume_boost
if audio_filter != '':
audio_filter = '-af ' + audio_filter
- if audio_sample_rate:
- audio_filter = '-srate %d ' % audio_sample_rate + audio_filter
+ #
+ #if audio_sample_rate:
+ # audio_filter = ('-srate %d ' % audio_sample_rate) + audio_filter
#
# build lavcopts argument
@@ -568,27 +612,44 @@ mencoder movie.wmv -o movie.avi -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrat
if video_gray_flag:
lavcopts = lavcopts + ':gray'
-# #
-# # build lameopts argument
-# #
-# lameopts = ''
-# if audio_bitrate:
-# if lameopts != '':
-# lameopts = lameopts + ':'
-# lameopts = lameopts + 'cbr:br=%s' % audio_bitrate
-# if audio_lowpass_filter:
-# if lameopts != '':
-# lameopts = lameopts + ':'
-# lameopts = lameopts + 'lowpassfreq=%s' % audio_lowpass_filter
-# if lameopts != '':
-# lameopts = '-lameopts ' + lameopts
-# #/usr/bin/mencoder VIDEO.vob -o video.avi -aid 128 -ffourcc XVID -oac mp3lame -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=922:mbd=2:vpass=2 -vf crop=704:368:8:54 -lameopts cbr:br=96 -af resample=32000
-# audio_copy_codec_options = lameopts
-#
+ seek_filter = ''
+ if seek_skip is not None:
+ seek_filter = '-ss %s' % (str(seek_skip))
+ if seek_length is not None:
+ seek_filter = seek_filter + ' -endpos %s' % (str(seek_length))
+
+ cmd = "mencoder -quiet -info comment='Arkivist' '%(video_source_filename)s' %(seek_filter)s %(chapter)s -aid %(audio_id)s -o '%(video_final_filename)s' -ffourcc %(video_fourcc_override)s -ovc lavc -oac lavc %(lavcopts)s %(video_filter)s %(audio_filter)s" % locals()
+ return cmd
+
+def compression_estimate (video_length, video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None):
+ """This attempts to figure out the best compression ratio for a given set of compression options.
+ """
+ # TODO Need to account for AVI overhead.
+ skip = int(video_length/9) # offset to skip (-ss option in mencoder)
+ sample_length = 10
+ cmd1 = build_compression_command (video_source_filename, "compression_test_1.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip, sample_length)
+ cmd2 = build_compression_command (video_source_filename, "compression_test_2.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*2, sample_length)
+ cmd3 = build_compression_command (video_source_filename, "compression_test_3.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*4, sample_length)
+ cmd4 = build_compression_command (video_source_filename, "compression_test_4.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*6, sample_length)
+ cmd5 = build_compression_command (video_source_filename, "compression_test_5.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*8, sample_length)
+ run(cmd1)
+ run(cmd2)
+ run(cmd3)
+ run(cmd4)
+ run(cmd5)
+ size = get_filesize ("compression_test_1.avi")+get_filesize ("compression_test_2.avi")+get_filesize ("compression_test_3.avi")+get_filesize ("compression_test_4.avi")+get_filesize ("compression_test_5.avi")
+ return (size / 5.0)
+
+def compress_video (video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None, seek_skip=None, seek_length=None, verbose_flag=0, dry_run_flag=0):
+ """This compresses the video and audio of the given source video filename to the transcoded filename.
+ This does a two-pass compression (I'm assuming mpeg4, I should probably make this smarter for other formats).
+ """
#
# do the first pass video compression
#
- cmd = "mencoder %(video_source_filename)s -aid %(audio_id)s -o %(video_final_filename)s -ffourcc %(video_fourcc_override)s -ovc lavc -oac lavc %(lavcopts)s %(video_filter)s %(audio_filter)s" % locals()
+ #cmd = "mencoder -quiet '%(video_source_filename)s' -ss 65 -endpos 20 -aid %(audio_id)s -o '%(video_final_filename)s' -ffourcc %(video_fourcc_override)s -ovc lavc -oac lavc %(lavcopts)s %(video_filter)s %(audio_filter)s" % locals()
+
+ cmd = build_compression_command (video_source_filename, video_final_filename, video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, seek_skip, seek_length)
if verbose_flag: print cmd
if not dry_run_flag:
run(cmd)
@@ -598,6 +659,16 @@ mencoder movie.wmv -o movie.avi -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrat
if video_encode_passes!='2':
return
+ if verbose_flag:
+ video_actual_size = get_filesize (video_final_filename)
+ if video_actual_size > video_target_size:
+ print "======================================================="
+ print "WARNING!"
+ print "First pass compression resulted in"
+ print "actual file size greater than target size."
+ print "Second pass will be too big."
+ print "======================================================="
+
#
# do the second pass video compression
#
@@ -646,7 +717,7 @@ def mux_mkv (video_final_filename, video_transcoded_filename, audio_compressed_f
def mux_avi (video_final_filename, video_transcoded_filename, audio_compressed_filename, verbose_flag=0, dry_run_flag=0):
"""This is depricated."""
- cmd = 'mencoder -oac copy -ovc copy -o %s -audiofile %s %s' % (video_final_filename, audio_compressed_filename, video_transcoded_filename)
+ cmd = "mencoder -quiet -oac copy -ovc copy -o '%s' -audiofile %s '%s'" % (video_final_filename, audio_compressed_filename, video_transcoded_filename)
if verbose_flag: print cmd
if not dry_run_flag:
run(cmd)
@@ -686,7 +757,7 @@ def interactive_convert ():
level_sort_string += "[0] Basic options:\n" + str(level_sort[0]) + "\n"
level_sort_string += "[1] Advanced options:\n" + str(level_sort[1]) + "\n"
level_sort_string += "[2] Expert options:\n" + str(level_sort[2])
- c = input_option("Prompt level (0, 1, or 2)?", "0", level_sort_string)
+ c = input_option("Prompt level (0, 1, or 2)?", "1", level_sort_string)
max_prompt_level = int(c)
options = {}
@@ -714,11 +785,12 @@ def interactive_convert ():
sid_list = get_sid_list (options['video_source_filename'])
default_id = 'None'
if max_prompt_level>=prompts[k][3]:
- if len(sid_list) > 1:
- print "This video has more than one subtitle stream. The following stream subtitle IDs were found:"
+ if len(sid_list) > 0:
+ print "This video has one or more subtitle streams. The following stream subtitle IDs were found:"
for sid in sid_list:
print " " + sid
- default_id = sid_list[0]
+ #default_id = sid_list[0]
+ default_id = prompts[k][0]
else:
print "WARNING!"
print "Unable to get the list of subtitle streams from this video. It may have none."
@@ -728,10 +800,19 @@ def interactive_convert ():
elif k == 'audio_lowpass_filter':
lowpass_default = "%.1f" % (math.floor(float(options['audio_sample_rate']) / 2.0))
options[k] = input_option (prompts[k][1], lowpass_default, prompts[k][2], prompts[k][3], max_prompt_level)
+ elif k == 'video_bitrate':
+ if options['video_length'].lower() == 'none':
+ options[k] = input_option (prompts[k][1], '1000', prompts[k][2], prompts[k][3], max_prompt_level)
+ else:
+ options[k] = input_option (prompts[k][1], prompts[k][0], prompts[k][2], prompts[k][3], max_prompt_level)
else:
- # Don't bother asking for video_target_size or video_bitrate_overhead if bitrate was set
+ # don't bother asking for video_target_size or video_bitrate_overhead if video_bitrate was set
if (k=='video_target_size' or k=='video_bitrate_overhead') and options['video_bitrate']!='calc':
continue
+ # don't bother with crop area if video length is none
+ if k == 'video_crop_area' and options['video_length'].lower() == 'none':
+ options['video_crop_area'] = 'none'
+ continue
options[k] = input_option (prompts[k][1], prompts[k][0], prompts[k][2], prompts[k][3], max_prompt_level)
#options['video_final_filename'] = options['video_final_filename'] + "." + options['video_container_format']
@@ -778,7 +859,8 @@ def clean_options (d):
else:
d['video_bitrate'] = int(float(d['video_bitrate']))
try:
- d['video_target_size'] = int(d['video_target_size'])
+ d['video_target_size'] = int(d['video_target_size'])
+ # shorthand magic numbers get automatically expanded
if d['video_target_size'] == 180:
d['video_target_size'] = 193536000
elif d['video_target_size'] == 550:
@@ -787,11 +869,19 @@ def clean_options (d):
d['video_target_size'] = 681984000
elif d['video_target_size'] == 700:
d['video_target_size'] = 737280000
- else:
- d['video_target_size'] = d['video_target_size'] * (1024 * 1024)
except:
d['video_target_size'] = 'none'
-
+
+ try:
+ d['video_chapter'] = int(d['video_chapter'])
+ except:
+ d['video_chapter'] = None
+
+ try:
+ d['subtitle_id'] = int(d['subtitle_id'])
+ except:
+ d['subtitle_id'] = None
+
try:
d['video_bitrate_overhead'] = float(d['video_bitrate_overhead'])
except:
@@ -799,6 +889,12 @@ def clean_options (d):
d['audio_bitrate'] = int(d['audio_bitrate'])
d['audio_sample_rate'] = int(d['audio_sample_rate'])
+ d['audio_volume_boost'] = d['audio_volume_boost'].lower()
+ if d['audio_volume_boost'][0]=='n':
+ d['audio_volume_boost'] = None
+ else:
+ d['audio_volume_boost'] = d['audio_volume_boost'].replace('db','')
+ d['audio_volume_boost'] = float(d['audio_volume_boost'])
# assert (d['video_bitrate']=='calc' and d['video_target_size']!='none')
# or (d['video_bitrate']!='calc' and d['video_target_size']=='none')
@@ -815,6 +911,13 @@ def clean_options (d):
d['video_length'] = d['video_length'].lower()
if d['video_length'][0]=='c':
d['video_length']='calc'
+ elif d['video_length'][0]=='n':
+ d['video_length']='none'
+ else:
+ d['video_length'] = int(float(d['video_length']))
+ if d['video_length']==0:
+ d['video_length'] = 'none'
+ assert (not (d['video_length']=='none' and d['video_bitrate']=='calc'))
return d
def main ():
@@ -845,7 +948,7 @@ def main ():
os._exit(1)
if len(args) > 0:
- # cute one-line string to dictionary parse (two-lines if you count this comment):
+ # cute one-line string-to-dictionary parser (two-lines if you count this comment):
options = dict(re.findall('([^: \t\n]*)\s*:\s*(".*"|[^ \t\n]*)', file(args[0]).read()))
options = clean_options(options)
convert (options)