mirror of
https://github.com/c0decracker/video-splitter.git
synced 2026-01-23 02:24:16 +00:00
Merge pull request #12 from csabahenk/master
some cleanups & enhancements
This commit is contained in:
commit
14c9360d2b
1 changed files with 81 additions and 48 deletions
129
ffmpeg-split.py
129
ffmpeg-split.py
|
|
@ -2,16 +2,13 @@
|
|||
|
||||
import csv
|
||||
import subprocess
|
||||
import re
|
||||
import math
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
|
||||
re_length = re.compile(length_regexp)
|
||||
|
||||
def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
||||
extra="", **kwargs):
|
||||
""" Split video into segments based on the given manifest file.
|
||||
|
|
@ -39,18 +36,15 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
print "Format not supported. File must be a csv or json file"
|
||||
raise SystemExit
|
||||
|
||||
split_cmd = "ffmpeg -i '%s' -vcodec %s -acodec %s -y %s" % (filename,
|
||||
vcodec,
|
||||
acodec,
|
||||
extra)
|
||||
split_count = 1
|
||||
split_error = []
|
||||
split_cmd = ["ffmpeg", "-i", filename, "-vcodec", vcodec,
|
||||
"-acodec", acodec, "-y"] + shlex.split(extra)
|
||||
try:
|
||||
fileext = filename.split(".")[-1]
|
||||
except IndexError as e:
|
||||
raise IndexError("No . in filename. Error: " + str(e))
|
||||
for video_config in config:
|
||||
split_str = ""
|
||||
split_args = []
|
||||
try:
|
||||
split_start = video_config["start_time"]
|
||||
split_length = video_config.get("end_time", None)
|
||||
|
|
@ -60,16 +54,12 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
if fileext in filebase:
|
||||
filebase = ".".join(filebase.split(".")[:-1])
|
||||
|
||||
split_str += " -ss " + str(split_start) + " -t " + \
|
||||
str(split_length) + \
|
||||
" '"+ filebase + "." + fileext + \
|
||||
"'"
|
||||
split_args += ["-ss", str(split_start), "-t",
|
||||
str(split_length), filebase + "." + fileext]
|
||||
print "########################################################"
|
||||
print "About to run: "+split_cmd+split_str
|
||||
print "About to run: "+" ".join(split_cmd+split_args)
|
||||
print "########################################################"
|
||||
output = subprocess.Popen(split_cmd+split_str,
|
||||
shell = True, stdout =
|
||||
subprocess.PIPE).stdout.read()
|
||||
subprocess.check_output(split_cmd+split_args)
|
||||
except KeyError as e:
|
||||
print "############# Incorrect format ##############"
|
||||
if manifest_type == "json":
|
||||
|
|
@ -82,53 +72,48 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
print e
|
||||
raise SystemExit
|
||||
|
||||
def get_video_length(filename):
|
||||
|
||||
output = subprocess.check_output(("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", filename)).strip()
|
||||
video_length = int(float(output))
|
||||
print "Video length in seconds: "+str(video_length)
|
||||
|
||||
return video_length
|
||||
|
||||
def ceildiv(a, b):
|
||||
return int(math.ceil(a / float(b)))
|
||||
|
||||
def split_by_seconds(filename, split_length, vcodec="copy", acodec="copy",
|
||||
extra="", **kwargs):
|
||||
extra="", video_length=None, **kwargs):
|
||||
if split_length and split_length <= 0:
|
||||
print "Split length can't be 0"
|
||||
raise SystemExit
|
||||
|
||||
output = subprocess.Popen("ffmpeg -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
|
||||
split_count = int(math.ceil(video_length/float(split_length)))
|
||||
if not video_length:
|
||||
video_length = get_video_length(filename)
|
||||
split_count = ceildiv(video_length, split_length)
|
||||
if(split_count == 1):
|
||||
print "Video length is less then the target split length."
|
||||
raise SystemExit
|
||||
|
||||
split_cmd = "ffmpeg -i '%s' -vcodec %s -acodec %s %s" % (filename, vcodec,
|
||||
acodec, extra)
|
||||
split_cmd = ["ffmpeg", "-i", filename, "-vcodec", vcodec, "-acodec", acodec] + shlex.split(extra)
|
||||
try:
|
||||
filebase = ".".join(filename.split(".")[:-1])
|
||||
fileext = filename.split(".")[-1]
|
||||
except IndexError as e:
|
||||
raise IndexError("No . in filename. Error: " + str(e))
|
||||
for n in range(0, split_count):
|
||||
split_str = ""
|
||||
split_args = []
|
||||
if n == 0:
|
||||
split_start = 0
|
||||
else:
|
||||
split_start = split_length * n
|
||||
|
||||
split_str += " -ss "+str(split_start)+" -t "+str(split_length) + \
|
||||
" '"+filebase + "-" + str(n) + "." + fileext + \
|
||||
"'"
|
||||
print "About to run: "+split_cmd+split_str
|
||||
output = subprocess.Popen(split_cmd+split_str, shell = True, stdout =
|
||||
subprocess.PIPE).stdout.read()
|
||||
split_args += ["-ss", str(split_start), "-t", str(split_length),
|
||||
filebase + "-" + str(n+1) + "-of-" + \
|
||||
str(split_count) + "." + fileext]
|
||||
print "About to run: "+" ".join(split_cmd+split_args)
|
||||
subprocess.check_output(split_cmd+split_args)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -146,6 +131,35 @@ def main():
|
|||
type = "int",
|
||||
action = "store"
|
||||
)
|
||||
parser.add_option("-c", "--split-chunks",
|
||||
dest = "split_chunks",
|
||||
help = "Number of chunks to split to",
|
||||
type = "int",
|
||||
action = "store"
|
||||
)
|
||||
parser.add_option("-S", "--split-filesize",
|
||||
dest = "split_filesize",
|
||||
help = "Split or chunk size in bytes (approximate)",
|
||||
type = "int",
|
||||
action = "store"
|
||||
)
|
||||
parser.add_option("--filesize-factor",
|
||||
dest = "filesize_factor",
|
||||
help = "with --split-filesize, use this factor in time to" \
|
||||
" size heuristics [default: %default]",
|
||||
type = "float",
|
||||
action = "store",
|
||||
default = 0.95
|
||||
)
|
||||
parser.add_option("--chunk-strategy",
|
||||
dest = "chunk_strategy",
|
||||
help = "with --split-filesize, allocate chunks according to" \
|
||||
" given strategy (eager or even)",
|
||||
type = "choice",
|
||||
action = "store",
|
||||
choices = ['eager', 'even'],
|
||||
default = 'eager'
|
||||
)
|
||||
parser.add_option("-m", "--manifest",
|
||||
dest = "manifest",
|
||||
help = "Split video based on a json manifest file. ",
|
||||
|
|
@ -175,13 +189,32 @@ def main():
|
|||
)
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.filename and options.manifest:
|
||||
split_by_manifest(**(options.__dict__))
|
||||
elif options.filename and options.split_length:
|
||||
split_by_seconds(**(options.__dict__))
|
||||
else:
|
||||
def bailout():
|
||||
parser.print_help()
|
||||
raise SystemExit
|
||||
|
||||
if not options.filename:
|
||||
bailout()
|
||||
|
||||
if options.manifest:
|
||||
split_by_manifest(**(options.__dict__))
|
||||
else:
|
||||
video_length = None
|
||||
if not options.split_length:
|
||||
video_length = get_video_length(options.filename)
|
||||
file_size = os.stat(options.filename).st_size
|
||||
split_filesize = None
|
||||
if options.split_filesize:
|
||||
split_filesize = int(options.split_filesize * options.filesize_factor)
|
||||
if split_filesize and options.chunk_strategy == 'even':
|
||||
options.split_chunks = ceildiv(file_size, split_filesize)
|
||||
if options.split_chunks:
|
||||
options.split_length = ceildiv(video_length, options.split_chunks)
|
||||
if not options.split_length and split_filesize:
|
||||
options.split_length = int(split_filesize / float(file_size) * video_length)
|
||||
if not options.split_length:
|
||||
bailout()
|
||||
split_by_seconds(video_length=video_length, **(options.__dict__))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue