File size: 17,531 Bytes
d85aab3
d4c1a45
 
 
 
dc323de
ba492f5
2ce2eb3
 
758e10b
2ce2eb3
758e10b
2ce2eb3
 
 
 
 
 
 
 
 
 
374a53a
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374a53a
2ce2eb3
 
 
 
 
 
d4c1a45
 
2ce2eb3
 
 
 
 
 
 
 
 
 
d4c1a45
2ce2eb3
d4c1a45
 
 
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4c1a45
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758e10b
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41cc9f0
d4c1a45
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d4c1a45
 
41cc9f0
 
ba492f5
2ce2eb3
 
 
 
 
 
374a53a
2ce2eb3
 
 
 
41cc9f0
d4c1a45
2ce2eb3
 
 
 
ba492f5
374a53a
ba492f5
 
2ce2eb3
ba492f5
 
 
 
2ce2eb3
ba492f5
2ce2eb3
ba492f5
2ce2eb3
ba492f5
374a53a
2ce2eb3
 
 
 
 
 
 
 
ba492f5
 
 
 
 
2ce2eb3
ba492f5
 
 
2ce2eb3
 
 
 
 
ba492f5
2ce2eb3
 
ba492f5
 
2ce2eb3
ba492f5
 
 
 
 
 
 
 
 
 
2ce2eb3
41cc9f0
ba492f5
758e10b
2ce2eb3
 
41cc9f0
ba492f5
 
2ce2eb3
 
 
 
 
 
 
 
ba492f5
 
41cc9f0
758e10b
2ce2eb3
 
758e10b
2ce2eb3
 
 
ba492f5
2ce2eb3
374a53a
2ce2eb3
 
 
d4c1a45
2ce2eb3
 
 
 
 
 
d4c1a45
2ce2eb3
 
 
 
 
d4c1a45
2ce2eb3
 
ba492f5
 
2ce2eb3
d4c1a45
2ce2eb3
ba492f5
 
 
 
 
 
2ce2eb3
 
 
 
 
 
ba492f5
2ce2eb3
 
 
 
 
ba492f5
2ce2eb3
374a53a
2ce2eb3
 
 
 
 
 
374a53a
2ce2eb3
 
 
 
758e10b
ba492f5
 
 
758e10b
 
2ce2eb3
 
d4c1a45
758e10b
 
2ce2eb3
758e10b
 
 
 
2ce2eb3
 
 
758e10b
 
 
2ce2eb3
 
 
 
 
 
 
 
758e10b
 
 
2ce2eb3
ba492f5
758e10b
ba492f5
758e10b
 
 
 
 
 
2ce2eb3
 
 
758e10b
 
 
2ce2eb3
758e10b
2ce2eb3
 
758e10b
 
374a53a
 
 
2ce2eb3
 
374a53a
 
758e10b
2ce2eb3
758e10b
 
 
 
 
 
 
374a53a
ba492f5
 
758e10b
 
 
ba492f5
 
2ce2eb3
ba492f5
758e10b
 
ba492f5
 
2ce2eb3
374a53a
758e10b
 
 
 
 
2ce2eb3
374a53a
ba492f5
758e10b
 
 
 
2ce2eb3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
758e10b
 
d4c1a45
dc323de
d4c1a45
7762994
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
import os
import gradio as gr
import tempfile
import random
import subprocess
import shutil
import zipfile
import threading
import concurrent.futures
from datetime import datetime
import time

