Spaces:
Running
Running
File size: 6,507 Bytes
d99713a 4b32b23 d99713a fe5a563 d99713a 602bdcc d99713a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
import os
import glob
import gradio as gr
from moviepy.editor import VideoFileClip, concatenate_videoclips
import subprocess
import tempfile
import shutil
def get_latest_transition_video():
"""获取最新生成的过渡视频文件"""
transition_files = glob.glob('*.mp4')
if not transition_files:
raise FileNotFoundError("未找到过渡视频文件")
latest_file = max(transition_files, key=os.path.getctime)
return latest_file
def concatenate_videos(video1_path, video2_path, transition_path, output_path, num_frames, fps):
"""拼接三个视频部分"""
clip1 = VideoFileClip(video1_path)
clip2 = VideoFileClip(video2_path)
transition = VideoFileClip(transition_path)
transition_duration = num_frames / fps
duration1 = clip1.duration - transition_duration
part1 = clip1.subclip(0, max(0, duration1))
start_time2 = transition_duration
part2 = clip2.subclip(min(start_time2, clip2.duration))
final_clip = concatenate_videoclips([part1, transition, part2])
final_clip.write_videofile(output_path, codec='libx264', audio_codec='aac')
clip1.close()
clip2.close()
transition.close()
final_clip.close()
def get_video_info(video_path):
"""获取视频信息"""
clip = VideoFileClip(video_path)
fps = clip.fps
duration = clip.duration
total_frames = int(duration * fps)
clip.close()
return fps, duration, total_frames
def process_videos(video1, video2, animation, num_frames):
# 创建临时目录
temp_dir = tempfile.mkdtemp()
try:
# 保存上传的视频到临时目录
video1_path = os.path.join(temp_dir, "video1.mp4")
video2_path = os.path.join(temp_dir, "video2.mp4")
shutil.copyfile(video1, video1_path)
shutil.copyfile(video2, video2_path)
# 获取视频信息
fps1, duration1, frames1 = get_video_info(video1_path)
fps2, duration2, frames2 = get_video_info(video2_path)
# 使用两个视频中较小的FPS
fps = min(fps1, fps2)
# 计算最大可用帧数
max_possible_frames = min(
int(duration1 * fps),
int(duration2 * fps)
)
num_frames = min(num_frames, max_possible_frames)
# 1. 生成过渡部分
transition_cmd = [
"python", "vid_transition.py",
"-i", video1_path, video2_path,
"--animation", animation,
"--num_frames", str(num_frames),
"--max_brightness", "1.5",
"-m", "y"
]
subprocess.run(transition_cmd, check=True)
# 2. 获取过渡视频
transition_path = get_latest_transition_video()
# 3. 拼接视频
#output_path = os.path.join(temp_dir, "output.mp4")
output_path = "output.mp4"
concatenate_videos(video1_path, video2_path, transition_path, output_path, num_frames, fps)
return output_path
except Exception as e:
raise gr.Error(f"处理视频时出错: {str(e)}")
finally:
# 清理临时目录
shutil.rmtree(temp_dir, ignore_errors=True)
def validate_inputs(video1, video2, num_frames):
"""验证输入参数"""
if not video1 or not video2:
raise gr.Error("请上传两个视频文件")
try:
fps1, duration1, frames1 = get_video_info(video1)
fps2, duration2, frames2 = get_video_info(video2)
except:
raise gr.Error("上传的视频文件无效")
fps = min(fps1, fps2)
max_possible_frames = min(frames1, frames2)
if num_frames > max_possible_frames:
raise gr.Error(f"视频太短,最大可用过渡帧数为: {max_possible_frames}")
return fps, max_possible_frames
def process_and_validate(video1, video2, animation, num_frames):
try:
fps, max_frames = validate_inputs(video1, video2, num_frames)
if num_frames > max_frames:
num_frames = max_frames
gr.Info(f"自动调整过渡帧数为: {num_frames}")
output_path = process_videos(video1, video2, animation, num_frames)
return output_path
except Exception as e:
raise gr.Error(str(e))
# 创建Gradio界面
with gr.Blocks(title="视频过渡与拼接工具") as demo:
gr.Markdown("""
# 视频过渡与拼接工具
上传两个视频,选择过渡效果,生成平滑过渡的合并视频。
""")
with gr.Row():
with gr.Column():
video1 = gr.Video(label="第一个视频")
video2 = gr.Video(label="第二个视频")
animation = gr.Dropdown(
label="过渡动画效果",
choices=[
'translation', 'translation_inv',
'rotation', 'rotation_inv',
'zoom_in', 'zoom_out',
'long_translation', 'long_translation_inv'
],
value='translation'
)
num_frames = gr.Slider(
label="过渡帧数",
minimum=10,
maximum=100,
step=5,
value=30,
info="会根据视频长度自动调整"
)
submit_btn = gr.Button("生成过渡视频", variant="primary")
with gr.Column():
output_video = gr.Video(label="合并后的视频")
info_box = gr.Textbox(label="处理信息", visible=False)
submit_btn.click(
fn=process_and_validate,
inputs=[video1, video2, animation, num_frames],
outputs=output_video
)
# 示例部分 - 使用0000.mp4和0001.mp4展示所有动画效果
examples = []
animations = [
'translation', 'translation_inv',
'rotation', 'rotation_inv',
'zoom_in', 'zoom_out',
'long_translation', 'long_translation_inv'
]
for anim in animations:
examples.append([
"examples/abc.mp4",
"examples/bcd.mp4",
anim,
30 # 使用30帧作为示例
])
gr.Examples(
examples=examples,
inputs=[video1, video2, animation, num_frames],
outputs=output_video,
fn=process_and_validate,
cache_examples=False,
label="不同过渡效果"
)
if __name__ == "__main__":
demo.launch(share = True) |