使用Python脚本在FFMPEG中将长视频分割成块

6

首先声明,我不是程序员,但我真的需要这个Python脚本所说的应用程序。

Antarctic Nest of Icephoenix的自动分割脚本

基本上,我有一个包含长时间 .MP4 文件的目录,需要根据总运行时间为3小时15分钟将其切成相等的部分。例如,我有一个8小时的视频,需要将其切成每个小于3:15:00的较小部分。

我们一直在手动创建FFMPEG代码来完成此操作,但我发现了上面的Python脚本,它似乎可以满足我们的需求。问题是我没有Python经验。我不知道在脚本中输入带有视频的文件夹路径,在哪里指定我的编解码器,或在哪里告诉程序每个视频块的最大时间为3:15:00。

我在64位Windows系统上通过命令提示符工作。

以下是我已经完成的内容:

  • 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'
    

我不知道该从哪里开始。看起来脚本已经正确加载,但我还没有输入变量。任何有关在哪里放置信息的帮助都将不胜感激。

这是我们通常使用的FFMPEG代码:

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

我们使用的FFMPEG代码:

-i 是 .mp4 文件

-vcodec h.264 编解码器

-acodec 应该是“copy”,或者可以是“libvo_aacenc”

-vf fps=30000/1000 强制帧速率为29.97

-ss 是开始时间(我们将与 -t 一起手动剪切成多个部分)

-t 是持续时间(我们将根据总运行时间除以3:15:00下的等时长计算每个部分的持续时间,无论是两个、三个还是四个部分)

谢谢你!

3个回答

4

您需要在print语句中添加括号,并将异常语法更改为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)

在进行这些更改之后,脚本将可以正常运行,并且还可以得到进一步的改进。

更新版本应该与Python2和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)

没问题,我已经在一个mp4文件上测试过了,它的表现符合预期。你想用一个命令将目录中的所有mp4文件转换吗? - Padraic Cunningham
我在考虑是否应该将我的命令放在选项的括号中。你能否粘贴一下你成功运行的代码?我认为这只是一个语法问题。 - Michael Hamilton
1
ffmpeg -i /home/padraic/horses/ams.mp4 -vcodec libx264 -acodec copy -vf fps=fps=30000/1001 -ss 00:05:01.000 -t 02:43:49.000 foo.mp4` - Padraic Cunningham
运行FFmpeg代码时,您不需要包含脚本吗? - Michael Hamilton
@MichaelHamilton。已添加更新的脚本,我删除了对shell=True的需求并整理了其余部分,只需像这样调用它python3 ffmp.py -f /home/padraic/horses/ams.mp4 - Padraic Cunningham
显示剩余4条评论

0

你可以从这里安装FFMPEG

以下是将长视频剪辑成每段5分钟(即600秒)的Python代码:

import os
import re
import sys
import subprocess
from decimal import Decimal

process = subprocess.Popen(['ffmpeg', '-i', path_of_video_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, stderr = process.communicate()
matches = re.search(r"Duration:\s{1}(?P<hours>\d+?):(?P<minutes>\d+?):(?P<seconds>\d+\.\d+?),", stdout, re.DOTALL).groupdict()
total_sec=(Decimal(matches['hours'])*60*60)+(Decimal(matches['minutes'])*60)+(Decimal(matches['seconds']))    #duration of the media file

dir_name=path_of_video_file.split('.')[0]+"_chunks"
if not os.path.exists(dir_name):                 
    os.makedirs(dir_name)       #creating directory to save the chunks of the media file

from_time=0
file_no=1
file_names=path_of_video_file.split('.')[0]+'_'
while total_sec>0:
    os.system('ffmpeg -ss '+str(from_time)+' -t 600 -i '+path_of_video_file+' '+dir_name+'/'+file_names+str(file_no)+'.mp4')   #In case if you want the chunks of the file to be in other formats then you can change 'mp4' to the required audio or video format.
    file_no=file_no+1
    from_time=from_time+600
    total_sec=total_sec-600

0

看起来这个 Python 脚本是用 Python 2 写的。不幸的是,它不能在 Python 3 上运行。你需要卸载 Python 3 并安装 Python 2.7。


那将是一个很好的开始。谢谢。 - Michael Hamilton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接