class FastVideoProcessor:
    def __init__(self, max_processing_time=30):
        self.max_processing_time = max_processing_time
        self.start_time = None
        
    def check_time_limit(self):
        """检查是否超过时间限制"""
        if self.start_time and time.time() - self.start_time > self.max_processing_time:
            return True
        return False

    def ffmpeg_cut_video_fast(self, input_path, start_time, duration, output_path):
        """高速剪切视频片段"""
        command = [
            'ffmpeg',
            '-ss', str(start_time),
            '-i', input_path,
            '-t', str(duration),
            '-c:v', 'libx264',     # H264编码器
            '-preset', 'ultrafast',  # 最快编码预设
            '-crf', '20',          # 高质量(18-24范围)
            '-c:a', 'aac',
            '-b:a', '128k',
            '-threads', '0',       # 使用所有CPU核心
            '-y',
            output_path
        ]
        process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return process.returncode == 0

    def ffmpeg_resize_video_fast(self, input_path, output_path, target_ratio):
        """高速调整视频比例"""
        if target_ratio == '9:16':
            scale_filter = "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2"
        else:
            scale_filter = "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2"

        command = [
            'ffmpeg',
            '-i', input_path,
            '-vf', scale_filter,
            '-c:v', 'libx264',
            '-preset', 'ultrafast',
            '-crf', '20',
            '-c:a', 'copy',        # 音频直接复制,不重编码
            '-threads', '0',
            '-y',
            output_path
        ]
        
        process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return process.returncode == 0

    def concat_videos_fast(self, file_list, output_path):
        """高速合并视频"""
        list_file = tempfile.NamedTemporaryFile(delete=False, mode='w', suffix='.txt')
        try:
            for f in file_list:
                list_file.write("file '{}'\n".format(f.replace("'", r"'\''")))
            list_file.close()

            command = [
                'ffmpeg', 
                '-f', 'concat', 
                '-safe', '0', 
                '-i', list_file.name,
                '-c', 'copy',          # 直接复制,无重编码
                '-threads', '0',
                '-y', 
                output_path
            ]
            process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            return process.returncode == 0
        finally:
            os.unlink(list_file.name)

    def extract_clips_parallel(self, video_files, clip_duration):
        """并行提取视频片段"""
        self.start_time = time.time()
        clips = []
        temp_dir = tempfile.mkdtemp()
        
        # 计算合理的片段数量,避免处理过多
        max_clips_per_video = max(3, int(20 / len(video_files)))  # 动态调整
        
        def process_single_video(args):
            idx, video_file = args
            video_clips = []
            
            try:
                video_path = video_file.name
                
                # 快速获取视频时长
                cmd_duration = [
                    'ffprobe', '-v', 'quiet', 
                    '-show_entries', 'format=duration',
                    '-of', 'default=noprint_wrappers=1:nokey=1',
                    video_path
                ]
                result = subprocess.run(cmd_duration, capture_output=True, text=True, timeout=5)
                total_duration = float(result.stdout.strip())
                
                # 智能选择起始点,避免从头开始
                step = max(clip_duration, total_duration / max_clips_per_video)
                
                count = 0
                start = 0.0
                
                while start < total_duration and count < max_clips_per_video:
                    if self.check_time_limit():
                        break
                        
                    duration = min(clip_duration, total_duration - start)
                    clip_path = os.path.join(temp_dir, f"clip_{idx}_{count}.mp4")
                    
                    success = self.ffmpeg_cut_video_fast(video_path, start, duration, clip_path)
                    if success:
                        video_clips.append(clip_path)
                    
                    start += step  # 跳跃式选择片段,提高多样性
                    count += 1
                    
                return video_clips
                
            except Exception as e:
                print(f"处理视频 {idx} 出错: {e}")
                return []
        
        # 并行处理所有视频
        with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
            video_args = [(idx, vf) for idx, vf in enumerate(video_files)]
            results = executor.map(process_single_video, video_args)
            
            for video_clips in results:
                clips.extend(video_clips)
        
        return clips, temp_dir

    def generate_mixed_videos_fast(self, clips, num_output_videos, target_ratio):
        """高速生成混剪视频"""
        temp_dir = tempfile.mkdtemp()
        random.shuffle(clips)
        
        # 智能分配片段
        clips_per_video = max(2, len(clips) // num_output_videos)
        output_files = []
        
        def create_single_mixed_video(args):
            i, selected_clips = args
            
            try:
                if self.check_time_limit():
                    return None
                
                # 先快速合并
                temp_video_path = os.path.join(temp_dir, f"temp_mixed_{i+1}.mp4")
                success = self.concat_videos_fast(selected_clips, temp_video_path)
                
                if not success:
                    return None
                
                # 再调整比例
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                output_path = os.path.join(temp_dir, f"混剪视频_{target_ratio.replace(':', 'x')}_{i+1}_{timestamp}.mp4")
                
                success = self.ffmpeg_resize_video_fast(temp_video_path, output_path, target_ratio)
                
                if success:
                    return output_path
                return None
                
            except Exception as e:
                print(f"生成混剪视频 {i+1} 出错: {e}")
                return None
        
        # 准备任务
        tasks = []
        for i in range(num_output_videos):
            start_idx = i * clips_per_video
            end_idx = len(clips) if i == num_output_videos - 1 else (start_idx + clips_per_video)
            selected_clips = clips[start_idx:end_idx]
            
            if selected_clips:
                tasks.append((i, selected_clips))
        
        # 并行生成
        with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
            results = executor.map(create_single_mixed_video, tasks)
            
            for result in results:
                if result:
                    output_files.append(result)
        
        return output_files, temp_dir

processor = FastVideoProcessor()

def create_video_package_fast(output_files, original_file_names, target_ratio, processing_time):
    """快速打包视频文件"""
    package_dir = tempfile.mkdtemp()
    zip_path = os.path.join(package_dir, f"混剪视频包_{target_ratio.replace(':', 'x')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.zip")
    
    try:
        with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED, compresslevel=1) as zipf:  # 最低压缩级别
            for video_file in output_files:
                arcname = os.path.basename(video_file)
                zipf.write(video_file, arcname)
            
            readme_content = f"""# 高速混剪视频包

## ⚡ 处理信息
- 生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- 处理耗时: {processing_time:.1f} 秒 ⚡
- 视频数量: {len(output_files)}
- 视频比例: {target_ratio}
- 优化级别: 高速模式 (30秒内完成)

## 🚀 高速优化技术
- 并行处理: 多线程同时处理
- 快速编码: ultrafast 预设
- 智能跳跃: 避免连续片段
- 零拷贝合并: 减少重编码
- 动态调整: 根据文件数量优化

## 📁 文件列表
"""
            
            for i, video_file in enumerate(output_files, 1):
                file_size = os.path.getsize(video_file) / (1024 * 1024)
                readme_content += f"- 混剪视频_{i}.mp4 ({file_size:.1f}MB)\n"
            
            readme_content += f"""
## 🎬 质量保证
- CRF 20: 高质量编码
- 原始音频: 保持音质
- 智能填充: 完美适配比例
- 多核加速: 充分利用CPU

## 📱 发布就绪
视频已经过专业优化,可直接发布到各大平台!

---
⚡ 高速混剪工具 - 30秒完成专业混剪
"""
            
            zipf.writestr("README.txt", readme_content.encode('utf-8'))
        
        return zip_path
    
    except Exception as e:
        shutil.rmtree(package_dir, ignore_errors=True)
        raise e

