fuck zsh
Browse files- png2mp4 +144 -0
- 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 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|