上一节中,实现了先生成一个固定背景的与音频长度一致的视频,然后插入字幕。再合并成一个视频的方法。
但是:这样有点单了,所以:
1.根据字幕的长度先生成视频片断
2.在片段上加上字幕。
3.合并所有片断,成为一个新的视频。
4.在新的视频上添加上音频。再次合成一个新的视频,即最后的视频。
可用代码1
from moviepy import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip, ImageClip
import cv2
import numpy as np
import random
import os
import warnings# 忽略特定的 UserWarning
# warnings.filterwarnings("ignore", category=UserWarning, message="In file .*\.mp4, .* bytes wanted but 0 bytes read at frame index .* \(out of a total .* frames\), at time .* sec. Using the last valid frame instead.")def parse_time(time_str):""" 解析 SRT 时间格式 """hours, minutes, seconds = time_str.split(':')seconds, milliseconds = seconds.split(',')return float(hours) * 3600 + float(minutes) * 60 + float(seconds) + float(milliseconds) / 1000def create_video(audio_path, subtitle_path, video_path, subtitle_position='center', use_temp_files=False):# 创建一个灰色背景的视频width, height = 1920, 1080 # 横屏视频分辨率fps = 24 # 视频帧率duration = AudioFileClip(audio_path).duration # 视频时长与音频相同# 加载音频audio_clip = AudioFileClip(audio_path)# 读取字幕文件with open(subtitle_path, 'r', encoding='utf-8') as file:subtitles = file.readlines()# 处理字幕video_clips = []temp_files = [] # 用于存储临时文件路径for i in range(0, len(subtitles), 3): # 4代表字幕文件中每一块所占行数index = subtitles[i].strip()time_range = subtitles[i + 1].strip().split(' --> ')start_time = time_range[0]end_time = time_range[1]text = subtitles[i + 2].strip()# 计算片段的持续时间start_seconds = parse_time(start_time)end_seconds = parse_time(end_time)clip_duration = end_seconds - start_seconds# 生成随机背景颜色random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))frame = np.zeros((height, width, 3), dtype=np.uint8)frame[:, :] = random_color# 创建视频片段fourcc = cv2.VideoWriter_fourcc(*'mp4v')if use_temp_files:output_path = f"temp_clip_{i}.mp4"out = cv2.VideoWriter(output_path, fourcc, fps, (width, height), isColor=True)for _ in range(int(fps * clip_duration)):out.write(frame)out.release()temp_files.append(output_path)# 检查临时视频文件是否存在且大小大于0if not os.path.exists(output_path) or os.path.getsize(output_path) == 0:raise Exception(f"Temporary video file {output_path} is missing or empty.")# 加载视频片段video_clip = VideoFileClip(output_path).with_duration(clip_duration)else:# 直接在内存中创建 VideoClipvideo_clip = ImageClip(frame).with_duration(clip_duration)# 折行处理font_size = 50font = cv2.FONT_HERSHEY_SIMPLEXmax_width = width * 0.8 # 最大宽度为视频宽度的80%words = text.split()lines = []line = ""for word in words:test_line = line + " " + word(test_width, _), _ = cv2.getTextSize(test_line, font, 1, font_size)if test_width <= max_width:line = test_lineelse:lines.append(line)line = wordlines.append(line)# 创建TextClipfinal_text = "\n".join(lines)subtitle_clip = TextClip(text=final_text, font_size=font_size, color='white',font='/usr/share/fonts/opentype/noto/NotoSerifCJK-Bold.ttc')subtitle_clip = subtitle_clip.with_start(0).with_end(clip_duration).with_position(('center', subtitle_position))# 创建灰色背景框text_width, text_height = subtitle_clip.sizepadding = 10 # 字幕框的内边距box_width = text_width + 2 * paddingbox_height = text_height + 2 * paddingbox_frame = np.zeros((box_height, box_width, 3), dtype=np.uint8) + 128 # 灰色背景box_clip = ImageClip(box_frame).with_start(0).with_end(clip_duration)# 设置背景框的位置if subtitle_position == 'center':box_position = ('center', 'center')elif subtitle_position == 'bottom':box_position = ('center', 'bottom')else:box_position = ('center', 'top')box_clip = box_clip.with_position(box_position, relative=True).with_duration(clip_duration)# 合成片段final_clip = CompositeVideoClip([video_clip, box_clip, subtitle_clip]).with_start(start_seconds)video_clips.append(final_clip)# 合成最终视频final_video = CompositeVideoClip(video_clips)final_video = final_video.with_audio(audio_clip)final_video.write_videofile(video_path, codec='libx264', fps=fps)# 清理临时文件if use_temp_files:for temp_file in temp_files:os.remove(temp_file)# 示例调用
audio_path = "wwww.wav"
subtitle_path = "wwww.srt"
video_path = "wwww.mp4"
subtitle_position = 'bottom' # 可选值: 'center', 'bottom'
use_temp_files = False # 设置为 True 以使用临时文件# 创建最终视频
create_video(audio_path, subtitle_path, video_path, subtitle_position, use_temp_files)
可用参考代码2:
from moviepy import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip, ImageClip
import cv2
import numpy as np
import random
import os
import warnings# 忽略特定的 UserWarning
# warnings.filterwarnings("ignore", category=UserWarning, message="In file .*\.mp4, .* bytes wanted but 0 bytes read at frame index .* \(out of a total .* frames\), at time .* sec. Using the last valid frame instead.")def parse_time(time_str):""" 解析 SRT 时间格式 """hours, minutes, seconds = time_str.split(':')seconds, milliseconds = seconds.split(',')return float(hours) * 3600 + float(minutes) * 60 + float(seconds) + float(milliseconds) / 1000def create_video(audio_path, subtitle_path, video_path, subtitle_position='center', use_temp_files=False):# 创建一个灰色背景的视频width, height = 1920, 1080 # 横屏视频分辨率fps = 24 # 视频帧率duration = AudioFileClip(audio_path).duration # 视频时长与音频相同# 加载音频audio_clip = AudioFileClip(audio_path)# 读取字幕文件with open(subtitle_path, 'r', encoding='utf-8') as file:subtitles = file.readlines()# 处理字幕video_clips = []temp_files = [] # 用于存储临时文件路径for i in range(0, len(subtitles), 3): # 4代表字幕文件中每一块所占行数index = subtitles[i].strip()time_range = subtitles[i + 1].strip().split(' --> ')start_time = time_range[0]end_time = time_range[1]text = subtitles[i + 2].strip()# 计算片段的持续时间start_seconds = parse_time(start_time)end_seconds = parse_time(end_time)clip_duration = end_seconds - start_seconds# 生成随机背景颜色random_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))frame = np.zeros((height, width, 3), dtype=np.uint8)frame[:, :] = random_color# 创建视频片段fourcc = cv2.VideoWriter_fourcc(*'mp4v')if use_temp_files:output_path = f"temp_clip_{i}.mp4"out = cv2.VideoWriter(output_path, fourcc, fps, (width, height), isColor=True)for _ in range(int(fps * clip_duration)):out.write(frame)out.release()temp_files.append(output_path)# 检查临时视频文件是否存在且大小大于0if not os.path.exists(output_path) or os.path.getsize(output_path) == 0:raise Exception(f"Temporary video file {output_path} is missing or empty.")# 加载视频片段video_clip = VideoFileClip(output_path).with_duration(clip_duration)else:# 直接在内存中创建 VideoClipvideo_clip = ImageClip(frame).with_duration(clip_duration)# 折行处理font_size = 50font = cv2.FONT_HERSHEY_SIMPLEXmax_width = width * 0.8 # 最大宽度为视频宽度的80%words = text.split()lines = []line = ""for word in words:test_line = line + " " + word(test_width, _), _ = cv2.getTextSize(test_line, font, 1, font_size)if test_width <= max_width:line = test_lineelse:lines.append(line)line = wordlines.append(line)# 创建TextClipfinal_text = "\n".join(lines)subtitle_clip = TextClip(text=final_text, font_size=font_size, color='white',font='/usr/share/fonts/opentype/noto/NotoSerifCJK-Bold.ttc')subtitle_clip = subtitle_clip.with_start(0).with_end(clip_duration).with_position(('center', subtitle_position))# 创建灰色背景框text_width, text_height = subtitle_clip.sizepadding = 10 # 字幕框的内边距box_width = text_width + 2 * paddingbox_height = text_height + 2 * paddingbox_frame = np.zeros((box_height, box_width, 3), dtype=np.uint8) + 128 # 灰色背景box_clip = ImageClip(box_frame).with_start(0).with_end(clip_duration)# 设置背景框的位置if subtitle_position == 'center':box_position = ('center', 'center')elif subtitle_position == 'bottom':box_position = ('center', 'bottom')else:box_position = ('center', 'top')box_clip = box_clip.with_position(box_position, relative=True).with_duration(clip_duration)# 合成片段final_clip = CompositeVideoClip([video_clip, box_clip, subtitle_clip]).with_start(start_seconds)video_clips.append(final_clip)# 合成最终视频final_video = CompositeVideoClip(video_clips)final_video = final_video.with_audio(audio_clip)final_video.write_videofile(video_path, codec='libx264', fps=fps)# 清理临时文件if use_temp_files:for temp_file in temp_files:os.remove(temp_file)# 示例调用
audio_path = "wwww.wav"
subtitle_path = "wwww.srt"
video_path = "wwww.mp4"
subtitle_position = 'bottom' # 可选值: 'center', 'bottom'
use_temp_files = False # 设置为 True 以使用临时文件# 创建最终视频
create_video(audio_path, subtitle_path, video_path, subtitle_position, use_temp_files)
以上代码参考,下一步。我计划。使用视频及字幕建立数据库,然后使用字幕进行匹配,替换目前的随机背景色的视频片断。那位朋友有好的参考意见的。交流一下。