1+ #! /usr/bin/env bash
2+ # License: GPLv3
3+ # Credits: Felipe Facundes
4+
5+ # Default values
6+ INPUT_FILE=" "
7+ OUTPUT_FILE=" "
8+ VIDEO_CODEC=" hevc_nvenc"
9+ DEFAULT_SUFFIX=" _FullHD_9-16"
10+ PROCESS_ALL=false
11+
12+ # Function to display help
13+ show_help () {
14+ echo " Usage: ${0##*/ } [OPTIONS] input_video"
15+ echo " "
16+ echo " Options:"
17+ echo " -o OUTPUT Specify output filename"
18+ echo " -c CODEC Specify video codec (default: hevc_nvenc)"
19+ echo " -l Process all video files in the current directory"
20+ echo " -h Show this help message"
21+ echo " "
22+ echo " Example:"
23+ echo " ${0##*/ } video.mp4"
24+ echo " ${0##*/ } -o converted.mp4 -c h264_nvenc video.mp4"
25+ echo " ${0##*/ } -l -c libsvtav1 # Process all videos in current dir with AV1 codec"
26+ exit 0
27+ }
28+
29+ # Parse command line arguments
30+ while getopts " o:c:lh" opt; do
31+ case $opt in
32+ o) OUTPUT_FILE=" $OPTARG " ;;
33+ c) VIDEO_CODEC=" $OPTARG " ;;
34+ l) PROCESS_ALL=true ;;
35+ h) show_help ;;
36+ * ) echo " Invalid option: -$OPTARG " >&2 ; exit 1 ;;
37+ esac
38+ done
39+
40+ # Shift to get the input file (only needed if not using -l)
41+ shift $(( OPTIND- 1 ))
42+
43+ # Function to process a single video file
44+ process_video () {
45+ local INPUT_FILE=" $1 "
46+
47+ # Check if input file exists
48+ if [ ! -f " $INPUT_FILE " ]; then
49+ echo " Error: Input file '$INPUT_FILE ' not found"
50+ return 1
51+ fi
52+
53+ # Get video dimensions using ffprobe
54+ DIMENSIONS=$( ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 " $INPUT_FILE " 2> /dev/null)
55+
56+ if [ -z " $DIMENSIONS " ]; then
57+ echo " Error: Could not get video dimensions from '$INPUT_FILE '"
58+ return 1
59+ fi
60+
61+ # Extract width and height
62+ WIDTH=$( echo " $DIMENSIONS " | cut -d' x' -f1)
63+ HEIGHT=$( echo " $DIMENSIONS " | cut -d' x' -f2)
64+
65+ # Check if video is portrait (height > width)
66+ if [ " $HEIGHT " -gt " $WIDTH " ]; then
67+ echo " Video is portrait (${WIDTH} x${HEIGHT} )"
68+ echo " Starting conversion..."
69+ else
70+ echo " Video is not portrait (${WIDTH} x${HEIGHT} )"
71+ echo " Skipping conversion..."
72+ return 0
73+ fi
74+
75+ # Generate output filename if not specified
76+ local OUTPUT_FILE_LOCAL=" "
77+ if [ -z " $OUTPUT_FILE " ]; then
78+ # Remove extension
79+ FILENAME=" ${INPUT_FILE% .* } "
80+ EXTENSION=" ${INPUT_FILE##* .} "
81+ OUTPUT_FILE_LOCAL=" ${FILENAME}${DEFAULT_SUFFIX} .${EXTENSION} "
82+ else
83+ # If processing multiple files with -l, we need to generate unique names
84+ if [ " $PROCESS_ALL " = true ]; then
85+ FILENAME=" ${INPUT_FILE% .* } "
86+ EXTENSION=" ${INPUT_FILE##* .} "
87+ OUTPUT_FILE_LOCAL=" ${FILENAME}${DEFAULT_SUFFIX} .${EXTENSION} "
88+ else
89+ OUTPUT_FILE_LOCAL=" $OUTPUT_FILE "
90+ fi
91+ fi
92+
93+ # Build ffmpeg command using array (safer than eval)
94+ if [[ " $VIDEO_CODEC " == " hevc_nvenc" ]]; then
95+ FFMPEG_CMD=(
96+ ffmpeg
97+ -i " $INPUT_FILE "
98+ -ab " 384k"
99+ -acodec " aac"
100+ -aspect " 0.5625"
101+ -color_range " pc"
102+ -cq " 0"
103+ -f " mp4"
104+ -map_metadata " -1"
105+ -movflags " +faststart"
106+ -preset " p7"
107+ -r " 30"
108+ -rc " constqp"
109+ -s " 1080x1920"
110+ -threads " 0"
111+ -vcodec " $VIDEO_CODEC "
112+ -y
113+ " $OUTPUT_FILE_LOCAL "
114+ )
115+ elif [[ " $VIDEO_CODEC " == " libsvtav1" ]]; then
116+ FFMPEG_CMD=(
117+ ffmpeg
118+ -i " $INPUT_FILE "
119+ -ab " 384k"
120+ -acodec " aac"
121+ -aspect " 0.5625"
122+ -color_range " pc"
123+ -preset " 13"
124+ -crf " 0"
125+ -f " mp4"
126+ -map_metadata " -1"
127+ -movflags " +faststart"
128+ -r " 30"
129+ -s " 1080x1920"
130+ -threads " 0"
131+ -vcodec " $VIDEO_CODEC "
132+ -svtav1-params " tune=0:enable-overlays=0:enable-qm=1:qm-min=0:qm-max=15"
133+ -y
134+ " $OUTPUT_FILE_LOCAL "
135+ )
136+ else
137+ FFMPEG_CMD=(
138+ ffmpeg
139+ -i " $INPUT_FILE "
140+ -ab " 384k"
141+ -acodec " aac"
142+ -aspect " 0.5625"
143+ -color_range " pc"
144+ -f " mp4"
145+ -map_metadata " -1"
146+ -movflags " +faststart"
147+ -preset " veryslow"
148+ -r " 30"
149+ -s " 1080x1920"
150+ -threads " 0"
151+ -vcodec " $VIDEO_CODEC "
152+ -crf " 0"
153+ -y
154+ " $OUTPUT_FILE_LOCAL "
155+ )
156+ fi
157+
158+ echo " Running command:"
159+ echo " ${FFMPEG_CMD[@]} "
160+ echo " "
161+
162+ # Execute the command
163+ if " ${FFMPEG_CMD[@]} " ; then
164+ echo -e " \nConversion completed successfully!"
165+ echo " Output file: $OUTPUT_FILE_LOCAL "
166+ echo " ----------------------------------------"
167+ return 0
168+ else
169+ echo -e " \nError during conversion of '$INPUT_FILE '"
170+ echo " ----------------------------------------"
171+ return 1
172+ fi
173+ }
174+
175+ # Main execution logic
176+ if [ " $PROCESS_ALL " = true ]; then
177+ echo " Processing all video files in current directory..."
178+ echo " Video codec: $VIDEO_CODEC "
179+ echo " ----------------------------------------"
180+
181+ # Find video files (common extensions)
182+ VIDEO_FILES=()
183+ while IFS= read -r -d $' \0' file; do
184+ VIDEO_FILES+=(" $file " )
185+ done < <( find . -maxdepth 1 -type f \( -iname " *.mp4" -o -iname " *.mkv" -o -iname " *.avi" \
186+ -o -iname " *.mov" -o -iname " *.webm" -o -iname " *.flv" -o -iname " *.wmv" \
187+ -o -iname " *.m4v" -o -iname " *.3gp" \) -print0 2> /dev/null)
188+
189+ if [ ${# VIDEO_FILES[@]} -eq 0 ]; then
190+ echo " No video files found in current directory."
191+ exit 1
192+ fi
193+
194+ echo " Found ${# VIDEO_FILES[@]} video file(s) to process:"
195+ for file in " ${VIDEO_FILES[@]} " ; do
196+ echo " - $file "
197+ done
198+ echo " ----------------------------------------"
199+
200+ # Process each video file
201+ SUCCESS_COUNT=0
202+ FAIL_COUNT=0
203+
204+ for video_file in " ${VIDEO_FILES[@]} " ; do
205+ echo " Processing: $video_file "
206+
207+ # Reset OUTPUT_FILE to ensure each file gets unique output name
208+ ORIG_OUTPUT=" $OUTPUT_FILE "
209+ OUTPUT_FILE=" "
210+
211+ if process_video " $video_file " ; then
212+ (( SUCCESS_COUNT++ ))
213+ else
214+ (( FAIL_COUNT++ ))
215+ fi
216+
217+ # Restore OUTPUT_FILE if it was set (though not used in -l mode)
218+ OUTPUT_FILE=" $ORIG_OUTPUT "
219+ done
220+
221+ echo " ========================================"
222+ echo " Processing completed!"
223+ echo " Successfully converted: $SUCCESS_COUNT file(s)"
224+ echo " Failed: $FAIL_COUNT file(s)"
225+ exit $(( FAIL_COUNT > 0 ? 1 : 0 ))
226+
227+ else
228+ # Single file processing mode (original behavior)
229+
230+ # Check if input file is provided
231+ if [ -z " $1 " ]; then
232+ echo " Error: No input file specified"
233+ echo " Usage: $0 [OPTIONS] input_video"
234+ exit 1
235+ fi
236+
237+ INPUT_FILE=" $1 "
238+ process_video " $INPUT_FILE "
239+ fi
0 commit comments