File size: 5,161 Bytes
404feac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71e076c
404feac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71e076c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import argparse
import os
import shutil
import subprocess
import glob
import re
from pathlib import Path

def create_video(input_dir, sample, temp_dir, step_multiplier, repeat, max_images):
    output_filename = f"{os.path.basename(os.getcwd())}_sample{sample}.mp4"
    print(f"Processing sample {sample}. Output filename: {output_filename}")
    
    # Create repeated images
    print(f"Creating repeated images for sample {sample}...")
    for img in glob.glob(f"{input_dir}/*_{sample}_*.png"):
        for i in range(repeat):
            base = os.path.splitext(os.path.basename(img))[0]
            shutil.copy(img, f"{temp_dir}/{base}_{i+1}.png")
    
    # Prepare ffmpeg options
    vf_options = "scale=1024x1024"
    if step_multiplier:
        vf_options += f",drawtext=fontfile=/usr/share/fonts/TTF/Inconsolata-Light.ttf:text='Steps\\: %{{expr\\:trunc(n*{step_multiplier}/{repeat})}}':x=10:y=h-th-10:fontsize=24:fontcolor=white"
    
    if max_images:
        vf_options = f"select='not(mod(n\\,{max_images}))',{vf_options}"
    
    # Run first ffmpeg command
    temp_output = f"{temp_dir}/temp_{sample}.mp4"
    ffmpeg_cmd = [
        "ffmpeg", "-framerate", "60",
        "-pattern_type", "glob", "-i", f"{temp_dir}/*_{sample}_*.png",
        "-vf", vf_options,
        "-crf", "18", "-c:v", "libx264", "-b:v", "12M",
        "-pix_fmt", "yuv420p", "-y", temp_output
    ]
    
    try:
        subprocess.run(ffmpeg_cmd, check=True)
    except subprocess.CalledProcessError:
        print(f"Error: ffmpeg command failed for sample {sample}.")
        return False
    
    # Get duration and process final video
    try:
        duration_cmd = ["ffmpeg", "-i", temp_output]
        result = subprocess.run(duration_cmd, capture_output=True, text=True)
        duration_match = re.search(r'Duration: (\d{2}):(\d{2}):(\d{2})', result.stderr)
        if duration_match:
            hours, minutes, seconds = map(float, duration_match.groups())
            duration = hours * 3600 + minutes * 60 + seconds
            fade_start = duration + 3
            
            final_cmd = [
                "ffmpeg", "-i", temp_output,
                "-vf", f"tpad=stop_mode=clone:stop_duration=8,fade=t=out:st={fade_start}:d=5",
                "-c:v", "libx264", "-b:v", "12M", "-crf", "18",
                "-pix_fmt", "yuv420p", "-y", output_filename
            ]
            subprocess.run(final_cmd, check=True)
        else:
            print("Error: Could not determine video duration.")
            return False
            
    except subprocess.CalledProcessError:
        print(f"Error: Final ffmpeg processing failed for sample {sample}.")
        return False
    
    # Clean up temporary files for this sample
    for f in glob.glob(f"{temp_dir}/*_{sample}_*.png"):
        os.remove(f)
    os.remove(temp_output)
    
    return True

def get_step_size_from_filenames(sample):
    files = sorted(glob.glob(f"*_{sample}_*.png"))
    if len(files) < 2:
        return None
    
    # Extract step numbers from first two files
    pattern = r'_(\d{6})_'
    first_match = re.search(pattern, files[0])
    second_match = re.search(pattern, files[1])
    
    if first_match and second_match:
        first_step = int(first_match.group(1))
        second_step = int(second_match.group(1))
        return second_step - first_step
    return None

def main():
    parser = argparse.ArgumentParser(description='Convert PNG sequence to MP4')
    parser.add_argument('--max', type=int, help='Maximum number of images')
    parser.add_argument('--step', type=int, help='Step multiplier')
    parser.add_argument('--repeat', type=int, default=1, help='Repeat count')
    parser.add_argument('--steps-from-filename', action='store_true', help='Calculate steps from filename')
    
    args = parser.parse_args()
    
    # Create temporary directory
    temp_dir = os.path.expanduser("~/.local/tmp")
    os.makedirs(temp_dir, exist_ok=True)
    print("Created temporary directory...")
    
    # Check for PNG files
    png_files = glob.glob("*.png")
    if not png_files:
        print("Error: No PNG files found in the current directory.")
        return 1
    
    # Find all unique sample numbers
    sample_pattern = r'_(\d{2})_'
    samples = sorted(set(re.findall(sample_pattern, ' '.join(png_files))))
    
    for sample in samples:
        if args.steps_from_filename:
            step_multiplier = get_step_size_from_filenames(sample)
            if step_multiplier:
                print(f"Detected step size: {step_multiplier}")
            else:
                print("Error: Could not determine step size from filenames")
                continue
        else:
            step_multiplier = args.step
        
        success = create_video(".", sample, temp_dir, step_multiplier, args.repeat, args.max)
        if not success:
            shutil.rmtree(temp_dir)
            return 1
    
    # Clean up
    print("Cleaning up temporary directory...")
    shutil.rmtree(temp_dir)
    print("All samples processed successfully.")
    return 0

if __name__ == "__main__":
    exit(main())