Python – Using Python script to cut long videos into chunks in FFMPEG

ffmpegpythonpython-2.7python-3.xvideo

Starting off by saying I'm not a programmer, but I really need the application this Python script I found says it can do.

Auto-Splitting Script by Antarctic Nest of Icephoenix

Basically I have a directory of long .MP4s that need to be cut into equal parts based on a total running time of 3 hours 15 minutes. For example, I would have an 8 hour video that needs to be cut into smaller parts each under 3:15:00.

We've been manually crating FFMPEG codes to do this, but I found the Python script above that seems like it will do what we are needing. The issue is that I have no Python experience. I don't know where in the script to enter in the folder path with the videos, or where to specify my codecs, or where to tell the program that the max time for each video chunk is 3:15:00.

I'm on a 64-bit windows system working in command prompt

Here's what I have done:

  • Installed python 3
  • downloaded the script
  • I can click on the script to see the cmd window flash to indicate it's running
  • I enter "C:\Python34\python.exe V:\ffmpeg\ffmpeg-split.py" into cmd
  • output is

    File "V:\ffmpeg\ffmpeg-split.py", line 16
    print "Split length can't be 0"

      SyntaxError: Missing parentheses in call to 'print'
    

I have no idea where to go from here. It seems like the script is loading properly, but I haven't entered my variables. Any help with where to put the information would be appreciated.

Here is the FFMPEG code we usually use:

ffmpeg -i V:\ffmpeg\88518_63c392af.mp4 -vcodec libx264 -acodec copy -vf fps=fps=30000/1001 -ss 00:05:01.000 -t 02:43:49.000 V:\events\88518.mp4

The ffmpeg codes we use:

-i is a .mp4

-vcodec h.264 codec

-acodec should be “copy” or can be “libvo_aacenc”

-vf fps=30000/1000 a forced fps of 29.97

-ss is start time (we would use this to manually cut into parts along with -t)

-t is duration (we would calculate the duration for each part as the total run time divided by the equal time under 3:15:00 be it two, three, or four parts)

Thank you a million dollars

Best Solution

You need to add parens to the print's and change the exception syntax to except Exception as e:

import subprocess
import re
import math
from optparse import OptionParser


length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
re_length = re.compile(length_regexp)

def main():

    (filename, split_length) = parse_options()
    if split_length <= 0:
        print("Split length can't be 0")
        raise SystemExit

    output = subprocess.Popen("ffmpeg -i '"+filename+"' 2>&1 | grep 'Duration'",
                            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 = 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 = "ffmpeg -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()


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",
                        type = "int",
                        action = "store"
                        )
    (options, args) = parser.parse_args()

    if options.filename and options.split_size:

        return (options.filename, options.split_size)

    else:
        parser.print_help()
        raise SystemExit

if __name__ == '__main__':

    try:
        main()
    except Exception as e:
        print("Exception occured running main():")
        print(e)

After those changes the script will run fine, it could also improved.

Updated version should be compatible with python2 and 3:

import re
import math
from optparse import OptionParser

length_regexp = 'Duration: (\d{2}):(\d{2}):(\d{2})\.\d+,'
re_length = re.compile(length_regexp)

from subprocess import check_call, PIPE, Popen
import shlex

def main():
    filename, split_length = parse_options()
    if split_length <= 0:
        print("Split length can't be 0")
        raise SystemExit

    p1 = Popen(["ffmpeg", "-i", filename], stdout=PIPE, stderr=PIPE, universal_newlines=True)
    # get p1.stderr as input
    output = Popen(["grep", 'Duration'], stdin=p1.stderr, stdout=PIPE, universal_newlines=True)
    p1.stdout.close()
    matches = re_length.search(output.stdout.read())
    if matches:
        video_length = int(matches.group(1)) * 3600 + \
                       int(matches.group(2)) * 60 + \
                       int(matches.group(3))
        print("Video length in seconds: {}".format(video_length))
    else:
        print("Can't determine video length.")
        raise SystemExit

    split_count = math.ceil(video_length / split_length)

    if split_count == 1:
        print("Video length is less than the target split length.")
        raise SystemExit

    for n in range(split_count):
        split_start = split_length * n
        pth, ext = filename.rsplit(".", 1)
        cmd = "ffmpeg -i {} -vcodec copy  -strict -2 -ss {} -t {} {}-{}.{}".\
            format(filename, split_start, split_length, pth, n, ext)
        print("About to run: {}".format(cmd))
        check_call(shlex.split(cmd), universal_newlines=True)


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",
                      type="int",
                      action="store"
    )
    (options, args) = parser.parse_args()

    if options.filename and options.split_size:

        return options.filename, options.split_size

    else:
        parser.print_help()
        raise SystemExit

if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        print(e)