SoFunction
Updated on 2025-04-28

Python calls ffmpeg to intercept video clips and perform batch processing

background

I downloaded some anime locally, but the opening and endings are useless and take up space, so I decided to use ffmpeg to cut the video and only retain the main content in the middle.

The ffmpeg command used

ffmpegChinese Documentation:/

​​​​​ Let’s talk about what you use firstffmpegCommands that you can execute in the cmd window yourself to process a single video.

  1. Get video duration:ffprobe -show_entries format=duration -v error -select_streams v:0 <video path>
    Sample output:
[FORMAT]
duration=1200.981333
[/FORMAT]
  1. ffmpeg -threads 4 -i <video path> -ss <start time point> -t <duration(s)> -c copy -y <output path>
    • -threads 4: Multi-threading, it doesn't feel that it's very useful
    • <Start time>:The format can behh:mm:ss, it can also be used as a specific video in what second
    • <Duration(s)>: How many seconds are intercepted from the specified starting time point, not the ending time point
    • -c copy: Copy both audio and video directly, without re-encoding, fast
    • -y: If the specified output file already exists, overwrite
    • Notice: If the output path is in other folders, you must create the folder in advance, such as the output file is./trimed_video/video.mp4, you need to create it in advancetrimed_videoFolder, otherwise an error will be reported

Python calls bash directive method

usesubprocessPackage, you can check the details by yourself, the simple usage is as follows:

import subprocess

command = "ffprobe -show_entries format=duration -v error -select_streams v:0 video.mp4"
result = (command, check=True,capture_output=True,text=True)
print() # Get the output data after the command is executed

Parameter description:

  • command: The command string to be executed can be spliced ​​through string operations to splice the required commands
  • check=True: If the process exit code is not 0, an exception is thrown, can be used to handle errors through try-catch
  • capture_output=True: Capture standard output or standard errors, obtain the output information of command execution
  • text=True: The default standard output is byte type, which can be changed to string type to facilitate string parsing

Python processing code

Note that all my codes do not consider videos with a duration of more than 1 hour. If you need to operate videos with a duration of more than 1 hour, please modify the relevant code yourself.

Prepare the function

Since these two functions may be used in multiple files, a separate file is created, and the other files need to be called throughimport myfuncJust

""""""
import os,re
from pathlib import Path
def match_files(dir,extension,content_range=[], not_content_range=[]):
    """Find files that match extensions in the specified directory,Don't recurse

    Usage example:match_files("./",[".mp4", ".mkv"],range(74,80+1))
    
    extension:The required extension,List of strings
    content_range:Range included,If empty, no restrictions,Integer list
    not_content_range:不Range included,Integer list
    """
    matchs = []
    files = (dir)
    for f in files:
        if Path(f).suffix in extension: # Check whether the file extension is in the specified extension list            # Extract the first sequence of numbers in the file name as number            number = int((r'\d+',f)[0])
            if content_range:# Determine whether the inclusion range is specified, and if specified, it determines whether it is within the range                if number in content_range  and number not in not_content_range :
                    (f)
            else: # If the range is not specified, match all                if number not in not_content_range :
                    (f)
    return matchs

def time_to_seconds(time_str):
    """Convert time string to seconds, format mm:ss"""
    minutes, seconds = map(int, time_str.split(':'))
    return  minutes * 60 + seconds

Python batch processing

import myfunc
import subprocess
import re
"""
 Pay attention to writing the path, extension, and the number range that needs to be processed and the number range that is excluded.
 """
videos = myfunc.match_files("./",[".mp4", ".mkv"],[140])
start_time_point = "02:35"
end_time_point = "17:42"
for video in videos:
    # If the file name has spaces, quotes are required    command1 = "ffprobe -show_entries format=duration -v error -select_streams v:0 \""+video+"\""
    try:
        # Get the video time first        result = (command1, check=True,capture_output=True,text=True)
        duration = round(float((r"duration=([\d.]+)",).group(1)))
        """Please modify the parameters of command2,
         The default hour of 00 is 00, which means that the time exceeds 1 hour is not considered, and the modification is required.
         "\"./trimed_video/"+video+"\""It's the output video path
         Need to modify according to your video situation
         """
        command2 = "ffmpeg -threads 4 -i "+"\""+ video +"\""+ " -ss 00:" + start_time_point + " -t "+str(myfunc.time_to_seconds(end_time_point)-myfunc.time_to_seconds(start_time_point)) +" -c copy -y "+"\"./trimed_video/"+video+"\""
        try:
            # Run the FFmpeg command            (command2, check=True,capture_output=True)
            print(f"The video has been successfully cropped to {video}")
        except  as e:
            print(f"FFmpegCommand execution failed: {e}", video)
    except  as e:
        print(f"FFmpegCommand execution failed: {e}", video)

Special circumstances handling

Perhaps the opening and ending length of the video is not always fixed, which makes it impossible to conveniently follow the code processed in python batches and directly operate according to the same opening and ending length. Therefore, I used the csv table to record the opening and ending length of the video, and used python to crop the video according to the data in the csv table.

The csv table example content is as followsEnd and ending information.csv

