mirror of
https://github.com/c0decracker/video-splitter.git
synced 2026-01-23 02:24:16 +00:00
Merge 9f628da12a into edcd7e9b12
This commit is contained in:
commit
f157917f65
1 changed files with 190 additions and 98 deletions
288
ffmpeg-split.py
288
ffmpeg-split.py
|
|
@ -11,9 +11,10 @@ import subprocess
|
|||
from optparse import OptionParser
|
||||
|
||||
|
||||
def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
||||
extra="", **kwargs):
|
||||
""" Split video into segments based on the given manifest file.
|
||||
def split_by_manifest(
|
||||
filename, manifest, vcodec="copy", acodec="copy", extra="", **kwargs
|
||||
):
|
||||
"""Split video into segments based on the given manifest file.
|
||||
|
||||
Arguments:
|
||||
filename (str) - Location of the video.
|
||||
|
|
@ -35,15 +36,24 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
elif manifest_type == "csv":
|
||||
config = csv.DictReader(manifest_file)
|
||||
else:
|
||||
print("Format not supported. File must be a csv or json file")
|
||||
raise SystemExit
|
||||
raise SystemExit("Format not supported. File must be a csv or json file")
|
||||
|
||||
split_cmd = [
|
||||
"ffmpeg",
|
||||
"-i",
|
||||
filename,
|
||||
"-vcodec",
|
||||
vcodec,
|
||||
"-acodec",
|
||||
acodec,
|
||||
"-y",
|
||||
] + shlex.split(extra)
|
||||
|
||||
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_args = []
|
||||
try:
|
||||
|
|
@ -55,8 +65,13 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
if fileext in filebase:
|
||||
filebase = ".".join(filebase.split(".")[:-1])
|
||||
|
||||
split_args += ["-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: " + " ".join(split_cmd + split_args))
|
||||
print("########################################################")
|
||||
|
|
@ -70,42 +85,79 @@ def split_by_manifest(filename, manifest, vcodec="copy", acodec="copy",
|
|||
print("start_time,length,rename_to should be the first line ")
|
||||
print("in the csv file.")
|
||||
print("#############################################")
|
||||
print(e)
|
||||
raise SystemExit
|
||||
raise SystemExit(e)
|
||||
|
||||
|
||||
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()
|
||||
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):
|
||||
def ceildiv(a: float, b: float) -> float:
|
||||
"""Helper function to simplify ceiling division.
|
||||
|
||||
See math.ceil for more information.
|
||||
Args:
|
||||
a (float): The dividend.
|
||||
b (float): The divisor, must be strictly > 0.
|
||||
|
||||
Returns:
|
||||
float: The quotient of a and b.
|
||||
"""
|
||||
return int(math.ceil(a / float(b)))
|
||||
|
||||
|
||||
def split_by_seconds(filename, split_length, vcodec="copy", acodec="copy",
|
||||
extra="", video_length=None, **kwargs):
|
||||
def split_by_seconds(
|
||||
filename,
|
||||
split_length,
|
||||
vcodec="copy",
|
||||
acodec="copy",
|
||||
extra="",
|
||||
video_length=None,
|
||||
**kwargs
|
||||
):
|
||||
if split_length and split_length <= 0:
|
||||
print("Split length can't be 0")
|
||||
raise SystemExit
|
||||
raise SystemExit("Split length can't be 0")
|
||||
|
||||
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", filename, "-vcodec", vcodec, "-acodec", acodec] + shlex.split(extra)
|
||||
split_count = ceildiv(video_length, split_length)
|
||||
|
||||
if split_count == 1:
|
||||
raise SystemExit("Video length is less then the target split length.")
|
||||
|
||||
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_args = []
|
||||
if n == 0:
|
||||
|
|
@ -113,9 +165,13 @@ def split_by_seconds(filename, split_length, vcodec="copy", acodec="copy",
|
|||
else:
|
||||
split_start = split_length * n
|
||||
|
||||
split_args += ["-ss", str(split_start), "-t", str(split_length),
|
||||
filebase + "-" + str(n + 1) + "-of-" +
|
||||
str(split_count) + "." + fileext]
|
||||
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)
|
||||
|
||||
|
|
@ -123,75 +179,103 @@ def split_by_seconds(filename, split_length, vcodec="copy", acodec="copy",
|
|||
def main():
|
||||
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_length",
|
||||
help="Split or chunk size in seconds, for example 10",
|
||||
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. ",
|
||||
type="string",
|
||||
action="store"
|
||||
)
|
||||
parser.add_option("-v", "--vcodec",
|
||||
dest="vcodec",
|
||||
help="Video codec to use. ",
|
||||
type="string",
|
||||
default="copy",
|
||||
action="store"
|
||||
)
|
||||
parser.add_option("-a", "--acodec",
|
||||
dest="acodec",
|
||||
help="Audio codec to use. ",
|
||||
type="string",
|
||||
default="copy",
|
||||
action="store"
|
||||
)
|
||||
parser.add_option("-e", "--extra",
|
||||
dest="extra",
|
||||
help="Extra options for ffmpeg, e.g. '-e -threads 8'. ",
|
||||
type="string",
|
||||
default="",
|
||||
action="store"
|
||||
)
|
||||
(options, args) = parser.parse_args()
|
||||
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_length",
|
||||
help="Split or chunk size in seconds, for example 10",
|
||||
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. ",
|
||||
type="string",
|
||||
action="store",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"-v",
|
||||
"--vcodec",
|
||||
dest="vcodec",
|
||||
help="Video codec to use. ",
|
||||
type="string",
|
||||
default="copy",
|
||||
action="store",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"-a",
|
||||
"--acodec",
|
||||
dest="acodec",
|
||||
help="Audio codec to use. ",
|
||||
type="string",
|
||||
default="copy",
|
||||
action="store",
|
||||
)
|
||||
|
||||
parser.add_option(
|
||||
"-e",
|
||||
"--extra",
|
||||
dest="extra",
|
||||
help="Extra options for ffmpeg, e.g. '-e -threads 8'. ",
|
||||
type="string",
|
||||
default="",
|
||||
action="store",
|
||||
)
|
||||
|
||||
options, _ = parser.parse_args()
|
||||
|
||||
def bailout():
|
||||
parser.print_help()
|
||||
|
|
@ -208,18 +292,26 @@ def main():
|
|||
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':
|
||||
|
||||
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)
|
||||
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__':
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue