import logging import os import subprocess from celery import shared_task from Ansjer.config import LOGGER import django # 设置 Django 的环境变量 os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'Ansjer.cn_config.test_settings') # 确保替换为实际的 settings 模块路径 django.setup() def start_xvfb(): try: # 检查 Xvfb 是否已经在运行 output = subprocess.check_output("pgrep -f Xvfb", shell=True) if output: LOGGER.info('虚拟显示服务已在运行') os.environ['DISPLAY'] = ':99' else: # 启动虚拟显示服务 process = subprocess.Popen(['Xvfb', ':99', '-screen', '0', '1024x768x16']) LOGGER.info('虚拟显示服务启动成功,进程ID: %s', process.pid) os.environ['DISPLAY'] = ':99' except subprocess.CalledProcessError: # 如果没有运行,启动 Xvfb process = subprocess.Popen(['Xvfb', ':99', '-screen', '0', '1024x768x16']) LOGGER.info('虚拟显示服务启动成功,进程ID: %s', process.pid) os.environ['DISPLAY'] = ':99' except Exception as e: LOGGER.error('启动虚拟显示服务失败: %s', e) @shared_task def generate_video(image_files, output_path): LOGGER.info('start开始视频生成任务') # 启动虚拟显示服务 start_xvfb() try: video_files = [] music_path = "static/ffmpeg/music.mp3" # 定义特效列表 transitions = [ "BowTieHorizontal.glsl", "burn.glsl", "cube.glsl", "pinwheel.glsl", "windowslice.glsl", "Radial.glsl", "rotateTransition.glsl", "wind.glsl", "squeeze.glsl" ] # 生成相邻图片的视频 for i in range(len(image_files) - 1): output_video = os.path.join(output_path, f'{i + 1}_{i + 2}.mp4') video_files.append(output_video) cmd = [ 'static/ffmpeg/ffmpeg4', '-loop', '1', '-i', image_files[i], '-loop', '1', '-i', image_files[i + 1], '-filter_complex', f'gltransition=duration=1:offset=0.7:source=static/gl-transitions/{transitions[i]}', '-t', '2', output_video ] subprocess.run(cmd, check=True) # 生成拼接列表文件 filelist_path = os.path.join(output_path, 'filelist.txt') with open(filelist_path, 'w') as f: for video in video_files: f.write(f"file '{os.path.relpath(video, output_path)}'\n") # 使用相对路径 # 拼接并生成背景音乐 final_output_with_music = os.path.join(output_path, 'final_output_with_music.mp4') subprocess.run( ['static/ffmpeg/ffmpeg6', '-f', 'concat', '-safe', '0', '-i', filelist_path, '-i', music_path, '-c:v', 'copy', '-c:a', 'aac', '-b:a', '192k', '-movflags', '+faststart', '-shortest', final_output_with_music], check=True ) video420acc = os.path.join(output_path, 'video420acc.mp4') subprocess.run( ['static/ffmpeg/ffmpeg6', '-i', final_output_with_music, '-pix_fmt', 'yuv420p', video420acc], check=True ) # 清理临时文件 for video in video_files: os.remove(video) os.remove(filelist_path) os.remove(final_output_with_music) except Exception as e: LOGGER.info(f'视频合成失败: {e}')