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
ffmpeg
Chinese Documentation:/
Let’s talk about what you use firstffmpeg
Commands that you can execute in the cmd window yourself to process a single video.
- Get video duration:
ffprobe -show_entries format=duration -v error -select_streams v:0 <video path>
Sample output:
[FORMAT] duration=1200.981333 [/FORMAT]
-
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_video
Folder, otherwise an error will be reported
-
Python calls bash directive method
usesubprocess
Package, 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 myfunc
Just
"""""" 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 number
,Title time point
,End time point
,Total duration
It is a required item, and the remaining two items can be empty, but an English semicolon must be filled in.
actuallyTotal duration
You 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 point
andEnd length
Can 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:
- Create a text file
and 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.mp4
Since 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!