kritnatee's picture
download
raw
2.57 kB
import argparse, os, subprocess, sys, glob, random, shutil
parser = argparse.ArgumentParser()
parser.add_argument('--images-dir', required=True)
parser.add_argument('--audio', default='')
parser.add_argument('--output', required=True)
parser.add_argument('--duration', type=float, default=3.0)
parser.add_argument('--fps', type=int, default=24)
args = parser.parse_args()
image_exts = ('*.png', '*.jpg', '*.jpeg', '*.webp')
images = []
for ext in image_exts:
images.extend(sorted(glob.glob(os.path.join(args.images_dir, '**', ext), recursive=True)))
if not images:
print("ERROR: No images found"); sys.exit(1)
print(f" Images: {len(images)} files")
ffmpeg = "ffmpeg.exe" if os.name == 'nt' else "ffmpeg"
out_dir = os.path.dirname(args.output)
os.makedirs(out_dir, exist_ok=True)
temp_dir = os.path.join(out_dir, '_segments')
os.makedirs(temp_dir, exist_ok=True)
frames = int(args.duration * args.fps)
concat_path = os.path.join(temp_dir, 'list.txt')
with open(concat_path, 'w') as f:
for i, img in enumerate(images):
seg_out = os.path.join(temp_dir, f"s{i:03d}.mp4")
rng = random.Random(hash(img) % 10000)
zoom = rng.uniform(1.02, 1.06)
dx = rng.uniform(-30, 30)
dy = rng.uniform(-30, 30)
vf = (
f"scale=1920:1080:force_original_aspect_ratio=decrease,"
f"pad=1920:1080:(ow-iw)/2:(oh-ih)/2,"
f"zoompan=z='if(eq(on,1),1,min(zoom+({zoom}-1)/{frames},{zoom}))':"
f"d={frames}:x='iw/2-(iw/zoom/2)+{dx}*(on/{frames})':"
f"y='ih/2-(ih/zoom/2)+{dy}*(on/{frames})':s=1920x1080"
)
subprocess.run(
[ffmpeg, '-y', '-loop', '1', '-i', img,
'-vf', vf, '-c:v', 'libx264', '-preset', 'fast',
'-crf', '18', '-t', str(args.duration), '-an', seg_out],
capture_output=True
)
f.write(f"file '{seg_out}'\n")
cmd = [ffmpeg, '-y', '-f', 'concat', '-safe', '0', '-i', concat_path,
'-c:v', 'libx264', '-preset', 'slow', '-crf', '18',
'-pix_fmt', 'yuv420p', '-movflags', '+faststart']
if args.audio and os.path.exists(args.audio):
cmd.extend(['-i', args.audio, '-c:a', 'aac', '-b:a', '192k', '-shortest'])
else:
cmd.extend(['-an'])
cmd.append(args.output)
result = subprocess.run(cmd, capture_output=True, text=True)
shutil.rmtree(temp_dir, ignore_errors=True)
if result.returncode == 0:
size = os.path.getsize(args.output)
print(f" -> Video: {args.output} ({size/1024/1024:.1f} MB)")
else:
print(f" ERROR: {result.stderr[-300:]}")
sys.exit(1)

Xet Storage Details

Size:
2.57 kB
·
Xet hash:
7c6cf0ed90e39d4b29eaa51509284dbfa74ec489f370595440af340d8dbce4ac

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.