-
Notifications
You must be signed in to change notification settings - Fork 155
Description
Hello C0decracker,
thanks for the small python script regarding letting ffmpeg do multiple jobs in order to losslessly splitting sourcefile.
I needed cuesheet support for doing non-equidistantly splits, therefore I added cuesheet-support.
I got no idea about how to operate git and the like, but I think this project is small enough to just give you my work here:
#!/usr/bin/env python
import subprocess
import re
import math
from optparse import OptionParser
length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
cue_reffile_regexp = 'FILE\s"(.*)"'
cue_index_regexp = 'INDEX\s01\s(\d{2}):(\d{2}):(\d{2})'
re_length = re.compile(length_regexp)
re_cue_reffile = re.compile(cue_reffile_regexp)
re_cue_index = re.compile(cue_index_regexp)
#splitbin = "ffmpeg"
splitbin = "avconv"
def main():
(filename, split_length) = parse_options()
if split_length <= 0:
# Cuesheet operation (individual split lengths)
cuefile = open (filename)
cue=cuefile.read ()
cuefile.close ()
filename = re_cue_reffile.search(cue).group(1)
#This finds only the first FILE; there should be only one FILE per cuesheet for this script being and working reasonable.
split_points = [int(indx.group(1))*60 + int(indx.group(2)) + float(indx.group(3))/75 for indx in re_cue_index.finditer(cue)]
equal = False
else:
equal = True
output = subprocess.Popen(splitbin+" -i '"+filename+"' 2>&1 | grep 'Duration'",
shell = True,
stdout = subprocess.PIPE
).stdout.read()
print output
matches = re_length.search(output)
if matches:
video_length = int(matches.group(1)) * 3600 + \
int(matches.group(2)) * 60 + \
int(matches.group(3))
print "Video length in seconds: "+str(video_length)
else:
print "Can't determine video length."
raise SystemExit
if equal:
split_count = int(math.ceil(video_length/float(split_length)))
if(split_count == 1):
print "Video length is less then the target split length."
raise SystemExit
split_cmd = splitbin + " -i '"+filename+"' -vcodec copy "
for n in range(0, split_count):
split_str = ""
if n == 0:
split_start = 0
else:
split_start = split_length * n
split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
" '"+filename[:-4] + "-" + str(n) + "." + filename[-3:] + \
"'"
print "About to run: "+split_cmd+split_str
output = subprocess.Popen(split_cmd+split_str, shell = True, stdout =
subprocess.PIPE).stdout.read()
else:
if(len (split_points) <= 1):
print "There aren't at least two indices in cuefile."
raise SystemExit
split_cmd = splitbin + " -i '"+filename+"' -codec copy " # Enable audio, too
n = 0
split_points.append(-1)
split_start = split_points [0]
for split_end in split_points[1:]:
split_str = " -ss "+str(split_start)+((" -t "+str(split_end - split_start)) if split_end != -1 else "") + \
" '"+filename[:-4] + "-" + str(n) + "." + filename[-3:] + \
"'" #Omit -t when last piece will be created
print "About to run: "+split_cmd+split_str
output = subprocess.Popen(split_cmd+split_str, shell = True, stdout =
subprocess.PIPE).stdout.read()
n += 1
split_start = split_end
def parse_options():
parser = OptionParser()
parser.add_option("-f", "--file",
dest = "filename",
help = "file to split, for example sample.avi",
type = "string",
action = "store"
)
parser.add_option("-s", "--split-size",
dest = "split_size",
help = "split or chunk size in seconds, for example 10; if 0 is given, -f refers to a cuefile",
type = "int",
action = "store"
)
(options, args) = parser.parse_args()
if options.filename and (options.split_size != None):
return (options.filename, options.split_size)
else:
parser.print_help()
raise SystemExit
if __name__ == '__main__':
try:
main()
except Exception, e:
print "Exception occured running main():"
print str(e)This isn't fairly tested and should give only the idea.
If the equidistantly splitting would be done in a slighty other way (namely by first building a list of split_starts and split_length or better split_ends and then doing the actual job), there could be less excess code for both if-cases.
It uses -s=0 as flag to interpret -f as cuefile; this may seem to be unaesthetic.
I used it to split m4a sound-only files, therefore I got to change from "-vcodec" to "-acodec". Because just "-codec" also worked, I just left it. I don't know what the impact would be to actual videos. I left the equidistant part, it still uses "-vcodec" for now.
Finally, as my system uses avconv instead of ffmpeg, I put its name into a variable to be able to simply change it in the source. Another idea: Retrieve file name of script (don't know if this is possible under python like it can be done under bash by retrieving argument no. 0), chop off the "-split.py" part and use the remaining as tool’s name – so you’d use "ffmpeg-split.py" whereas I’d rename it to "avconv-split.py".
I haven't tracked down it thoroughly, but I'm suspiciously wondering if your code possibly omits the last fraction of seconds of the source video, because it handles only integer seconds.
Thanks – Peter