caption.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import os
  2. import json
  3. import subprocess
  4. import time
  5. import ffmpeg
  6. from moviepy.editor import VideoFileClip, TextClip, CompositeVideoClip
  7. from moviepy.video.tools.subtitles import SubtitlesClip
  8. from .logger_config import setup_logger
  9. from .llm_director import caption_correct
  10. logger = setup_logger(__name__)
  11. def sec_to_srt_time(seconds):
  12. hours = int(seconds // 3600)
  13. mins = int((seconds % 3600) // 60)
  14. secs = seconds % 60
  15. return f"{hours:02d}:{mins:02d}:{secs:06.3f}".replace('.', ',')
  16. def generate_srt_file(text_sequence, output_path):
  17. """
  18. 生成SRT字幕文件
  19. 参数:
  20. text_sequence: 字幕列表,格式 [(start_sec, end_sec, text), ...]
  21. """
  22. logger.info(f"字幕文件生成。。。")
  23. with open(output_path, 'w', encoding='utf-8') as f:
  24. for i, (start, end, text) in enumerate(text_sequence, 1):
  25. f.write(f"{i}\n")
  26. f.write(f"{sec_to_srt_time(start)} --> {sec_to_srt_time(end)}\n")
  27. f.write(f"{caption_correct(text)}\n\n")
  28. def burn_subtitles_bash(input_path, srt_path, output_path):
  29. cmdLine = f"ffmpeg -i {input_path} -vf subtitles={srt_path} -c:a copy -c:v h264_nvenc -preset fast -cq 23 {output_path}"
  30. subprocess.call(cmdLine, shell=True)
  31. def burn_subtitles_ffmpeg(input_path, srt_path, output_path, style_config=None):
  32. """
  33. 通过FFmpeg烧录字幕(硬编码) - 确保音频保留的版本
  34. """
  35. logger.info(f"视频加字幕。。。")
  36. # 默认字幕样式(精简必要参数)
  37. with open("./config/caption_config.json", 'r', encoding='utf-8') as file:
  38. caption = json.load(file)
  39. default_style = caption
  40. style = style_config or default_style
  41. # 构建字幕过滤器字符串
  42. subtitle_filter = (
  43. f"subtitles={srt_path}:force_style='"
  44. f"Fontname={style['fontname']},"
  45. f"Fontsize={style['fontsize']},"
  46. f"PrimaryColour={style['fontcolor']},"
  47. f"BackColour={style['bordercolor']},"
  48. f"Outline={style['borderw']},"
  49. f"Alignment={style['alignment']},"
  50. f"MarginV={style['margin']}'"
  51. )
  52. # 使用更简单的命令结构,确保音频流被正确处理
  53. (
  54. ffmpeg
  55. .input(input_path)
  56. .output(
  57. output_path,
  58. vf=subtitle_filter, # 应用字幕过滤器
  59. **{
  60. 'preset': 'fast',
  61. 'tune': 'fastdecode',
  62. 'c:a': 'copy', # 尝试直接复制音频
  63. 'threads': '8',
  64. 'y': None
  65. }
  66. )
  67. .global_args('-hwaccel', 'cuda')
  68. .run()
  69. # 'c:v': 'h264_nvenc',
  70. # 'cq': 28,
  71. # 'gpu': '1',
  72. # 'rc': 'constqp',
  73. )
  74. if __name__ == "__main__":
  75. # 生成测试字幕
  76. text_sequence = [
  77. (0.0, 10.0, "第一句字幕测试"),
  78. ]
  79. generate_srt_file(text_sequence, 'dynamic_subtitles.srt')
  80. start_time = time.time()
  81. # 示例用法(硬件加速需配置FFmpeg)
  82. burn_subtitles_ffmpeg('./output/video_clips/cut_video3.mp4', 'dynamic_subtitles.srt', 'output3.mp4')
  83. print(f"{time.time() - start_time} secs")
  84. ## TODO:
  85. # 1、JSON to SRT
  86. # 2、JSON to CLIPS
  87. # 3、SRT add to CLIPS