k4d3 commited on
Commit
404feac
1 Parent(s): e2639ce
Files changed (2) hide show
  1. png2mp4 +144 -0
  2. zsh/png2mp4.zsh +0 -97
png2mp4 ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ #!/usr/bin/env python3
5
+
6
+ import argparse
7
+ import os
8
+ import shutil
9
+ import subprocess
10
+ import glob
11
+ import re
12
+ from pathlib import Path
13
+
14
+ def create_video(input_dir, sample, temp_dir, step_multiplier, repeat, max_images):
15
+ output_filename = f"{os.path.basename(os.getcwd())}_sample{sample}.mp4"
16
+ print(f"Processing sample {sample}. Output filename: {output_filename}")
17
+
18
+ # Create repeated images
19
+ print(f"Creating repeated images for sample {sample}...")
20
+ for img in glob.glob(f"{input_dir}/*_{sample}_*.png"):
21
+ for i in range(repeat):
22
+ base = os.path.splitext(os.path.basename(img))[0]
23
+ shutil.copy(img, f"{temp_dir}/{base}_{i+1}.png")
24
+
25
+ # Prepare ffmpeg options
26
+ vf_options = "scale=1024x1024"
27
+ if step_multiplier:
28
+ 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"
29
+
30
+ if max_images:
31
+ vf_options = f"select='not(mod(n\\,{max_images}))',{vf_options}"
32
+
33
+ # Run first ffmpeg command
34
+ temp_output = f"{temp_dir}/temp_{sample}.mp4"
35
+ ffmpeg_cmd = [
36
+ "ffmpeg", "-framerate", "60",
37
+ "-pattern_type", "glob", "-i", f"{temp_dir}/*_{sample}_*.png",
38
+ "-vf", vf_options,
39
+ "-crf", "18", "-c:v", "libx264", "-b:v", "12M",
40
+ "-pix_fmt", "yuv420p", "-y", temp_output
41
+ ]
42
+
43
+ try:
44
+ subprocess.run(ffmpeg_cmd, check=True)
45
+ except subprocess.CalledProcessError:
46
+ print(f"Error: ffmpeg command failed for sample {sample}.")
47
+ return False
48
+
49
+ # Get duration and process final video
50
+ try:
51
+ duration_cmd = ["ffmpeg", "-i", temp_output]
52
+ result = subprocess.run(duration_cmd, capture_output=True, text=True, stderr=subprocess.PIPE)
53
+ duration_match = re.search(r'Duration: (\d{2}):(\d{2}):(\d{2})', result.stderr)
54
+ if duration_match:
55
+ hours, minutes, seconds = map(float, duration_match.groups())
56
+ duration = hours * 3600 + minutes * 60 + seconds
57
+ fade_start = duration + 3
58
+
59
+ final_cmd = [
60
+ "ffmpeg", "-i", temp_output,
61
+ "-vf", f"tpad=stop_mode=clone:stop_duration=8,fade=t=out:st={fade_start}:d=5",
62
+ "-c:v", "libx264", "-b:v", "12M", "-crf", "18",
63
+ "-pix_fmt", "yuv420p", "-y", output_filename
64
+ ]
65
+ subprocess.run(final_cmd, check=True)
66
+ else:
67
+ print("Error: Could not determine video duration.")
68
+ return False
69
+
70
+ except subprocess.CalledProcessError:
71
+ print(f"Error: Final ffmpeg processing failed for sample {sample}.")
72
+ return False
73
+
74
+ # Clean up temporary files for this sample
75
+ for f in glob.glob(f"{temp_dir}/*_{sample}_*.png"):
76
+ os.remove(f)
77
+ os.remove(temp_output)
78
+
79
+ return True
80
+
81
+ def get_step_size_from_filenames(sample):
82
+ files = sorted(glob.glob(f"*_{sample}_*.png"))
83
+ if len(files) < 2:
84
+ return None
85
+
86
+ # Extract step numbers from first two files
87
+ pattern = r'_(\d{6})_'
88
+ first_match = re.search(pattern, files[0])
89
+ second_match = re.search(pattern, files[1])
90
+
91
+ if first_match and second_match:
92
+ first_step = int(first_match.group(1))
93
+ second_step = int(second_match.group(1))
94
+ return second_step - first_step
95
+ return None
96
+
97
+ def main():
98
+ parser = argparse.ArgumentParser(description='Convert PNG sequence to MP4')
99
+ parser.add_argument('--max', type=int, help='Maximum number of images')
100
+ parser.add_argument('--step', type=int, help='Step multiplier')
101
+ parser.add_argument('--repeat', type=int, default=1, help='Repeat count')
102
+ parser.add_argument('--steps-from-filename', action='store_true', help='Calculate steps from filename')
103
+
104
+ args = parser.parse_args()
105
+
106
+ # Create temporary directory
107
+ temp_dir = os.path.expanduser("~/.local/tmp")
108
+ os.makedirs(temp_dir, exist_ok=True)
109
+ print("Created temporary directory...")
110
+
111
+ # Check for PNG files
112
+ png_files = glob.glob("*.png")
113
+ if not png_files:
114
+ print("Error: No PNG files found in the current directory.")
115
+ return 1
116
+
117
+ # Find all unique sample numbers
118
+ sample_pattern = r'_(\d{2})_'
119
+ samples = sorted(set(re.findall(sample_pattern, ' '.join(png_files))))
120
+
121
+ for sample in samples:
122
+ if args.steps_from_filename:
123
+ step_multiplier = get_step_size_from_filenames(sample)
124
+ if step_multiplier:
125
+ print(f"Detected step size: {step_multiplier}")
126
+ else:
127
+ print("Error: Could not determine step size from filenames")
128
+ continue
129
+ else:
130
+ step_multiplier = args.step
131
+
132
+ success = create_video(".", sample, temp_dir, step_multiplier, args.repeat, args.max)
133
+ if not success:
134
+ shutil.rmtree(temp_dir)
135
+ return 1
136
+
137
+ # Clean up
138
+ print("Cleaning up temporary directory...")
139
+ shutil.rmtree(temp_dir)
140
+ print("All samples processed successfully.")
141
+ return 0
142
+
143
+ if __name__ == "__main__":
144
+ exit(main())
zsh/png2mp4.zsh DELETED
@@ -1,97 +0,0 @@
1
- png2mp4() {
2
- local max_images=""
3
- local step_multiplier=""
4
- local repeat=1
5
- local temp_dir="/home/kade/.local/tmp"
6
- local steps_from_filename=0
7
-
8
- while [[ "$#" -gt 0 ]]; do
9
- case $1 in
10
- --max) max_images="$2"; shift ;;
11
- --step) step_multiplier="$2"; shift ;;
12
- --repeat) repeat="$2"; shift ;;
13
- --steps-from-filename) steps_from_filename=1; shift ;;
14
- *) echo "Unknown parameter passed: $1"; return 1 ;;
15
- esac
16
- shift
17
- done
18
-
19
- echo "Creating temporary directory..."
20
- mkdir -p "$temp_dir"
21
-
22
- echo "Checking for PNG files..."
23
- png_files=($(/usr/bin/env ls *.png 2>/dev/null))
24
- if [ ${#png_files[@]} -eq 0 ]; then
25
- echo "Error: No PNG files found in the current directory."
26
- return 1
27
- fi
28
-
29
- # Find all unique sample numbers
30
- local samples=($(ls *.png | sed -n 's/.*_\([0-9][0-9]\)_.*/\1/p' | sort -u))
31
-
32
- for sample in "${samples[@]}"; do
33
- local output_filename="$(basename "$(pwd)")_sample${sample}.mp4"
34
- echo "Processing sample ${sample}. Output filename: $output_filename"
35
-
36
- # Calculate step size from filenames if requested
37
- if [[ $steps_from_filename -eq 1 ]]; then
38
- # Get first two files for this sample
39
- local first_file=$(ls *_${sample}_*.png | sort | head -n 1)
40
- local second_file=$(ls *_${sample}_*.png | sort | head -n 2 | tail -n 1)
41
-
42
- # Extract step numbers from filenames
43
- local first_step=$(echo $first_file | grep -o '_[0-9]\{6\}_' | tr -d '_')
44
- local second_step=$(echo $second_file | grep -o '_[0-9]\{6\}_' | tr -d '_')
45
-
46
- # Calculate step difference using bc
47
- step_multiplier=$(echo "$second_step - $first_step" | bc)
48
- echo "Detected step size: $step_multiplier"
49
- fi
50
-
51
- echo "Creating repeated images for sample ${sample}..."
52
- for img in *_${sample}_*.png; do
53
- for i in $(seq 1 $repeat); do
54
- cp "$img" "$temp_dir/${img%.*}_${i}.png"
55
- done
56
- done
57
-
58
- echo "Running ffmpeg for sample ${sample}..."
59
- local vf_options="scale=1024x1024"
60
- if [[ -n "$step_multiplier" ]]; then
61
- # Modified to use printf for integer formatting
62
- vf_options+=",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"
63
- fi
64
-
65
- if [[ -n "$max_images" ]]; then
66
- vf_options="select='not(mod(n\,$max_images))',$vf_options"
67
- fi
68
-
69
- ffmpeg -framerate 60 -pattern_type glob -i "$temp_dir/*_${sample}_*.png" -vf "$vf_options" -crf 18 \
70
- -c:v libx264 -b:v 12M -pix_fmt yuv420p -y "$temp_dir/temp_${sample}.mp4"
71
-
72
- if [ $? -ne 0 ]; then
73
- echo "Error: ffmpeg command failed for sample ${sample}."
74
- rm -rf "$temp_dir"
75
- return 1
76
- fi
77
-
78
- echo "Processing final video for sample ${sample}..."
79
- duration=$(ffmpeg -i "$temp_dir/temp_${sample}.mp4" 2>&1 | grep 'Duration' | awk '{print $2}' | tr -d , | awk -F: '{print ($1 * 3600) + ($2 * 60) + $3}')
80
- fade_start=$(echo "$duration + 3" | bc)
81
- ffmpeg -i "$temp_dir/temp_${sample}.mp4" -vf "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"
82
-
83
- if [ $? -ne 0 ]; then
84
- echo "Error: Final ffmpeg processing failed for sample ${sample}."
85
- rm -rf "$temp_dir"
86
- return 1
87
- fi
88
-
89
- # Clean up temporary files for this sample
90
- rm "$temp_dir"/*_${sample}_*.png "$temp_dir/temp_${sample}.mp4"
91
- done
92
-
93
- echo "Cleaning up temporary directory..."
94
- rm -rf "$temp_dir"
95
-
96
- echo "All samples processed successfully."
97
- }