​​​Serial numberTitle time pointEnd time pointTotal durationIt is a required item, and the remaining two items can be empty, but an English semicolon must be filled in.
actuallyTotal durationYou can get it through the ffmpeg command, but since it is a special situation, you can manually open the video, so it is not troublesome to fill in the total time.

Optional operation: Fill in csv data

Sometimes you need to fill in a few video information to determine whether the video between these two serial numbers has the same opening and ending time. If the same, you can operate it through python batch processing code. Therefore, after writing the following code, you can automatically calculate the last two columns of data in the csv table and observeTitle time pointandEnd lengthCan you always judge whether it is a rough way

import csv

# File pathfile_path = "./Open and end information.csv"
# Convert time string to secondsdef time_to_seconds(time_str):
    minutes, seconds = map(int, time_str.split(':'))
    return  minutes * 60 + seconds

# Read CSV filewith open(file_path, mode='r', encoding='utf-8') as file:
    reader = (file)
    rows = list(reader)

rows = [row for row in rows if row]
for i in range(1, len(rows)):
    end_time_str = rows[i][2]
    if rows[i][4]  != '':
        continue # If there is already a value, it will no longer be calculated    total_duration_str = rows[i][3]
    end_time_seconds = time_to_seconds(end_time_str)
    total_duration_seconds = time_to_seconds(total_duration_str)
    tail_length_seconds = total_duration_seconds - end_time_seconds
    rows[i][4] = str(tail_length_seconds)
    start_time_seconds = time_to_seconds(rows[i][1])
    rows[i][5] = str(end_time_seconds - start_time_seconds)

# Write the updated content back to the CSV filewith open(file_path, mode='w', newline='', encoding='utf-8') as file:
    writer = (file)
    (rows)

python crops videos based on csv data

import csv

# File pathfile_path = "./Open and end information.csv"
# Convert time string to secondsdef time_to_seconds(time_str):
    minutes, seconds = map(int, time_str.split(':'))
    return  minutes * 60 + seconds

# Read CSV filewith open(file_path, mode='r', encoding='utf-8') as file:
    reader = (file)
    rows = list(reader)

rows = [row for row in rows if row]
for i in range(1, len(rows)):
    end_time_str = rows[i][2]
    if rows[i][4]  != '':
        continue # If there is already a value, it will no longer be calculated    total_duration_str = rows[i][3]
    end_time_seconds = time_to_seconds(end_time_str)
    total_duration_seconds = time_to_seconds(total_duration_str)
    tail_length_seconds = total_duration_seconds - end_time_seconds
    rows[i][4] = str(tail_length_seconds)
    start_time_seconds = time_to_seconds(rows[i][1])
    rows[i][5] = str(end_time_seconds - start_time_seconds)

# Write the updated content back to the CSV filewith open(file_path, mode='w', newline='', encoding='utf-8') as file:
    writer = (file)
    (rows)

python crops videos based on csv data

import myfunc
import csv, re,subprocess
"""Please modify the file extension you want to match"""
videos = myfunc.match_files("./",[".mp4", ".mkv"])
"""Please change to your csv file path"""
with open("./Open and end information.csv", mode='r', encoding='utf-8') as file:
    reader = (file)
    rows = list(reader)

# Extract the first column of datadel rows[0]# Delete the table headerfirst_column = [int(row[0]) for row in rows if row]  # Use list comprehensions to skip empty linesvideos = [video for video in videos if int((r'\d+',video)[0]) in first_column]

count = 0
for video in videos:
    command1 = "ffprobe -show_entries format=duration -v error -select_streams v:0 \""+video+"\""
    try:
        # Get the video time first        result = (command1, check=True,capture_output=True,text=True)
        duration = round(float((r"duration=([\d.]+)",).group(1)))
        start_time_pint = myfunc.time_to_seconds(rows[count][1])
        end_time_pount = myfunc.time_to_seconds(rows[count][2])
        """Please replace the output path you want"""
        command2 = "ffmpeg -threads 4 -i "+video + " -ss " + str(start_time_pint) + " -t "+str(end_time_pount-start_time_pint) +" -c copy -y "+"\"./trimed_video/"+video+"\""
        # print(command2)
        try:
            # Run the FFmpeg command            (command2, check=True,capture_output=True)
            print(f"The video has been successfully cropped to {video}")
        except  as e:
            print(f"FFmpegCommand execution failed: {e}", video)
    except  as e:
        print(f"FFmpegCommand execution failed: {e}", video)
    count += 1

Processing of videos with multiple clips [TODO]

If anyone knows it, please discuss it. I think it’s too troublesome to slice first and then merge.
This special situation usually occurs when the video contains easter eggs, and there is still the main content before or after the end of the movie.

I searched online but couldn't find a very good one. I found an article but it was not easy to use after testing, so I chose to slice it manually and merge it.
ffmpeg command for merging multiple videos:

  1. Create a text fileand write multiple video clips to be merged
file 'input1.mp4' 
file 'input2.mp4'
  • Execute the merge command:ffmpeg -f concat -safe 0 -i -c copy output.mp4Since this situation is relatively rare, I am too lazy to write python code, so I can execute it manually in cmd

The above is the detailed content of Python calling ffmpeg to intercept video clips and perform batch processing. For more information about Python ffmpeg intercept video batch processing, please pay attention to my other related articles!