Refactor Timelapse Tuner to merge multiple videos with audio

This commit is contained in:
Roger Gonzalez 2024-10-19 13:41:20 -03:00
parent 0e3b2ff3c3
commit 96b3c05ac7
Signed by: rogs
GPG Key ID: C7ECE9C6C36EC2E6
2 changed files with 62 additions and 42 deletions

View File

@ -2,7 +2,7 @@
[[https://gitlab.com/uploads/-/system/project/avatar/62789004/timelapse_tuner.png]] [[https://gitlab.com/uploads/-/system/project/avatar/62789004/timelapse_tuner.png]]
Timelapse Tuner is a Bash script that automates the process of creating timelapse videos with randomly selected background music. It merges a timelapse video file with a randomly chosen audio file from the current directory, applying fade-in and fade-out effects to the audio for a polished result. It now supports both horizontal and vertical video output! Timelapse Tuner is a Bash script that automates the process of creating timelapse videos with randomly selected background music. It can merge multiple timelapse video files and combine them with a randomly chosen audio file from the current directory, applying fade-in and fade-out effects to the audio for a polished result. It supports both horizontal and vertical video output!
* Video Demo * Video Demo
:PROPERTIES: :PROPERTIES:
@ -18,10 +18,11 @@ Timelapse Tuner is a Bash script that automates the process of creating timelaps
:ID: f0a43fa6-6a89-409e-a72b-83145dd70e0c :ID: f0a43fa6-6a89-409e-a72b-83145dd70e0c
:END: :END:
- Merges a specified timelapse video file with a randomly selected MP3 audio file - Merges multiple timelapse video files into a single video
- Combines the merged video with a randomly selected MP3 audio file
- Applies fade-in and fade-out effects to the audio for smooth transitions - Applies fade-in and fade-out effects to the audio for smooth transitions
- Randomly selects a start point in the audio file to add variety - Randomly selects a start point in the audio file to add variety
- Supports custom input timelapse video and output file specification - Supports custom input timelapse videos and output file specification
- Allows customization of fade duration - Allows customization of fade duration
- Provides option to convert horizontal videos to vertical format - Provides option to convert horizontal videos to vertical format
- Provides detailed logging of the merging process - Provides detailed logging of the merging process
@ -66,7 +67,7 @@ You will also need to provide your own MP3 files for background music. If you ne
Run the script with the following command: Run the script with the following command:
#+BEGIN_SRC sh #+BEGIN_SRC sh
./tt --video <input_timelapse_video> --output <output_file> [--fade <fade_duration>] [--vertical] ./tt --video <video_file1> [<video_file2> ...] --output <output_file> [--fade <fade_duration>] [--vertical]
#+END_SRC #+END_SRC
** Options: ** Options:
@ -74,7 +75,7 @@ Run the script with the following command:
:ID: 9afd9a28-f9bf-47f0-a154-ff51f72c67e8 :ID: 9afd9a28-f9bf-47f0-a154-ff51f72c67e8
:END: :END:
- =--video=: Specify the input timelapse video file (required) - =--video=: Specify one or more input video files (at least one is required)
- =--output=: Specify the output MP4 file name (optional, default: output_video.mp4) - =--output=: Specify the output MP4 file name (optional, default: output_video.mp4)
- =--fade=: Specify the fade duration in seconds (optional, default: 2) - =--fade=: Specify the fade duration in seconds (optional, default: 2)
- =--vertical=: Convert the video to vertical format (optional, default: horizontal) - =--vertical=: Convert the video to vertical format (optional, default: horizontal)
@ -84,14 +85,14 @@ Run the script with the following command:
:ID: 0b930521-693e-49de-af95-fc7004264b30 :ID: 0b930521-693e-49de-af95-fc7004264b30
:END: :END:
For horizontal output (default): For merging multiple horizontal videos (default):
#+BEGIN_SRC sh #+BEGIN_SRC sh
./tt --video my_timelapse.mp4 --output final_timelapse.mp4 --fade 3 ./tt --video timelapse1.mp4 timelapse2.mp4 timelapse3.mp4 --output merged_timelapse.mp4 --fade 3
#+END_SRC #+END_SRC
For vertical output: For merging multiple videos and converting to vertical format:
#+BEGIN_SRC sh #+BEGIN_SRC sh
./tt --video my_timelapse.mp4 --output vertical_timelapse.mp4 --fade 3 --vertical ./tt --video timelapse1.mp4 timelapse2.mp4 --output vertical_timelapse.mp4 --fade 3 --vertical
#+END_SRC #+END_SRC
* How It Works * How It Works
@ -100,14 +101,15 @@ For vertical output:
:END: :END:
1. The script checks for the required dependencies (FFmpeg, FFprobe, bc). 1. The script checks for the required dependencies (FFmpeg, FFprobe, bc).
2. It verifies the input timelapse video file exists. 2. It verifies that all input video files exist.
3. A random MP3 file is selected from the current directory to serve as background music. 3. A random MP3 file is selected from the current directory to serve as background music.
4. The lengths of both the timelapse video and audio files are calculated. 4. The lengths of all video files and the audio file are calculated.
5. Fade-in and fade-out durations are set (default 2 seconds, customizable with --fade) for smooth audio transitions. 5. If multiple video files are provided, they are concatenated in the order specified.
6. A random start point in the audio file is selected to ensure variety in the background music. 6. Fade-in and fade-out durations are set (default 2 seconds, customizable with --fade) for smooth audio transitions.
7. If the --vertical option is used, the video is scaled and cropped to 1080x1920 resolution. 7. A random start point in the audio file is selected to ensure variety in the background music.
8. FFmpeg is used to merge the timelapse video with the selected portion of the audio, applying fade effects and any necessary format conversion. 8. If the --vertical option is used, the combined video is scaled and cropped to 1080x1920 resolution.
9. The final timelapse video with background music is saved as an MP4 file. 9. FFmpeg is used to merge the concatenated video with the selected portion of the audio, applying fade effects and any necessary format conversion.
10. The final timelapse video with background music is saved as an MP4 file.
* Providing Background Music * Providing Background Music
:PROPERTIES: :PROPERTIES:
@ -136,6 +138,7 @@ If you encounter any issues:
2. Check that you have read/write permissions in the current directory. 2. Check that you have read/write permissions in the current directory.
3. Verify that there are MP3 files in the same directory as the script for background music. 3. Verify that there are MP3 files in the same directory as the script for background music.
4. If FFmpeg fails, check the error message for details on what went wrong. 4. If FFmpeg fails, check the error message for details on what went wrong.
5. When using multiple input videos, ensure they have compatible formats and resolutions.
* Contributing * Contributing
:PROPERTIES: :PROPERTIES:

65
tt
View File

@ -24,9 +24,9 @@ command_exists() {
# Function to print usage information # Function to print usage information
print_usage() { print_usage() {
echo "Usage: $0 --video <video_file> --output <output_file> [--fade <fade_duration>] [--vertical]" echo "Usage: $0 --video <video_file1> [<video_file2> ...] --output <output_file> [--fade <fade_duration>] [--vertical]"
echo "Options:" echo "Options:"
echo " --video Specify the input video file" echo " --video Specify one or more input video files"
echo " --output Specify the output MP4 file name (default: output_video.mp4)" echo " --output Specify the output MP4 file name (default: output_video.mp4)"
echo " --fade Specify the fade duration in seconds (default: 2)" echo " --fade Specify the fade duration in seconds (default: 2)"
echo " --vertical Convert the video to vertical format (default: horizontal)" echo " --vertical Convert the video to vertical format (default: horizontal)"
@ -38,7 +38,7 @@ log_message() {
} }
# Initialize variables # Initialize variables
video_file="" video_files=()
output_file="output_video.mp4" output_file="output_video.mp4"
fade_duration=2 fade_duration=2
vertical=false vertical=false
@ -47,8 +47,11 @@ vertical=false
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case $1 in case $1 in
--video) --video)
video_file="$2" shift
shift 2 while [[ $# -gt 0 && ! $1 == --* ]]; do
video_files+=("$1")
shift
done
;; ;;
--output) --output)
output_file="$2" output_file="$2"
@ -80,19 +83,21 @@ for cmd in ffmpeg ffprobe bc; do
done done
log_message "All required programs found" log_message "All required programs found"
# Check if a video file is provided # Check if video files are provided
if [ -z "$video_file" ]; then if [ ${#video_files[@]} -eq 0 ]; then
log_message "Error: No video file specified" log_message "Error: No video files specified"
print_usage print_usage
exit 1 exit 1
fi fi
# Check if the video file exists # Check if all video files exist
if [ ! -f "$video_file" ]; then for video_file in "${video_files[@]}"; do
if [ ! -f "$video_file" ]; then
log_message "Error: Video file '$video_file' not found" log_message "Error: Video file '$video_file' not found"
exit 1 exit 1
fi fi
log_message "Input video file: $video_file" done
log_message "Input video files: ${video_files[*]}"
# Pick a random .mp3 file from the current directory # Pick a random .mp3 file from the current directory
log_message "Selecting a random MP3 file..." log_message "Selecting a random MP3 file..."
@ -112,14 +117,24 @@ log_message "Audio length: $audio_length seconds"
log_message "Fade duration set to $fade_duration seconds" log_message "Fade duration set to $fade_duration seconds"
# Get the length of the video file in seconds # Prepare FFmpeg command for video concatenation
log_message "Calculating video file length..." concat_filter="concat=n=${#video_files[@]}:v=1:a=0"
video_length=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$video_file") video_inputs=""
log_message "Video length: $video_length seconds" for i in "${!video_files[@]}"; do
video_inputs+="-i \"${video_files[$i]}\" "
done
# Calculate total video length
total_video_length=0
for video_file in "${video_files[@]}"; do
video_length=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$video_file")
total_video_length=$(echo "$total_video_length + $video_length" | bc)
done
log_message "Total video length: $total_video_length seconds"
# Use the shorter of the two lengths for fade-out calculation # Use the shorter of the two lengths for fade-out calculation
log_message "Calculating minimum length for fade-out..." log_message "Calculating minimum length for fade-out..."
min_length=$(echo "if ($video_length < $audio_length) $video_length else $audio_length" | bc) min_length=$(echo "if ($total_video_length < $audio_length) $total_video_length else $audio_length" | bc)
log_message "Minimum length: $min_length seconds" log_message "Minimum length: $min_length seconds"
# Ensure fade-out starts at a valid time # Ensure fade-out starts at a valid time
@ -130,9 +145,9 @@ if (( $(echo "$fade_out_start < 0" | bc -l) )); then
fi fi
log_message "Fade-out starts at: $fade_out_start seconds" log_message "Fade-out starts at: $fade_out_start seconds"
# Calculate a random start time within the audio length minus the video length # Calculate a random start time within the audio length minus the total video length
log_message "Calculating random start time for audio..." log_message "Calculating random start time for audio..."
max_start=$(echo "$audio_length - $video_length" | bc | cut -d'.' -f1) max_start=$(echo "$audio_length - $total_video_length" | bc | cut -d'.' -f1)
if [ "$max_start" -lt 0 ]; then if [ "$max_start" -lt 0 ]; then
random_start=0 random_start=0
else else
@ -141,15 +156,17 @@ fi
log_message "Random start time: $random_start seconds" log_message "Random start time: $random_start seconds"
# Prepare FFmpeg command # Prepare FFmpeg command
ffmpeg_command="ffmpeg -loglevel error -stats -i \"$video_file\" -ss $random_start -i \"$audio_file\"" ffmpeg_command="ffmpeg -loglevel error -stats $video_inputs -ss $random_start -i \"$audio_file\" -filter_complex \""
if $vertical; then if $vertical; then
log_message "Converting to vertical format..." log_message "Converting to vertical format..."
ffmpeg_command+=" -filter_complex \"[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,setsar=1[v];[1:a]afade=t=in:st=0:d=$fade_duration,afade=t=out:st=$fade_out_start:d=$fade_duration[a]\"" ffmpeg_command+="$concat_filter [v_concat]; [v_concat]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,setsar=1[v];"
ffmpeg_command+="[${#video_files[@]}:a]afade=t=in:st=0:d=$fade_duration,afade=t=out:st=$fade_out_start:d=$fade_duration[a]\""
ffmpeg_command+=" -map \"[v]\" -map \"[a]\"" ffmpeg_command+=" -map \"[v]\" -map \"[a]\""
else else
ffmpeg_command+=" -filter_complex \"[1:a]afade=t=in:st=0:d=$fade_duration,afade=t=out:st=$fade_out_start:d=$fade_duration[a]\"" ffmpeg_command+="$concat_filter [v_concat];"
ffmpeg_command+=" -map 0:v -map \"[a]\"" ffmpeg_command+="[${#video_files[@]}:a]afade=t=in:st=0:d=$fade_duration,afade=t=out:st=$fade_out_start:d=$fade_duration[a]\""
ffmpeg_command+=" -map \"[v_concat]\" -map \"[a]\""
fi fi
ffmpeg_command+=" -c:v libx264 -c:a aac -shortest \"$output_file\"" ffmpeg_command+=" -c:v libx264 -c:a aac -shortest \"$output_file\""
@ -161,7 +178,7 @@ eval $ffmpeg_command
# Check if ffmpeg was successful # Check if ffmpeg was successful
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
log_message "ffmpeg process completed successfully" log_message "ffmpeg process completed successfully"
log_message "Merged $video_file with random audio: $audio_file" log_message "Merged ${#video_files[@]} video files with random audio: $audio_file"
log_message "Audio starts at $random_start seconds, with fade-in/out effects" log_message "Audio starts at $random_start seconds, with fade-in/out effects"
if $vertical; then if $vertical; then
log_message "Video converted to vertical format" log_message "Video converted to vertical format"