def process_and_package_ultra_fast(video_files, clip_duration, num_output_videos, target_ratio):
    if not video_files or len(video_files) == 0:
        return "❌ 请上传至少一个视频文件", None, ""
    
    start_time = time.time()
    
    try:
        original_names = [os.path.basename(f.name) for f in video_files]
        
        # 1. 高速提取片段
        clips, clips_temp_dir = processor.extract_clips_parallel(video_files, clip_duration)
        
        if not clips:
            return "❌ 未能提取到有效片段", None, ""
        
        # 2. 高速生成混剪视频
        output_files, output_temp_dir = processor.generate_mixed_videos_fast(clips, num_output_videos, target_ratio)
        
        # 清理切片临时目录
        shutil.rmtree(clips_temp_dir, ignore_errors=True)
        
        if not output_files:
            return "❌ 未能生成混剪视频", None, ""
        
        # 3. 快速打包
        processing_time = time.time() - start_time
        zip_file_path = create_video_package_fast(output_files, original_names, target_ratio, processing_time)
        
        total_size = os.path.getsize(zip_file_path) / (1024 * 1024)
        
        platform_info = "📱 短视频平台" if target_ratio == '9:16' else "🖥️ 长视频平台"
        
        status_msg = f"""⚡ 高速处理完成!

📊 **处理统计:**
• ⚡ 处理时间: {processing_time:.1f}
• 🎬 混剪视频: {len(output_files)}
• 📐 视频比例: {target_ratio}
• 🎯 适合平台: {platform_info}
• 📦 文件大小: {total_size:.1f}MB

🚀 **高速优化:**
• 多线程并行处理
• 智能片段选择
• 快速编码预设
• 零拷贝合并技术

💾 **立即下载:**
点击下方按钮保存到本地
"""
        
        details = f"""⚡ **高速处理详情:**

🎬 **视频信息:**
"""
        for i, video_file in enumerate(output_files, 1):
            file_size = os.path.getsize(video_file) / (1024 * 1024)
            details += f"• 混剪视频_{i}: {file_size:.1f}MB\n"
        
        details += f"""
⚡ **优化技术:**
• 处理时间: {processing_time:.1f}秒 (目标: 30秒内)
• 并行处理: {'✅ 已启用' if len(video_files) > 1 else '单文件处理'}
• 快速编码: ultrafast + CRF 20
• 智能跳跃: 避免连续片段
• 多核心: CPU全核心利用

🎯 **质量保证:**
• 视频编码: H.264 高质量
• 音频处理: AAC 128k
• 比例适配: 智能填充黑边
• 兼容性: 支持所有主流播放器

📱 **发布优势:**
"""
        
        if target_ratio == '9:16':
            details += """• 完美适配移动端全屏
• 抖音算法友好格式
• 高清1080x1920分辨率
• 即刻发布无需二次处理"""
        else:
            details += """• 传统影视观看体验  
• YouTube推荐格式
• 高清1920x1080分辨率
• 适合详细内容展示"""
        
        shutil.rmtree(output_temp_dir, ignore_errors=True)
        
        return status_msg, zip_file_path, details
        
    except Exception as e:
        processing_time = time.time() - start_time
        return f"❌ 处理失败 (耗时{processing_time:.1f}秒): {str(e)}", None, ""

