svjack's picture
Update app.py
602bdcc verified
raw
history blame
6.47 kB
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")
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/0000.mp4",
"examples/0001.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)