Ryanus commited on
Commit
f17c73e
·
verified ·
1 Parent(s): 7397c75

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -71
app.py CHANGED
@@ -264,15 +264,19 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
264
  threads = get_optimal_threads()
265
  encoder = HARDWARE_ACCEL['encoder']
266
 
267
- base_command = ['ffmpeg', '-threads', str(threads)]
 
 
268
 
269
- # 硬件加速解码
270
- if HARDWARE_ACCEL['nvidia']:
271
- base_command.extend(['-hwaccel', 'cuda'])
272
- elif HARDWARE_ACCEL['amd']:
273
- base_command.extend(['-hwaccel', 'amf'])
274
- elif HARDWARE_ACCEL['intel']:
275
- base_command.extend(['-hwaccel', 'qsv'])
 
 
276
 
277
  base_command.extend(['-i', input_path])
278
 
@@ -281,19 +285,18 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
281
 
282
  # 编码参数
283
  if encoder == 'h264_nvenc':
284
- # NVIDIA GPU编码参数
285
  base_command.extend([
286
  '-c:v', 'h264_nvenc',
287
- '-preset', 'p1', # 最快预设
288
- '-tune', 'ull', # 超低延迟
289
- '-cq', '28', # 质量参数
290
  '-c:a', 'aac',
291
  '-b:a', '128k',
292
  '-movflags', '+faststart',
293
  '-y', output_path
294
  ])
295
  elif encoder == 'h264_amf':
296
- # AMD GPU编码参数
297
  base_command.extend([
298
  '-c:v', 'h264_amf',
299
  '-quality', 'speed',
@@ -306,7 +309,7 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
306
  '-y', output_path
307
  ])
308
  elif encoder == 'h264_qsv':
