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)