TimeAlbumTask.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import logging
  2. import os
  3. import subprocess
  4. from celery import shared_task
  5. from Ansjer.config import LOGGER
  6. import django
  7. # 设置 Django 的环境变量
  8. os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'Ansjer.cn_config.test_settings') # 确保替换为实际的 settings 模块路径
  9. django.setup()
  10. def start_xvfb():
  11. try:
  12. # 检查 Xvfb 是否已经在运行
  13. output = subprocess.check_output("pgrep -f Xvfb", shell=True)
  14. if output:
  15. LOGGER.info('虚拟显示服务已在运行')
  16. os.environ['DISPLAY'] = ':99'
  17. else:
  18. # 启动虚拟显示服务
  19. process = subprocess.Popen(['Xvfb', ':99', '-screen', '0', '1024x768x16'])
  20. LOGGER.info('虚拟显示服务启动成功,进程ID: %s', process.pid)
  21. os.environ['DISPLAY'] = ':99'
  22. except subprocess.CalledProcessError:
  23. # 如果没有运行,启动 Xvfb
  24. process = subprocess.Popen(['Xvfb', ':99', '-screen', '0', '1024x768x16'])
  25. LOGGER.info('虚拟显示服务启动成功,进程ID: %s', process.pid)
  26. os.environ['DISPLAY'] = ':99'
  27. except Exception as e:
  28. LOGGER.error('启动虚拟显示服务失败: %s', e)
  29. @shared_task
  30. def generate_video(image_files, output_path):
  31. LOGGER.info('start开始视频生成任务')
  32. # 启动虚拟显示服务
  33. start_xvfb()
  34. try:
  35. video_files = []
  36. music_path = "static/ffmpeg/music.mp3"
  37. # 定义特效列表
  38. transitions = [
  39. "BowTieHorizontal.glsl",
  40. "burn.glsl",
  41. "cube.glsl",
  42. "pinwheel.glsl",
  43. "windowslice.glsl",
  44. "Radial.glsl",
  45. "rotateTransition.glsl",
  46. "wind.glsl",
  47. "squeeze.glsl"
  48. ]
  49. # 生成相邻图片的视频
  50. for i in range(len(image_files) - 1):
  51. output_video = os.path.join(output_path, f'{i + 1}_{i + 2}.mp4')
  52. video_files.append(output_video)
  53. cmd = [
  54. 'static/ffmpeg/ffmpeg4', '-loop', '1', '-i', image_files[i],
  55. '-loop', '1', '-i', image_files[i + 1],
  56. '-filter_complex',
  57. f'gltransition=duration=1:offset=0.7:source=static/gl-transitions/{transitions[i]}',
  58. '-t', '2', output_video
  59. ]
  60. subprocess.run(cmd, check=True)
  61. # 生成拼接列表文件
  62. filelist_path = os.path.join(output_path, 'filelist.txt')
  63. with open(filelist_path, 'w') as f:
  64. for video in video_files:
  65. f.write(f"file '{os.path.relpath(video, output_path)}'\n") # 使用相对路径
  66. # 拼接并生成背景音乐
  67. final_output_with_music = os.path.join(output_path, 'final_output_with_music.mp4')
  68. subprocess.run(
  69. ['static/ffmpeg/ffmpeg6', '-f', 'concat', '-safe', '0', '-i', filelist_path, '-i', music_path,
  70. '-c:v', 'copy', '-c:a', 'aac', '-b:a', '192k', '-movflags', '+faststart', '-shortest',
  71. final_output_with_music],
  72. check=True
  73. )
  74. video420acc = os.path.join(output_path, 'video420acc.mp4')
  75. subprocess.run(
  76. ['static/ffmpeg/ffmpeg6', '-i', final_output_with_music, '-pix_fmt', 'yuv420p', video420acc],
  77. check=True
  78. )
  79. # 清理临时文件
  80. for video in video_files:
  81. os.remove(video)
  82. os.remove(filelist_path)
  83. os.remove(final_output_with_music)
  84. except Exception as e:
  85. LOGGER.info(f'视频合成失败: {e}')