def main():
    with gr.Blocks(
        title="⚡高速FFmpeg剪辑工具", 
        theme=gr.themes.Soft()
    ) as demo:
        
        gr.HTML("""
        <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #FF6B6B 0%, #4ECDC4 100%); border-radius: 15px; color: white; margin-bottom: 20px;">
            <h1>⚡ 高速 FFmpeg 自动剪辑工具</h1>
            <p style="margin: 10px 0 0 0; font-size: 18px;">🚀 30秒内完成 → 智能并行 → 保证品质 → 一键下载</p>
        </div>
        """)
        
        gr.Markdown("""
        ### ⚡ 高速优化特性
        - 🚀 **30秒完成**: 智能时间控制,确保快速处理
        - 🔥 **并行处理**: 多线程同时处理,充分利用CPU
        - 💎 **保证品质**: CRF 20高质量编码,ultrafast预设
        - 🧠 **智能优化**: 动态调整处理量,避免超时
        """)
        
        with gr.Row():
            with gr.Column(scale=2):
                video_input = gr.File(
                    label="📤 上传视频文件 (支持批量)", 
                    file_types=[".mp4", ".mov", ".avi", ".mkv"], 
                    file_count="multiple",
                    height=120
                )
                
                with gr.Row():
                    clip_duration = gr.Number(
                        value=3, 
                        label="切片时长(秒)", 
                        minimum=2, 
                        maximum=8,
                        info="建议2-5秒,太长影响速度"
                    )
                    num_output = gr.Number(
                        value=3, 
                        label="生成数量", 
                        minimum=1, 
                        maximum=5,
                        info="建议1-3个,太多影响速度"
                    )
                
                ratio_selection = gr.Radio(
                    choices=["9:16", "16:9"], 
                    value="9:16",
                    label="📐 视频比例",
                    info="9:16抖音快手 | 16:9 YouTube B站"
                )
                
                process_btn = gr.Button(
                    "⚡ 高速处理 (30秒完成)", 
                    variant="primary", 
                    size="lg"
                )
            
            with gr.Column(scale=1):
                status_output = gr.Textbox(
                    label="📊 处理状态", 
                    lines=12, 
                    interactive=False,
                    show_copy_button=True
                )
        
        with gr.Row():
            with gr.Column(scale=1):
                download_file = gr.File(
                    label="⚡ 高速下载视频包",
                    interactive=False
                )
            
            with gr.Column(scale=1):
                details_output = gr.Textbox(
                    label="📝 处理详情", 
                    lines=18, 
                    interactive=False,
                    show_copy_button=True
                )
        
        process_btn.click(
            fn=process_and_package_ultra_fast,
            inputs=[video_input, clip_duration, num_output, ratio_selection],
            outputs=[status_output, download_file, details_output]
        )
        
        gr.Markdown("""
        ---
        ### ⚡ 高速处理说明
        
        **🚀 速度优化技术:**
        - **并行切片**: 多个视频同时处理,4线程并发
        - **ultrafast预设**: FFmpeg最快编码,保证30秒完成  
        - **智能跳跃**: 非连续片段选择,提高多样性
        - **零拷贝合并**: 减少重编码,加速处理
        - **动态调整**: 根据文件量自动优化处理数量
        
        **💎 品质保证:**
        - **CRF 20编码**: 高质量视频输出
        - **原音保持**: 音频直接复制,无损处理
        - **智能填充**: 完美适配目标比例
        - **兼容性优化**: H.264编码,支持所有平台
        
        **📊 性能建议:**
        - **视频数量**: 1-3个文件最佳速度
        - **切片时长**: 2-5秒推荐
        - **输出数量**: 1-3个视频最快
        - **文件大小**: 单文件<500MB最优
        
        **⚠️ 注意事项:**
        - 系统将在30秒内强制完成处理
        - 超时会返回已处理的部分结果  
        - 建议在稳定网络环境下使用
        - CPU性能越好处理越快
        """)
    
    demo.launch()

if __name__ == "__main__":
    main()