309
- # Intel Quick Sync编码参数
310
  base_command.extend([
311
  '-c:v', 'h264_qsv',
312
  '-preset', 'veryfast',
@@ -323,7 +326,6 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
323
  '-preset', 'ultrafast', # 最快预设
324
  '-crf', '28', # 质量参数
325
  '-tune', 'fastdecode', # 优化解码速度
326
- '-x264opts', 'no-scenecut', # 禁用场景检测以加快速度
327
  '-c:a', 'aac',
328
  '-b:a', '128k',
329
  '-movflags', '+faststart',
@@ -336,8 +338,7 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
336
  if encoder == 'h264_nvenc':
337
  base_command.extend([
338
  '-c:v', 'h264_nvenc',
339
- '-preset', 'p1',
340
- '-tune', 'ull',
341
  '-cq', '28',
342
  '-c:a', 'copy',
343
  '-movflags', '+faststart',
@@ -349,7 +350,6 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
349
  '-preset', 'ultrafast',
350
  '-crf', '28',
351
  '-tune', 'fastdecode',
352
- '-x264opts', 'no-scenecut',
353
  '-c:a', 'copy',
354
  '-movflags', '+faststart',
355
  '-y', output_path
@@ -359,24 +359,52 @@ def build_ffmpeg_command(input_path, start_time, duration, output_path, operatio
359
 
360
  def ffmpeg_cut_video(input_path, start_time, duration, output_path):
361
  """[优化] 快速的视频切割,使用硬件加速和ultrafast预设"""
362
- command = build_ffmpeg_command(input_path, start_time, duration, output_path, 'cut')
363
- result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
364
- return result.returncode == 0 and os.path.exists(output_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
  def ffmpeg_resize_video(input_path, output_path, target_ratio):
367
  """[优化] 快速的比例调整,使用硬件���速和ultrafast预设"""
368
- if target_ratio == '9:16':
369
- filter_complex = "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black"
370
- else:
371
- filter_complex = "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black"
372
-
373
- command = build_ffmpeg_command(input_path, 0, 0, output_path, 'resize')
374
- # resize操作中插入滤镜
375
- command.insert(-5, '-vf') # 在-y之前插入
376
- command.insert(-4, filter_complex)
377
-
378
- result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
379
- return result.returncode == 0 and os.path.exists(output_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
  def concat_videos(file_list, output_path):
382
  """稳定的视频合并"""
@@ -397,8 +425,19 @@ def concat_videos(file_list, output_path):
397
  # 使用多线程进行合并
398
  threads = get_optimal_threads()
399
  command = ['ffmpeg', '-threads', str(threads), '-f', 'concat', '-safe', '0', '-i', list_file.name, '-c', 'copy', '-y', output_path]
400
- result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
401
- return result.returncode == 0 and os.path.exists(output_path)
 
 
 
 
 
 
 
 
 
 
 
402
  finally:
403
  try:
404
  os.unlink(list_file.name)
@@ -414,6 +453,7 @@ def process_single_video(video_file, clip_duration, temp_dir):
414
  cmd = ['ffprobe', '-v', 'quiet', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', video_path]
415
  result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
416
  total_duration = float(result.stdout.strip())
 
417
  except Exception as e:
418
  print(f"处理视频 {video_path} 时获取时长失败: {e}")
419
  return clips
@@ -425,10 +465,13 @@ def process_single_video(video_file, clip_duration, temp_dir):
425
  # 修改文件名,包含原始文件名和计数,避免不同视频的切片重名
426
  clip_path = os.path.join(temp_dir, f"clip_{os.path.splitext(os.path.basename(video_path))[0]}_{count}.mp4")
427
 
 
 
428
  if ffmpeg_cut_video(video_path, start, duration, clip_path):
429
  clips.append(clip_path)
 
430
  else:
431
- print(f"切割视频 {video_path} 的第 {count} 个片段失败")
432
 
433
  start += clip_duration
434
  count += 1
@@ -451,9 +494,9 @@ def process_videos_with_storage(video_files, clip_duration, num_output_videos, t
451
 
452
  all_clips = []
453
 
454
- # 使用进程池进行并行处理(避免GIL限制)
455
- print(f"🚀 启动并行切片({min(8, os.cpu_count() or 1)} 进程)...")
456
- with concurrent.futures.ProcessPoolExecutor(max_workers=min(8, os.cpu_count() or 1)) as executor:
457
  future_to_video = {
458
  executor.submit(process_single_video, vf, clip_duration, temp_dir): vf
459
  for vf in video_files
@@ -809,35 +852,4 @@ def main():
809
  **⬇️ 一键下载功能:**
810
  - 📦 **一键下载全部**: 打包下载储存空间中所有视频
811
  - 📥 **选择下载**: 勾选特定文件进行批量下载
812
- - 🗂️ **自动清单**: 下载包含详细文件清单
813
- - ⚡ **快速打包**: 自动压缩,节省下载时间
814
-
815
- **🗑️ 文件管理功能:**
816
- - 🗑️ 支持单个文件删除
817
- - 🧹 支持清空全部储存文件
818
- - 📱 灵活的文件管理操作
819
-
820
- **🔥 使用场景:**
821
- - **批量备份**: 一键下载所有混剪作品
822
- - **选择性导出**: 只下载需要的特定视频
823
- - **移动设备**: 下载到手机/平板继续编辑
824
- - **分享协作**: 打包分享给团队成员
825
- - **存档管理**: 定期下载备份到云盘
826
-
827
- **⚡ 性能优化:**
828
- - **硬件加速**: 自动检测并使用GPU加速
829
- - **多线程处理**: 充分利用多核CPU
830
- - **快速预设**: 使用ultrafast预设提升速度
831
- - **并行处理**: 多个视频同时处理
832
-
833
- **⚠️ 注意事项:**
834
- - 下载文件为ZIP格式,需要解压使用
835
- - 一键下载包含储存空间中所有视频文件
836
- - 选择下载可以精确控制需要的文件
837
- - 下载包自动包含详细的文件清单
838
- """)
839
-
840
- demo.launch()
841
-
842
- if __name__ == "__main__":
843
- main()
 
264
  threads = get_optimal_threads()
265
  encoder = HARDWARE_ACCEL['encoder']
266
 
267
+ # 处理中文文件名 - 使用绝对路径并确保路径正确
268
+ input_path = os.path.abspath(input_path)
269
+ output_path = os.path.abspath(output_path)
270
 
271
+ base_command = ['ffmpeg']
272
+
273
+ # 硬件加速解码 - 简化处理,避免兼容性问题
274
+ # if HARDWARE_ACCEL['nvidia']:
275
+ # base_command.extend(['-hwaccel', 'cuda'])
276
+ # elif HARDWARE_ACCEL['amd']:
277
+ # base_command.extend(['-hwaccel', 'amf'])
278
+ # elif HARDWARE_ACCEL['intel']:
279
+ # base_command.extend(['-hwaccel', 'qsv'])
280
 
281
  base_command.extend(['-i', input_path])
282
 
 
285
 
286
  # 编码参数
287
  if encoder == 'h264_nvenc':
288
+ # NVIDIA GPU编码参数 - 简化版本
289
  base_command.extend([
290
  '-c:v', 'h264_nvenc',
291
+ '-preset', 'fast', # 使用fast而不是p1,更兼容
292
+ '-cq', '28', # 质量参数
 
293
  '-c:a', 'aac',
294
  '-b:a', '128k',
295
  '-movflags', '+faststart',
296
  '-y', output_path
297
  ])
298
  elif encoder == 'h264_amf':
299
+ # AMD GPU编码参数 - 简化版本
300
  base_command.extend([
301
  '-c:v', 'h264_amf',
302
  '-quality', 'speed',
 
309
  '-y', output_path
310
  ])
311
  elif encoder == 'h264_qsv':
312
+ # Intel Quick Sync编码参数 - 简化版本
313
  base_command.extend([
314
  '-c:v', 'h264_qsv',
315
  '-preset', 'veryfast',
 
326
  '-preset', 'ultrafast', # 最快预设
327
  '-crf', '28', # 质量参数
328
  '-tune', 'fastdecode', # 优化解码速度
 
329
  '-c:a', 'aac',
330
  '-b:a', '128k',
331
  '-movflags', '+faststart',
 
338
  if encoder == 'h264_nvenc':
339
  base_command.extend([
340
  '-c:v', 'h264_nvenc',
341
+ '-preset', 'fast',
 
342
  '-cq', '28',
343
  '-c:a', 'copy',
344
  '-movflags', '+faststart',
 
350
  '-preset', 'ultrafast',
351
  '-crf', '28',
352
  '-tune', 'fastdecode',
 
353
  '-c:a', 'copy',
354
  '-movflags', '+faststart',
355
  '-y', output_path
 
359
 
360
  def ffmpeg_cut_video(input_path, start_time, duration, output_path):
361
  """[优化] 快速的视频切割,使用硬件加速和ultrafast预设"""
362
+ try:
363
+ command = build_ffmpeg_command(input_path, start_time, duration, output_path, 'cut')
364
+ print(f"执行FFmpeg命令: {' '.join(command)}") # 调试输出
365
+
366
+ # 创建输出目录(如果不存在)
367
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
368
+
369
+ result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
370
+
371
+ if result.returncode != 0:
372
+ print(f"FFmpeg错误: {result.stderr}") # 输出错误信息
373
+ return False
374
+
375
+ return os.path.exists(output_path)
376
+ except Exception as e:
377
+ print(f"切割视频异常: {e}")
378
+ return False
379
 
380
  def ffmpeg_resize_video(input_path, output_path, target_ratio):
381
  """[优化] 快速的比例调整,使用硬件���速和ultrafast预设"""
382
+ try:
383
+ if target_ratio == '9:16':
384
+ filter_complex = "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black"
385
+ else:
386
+ filter_complex = "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black"
387
+
388
+ command = build_ffmpeg_command(input_path, 0, 0, output_path, 'resize')
389
+ # 在resize操作中插入滤镜
390
+ command.insert(-5, '-vf') # 在-y之前插入
391
+ command.insert(-4, filter_complex)
392
+
393
+ print(f"执行FFmpeg调整命令: {' '.join(command)}") # 调试输出
394
+
395
+ # 创建输出目录(如果不存在)
396
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
397
+
398
+ result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
399
+
400
+ if result.returncode != 0:
401
+ print(f"FFmpeg调整错误: {result.stderr}") # 输出错误信息
402
+ return False
403
+
404
+ return os.path.exists(output_path)
405
+ except Exception as e:
406
+ print(f"调整视频异常: {e}")
407
+ return False
408
 
409
  def concat_videos(file_list, output_path):
410
  """稳定的视频合并"""
 
425
  # 使用多线程进行合并
426
  threads = get_optimal_threads()
427
  command = ['ffmpeg', '-threads', str(threads), '-f', 'concat', '-safe', '0', '-i', list_file.name, '-c', 'copy', '-y', output_path]
428
+
429
+ print(f"执行FFmpeg合并命令: {' '.join(command)}") # 调试输出
430
+
431
+ # 创建输出目录(如果不存在)
432
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
433
+
434
+ result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
435
+
436
+ if result.returncode != 0:
437
+ print(f"FFmpeg合并错误: {result.stderr}") # 输出错误信息
438
+ return False
439
+
440
+ return os.path.exists(output_path)
441
  finally:
442
  try:
443
  os.unlink(list_file.name)
 
453
  cmd = ['ffprobe', '-v', 'quiet', '-show_entries', 'format=duration', '-of', 'default=noprint_wrappers=1:nokey=1', video_path]
454
  result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
455
  total_duration = float(result.stdout.strip())
456
+ print(f"视频总时长: {total_duration} 秒")
457
  except Exception as e:
458
  print(f"处理视频 {video_path} 时获取时长失败: {e}")
459
  return clips
 
465
  # 修改文件名,包含原始文件名和计数,避免不同视频的切片重名
466
  clip_path = os.path.join(temp_dir, f"clip_{os.path.splitext(os.path.basename(video_path))[0]}_{count}.mp4")
467
 
468
+ print(f"正在切割片段 {count}: {start}-{start+duration} 秒 -> {clip_path}")
469
+
470
  if ffmpeg_cut_video(video_path, start, duration, clip_path):
471
  clips.append(clip_path)
472
+ print(f"✅ 切片成功: {clip_path}")
473
  else:
474
+ print(f" 切片失败: {clip_path}")
475
 
476
  start += clip_duration
477
  count += 1
 
494
 
495
  all_clips = []
496
 
497
+ # 使用线程池进行并行处理(避免GIL限制)
498
+ print(f"🚀 启动并行切片({min(4, os.cpu_count() or 1)} 线程)...")
499
+ with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor:
500
  future_to_video = {
501
  executor.submit(process_single_video, vf, clip_duration, temp_dir): vf
502
  for vf in video_files
 
852
  **⬇️ 一键下载功能:**
853
  - 📦 **一键下载全部**: 打包下载储存空间中所有视频
854
  - 📥 **选择下载**: 勾选特定文件进行批量下载
855
+