StableSwarmUI icon indicating copy to clipboard operation
StableSwarmUI copied to clipboard

[Feature Request] - Add video formats (GIF, WebP) to 'Save Image of Current View' in Web Page Grid output

Open githubarooski opened this issue 1 year ago • 3 comments

When using Grid Generator to make a grid of animations, it would be great to be able to output the grid of videos as a single video output file, either GIF, webp, or otherwise. Currently, I am using OBS Studio to record my screen.

image

githubarooski avatar Apr 15 '24 04:04 githubarooski

betting this'll end up as a great way to crash your browser lol, trying to do large-res video processing in javascript

mcmonkey4eva avatar Apr 15 '24 04:04 mcmonkey4eva

another option that comes to mind, now that I'm looking at the output folder structure, would be to drop a batch file into each grid output directory that would create this grid video with ffmpeg. the grid variables could be overlaid on the video with text https://stackoverflow.com/questions/17623676/text-on-video-ffmpeg that would keep it out of the browser entirely.

githubarooski avatar Apr 15 '24 05:04 githubarooski

I wrestled this shell script out of chatgpt which manages to work pretty well at generating an FFMPEG command that combines all videos in subdirectories into a larger grid video. It works great on the few tests I've done. The task of pulling the JSON data out of the grid subdirectories and overlaying it as text on top of the videos seems a bit more daunting as of right now.

#!/bin/bash

ffmpeg_bin="ffmpeg"  # Variable to set the ffmpeg executable path
current_time=$(date +"%Y-%m-%d-%H-%M-%S")  # Current timestamp
output_file="grid-video-output-${current_time}.mp4"
declare -a inputs=()
declare -a layouts=()

# Function to generate the layout string
generate_layout() {
    local num_rows=$1
    local num_cols=$2
    local layout_string=""
    local index=0

    for (( row=0; row<num_rows; row++ )); do
        for (( col=0; col<num_cols; col++ )); do
            if [ $col -eq 0 ]; then
                x_pos="0"
            else
                x_pos="w0"
                for (( k=1; k<col; k++ )); do
                    x_pos+="+w$k"
                done
            fi

            if [ $row -eq 0 ]; then
                y_pos="0"
            else
                y_pos="h0"
                for (( k=1; k<row; k++ )); do
                    y_pos+="+h$k"
                done
            fi

            layout_string+="$x_pos"_"$y_pos|"
        done
    done

    # Remove the last pipe character
    echo "${layout_string%|}"
}

# Find subdirectories and assume each subdirectory corresponds to a row
subdirs=()
for dir in */; do
    # Ensure it is a directory and not empty
    if [ -d "$dir" ] && [ "$(ls -A $dir*.{mp4,webp,mov} 2>/dev/null)" ]; then
        subdirs+=("$dir")
        # Using a glob pattern to match mp4, webp, and mov files
        videos=($(ls $dir*.{mp4,webp,mov} 2>/dev/null))

        # For the first directory, define the number of columns
        if [ ${#inputs[@]} -eq 0 ]; then
            num_columns=${#videos[@]}
        fi

        # Append each video to ffmpeg input
        for (( i=0; i<num_columns; i++ )); do
            inputs+=("-i \"${videos[$i]}\"")
        done
    fi
done

num_rows=${#subdirs[@]}

# Check if we have at least one column and one row
if [ ${#inputs[@]} -eq 0 ] || [ $num_rows -eq 0 ]; then
    echo "No video files found in subdirectories."
    exit 1
fi

# Generate layout string
layout_str=$(generate_layout $num_rows $num_columns)

# Join inputs
input_str=$(IFS=" "; echo "${inputs[*]}")

# Construct the ffmpeg command
ffmpeg_command="$ffmpeg_bin $input_str -filter_complex \"xstack=inputs=$((${#inputs[@]})):layout=$layout_str[v]\" -map '[v]' $output_file"

# Output the command to use it directly
echo "Generated ffmpeg command:"
echo "$ffmpeg_command"

# Uncomment the following line to execute the ffmpeg command directly
# eval "$ffmpeg_command"

githubarooski avatar Apr 15 '24 09:04 githubarooski