| import os |
| import subprocess |
|
|
|
|
| def render_final_video( |
| background, |
| audio, |
| subtitles, |
| output, |
| crf=23, |
| preset="ultrafast" |
| ): |
|
|
| if not os.path.exists(background): |
| raise FileNotFoundError( |
| f"Background file not found: {background}" |
| ) |
|
|
| if not os.path.exists(audio): |
| raise FileNotFoundError( |
| f"Audio file not found: {audio}" |
| ) |
|
|
| if not os.path.exists(subtitles): |
| raise FileNotFoundError( |
| f"Subtitle file not found: {subtitles}" |
| ) |
|
|
| print("=" * 60) |
| print("AVAILABLE FONTS") |
| print("=" * 60) |
|
|
| if os.path.exists("fonts"): |
|
|
| for f in os.listdir("fonts"): |
| print(f) |
|
|
| print("=" * 60) |
| print("FINAL RENDER START") |
| print("=" * 60) |
|
|
| print("BACKGROUND :", background) |
| print("AUDIO :", audio) |
| print("SUBTITLE :", subtitles) |
| print("OUTPUT :", output) |
|
|
| vf_filter = ( |
| |
| |
| |
| |
| |
| f"ass={subtitles}:fontsdir=fonts" |
| ) |
|
|
| cmd = [ |
| "ffmpeg", |
| "-y", |
|
|
| "-stream_loop", |
| "-1", |
|
|
| "-i", |
| background, |
|
|
| "-i", |
| audio, |
|
|
| "-vf", |
| vf_filter, |
|
|
| "-map", |
| "0:v", |
|
|
| "-map", |
| "1:a", |
|
|
| "-c:v", |
| "libx264", |
|
|
| "-preset", |
| preset, |
|
|
| "-crf", |
| str(crf), |
|
|
| "-pix_fmt", |
| "yuv420p", |
|
|
| "-movflags", |
| "+faststart", |
|
|
| "-c:a", |
| "aac", |
|
|
| "-b:a", |
| "192k", |
|
|
| "-shortest", |
|
|
| output |
| ] |
|
|
| print("\nFFMPEG COMMAND:\n") |
| print(" ".join(cmd)) |
| print() |
|
|
| result = subprocess.run( |
| cmd, |
| capture_output=True, |
| text=True |
| ) |
|
|
| print("=" * 60) |
| print("STDOUT") |
| print("=" * 60) |
| print(result.stdout) |
|
|
| print("=" * 60) |
| print("STDERR") |
| print("=" * 60) |
| print(result.stderr) |
|
|
| result.check_returncode() |
|
|
| if not os.path.exists(output): |
|
|
| raise Exception( |
| "Output video was not generated" |
| ) |
|
|
| probe = subprocess.run( |
| [ |
| "ffprobe", |
| "-v", |
| "error", |
|
|
| "-show_entries", |
| "format=duration", |
|
|
| "-of", |
| "default=noprint_wrappers=1:nokey=1", |
|
|
| output |
| ], |
| capture_output=True, |
| text=True |
| ) |
|
|
| duration = probe.stdout.strip() |
|
|
| print("=" * 60) |
| print("FINAL VIDEO DURATION") |
| print("=" * 60) |
| print(duration) |
|
|
| size_mb = ( |
| os.path.getsize(output) |
| / 1024 |
| / 1024 |
| ) |
|
|
| print("=" * 60) |
| print("FINAL VIDEO SIZE") |
| print("=" * 60) |
|
|
| print( |
| f"{size_mb:.2f} MB" |
| ) |
|
|
| print("=" * 60) |
| print("FINAL RENDER SUCCESS") |
| print("=" * 60) |
|
|
| return output |