1. Article directory
After reading this article, you will be able to learn the following:
- Batch video frame extraction;
- Add srt subtitles;
- Add srt dubbing;
- Add background music;
- Combine multiple video clips into a new video;
Effect:
2. Install dependencies
First install the video processing libraries opencv-python
and moviepy
. The installation method is pip install xxx.
py file at the top (the functions used below will not be described in detail in the import process):
from moviepy.editor import VideoFileClip, CompositeAudioClip, CompositeVideoClip, concatenate_videoclips from cv2 import VideoCapture, VideoWriter, VideoWriter_fourcc, CAP_PROP_FRAME_COUNT
2. Video frame extraction
cv2.VideoCapture:
Function: Used to capture video frames from video files or cameras.
Explanation: This function allows you to create a video capture object to read video frames from the specified video source. You can pass the path to the video file or the index of the camera as a parameter and then use that to read the video frame by frame.
cv2.VideoWriter:
Function: Used to write video frames to a new video file.
Explanation: This function allows you to create a video writer object to write video frames to a new video file. You can specify the output file name, video codec, frame rate, resolution and other parameters. This is very useful when editing videos and saving processed videos.
cv2.VideoWriter_fourcc:
Function: Used to specify the four-character code (FourCC) of the video codec.
Explanation: FourCC is a 4-byte code used to identify the video codec. Different codecs have different FourCC codes. By using this function you can select the codec to use in the output video.
CAP_PROP_FRAME_COUNT:
Function: Used to obtain the total number of frames in the video file.
Explanation: CAP_PROP_FRAME_COUNT is a property of the cv2.VideoCapture object, used to obtain the total number of frames in the video file. This is useful for things like determining the duration of a video and looping the video.
Complete code block:
# Single video frame extraction def video_extract_frame(video_path, out_path): #Open video file vc = VideoCapture(video_path) #The total number of frames in the video total_frame = int(vc.get(CAP_PROP_FRAME_COUNT)) video = VideoFileClip(video_path, audio=False) # # Create a video writing object. Set video width and height, frame rate, output path fourcc = VideoWriter_fourcc(*'mp4v') videoWriter = VideoWriter(out_path, fourcc, VIDEO_FPS, (video.w, video.h)) if vc.isOpened(): status, frame = vc.read() else: status=False print("The video was not opened successfully!") vc.release() video.close() videoWriter.release() return False if status: for index in trange(total_frame, desc='Frame extraction progress'): # Read video frames and write output video status, frame = vc.read() if index % VIDEO_FPS == 0: skip_frames = tool.get_unique_random_numbers(index, VIDEO_FPS) if index in skip_frames: continue videoWriter.write(frame) videoWriter.release() vc.release() video.close()
Call the frame extraction function above:
video_extract_frame('./test.mp4', 'result.mp4')
If there are multiple videos that need to extract frames, you only need to call them in a loop:
for index, video_file in enumerate(['1.mp4', '2.mp4', '3.mp4']): //Get the video file name in the link, such as 1,2,3 video_name = tool.get_file_name(video_file) //Assemble into a new directory and new name (according to your needs) out_path = "{}{}.mp4".format(frame_path, video_name) videoTool.video_extract_frame(video_file, out_path) print("\ Item {}, video frame extraction completed: {}".format(index + 1, out_path))
3. Add srt subtitles;
Complete sample code:
# subtitle snippet def generate_textclip(text, width, params, start, duration) -> TextClip: return TextClip( text, font=params.get('font'), align=params.get('align'), fontsize=params.get('fontsize'), color=params.get('color', '#ffbd00'), size=(width, params.get('height')), stroke_color=params.get('stroke_color'), stroke_width=params.get('stroke_width') ).set_position((params['location']['x'], params['location']['y'])).set_duration(duration).set_start(start) # Add srt subtitles def add_srt(video_clip, params): if not (isfile(params["srt_path"]) and params["srt_path"].endswith('.srt')): print('Subtitles only support srt format!') return [] else: # Get the width and height of the video v_width, v_height = video_clip.w, video_clip.h # All subtitle clips txts = [] content = tool.read_srt(params["srt_path"]) sequences = tool.get_sequences(content) max_count = len(sequences) max_duration = video_clip.duration srt_text = params["srt_text"] for index, line in enumerate(sequences): print("Subtitle generation progress:{}/{}".format(index, max_count)) if len(line) < 3: continue start = line[1].split(' --> ')[0] end = line[1].split(' --> ')[1] start = tool.str_float_time(start) end = tool.str_float_time(end) start, end = map(float, (start, end)) if start >= max_duration: break if end >= max_duration: end = max_duration duration=end-start txt_srt = generate_textclip(line[2], (v_width - 20), srt_text, start, duration) txts.append(txt_srt) print("\ Subtitle conversion completed...") return txts
tool.read_srt code:
def read_srt(self, path): content = "" with open(path, 'r', encoding='UTF-8') as f: content = f.read() return content
tool.get_sequences code:
# Subtitle splitting def get_sequences(self, content): sequences = content.split('\ \ ') sequences = [sequence.split('\ ') for sequence in sequences] #Remove null values from each sentence sequences = [list(filter(None, sequence)) for sequence in sequences] #Remove overall null values return list(filter(None, sequences))
tool.str_float_time code:
# Format string numbers into time def str_float_time(self, str): str_list = str.split(':') hour = int(str_list[0]) minute = int(str_list[1]) second = int(str_list[2].split(',')[0]) minsecond = int(str_list[2].split(',')[1]) allTime = hour * 60 * 60 + minute * 60 + second + minsecond / 1000 return allTime
4. Add background music, srt audio, and export
# frame_video_paths: is the video clip after frame extraction def merge_videos_with_bgm(params, frame_video_paths, out_path): # Use VideoFileClip to load all input video files video_clips = [VideoFileClip(file) for file in frame_video_paths] final_clip = concatenate_videoclips(video_clips) bgm_music = audioTool.get_audio({<!-- --> "volume": params.get("bgm_volume", 0.1), #Keep the background audio down "duration": final_clip.duration, "audio_path": params['bgm_path'] }) # Load main music (reading audio) main_music = audioTool.get_audio({<!-- --> "volume": params.get("audio_volume", 1.0),# Read the audio louder "duration": final_clip.duration, "audio_path": params['audio_path'] }) # Mix music into final video slice final_clip = final_clip.set_audio(CompositeAudioClip([main_music, bgm_music])) video_srt = videoTextTool.add_srt(final_clip, params) final_clip.extend(video_srt) # composite video video = CompositeVideoClip(final_clip) output_path = path.join(out_path, "result.mp4") # Output final video video.write_videofile(output_path)
For more exciting crawler cases and tool source codes, search the public account “A snail running hard“
The complete source code of the actual combat has been uploaded to the WeChat public account, and it will be more exciting to share in the future!