看完本文章,你将能学会一下内容:
效果:
首先安装视频处理库opencv-python
和moviepy
,安装方式pip install xxx。
py文件顶部中导入(下文中使用到的函数将不在赘述导入过程):
from moviepy.editor import VideoFileClip, CompositeAudioClip, CompositeVideoClip, concatenate_videoclips
from cv2 import VideoCapture, VideoWriter, VideoWriter_fourcc, CAP_PROP_FRAME_COUNT
cv2.VideoCapture:
作用:用于从视频文件或摄像头捕获视频帧。
解释:这个函数允许你创建一个视频捕获对象,以便从指定的视频源中读取视频帧。你可以传递视频文件的路径或摄像头的索引作为参数,然后使用它来逐帧读取视频。
cv2.VideoWriter:
作用:用于将视频帧写入到一个新的视频文件中。
解释:这个函数允许你创建一个视频写入对象,以便将视频帧写入到一个新的视频文件中。你可以指定输出文件的名称、视频编解码器、帧速率、分辨率等参数。这在视频编辑和保存处理后的视频时非常有用。
cv2.VideoWriter_fourcc:
作用:用于指定视频编解码器的四字符码(FourCC)。
解释:FourCC 是一个4字节的代码,用于标识视频编解码器。不同的编解码器有不同的FourCC码。通过使用这个函数,你可以选择要在输出视频中使用的编解码器。
CAP_PROP_FRAME_COUNT:
作用:用于获取视频文件中的总帧数。
解释:CAP_PROP_FRAME_COUNT 是 cv2.VideoCapture 对象的一个属性,用于获取视频文件中的总帧数。这对于确定视频的时长以及循环播放视频等操作非常有用。
完整代码块:
# 单个视频抽帧
def video_extract_frame(video_path, out_path):
# 打开视频文件
vc = VideoCapture(video_path)
# 视频的总帧数
total_frame = int(vc.get(CAP_PROP_FRAME_COUNT))
video = VideoFileClip(video_path, audio=False)
# # 创建一个视频写入对象。设置视频的宽度和高度、帧率、输出路径
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("视频没有打开成功!")
vc.release()
video.close()
videoWriter.release()
return False
if status:
for index in trange(total_frame, desc='抽帧进度'):
# 读取视频帧并写入输出视频
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()
调用上面的抽帧函数:
video_extract_frame('./test.mp4', 'result.mp4')
如果有多个视频需要抽帧,只需要循环调用即可:
for index, video_file in enumerate(['1.mp4', '2.mp4', '3.mp4']):
//取出链接中的视频文件名称,例如1,2,3
video_name = tool.get_file_name(video_file)
//组装成新目录、新名字(根据自己需要)
out_path = "{}{}.mp4".format(frame_path, video_name)
videoTool.video_extract_frame(video_file, out_path)
print("\n第{}条, 视频抽帧已完成: {}".format(index + 1, out_path))
完整示例代码:
# 字幕片段
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)
# 添加srt字幕
def add_srt(video_clip, params):
if not (isfile(params["srt_path"]) and params["srt_path"].endswith('.srt')):
print('字幕仅支持srt格式!')
return []
else:
# 获取视频的宽度和高度
v_width, v_height = video_clip.w, video_clip.h
# 所有字幕剪辑
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("字幕生成进度:{}/{}".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("\n字幕转换已完成...")
return txts
tool.read_srt 代码:
def read_srt(self, path):
content = ""
with open(path, 'r', encoding='UTF-8') as f:
content = f.read()
return content
tool.get_sequences 代码:
# 字幕拆分
def get_sequences(self, content):
sequences = content.split('\n\n')
sequences = [sequence.split('\n') for sequence in sequences]
# 去除每一句空值
sequences = [list(filter(None, sequence)) for sequence in sequences]
# 去除整体空值
return list(filter(None, sequences))
tool.str_float_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
# frame_video_paths:是抽帧后的视频片段
def merge_videos_with_bgm(params, frame_video_paths, out_path):
# 用VideoFileClip加载所有输入视频文件
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), #背景音频小声点
"duration": final_clip.duration,
"audio_path": params['bgm_path']
})
# 加载主音乐(朗读音频)
main_music = audioTool.get_audio({
"volume": params.get("audio_volume", 1.0),# 朗读音频大声点
"duration": final_clip.duration,
"audio_path": params['audio_path']
})
# 将音乐混合到最终视频切片
final_clip = final_clip.set_audio(CompositeAudioClip([main_music, bgm_music]))
video_srt = videoTextTool.add_srt(final_clip, params)
final_clip.extend(video_srt)
# 复合视频
video = CompositeVideoClip(final_clip)
output_path = path.join(out_path, "result.mp4")
# 输出最终视频
video.write_videofile(output_path)
更多爬虫精彩案例、工具源码,搜索公众号“一个努力奔跑的snail”
实战完整源码,已上传微信公众号,后期分享更精彩!